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