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 TQRgb *sl = reinterpret_cast<TQRgb *>(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 sfactor_sq = 1.0 / d - 0.25; 00751 00752 if(sfactor_sq < 0) 00753 sfactor_sq = 0; 00754 00755 sfactor = sqrt(sfactor_sq); 00756 00757 if(sweepFlag == largeArcFlag) 00758 sfactor = -sfactor; 00759 00760 xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0); 00761 yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0); 00762 00763 /* (xc, yc) is center of the circle. */ 00764 th0 = atan2(y0 - yc, x0 - xc); 00765 th1 = atan2(y1 - yc, x1 - xc); 00766 00767 th_arc = th1 - th0; 00768 if(th_arc < 0 && sweepFlag) 00769 th_arc += 2 * M_PI; 00770 else if(th_arc > 0 && !sweepFlag) 00771 th_arc -= 2 * M_PI; 00772 00773 n_segs = (int) (int) ceil(fabs(th_arc / (M_PI * 0.5 + 0.001))); 00774 00775 for(i = 0; i < n_segs; i++) 00776 { 00777 index++; 00778 00779 ensureSpace(vec, index); 00780 00781 { 00782 double sin_th, cos_th; 00783 double a00, a01, a10, a11; 00784 double x1, y1, x2, y2, x3, y3; 00785 double t; 00786 double th_half; 00787 00788 double _th0 = th0 + i * th_arc / n_segs; 00789 double _th1 = th0 + (i + 1) * th_arc / n_segs; 00790 00791 sin_th = sin(angle * (M_PI / 180.0)); 00792 cos_th = cos(angle * (M_PI / 180.0)); 00793 00794 /* inverse transform compared with rsvg_path_arc */ 00795 a00 = cos_th * r1; 00796 a01 = -sin_th * r2; 00797 a10 = sin_th * r1; 00798 a11 = cos_th * r2; 00799 00800 th_half = 0.5 * (_th1 - _th0); 00801 t = (8.0 / 3.0) * sin(th_half * 0.5) * sin(th_half * 0.5) / sin(th_half); 00802 x1 = xc + cos(_th0) - t * sin(_th0); 00803 y1 = yc + sin(_th0) + t * cos(_th0); 00804 x3 = xc + cos(_th1); 00805 y3 = yc + sin(_th1); 00806 x2 = x3 + t * sin(_th1); 00807 y2 = y3 - t * cos(_th1); 00808 00809 ensureSpace(vec, index); 00810 00811 vec[index].code = ART_CURVETO; 00812 vec[index].x1 = a00 * x1 + a01 * y1; 00813 vec[index].y1 = a10 * x1 + a11 * y1; 00814 vec[index].x2 = a00 * x2 + a01 * y2; 00815 vec[index].y2 = a10 * x2 + a11 * y2; 00816 vec[index].x3 = a00 * x3 + a01 * y3; 00817 vec[index].y3 = a10 * x3 + a11 * y3; 00818 } 00819 } 00820 00821 if(!relative) 00822 curx = x; 00823 else 00824 curx += x; 00825 00826 if(!relative) 00827 cury = y; 00828 else 00829 cury += y; 00830 } 00831 00832 // For any docs, see the libart library 00833 static void art_vpath_render_bez(ArtVpath **p_vpath, int *pn, int *pn_max, 00834 double x0, double y0, 00835 double x1, double y1, 00836 double x2, double y2, 00837 double x3, double y3, 00838 double flatness) 00839 { 00840 double x3_0, y3_0, z3_0_dot, z1_dot, z2_dot; 00841 double z1_perp, z2_perp, max_perp_sq; 00842 00843 double x_m, y_m, xa1, ya1, xa2, ya2, xb1, yb1, xb2, yb2; 00844 00845 x3_0 = x3 - x0; 00846 y3_0 = y3 - y0; 00847 00848 z3_0_dot = x3_0 * x3_0 + y3_0 * y3_0; 00849 00850 if (z3_0_dot < 0.001) 00851 goto nosubdivide; 00852 00853 max_perp_sq = flatness * flatness * z3_0_dot; 00854 00855 z1_perp = (y1 - y0) * x3_0 - (x1 - x0) * y3_0; 00856 if (z1_perp * z1_perp > max_perp_sq) 00857 goto subdivide; 00858 00859 z2_perp = (y3 - y2) * x3_0 - (x3 - x2) * y3_0; 00860 if (z2_perp * z2_perp > max_perp_sq) 00861 goto subdivide; 00862 00863 z1_dot = (x1 - x0) * x3_0 + (y1 - y0) * y3_0; 00864 if (z1_dot < 0 && z1_dot * z1_dot > max_perp_sq) 00865 goto subdivide; 00866 00867 z2_dot = (x3 - x2) * x3_0 + (y3 - y2) * y3_0; 00868 if (z2_dot < 0 && z2_dot * z2_dot > max_perp_sq) 00869 goto subdivide; 00870 00871 if (z1_dot + z1_dot > z3_0_dot) 00872 goto subdivide; 00873 00874 if (z2_dot + z2_dot > z3_0_dot) 00875 goto subdivide; 00876 00877 nosubdivide: 00878 art_vpath_add_point (p_vpath, pn, pn_max, ART_LINETO, x3, y3); 00879 return; 00880 00881 subdivide: 00882 xa1 = (x0 + x1) * 0.5; 00883 ya1 = (y0 + y1) * 0.5; 00884 xa2 = (x0 + 2 * x1 + x2) * 0.25; 00885 ya2 = (y0 + 2 * y1 + y2) * 0.25; 00886 xb1 = (x1 + 2 * x2 + x3) * 0.25; 00887 yb1 = (y1 + 2 * y2 + y3) * 0.25; 00888 xb2 = (x2 + x3) * 0.5; 00889 yb2 = (y2 + y3) * 0.5; 00890 x_m = (xa2 + xb1) * 0.5; 00891 y_m = (ya2 + yb1) * 0.5; 00892 art_vpath_render_bez (p_vpath, pn, pn_max, x0, y0, xa1, ya1, xa2, ya2, x_m, y_m, flatness); 00893 art_vpath_render_bez (p_vpath, pn, pn_max, x_m, y_m, xb1, yb1, xb2, yb2, x3, y3, flatness); 00894 } 00895 00896 ArtVpath *art_bez_path_to_vec(const ArtBpath *bez, double flatness) 00897 { 00898 ArtVpath *vec; 00899 int vec_n, vec_n_max; 00900 int bez_index; 00901 double x, y; 00902 00903 vec_n = 0; 00904 vec_n_max = (1 << 4); 00905 vec = art_new (ArtVpath, vec_n_max); 00906 00907 x = 0; 00908 y = 0; 00909 00910 bez_index = 0; 00911 do 00912 { 00913 if(vec_n >= vec_n_max) 00914 art_expand (vec, ArtVpath, vec_n_max); 00915 00916 switch (bez[bez_index].code) 00917 { 00918 case ART_MOVETO_OPEN: 00919 case ART_MOVETO: 00920 case ART_LINETO: 00921 x = bez[bez_index].x3; 00922 y = bez[bez_index].y3; 00923 vec[vec_n].code = bez[bez_index].code; 00924 vec[vec_n].x = x; 00925 vec[vec_n].y = y; 00926 vec_n++; 00927 break; 00928 case ART_END: 00929 vec[vec_n].code = ART_END; 00930 vec[vec_n].x = 0; 00931 vec[vec_n].y = 0; 00932 vec_n++; 00933 break; 00934 case ART_END2: 00935 vec[vec_n].code = (ArtPathcode)ART_END2; 00936 vec[vec_n].x = bez[bez_index].x3; 00937 vec[vec_n].y = bez[bez_index].y3; 00938 vec_n++; 00939 break; 00940 case ART_CURVETO: 00941 art_vpath_render_bez (&vec, &vec_n, &vec_n_max, 00942 x, y, 00943 bez[bez_index].x1, bez[bez_index].y1, 00944 bez[bez_index].x2, bez[bez_index].y2, 00945 bez[bez_index].x3, bez[bez_index].y3, 00946 flatness); 00947 x = bez[bez_index].x3; 00948 y = bez[bez_index].y3; 00949 break; 00950 } 00951 } 00952 00953 while (bez[bez_index++].code != ART_END); 00954 return vec; 00955 } 00956 00957 static void art_rgb_affine_run(int *p_x0, int *p_x1, int y, 00958 int src_width, int src_height, 00959 const double affine[6]) 00960 { 00961 int x0, x1; 00962 double z; 00963 double x_intercept; 00964 int xi; 00965 00966 x0 = *p_x0; 00967 x1 = *p_x1; 00968 00969 if (affine[0] > 1e-6) 00970 { 00971 z = affine[2] * (y + 0.5) + affine[4]; 00972 x_intercept = -z / affine[0]; 00973 xi = (int) (int) ceil (x_intercept + 1e-6 - 0.5); 00974 if (xi > x0) 00975 x0 = xi; 00976 x_intercept = (-z + src_width) / affine[0]; 00977 xi = (int) ceil (x_intercept - 1e-6 - 0.5); 00978 if (xi < x1) 00979 x1 = xi; 00980 } 00981 else if (affine[0] < -1e-6) 00982 { 00983 z = affine[2] * (y + 0.5) + affine[4]; 00984 x_intercept = (-z + src_width) / affine[0]; 00985 xi = (int) ceil (x_intercept + 1e-6 - 0.5); 00986 if (xi > x0) 00987 x0 = xi; 00988 x_intercept = -z / affine[0]; 00989 xi = (int) ceil (x_intercept - 1e-6 - 0.5); 00990 if (xi < x1) 00991 x1 = xi; 00992 } 00993 else 00994 { 00995 z = affine[2] * (y + 0.5) + affine[4]; 00996 if (z < 0 || z >= src_width) 00997 { 00998 *p_x1 = *p_x0; 00999 return; 01000 } 01001 } 01002 if (affine[1] > 1e-6) 01003 { 01004 z = affine[3] * (y + 0.5) + affine[5]; 01005 x_intercept = -z / affine[1]; 01006 xi = (int) ceil (x_intercept + 1e-6 - 0.5); 01007 if (xi > x0) 01008 x0 = xi; 01009 x_intercept = (-z + src_height) / affine[1]; 01010 xi = (int) ceil (x_intercept - 1e-6 - 0.5); 01011 if (xi < x1) 01012 x1 = xi; 01013 } 01014 else if (affine[1] < -1e-6) 01015 { 01016 z = affine[3] * (y + 0.5) + affine[5]; 01017 x_intercept = (-z + src_height) / affine[1]; 01018 xi = (int) ceil (x_intercept + 1e-6 - 0.5); 01019 if (xi > x0) 01020 x0 = xi; 01021 x_intercept = -z / affine[1]; 01022 xi = (int) ceil (x_intercept - 1e-6 - 0.5); 01023 if (xi < x1) 01024 x1 = xi; 01025 } 01026 else 01027 { 01028 z = affine[3] * (y + 0.5) + affine[5]; 01029 if (z < 0 || z >= src_height) 01030 { 01031 *p_x1 = *p_x0; 01032 return; 01033 } 01034 } 01035 01036 *p_x0 = x0; 01037 *p_x1 = x1; 01038 } 01039 01040 // Slightly modified version to support RGBA buffers, copied from gnome-print 01041 static void art_rgba_rgba_affine(art_u8 *dst, 01042 int x0, int y0, int x1, int y1, int dst_rowstride, 01043 const art_u8 *src, 01044 int src_width, int src_height, int src_rowstride, 01045 const double affine[6]) 01046 { 01047 int x, y; 01048 double inv[6]; 01049 art_u8 *dst_p, *dst_linestart; 01050 const art_u8 *src_p; 01051 ArtPoint pt, src_pt; 01052 int src_x, src_y; 01053 int alpha; 01054 art_u8 bg_r, bg_g, bg_b, bg_a, cr, cg, cb; 01055 art_u8 fg_r, fg_g, fg_b; 01056 int tmp; 01057 int run_x0, run_x1; 01058 01059 dst_linestart = dst; 01060 art_affine_invert (inv, affine); 01061 for (y = y0; y < y1; y++) 01062 { 01063 pt.y = y + 0.5; 01064 run_x0 = x0; 01065 run_x1 = x1; 01066 art_rgb_affine_run (&run_x0, &run_x1, y, src_width, src_height, 01067 inv); 01068 dst_p = dst_linestart + (run_x0 - x0) * 4; 01069 for (x = run_x0; x < run_x1; x++) 01070 { 01071 pt.x = x + 0.5; 01072 art_affine_point (&src_pt, &pt, inv); 01073 src_x = (int) floor (src_pt.x); 01074 src_y = (int) floor (src_pt.y); 01075 src_p = src + (src_y * src_rowstride) + src_x * 4; 01076 if (src_x >= 0 && src_x < src_width && 01077 src_y >= 0 && src_y < src_height) 01078 { 01079 01080 alpha = src_p[3]; 01081 if (alpha) 01082 { 01083 if (alpha == 255) 01084 { 01085 dst_p[0] = src_p[0]; 01086 dst_p[1] = src_p[1]; 01087 dst_p[2] = src_p[2]; 01088 dst_p[3] = 255; 01089 } 01090 else 01091 { 01092 bg_r = dst_p[0]; 01093 bg_g = dst_p[1]; 01094 bg_b = dst_p[2]; 01095 bg_a = dst_p[3]; 01096 01097 cr = (bg_r * bg_a + 0x80) >> 8; 01098 cg = (bg_g * bg_g + 0x80) >> 8; 01099 cb = (bg_b * bg_b + 0x80) >> 8; 01100 01101 tmp = (src_p[0] - bg_r) * alpha; 01102 fg_r = bg_r + ((tmp + (tmp >> 8) + 0x80) >> 8); 01103 tmp = (src_p[1] - bg_g) * alpha; 01104 fg_g = bg_g + ((tmp + (tmp >> 8) + 0x80) >> 8); 01105 tmp = (src_p[2] - bg_b) * alpha; 01106 fg_b = bg_b + ((tmp + (tmp >> 8) + 0x80) >> 8); 01107 01108 dst_p[0] = fg_r; 01109 dst_p[1] = fg_g; 01110 dst_p[2] = fg_b; 01111 dst_p[3] = bg_a + (((255 - bg_a) * alpha + 0x80) >> 8); 01112 } 01113 } 01114 } else { dst_p[0] = 255; dst_p[1] = 0; dst_p[2] = 0; dst_p[3] = 255;} 01115 dst_p += 4; 01116 } 01117 dst_linestart += dst_rowstride; 01118 } 01119 } 01120 01121 private: 01122 friend class KSVGIconPainter; 01123 ArtSVP *m_clipSVP; 01124 01125 TQImage *m_image; 01126 TQWMatrix *m_worldMatrix; 01127 01128 TQString m_fillRule; 01129 TQString m_joinStyle; 01130 TQString m_capStyle; 01131 01132 int m_strokeMiterLimit; 01133 01134 TQString m_dashes; 01135 unsigned short m_dashOffset; 01136 01137 TQColor m_fillColor; 01138 TQColor m_strokeColor; 01139 01140 art_u8 *m_buffer; 01141 art_u8 *m_tempBuffer; 01142 01143 int m_width; 01144 int m_height; 01145 01146 int m_rowstride; 01147 01148 double m_opacity; 01149 double m_fillOpacity; 01150 double m_strokeOpacity; 01151 01152 bool m_useFill; 01153 bool m_useStroke; 01154 01155 bool m_useFillGradient; 01156 bool m_useStrokeGradient; 01157 01158 TQString m_fillGradientReference; 01159 TQString m_strokeGradientReference; 01160 01161 TQMap<TQString, ArtGradientLinear *> m_linearGradientMap; 01162 TQMap<ArtGradientLinear *, TQDomElement> m_linearGradientElementMap; 01163 01164 TQMap<TQString, ArtGradientRadial *> m_radialGradientMap; 01165 TQMap<ArtGradientRadial *, TQDomElement> m_radialGradientElementMap; 01166 01167 KSVGIconPainter *m_painter; 01168 01169 double m_strokeWidth; 01170 }; 01171 01172 struct KSVGIconPainter::Private 01173 { 01174 KSVGIconPainterHelper *helper; 01175 01176 int drawWidth; 01177 int drawHeight; 01178 }; 01179 01180 KSVGIconPainter::KSVGIconPainter(int width, int height) : d(new Private()) 01181 { 01182 d->helper = new KSVGIconPainterHelper(width, height, this); 01183 01184 d->drawWidth = width; 01185 d->drawHeight = height; 01186 } 01187 01188 KSVGIconPainter::~KSVGIconPainter() 01189 { 01190 delete d->helper; 01191 delete d; 01192 } 01193 01194 void KSVGIconPainter::setDrawWidth(int dwidth) 01195 { 01196 d->drawWidth = dwidth; 01197 } 01198 01199 void KSVGIconPainter::setDrawHeight(int dheight) 01200 { 01201 d->drawHeight = dheight; 01202 } 01203 01204 void KSVGIconPainter::finish() 01205 { 01206 d->helper->blit(); 01207 } 01208 01209 TQImage *KSVGIconPainter::image() 01210 { 01211 return new TQImage(*d->helper->m_image); 01212 } 01213 01214 TQWMatrix *KSVGIconPainter::worldMatrix() 01215 { 01216 return d->helper->m_worldMatrix; 01217 } 01218 01219 void KSVGIconPainter::setWorldMatrix(TQWMatrix *matrix) 01220 { 01221 if(d->helper->m_worldMatrix) 01222 delete d->helper->m_worldMatrix; 01223 01224 d->helper->m_worldMatrix = matrix; 01225 } 01226 01227 void KSVGIconPainter::setStrokeWidth(double width) 01228 { 01229 d->helper->m_strokeWidth = width; 01230 } 01231 01232 void KSVGIconPainter::setStrokeMiterLimit(const TQString &miter) 01233 { 01234 d->helper->m_strokeMiterLimit = miter.toInt(); 01235 } 01236 01237 void KSVGIconPainter::setStrokeDashOffset(const TQString &dashOffset) 01238 { 01239 d->helper->m_dashOffset = dashOffset.toUInt(); 01240 } 01241 01242 void KSVGIconPainter::setStrokeDashArray(const TQString &dashes) 01243 { 01244 d->helper->m_dashes = dashes; 01245 } 01246 01247 void KSVGIconPainter::setCapStyle(const TQString &cap) 01248 { 01249 d->helper->m_capStyle = cap; 01250 } 01251 01252 void KSVGIconPainter::setJoinStyle(const TQString &join) 01253 { 01254 d->helper->m_joinStyle = join; 01255 } 01256 01257 void KSVGIconPainter::setStrokeColor(const TQString &stroke) 01258 { 01259 if(stroke.startsWith("url")) 01260 { 01261 d->helper->m_useStroke = false; 01262 d->helper->m_useStrokeGradient = true; 01263 01264 TQString url = stroke; 01265 01266 unsigned int start = url.find("#") + 1; 01267 unsigned int end = url.findRev(")"); 01268 01269 d->helper->m_strokeGradientReference = url.mid(start, end - start); 01270 } 01271 else 01272 { 01273 d->helper->m_strokeColor = parseColor(stroke); 01274 01275 d->helper->m_useStrokeGradient = false; 01276 d->helper->m_strokeGradientReference = TQString::null; 01277 01278 if(stroke.stripWhiteSpace().lower() != "none") 01279 setUseStroke(true); 01280 else 01281 setUseStroke(false); 01282 } 01283 } 01284 01285 void KSVGIconPainter::setFillColor(const TQString &fill) 01286 { 01287 if(fill.startsWith("url")) 01288 { 01289 d->helper->m_useFill = false; 01290 d->helper->m_useFillGradient = true; 01291 01292 TQString url = fill; 01293 01294 unsigned int start = url.find("#") + 1; 01295 unsigned int end = url.findRev(")"); 01296 01297 d->helper->m_fillGradientReference = url.mid(start, end - start); 01298 } 01299 else 01300 { 01301 d->helper->m_fillColor = parseColor(fill); 01302 01303 d->helper->m_useFillGradient = false; 01304 d->helper->m_fillGradientReference = TQString::null; 01305 01306 if(fill.stripWhiteSpace().lower() != "none") 01307 setUseFill(true); 01308 else 01309 setUseFill(false); 01310 } 01311 } 01312 01313 void KSVGIconPainter::setFillRule(const TQString &fillRule) 01314 { 01315 d->helper->m_fillRule = fillRule; 01316 } 01317 01318 TQ_UINT32 KSVGIconPainter::parseOpacity(const TQString &data) 01319 { 01320 int opacity = 255; 01321 01322 if(!data.isEmpty()) 01323 { 01324 double temp; 01325 01326 if(data.contains("%")) 01327 { 01328 TQString tempString = data.left(data.length() - 1); 01329 temp = double(255 * tempString.toDouble()) / 100.0; 01330 } 01331 else 01332 temp = data.toDouble(); 01333 01334 opacity = (int) floor(temp * 255 + 0.5); 01335 } 01336 01337 return opacity; 01338 } 01339 01340 void KSVGIconPainter::setFillOpacity(const TQString &fillOpacity) 01341 { 01342 d->helper->m_fillOpacity = parseOpacity(fillOpacity); 01343 } 01344 01345 void KSVGIconPainter::setStrokeOpacity(const TQString &strokeOpacity) 01346 { 01347 d->helper->m_strokeOpacity = parseOpacity(strokeOpacity); 01348 } 01349 01350 void KSVGIconPainter::setOpacity(const TQString &opacity) 01351 { 01352 d->helper->m_opacity = parseOpacity(opacity); 01353 } 01354 01355 void KSVGIconPainter::setUseFill(bool fill) 01356 { 01357 d->helper->m_useFill = fill; 01358 } 01359 01360 void KSVGIconPainter::setUseStroke(bool stroke) 01361 { 01362 d->helper->m_useStroke = stroke; 01363 } 01364 01365 void KSVGIconPainter::setClippingRect(int x, int y, int w, int h) 01366 { 01367 ArtVpath *vec = d->helper->allocVPath(6); 01368 01369 vec[0].code = ART_MOVETO; 01370 vec[0].x = x; 01371 vec[0].y = y; 01372 01373 vec[1].code = ART_LINETO; 01374 vec[1].x = x; 01375 vec[1].y = y + h; 01376 01377 vec[2].code = ART_LINETO; 01378 vec[2].x = x + w; 01379 vec[2].y = y + h; 01380 01381 vec[3].code = ART_LINETO; 01382 vec[3].x = x + w; 01383 vec[3].y = y; 01384 01385 vec[4].code = ART_LINETO; 01386 vec[4].x = x; 01387 vec[4].y = y; 01388 01389 vec[5].code = ART_END; 01390 01391 if(d->helper->m_clipSVP) 01392 art_svp_free(d->helper->m_clipSVP); 01393 01394 d->helper->m_clipSVP = art_svp_from_vpath(vec); 01395 01396 art_free(vec); 01397 } 01398 01399 void KSVGIconPainter::drawRectangle(double x, double y, double w, double h, double rx, double ry) 01400 { 01401 if((int) rx != 0 && (int) ry != 0) 01402 { 01403 ArtVpath *res; 01404 ArtBpath *vec = d->helper->allocBPath(10); 01405 01406 int i = 0; 01407 01408 if(rx > w / 2) 01409 rx = w / 2; 01410 01411 if(ry > h / 2) 01412 ry = h / 2; 01413 01414 vec[i].code = ART_MOVETO_OPEN; 01415 vec[i].x3 = x + rx; 01416 vec[i].y3 = y; 01417 01418 i++; 01419 01420 vec[i].code = ART_CURVETO; 01421 vec[i].x1 = x + rx * (1 - 0.552); 01422 vec[i].y1 = y; 01423 vec[i].x2 = x; 01424 vec[i].y2 = y + ry * (1 - 0.552); 01425 vec[i].x3 = x; 01426 vec[i].y3 = y + ry; 01427 01428 i++; 01429 01430 if(ry < h / 2) 01431 { 01432 vec[i].code = ART_LINETO; 01433 vec[i].x3 = x; 01434 vec[i].y3 = y + h - ry; 01435 01436 i++; 01437 } 01438 01439 vec[i].code = ART_CURVETO; 01440 vec[i].x1 = x; 01441 vec[i].y1 = y + h - ry * (1 - 0.552); 01442 vec[i].x2 = x + rx * (1 - 0.552); 01443 vec[i].y2 = y + h; 01444 vec[i].x3 = x + rx; 01445 vec[i].y3 = y + h; 01446 01447 i++; 01448 01449 if(rx < w / 2) 01450 { 01451 vec[i].code = ART_LINETO; 01452 vec[i].x3 = x + w - rx; 01453 vec[i].y3 = y + h; 01454 01455 i++; 01456 } 01457 01458 vec[i].code = ART_CURVETO; 01459 vec[i].x1 = x + w - rx * (1 - 0.552); 01460 vec[i].y1 = y + h; 01461 vec[i].x2 = x + w; 01462 vec[i].y2 = y + h - ry * (1 - 0.552); 01463 vec[i].x3 = x + w; 01464 01465 vec[i].y3 = y + h - ry; 01466 01467 i++; 01468 01469 if(ry < h / 2) 01470 { 01471 vec[i].code = ART_LINETO; 01472 vec[i].x3 = x + w; 01473 vec[i].y3 = y + ry; 01474 01475 i++; 01476 } 01477 01478 vec[i].code = ART_CURVETO; 01479 vec[i].x1 = x + w; 01480 vec[i].y1 = y + ry * (1 - 0.552); 01481 vec[i].x2 = x + w - rx * (1 - 0.552); 01482 vec[i].y2 = y; 01483 vec[i].x3 = x + w - rx; 01484 vec[i].y3 = y; 01485 01486 i++; 01487 01488 if(rx < w / 2) 01489 { 01490 vec[i].code = ART_LINETO; 01491 vec[i].x3 = x + rx; 01492 vec[i].y3 = y; 01493 01494 i++; 01495 } 01496 01497 vec[i].code = ART_END; 01498 01499 res = d->helper->art_bez_path_to_vec(vec, 0.25); 01500 art_free(vec); 01501 d->helper->drawVPath(res); 01502 } 01503 else 01504 { 01505 ArtVpath *vec = d->helper->allocVPath(6); 01506 01507 vec[0].code = ART_MOVETO; 01508 vec[0].x = x; 01509 vec[0].y = y; 01510 01511 vec[1].code = ART_LINETO; 01512 vec[1].x = x; 01513 vec[1].y = y + h; 01514 01515 vec[2].code = ART_LINETO; 01516 vec[2].x = x + w; 01517 vec[2].y = y + h; 01518 01519 vec[3].code = ART_LINETO; 01520 vec[3].x = x + w; 01521 vec[3].y = y; 01522 01523 vec[4].code = ART_LINETO; 01524 vec[4].x = x; 01525 vec[4].y = y; 01526 01527 vec[5].code = ART_END; 01528 01529 d->helper->drawVPath(vec); 01530 } 01531 } 01532 01533 void KSVGIconPainter::drawEllipse(double cx, double cy, double rx, double ry) 01534 { 01535 ArtBpath *temp; 01536 01537 temp = d->helper->allocBPath(6); 01538 01539 double x1, y1, x2, y2, x3, y3; 01540 double len = 0.55228474983079356; 01541 double cos4[] = {1.0, 0.0, -1.0, 0.0, 1.0}; 01542 double sin4[] = {0.0, 1.0, 0.0, -1.0, 0.0}; 01543 int i = 0; 01544 01545 temp[i].code = ART_MOVETO; 01546 temp[i].x3 = cx + rx; 01547 temp[i].y3 = cy; 01548 01549 i++; 01550 01551 while(i < 5) 01552 { 01553 x1 = cos4[i-1] + len * cos4[i]; 01554 y1 = sin4[i-1] + len * sin4[i]; 01555 x2 = cos4[i] + len * cos4[i-1]; 01556 y2 = sin4[i] + len * sin4[i-1]; 01557 x3 = cos4[i]; 01558 y3 = sin4[i]; 01559 01560 temp[i].code = ART_CURVETO; 01561 temp[i].x1 = cx + x1 * rx; 01562 temp[i].y1 = cy + y1 * ry; 01563 temp[i].x2 = cx + x2 * rx; 01564 temp[i].y2 = cy + y2 * ry; 01565 temp[i].x3 = cx + x3 * rx; 01566 temp[i].y3 = cy + y3 * ry; 01567 01568 i++; 01569 } 01570 01571 temp[i].code = ART_END; 01572 01573 d->helper->drawBPath(temp); 01574 01575 art_free(temp); 01576 } 01577 01578 void KSVGIconPainter::drawLine(double x1, double y1, double x2, double y2) 01579 { 01580 ArtVpath *vec; 01581 01582 vec = d->helper->allocVPath(3); 01583 01584 vec[0].code = ART_MOVETO_OPEN; 01585 vec[0].x = x1; 01586 vec[0].y = y1; 01587 01588 vec[1].code = ART_LINETO; 01589 vec[1].x = x2; 01590 vec[1].y = y2; 01591 01592 vec[2].code = ART_END; 01593 01594 d->helper->drawVPath(vec); 01595 } 01596 01597 void KSVGIconPainter::drawPolyline(TQPointArray polyArray, int points) 01598 { 01599 if(polyArray.point(0).x() == -1 || polyArray.point(0).y() == -1) 01600 return; 01601 01602 ArtVpath *polyline; 01603 01604 if(points == -1) 01605 points = polyArray.count(); 01606 01607 polyline = d->helper->allocVPath(3 + points); 01608 polyline[0].code = ART_MOVETO; 01609 polyline[0].x = polyArray.point(0).x(); 01610 polyline[0].y = polyArray.point(0).y(); 01611 01612 int index; 01613 for(index = 1; index < points; index++) 01614 { 01615 TQPoint point = polyArray.point(index); 01616 polyline[index].code = ART_LINETO; 01617 polyline[index].x = point.x(); 01618 polyline[index].y = point.y(); 01619 } 01620 01621 if(d->helper->m_useFill) // if the polyline must be filled, inform libart that it should not be closed. 01622 { 01623 polyline[index].code = (ArtPathcode)ART_END2; 01624 polyline[index].x = polyArray.point(0).x(); 01625 polyline[index++].y = polyArray.point(0).y(); 01626 } 01627 01628 polyline[index].code = ART_END; 01629 01630 d->helper->drawVPath(polyline); 01631 } 01632 01633 void KSVGIconPainter::drawPolygon(TQPointArray polyArray) 01634 { 01635 ArtVpath *polygon; 01636 01637 polygon = d->helper->allocVPath(3 + polyArray.count()); 01638 polygon[0].code = ART_MOVETO; 01639 polygon[0].x = polyArray.point(0).x(); 01640 polygon[0].y = polyArray.point(0).y(); 01641 01642 unsigned int index; 01643 for(index = 1; index < polyArray.count(); index++) 01644 { 01645 TQPoint point = polyArray.point(index); 01646 polygon[index].code = ART_LINETO; 01647 polygon[index].x = point.x(); 01648 polygon[index].y = point.y(); 01649 } 01650 01651 polygon[index].code = ART_LINETO; 01652 polygon[index].x = polyArray.point(0).x(); 01653 polygon[index].y = polyArray.point(0).y(); 01654 01655 index++; 01656 polygon[index].code = ART_END; 01657 01658 d->helper->drawVPath(polygon); 01659 } 01660 01661 // Path parsing tool 01662 // parses the coord into number and forwards to the next token 01663 static const char *getCoord(const char *ptr, double &number) 01664 { 01665 int integer, exponent; 01666 double decimal, frac; 01667 int sign, expsign; 01668 01669 exponent = 0; 01670 integer = 0; 01671 frac = 1.0; 01672 decimal = 0; 01673 sign = 1; 01674 expsign = 1; 01675 01676 // read the sign 01677 if(*ptr == '+') 01678 ptr++; 01679 else if(*ptr == '-') 01680 { 01681 ptr++; 01682 sign = -1; 01683 } 01684 // read the integer part 01685 while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9') 01686 integer = (integer * 10) + *(ptr++) - '0'; 01687 01688 if(*ptr == '.') // read the decimals 01689 { 01690 ptr++; 01691 while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9') 01692 decimal += (*(ptr++) - '0') * (frac *= 0.1); 01693 } 01694 01695 if(*ptr == 'e' || *ptr == 'E') // read the exponent part 01696 { 01697 ptr++; 01698 01699 // read the sign of the exponent 01700 if(*ptr == '+') 01701 ptr++; 01702 else if(*ptr == '-') 01703 { 01704 ptr++; 01705 expsign = -1; 01706 } 01707 01708 exponent = 0; 01709 while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9') 01710 { 01711 exponent *= 10; 01712 exponent += *ptr - '0'; 01713 ptr++; 01714 } 01715 } 01716 01717 number = integer + decimal; 01718 number *= sign * pow(10.0, expsign * exponent); 01719 01720 // skip the following space 01721 if(*ptr == ' ') 01722 ptr++; 01723 01724 return ptr; 01725 } 01726 01727 void KSVGIconPainter::drawPath(const TQString &data, bool filled) 01728 { 01729 if (!data.isEmpty()) 01730 { 01731 TQString value = data; 01732 01733 TQMemArray<ArtBpath> vec; 01734 int index = -1; 01735 01736 double curx = 0.0, cury = 0.0, contrlx = 0.0, contrly = 0.0, xc, yc; 01737 unsigned int lastCommand = 0; 01738 01739 TQString _d = value.replace(",", " "); 01740 _d = _d.simplifyWhiteSpace(); 01741 const char *ptr = _d.latin1(); 01742 const char *end = _d.latin1() + _d.length() + 1; 01743 01744 double tox, toy, x1, y1, x2, y2, rx, ry, angle; 01745 bool largeArc, sweep; 01746 char command = *(ptr++); 01747 01748 while(ptr < end) 01749 { 01750 if(*ptr == ' ') 01751 ptr++; 01752 01753 switch(command) 01754 { 01755 case 'm': 01756 ptr = getCoord(ptr, tox); 01757 ptr = getCoord(ptr, toy); 01758 01759 if(index != -1 && lastCommand != 'z') 01760 { 01761 // Find last subpath 01762 int find = -1; 01763 for(int i = index; i >= 0; i--) 01764 { 01765 if(vec[i].code == ART_MOVETO_OPEN || vec[i].code == ART_MOVETO) 01766 { 01767 find = i; 01768 break; 01769 } 01770 } 01771 01772 index++; 01773 01774 if(vec.size() == (unsigned int) index) 01775 vec.resize(index + 1); 01776 01777 vec[index].code = (ArtPathcode)ART_END2; 01778 vec[index].x3 = vec[find].x3; 01779 vec[index].y3 = vec[find].y3; 01780 } 01781 01782 curx += tox; 01783 cury += toy; 01784 01785 index++; 01786 01787 d->helper->ensureSpace(vec, index); 01788 01789 vec[index].code = (index == 0) ? ART_MOVETO : ART_MOVETO_OPEN; 01790 vec[index].x3 = curx; 01791 vec[index].y3 = cury; 01792 01793 lastCommand = 'm'; 01794 break; 01795 case 'M': 01796 ptr = getCoord(ptr, tox); 01797 ptr = getCoord(ptr, toy); 01798 if(index != -1 && lastCommand != 'z') 01799 { 01800 // Find last subpath 01801 int find = -1; 01802 for(int i = index; i >= 0; i--) 01803 { 01804 if(vec[i].code == ART_MOVETO_OPEN || vec[i].code == ART_MOVETO) 01805 { 01806 find = i; 01807 break; 01808 } 01809 } 01810 01811 index++; 01812 01813 if(vec.size() == (unsigned int) index) 01814 vec.resize(index + 1); 01815 01816 vec[index].code = (ArtPathcode)ART_END2; 01817 vec[index].x3 = vec[find].x3; 01818 vec[index].y3 = vec[find].y3; 01819 } 01820 01821 curx = tox; 01822 cury = toy; 01823 01824 index++; 01825 01826 d->helper->ensureSpace(vec, index); 01827 01828 vec[index].code = (index == 0) ? ART_MOVETO : ART_MOVETO_OPEN; 01829 vec[index].x3 = curx; 01830 vec[index].y3 = cury; 01831 01832 lastCommand = 'M'; 01833 break; 01834 case 'l': 01835 ptr = getCoord(ptr, tox); 01836 ptr = getCoord(ptr, toy); 01837 01838 index++; 01839 01840 d->helper->ensureSpace(vec, index); 01841 01842 vec[index].code = ART_LINETO; 01843 vec[index].x3 = curx + tox; 01844 vec[index].y3 = cury + toy; 01845 01846 curx += tox; 01847 cury += toy; 01848 01849 lastCommand = 'l'; 01850 break; 01851 case 'L': 01852 ptr = getCoord(ptr, tox); 01853 ptr = getCoord(ptr, toy); 01854 01855 index++; 01856 01857 d->helper->ensureSpace(vec, index); 01858 01859 vec[index].code = ART_LINETO; 01860 vec[index].x3 = tox; 01861 vec[index].y3 = toy; 01862 01863 curx = tox; 01864 cury = toy; 01865 01866 lastCommand = 'L'; 01867 break; 01868 case 'h': 01869 ptr = getCoord(ptr, tox); 01870 01871 index++; 01872 01873 curx += tox; 01874 01875 d->helper->ensureSpace(vec, index); 01876 01877 vec[index].code = ART_LINETO; 01878 vec[index].x3 = curx; 01879 vec[index].y3 = cury; 01880 01881 lastCommand = 'h'; 01882 break; 01883 case 'H': 01884 ptr = getCoord(ptr, tox); 01885 01886 index++; 01887 01888 curx = tox; 01889 01890 d->helper->ensureSpace(vec, index); 01891 01892 vec[index].code = ART_LINETO; 01893 vec[index].x3 = curx; 01894 vec[index].y3 = cury; 01895 01896 lastCommand = 'H'; 01897 break; 01898 case 'v': 01899 ptr = getCoord(ptr, toy); 01900 01901 index++; 01902 01903 cury += toy; 01904 01905 d->helper->ensureSpace(vec, index); 01906 01907 vec[index].code = ART_LINETO; 01908 vec[index].x3 = curx; 01909 vec[index].y3 = cury; 01910 01911 lastCommand = 'v'; 01912 break; 01913 case 'V': 01914 ptr = getCoord(ptr, toy); 01915 01916 index++; 01917 01918 cury = toy; 01919 01920 d->helper->ensureSpace(vec, index); 01921 01922 vec[index].code = ART_LINETO; 01923 vec[index].x3 = curx; 01924 vec[index].y3 = cury; 01925 01926 lastCommand = 'V'; 01927 break; 01928 case 'c': 01929 ptr = getCoord(ptr, x1); 01930 ptr = getCoord(ptr, y1); 01931 ptr = getCoord(ptr, x2); 01932 ptr = getCoord(ptr, y2); 01933 ptr = getCoord(ptr, tox); 01934 ptr = getCoord(ptr, toy); 01935 01936 index++; 01937 01938 d->helper->ensureSpace(vec, index); 01939 01940 vec[index].code = ART_CURVETO; 01941 vec[index].x1 = curx + x1; 01942 vec[index].y1 = cury + y1; 01943 vec[index].x2 = curx + x2; 01944 vec[index].y2 = cury + y2; 01945 vec[index].x3 = curx + tox; 01946 vec[index].y3 = cury + toy; 01947 01948 curx += tox; 01949 cury += toy; 01950 01951 contrlx = vec[index].x2; 01952 contrly = vec[index].y2; 01953 01954 lastCommand = 'c'; 01955 break; 01956 case 'C': 01957 ptr = getCoord(ptr, x1); 01958 ptr = getCoord(ptr, y1); 01959 ptr = getCoord(ptr, x2); 01960 ptr = getCoord(ptr, y2); 01961 ptr = getCoord(ptr, tox); 01962 ptr = getCoord(ptr, toy); 01963 01964 index++; 01965 01966 d->helper->ensureSpace(vec, index); 01967 01968 vec[index].code = ART_CURVETO; 01969 vec[index].x1 = x1; 01970 vec[index].y1 = y1; 01971 vec[index].x2 = x2; 01972 vec[index].y2 = y2; 01973 vec[index].x3 = tox; 01974 vec[index].y3 = toy; 01975 01976 curx = vec[index].x3; 01977 cury = vec[index].y3; 01978 contrlx = vec[index].x2; 01979 contrly = vec[index].y2; 01980 01981 lastCommand = 'C'; 01982 break; 01983 case 's': 01984 ptr = getCoord(ptr, x2); 01985 ptr = getCoord(ptr, y2); 01986 ptr = getCoord(ptr, tox); 01987 ptr = getCoord(ptr, toy); 01988 01989 index++; 01990 01991 d->helper->ensureSpace(vec, index); 01992 01993 vec[index].code = ART_CURVETO; 01994 vec[index].x1 = 2 * curx - contrlx; 01995 vec[index].y1 = 2 * cury - contrly; 01996 vec[index].x2 = curx + x2; 01997 vec[index].y2 = cury + y2; 01998 vec[index].x3 = curx + tox; 01999 vec[index].y3 = cury + toy; 02000 02001 curx += tox; 02002 cury += toy; 02003 02004 contrlx = vec[index].x2; 02005 contrly = vec[index].y2; 02006 02007 lastCommand = 's'; 02008 break; 02009 case 'S': 02010 ptr = getCoord(ptr, x2); 02011 ptr = getCoord(ptr, y2); 02012 ptr = getCoord(ptr, tox); 02013 ptr = getCoord(ptr, toy); 02014 02015 index++; 02016 02017 d->helper->ensureSpace(vec, index); 02018 02019 vec[index].code = ART_CURVETO; 02020 vec[index].x1 = 2 * curx - contrlx; 02021 vec[index].y1 = 2 * cury - contrly; 02022 vec[index].x2 = x2; 02023 vec[index].y2 = y2; 02024 vec[index].x3 = tox; 02025 vec[index].y3 = toy; 02026 02027 curx = vec[index].x3; 02028 cury = vec[index].y3; 02029 contrlx = vec[index].x2; 02030 contrly = vec[index].y2; 02031 02032 lastCommand = 'S'; 02033 break; 02034 case 'q': 02035 ptr = getCoord(ptr, x1); 02036 ptr = getCoord(ptr, y1); 02037 ptr = getCoord(ptr, tox); 02038 ptr = getCoord(ptr, toy); 02039 02040 index++; 02041 02042 d->helper->ensureSpace(vec, index); 02043 02044 vec[index].code = ART_CURVETO; 02045 vec[index].x1 = (curx + 2 * (x1 + curx)) * (1.0 / 3.0); 02046 vec[index].y1 = (cury + 2 * (y1 + cury)) * (1.0 / 3.0); 02047 vec[index].x2 = ((curx + tox) + 2 * (x1 + curx)) * (1.0 / 3.0); 02048 vec[index].y2 = ((cury + toy) + 2 * (y1 + cury)) * (1.0 / 3.0); 02049 vec[index].x3 = curx + tox; 02050 vec[index].y3 = cury + toy; 02051 02052 contrlx = curx + x1; 02053 contrly = cury + y1; 02054 curx += tox; 02055 cury += toy; 02056 02057 lastCommand = 'q'; 02058 break; 02059 case 'Q': 02060 ptr = getCoord(ptr, x1); 02061 ptr = getCoord(ptr, y1); 02062 ptr = getCoord(ptr, tox); 02063 ptr = getCoord(ptr, toy); 02064 02065 index++; 02066 02067 d->helper->ensureSpace(vec, index); 02068 02069 // TODO : if this fails make it more like QuadraticRel 02070 vec[index].code = ART_CURVETO; 02071 vec[index].x1 = (curx + 2 * x1) * (1.0 / 3.0); 02072 vec[index].y1 = (cury + 2 * y1) * (1.0 / 3.0); 02073 vec[index].x2 = (tox + 2 * x1) * (1.0 / 3.0); 02074 vec[index].y2 = (toy + 2 * y1) * (1.0 / 3.0); 02075 vec[index].x3 = tox; 02076 vec[index].y3 = toy; 02077 02078 curx = vec[index].x3; 02079 cury = vec[index].y3; 02080 contrlx = vec[index].x2; 02081 contrly = vec[index].y2; 02082 02083 lastCommand = 'Q'; 02084 break; 02085 case 't': 02086 ptr = getCoord(ptr, tox); 02087 ptr = getCoord(ptr, toy); 02088 02089 xc = 2 * curx - contrlx; 02090 yc = 2 * cury - contrly; 02091 02092 index++; 02093 02094 d->helper->ensureSpace(vec, index); 02095 02096 vec[index].code = ART_CURVETO; 02097 vec[index].x1 = (curx + 2 * xc) * (1.0 / 3.0); 02098 vec[index].y1 = (cury + 2 * yc) * (1.0 / 3.0); 02099 vec[index].x2 = ((curx + tox) + 2 * xc) * (1.0 / 3.0); 02100 vec[index].y2 = ((cury + toy) + 2 * yc) * (1.0 / 3.0); 02101 02102 vec[index].x3 = curx + tox; 02103 vec[index].y3 = cury + toy; 02104 02105 curx += tox; 02106 cury += toy; 02107 contrlx = xc; 02108 contrly = yc; 02109 02110 lastCommand = 't'; 02111 break; 02112 case 'T': 02113 ptr = getCoord(ptr, tox); 02114 ptr = getCoord(ptr, toy); 02115 02116 xc = 2 * curx - contrlx; 02117 yc = 2 * cury - contrly; 02118 02119 index++; 02120 02121 d->helper->ensureSpace(vec, index); 02122 02123 vec[index].code = ART_CURVETO; 02124 vec[index].x1 = (curx + 2 * xc) * (1.0 / 3.0); 02125 vec[index].y1 = (cury + 2 * yc) * (1.0 / 3.0); 02126 vec[index].x2 = (tox + 2 * xc) * (1.0 / 3.0); 02127 vec[index].y2 = (toy + 2 * yc) * (1.0 / 3.0); 02128 vec[index].x3 = tox; 02129 vec[index].y3 = toy; 02130 02131 curx = tox; 02132 cury = toy; 02133 contrlx = xc; 02134 contrly = yc; 02135 02136 lastCommand = 'T'; 02137 break; 02138 case 'z': 02139 case 'Z': 02140 int find; 02141 find = -1; 02142 for(int i = index; i >= 0; i--) 02143 { 02144 if(vec[i].code == ART_MOVETO_OPEN || vec[i].code == ART_MOVETO) 02145 { 02146 find = i; 02147 break; 02148 } 02149 } 02150 02151 if(find != -1) 02152 { 02153 if(vec[find].x3 != curx || vec[find].y3 != cury) 02154 { 02155 index++; 02156 02157 d->helper->ensureSpace(vec, index); 02158 02159 vec[index].code = ART_LINETO; 02160 vec[index].x3 = vec[find].x3; 02161 vec[index].y3 = vec[find].y3; 02162 } 02163 } 02164 02165 // reset for next (sub)path 02166 curx = vec[find].x3; 02167 cury = vec[find].y3; 02168 02169 lastCommand = 'z'; 02170 break; 02171 case 'a': 02172 ptr = getCoord(ptr, rx); 02173 ptr = getCoord(ptr, ry); 02174 ptr = getCoord(ptr, angle); 02175 ptr = getCoord(ptr, tox); 02176 largeArc = tox == 1; 02177 ptr = getCoord(ptr, tox); 02178 sweep = tox == 1; 02179 ptr = getCoord(ptr, tox); 02180 ptr = getCoord(ptr, toy); 02181 02182 // Spec: radii are nonnegative numbers 02183 rx = fabs(rx); 02184 ry = fabs(ry); 02185 02186 d->helper->calculateArc(true, vec, index, curx, cury, angle, tox, toy, rx, ry, largeArc, sweep); 02187 02188 lastCommand = 'a'; 02189 break; 02190 case 'A': 02191 ptr = getCoord(ptr, rx); 02192 ptr = getCoord(ptr, ry); 02193 ptr = getCoord(ptr, angle); 02194 ptr = getCoord(ptr, tox); 02195 largeArc = tox == 1; 02196 ptr = getCoord(ptr, tox); 02197 sweep = tox == 1; 02198 ptr = getCoord(ptr, tox); 02199 ptr = getCoord(ptr, toy); 02200 02201 // Spec: radii are nonnegative numbers 02202 rx = fabs(rx); 02203 ry = fabs(ry); 02204 02205 d->helper->calculateArc(false, vec, index, curx, cury, angle, tox, toy, rx, ry, largeArc, sweep); 02206 02207 lastCommand = 'A'; 02208 break; 02209 } 02210 02211 if(*ptr == '+' || *ptr == '-' || *ptr == '.' || (*ptr >= '0' && *ptr <= '9')) 02212 { 02213 // there are still coords in this command 02214 if(command == 'M') 02215 { 02216 command = 'L'; 02217 } 02218 else if(command == 'm') 02219 { 02220 command = 'l'; 02221 } 02222 } 02223 else 02224 { 02225 command = *(ptr++); 02226 } 02227 02228 // Detect reflection points 02229 if(lastCommand != 'C' && lastCommand != 'c' && 02230 lastCommand != 'S' && lastCommand != 's' && 02231 lastCommand != 'Q' && lastCommand != 'q' && 02232 lastCommand != 'T' && lastCommand != 't') 02233 { 02234 contrlx = curx; 02235 contrly = cury; 02236 } 02237 } 02238 02239 // Find last subpath 02240 int find = -1; 02241 for(int i = index; i >= 0; i--) 02242 { 02243 if(vec[i].code == ART_MOVETO_OPEN || vec[i].code == ART_MOVETO) 02244 { 02245 find = i; 02246 break; 02247 } 02248 } 02249 02250 // Fix a problem where the .svg file used doubles as values... (sofico.svg) 02251 if(curx != vec[find].x3 && cury != vec[find].y3) 02252 { 02253 if((int) curx == (int) vec[find].x3 && (int) cury == (int) vec[find].y3) 02254 { 02255 index++; 02256 02257 if(vec.size() == (unsigned int) index) 02258 vec.resize(index + 1); 02259 02260 vec[index].code = ART_LINETO; 02261 vec[index].x3 = vec[find].x3; 02262 vec[index].y3 = vec[find].y3; 02263 02264 curx = vec[find].x3; 02265 cury = vec[find].y3; 02266 } 02267 } 02268 02269 // Handle filled paths that are not closed explicitly 02270 if(filled) 02271 { 02272 if((int) curx != (int) vec[find].x3 || (int) cury != (int) vec[find].y3) 02273 { 02274 index++; 02275 02276 if(vec.size() == (unsigned int) index) 02277 vec.resize(index + 1); 02278 02279 vec[index].code = (ArtPathcode)ART_END2; 02280 vec[index].x3 = vec[find].x3; 02281 vec[index].y3 = vec[find].y3; 02282 02283 curx = vec[find].x3; 02284 cury = vec[find].y3; 02285 } 02286 } 02287 02288 // Close 02289 index++; 02290 02291 if(vec.size() == (unsigned int) index) 02292 vec.resize(index + 1); 02293 02294 vec[index].code = ART_END; 02295 02296 // There are pure-moveto paths which reference paint servers *bah* 02297 // Do NOT render them 02298 bool render = false; 02299 for(int i = index; i >= 0; i--) 02300 { 02301 if(vec[i].code != ART_MOVETO_OPEN && vec[i].code != ART_MOVETO && !(vec[i].code >= ART_END)) 02302 { 02303 render = true; 02304 break; 02305 } 02306 } 02307 02308 if(render) 02309 d->helper->drawBPath(vec.data()); 02310 } 02311 } 02312 02313 void KSVGIconPainter::drawImage(double x, double y, TQImage &image) 02314 { 02315 if(image.depth() != 32) 02316 image = image.convertDepth(32); 02317 02318 double affine[6]; 02319 affine[0] = d->helper->m_worldMatrix->m11(); 02320 affine[1] = d->helper->m_worldMatrix->m12(); 02321 affine[2] = d->helper->m_worldMatrix->m21(); 02322 affine[3] = d->helper->m_worldMatrix->m22(); 02323 // use the world matrix to convert the coordinates 02324 d->helper->m_worldMatrix->map(x, y, &affine[4], &affine[5]); 02325 02326 d->helper->art_rgba_rgba_affine(d->helper->m_buffer, 0, 0, d->helper->m_width, d->helper->m_height, 02327 d->helper->m_rowstride, image.bits(), image.width(), image.height(), 02328 image.width() * 4, affine); 02329 } 02330 02331 TQColor KSVGIconPainter::parseColor(const TQString ¶m) 02332 { 02333 if(param.stripWhiteSpace().startsWith("#")) 02334 { 02335 TQColor color; 02336 color.setNamedColor(param.stripWhiteSpace()); 02337 return color; 02338 } 02339 else if(param.stripWhiteSpace().startsWith("rgb(")) 02340 { 02341 TQString parse = param.stripWhiteSpace(); 02342 TQStringList colors = TQStringList::split(',', parse); 02343 TQString r = colors[0].right((colors[0].length() - 4)); 02344 TQString g = colors[1]; 02345 TQString b = colors[2].left((colors[2].length() - 1)); 02346 02347 if(r.contains("%")) 02348 { 02349 r = r.left(r.length() - 1); 02350 r = TQString::number(int((double(255 * r.toDouble()) / 100.0))); 02351 } 02352 02353 if(g.contains("%")) 02354 { 02355 g = g.left(g.length() - 1); 02356 g = TQString::number(int((double(255 * g.toDouble()) / 100.0))); 02357 } 02358 02359 if(b.contains("%")) 02360 { 02361 b = b.left(b.length() - 1); 02362 b = TQString::number(int((double(255 * b.toDouble()) / 100.0))); 02363 } 02364 02365 return TQColor(r.toInt(), g.toInt(), b.toInt()); 02366 } 02367 else 02368 { 02369 TQString rgbColor = param.stripWhiteSpace(); 02370 02371 if(rgbColor == "aliceblue") 02372 return TQColor(240, 248, 255); 02373 else if(rgbColor == "antiquewhite") 02374 return TQColor(250, 235, 215); 02375 else if(rgbColor == "aqua") 02376 return TQColor(0, 255, 255); 02377 else if(rgbColor == "aquamarine") 02378 return TQColor(127, 255, 212); 02379 else if(rgbColor == "azure") 02380 return TQColor(240, 255, 255); 02381 else if(rgbColor == "beige") 02382 return TQColor(245, 245, 220); 02383 else if(rgbColor == "bisque") 02384 return TQColor(255, 228, 196); 02385 else if(rgbColor == "black") 02386 return TQColor(0, 0, 0); 02387 else if(rgbColor == "blanchedalmond") 02388 return TQColor(255, 235, 205); 02389 else if(rgbColor == "blue") 02390 return TQColor(0, 0, 255); 02391 else if(rgbColor == "blueviolet") 02392 return TQColor(138, 43, 226); 02393 else if(rgbColor == "brown") 02394 return TQColor(165, 42, 42); 02395 else if(rgbColor == "burlywood") 02396 return TQColor(222, 184, 135); 02397 else if(rgbColor == "cadetblue") 02398 return TQColor(95, 158, 160); 02399 else if(rgbColor == "chartreuse") 02400 return TQColor(127, 255, 0); 02401 else if(rgbColor == "chocolate") 02402 return TQColor(210, 105, 30); 02403 else if(rgbColor == "coral") 02404 return TQColor(255, 127, 80); 02405 else if(rgbColor == "cornflowerblue") 02406 return TQColor(100, 149, 237); 02407 else if(rgbColor == "cornsilk") 02408 return TQColor(255, 248, 220); 02409 else if(rgbColor == "crimson") 02410 return TQColor(220, 20, 60); 02411 else if(rgbColor == "cyan") 02412 return TQColor(0, 255, 255); 02413 else if(rgbColor == "darkblue") 02414 return TQColor(0, 0, 139); 02415 else if(rgbColor == "darkcyan") 02416 return TQColor(0, 139, 139); 02417 else if(rgbColor == "darkgoldenrod") 02418 return TQColor(184, 134, 11); 02419 else if(rgbColor == "darkgray") 02420 return TQColor(169, 169, 169); 02421 else if(rgbColor == "darkgrey") 02422 return TQColor(169, 169, 169); 02423 else if(rgbColor == "darkgreen") 02424 return TQColor(0, 100, 0); 02425 else if(rgbColor == "darkkhaki") 02426 return TQColor(189, 183, 107); 02427 else if(rgbColor == "darkmagenta") 02428 return TQColor(139, 0, 139); 02429 else if(rgbColor == "darkolivegreen") 02430 return TQColor(85, 107, 47); 02431 else if(rgbColor == "darkorange") 02432 return TQColor(255, 140, 0); 02433 else if(rgbColor == "darkorchid") 02434 return TQColor(153, 50, 204); 02435 else if(rgbColor == "darkred") 02436 return TQColor(139, 0, 0); 02437 else if(rgbColor == "darksalmon") 02438 return TQColor(233, 150, 122); 02439 else if(rgbColor == "darkseagreen") 02440 return TQColor(143, 188, 143); 02441 else if(rgbColor == "darkslateblue") 02442 return TQColor(72, 61, 139); 02443 else if(rgbColor == "darkslategray") 02444 return TQColor(47, 79, 79); 02445 else if(rgbColor == "darkslategrey") 02446 return TQColor(47, 79, 79); 02447 else if(rgbColor == "darkturquoise") 02448 return TQColor(0, 206, 209); 02449 else if(rgbColor == "darkviolet") 02450 return TQColor(148, 0, 211); 02451 else if(rgbColor == "deeppink") 02452 return TQColor(255, 20, 147); 02453 else if(rgbColor == "deepskyblue") 02454 return TQColor(0, 191, 255); 02455 else if(rgbColor == "dimgray") 02456 return TQColor(105, 105, 105); 02457 else if(rgbColor == "dimgrey") 02458 return TQColor(105, 105, 105); 02459 else if(rgbColor == "dodgerblue") 02460 return TQColor(30, 144, 255); 02461 else if(rgbColor == "firebrick") 02462 return TQColor(178, 34, 34); 02463 else if(rgbColor == "floralwhite") 02464 return TQColor(255, 250, 240); 02465 else if(rgbColor == "forestgreen") 02466 return TQColor(34, 139, 34); 02467 else if(rgbColor == "fuchsia") 02468 return TQColor(255, 0, 255); 02469 else if(rgbColor == "gainsboro") 02470 return TQColor(220, 220, 220); 02471 else if(rgbColor == "ghostwhite") 02472 return TQColor(248, 248, 255); 02473 else if(rgbColor == "gold") 02474 return TQColor(255, 215, 0); 02475 else if(rgbColor == "goldenrod") 02476 return TQColor(218, 165, 32); 02477 else if(rgbColor == "gray") 02478 return TQColor(128, 128, 128); 02479 else if(rgbColor == "grey") 02480 return TQColor(128, 128, 128); 02481 else if(rgbColor == "green") 02482 return TQColor(0, 128, 0); 02483 else if(rgbColor == "greenyellow") 02484 return TQColor(173, 255, 47); 02485 else if(rgbColor == "honeydew") 02486 return TQColor(240, 255, 240); 02487 else if(rgbColor == "hotpink") 02488 return TQColor(255, 105, 180); 02489 else if(rgbColor == "indianred") 02490 return TQColor(205, 92, 92); 02491 else if(rgbColor == "indigo") 02492 return TQColor(75, 0, 130); 02493 else if(rgbColor == "ivory") 02494 return TQColor(255, 255, 240); 02495 else if(rgbColor == "khaki") 02496 return TQColor(240, 230, 140); 02497 else if(rgbColor == "lavender") 02498 return TQColor(230, 230, 250); 02499 else if(rgbColor == "lavenderblush") 02500 return TQColor(255, 240, 245); 02501 else if(rgbColor == "lawngreen") 02502 return TQColor(124, 252, 0); 02503 else if(rgbColor == "lemonchiffon") 02504 return TQColor(255, 250, 205); 02505 else if(rgbColor == "lightblue") 02506 return TQColor(173, 216, 230); 02507 else if(rgbColor == "lightcoral") 02508 return TQColor(240, 128, 128); 02509 else if(rgbColor == "lightcyan") 02510 return TQColor(224, 255, 255); 02511 else if(rgbColor == "lightgoldenrodyellow") 02512 return TQColor(250, 250, 210); 02513 else if(rgbColor == "lightgray") 02514 return TQColor(211, 211, 211); 02515 else if(rgbColor == "lightgrey") 02516 return TQColor(211, 211, 211); 02517 else if(rgbColor == "lightgreen") 02518 return TQColor(144, 238, 144); 02519 else if(rgbColor == "lightpink") 02520 return TQColor(255, 182, 193); 02521 else if(rgbColor == "lightsalmon") 02522 return TQColor(255, 160, 122); 02523 else if(rgbColor == "lightseagreen") 02524 return TQColor(32, 178, 170); 02525 else if(rgbColor == "lightskyblue") 02526 return TQColor(135, 206, 250); 02527 else if(rgbColor == "lightslategray") 02528 return TQColor(119, 136, 153); 02529 else if(rgbColor == "lightslategrey") 02530 return TQColor(119, 136, 153); 02531 else if(rgbColor == "lightsteelblue") 02532 return TQColor(176, 196, 222); 02533 else if(rgbColor == "lightyellow") 02534 return TQColor(255, 255, 224); 02535 else if(rgbColor == "lime") 02536 return TQColor(0, 255, 0); 02537 else if(rgbColor == "limegreen") 02538 return TQColor(50, 205, 50); 02539 else if(rgbColor == "linen") 02540 return TQColor(250, 240, 230); 02541 else if(rgbColor == "magenta") 02542 return TQColor(255, 0, 255); 02543 else if(rgbColor == "maroon") 02544 return TQColor(128, 0, 0); 02545 else if(rgbColor == "mediumaquamarine") 02546 return TQColor(102, 205, 170); 02547 else if(rgbColor == "mediumblue") 02548 return TQColor(0, 0, 205); 02549 else if(rgbColor == "mediumorchid") 02550 return TQColor(186, 85, 211); 02551 else if(rgbColor == "mediumpurple") 02552 return TQColor(147, 112, 219); 02553 else if(rgbColor == "mediumseagreen") 02554 return TQColor(60, 179, 113); 02555 else if(rgbColor == "mediumslateblue") 02556 return TQColor(123, 104, 238); 02557 else if(rgbColor == "mediumspringgreen") 02558 return TQColor(0, 250, 154); 02559 else if(rgbColor == "mediumturquoise") 02560 return TQColor(72, 209, 204); 02561 else if(rgbColor == "mediumvioletred") 02562 return TQColor(199, 21, 133); 02563 else if(rgbColor == "midnightblue") 02564 return TQColor(25, 25, 112); 02565 else if(rgbColor == "mintcream") 02566 return TQColor(245, 255, 250); 02567 else if(rgbColor == "mistyrose") 02568 return TQColor(255, 228, 225); 02569 else if(rgbColor == "moccasin") 02570 return TQColor(255, 228, 181); 02571 else if(rgbColor == "navajowhite") 02572 return TQColor(255, 222, 173); 02573 else if(rgbColor == "navy") 02574 return TQColor(0, 0, 128); 02575 else if(rgbColor == "oldlace") 02576 return TQColor(253, 245, 230); 02577 else if(rgbColor == "olive") 02578 return TQColor(128, 128, 0); 02579 else if(rgbColor == "olivedrab") 02580 return TQColor(107, 142, 35); 02581 else if(rgbColor == "orange") 02582 return TQColor(255, 165, 0); 02583 else if(rgbColor == "orangered") 02584 return TQColor(255, 69, 0); 02585 else if(rgbColor == "orchid") 02586 return TQColor(218, 112, 214); 02587 else if(rgbColor == "palegoldenrod") 02588 return TQColor(238, 232, 170); 02589 else if(rgbColor == "palegreen") 02590 return TQColor(152, 251, 152); 02591 else if(rgbColor == "paleturquoise") 02592 return TQColor(175, 238, 238); 02593 else if(rgbColor == "palevioletred") 02594 return TQColor(219, 112, 147); 02595 else if(rgbColor == "papayawhip") 02596 return TQColor(255, 239, 213); 02597 else if(rgbColor == "peachpuff") 02598 return TQColor(255, 218, 185); 02599 else if(rgbColor == "peru") 02600 return TQColor(205, 133, 63); 02601 else if(rgbColor == "pink") 02602 return TQColor(255, 192, 203); 02603 else if(rgbColor == "plum") 02604 return TQColor(221, 160, 221); 02605 else if(rgbColor == "powderblue") 02606 return TQColor(176, 224, 230); 02607 else if(rgbColor == "purple") 02608 return TQColor(128, 0, 128); 02609 else if(rgbColor == "red") 02610 return TQColor(255, 0, 0); 02611 else if(rgbColor == "rosybrown") 02612 return TQColor(188, 143, 143); 02613 else if(rgbColor == "royalblue") 02614 return TQColor(65, 105, 225); 02615 else if(rgbColor == "saddlebrown") 02616 return TQColor(139, 69, 19); 02617 else if(rgbColor == "salmon") 02618 return TQColor(250, 128, 114); 02619 else if(rgbColor == "sandybrown") 02620 return TQColor(244, 164, 96); 02621 else if(rgbColor == "seagreen") 02622 return TQColor(46, 139, 87); 02623 else if(rgbColor == "seashell") 02624 return TQColor(255, 245, 238); 02625 else if(rgbColor == "sienna") 02626 return TQColor(160, 82, 45); 02627 else if(rgbColor == "silver") 02628 return TQColor(192, 192, 192); 02629 else if(rgbColor == "skyblue") 02630 return TQColor(135, 206, 235); 02631 else if(rgbColor == "slateblue") 02632 return TQColor(106, 90, 205); 02633 else if(rgbColor == "slategray") 02634 return TQColor(112, 128, 144); 02635 else if(rgbColor == "slategrey") 02636 return TQColor(112, 128, 144); 02637 else if(rgbColor == "snow") 02638 return TQColor(255, 250, 250); 02639 else if(rgbColor == "springgreen") 02640 return TQColor(0, 255, 127); 02641 else if(rgbColor == "steelblue") 02642 return TQColor(70, 130, 180); 02643 else if(rgbColor == "tan") 02644 return TQColor(210, 180, 140); 02645 else if(rgbColor == "teal") 02646 return TQColor(0, 128, 128); 02647 else if(rgbColor == "thistle") 02648 return TQColor(216, 191, 216); 02649 else if(rgbColor == "tomato") 02650 return TQColor(255, 99, 71); 02651 else if(rgbColor == "turquoise") 02652 return TQColor(64, 224, 208); 02653 else if(rgbColor == "violet") 02654 return TQColor(238, 130, 238); 02655 else if(rgbColor == "wheat") 02656 return TQColor(245, 222, 179); 02657 else if(rgbColor == "white") 02658 return TQColor(255, 255, 255); 02659 else if(rgbColor == "whitesmoke") 02660 return TQColor(245, 245, 245); 02661 else if(rgbColor == "yellow") 02662 return TQColor(255, 255, 0); 02663 else if(rgbColor == "yellowgreen") 02664 return TQColor(154, 205, 50); 02665 } 02666 02667 return TQColor(); 02668 } 02669 02670 double KSVGIconPainter::dpi() 02671 { 02672 return 90.0; // TODO: make modal? 02673 } 02674 02675 double KSVGIconPainter::toPixel(const TQString &s, bool hmode) 02676 { 02677 if(s.isEmpty()) 02678 return 0.0; 02679 02680 TQString check = s; 02681 02682 double ret = 0.0; 02683 02684 double value = 0; 02685 const char *start = check.latin1(); 02686 const char *end = getCoord(start, value); 02687 02688 if(uint(end - start) < check.length()) 02689 { 02690 if(check.endsWith("px")) 02691 ret = value; 02692 else if(check.endsWith("cm")) 02693 ret = (value / 2.54) * dpi(); 02694 else if(check.endsWith("pc")) 02695 ret = (value / 6.0) * dpi(); 02696 else if(check.endsWith("mm")) 02697 ret = (value / 25.4) * dpi(); 02698 else if(check.endsWith("in")) 02699 ret = value * dpi(); 02700 else if(check.endsWith("pt")) 02701 ret = (value / 72.0) * dpi(); 02702 else if(check.endsWith("%")) 02703 { 02704 ret = value / 100.0; 02705 02706 if(hmode) 02707 ret *= d->drawWidth; 02708 else 02709 ret *= d->drawHeight; 02710 } 02711 else if(check.endsWith("em")) 02712 { 02713 ret = value * 10.0; // TODO make this depend on actual font size 02714 } 02715 } 02716 else 02717 ret = value; 02718 02719 return ret; 02720 } 02721 02722 ArtGradientLinear *KSVGIconPainter::linearGradient(const TQString &id) 02723 { 02724 return d->helper->m_linearGradientMap[id]; 02725 } 02726 02727 void KSVGIconPainter::addLinearGradient(const TQString &id, ArtGradientLinear *gradient) 02728 { 02729 d->helper->m_linearGradientMap.insert(id, gradient); 02730 } 02731 02732 TQDomElement KSVGIconPainter::linearGradientElement(ArtGradientLinear *linear) 02733 { 02734 return d->helper->m_linearGradientElementMap[linear]; 02735 } 02736 02737 void KSVGIconPainter::addLinearGradientElement(ArtGradientLinear *gradient, TQDomElement element) 02738 { 02739 d->helper->m_linearGradientElementMap.insert(gradient, element); 02740 } 02741 02742 ArtGradientRadial *KSVGIconPainter::radialGradient(const TQString &id) 02743 { 02744 return d->helper->m_radialGradientMap[id]; 02745 } 02746 02747 void KSVGIconPainter::addRadialGradient(const TQString &id, ArtGradientRadial *gradient) 02748 { 02749 d->helper->m_radialGradientMap.insert(id, gradient); 02750 } 02751 02752 TQDomElement KSVGIconPainter::radialGradientElement(ArtGradientRadial *radial) 02753 { 02754 return d->helper->m_radialGradientElementMap[radial]; 02755 } 02756 02757 void KSVGIconPainter::addRadialGradientElement(ArtGradientRadial *gradient, TQDomElement element) 02758 { 02759 d->helper->m_radialGradientElementMap.insert(gradient, element); 02760 } 02761 02762 TQ_UINT32 KSVGIconPainter::toArtColor(const TQColor &color) 02763 { 02764 return d->helper->toArtColor(color); 02765 } 02766 02767 TQWMatrix KSVGIconPainter::parseTransform(const TQString &transform) 02768 { 02769 TQWMatrix result; 02770 02771 // Split string for handling 1 transform statement at a time 02772 TQStringList subtransforms = TQStringList::split(')', transform); 02773 TQStringList::ConstIterator it = subtransforms.begin(); 02774 TQStringList::ConstIterator end = subtransforms.end(); 02775 for(; it != end; ++it) 02776 { 02777 TQStringList subtransform = TQStringList::split('(', (*it)); 02778 02779 subtransform[0] = subtransform[0].stripWhiteSpace().lower(); 02780 subtransform[1] = subtransform[1].simplifyWhiteSpace(); 02781 TQRegExp reg("([-]?\\d*\\.?\\d+(?:e[-]?\\d+)?)"); 02782 02783 int pos = 0; 02784 TQStringList params; 02785 02786 while(pos >= 0) 02787 { 02788 pos = reg.search(subtransform[1], pos); 02789 if(pos != -1) 02790 { 02791 params += reg.cap(1); 02792 pos += reg.matchedLength(); 02793 } 02794 } 02795 02796 if(subtransform[0].startsWith(";") || subtransform[0].startsWith(",")) 02797 subtransform[0] = subtransform[0].right(subtransform[0].length() - 1); 02798 02799 if(subtransform[0] == "rotate") 02800 { 02801 if(params.count() == 3) 02802 { 02803 double x = params[1].toDouble(); 02804 double y = params[2].toDouble(); 02805 02806 result.translate(x, y); 02807 result.rotate(params[0].toDouble()); 02808 result.translate(-x, -y); 02809 } 02810 else 02811 result.rotate(params[0].toDouble()); 02812 } 02813 else if(subtransform[0] == "translate") 02814 { 02815 if(params.count() == 2) 02816 result.translate(params[0].toDouble(), params[1].toDouble()); 02817 else // Spec : if only one param given, assume 2nd param to be 0 02818 result.translate(params[0].toDouble() , 0); 02819 } 02820 else if(subtransform[0] == "scale") 02821 { 02822 if(params.count() == 2) 02823 result.scale(params[0].toDouble(), params[1].toDouble()); 02824 else // Spec : if only one param given, assume uniform scaling 02825 result.scale(params[0].toDouble(), params[0].toDouble()); 02826 } 02827 else if(subtransform[0] == "skewx") 02828 result.shear(tan(params[0].toDouble() * deg2rad), 0.0F); 02829 else if(subtransform[0] == "skewy") 02830 result.shear(tan(params[0].toDouble() * deg2rad), 0.0F); 02831 else if(subtransform[0] == "skewy") 02832 result.shear(0.0F, tan(params[0].toDouble() * deg2rad)); 02833 else if(subtransform[0] == "matrix") 02834 { 02835 if(params.count() >= 6) 02836 { 02837 result.setMatrix(params[0].toDouble(), params[1].toDouble(), params[2].toDouble(), params[3].toDouble(), params[4].toDouble(), params[5].toDouble()); 02838 } 02839 } 02840 } 02841 02842 return result; 02843 }