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