ksvgiconpainter.cpp
00001 /* 00002 Copyright (C) 2002 Nikolas Zimmermann <wildfox@kde.org> 00003 This file is part of the KDE project 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License as published by the Free Software Foundation; either 00008 version 2 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 aint with this library; see the file COPYING.LIB. If not, write to 00017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00018 Boston, MA 02110-1301, USA. 00019 */ 00020 00021 #include <tqvaluevector.h> 00022 #include <tqstringlist.h> 00023 #include <tqwmatrix.h> 00024 #include <tqregexp.h> 00025 #include <tqimage.h> 00026 #include <tqdict.h> 00027 #include <tqmap.h> 00028 #include <tqdom.h> 00029 00030 #include <math.h> 00031 00032 #include <kdebug.h> 00033 00034 #include <libart_lgpl/art_rgba.h> 00035 #include <libart_lgpl/art_bpath.h> 00036 #include <libart_lgpl/art_vpath.h> 00037 #include <libart_lgpl/art_vpath_dash.h> 00038 #include <libart_lgpl/art_affine.h> 00039 #include <libart_lgpl/art_render_svp.h> 00040 #include <libart_lgpl/art_svp.h> 00041 #include <libart_lgpl/art_svp_vpath.h> 00042 #include <libart_lgpl/art_svp_intersect.h> 00043 #include <libart_lgpl/art_svp_vpath_stroke.h> 00044 00045 #include "ksvgiconpainter.h" 00046 00047 #define ART_END2 10 00048 00049 const double deg2rad = 0.017453292519943295769; // pi/180 00050 00051 class KSVGIconPainterHelper 00052 { 00053 public: 00054 KSVGIconPainterHelper(int width, int height, KSVGIconPainter *painter) 00055 { 00056 m_painter = painter; 00057 00058 m_clipSVP = 0; 00059 00060 m_fillColor = Qt::black; 00061 00062 m_useFill = true; 00063 m_useStroke = false; 00064 00065 m_useFillGradient = false; 00066 m_useStrokeGradient = false; 00067 00068 m_worldMatrix = new TQWMatrix(); 00069 00070 // Create new image with alpha support 00071 m_image = new TQImage(width, height, 32); 00072 m_image->setAlphaBuffer(true); 00073 00074 m_strokeWidth = 1.0; 00075 m_strokeMiterLimit = 4; 00076 m_dashOffset = 0; 00077 m_dashes = ""; 00078 00079 m_opacity = 0xff; 00080 m_fillOpacity = 0xff; 00081 m_strokeOpacity = 0xff; 00082 00083 m_fillRule = "nonzero"; 00084 00085 m_width = width; 00086 m_height = height; 00087 00088 m_rowstride = m_width * 4; 00089 00090 // Make internal libart rendering buffer transparent 00091 m_buffer = art_new(art_u8, m_rowstride * m_height); 00092 memset(m_buffer, 0, m_rowstride * m_height); 00093 00094 m_tempBuffer = 0; 00095 } 00096 00097 ~KSVGIconPainterHelper() 00098 { 00099 if(m_clipSVP) 00100 art_svp_free(m_clipSVP); 00101 00102 art_free(m_buffer); 00103 00104 delete m_image; 00105 delete m_worldMatrix; 00106 00107 for(TQMap<TQString, ArtGradientLinear *>::Iterator it = m_linearGradientMap.begin(); it != m_linearGradientMap.end(); ++it) 00108 { 00109 if (!it.data()) 00110 continue; 00111 delete [] it.data()->stops; 00112 delete it.data(); 00113 } 00114 for(TQMap<TQString, ArtGradientRadial *>::Iterator it = m_radialGradientMap.begin(); it != m_radialGradientMap.end(); ++it) 00115 { 00116 if (!it.data()) 00117 continue; 00118 delete [] it.data()->stops; 00119 delete it.data(); 00120 } 00121 } 00122 00123 ArtVpath *allocVPath(int number) 00124 { 00125 return art_new(ArtVpath, number); 00126 } 00127 00128 ArtBpath *allocBPath(int number) 00129 { 00130 return art_new(ArtBpath, number); 00131 } 00132 00133 void ensureSpace(TQMemArray<ArtBpath> &vec, int index) 00134 { 00135 if(vec.size() == (unsigned int) index) 00136 vec.resize(index + 1); 00137 } 00138 00139 void createBuffer() 00140 { 00141 m_tempBuffer = art_new(art_u8, m_rowstride * m_height); 00142 memset(m_tempBuffer, 0, m_rowstride * m_height); 00143 00144 // Swap buffers, so we work with the new one internally... 00145 art_u8 *temp = m_buffer; 00146 m_buffer = m_tempBuffer; 00147 m_tempBuffer = temp; 00148 } 00149 00150 void mixBuffer(int opacity) 00151 { 00152 art_u8 *srcPixel = m_buffer; 00153 art_u8 *dstPixel = m_tempBuffer; 00154 00155 for(int y = 0; y < m_height; y++) 00156 { 00157 for(int x = 0; x < m_width; x++) 00158 { 00159 art_u8 r, g, b, a; 00160 00161 a = srcPixel[4 * x + 3]; 00162 00163 if(a) 00164 { 00165 r = srcPixel[4 * x]; 00166 g = srcPixel[4 * x + 1]; 00167 b = srcPixel[4 * x + 2]; 00168 00169 int temp = a * opacity + 0x80; 00170 a = (temp + (temp >> 8)) >> 8; 00171 art_rgba_run_alpha(dstPixel + 4 * x, r, g, b, a, 1); 00172 } 00173 } 00174 00175 srcPixel += m_rowstride; 00176 dstPixel += m_rowstride; 00177 } 00178 00179 // Re-swap again... 00180 art_u8 *temp = m_buffer; 00181 m_buffer = m_tempBuffer; 00182 m_tempBuffer = temp; 00183 00184 art_free(m_tempBuffer); 00185 m_tempBuffer = 0; 00186 } 00187 00188 TQ_UINT32 toArtColor(const TQColor &color) 00189 { 00190 // Convert in a libart suitable form 00191 TQString tempName = color.name(); 00192 const char *str = tempName.latin1(); 00193 00194 int result = 0; 00195 00196 for(int i = 1; str[i]; i++) 00197 { 00198 int hexval; 00199 if(str[i] >= '0' && str[i] <= '9') 00200 hexval = str[i] - '0'; 00201 else if (str[i] >= 'A' && str[i] <= 'F') 00202 hexval = str[i] - 'A' + 10; 00203 else if (str[i] >= 'a' && str[i] <= 'f') 00204 hexval = str[i] - 'a' + 10; 00205 else 00206 break; 00207 00208 result = (result << 4) + hexval; 00209 } 00210 00211 return result; 00212 } 00213 00214 void drawSVP(ArtSVP *svp, TQ_UINT32 rgb, int opacity) 00215 { 00216 if(!svp) 00217 return; 00218 00219 ArtRender *render = art_render_new(0, 0, m_width, m_height, m_buffer, m_rowstride, 3, 8, ART_ALPHA_SEPARATE, 0); 00220 art_render_svp(render, svp); 00221 00222 art_render_mask_solid(render, (opacity << 8) + opacity + (opacity >> 7)); 00223 00224 ArtPixMaxDepth color[3]; 00225 color[0] = ART_PIX_MAX_FROM_8(rgb >> 16); 00226 color[1] = ART_PIX_MAX_FROM_8((rgb >> 8) & 0xff); 00227 color[2] = ART_PIX_MAX_FROM_8(rgb & 0xff); 00228 00229 art_render_image_solid(render, color); 00230 art_render_invoke(render); 00231 } 00232 00233 void drawBPath(ArtBpath *bpath) 00234 { 00235 double affine[6]; 00236 affine[0] = m_worldMatrix->m11(); 00237 affine[1] = m_worldMatrix->m12(); 00238 affine[2] = m_worldMatrix->m21(); 00239 affine[3] = m_worldMatrix->m22(); 00240 affine[4] = m_worldMatrix->dx(); 00241 affine[5] = m_worldMatrix->dy(); 00242 00243 ArtBpath *temp = art_bpath_affine_transform(bpath, affine); 00244 ArtVpath *vec = art_bez_path_to_vec(temp, 0.25); 00245 art_free(temp); 00246 drawPathInternal(vec, affine); 00247 } 00248 00249 void drawVPath(ArtVpath *vec) 00250 { 00251 double affine[6]; 00252 affine[0] = m_worldMatrix->m11(); 00253 affine[1] = m_worldMatrix->m12(); 00254 affine[2] = m_worldMatrix->m21(); 00255 affine[3] = m_worldMatrix->m22(); 00256 affine[4] = m_worldMatrix->dx(); 00257 affine[5] = m_worldMatrix->dy(); 00258 00259 ArtVpath *temp = art_vpath_affine_transform(vec, affine); 00260 art_free(vec); 00261 vec = temp; 00262 drawPathInternal(vec, affine); 00263 } 00264 00265 void drawPathInternal(ArtVpath *vec, double *affine) 00266 { 00267 ArtSVP *svp; 00268 ArtSVP *fillSVP = 0, *strokeSVP = 0; 00269 00270 TQ_UINT32 fillColor = 0, strokeColor = 0; 00271 00272 // Filling 00273 { 00274 int index = -1; 00275 TQValueVector<int> toCorrect; 00276 while(vec[++index].code != ART_END) 00277 { 00278 if(vec[index].code == ART_END2) 00279 { 00280 vec[index].code = ART_LINETO; 00281 toCorrect.push_back(index); 00282 } 00283 } 00284 00285 fillColor = toArtColor(m_fillColor); 00286 00287 ArtSvpWriter *swr; 00288 ArtSVP *temp; 00289 temp = art_svp_from_vpath(vec); 00290 00291 if(m_fillRule == "evenodd") 00292 swr = art_svp_writer_rewind_new(ART_WIND_RULE_ODDEVEN); 00293 else 00294 swr = art_svp_writer_rewind_new(ART_WIND_RULE_NONZERO); 00295 00296 art_svp_intersector(temp, swr); 00297 svp = art_svp_writer_rewind_reap(swr); 00298 00299 fillSVP = svp; 00300 00301 art_svp_free(temp); 00302 00303 TQValueVector<int>::iterator it; 00304 for(it = toCorrect.begin(); it != toCorrect.end(); ++it) 00305 vec[(*it)].code = (ArtPathcode)ART_END2; 00306 } 00307 00308 // There seems to be a problem when stroke width is zero, this is a quick 00309 // fix (Rob). 00310 if(m_strokeWidth <= 0) 00311 m_useStroke = m_useStrokeGradient = false; 00312 00313 // Stroking 00314 if(m_useStroke || m_useStrokeGradient) 00315 { 00316 strokeColor = toArtColor(m_strokeColor); 00317 00318 double ratio = art_affine_expansion(affine); 00319 double strokeWidth = m_strokeWidth * ratio; 00320 00321 ArtPathStrokeJoinType joinStyle = ART_PATH_STROKE_JOIN_MITER; 00322 ArtPathStrokeCapType capStyle = ART_PATH_STROKE_CAP_BUTT; 00323 00324 if(m_joinStyle == "miter") 00325 joinStyle = ART_PATH_STROKE_JOIN_MITER; 00326 else if(m_joinStyle == "round") 00327 joinStyle = ART_PATH_STROKE_JOIN_ROUND; 00328 else if(m_joinStyle == "bevel") 00329 joinStyle = ART_PATH_STROKE_JOIN_BEVEL; 00330 00331 if(m_capStyle == "butt") 00332 capStyle = ART_PATH_STROKE_CAP_BUTT; 00333 else if(m_capStyle == "round") 00334 capStyle = ART_PATH_STROKE_CAP_ROUND; 00335 else if(m_capStyle == "square") 00336 capStyle = ART_PATH_STROKE_CAP_SQUARE; 00337 00338 if(m_dashes.length() > 0) 00339 { 00340 TQRegExp reg("[, ]"); 00341 TQStringList dashList = TQStringList::split(reg, m_dashes); 00342 00343 double *dashes = new double[dashList.count()]; 00344 for(unsigned int i = 0; i < dashList.count(); i++) 00345 dashes[i] = m_painter->toPixel(dashList[i], true); 00346 00347 ArtVpathDash dash; 00348 dash.offset = m_dashOffset; 00349 dash.n_dash = dashList.count(); 00350 00351 dash.dash = dashes; 00352 00353 ArtVpath *vec2 = art_vpath_dash(vec, &dash); 00354 art_free(vec); 00355 00356 delete[] dashes; 00357 00358 vec = vec2; 00359 } 00360 00361 svp = art_svp_vpath_stroke(vec, joinStyle, capStyle, strokeWidth, m_strokeMiterLimit, 0.25); 00362 00363 strokeSVP = svp; 00364 } 00365 00366 // Apply opacity 00367 int fillOpacity = static_cast<int>(m_fillOpacity); 00368 int strokeOpacity = static_cast<int>(m_strokeOpacity); 00369 int opacity = static_cast<int>(m_opacity); 00370 00371 // Needed hack, to support both transparent 00372 // paths and transparent gradients 00373 if(fillOpacity == strokeOpacity && fillOpacity == opacity && !m_useFillGradient && !m_useStrokeGradient) 00374 opacity = 255; 00375 00376 if(fillOpacity != 255) 00377 { 00378 int temp = fillOpacity * opacity + 0x80; 00379 fillOpacity = (temp + (temp >> 8)) >> 8; 00380 } 00381 00382 if(strokeOpacity != 255) 00383 { 00384 int temp = strokeOpacity * opacity + 0x80; 00385 strokeOpacity = (temp + (temp >> 8)) >> 8; 00386 } 00387 00388 // Create temporary buffer if necessary 00389 bool tempDone = false; 00390 if(m_opacity != 0xff) 00391 { 00392 tempDone = true; 00393 createBuffer(); 00394 } 00395 00396 // Apply Gradients on fill/stroke 00397 if(m_useFillGradient) 00398 applyGradient(fillSVP, true); 00399 else if(m_useFill) 00400 drawSVP(fillSVP, fillColor, fillOpacity); 00401 00402 if(m_useStrokeGradient) 00403 applyGradient(strokeSVP, false); 00404 else if(m_useStroke) 00405 drawSVP(strokeSVP, strokeColor, strokeOpacity); 00406 00407 // Mix in temporary buffer, if possible 00408 if(tempDone) 00409 mixBuffer(opacity); 00410 00411 if(m_clipSVP) 00412 { 00413 art_svp_free(m_clipSVP); 00414 m_clipSVP = 0; 00415 } 00416 00417 if(fillSVP) 00418 art_svp_free(fillSVP); 00419 00420 if(strokeSVP) 00421 art_svp_free(strokeSVP); 00422 00423 // Reset opacity values 00424 m_opacity = 255.0; 00425 m_fillOpacity = 255.0; 00426 m_strokeOpacity = 255.0; 00427 00428 art_free(vec); 00429 } 00430 00431 void applyLinearGradient(ArtSVP *svp, const TQString &ref) 00432 { 00433 ArtGradientLinear *linear = m_linearGradientMap[ref]; 00434 if(linear) 00435 { 00436 TQDomElement element = m_linearGradientElementMap[linear]; 00437 00438 double x1, y1, x2, y2; 00439 if(element.hasAttribute("x1")) 00440 x1 = m_painter->toPixel(element.attribute("x1"), true); 00441 else 00442 x1 = 0; 00443 00444 if(element.hasAttribute("y1")) 00445 y1 = m_painter->toPixel(element.attribute("y1"), false); 00446 else 00447 y1 = 0; 00448 00449 if(element.hasAttribute("x2")) 00450 x2 = m_painter->toPixel(element.attribute("x2"), true); 00451 else 00452 x2 = 100; 00453 00454 if(element.hasAttribute("y2")) 00455 y2 = m_painter->toPixel(element.attribute("y2"), false); 00456 else 00457 y2 = 0; 00458 00459 // Adjust to gradientTransform 00460 TQWMatrix m = m_painter->parseTransform(element.attribute("gradientTransform")); 00461 m.map(x1, y1, &x1, &y1); 00462 m.map(x2, y2, &x2, &y2); 00463 00464 double x1n = x1 * m_worldMatrix->m11() + y1 * m_worldMatrix->m21() + m_worldMatrix->dx(); 00465 double y1n = x1 * m_worldMatrix->m12() + y1 * m_worldMatrix->m22() + m_worldMatrix->dy(); 00466 double x2n = x2 * m_worldMatrix->m11() + y2 * m_worldMatrix->m21() + m_worldMatrix->dx(); 00467 double y2n = x2 * m_worldMatrix->m12() + y2 * m_worldMatrix->m22() + m_worldMatrix->dy(); 00468 00469 double dx = x2n - x1n; 00470 double dy = y2n - y1n; 00471 double scale = 1.0 / (dx * dx + dy * dy); 00472 00473 linear->a = dx * scale; 00474 linear->b = dy * scale; 00475 linear->c = -(x1n * linear->a + y1n * linear->b); 00476 00477 ArtRender *render = art_render_new(0, 0, m_width, m_height, m_buffer, m_rowstride, 3, 8, ART_ALPHA_SEPARATE, 0); 00478 art_render_svp(render, svp); 00479 00480 art_render_gradient_linear(render, linear, ART_FILTER_HYPER); 00481 art_render_invoke(render); 00482 } 00483 } 00484 00485 void applyRadialGradient(ArtSVP *svp, const TQString &ref) 00486 { 00487 ArtGradientRadial *radial = m_radialGradientMap[ref]; 00488 if(radial) 00489 { 00490 TQDomElement element = m_radialGradientElementMap[radial]; 00491 00492 double cx, cy, r, fx, fy; 00493 if(element.hasAttribute("cx")) 00494 cx = m_painter->toPixel(element.attribute("cx"), true); 00495 else 00496 cx = 50; 00497 00498 if(element.hasAttribute("cy")) 00499 cy = m_painter->toPixel(element.attribute("cy"), false); 00500 else 00501 cy = 50; 00502 00503 if(element.hasAttribute("r")) 00504 r = m_painter->toPixel(element.attribute("r"), true); 00505 else 00506 r = 50; 00507 00508 if(element.hasAttribute("fx")) 00509 fx = m_painter->toPixel(element.attribute("fx"), false); 00510 else 00511 fx = cx; 00512 00513 if(element.hasAttribute("fy")) 00514 fy = m_painter->toPixel(element.attribute("fy"), false); 00515 else 00516 fy = cy; 00517 00518 radial->affine[0] = m_worldMatrix->m11(); 00519 radial->affine[1] = m_worldMatrix->m12(); 00520 radial->affine[2] = m_worldMatrix->m21(); 00521 radial->affine[3] = m_worldMatrix->m22(); 00522 radial->affine[4] = m_worldMatrix->dx(); 00523 radial->affine[5] = m_worldMatrix->dy(); 00524 00525 radial->fx = (fx - cx) / r; 00526 radial->fy = (fy - cy) / r; 00527 00528 double aff1[6], aff2[6], gradTransform[6]; 00529 00530 // Respect gradientTransform 00531 TQWMatrix m = m_painter->parseTransform(element.attribute("gradientTransform")); 00532 00533 gradTransform[0] = m.m11(); 00534 gradTransform[1] = m.m12(); 00535 gradTransform[2] = m.m21(); 00536 gradTransform[3] = m.m22(); 00537 gradTransform[4] = m.dx(); 00538 gradTransform[5] = m.dy(); 00539 00540 art_affine_scale(aff1, r, r); 00541 art_affine_translate(aff2, cx, cy); 00542 00543 art_affine_multiply(aff1, aff1, aff2); 00544 art_affine_multiply(aff1, aff1, gradTransform); 00545 art_affine_multiply(aff1, aff1, radial->affine); 00546 art_affine_invert(radial->affine, aff1); 00547 00548 ArtRender *render = art_render_new(0, 0, m_width, m_height, m_buffer, m_rowstride, 3, 8, ART_ALPHA_SEPARATE, 0); 00549 art_render_svp(render, svp); 00550 00551 art_render_gradient_radial(render, radial, ART_FILTER_HYPER); 00552 art_render_invoke(render); 00553 } 00554 } 00555 00556 void applyGradient(ArtSVP *svp, const TQString &ref) 00557 { 00558 ArtGradientLinear *linear = m_linearGradientMap[ref]; 00559 if(linear) 00560 { 00561 TQDomElement element = m_linearGradientElementMap[linear]; 00562 00563 if(!element.hasAttribute("xlink:href")) 00564 { 00565 applyLinearGradient(svp, ref); 00566 return; 00567 } 00568 else 00569 { 00570 ArtGradientLinear *linear = m_linearGradientMap[element.attribute("xlink:href").mid(1)]; 00571 TQDomElement newElement = m_linearGradientElementMap[linear]; 00572 00573 // Saved 'old' attributes 00574 TQDict<TQString> refattrs; 00575 refattrs.setAutoDelete(true); 00576 00577 for(unsigned int i = 0; i < newElement.attributes().length(); ++i) 00578 refattrs.insert(newElement.attributes().item(i).nodeName(), new TQString(newElement.attributes().item(i).nodeValue())); 00579 00580 // Copy attributes 00581 if(!newElement.isNull()) 00582 { 00583 TQDomNamedNodeMap attr = element.attributes(); 00584 00585 for(unsigned int i = 0; i < attr.length(); i++) 00586 { 00587 TQString name = attr.item(i).nodeName(); 00588 if(name != "xlink:href" && name != "id") 00589 newElement.setAttribute(name, attr.item(i).nodeValue()); 00590 } 00591 } 00592 00593 applyGradient(svp, element.attribute("xlink:href").mid(1)); 00594 00595 // Restore attributes 00596 TQDictIterator<TQString> itr(refattrs); 00597 for(; itr.current(); ++itr) 00598 newElement.setAttribute(itr.currentKey(), *(itr.current())); 00599 00600 return; 00601 } 00602 } 00603 00604 ArtGradientRadial *radial = m_radialGradientMap[ref]; 00605 if(radial) 00606 { 00607 TQDomElement element = m_radialGradientElementMap[radial]; 00608 00609 if(!element.hasAttribute("xlink:href")) 00610 { 00611 applyRadialGradient(svp, ref); 00612 return; 00613 } 00614 else 00615 { 00616 ArtGradientRadial *radial = m_radialGradientMap[element.attribute("xlink:href").mid(1)]; 00617 TQDomElement newElement = m_radialGradientElementMap[radial]; 00618 00619 // Saved 'old' attributes 00620 TQDict<TQString> refattrs; 00621 refattrs.setAutoDelete(true); 00622 00623 for(unsigned int i = 0; i < newElement.attributes().length(); ++i) 00624 refattrs.insert(newElement.attributes().item(i).nodeName(), new TQString(newElement.attributes().item(i).nodeValue())); 00625 00626 // Copy attributes 00627 if(!newElement.isNull()) 00628 { 00629 TQDomNamedNodeMap attr = element.attributes(); 00630 00631 for(unsigned int i = 0; i < attr.length(); i++) 00632 { 00633 TQString name = attr.item(i).nodeName(); 00634 if(name != "xlink:href" && name != "id") 00635 newElement.setAttribute(name, attr.item(i).nodeValue()); 00636 } 00637 } 00638 00639 applyGradient(svp, element.attribute("xlink:href").mid(1)); 00640 00641 // Restore attributes 00642 TQDictIterator<TQString> itr(refattrs); 00643 for(; itr.current(); ++itr) 00644 newElement.setAttribute(itr.currentKey(), *(itr.current())); 00645 00646 return; 00647 } 00648 } 00649 } 00650 00651 void applyGradient(ArtSVP *svp, bool fill) 00652 { 00653 TQString ref; 00654 00655 if(fill) 00656 { 00657 m_useFillGradient = false; 00658 ref = m_fillGradientReference; 00659 } 00660 else 00661 { 00662 m_useStrokeGradient = false; 00663 ref = m_strokeGradientReference; 00664 } 00665 00666 applyGradient(svp, ref); 00667 } 00668 00669 void blit() 00670 { 00671 unsigned char *line = m_buffer; 00672 00673 for(int y = 0; y < m_height; y++) 00674 { 00675 QRgb *sl = reinterpret_cast<QRgb *>(m_image->scanLine(y)); 00676 for(int x = 0; x < m_width; x++) 00677 sl[x] = tqRgba(line[x * 4], line[x * 4 + 1], line[x * 4 + 2], line[x * 4 + 3]); 00678 00679 line += m_rowstride; 00680 } 00681 } 00682 00683 void calculateArc(bool relative, TQMemArray<ArtBpath> &vec, int &index, double &curx, double &cury, double angle, double x, double y, double r1, double r2, bool largeArcFlag, bool sweepFlag) 00684 { 00685 double sin_th, cos_th; 00686 double a00, a01, a10, a11; 00687 double x0, y0, x1, y1, xc, yc; 00688 double d, sfactor, sfactor_sq; 00689 double th0, th1, th_arc; 00690 int i, n_segs; 00691 00692 sin_th = sin(angle * (M_PI / 180.0)); 00693 cos_th = cos(angle * (M_PI / 180.0)); 00694 00695 double dx; 00696 00697 if(!relative) 00698 dx = (curx - x) / 2.0; 00699 else 00700 dx = -x / 2.0; 00701 00702 double dy; 00703 00704 if(!relative) 00705 dy = (cury - y) / 2.0; 00706 else 00707 dy = -y / 2.0; 00708 00709 double _x1 = cos_th * dx + sin_th * dy; 00710 double _y1 = -sin_th * dx + cos_th * dy; 00711 double Pr1 = r1 * r1; 00712 double Pr2 = r2 * r2; 00713 double Px = _x1 * _x1; 00714 double Py = _y1 * _y1; 00715 00716 // Spec : check if radii are large enough 00717 double check = Px / Pr1 + Py / Pr2; 00718 if(check > 1) 00719 { 00720 r1 = r1 * sqrt(check); 00721 r2 = r2 * sqrt(check); 00722 } 00723 00724 a00 = cos_th / r1; 00725 a01 = sin_th / r1; 00726 a10 = -sin_th / r2; 00727 a11 = cos_th / r2; 00728 00729 x0 = a00 * curx + a01 * cury; 00730 y0 = a10 * curx + a11 * cury; 00731 00732 if(!relative) 00733 x1 = a00 * x + a01 * y; 00734 else 00735 x1 = a00 * (curx + x) + a01 * (cury + y); 00736 00737 if(!relative) 00738 y1 = a10 * x + a11 * y; 00739 else 00740 y1 = a10 * (curx + x) + a11 * (cury + y); 00741 00742 /* (x0, y0) is current point in transformed coordinate space. 00743 (x1, y1) is new point in transformed coordinate space. 00744 00745 The arc fits a unit-radius circle in this space. 00746 */ 00747 00748 d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0); 00749 00750 if (d) 00751 { 00752 sfactor_sq = 1.0 / d - 0.25; 00753 } 00754 else 00755 { 00756 sfactor_sq = 0; 00757 } 00758 00759 if(sfactor_sq < 0) 00760 sfactor_sq = 0; 00761 00762 sfactor = sqrt(sfactor_sq); 00763 00764 if(sweepFlag == largeArcFlag) 00765 sfactor = -sfactor; 00766 00767 xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0); 00768 yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0); 00769 00770 /* (xc, yc) is center of the circle. */ 00771 th0 = atan2(y0 - yc, x0 - xc); 00772 th1 = atan2(y1 - yc, x1 - xc); 00773 00774 th_arc = th1 - th0; 00775 if(th_arc < 0 && sweepFlag) 00776 th_arc += 2 * M_PI; 00777 else if(th_arc > 0 && !sweepFlag) 00778 th_arc -= 2 * M_PI; 00779 00780 n_segs = (int) ceil(fabs(th_arc / (M_PI * 0.5 + 0.001))); 00781 00782 for(i = 0; i < n_segs; i++) 00783 { 00784 index++; 00785 00786 ensureSpace(vec, index); 00787 00788 { 00789 double sin_th, cos_th; 00790 double a00, a01, a10, a11; 00791 double x1, y1, x2, y2, x3, y3; 00792 double t; 00793 double th_half; 00794 00795 double _th0 = th0 + i * th_arc / n_segs; 00796 double _th1 = th0 + (i + 1) * th_arc / n_segs; 00797 00798 sin_th = sin(angle * (M_PI / 180.0)); 00799 cos_th = cos(angle * (M_PI / 180.0)); 00800 00801 /* inverse transform compared with rsvg_path_arc */ 00802 a00 = cos_th * r1; 00803 a01 = -sin_th * r2; 00804 a10 = sin_th * r1; 00805 a11 = cos_th * r2; 00806 00807 th_half = 0.5 * (_th1 - _th0); 00808 t = (8.0 / 3.0) * sin(th_half * 0.5) * sin(th_half * 0.5) / sin(th_half); 00809 x1 = xc + cos(_th0) - t * sin(_th0); 00810 y1 = yc + sin(_th0) + t * cos(_th0); 00811 x3 = xc + cos(_th1); 00812 y3 = yc + sin(_th1); 00813 x2 = x3 + t * sin(_th1); 00814 y2 = y3 - t * cos(_th1); 00815 00816 ensureSpace(vec, index); 00817 00818 vec[index].code = ART_CURVETO; 00819 vec[index].x1 = a00 * x1 + a01 * y1; 00820 vec[index].y1 = a10 * x1 + a11 * y1; 00821 vec[index].x2 = a00 * x2 + a01 * y2; 00822 vec[index].y2 = a10 * x2 + a11 * y2; 00823 vec[index].x3 = a00 * x3 + a01 * y3; 00824 vec[index].y3 = a10 * x3 + a11 * y3; 00825 } 00826 } 00827 00828 if(!relative) 00829 curx = x; 00830 else 00831 curx += x; 00832 00833 if(!relative) 00834 cury = y; 00835 else 00836 cury += y; 00837 } 00838 00839 // For any docs, see the libart library 00840 static void art_vpath_render_bez(ArtVpath **p_vpath, int *pn, int *pn_max, 00841 double x0, double y0, 00842 double x1, double y1, 00843 double x2, double y2, 00844 double x3, double y3, 00845 double flatness) 00846 { 00847 double x3_0, y3_0, z3_0_dot, z1_dot, z2_dot; 00848 double z1_perp, z2_perp, max_perp_sq; 00849 00850 double x_m, y_m, xa1, ya1, xa2, ya2, xb1, yb1, xb2, yb2; 00851 00852 x3_0 = x3 - x0; 00853 y3_0 = y3 - y0; 00854 00855 z3_0_dot = x3_0 * x3_0 + y3_0 * y3_0; 00856 00857 if (z3_0_dot < 0.001) 00858 goto nosubdivide; 00859 00860 max_perp_sq = flatness * flatness * z3_0_dot; 00861 00862 z1_perp = (y1 - y0) * x3_0 - (x1 - x0) * y3_0; 00863 if (z1_perp * z1_perp > max_perp_sq) 00864 goto subdivide; 00865 00866 z2_perp = (y3 - y2) * x3_0 - (x3 - x2) * y3_0; 00867 if (z2_perp * z2_perp > max_perp_sq) 00868 goto subdivide; 00869 00870 z1_dot = (x1 - x0) * x3_0 + (y1 - y0) * y3_0; 00871 if (z1_dot < 0 && z1_dot * z1_dot > max_perp_sq) 00872 goto subdivide; 00873 00874 z2_dot = (x3 - x2) * x3_0 + (y3 - y2) * y3_0; 00875 if (z2_dot < 0 && z2_dot * z2_dot > max_perp_sq) 00876 goto subdivide; 00877 00878 if (z1_dot + z1_dot > z3_0_dot) 00879 goto subdivide; 00880 00881 if (z2_dot + z2_dot > z3_0_dot) 00882 goto subdivide; 00883 00884 nosubdivide: 00885 art_vpath_add_point (p_vpath, pn, pn_max, ART_LINETO, x3, y3); 00886 return; 00887 00888 subdivide: 00889 xa1 = (x0 + x1) * 0.5; 00890 ya1 = (y0 + y1) * 0.5; 00891 xa2 = (x0 + 2 * x1 + x2) * 0.25; 00892 ya2 = (y0 + 2 * y1 + y2) * 0.25; 00893 xb1 = (x1 + 2 * x2 + x3) * 0.25; 00894 yb1 = (y1 + 2 * y2 + y3) * 0.25; 00895 xb2 = (x2 + x3) * 0.5; 00896 yb2 = (y2 + y3) * 0.5; 00897 x_m = (xa2 + xb1) * 0.5; 00898 y_m = (ya2 + yb1) * 0.5; 00899 art_vpath_render_bez (p_vpath, pn, pn_max, x0, y0, xa1, ya1, xa2, ya2, x_m, y_m, flatness); 00900 art_vpath_render_bez (p_vpath, pn, pn_max, x_m, y_m, xb1, yb1, xb2, yb2, x3, y3, flatness); 00901 } 00902 00903 ArtVpath *art_bez_path_to_vec(const ArtBpath *bez, double flatness) 00904 { 00905 ArtVpath *vec; 00906 int vec_n, vec_n_max; 00907 int bez_index; 00908 double x, y; 00909 00910 vec_n = 0; 00911 vec_n_max = (1 << 4); 00912 vec = art_new (ArtVpath, vec_n_max); 00913 00914 x = 0; 00915 y = 0; 00916 00917 bez_index = 0; 00918 do 00919 { 00920 if(vec_n >= vec_n_max) 00921 art_expand (vec, ArtVpath, vec_n_max); 00922 00923 switch (bez[bez_index].code) 00924 { 00925 case ART_MOVETO_OPEN: 00926 case ART_MOVETO: 00927 case ART_LINETO: 00928 x = bez[bez_index].x3; 00929 y = bez[bez_index].y3; 00930 vec[vec_n].code = bez[bez_index].code; 00931 vec[vec_n].x = x; 00932 vec[vec_n].y = y; 00933 vec_n++; 00934 break; 00935 case ART_END: 00936 vec[vec_n].code = ART_END; 00937 vec[vec_n].x = 0; 00938 vec[vec_n].y = 0; 00939 vec_n++; 00940 break; 00941 case ART_END2: 00942 vec[vec_n].code = (ArtPathcode)ART_END2; 00943 vec[vec_n].x = bez[bez_index].x3; 00944 vec[vec_n].y = bez[bez_index].y3; 00945 vec_n++; 00946 break; 00947 case ART_CURVETO: 00948 art_vpath_render_bez (&vec, &vec_n, &vec_n_max, 00949 x, y, 00950 bez[bez_index].x1, bez[bez_index].y1, 00951 bez[bez_index].x2, bez[bez_index].y2, 00952 bez[bez_index].x3, bez[bez_index].y3, 00953 flatness); 00954 x = bez[bez_index].x3; 00955 y = bez[bez_index].y3; 00956 break; 00957 } 00958 } 00959 00960 while (bez[bez_index++].code != ART_END); 00961 return vec; 00962 } 00963 00964 static void art_rgb_affine_run(int *p_x0, int *p_x1, int y, 00965 int src_width, int src_height, 00966 const double affine[6]) 00967 { 00968 int x0, x1; 00969 double z; 00970 double x_intercept; 00971 int xi; 00972 00973 x0 = *p_x0; 00974 x1 = *p_x1; 00975 00976 if (affine[0] > 1e-6) 00977 { 00978 z = affine[2] * (y + 0.5) + affine[4]; 00979 x_intercept = -z / affine[0]; 00980 xi = (int) (int) ceil (x_intercept + 1e-6 - 0.5); 00981 if (xi > x0) 00982 x0 = xi; 00983 x_intercept = (-z + src_width) / affine[0]; 00984 xi = (int) ceil (x_intercept - 1e-6 - 0.5); 00985 if (xi < x1) 00986 x1 = xi; 00987 } 00988 else if (affine[0] < -1e-6) 00989 { 00990 z = affine[2] * (y + 0.5) + affine[4]; 00991 x_intercept = (-z + src_width) / affine[0]; 00992 xi = (int) ceil (x_intercept + 1e-6 - 0.5); 00993 if (xi > x0) 00994 x0 = xi; 00995 x_intercept = -z / affine[0]; 00996 xi = (int) ceil (x_intercept - 1e-6 - 0.5); 00997 if (xi < x1) 00998 x1 = xi; 00999 } 01000 else 01001 { 01002 z = affine[2] * (y + 0.5) + affine[4]; 01003 if (z < 0 || z >= src_width) 01004 { 01005 *p_x1 = *p_x0; 01006 return; 01007 } 01008 } 01009 if (affine[1] > 1e-6) 01010 { 01011 z = affine[3] * (y + 0.5) + affine[5]; 01012 x_intercept = -z / affine[1]; 01013 xi = (int) ceil (x_intercept + 1e-6 - 0.5); 01014 if (xi > x0) 01015 x0 = xi; 01016 x_intercept = (-z + src_height) / affine[1]; 01017 xi = (int) ceil (x_intercept - 1e-6 - 0.5); 01018 if (xi < x1) 01019 x1 = xi; 01020 } 01021 else if (affine[1] < -1e-6) 01022 { 01023 z = affine[3] * (y + 0.5) + affine[5]; 01024 x_intercept = (-z + src_height) / affine[1]; 01025 xi = (int) ceil (x_intercept + 1e-6 - 0.5); 01026 if (xi > x0) 01027 x0 = xi; 01028 x_intercept = -z / affine[1]; 01029 xi = (int) ceil (x_intercept - 1e-6 - 0.5); 01030 if (xi < x1) 01031 x1 = xi; 01032 } 01033 else 01034 { 01035 z = affine[3] * (y + 0.5) + affine[5]; 01036 if (z < 0 || z >= src_height) 01037 { 01038 *p_x1 = *p_x0; 01039 return; 01040 } 01041 } 01042 01043 *p_x0 = x0; 01044 *p_x1 = x1; 01045 } 01046 01047 // Slightly modified version to support RGBA buffers, copied from gnome-print 01048 static void art_rgba_rgba_affine(art_u8 *dst, 01049 int x0, int y0, int x1, int y1, int dst_rowstride, 01050 const art_u8 *src, 01051 int src_width, int src_height, int src_rowstride, 01052 const double affine[6]) 01053 { 01054 int x, y; 01055 double inv[6]; 01056 art_u8 *dst_p, *dst_linestart; 01057 const art_u8 *src_p; 01058 ArtPoint pt, src_pt; 01059 int src_x, src_y; 01060 int alpha; 01061 art_u8 bg_r, bg_g, bg_b, bg_a, cr, cg, cb; 01062 art_u8 fg_r, fg_g, fg_b; 01063 int tmp; 01064 int run_x0, run_x1; 01065 01066 dst_linestart = dst; 01067 art_affine_invert (inv, affine); 01068 for (y = y0; y < y1; y++) 01069 { 01070 pt.y = y + 0.5; 01071 run_x0 = x0; 01072 run_x1 = x1; 01073 art_rgb_affine_run (&run_x0, &run_x1, y, src_width, src_height, 01074 inv); 01075 dst_p = dst_linestart + (run_x0 - x0) * 4; 01076 for (x = run_x0; x < run_x1; x++) 01077 { 01078 pt.x = x + 0.5; 01079 art_affine_point (&src_pt, &pt, inv); 01080 src_x = (int) floor (src_pt.x); 01081 src_y = (int) floor (src_pt.y); 01082 src_p = src + (src_y * src_rowstride) + src_x * 4; 01083 if (src_x >= 0 && src_x < src_width && 01084 src_y >= 0 && src_y < src_height) 01085 { 01086 01087 alpha = src_p[3]; 01088 if (alpha) 01089 { 01090 if (alpha == 255) 01091 { 01092 dst_p[0] = src_p[0]; 01093 dst_p[1] = src_p[1]; 01094 dst_p[2] = src_p[2]; 01095 dst_p[3] = 255; 01096 } 01097 else 01098 { 01099 bg_r = dst_p[0]; 01100 bg_g = dst_p[1]; 01101 bg_b = dst_p[2]; 01102 bg_a = dst_p[3]; 01103 01104 cr = (bg_r * bg_a + 0x80) >> 8; 01105 cg = (bg_g * bg_g + 0x80) >> 8; 01106 cb = (bg_b * bg_b + 0x80) >> 8; 01107 01108 tmp = (src_p[0] - bg_r) * alpha; 01109 fg_r = bg_r + ((tmp + (tmp >> 8) + 0x80) >> 8); 01110 tmp = (src_p[1] - bg_g) * alpha; 01111 fg_g = bg_g + ((tmp + (tmp >> 8) + 0x80) >> 8); 01112 tmp = (src_p[2] - bg_b) * alpha; 01113 fg_b = bg_b + ((tmp + (tmp >> 8) + 0x80) >> 8); 01114 01115 dst_p[0] = fg_r; 01116 dst_p[1] = fg_g; 01117 dst_p[2] = fg_b; 01118 dst_p[3] = bg_a + (((255 - bg_a) * alpha + 0x80) >> 8); 01119 } 01120 } 01121 } else { dst_p[0] = 255; dst_p[1] = 0; dst_p[2] = 0; dst_p[3] = 255;} 01122 dst_p += 4; 01123 } 01124 dst_linestart += dst_rowstride; 01125 } 01126 } 01127 01128 private: 01129 friend class KSVGIconPainter; 01130 ArtSVP *m_clipSVP; 01131 01132 TQImage *m_image; 01133 TQWMatrix *m_worldMatrix; 01134 01135 TQString m_fillRule; 01136 TQString m_joinStyle; 01137 TQString m_capStyle; 01138 01139 int m_strokeMiterLimit; 01140 01141 TQString m_dashes; 01142 unsigned short m_dashOffset; 01143 01144 TQColor m_fillColor; 01145 TQColor m_strokeColor; 01146 01147 art_u8 *m_buffer; 01148 art_u8 *m_tempBuffer; 01149 01150 int m_width; 01151 int m_height; 01152 01153 int m_rowstride; 01154 01155 double m_opacity; 01156 double m_fillOpacity; 01157 double m_strokeOpacity; 01158 01159 bool m_useFill; 01160 bool m_useStroke; 01161 01162 bool m_useFillGradient; 01163 bool m_useStrokeGradient; 01164 01165 TQString m_fillGradientReference; 01166 TQString m_strokeGradientReference; 01167 01168 TQMap<TQString, ArtGradientLinear *> m_linearGradientMap; 01169 TQMap<ArtGradientLinear *, TQDomElement> m_linearGradientElementMap; 01170 01171 TQMap<TQString, ArtGradientRadial *> m_radialGradientMap; 01172 TQMap<ArtGradientRadial *, TQDomElement> m_radialGradientElementMap; 01173 01174 KSVGIconPainter *m_painter; 01175 01176 double m_strokeWidth; 01177 }; 01178 01179 struct KSVGIconPainter::Private 01180 { 01181 KSVGIconPainterHelper *helper; 01182 01183 int drawWidth; 01184 int drawHeight; 01185 }; 01186 01187 KSVGIconPainter::KSVGIconPainter(int width, int height) : d(new Private()) 01188 { 01189 d->helper = new KSVGIconPainterHelper(width, height, this); 01190 01191 d->drawWidth = width; 01192 d->drawHeight = height; 01193 } 01194 01195 KSVGIconPainter::~KSVGIconPainter() 01196 { 01197 delete d->helper; 01198 delete d; 01199 } 01200 01201 void KSVGIconPainter::setDrawWidth(int dwidth) 01202 { 01203 d->drawWidth = dwidth; 01204 } 01205 01206 void KSVGIconPainter::setDrawHeight(int dheight) 01207 { 01208 d->drawHeight = dheight; 01209 } 01210 01211 void KSVGIconPainter::finish() 01212 { 01213 d->helper->blit(); 01214 } 01215 01216 TQImage *KSVGIconPainter::image() 01217 { 01218 return new TQImage(*d->helper->m_image); 01219 } 01220 01221 TQWMatrix *KSVGIconPainter::worldMatrix() 01222 { 01223 return d->helper->m_worldMatrix; 01224 } 01225 01226 void KSVGIconPainter::setWorldMatrix(TQWMatrix *matrix) 01227 { 01228 if(d->helper->m_worldMatrix) 01229 delete d->helper->m_worldMatrix; 01230 01231 d->helper->m_worldMatrix = matrix; 01232 } 01233 01234 void KSVGIconPainter::setStrokeWidth(double width) 01235 { 01236 d->helper->m_strokeWidth = width; 01237 } 01238 01239 void KSVGIconPainter::setStrokeMiterLimit(const TQString &miter) 01240 { 01241 d->helper->m_strokeMiterLimit = miter.toInt(); 01242 } 01243 01244 void KSVGIconPainter::setStrokeDashOffset(const TQString &dashOffset) 01245 { 01246 d->helper->m_dashOffset = dashOffset.toUInt(); 01247 } 01248 01249 void KSVGIconPainter::setStrokeDashArray(const TQString &dashes) 01250 { 01251 d->helper->m_dashes = dashes; 01252 } 01253 01254 void KSVGIconPainter::setCapStyle(const TQString &cap) 01255 { 01256 d->helper->m_capStyle = cap; 01257 } 01258 01259 void KSVGIconPainter::setJoinStyle(const TQString &join) 01260 { 01261 d->helper->m_joinStyle = join; 01262 } 01263 01264 void KSVGIconPainter::setStrokeColor(const TQString &stroke) 01265 { 01266 if(stroke.startsWith("url")) 01267 { 01268 d->helper->m_useStroke = false; 01269 d->helper->m_useStrokeGradient = true; 01270 01271 TQString url = stroke; 01272 01273 unsigned int start = url.find("#") + 1; 01274 unsigned int end = url.findRev(")"); 01275 01276 d->helper->m_strokeGradientReference = url.mid(start, end - start); 01277 } 01278 else 01279 { 01280 d->helper->m_strokeColor = parseColor(stroke); 01281 01282 d->helper->m_useStrokeGradient = false; 01283 d->helper->m_strokeGradientReference = TQString::null; 01284 01285 if(stroke.stripWhiteSpace().lower() != "none") 01286 setUseStroke(true); 01287 else 01288 setUseStroke(false); 01289 } 01290 } 01291 01292 void KSVGIconPainter::setFillColor(const TQString &fill) 01293 { 01294 if(fill.startsWith("url")) 01295 { 01296 d->helper->m_useFill = false; 01297 d->helper->m_useFillGradient = true; 01298 01299 TQString url = fill; 01300 01301 unsigned int start = url.find("#") + 1; 01302 unsigned int end = url.findRev(")"); 01303 01304 d->helper->m_fillGradientReference = url.mid(start, end - start); 01305 } 01306 else 01307 { 01308 d->helper->m_fillColor = parseColor(fill); 01309 01310 d->helper->m_useFillGradient = false; 01311 d->helper->m_fillGradientReference = TQString::null; 01312 01313 if(fill.stripWhiteSpace().lower() != "none") 01314 setUseFill(true); 01315 else 01316 setUseFill(false); 01317 } 01318 } 01319 01320 void KSVGIconPainter::setFillRule(const TQString &fillRule) 01321 { 01322 d->helper->m_fillRule = fillRule; 01323 } 01324 01325 TQ_UINT32 KSVGIconPainter::parseOpacity(const TQString &data) 01326 { 01327 int opacity = 255; 01328 01329 if(!data.isEmpty()) 01330 { 01331 double temp; 01332 01333 if(data.contains("%")) 01334 { 01335 TQString tempString = data.left(data.length() - 1); 01336 temp = double(255 * tempString.toDouble()) / 100.0; 01337 } 01338 else 01339 temp = data.toDouble(); 01340 01341 opacity = (int) floor(temp * 255 + 0.5); 01342 } 01343 01344 return opacity; 01345 } 01346 01347 void KSVGIconPainter::setFillOpacity(const TQString &fillOpacity) 01348 { 01349 d->helper->m_fillOpacity = parseOpacity(fillOpacity); 01350 } 01351 01352 void KSVGIconPainter::setStrokeOpacity(const TQString &strokeOpacity) 01353 { 01354 d->helper->m_strokeOpacity = parseOpacity(strokeOpacity); 01355 } 01356 01357 void KSVGIconPainter::setOpacity(const TQString &opacity) 01358 { 01359 d->helper->m_opacity = parseOpacity(opacity); 01360 } 01361 01362 void KSVGIconPainter::setUseFill(bool fill) 01363 { 01364 d->helper->m_useFill = fill; 01365 } 01366 01367 void KSVGIconPainter::setUseStroke(bool stroke) 01368 { 01369 d->helper->m_useStroke = stroke; 01370 } 01371 01372 void KSVGIconPainter::setClippingRect(int x, int y, int w, int h) 01373 { 01374 ArtVpath *vec = d->helper->allocVPath(6); 01375 01376 vec[0].code = ART_MOVETO; 01377 vec[0].x = x; 01378 vec[0].y = y; 01379 01380 vec[1].code = ART_LINETO; 01381 vec[1].x = x; 01382 vec[1].y = y + h; 01383 01384 vec[2].code = ART_LINETO; 01385 vec[2].x = x + w; 01386 vec[2].y = y + h; 01387 01388 vec[3].code = ART_LINETO; 01389 vec[3].x = x + w; 01390 vec[3].y = y; 01391 01392 vec[4].code = ART_LINETO; 01393 vec[4].x = x; 01394 vec[4].y = y; 01395 01396 vec[5].code = ART_END; 01397 01398 if(d->helper->m_clipSVP) 01399 art_svp_free(d->helper->m_clipSVP); 01400 01401 d->helper->m_clipSVP = art_svp_from_vpath(vec); 01402 01403 art_free(vec); 01404 } 01405 01406 void KSVGIconPainter::drawRectangle(double x, double y, double w, double h, double rx, double ry) 01407 { 01408 if((int) rx != 0 && (int) ry != 0) 01409 { 01410 ArtVpath *res; 01411 ArtBpath *vec = d->helper->allocBPath(10); 01412 01413 int i = 0; 01414 01415 if(rx > w / 2) 01416 rx = w / 2; 01417 01418 if(ry > h / 2) 01419 ry = h / 2; 01420 01421 vec[i].code = ART_MOVETO_OPEN; 01422 vec[i].x3 = x + rx; 01423 vec[i].y3 = y; 01424 01425 i++; 01426 01427 vec[i].code = ART_CURVETO; 01428 vec[i].x1 = x + rx * (1 - 0.552); 01429 vec[i].y1 = y; 01430 vec[i].x2 = x; 01431 vec[i].y2 = y + ry * (1 - 0.552); 01432 vec[i].x3 = x; 01433 vec[i].y3 = y + ry; 01434 01435 i++; 01436 01437 if(ry < h / 2) 01438 { 01439 vec[i].code = ART_LINETO; 01440 vec[i].x3 = x; 01441 vec[i].y3 = y + h - ry; 01442 01443 i++; 01444 } 01445 01446 vec[i].code = ART_CURVETO; 01447 vec[i].x1 = x; 01448 vec[i].y1 = y + h - ry * (1 - 0.552); 01449 vec[i].x2 = x + rx * (1 - 0.552); 01450 vec[i].y2 = y + h; 01451 vec[i].x3 = x + rx; 01452 vec[i].y3 = y + h; 01453 01454 i++; 01455 01456 if(rx < w / 2) 01457 { 01458 vec[i].code = ART_LINETO; 01459 vec[i].x3 = x + w - rx; 01460 vec[i].y3 = y + h; 01461 01462 i++; 01463 } 01464 01465 vec[i].code = ART_CURVETO; 01466 vec[i].x1 = x + w - rx * (1 - 0.552); 01467 vec[i].y1 = y + h; 01468 vec[i].x2 = x + w; 01469 vec[i].y2 = y + h - ry * (1 - 0.552); 01470 vec[i].x3 = x + w; 01471 01472 vec[i].y3 = y + h - ry; 01473 01474 i++; 01475 01476 if(ry < h / 2) 01477 { 01478 vec[i].code = ART_LINETO; 01479 vec[i].x3 = x + w; 01480 vec[i].y3 = y + ry; 01481 01482 i++; 01483 } 01484 01485 vec[i].code = ART_CURVETO; 01486 vec[i].x1 = x + w; 01487 vec[i].y1 = y + ry * (1 - 0.552); 01488 vec[i].x2 = x + w - rx * (1 - 0.552); 01489 vec[i].y2 = y; 01490 vec[i].x3 = x + w - rx; 01491 vec[i].y3 = y; 01492 01493 i++; 01494 01495 if(rx < w / 2) 01496 { 01497 vec[i].code = ART_LINETO; 01498 vec[i].x3 = x + rx; 01499 vec[i].y3 = y; 01500 01501 i++; 01502 } 01503 01504 vec[i].code = ART_END; 01505 01506 res = d->helper->art_bez_path_to_vec(vec, 0.25); 01507 art_free(vec); 01508 d->helper->drawVPath(res); 01509 } 01510 else 01511 { 01512 ArtVpath *vec = d->helper->allocVPath(6); 01513 01514 vec[0].code = ART_MOVETO; 01515 vec[0].x = x; 01516 vec[0].y = y; 01517 01518 vec[1].code = ART_LINETO; 01519 vec[1].x = x; 01520 vec[1].y = y + h; 01521 01522 vec[2].code = ART_LINETO; 01523 vec[2].x = x + w; 01524 vec[2].y = y + h; 01525 01526 vec[3].code = ART_LINETO; 01527 vec[3].x = x + w; 01528 vec[3].y = y; 01529 01530 vec[4].code = ART_LINETO; 01531 vec[4].x = x; 01532 vec[4].y = y; 01533 01534 vec[5].code = ART_END; 01535 01536 d->helper->drawVPath(vec); 01537 } 01538 } 01539 01540 void KSVGIconPainter::drawEllipse(double cx, double cy, double rx, double ry) 01541 { 01542 ArtBpath *temp; 01543 01544 temp = d->helper->allocBPath(6); 01545 01546 double x1, y1, x2, y2, x3, y3; 01547 double len = 0.55228474983079356; 01548 double cos4[] = {1.0, 0.0, -1.0, 0.0, 1.0}; 01549 double sin4[] = {0.0, 1.0, 0.0, -1.0, 0.0}; 01550 int i = 0; 01551 01552 temp[i].code = ART_MOVETO; 01553 temp[i].x3 = cx + rx; 01554 temp[i].y3 = cy; 01555 01556 i++; 01557 01558 while(i < 5) 01559 { 01560 x1 = cos4[i-1] + len * cos4[i]; 01561 y1 = sin4[i-1] + len * sin4[i]; 01562 x2 = cos4[i] + len * cos4[i-1]; 01563 y2 = sin4[i] + len * sin4[i-1]; 01564 x3 = cos4[i]; 01565 y3 = sin4[i]; 01566 01567 temp[i].code = ART_CURVETO; 01568 temp[i].x1 = cx + x1 * rx; 01569 temp[i].y1 = cy + y1 * ry; 01570 temp[i].x2 = cx + x2 * rx; 01571 temp[i].y2 = cy + y2 * ry; 01572 temp[i].x3 = cx + x3 * rx; 01573 temp[i].y3 = cy + y3 * ry; 01574 01575 i++; 01576 } 01577 01578 temp[i].code = ART_END; 01579 01580 d->helper->drawBPath(temp); 01581 01582 art_free(temp); 01583 } 01584 01585 void KSVGIconPainter::drawLine(double x1, double y1, double x2, double y2) 01586 { 01587 ArtVpath *vec; 01588 01589 vec = d->helper->allocVPath(3); 01590 01591 vec[0].code = ART_MOVETO_OPEN; 01592 vec[0].x = x1; 01593 vec[0].y = y1; 01594 01595 vec[1].code = ART_LINETO; 01596 vec[1].x = x2; 01597 vec[1].y = y2; 01598 01599 vec[2].code = ART_END; 01600 01601 d->helper->drawVPath(vec); 01602 } 01603 01604 void KSVGIconPainter::drawPolyline(TQPointArray polyArray, int points) 01605 { 01606 if(polyArray.point(0).x() == -1 || polyArray.point(0).y() == -1) 01607 return; 01608 01609 ArtVpath *polyline; 01610 01611 if(points == -1) 01612 points = polyArray.count(); 01613 01614 polyline = d->helper->allocVPath(3 + points); 01615 polyline[0].code = ART_MOVETO; 01616 polyline[0].x = polyArray.point(0).x(); 01617 polyline[0].y = polyArray.point(0).y(); 01618 01619 int index; 01620 for(index = 1; index < points; index++) 01621 { 01622 TQPoint point = polyArray.point(index); 01623 polyline[index].code = ART_LINETO; 01624 polyline[index].x = point.x(); 01625 polyline[index].y = point.y(); 01626 } 01627 01628 if(d->helper->m_useFill) // if the polyline must be filled, inform libart that it should not be closed. 01629 { 01630 polyline[index].code = (ArtPathcode)ART_END2; 01631 polyline[index].x = polyArray.point(0).x(); 01632 polyline[index++].y = polyArray.point(0).y(); 01633 } 01634 01635 polyline[index].code = ART_END; 01636 01637 d->helper->drawVPath(polyline); 01638 } 01639 01640 void KSVGIconPainter::drawPolygon(TQPointArray polyArray) 01641 { 01642 ArtVpath *polygon; 01643 01644 polygon = d->helper->allocVPath(3 + polyArray.count()); 01645 polygon[0].code = ART_MOVETO; 01646 polygon[0].x = polyArray.point(0).x(); 01647 polygon[0].y = polyArray.point(0).y(); 01648 01649 unsigned int index; 01650 for(index = 1; index < polyArray.count(); index++) 01651 { 01652 TQPoint point = polyArray.point(index); 01653 polygon[index].code = ART_LINETO; 01654 polygon[index].x = point.x(); 01655 polygon[index].y = point.y(); 01656 } 01657 01658 polygon[index].code = ART_LINETO; 01659 polygon[index].x = polyArray.point(0).x(); 01660 polygon[index].y = polyArray.point(0).y(); 01661 01662 index++; 01663 polygon[index].code = ART_END; 01664 01665 d->helper->drawVPath(polygon); 01666 } 01667 01668 // Path parsing tool 01669 // parses the coord into number and forwards to the next token 01670 static const char *getCoord(const char *ptr, double &number) 01671 { 01672 int integer, exponent; 01673 double decimal, frac; 01674 int sign, expsign; 01675 01676 exponent = 0; 01677 integer = 0; 01678 frac = 1.0; 01679 decimal = 0; 01680 sign = 1; 01681 expsign = 1; 01682 01683 // read the sign 01684 if(*ptr == '+') 01685 ptr++; 01686 else if(*ptr == '-') 01687 { 01688 ptr++; 01689 sign = -1; 01690 } 01691 // read the integer part 01692 while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9') 01693 integer = (integer * 10) + *(ptr++) - '0'; 01694 01695 if(*ptr == '.') // read the decimals 01696 { 01697 ptr++; 01698 while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9') 01699 decimal += (*(ptr++) - '0') * (frac *= 0.1); 01700 } 01701 01702 if(*ptr == 'e' || *ptr == 'E') // read the exponent part 01703 { 01704 ptr++; 01705 01706 // read the sign of the exponent 01707 if(*ptr == '+') 01708 ptr++; 01709 else if(*ptr == '-') 01710 { 01711 ptr++; 01712 expsign = -1; 01713 } 01714 01715 exponent = 0; 01716 while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9') 01717 { 01718 exponent *= 10; 01719 exponent += *ptr - '0'; 01720 ptr++; 01721 } 01722 } 01723 01724 number = integer + decimal; 01725 number *= sign * pow(10.0, expsign * exponent); 01726 01727 // skip the following space 01728 if(*ptr == ' ') 01729 ptr++; 01730 01731 return ptr; 01732 } 01733 01734 void KSVGIconPainter::drawPath(const TQString &data, bool filled) 01735 { 01736 if (!data.isEmpty()) 01737 { 01738 TQString value = data; 01739 01740 TQMemArray<ArtBpath> vec; 01741 int index = -1; 01742 01743 double curx = 0.0, cury = 0.0, contrlx = 0.0, contrly = 0.0, xc, yc; 01744 unsigned int lastCommand = 0; 01745 01746 TQCString _d = value.replace(",", " ").simplifyWhiteSpace().latin1(); 01747 const char *ptr = _d.data(); 01748 const char *end = _d.data() + _d.length(); 01749 01750 double tox, toy, x1, y1, x2, y2, rx, ry, angle; 01751 bool largeArc, sweep; 01752 char command = *ptr; 01753 01754 while(ptr < end) 01755 { 01756 01757 if(*ptr == '+' || *ptr == '-' || *ptr == '.' || (*ptr >= '0' && *ptr <= '9')) 01758 { 01759 // there are still coords in this command 01760 if(command == 'M') 01761 { 01762 command = 'L'; 01763 } 01764 else if(command == 'm') 01765 { 01766 command = 'l'; 01767 } 01768 } 01769 else 01770 { 01771 command = *(ptr++); 01772 } 01773 01774 if(*ptr == ' ') 01775 ptr++; 01776 01777 switch(command) 01778 { 01779 case 'm': 01780 ptr = getCoord(ptr, tox); 01781 ptr = getCoord(ptr, toy); 01782 01783 if(index != -1 && lastCommand != 'z') 01784 { 01785 // Find last subpath 01786 int find = -1; 01787 for(int i = index; i >= 0; i--) 01788 { 01789 if(vec[i].code == ART_MOVETO_OPEN || vec[i].code == ART_MOVETO) 01790 { 01791 find = i; 01792 break; 01793 } 01794 } 01795 01796 index++; 01797 01798 if(vec.size() == (unsigned int) index) 01799 vec.resize(index + 1); 01800 01801 vec[index].code = (ArtPathcode)ART_END2; 01802 vec[index].x3 = vec[find].x3; 01803 vec[index].y3 = vec[find].y3; 01804 } 01805 01806 curx += tox; 01807 cury += toy; 01808 01809 index++; 01810 01811 d->helper->ensureSpace(vec, index); 01812 01813 vec[index].code = (index == 0) ? ART_MOVETO : ART_MOVETO_OPEN; 01814 vec[index].x3 = curx; 01815 vec[index].y3 = cury; 01816 01817 lastCommand = 'm'; 01818 break; 01819 case 'M': 01820 ptr = getCoord(ptr, tox); 01821 ptr = getCoord(ptr, toy); 01822 if(index != -1 && lastCommand != 'z') 01823 { 01824 // Find last subpath 01825 int find = -1; 01826 for(int i = index; i >= 0; i--) 01827 { 01828 if(vec[i].code == ART_MOVETO_OPEN || vec[i].code == ART_MOVETO) 01829 { 01830 find = i; 01831 break; 01832 } 01833 } 01834 01835 index++; 01836 01837 if(vec.size() == (unsigned int) index) 01838 vec.resize(index + 1); 01839 01840 vec[index].code = (ArtPathcode)ART_END2; 01841 vec[index].x3 = vec[find].x3; 01842 vec[index].y3 = vec[find].y3; 01843 } 01844 01845 curx = tox; 01846 cury = toy; 01847 01848 index++; 01849 01850 d->helper->ensureSpace(vec, index); 01851 01852 vec[index].code = (index == 0) ? ART_MOVETO : ART_MOVETO_OPEN; 01853 vec[index].x3 = curx; 01854 vec[index].y3 = cury; 01855 01856 lastCommand = 'M'; 01857 break; 01858 case 'l': 01859 ptr = getCoord(ptr, tox); 01860 ptr = getCoord(ptr, toy); 01861 01862 index++; 01863 01864 d->helper->ensureSpace(vec, index); 01865 01866 vec[index].code = ART_LINETO; 01867 vec[index].x3 = curx + tox; 01868 vec[index].y3 = cury + toy; 01869 01870 curx += tox; 01871 cury += toy; 01872 01873 lastCommand = 'l'; 01874 break; 01875 case 'L': 01876 ptr = getCoord(ptr, tox); 01877 ptr = getCoord(ptr, toy); 01878 01879 index++; 01880 01881 d->helper->ensureSpace(vec, index); 01882 01883 vec[index].code = ART_LINETO; 01884 vec[index].x3 = tox; 01885 vec[index].y3 = toy; 01886 01887 curx = tox; 01888 cury = toy; 01889 01890 lastCommand = 'L'; 01891 break; 01892 case 'h': 01893 ptr = getCoord(ptr, tox); 01894 01895 index++; 01896 01897 curx += tox; 01898 01899 d->helper->ensureSpace(vec, index); 01900 01901 vec[index].code = ART_LINETO; 01902 vec[index].x3 = curx; 01903 vec[index].y3 = cury; 01904 01905 lastCommand = 'h'; 01906 break; 01907 case 'H': 01908 ptr = getCoord(ptr, tox); 01909 01910 index++; 01911 01912 curx = tox; 01913 01914 d->helper->ensureSpace(vec, index); 01915 01916 vec[index].code = ART_LINETO; 01917 vec[index].x3 = curx; 01918 vec[index].y3 = cury; 01919 01920 lastCommand = 'H'; 01921 break; 01922 case 'v': 01923 ptr = getCoord(ptr, toy); 01924 01925 index++; 01926 01927 cury += toy; 01928 01929 d->helper->ensureSpace(vec, index); 01930 01931 vec[index].code = ART_LINETO; 01932 vec[index].x3 = curx; 01933 vec[index].y3 = cury; 01934 01935 lastCommand = 'v'; 01936 break; 01937 case 'V': 01938 ptr = getCoord(ptr, toy); 01939 01940 index++; 01941 01942 cury = toy; 01943 01944 d->helper->ensureSpace(vec, index); 01945 01946 vec[index].code = ART_LINETO; 01947 vec[index].x3 = curx; 01948 vec[index].y3 = cury; 01949 01950 lastCommand = 'V'; 01951 break; 01952 case 'c': 01953 ptr = getCoord(ptr, x1); 01954 ptr = getCoord(ptr, y1); 01955 ptr = getCoord(ptr, x2); 01956 ptr = getCoord(ptr, y2); 01957 ptr = getCoord(ptr, tox); 01958 ptr = getCoord(ptr, toy); 01959 01960 index++; 01961 01962 d->helper->ensureSpace(vec, index); 01963 01964 vec[index].code = ART_CURVETO; 01965 vec[index].x1 = curx + x1; 01966 vec[index].y1 = cury + y1; 01967 vec[index].x2 = curx + x2; 01968 vec[index].y2 = cury + y2; 01969 vec[index].x3 = curx + tox; 01970 vec[index].y3 = cury + toy; 01971 01972 curx += tox; 01973 cury += toy; 01974 01975 contrlx = vec[index].x2; 01976 contrly = vec[index].y2; 01977 01978 lastCommand = 'c'; 01979 break; 01980 case 'C': 01981 ptr = getCoord(ptr, x1); 01982 ptr = getCoord(ptr, y1); 01983 ptr = getCoord(ptr, x2); 01984 ptr = getCoord(ptr, y2); 01985 ptr = getCoord(ptr, tox); 01986 ptr = getCoord(ptr, toy); 01987 01988 index++; 01989 01990 d->helper->ensureSpace(vec, index); 01991 01992 vec[index].code = ART_CURVETO; 01993 vec[index].x1 = x1; 01994 vec[index].y1 = y1; 01995 vec[index].x2 = x2; 01996 vec[index].y2 = y2; 01997 vec[index].x3 = tox; 01998 vec[index].y3 = toy; 01999 02000 curx = vec[index].x3; 02001 cury = vec[index].y3; 02002 contrlx = vec[index].x2; 02003 contrly = vec[index].y2; 02004 02005 lastCommand = 'C'; 02006 break; 02007 case 's': 02008 ptr = getCoord(ptr, x2); 02009 ptr = getCoord(ptr, y2); 02010 ptr = getCoord(ptr, tox); 02011 ptr = getCoord(ptr, toy); 02012 02013 index++; 02014 02015 d->helper->ensureSpace(vec, index); 02016 02017 vec[index].code = ART_CURVETO; 02018 vec[index].x1 = 2 * curx - contrlx; 02019 vec[index].y1 = 2 * cury - contrly; 02020 vec[index].x2 = curx + x2; 02021 vec[index].y2 = cury + y2; 02022 vec[index].x3 = curx + tox; 02023 vec[index].y3 = cury + toy; 02024 02025 curx += tox; 02026 cury += toy; 02027 02028 contrlx = vec[index].x2; 02029 contrly = vec[index].y2; 02030 02031 lastCommand = 's'; 02032 break; 02033 case 'S': 02034 ptr = getCoord(ptr, x2); 02035 ptr = getCoord(ptr, y2); 02036 ptr = getCoord(ptr, tox); 02037 ptr = getCoord(ptr, toy); 02038 02039 index++; 02040 02041 d->helper->ensureSpace(vec, index); 02042 02043 vec[index].code = ART_CURVETO; 02044 vec[index].x1 = 2 * curx - contrlx; 02045 vec[index].y1 = 2 * cury - contrly; 02046 vec[index].x2 = x2; 02047 vec[index].y2 = y2; 02048 vec[index].x3 = tox; 02049 vec[index].y3 = toy; 02050 02051 curx = vec[index].x3; 02052 cury = vec[index].y3; 02053 contrlx = vec[index].x2; 02054 contrly = vec[index].y2; 02055 02056 lastCommand = 'S'; 02057 break; 02058 case 'q': 02059 ptr = getCoord(ptr, x1); 02060 ptr = getCoord(ptr, y1); 02061 ptr = getCoord(ptr, tox); 02062 ptr = getCoord(ptr, toy); 02063 02064 index++; 02065 02066 d->helper->ensureSpace(vec, index); 02067 02068 vec[index].code = ART_CURVETO; 02069 vec[index].x1 = (curx + 2 * (x1 + curx)) * (1.0 / 3.0); 02070 vec[index].y1 = (cury + 2 * (y1 + cury)) * (1.0 / 3.0); 02071 vec[index].x2 = ((curx + tox) + 2 * (x1 + curx)) * (1.0 / 3.0); 02072 vec[index].y2 = ((cury + toy) + 2 * (y1 + cury)) * (1.0 / 3.0); 02073 vec[index].x3 = curx + tox; 02074 vec[index].y3 = cury + toy; 02075 02076 contrlx = curx + x1; 02077 contrly = cury + y1; 02078 curx += tox; 02079 cury += toy; 02080 02081 lastCommand = 'q'; 02082 break; 02083 case 'Q': 02084 ptr = getCoord(ptr, x1); 02085 ptr = getCoord(ptr, y1); 02086 ptr = getCoord(ptr, tox); 02087 ptr = getCoord(ptr, toy); 02088 02089 index++; 02090 02091 d->helper->ensureSpace(vec, index); 02092 02093 // TODO : if this fails make it more like QuadraticRel 02094 vec[index].code = ART_CURVETO; 02095 vec[index].x1 = (curx + 2 * x1) * (1.0 / 3.0); 02096 vec[index].y1 = (cury + 2 * y1) * (1.0 / 3.0); 02097 vec[index].x2 = (tox + 2 * x1) * (1.0 / 3.0); 02098 vec[index].y2 = (toy + 2 * y1) * (1.0 / 3.0); 02099 vec[index].x3 = tox; 02100 vec[index].y3 = toy; 02101 02102 curx = vec[index].x3; 02103 cury = vec[index].y3; 02104 contrlx = vec[index].x2; 02105 contrly = vec[index].y2; 02106 02107 lastCommand = 'Q'; 02108 break; 02109 case 't': 02110 ptr = getCoord(ptr, tox); 02111 ptr = getCoord(ptr, toy); 02112 02113 xc = 2 * curx - contrlx; 02114 yc = 2 * cury - contrly; 02115 02116 index++; 02117 02118 d->helper->ensureSpace(vec, index); 02119 02120 vec[index].code = ART_CURVETO; 02121 vec[index].x1 = (curx + 2 * xc) * (1.0 / 3.0); 02122 vec[index].y1 = (cury + 2 * yc) * (1.0 / 3.0); 02123 vec[index].x2 = ((curx + tox) + 2 * xc) * (1.0 / 3.0); 02124 vec[index].y2 = ((cury + toy) + 2 * yc) * (1.0 / 3.0); 02125 02126 vec[index].x3 = curx + tox; 02127 vec[index].y3 = cury + toy; 02128 02129 curx += tox; 02130 cury += toy; 02131 contrlx = xc; 02132 contrly = yc; 02133 02134 lastCommand = 't'; 02135 break; 02136 case 'T': 02137 ptr = getCoord(ptr, tox); 02138 ptr = getCoord(ptr, toy); 02139 02140 xc = 2 * curx - contrlx; 02141 yc = 2 * cury - contrly; 02142 02143 index++; 02144 02145 d->helper->ensureSpace(vec, index); 02146 02147 vec[index].code = ART_CURVETO; 02148 vec[index].x1 = (curx + 2 * xc) * (1.0 / 3.0); 02149 vec[index].y1 = (cury + 2 * yc) * (1.0 / 3.0); 02150 vec[index].x2 = (tox + 2 * xc) * (1.0 / 3.0); 02151 vec[index].y2 = (toy + 2 * yc) * (1.0 / 3.0); 02152 vec[index].x3 = tox; 02153 vec[index].y3 = toy; 02154 02155 curx = tox; 02156 cury = toy; 02157 contrlx = xc; 02158 contrly = yc; 02159 02160 lastCommand = 'T'; 02161 break; 02162 case 'z': 02163 case 'Z': 02164 int find; 02165 find = -1; 02166 for(int i = index; i >= 0; i--) 02167 { 02168 if(vec[i].code == ART_MOVETO_OPEN || vec[i].code == ART_MOVETO) 02169 { 02170 find = i; 02171 break; 02172 } 02173 } 02174 02175 if(find != -1) 02176 { 02177 if(vec[find].x3 != curx || vec[find].y3 != cury) 02178 { 02179 index++; 02180 02181 d->helper->ensureSpace(vec, index); 02182 02183 vec[index].code = ART_LINETO; 02184 vec[index].x3 = vec[find].x3; 02185 vec[index].y3 = vec[find].y3; 02186 } 02187 } 02188 02189 // reset for next (sub)path 02190 curx = vec[find].x3; 02191 cury = vec[find].y3; 02192 02193 lastCommand = 'z'; 02194 break; 02195 case 'a': 02196 ptr = getCoord(ptr, rx); 02197 ptr = getCoord(ptr, ry); 02198 ptr = getCoord(ptr, angle); 02199 // 'largeArc' and 'sweep' are single digit flags. Some non conforming svg files do not 02200 // separate those fields with separators, so we can't use getCoord() here. 02201 // See TDE/tde issue #46 on TGW 02202 largeArc = ((*ptr++) != '0'); 02203 while (*ptr == ' ') 02204 { 02205 ptr++; 02206 } 02207 sweep = ((*ptr++) != '0'); 02208 while (*ptr == ' ') 02209 { 02210 ptr++; 02211 } 02212 ptr = getCoord(ptr, tox); 02213 ptr = getCoord(ptr, toy); 02214 02215 // Spec: radii are nonnegative numbers 02216 rx = fabs(rx); 02217 ry = fabs(ry); 02218 02219 d->helper->calculateArc(true, vec, index, curx, cury, angle, tox, toy, rx, ry, largeArc, sweep); 02220 02221 lastCommand = 'a'; 02222 break; 02223 case 'A': 02224 ptr = getCoord(ptr, rx); 02225 ptr = getCoord(ptr, ry); 02226 ptr = getCoord(ptr, angle); 02227 // 'largeArc' and 'sweep' are single digit flags. Some non conforming svg files do not 02228 // separate those fields with separators, so we can't use getCoord() here. 02229 // See TDE/tde issue #46 on TGW 02230 largeArc = ((*ptr++) != '0'); 02231 while (*ptr == ' ') 02232 { 02233 ptr++; 02234 } 02235 sweep = ((*ptr++) != '0'); 02236 while (*ptr == ' ') 02237 { 02238 ptr++; 02239 } 02240 ptr = getCoord(ptr, tox); 02241 ptr = getCoord(ptr, toy); 02242 02243 // Spec: radii are nonnegative numbers 02244 rx = fabs(rx); 02245 ry = fabs(ry); 02246 02247 d->helper->calculateArc(false, vec, index, curx, cury, angle, tox, toy, rx, ry, largeArc, sweep); 02248 02249 lastCommand = 'A'; 02250 break; 02251 } 02252 02253 // Detect reflection points 02254 if(lastCommand != 'C' && lastCommand != 'c' && 02255 lastCommand != 'S' && lastCommand != 's' && 02256 lastCommand != 'Q' && lastCommand != 'q' && 02257 lastCommand != 'T' && lastCommand != 't') 02258 { 02259 contrlx = curx; 02260 contrly = cury; 02261 } 02262 } 02263 02264 // Find last subpath 02265 int find = -1; 02266 for(int i = index; i >= 0; i--) 02267 { 02268 if(vec[i].code == ART_MOVETO_OPEN || vec[i].code == ART_MOVETO) 02269 { 02270 find = i; 02271 break; 02272 } 02273 } 02274 02275 // Fix a problem where the .svg file used doubles as values... (sofico.svg) 02276 if(curx != vec[find].x3 && cury != vec[find].y3) 02277 { 02278 if((int) curx == (int) vec[find].x3 && (int) cury == (int) vec[find].y3) 02279 { 02280 index++; 02281 02282 if(vec.size() == (unsigned int) index) 02283 vec.resize(index + 1); 02284 02285 vec[index].code = ART_LINETO; 02286 vec[index].x3 = vec[find].x3; 02287 vec[index].y3 = vec[find].y3; 02288 02289 curx = vec[find].x3; 02290 cury = vec[find].y3; 02291 } 02292 } 02293 02294 // Handle filled paths that are not closed explicitly 02295 if(filled) 02296 { 02297 if((int) curx != (int) vec[find].x3 || (int) cury != (int) vec[find].y3) 02298 { 02299 index++; 02300 02301 if(vec.size() == (unsigned int) index) 02302 vec.resize(index + 1); 02303 02304 vec[index].code = (ArtPathcode)ART_END2; 02305 vec[index].x3 = vec[find].x3; 02306 vec[index].y3 = vec[find].y3; 02307 02308 curx = vec[find].x3; 02309 cury = vec[find].y3; 02310 } 02311 } 02312 02313 // Close 02314 index++; 02315 02316 if(vec.size() == (unsigned int) index) 02317 vec.resize(index + 1); 02318 02319 vec[index].code = ART_END; 02320 02321 // There are pure-moveto paths which reference paint servers *bah* 02322 // Do NOT render them 02323 bool render = false; 02324 for(int i = index; i >= 0; i--) 02325 { 02326 if(vec[i].code != ART_MOVETO_OPEN && vec[i].code != ART_MOVETO && !(vec[i].code >= ART_END)) 02327 { 02328 render = true; 02329 break; 02330 } 02331 } 02332 02333 if(render) 02334 d->helper->drawBPath(vec.data()); 02335 } 02336 } 02337 02338 void KSVGIconPainter::drawImage(double x, double y, TQImage &image) 02339 { 02340 if(image.depth() != 32) 02341 image = image.convertDepth(32); 02342 02343 double affine[6]; 02344 affine[0] = d->helper->m_worldMatrix->m11(); 02345 affine[1] = d->helper->m_worldMatrix->m12(); 02346 affine[2] = d->helper->m_worldMatrix->m21(); 02347 affine[3] = d->helper->m_worldMatrix->m22(); 02348 // use the world matrix to convert the coordinates 02349 d->helper->m_worldMatrix->map(x, y, &affine[4], &affine[5]); 02350 02351 d->helper->art_rgba_rgba_affine(d->helper->m_buffer, 0, 0, d->helper->m_width, d->helper->m_height, 02352 d->helper->m_rowstride, image.bits(), image.width(), image.height(), 02353 image.width() * 4, affine); 02354 } 02355 02356 TQColor KSVGIconPainter::parseColor(const TQString ¶m) 02357 { 02358 if(param.stripWhiteSpace().startsWith("#")) 02359 { 02360 TQColor color; 02361 color.setNamedColor(param.stripWhiteSpace()); 02362 return color; 02363 } 02364 else if(param.stripWhiteSpace().startsWith("rgb(")) 02365 { 02366 TQString parse = param.stripWhiteSpace(); 02367 TQStringList colors = TQStringList::split(',', parse); 02368 TQString r = colors[0].right((colors[0].length() - 4)); 02369 TQString g = colors[1]; 02370 TQString b = colors[2].left((colors[2].length() - 1)); 02371 02372 if(r.contains("%")) 02373 { 02374 r = r.left(r.length() - 1); 02375 r = TQString::number(int((double(255 * r.toDouble()) / 100.0))); 02376 } 02377 02378 if(g.contains("%")) 02379 { 02380 g = g.left(g.length() - 1); 02381 g = TQString::number(int((double(255 * g.toDouble()) / 100.0))); 02382 } 02383 02384 if(b.contains("%")) 02385 { 02386 b = b.left(b.length() - 1); 02387 b = TQString::number(int((double(255 * b.toDouble()) / 100.0))); 02388 } 02389 02390 return TQColor(r.toInt(), g.toInt(), b.toInt()); 02391 } 02392 else 02393 { 02394 TQString rgbColor = param.stripWhiteSpace(); 02395 02396 if(rgbColor == "aliceblue") 02397 return TQColor(240, 248, 255); 02398 else if(rgbColor == "antiquewhite") 02399 return TQColor(250, 235, 215); 02400 else if(rgbColor == "aqua") 02401 return TQColor(0, 255, 255); 02402 else if(rgbColor == "aquamarine") 02403 return TQColor(127, 255, 212); 02404 else if(rgbColor == "azure") 02405 return TQColor(240, 255, 255); 02406 else if(rgbColor == "beige") 02407 return TQColor(245, 245, 220); 02408 else if(rgbColor == "bisque") 02409 return TQColor(255, 228, 196); 02410 else if(rgbColor == "black") 02411 return TQColor(0, 0, 0); 02412 else if(rgbColor == "blanchedalmond") 02413 return TQColor(255, 235, 205); 02414 else if(rgbColor == "blue") 02415 return TQColor(0, 0, 255); 02416 else if(rgbColor == "blueviolet") 02417 return TQColor(138, 43, 226); 02418 else if(rgbColor == "brown") 02419 return TQColor(165, 42, 42); 02420 else if(rgbColor == "burlywood") 02421 return TQColor(222, 184, 135); 02422 else if(rgbColor == "cadetblue") 02423 return TQColor(95, 158, 160); 02424 else if(rgbColor == "chartreuse") 02425 return TQColor(127, 255, 0); 02426 else if(rgbColor == "chocolate") 02427 return TQColor(210, 105, 30); 02428 else if(rgbColor == "coral") 02429 return TQColor(255, 127, 80); 02430 else if(rgbColor == "cornflowerblue") 02431 return TQColor(100, 149, 237); 02432 else if(rgbColor == "cornsilk") 02433 return TQColor(255, 248, 220); 02434 else if(rgbColor == "crimson") 02435 return TQColor(220, 20, 60); 02436 else if(rgbColor == "cyan") 02437 return TQColor(0, 255, 255); 02438 else if(rgbColor == "darkblue") 02439 return TQColor(0, 0, 139); 02440 else if(rgbColor == "darkcyan") 02441 return TQColor(0, 139, 139); 02442 else if(rgbColor == "darkgoldenrod") 02443 return TQColor(184, 134, 11); 02444 else if(rgbColor == "darkgray") 02445 return TQColor(169, 169, 169); 02446 else if(rgbColor == "darkgrey") 02447 return TQColor(169, 169, 169); 02448 else if(rgbColor == "darkgreen") 02449 return TQColor(0, 100, 0); 02450 else if(rgbColor == "darkkhaki") 02451 return TQColor(189, 183, 107); 02452 else if(rgbColor == "darkmagenta") 02453 return TQColor(139, 0, 139); 02454 else if(rgbColor == "darkolivegreen") 02455 return TQColor(85, 107, 47); 02456 else if(rgbColor == "darkorange") 02457 return TQColor(255, 140, 0); 02458 else if(rgbColor == "darkorchid") 02459 return TQColor(153, 50, 204); 02460 else if(rgbColor == "darkred") 02461 return TQColor(139, 0, 0); 02462 else if(rgbColor == "darksalmon") 02463 return TQColor(233, 150, 122); 02464 else if(rgbColor == "darkseagreen") 02465 return TQColor(143, 188, 143); 02466 else if(rgbColor == "darkslateblue") 02467 return TQColor(72, 61, 139); 02468 else if(rgbColor == "darkslategray") 02469 return TQColor(47, 79, 79); 02470 else if(rgbColor == "darkslategrey") 02471 return TQColor(47, 79, 79); 02472 else if(rgbColor == "darkturquoise") 02473 return TQColor(0, 206, 209); 02474 else if(rgbColor == "darkviolet") 02475 return TQColor(148, 0, 211); 02476 else if(rgbColor == "deeppink") 02477 return TQColor(255, 20, 147); 02478 else if(rgbColor == "deepskyblue") 02479 return TQColor(0, 191, 255); 02480 else if(rgbColor == "dimgray") 02481 return TQColor(105, 105, 105); 02482 else if(rgbColor == "dimgrey") 02483 return TQColor(105, 105, 105); 02484 else if(rgbColor == "dodgerblue") 02485 return TQColor(30, 144, 255); 02486 else if(rgbColor == "firebrick") 02487 return TQColor(178, 34, 34); 02488 else if(rgbColor == "floralwhite") 02489 return TQColor(255, 250, 240); 02490 else if(rgbColor == "forestgreen") 02491 return TQColor(34, 139, 34); 02492 else if(rgbColor == "fuchsia") 02493 return TQColor(255, 0, 255); 02494 else if(rgbColor == "gainsboro") 02495 return TQColor(220, 220, 220); 02496 else if(rgbColor == "ghostwhite") 02497 return TQColor(248, 248, 255); 02498 else if(rgbColor == "gold") 02499 return TQColor(255, 215, 0); 02500 else if(rgbColor == "goldenrod") 02501 return TQColor(218, 165, 32); 02502 else if(rgbColor == "gray") 02503 return TQColor(128, 128, 128); 02504 else if(rgbColor == "grey") 02505 return TQColor(128, 128, 128); 02506 else if(rgbColor == "green") 02507 return TQColor(0, 128, 0); 02508 else if(rgbColor == "greenyellow") 02509 return TQColor(173, 255, 47); 02510 else if(rgbColor == "honeydew") 02511 return TQColor(240, 255, 240); 02512 else if(rgbColor == "hotpink") 02513 return TQColor(255, 105, 180); 02514 else if(rgbColor == "indianred") 02515 return TQColor(205, 92, 92); 02516 else if(rgbColor == "indigo") 02517 return TQColor(75, 0, 130); 02518 else if(rgbColor == "ivory") 02519 return TQColor(255, 255, 240); 02520 else if(rgbColor == "khaki") 02521 return TQColor(240, 230, 140); 02522 else if(rgbColor == "lavender") 02523 return TQColor(230, 230, 250); 02524 else if(rgbColor == "lavenderblush") 02525 return TQColor(255, 240, 245); 02526 else if(rgbColor == "lawngreen") 02527 return TQColor(124, 252, 0); 02528 else if(rgbColor == "lemonchiffon") 02529 return TQColor(255, 250, 205); 02530 else if(rgbColor == "lightblue") 02531 return TQColor(173, 216, 230); 02532 else if(rgbColor == "lightcoral") 02533 return TQColor(240, 128, 128); 02534 else if(rgbColor == "lightcyan") 02535 return TQColor(224, 255, 255); 02536 else if(rgbColor == "lightgoldenrodyellow") 02537 return TQColor(250, 250, 210); 02538 else if(rgbColor == "lightgray") 02539 return TQColor(211, 211, 211); 02540 else if(rgbColor == "lightgrey") 02541 return TQColor(211, 211, 211); 02542 else if(rgbColor == "lightgreen") 02543 return TQColor(144, 238, 144); 02544 else if(rgbColor == "lightpink") 02545 return TQColor(255, 182, 193); 02546 else if(rgbColor == "lightsalmon") 02547 return TQColor(255, 160, 122); 02548 else if(rgbColor == "lightseagreen") 02549 return TQColor(32, 178, 170); 02550 else if(rgbColor == "lightskyblue") 02551 return TQColor(135, 206, 250); 02552 else if(rgbColor == "lightslategray") 02553 return TQColor(119, 136, 153); 02554 else if(rgbColor == "lightslategrey") 02555 return TQColor(119, 136, 153); 02556 else if(rgbColor == "lightsteelblue") 02557 return TQColor(176, 196, 222); 02558 else if(rgbColor == "lightyellow") 02559 return TQColor(255, 255, 224); 02560 else if(rgbColor == "lime") 02561 return TQColor(0, 255, 0); 02562 else if(rgbColor == "limegreen") 02563 return TQColor(50, 205, 50); 02564 else if(rgbColor == "linen") 02565 return TQColor(250, 240, 230); 02566 else if(rgbColor == "magenta") 02567 return TQColor(255, 0, 255); 02568 else if(rgbColor == "maroon") 02569 return TQColor(128, 0, 0); 02570 else if(rgbColor == "mediumaquamarine") 02571 return TQColor(102, 205, 170); 02572 else if(rgbColor == "mediumblue") 02573 return TQColor(0, 0, 205); 02574 else if(rgbColor == "mediumorchid") 02575 return TQColor(186, 85, 211); 02576 else if(rgbColor == "mediumpurple") 02577 return TQColor(147, 112, 219); 02578 else if(rgbColor == "mediumseagreen") 02579 return TQColor(60, 179, 113); 02580 else if(rgbColor == "mediumslateblue") 02581 return TQColor(123, 104, 238); 02582 else if(rgbColor == "mediumspringgreen") 02583 return TQColor(0, 250, 154); 02584 else if(rgbColor == "mediumturquoise") 02585 return TQColor(72, 209, 204); 02586 else if(rgbColor == "mediumvioletred") 02587 return TQColor(199, 21, 133); 02588 else if(rgbColor == "midnightblue") 02589 return TQColor(25, 25, 112); 02590 else if(rgbColor == "mintcream") 02591 return TQColor(245, 255, 250); 02592 else if(rgbColor == "mistyrose") 02593 return TQColor(255, 228, 225); 02594 else if(rgbColor == "moccasin") 02595 return TQColor(255, 228, 181); 02596 else if(rgbColor == "navajowhite") 02597 return TQColor(255, 222, 173); 02598 else if(rgbColor == "navy") 02599 return TQColor(0, 0, 128); 02600 else if(rgbColor == "oldlace") 02601 return TQColor(253, 245, 230); 02602 else if(rgbColor == "olive") 02603 return TQColor(128, 128, 0); 02604 else if(rgbColor == "olivedrab") 02605 return TQColor(107, 142, 35); 02606 else if(rgbColor == "orange") 02607 return TQColor(255, 165, 0); 02608 else if(rgbColor == "orangered") 02609 return TQColor(255, 69, 0); 02610 else if(rgbColor == "orchid") 02611 return TQColor(218, 112, 214); 02612 else if(rgbColor == "palegoldenrod") 02613 return TQColor(238, 232, 170); 02614 else if(rgbColor == "palegreen") 02615 return TQColor(152, 251, 152); 02616 else if(rgbColor == "paleturquoise") 02617 return TQColor(175, 238, 238); 02618 else if(rgbColor == "palevioletred") 02619 return TQColor(219, 112, 147); 02620 else if(rgbColor == "papayawhip") 02621 return TQColor(255, 239, 213); 02622 else if(rgbColor == "peachpuff") 02623 return TQColor(255, 218, 185); 02624 else if(rgbColor == "peru") 02625 return TQColor(205, 133, 63); 02626 else if(rgbColor == "pink") 02627 return TQColor(255, 192, 203); 02628 else if(rgbColor == "plum") 02629 return TQColor(221, 160, 221); 02630 else if(rgbColor == "powderblue") 02631 return TQColor(176, 224, 230); 02632 else if(rgbColor == "purple") 02633 return TQColor(128, 0, 128); 02634 else if(rgbColor == "red") 02635 return TQColor(255, 0, 0); 02636 else if(rgbColor == "rosybrown") 02637 return TQColor(188, 143, 143); 02638 else if(rgbColor == "royalblue") 02639 return TQColor(65, 105, 225); 02640 else if(rgbColor == "saddlebrown") 02641 return TQColor(139, 69, 19); 02642 else if(rgbColor == "salmon") 02643 return TQColor(250, 128, 114); 02644 else if(rgbColor == "sandybrown") 02645 return TQColor(244, 164, 96); 02646 else if(rgbColor == "seagreen") 02647 return TQColor(46, 139, 87); 02648 else if(rgbColor == "seashell") 02649 return TQColor(255, 245, 238); 02650 else if(rgbColor == "sienna") 02651 return TQColor(160, 82, 45); 02652 else if(rgbColor == "silver") 02653 return TQColor(192, 192, 192); 02654 else if(rgbColor == "skyblue") 02655 return TQColor(135, 206, 235); 02656 else if(rgbColor == "slateblue") 02657 return TQColor(106, 90, 205); 02658 else if(rgbColor == "slategray") 02659 return TQColor(112, 128, 144); 02660 else if(rgbColor == "slategrey") 02661 return TQColor(112, 128, 144); 02662 else if(rgbColor == "snow") 02663 return TQColor(255, 250, 250); 02664 else if(rgbColor == "springgreen") 02665 return TQColor(0, 255, 127); 02666 else if(rgbColor == "steelblue") 02667 return TQColor(70, 130, 180); 02668 else if(rgbColor == "tan") 02669 return TQColor(210, 180, 140); 02670 else if(rgbColor == "teal") 02671 return TQColor(0, 128, 128); 02672 else if(rgbColor == "thistle") 02673 return TQColor(216, 191, 216); 02674 else if(rgbColor == "tomato") 02675 return TQColor(255, 99, 71); 02676 else if(rgbColor == "turquoise") 02677 return TQColor(64, 224, 208); 02678 else if(rgbColor == "violet") 02679 return TQColor(238, 130, 238); 02680 else if(rgbColor == "wheat") 02681 return TQColor(245, 222, 179); 02682 else if(rgbColor == "white") 02683 return TQColor(255, 255, 255); 02684 else if(rgbColor == "whitesmoke") 02685 return TQColor(245, 245, 245); 02686 else if(rgbColor == "yellow") 02687 return TQColor(255, 255, 0); 02688 else if(rgbColor == "yellowgreen") 02689 return TQColor(154, 205, 50); 02690 } 02691 02692 return TQColor(); 02693 } 02694 02695 double KSVGIconPainter::dpi() 02696 { 02697 return 90.0; // TODO: make modal? 02698 } 02699 02700 double KSVGIconPainter::toPixel(const TQString &s, bool hmode) 02701 { 02702 if(s.isEmpty()) 02703 return 0.0; 02704 02705 TQString check = s; 02706 02707 double ret = 0.0; 02708 02709 double value = 0; 02710 const char *start = check.latin1(); 02711 const char *end = getCoord(start, value); 02712 02713 if(uint(end - start) < check.length()) 02714 { 02715 if(check.endsWith("px")) 02716 ret = value; 02717 else if(check.endsWith("cm")) 02718 ret = (value / 2.54) * dpi(); 02719 else if(check.endsWith("pc")) 02720 ret = (value / 6.0) * dpi(); 02721 else if(check.endsWith("mm")) 02722 ret = (value / 25.4) * dpi(); 02723 else if(check.endsWith("in")) 02724 ret = value * dpi(); 02725 else if(check.endsWith("pt")) 02726 ret = (value / 72.0) * dpi(); 02727 else if(check.endsWith("%")) 02728 { 02729 ret = value / 100.0; 02730 02731 if(hmode) 02732 ret *= d->drawWidth; 02733 else 02734 ret *= d->drawHeight; 02735 } 02736 else if(check.endsWith("em")) 02737 { 02738 ret = value * 10.0; // TODO make this depend on actual font size 02739 } 02740 } 02741 else 02742 ret = value; 02743 02744 return ret; 02745 } 02746 02747 ArtGradientLinear *KSVGIconPainter::linearGradient(const TQString &id) 02748 { 02749 return d->helper->m_linearGradientMap[id]; 02750 } 02751 02752 void KSVGIconPainter::addLinearGradient(const TQString &id, ArtGradientLinear *gradient) 02753 { 02754 d->helper->m_linearGradientMap.insert(id, gradient); 02755 } 02756 02757 TQDomElement KSVGIconPainter::linearGradientElement(ArtGradientLinear *linear) 02758 { 02759 return d->helper->m_linearGradientElementMap[linear]; 02760 } 02761 02762 void KSVGIconPainter::addLinearGradientElement(ArtGradientLinear *gradient, TQDomElement element) 02763 { 02764 d->helper->m_linearGradientElementMap.insert(gradient, element); 02765 } 02766 02767 ArtGradientRadial *KSVGIconPainter::radialGradient(const TQString &id) 02768 { 02769 return d->helper->m_radialGradientMap[id]; 02770 } 02771 02772 void KSVGIconPainter::addRadialGradient(const TQString &id, ArtGradientRadial *gradient) 02773 { 02774 d->helper->m_radialGradientMap.insert(id, gradient); 02775 } 02776 02777 TQDomElement KSVGIconPainter::radialGradientElement(ArtGradientRadial *radial) 02778 { 02779 return d->helper->m_radialGradientElementMap[radial]; 02780 } 02781 02782 void KSVGIconPainter::addRadialGradientElement(ArtGradientRadial *gradient, TQDomElement element) 02783 { 02784 d->helper->m_radialGradientElementMap.insert(gradient, element); 02785 } 02786 02787 TQ_UINT32 KSVGIconPainter::toArtColor(const TQColor &color) 02788 { 02789 return d->helper->toArtColor(color); 02790 } 02791 02792 TQWMatrix KSVGIconPainter::parseTransform(const TQString &transform) 02793 { 02794 TQWMatrix result; 02795 02796 // Split string for handling 1 transform statement at a time 02797 TQStringList subtransforms = TQStringList::split(')', transform); 02798 TQStringList::ConstIterator it = subtransforms.begin(); 02799 TQStringList::ConstIterator end = subtransforms.end(); 02800 for(; it != end; ++it) 02801 { 02802 TQStringList subtransform = TQStringList::split('(', (*it)); 02803 02804 subtransform[0] = subtransform[0].stripWhiteSpace().lower(); 02805 subtransform[1] = subtransform[1].simplifyWhiteSpace(); 02806 TQRegExp reg("([-]?\\d*\\.?\\d+(?:e[-]?\\d+)?)"); 02807 02808 int pos = 0; 02809 TQStringList params; 02810 02811 while(pos >= 0) 02812 { 02813 pos = reg.search(subtransform[1], pos); 02814 if(pos != -1) 02815 { 02816 params += reg.cap(1); 02817 pos += reg.matchedLength(); 02818 } 02819 } 02820 02821 if(subtransform[0].startsWith(";") || subtransform[0].startsWith(",")) 02822 subtransform[0] = subtransform[0].right(subtransform[0].length() - 1); 02823 02824 if(subtransform[0] == "rotate") 02825 { 02826 if(params.count() == 3) 02827 { 02828 double x = params[1].toDouble(); 02829 double y = params[2].toDouble(); 02830 02831 result.translate(x, y); 02832 result.rotate(params[0].toDouble()); 02833 result.translate(-x, -y); 02834 } 02835 else 02836 result.rotate(params[0].toDouble()); 02837 } 02838 else if(subtransform[0] == "translate") 02839 { 02840 if(params.count() == 2) 02841 result.translate(params[0].toDouble(), params[1].toDouble()); 02842 else // Spec : if only one param given, assume 2nd param to be 0 02843 result.translate(params[0].toDouble() , 0); 02844 } 02845 else if(subtransform[0] == "scale") 02846 { 02847 if(params.count() == 2) 02848 result.scale(params[0].toDouble(), params[1].toDouble()); 02849 else // Spec : if only one param given, assume uniform scaling 02850 result.scale(params[0].toDouble(), params[0].toDouble()); 02851 } 02852 else if(subtransform[0] == "skewx") 02853 result.shear(tan(params[0].toDouble() * deg2rad), 0.0F); 02854 else if(subtransform[0] == "skewy") 02855 result.shear(tan(params[0].toDouble() * deg2rad), 0.0F); 02856 else if(subtransform[0] == "skewy") 02857 result.shear(0.0F, tan(params[0].toDouble() * deg2rad)); 02858 else if(subtransform[0] == "matrix") 02859 { 02860 if(params.count() >= 6) 02861 { 02862 result.setMatrix(params[0].toDouble(), params[1].toDouble(), params[2].toDouble(), params[3].toDouble(), params[4].toDouble(), params[5].toDouble()); 02863 } 02864 } 02865 } 02866 02867 return result; 02868 }