kdecore Library API Documentation

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