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