kdecore Library API Documentation

ksvgiconpainter.cpp

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