ksvgiconpainter.cpp

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