• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

KDECore

ksvgiconpainter.cpp

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

KDECore

Skip menu "KDECore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal