kdecore Library API Documentation

ksvgiconpainter.cpp

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