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 = sqrt(pow(affine[0], 2) + pow(affine[3], 2)) / sqrt(2.0); 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 QString value = data; 01724 01725 QMemArray<ArtBpath> vec; 01726 int index = -1; 01727 01728 double curx = 0.0, cury = 0.0, contrlx = 0.0, contrly = 0.0, xc, yc; 01729 unsigned int lastCommand = 0; 01730 01731 QString _d = value.replace(",", " "); 01732 _d = _d.simplifyWhiteSpace(); 01733 const char *ptr = _d.latin1(); 01734 const char *end = _d.latin1() + _d.length() + 1; 01735 01736 double tox, toy, x1, y1, x2, y2, rx, ry, angle; 01737 bool largeArc, sweep; 01738 char command = *(ptr++); 01739 01740 while(ptr < end) 01741 { 01742 if(*ptr == ' ') 01743 ptr++; 01744 01745 switch(command) 01746 { 01747 case 'm': 01748 ptr = getCoord(ptr, tox); 01749 ptr = getCoord(ptr, toy); 01750 01751 if(index != -1 && lastCommand != 'z') 01752 { 01753 // Find last subpath 01754 int find = -1; 01755 for(int i = index; i >= 0; i--) 01756 { 01757 if(vec[i].code == ART_MOVETO_OPEN || vec[i].code == ART_MOVETO) 01758 { 01759 find = i; 01760 break; 01761 } 01762 } 01763 01764 index++; 01765 01766 if(vec.size() == (unsigned int) index) 01767 vec.resize(index + 1); 01768 01769 vec[index].code = (ArtPathcode)ART_END2; 01770 vec[index].x3 = vec[find].x3; 01771 vec[index].y3 = vec[find].y3; 01772 } 01773 01774 curx += tox; 01775 cury += toy; 01776 01777 index++; 01778 01779 d->helper->ensureSpace(vec, index); 01780 01781 vec[index].code = (index == 0) ? ART_MOVETO : ART_MOVETO_OPEN; 01782 vec[index].x3 = curx; 01783 vec[index].y3 = cury; 01784 01785 lastCommand = 'm'; 01786 break; 01787 case 'M': 01788 ptr = getCoord(ptr, tox); 01789 ptr = getCoord(ptr, toy); 01790 if(index != -1 && lastCommand != 'z') 01791 { 01792 // Find last subpath 01793 int find = -1; 01794 for(int i = index; i >= 0; i--) 01795 { 01796 if(vec[i].code == ART_MOVETO_OPEN || vec[i].code == ART_MOVETO) 01797 { 01798 find = i; 01799 break; 01800 } 01801 } 01802 01803 index++; 01804 01805 if(vec.size() == (unsigned int) index) 01806 vec.resize(index + 1); 01807 01808 vec[index].code = (ArtPathcode)ART_END2; 01809 vec[index].x3 = vec[find].x3; 01810 vec[index].y3 = vec[find].y3; 01811 } 01812 01813 curx = tox; 01814 cury = toy; 01815 01816 index++; 01817 01818 d->helper->ensureSpace(vec, index); 01819 01820 vec[index].code = (index == 0) ? ART_MOVETO : ART_MOVETO_OPEN; 01821 vec[index].x3 = curx; 01822 vec[index].y3 = cury; 01823 01824 lastCommand = 'M'; 01825 break; 01826 case 'l': 01827 ptr = getCoord(ptr, tox); 01828 ptr = getCoord(ptr, toy); 01829 01830 index++; 01831 01832 d->helper->ensureSpace(vec, index); 01833 01834 vec[index].code = ART_LINETO; 01835 vec[index].x3 = curx + tox; 01836 vec[index].y3 = cury + toy; 01837 01838 curx += tox; 01839 cury += toy; 01840 01841 lastCommand = 'l'; 01842 break; 01843 case 'L': 01844 ptr = getCoord(ptr, tox); 01845 ptr = getCoord(ptr, toy); 01846 01847 index++; 01848 01849 d->helper->ensureSpace(vec, index); 01850 01851 vec[index].code = ART_LINETO; 01852 vec[index].x3 = tox; 01853 vec[index].y3 = toy; 01854 01855 curx = tox; 01856 cury = toy; 01857 01858 lastCommand = 'L'; 01859 break; 01860 case 'h': 01861 ptr = getCoord(ptr, tox); 01862 01863 index++; 01864 01865 curx += tox; 01866 01867 d->helper->ensureSpace(vec, index); 01868 01869 vec[index].code = ART_LINETO; 01870 vec[index].x3 = curx; 01871 vec[index].y3 = cury; 01872 01873 lastCommand = 'h'; 01874 break; 01875 case 'H': 01876 ptr = getCoord(ptr, tox); 01877 01878 index++; 01879 01880 curx = tox; 01881 01882 d->helper->ensureSpace(vec, index); 01883 01884 vec[index].code = ART_LINETO; 01885 vec[index].x3 = curx; 01886 vec[index].y3 = cury; 01887 01888 lastCommand = 'H'; 01889 break; 01890 case 'v': 01891 ptr = getCoord(ptr, toy); 01892 01893 index++; 01894 01895 cury += toy; 01896 01897 d->helper->ensureSpace(vec, index); 01898 01899 vec[index].code = ART_LINETO; 01900 vec[index].x3 = curx; 01901 vec[index].y3 = cury; 01902 01903 lastCommand = 'v'; 01904 break; 01905 case 'V': 01906 ptr = getCoord(ptr, toy); 01907 01908 index++; 01909 01910 cury = toy; 01911 01912 d->helper->ensureSpace(vec, index); 01913 01914 vec[index].code = ART_LINETO; 01915 vec[index].x3 = curx; 01916 vec[index].y3 = cury; 01917 01918 lastCommand = 'V'; 01919 break; 01920 case 'c': 01921 ptr = getCoord(ptr, x1); 01922 ptr = getCoord(ptr, y1); 01923 ptr = getCoord(ptr, x2); 01924 ptr = getCoord(ptr, y2); 01925 ptr = getCoord(ptr, tox); 01926 ptr = getCoord(ptr, toy); 01927 01928 index++; 01929 01930 d->helper->ensureSpace(vec, index); 01931 01932 vec[index].code = ART_CURVETO; 01933 vec[index].x1 = curx + x1; 01934 vec[index].y1 = cury + y1; 01935 vec[index].x2 = curx + x2; 01936 vec[index].y2 = cury + y2; 01937 vec[index].x3 = curx + tox; 01938 vec[index].y3 = cury + toy; 01939 01940 curx += tox; 01941 cury += toy; 01942 01943 contrlx = vec[index].x2; 01944 contrly = vec[index].y2; 01945 01946 lastCommand = 'c'; 01947 break; 01948 case 'C': 01949 ptr = getCoord(ptr, x1); 01950 ptr = getCoord(ptr, y1); 01951 ptr = getCoord(ptr, x2); 01952 ptr = getCoord(ptr, y2); 01953 ptr = getCoord(ptr, tox); 01954 ptr = getCoord(ptr, toy); 01955 01956 index++; 01957 01958 d->helper->ensureSpace(vec, index); 01959 01960 vec[index].code = ART_CURVETO; 01961 vec[index].x1 = x1; 01962 vec[index].y1 = y1; 01963 vec[index].x2 = x2; 01964 vec[index].y2 = y2; 01965 vec[index].x3 = tox; 01966 vec[index].y3 = toy; 01967 01968 curx = vec[index].x3; 01969 cury = vec[index].y3; 01970 contrlx = vec[index].x2; 01971 contrly = vec[index].y2; 01972 01973 lastCommand = 'C'; 01974 break; 01975 case 's': 01976 ptr = getCoord(ptr, x2); 01977 ptr = getCoord(ptr, y2); 01978 ptr = getCoord(ptr, tox); 01979 ptr = getCoord(ptr, toy); 01980 01981 index++; 01982 01983 d->helper->ensureSpace(vec, index); 01984 01985 vec[index].code = ART_CURVETO; 01986 vec[index].x1 = 2 * curx - contrlx; 01987 vec[index].y1 = 2 * cury - contrly; 01988 vec[index].x2 = curx + x2; 01989 vec[index].y2 = cury + y2; 01990 vec[index].x3 = curx + tox; 01991 vec[index].y3 = cury + toy; 01992 01993 curx += tox; 01994 cury += toy; 01995 01996 contrlx = vec[index].x2; 01997 contrly = vec[index].y2; 01998 01999 lastCommand = 's'; 02000 break; 02001 case 'S': 02002 ptr = getCoord(ptr, x2); 02003 ptr = getCoord(ptr, y2); 02004 ptr = getCoord(ptr, tox); 02005 ptr = getCoord(ptr, toy); 02006 02007 index++; 02008 02009 d->helper->ensureSpace(vec, index); 02010 02011 vec[index].code = ART_CURVETO; 02012 vec[index].x1 = 2 * curx - contrlx; 02013 vec[index].y1 = 2 * cury - contrly; 02014 vec[index].x2 = x2; 02015 vec[index].y2 = y2; 02016 vec[index].x3 = tox; 02017 vec[index].y3 = toy; 02018 02019 curx = vec[index].x3; 02020 cury = vec[index].y3; 02021 contrlx = vec[index].x2; 02022 contrly = vec[index].y2; 02023 02024 lastCommand = 'S'; 02025 break; 02026 case 'q': 02027 ptr = getCoord(ptr, x1); 02028 ptr = getCoord(ptr, y1); 02029 ptr = getCoord(ptr, tox); 02030 ptr = getCoord(ptr, toy); 02031 02032 index++; 02033 02034 d->helper->ensureSpace(vec, index); 02035 02036 vec[index].code = ART_CURVETO; 02037 vec[index].x1 = (curx + 2 * (x1 + curx)) * (1.0 / 3.0); 02038 vec[index].y1 = (cury + 2 * (y1 + cury)) * (1.0 / 3.0); 02039 vec[index].x2 = ((curx + tox) + 2 * (x1 + curx)) * (1.0 / 3.0); 02040 vec[index].y2 = ((cury + toy) + 2 * (y1 + cury)) * (1.0 / 3.0); 02041 vec[index].x3 = curx + tox; 02042 vec[index].y3 = cury + toy; 02043 02044 contrlx = curx + x1; 02045 contrly = cury + y1; 02046 curx += tox; 02047 cury += toy; 02048 02049 lastCommand = 'q'; 02050 break; 02051 case 'Q': 02052 ptr = getCoord(ptr, x1); 02053 ptr = getCoord(ptr, y1); 02054 ptr = getCoord(ptr, tox); 02055 ptr = getCoord(ptr, toy); 02056 02057 index++; 02058 02059 d->helper->ensureSpace(vec, index); 02060 02061 // TODO : if this fails make it more like QuadraticRel 02062 vec[index].code = ART_CURVETO; 02063 vec[index].x1 = (curx + 2 * x1) * (1.0 / 3.0); 02064 vec[index].y1 = (cury + 2 * y1) * (1.0 / 3.0); 02065 vec[index].x2 = (tox + 2 * x1) * (1.0 / 3.0); 02066 vec[index].y2 = (toy + 2 * y1) * (1.0 / 3.0); 02067 vec[index].x3 = tox; 02068 vec[index].y3 = toy; 02069 02070 curx = vec[index].x3; 02071 cury = vec[index].y3; 02072 contrlx = vec[index].x2; 02073 contrly = vec[index].y2; 02074 02075 lastCommand = 'Q'; 02076 break; 02077 case 't': 02078 ptr = getCoord(ptr, tox); 02079 ptr = getCoord(ptr, toy); 02080 02081 xc = 2 * curx - contrlx; 02082 yc = 2 * cury - contrly; 02083 02084 index++; 02085 02086 d->helper->ensureSpace(vec, index); 02087 02088 vec[index].code = ART_CURVETO; 02089 vec[index].x1 = (curx + 2 * xc) * (1.0 / 3.0); 02090 vec[index].y1 = (cury + 2 * yc) * (1.0 / 3.0); 02091 vec[index].x2 = ((curx + tox) + 2 * xc) * (1.0 / 3.0); 02092 vec[index].y2 = ((cury + toy) + 2 * yc) * (1.0 / 3.0); 02093 02094 vec[index].x3 = curx + tox; 02095 vec[index].y3 = cury + toy; 02096 02097 curx += tox; 02098 cury += toy; 02099 contrlx = xc; 02100 contrly = yc; 02101 02102 lastCommand = 't'; 02103 break; 02104 case 'T': 02105 ptr = getCoord(ptr, tox); 02106 ptr = getCoord(ptr, toy); 02107 02108 xc = 2 * curx - contrlx; 02109 yc = 2 * cury - contrly; 02110 02111 index++; 02112 02113 d->helper->ensureSpace(vec, index); 02114 02115 vec[index].code = ART_CURVETO; 02116 vec[index].x1 = (curx + 2 * xc) * (1.0 / 3.0); 02117 vec[index].y1 = (cury + 2 * yc) * (1.0 / 3.0); 02118 vec[index].x2 = (tox + 2 * xc) * (1.0 / 3.0); 02119 vec[index].y2 = (toy + 2 * yc) * (1.0 / 3.0); 02120 vec[index].x3 = tox; 02121 vec[index].y3 = toy; 02122 02123 curx = tox; 02124 cury = toy; 02125 contrlx = xc; 02126 contrly = yc; 02127 02128 lastCommand = 'T'; 02129 break; 02130 case 'z': 02131 case 'Z': 02132 int find; 02133 find = -1; 02134 for(int i = index; i >= 0; i--) 02135 { 02136 if(vec[i].code == ART_MOVETO_OPEN || vec[i].code == ART_MOVETO) 02137 { 02138 find = i; 02139 break; 02140 } 02141 } 02142 02143 if(find != -1) 02144 { 02145 if(vec[find].x3 != curx || vec[find].y3 != cury) 02146 { 02147 index++; 02148 02149 d->helper->ensureSpace(vec, index); 02150 02151 vec[index].code = ART_LINETO; 02152 vec[index].x3 = vec[find].x3; 02153 vec[index].y3 = vec[find].y3; 02154 } 02155 } 02156 02157 // reset for next (sub)path 02158 curx = vec[find].x3; 02159 cury = vec[find].y3; 02160 02161 lastCommand = 'z'; 02162 break; 02163 case 'a': 02164 ptr = getCoord(ptr, rx); 02165 ptr = getCoord(ptr, ry); 02166 ptr = getCoord(ptr, angle); 02167 ptr = getCoord(ptr, tox); 02168 largeArc = tox == 1; 02169 ptr = getCoord(ptr, tox); 02170 sweep = tox == 1; 02171 ptr = getCoord(ptr, tox); 02172 ptr = getCoord(ptr, toy); 02173 02174 // Spec: radii are nonnegative numbers 02175 rx = fabs(rx); 02176 ry = fabs(ry); 02177 02178 d->helper->calculateArc(true, vec, index, curx, cury, angle, tox, toy, rx, ry, largeArc, sweep); 02179 02180 lastCommand = 'a'; 02181 break; 02182 case 'A': 02183 ptr = getCoord(ptr, rx); 02184 ptr = getCoord(ptr, ry); 02185 ptr = getCoord(ptr, angle); 02186 ptr = getCoord(ptr, tox); 02187 largeArc = tox == 1; 02188 ptr = getCoord(ptr, tox); 02189 sweep = tox == 1; 02190 ptr = getCoord(ptr, tox); 02191 ptr = getCoord(ptr, toy); 02192 02193 // Spec: radii are nonnegative numbers 02194 rx = fabs(rx); 02195 ry = fabs(ry); 02196 02197 d->helper->calculateArc(false, vec, index, curx, cury, angle, tox, toy, rx, ry, largeArc, sweep); 02198 02199 lastCommand = 'A'; 02200 break; 02201 } 02202 02203 if(*ptr == '+' || *ptr == '-' || (*ptr >= '0' && *ptr <= '9')) 02204 { 02205 // there are still coords in this command 02206 if(command == 'M') 02207 command = 'L'; 02208 else if(command == 'm') 02209 command = 'l'; 02210 } 02211 else 02212 command = *(ptr++); 02213 02214 // Detect reflection points 02215 if(lastCommand != 'C' && lastCommand != 'c' && 02216 lastCommand != 'S' && lastCommand != 's' && 02217 lastCommand != 'Q' && lastCommand != 'q' && 02218 lastCommand != 'T' && lastCommand != 't') 02219 { 02220 contrlx = curx; 02221 contrly = cury; 02222 } 02223 } 02224 02225 // Find last subpath 02226 int find = -1; 02227 for(int i = index; i >= 0; i--) 02228 { 02229 if(vec[i].code == ART_MOVETO_OPEN || vec[i].code == ART_MOVETO) 02230 { 02231 find = i; 02232 break; 02233 } 02234 } 02235 02236 // Fix a problem where the .svg file used doubles as values... (sofico.svg) 02237 if(curx != vec[find].x3 && cury != vec[find].y3) 02238 { 02239 if((int) curx == (int) vec[find].x3 && (int) cury == (int) vec[find].y3) 02240 { 02241 index++; 02242 02243 if(vec.size() == (unsigned int) index) 02244 vec.resize(index + 1); 02245 02246 vec[index].code = ART_LINETO; 02247 vec[index].x3 = vec[find].x3; 02248 vec[index].y3 = vec[find].y3; 02249 02250 curx = vec[find].x3; 02251 cury = vec[find].y3; 02252 } 02253 } 02254 02255 // Handle filled paths that are not closed explicitly 02256 if(filled) 02257 { 02258 if((int) curx != (int) vec[find].x3 || (int) cury != (int) vec[find].y3) 02259 { 02260 index++; 02261 02262 if(vec.size() == (unsigned int) index) 02263 vec.resize(index + 1); 02264 02265 vec[index].code = (ArtPathcode)ART_END2; 02266 vec[index].x3 = vec[find].x3; 02267 vec[index].y3 = vec[find].y3; 02268 02269 curx = vec[find].x3; 02270 cury = vec[find].y3; 02271 } 02272 } 02273 02274 // Close 02275 index++; 02276 02277 if(vec.size() == (unsigned int) index) 02278 vec.resize(index + 1); 02279 02280 vec[index].code = ART_END; 02281 02282 // There are pure-moveto paths which reference paint servers *bah* 02283 // Do NOT render them 02284 bool render = false; 02285 for(int i = index; i >= 0; i--) 02286 { 02287 if(vec[i].code != ART_MOVETO_OPEN && vec[i].code != ART_MOVETO && !(vec[i].code >= ART_END)) 02288 { 02289 render = true; 02290 break; 02291 } 02292 } 02293 02294 if(render) 02295 d->helper->drawBPath(vec.data()); 02296 } 02297 02298 void KSVGIconPainter::drawImage(double x, double y, QImage &image) 02299 { 02300 if(image.depth() != 32) 02301 image = image.convertDepth(32); 02302 02303 double affine[6]; 02304 affine[0] = d->helper->m_worldMatrix->m11(); 02305 affine[1] = d->helper->m_worldMatrix->m12(); 02306 affine[2] = d->helper->m_worldMatrix->m21(); 02307 affine[3] = d->helper->m_worldMatrix->m22(); 02308 affine[4] = d->helper->m_worldMatrix->dx() + x; 02309 affine[5] = d->helper->m_worldMatrix->dy() + y; 02310 02311 d->helper->art_rgba_rgba_affine(d->helper->m_buffer, 0, 0, d->helper->m_width, d->helper->m_height, 02312 d->helper->m_rowstride, image.bits(), image.width(), image.height(), 02313 image.width() * 4, affine); 02314 } 02315 02316 QColor KSVGIconPainter::parseColor(const QString &param) 02317 { 02318 if(param.stripWhiteSpace().startsWith("#")) 02319 { 02320 QColor color; 02321 color.setNamedColor(param.stripWhiteSpace()); 02322 return color; 02323 } 02324 else if(param.stripWhiteSpace().startsWith("rgb(")) 02325 { 02326 QString parse = param.stripWhiteSpace(); 02327 QStringList colors = QStringList::split(',', parse); 02328 QString r = colors[0].right((colors[0].length() - 4)); 02329 QString g = colors[1]; 02330 QString b = colors[2].left((colors[2].length() - 1)); 02331 02332 if(r.contains("%")) 02333 { 02334 r = r.left(r.length() - 1); 02335 r = QString::number(int((double(255 * r.toDouble()) / 100.0))); 02336 } 02337 02338 if(g.contains("%")) 02339 { 02340 g = g.left(g.length() - 1); 02341 g = QString::number(int((double(255 * g.toDouble()) / 100.0))); 02342 } 02343 02344 if(b.contains("%")) 02345 { 02346 b = b.left(b.length() - 1); 02347 b = QString::number(int((double(255 * b.toDouble()) / 100.0))); 02348 } 02349 02350 return QColor(r.toInt(), g.toInt(), b.toInt()); 02351 } 02352 else 02353 { 02354 QString rgbColor = param.stripWhiteSpace(); 02355 02356 if(rgbColor == "aliceblue") 02357 return QColor(240, 248, 255); 02358 else if(rgbColor == "antiquewhite") 02359 return QColor(250, 235, 215); 02360 else if(rgbColor == "aqua") 02361 return QColor(0, 255, 255); 02362 else if(rgbColor == "aquamarine") 02363 return QColor(127, 255, 212); 02364 else if(rgbColor == "azure") 02365 return QColor(240, 255, 255); 02366 else if(rgbColor == "beige") 02367 return QColor(245, 245, 220); 02368 else if(rgbColor == "bisque") 02369 return QColor(255, 228, 196); 02370 else if(rgbColor == "black") 02371 return QColor(0, 0, 0); 02372 else if(rgbColor == "blanchedalmond") 02373 return QColor(255, 235, 205); 02374 else if(rgbColor == "blue") 02375 return QColor(0, 0, 255); 02376 else if(rgbColor == "blueviolet") 02377 return QColor(138, 43, 226); 02378 else if(rgbColor == "brown") 02379 return QColor(165, 42, 42); 02380 else if(rgbColor == "burlywood") 02381 return QColor(222, 184, 135); 02382 else if(rgbColor == "cadetblue") 02383 return QColor(95, 158, 160); 02384 else if(rgbColor == "chartreuse") 02385 return QColor(127, 255, 0); 02386 else if(rgbColor == "chocolate") 02387 return QColor(210, 105, 30); 02388 else if(rgbColor == "coral") 02389 return QColor(255, 127, 80); 02390 else if(rgbColor == "cornflowerblue") 02391 return QColor(100, 149, 237); 02392 else if(rgbColor == "cornsilk") 02393 return QColor(255, 248, 220); 02394 else if(rgbColor == "crimson") 02395 return QColor(220, 20, 60); 02396 else if(rgbColor == "cyan") 02397 return QColor(0, 255, 255); 02398 else if(rgbColor == "darkblue") 02399 return QColor(0, 0, 139); 02400 else if(rgbColor == "darkcyan") 02401 return QColor(0, 139, 139); 02402 else if(rgbColor == "darkgoldenrod") 02403 return QColor(184, 134, 11); 02404 else if(rgbColor == "darkgray") 02405 return QColor(169, 169, 169); 02406 else if(rgbColor == "darkgrey") 02407 return QColor(169, 169, 169); 02408 else if(rgbColor == "darkgreen") 02409 return QColor(0, 100, 0); 02410 else if(rgbColor == "darkkhaki") 02411 return QColor(189, 183, 107); 02412 else if(rgbColor == "darkmagenta") 02413 return QColor(139, 0, 139); 02414 else if(rgbColor == "darkolivegreen") 02415 return QColor(85, 107, 47); 02416 else if(rgbColor == "darkorange") 02417 return QColor(255, 140, 0); 02418 else if(rgbColor == "darkorchid") 02419 return QColor(153, 50, 204); 02420 else if(rgbColor == "darkred") 02421 return QColor(139, 0, 0); 02422 else if(rgbColor == "darksalmon") 02423 return QColor(233, 150, 122); 02424 else if(rgbColor == "darkseagreen") 02425 return QColor(143, 188, 143); 02426 else if(rgbColor == "darkslateblue") 02427 return QColor(72, 61, 139); 02428 else if(rgbColor == "darkslategray") 02429 return QColor(47, 79, 79); 02430 else if(rgbColor == "darkslategrey") 02431 return QColor(47, 79, 79); 02432 else if(rgbColor == "darkturquoise") 02433 return QColor(0, 206, 209); 02434 else if(rgbColor == "darkviolet") 02435 return QColor(148, 0, 211); 02436 else if(rgbColor == "deeppink") 02437 return QColor(255, 20, 147); 02438 else if(rgbColor == "deepskyblue") 02439 return QColor(0, 191, 255); 02440 else if(rgbColor == "dimgray") 02441 return QColor(105, 105, 105); 02442 else if(rgbColor == "dimgrey") 02443 return QColor(105, 105, 105); 02444 else if(rgbColor == "dodgerblue") 02445 return QColor(30, 144, 255); 02446 else if(rgbColor == "firebrick") 02447 return QColor(178, 34, 34); 02448 else if(rgbColor == "floralwhite") 02449 return QColor(255, 250, 240); 02450 else if(rgbColor == "forestgreen") 02451 return QColor(34, 139, 34); 02452 else if(rgbColor == "fuchsia") 02453 return QColor(255, 0, 255); 02454 else if(rgbColor == "gainsboro") 02455 return QColor(220, 220, 220); 02456 else if(rgbColor == "ghostwhite") 02457 return QColor(248, 248, 255); 02458 else if(rgbColor == "gold") 02459 return QColor(255, 215, 0); 02460 else if(rgbColor == "goldenrod") 02461 return QColor(218, 165, 32); 02462 else if(rgbColor == "gray") 02463 return QColor(128, 128, 128); 02464 else if(rgbColor == "grey") 02465 return QColor(128, 128, 128); 02466 else if(rgbColor == "green") 02467 return QColor(0, 128, 0); 02468 else if(rgbColor == "greenyellow") 02469 return QColor(173, 255, 47); 02470 else if(rgbColor == "honeydew") 02471 return QColor(240, 255, 240); 02472 else if(rgbColor == "hotpink") 02473 return QColor(255, 105, 180); 02474 else if(rgbColor == "indianred") 02475 return QColor(205, 92, 92); 02476 else if(rgbColor == "indigo") 02477 return QColor(75, 0, 130); 02478 else if(rgbColor == "ivory") 02479 return QColor(255, 255, 240); 02480 else if(rgbColor == "khaki") 02481 return QColor(240, 230, 140); 02482 else if(rgbColor == "lavender") 02483 return QColor(230, 230, 250); 02484 else if(rgbColor == "lavenderblush") 02485 return QColor(255, 240, 245); 02486 else if(rgbColor == "lawngreen") 02487 return QColor(124, 252, 0); 02488 else if(rgbColor == "lemonchiffon") 02489 return QColor(255, 250, 205); 02490 else if(rgbColor == "lightblue") 02491 return QColor(173, 216, 230); 02492 else if(rgbColor == "lightcoral") 02493 return QColor(240, 128, 128); 02494 else if(rgbColor == "lightcyan") 02495 return QColor(224, 255, 255); 02496 else if(rgbColor == "lightgoldenrodyellow") 02497 return QColor(250, 250, 210); 02498 else if(rgbColor == "lightgray") 02499 return QColor(211, 211, 211); 02500 else if(rgbColor == "lightgrey") 02501 return QColor(211, 211, 211); 02502 else if(rgbColor == "lightgreen") 02503 return QColor(144, 238, 144); 02504 else if(rgbColor == "lightpink") 02505 return QColor(255, 182, 193); 02506 else if(rgbColor == "lightsalmon") 02507 return QColor(255, 160, 122); 02508 else if(rgbColor == "lightseagreen") 02509 return QColor(32, 178, 170); 02510 else if(rgbColor == "lightskyblue") 02511 return QColor(135, 206, 250); 02512 else if(rgbColor == "lightslategray") 02513 return QColor(119, 136, 153); 02514 else if(rgbColor == "lightslategrey") 02515 return QColor(119, 136, 153); 02516 else if(rgbColor == "lightsteelblue") 02517 return QColor(176, 196, 222); 02518 else if(rgbColor == "lightyellow") 02519 return QColor(255, 255, 224); 02520 else if(rgbColor == "lime") 02521 return QColor(0, 255, 0); 02522 else if(rgbColor == "limegreen") 02523 return QColor(50, 205, 50); 02524 else if(rgbColor == "linen") 02525 return QColor(250, 240, 230); 02526 else if(rgbColor == "magenta") 02527 return QColor(255, 0, 255); 02528 else if(rgbColor == "maroon") 02529 return QColor(128, 0, 0); 02530 else if(rgbColor == "mediumaquamarine") 02531 return QColor(102, 205, 170); 02532 else if(rgbColor == "mediumblue") 02533 return QColor(0, 0, 205); 02534 else if(rgbColor == "mediumorchid") 02535 return QColor(186, 85, 211); 02536 else if(rgbColor == "mediumpurple") 02537 return QColor(147, 112, 219); 02538 else if(rgbColor == "mediumseagreen") 02539 return QColor(60, 179, 113); 02540 else if(rgbColor == "mediumslateblue") 02541 return QColor(123, 104, 238); 02542 else if(rgbColor == "mediumspringgreen") 02543 return QColor(0, 250, 154); 02544 else if(rgbColor == "mediumturquoise") 02545 return QColor(72, 209, 204); 02546 else if(rgbColor == "mediumvioletred") 02547 return QColor(199, 21, 133); 02548 else if(rgbColor == "midnightblue") 02549 return QColor(25, 25, 112); 02550 else if(rgbColor == "mintcream") 02551 return QColor(245, 255, 250); 02552 else if(rgbColor == "mistyrose") 02553 return QColor(255, 228, 225); 02554 else if(rgbColor == "moccasin") 02555 return QColor(255, 228, 181); 02556 else if(rgbColor == "navajowhite") 02557 return QColor(255, 222, 173); 02558 else if(rgbColor == "navy") 02559 return QColor(0, 0, 128); 02560 else if(rgbColor == "oldlace") 02561 return QColor(253, 245, 230); 02562 else if(rgbColor == "olive") 02563 return QColor(128, 128, 0); 02564 else if(rgbColor == "olivedrab") 02565 return QColor(107, 142, 35); 02566 else if(rgbColor == "orange") 02567 return QColor(255, 165, 0); 02568 else if(rgbColor == "orangered") 02569 return QColor(255, 69, 0); 02570 else if(rgbColor == "orchid") 02571 return QColor(218, 112, 214); 02572 else if(rgbColor == "palegoldenrod") 02573 return QColor(238, 232, 170); 02574 else if(rgbColor == "palegreen") 02575 return QColor(152, 251, 152); 02576 else if(rgbColor == "paleturquoise") 02577 return QColor(175, 238, 238); 02578 else if(rgbColor == "palevioletred") 02579 return QColor(219, 112, 147); 02580 else if(rgbColor == "papayawhip") 02581 return QColor(255, 239, 213); 02582 else if(rgbColor == "peachpuff") 02583 return QColor(255, 218, 185); 02584 else if(rgbColor == "peru") 02585 return QColor(205, 133, 63); 02586 else if(rgbColor == "pink") 02587 return QColor(255, 192, 203); 02588 else if(rgbColor == "plum") 02589 return QColor(221, 160, 221); 02590 else if(rgbColor == "powderblue") 02591 return QColor(176, 224, 230); 02592 else if(rgbColor == "purple") 02593 return QColor(128, 0, 128); 02594 else if(rgbColor == "red") 02595 return QColor(255, 0, 0); 02596 else if(rgbColor == "rosybrown") 02597 return QColor(188, 143, 143); 02598 else if(rgbColor == "royalblue") 02599 return QColor(65, 105, 225); 02600 else if(rgbColor == "saddlebrown") 02601 return QColor(139, 69, 19); 02602 else if(rgbColor == "salmon") 02603 return QColor(250, 128, 114); 02604 else if(rgbColor == "sandybrown") 02605 return QColor(244, 164, 96); 02606 else if(rgbColor == "seagreen") 02607 return QColor(46, 139, 87); 02608 else if(rgbColor == "seashell") 02609 return QColor(255, 245, 238); 02610 else if(rgbColor == "sienna") 02611 return QColor(160, 82, 45); 02612 else if(rgbColor == "silver") 02613 return QColor(192, 192, 192); 02614 else if(rgbColor == "skyblue") 02615 return QColor(135, 206, 235); 02616 else if(rgbColor == "slateblue") 02617 return QColor(106, 90, 205); 02618 else if(rgbColor == "slategray") 02619 return QColor(112, 128, 144); 02620 else if(rgbColor == "slategrey") 02621 return QColor(112, 128, 144); 02622 else if(rgbColor == "snow") 02623 return QColor(255, 250, 250); 02624 else if(rgbColor == "springgreen") 02625 return QColor(0, 255, 127); 02626 else if(rgbColor == "steelblue") 02627 return QColor(70, 130, 180); 02628 else if(rgbColor == "tan") 02629 return QColor(210, 180, 140); 02630 else if(rgbColor == "teal") 02631 return QColor(0, 128, 128); 02632 else if(rgbColor == "thistle") 02633 return QColor(216, 191, 216); 02634 else if(rgbColor == "tomato") 02635 return QColor(255, 99, 71); 02636 else if(rgbColor == "turquoise") 02637 return QColor(64, 224, 208); 02638 else if(rgbColor == "violet") 02639 return QColor(238, 130, 238); 02640 else if(rgbColor == "wheat") 02641 return QColor(245, 222, 179); 02642 else if(rgbColor == "white") 02643 return QColor(255, 255, 255); 02644 else if(rgbColor == "whitesmoke") 02645 return QColor(245, 245, 245); 02646 else if(rgbColor == "yellow") 02647 return QColor(255, 255, 0); 02648 else if(rgbColor == "yellowgreen") 02649 return QColor(154, 205, 50); 02650 } 02651 02652 return QColor(); 02653 } 02654 02655 double KSVGIconPainter::dpi() 02656 { 02657 return 90.0; // TODO: make modal? 02658 } 02659 02660 double KSVGIconPainter::toPixel(const QString &s, bool hmode) 02661 { 02662 if(s.isEmpty()) 02663 return 0.0; 02664 02665 QString check = s; 02666 02667 double ret = 0.0; 02668 02669 bool ok = false; 02670 02671 double value = check.toDouble(&ok); 02672 02673 if(!ok) 02674 { 02675 check.replace(QRegExp("[0-9 .-]"), QString::null); 02676 02677 if(check.compare("px") == 0) 02678 ret = value; 02679 else if(check.compare("cm") == 0) 02680 ret = (value / 2.54) * dpi(); 02681 else if(check.compare("pc") == 0) 02682 ret = (value / 6.0) * dpi(); 02683 else if(check.compare("mm") == 0) 02684 ret = (value / 25.4) * dpi(); 02685 else if(check.compare("in") == 0) 02686 ret = value * dpi(); 02687 else if(check.compare("pt") == 0) 02688 ret = (value / 72.0) * dpi(); 02689 else if(check.compare("%") == 0) 02690 { 02691 ret = value / 100.0; 02692 02693 if(hmode) 02694 ret *= d->drawWidth; 02695 else 02696 ret *= d->drawHeight; 02697 } 02698 else if(check.compare("em") == 0) 02699 { 02700 ret = value * 10.0; // TODO make this depend on actual font size 02701 } 02702 } 02703 else 02704 ret = value; 02705 02706 return ret; 02707 } 02708 02709 ArtGradientLinear *KSVGIconPainter::linearGradient(const QString &id) 02710 { 02711 return d->helper->m_linearGradientMap[id]; 02712 } 02713 02714 void KSVGIconPainter::addLinearGradient(const QString &id, ArtGradientLinear *gradient) 02715 { 02716 d->helper->m_linearGradientMap.insert(id, gradient); 02717 } 02718 02719 QDomElement KSVGIconPainter::linearGradientElement(ArtGradientLinear *linear) 02720 { 02721 return d->helper->m_linearGradientElementMap[linear]; 02722 } 02723 02724 void KSVGIconPainter::addLinearGradientElement(ArtGradientLinear *gradient, QDomElement element) 02725 { 02726 d->helper->m_linearGradientElementMap.insert(gradient, element); 02727 } 02728 02729 ArtGradientRadial *KSVGIconPainter::radialGradient(const QString &id) 02730 { 02731 return d->helper->m_radialGradientMap[id]; 02732 } 02733 02734 void KSVGIconPainter::addRadialGradient(const QString &id, ArtGradientRadial *gradient) 02735 { 02736 d->helper->m_radialGradientMap.insert(id, gradient); 02737 } 02738 02739 QDomElement KSVGIconPainter::radialGradientElement(ArtGradientRadial *radial) 02740 { 02741 return d->helper->m_radialGradientElementMap[radial]; 02742 } 02743 02744 void KSVGIconPainter::addRadialGradientElement(ArtGradientRadial *gradient, QDomElement element) 02745 { 02746 d->helper->m_radialGradientElementMap.insert(gradient, element); 02747 } 02748 02749 Q_UINT32 KSVGIconPainter::toArtColor(const QColor &color) 02750 { 02751 return d->helper->toArtColor(color); 02752 } 02753 02754 QWMatrix KSVGIconPainter::parseTransform(const QString &transform) 02755 { 02756 QWMatrix result; 02757 02758 // Split string for handling 1 transform statement at a time 02759 QStringList subtransforms = QStringList::split(')', transform); 02760 QStringList::ConstIterator it = subtransforms.begin(); 02761 QStringList::ConstIterator end = subtransforms.end(); 02762 for(; it != end; ++it) 02763 { 02764 QStringList subtransform = QStringList::split('(', (*it)); 02765 02766 subtransform[0] = subtransform[0].stripWhiteSpace().lower(); 02767 subtransform[1] = subtransform[1].simplifyWhiteSpace(); 02768 QRegExp reg("[a-zA-Z,( ]"); 02769 QStringList params = QStringList::split(reg, subtransform[1]); 02770 02771 if(subtransform[0].startsWith(";") || subtransform[0].startsWith(",")) 02772 subtransform[0] = subtransform[0].right(subtransform[0].length() - 1); 02773 02774 if(subtransform[0] == "rotate") 02775 { 02776 if(params.count() == 3) 02777 { 02778 float x = params[1].toFloat(); 02779 float y = params[2].toFloat(); 02780 02781 result.translate(x, y); 02782 result.rotate(params[0].toFloat()); 02783 result.translate(-x, -y); 02784 } 02785 else 02786 result.rotate(params[0].toFloat()); 02787 } 02788 else if(subtransform[0] == "translate") 02789 { 02790 if(params.count() == 2) 02791 result.translate(params[0].toFloat(), params[1].toFloat()); 02792 else // Spec : if only one param given, assume 2nd param to be 0 02793 result.translate(params[0].toFloat() , 0); 02794 } 02795 else if(subtransform[0] == "scale") 02796 { 02797 if(params.count() == 2) 02798 result.scale(params[0].toFloat(), params[1].toFloat()); 02799 else // Spec : if only one param given, assume uniform scaling 02800 result.scale(params[0].toFloat(), params[0].toFloat()); 02801 } 02802 else if(subtransform[0] == "skewx") 02803 result.shear(tan(params[0].toFloat() * deg2rad), 0.0F); 02804 else if(subtransform[0] == "skewy") 02805 result.shear(tan(params[0].toFloat() * deg2rad), 0.0F); 02806 else if(subtransform[0] == "skewy") 02807 result.shear(0.0F, tan(params[0].toFloat() * deg2rad)); 02808 else if(subtransform[0] == "matrix") 02809 { 02810 if(params.count() >= 6) 02811 result.setMatrix(params[0].toFloat(), params[1].toFloat(), params[2].toFloat(), params[3].toFloat(), params[4].toFloat(), params[5].toFloat()); 02812 } 02813 } 02814 02815 return result; 02816 }
KDE Logo
This file is part of the documentation for kdecore Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Oct 8 11:14:03 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003