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 = sqrt(pow(affine[0], 2) + pow(affine[3], 2)) / sqrt(2.0);
00313 double strokeWidth = m_strokeWidth * ratio;
00314
00315 ArtPathStrokeJoinType joinStyle = ART_PATH_STROKE_JOIN_MITER;
00316 ArtPathStrokeCapType capStyle = ART_PATH_STROKE_CAP_BUTT;
00317
00318 if(m_joinStyle == "miter")
00319 joinStyle = ART_PATH_STROKE_JOIN_MITER;
00320 else if(m_joinStyle == "round")
00321 joinStyle = ART_PATH_STROKE_JOIN_ROUND;
00322 else if(m_joinStyle == "bevel")
00323 joinStyle = ART_PATH_STROKE_JOIN_BEVEL;
00324
00325 if(m_capStyle == "butt")
00326 capStyle = ART_PATH_STROKE_CAP_BUTT;
00327 else if(m_capStyle == "round")
00328 capStyle = ART_PATH_STROKE_CAP_ROUND;
00329 else if(m_capStyle == "square")
00330 capStyle = ART_PATH_STROKE_CAP_SQUARE;
00331
00332 if(m_dashes.length() > 0)
00333 {
00334 QRegExp reg("[, ]");
00335 QStringList dashList = QStringList::split(reg, m_dashes);
00336
00337 double *dashes = new double[dashList.count()];
00338 for(unsigned int i = 0; i < dashList.count(); i++)
00339 dashes[i] = m_painter->toPixel(dashList[i], true);
00340
00341 ArtVpathDash dash;
00342 dash.offset = m_dashOffset;
00343 dash.n_dash = dashList.count();
00344
00345 dash.dash = dashes;
00346
00347 ArtVpath *vec2 = art_vpath_dash(vec, &dash);
00348 art_free(vec);
00349
00350 delete dashes;
00351
00352 vec = vec2;
00353 }
00354
00355 svp = art_svp_vpath_stroke(vec, joinStyle, capStyle, strokeWidth, m_strokeMiterLimit, 0.25);
00356
00357 strokeSVP = svp;
00358 }
00359
00360
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 QString value = data;
01724
01725 QMemArray<ArtBpath> vec;
01726 int index = -1;
01727
01728 double curx = 0.0, cury = 0.0, contrlx = 0.0, contrly = 0.0, xc, yc;
01729 unsigned int lastCommand = 0;
01730
01731 QString _d = value.replace(",", " ");
01732 _d = _d.simplifyWhiteSpace();
01733 const char *ptr = _d.latin1();
01734 const char *end = _d.latin1() + _d.length() + 1;
01735
01736 double tox, toy, x1, y1, x2, y2, rx, ry, angle;
01737 bool largeArc, sweep;
01738 char command = *(ptr++);
01739
01740 while(ptr < end)
01741 {
01742 if(*ptr == ' ')
01743 ptr++;
01744
01745 switch(command)
01746 {
01747 case 'm':
01748 ptr = getCoord(ptr, tox);
01749 ptr = getCoord(ptr, toy);
01750
01751 if(index != -1 && lastCommand != 'z')
01752 {
01753
01754 int find = -1;
01755 for(int i = index; i >= 0; i--)
01756 {
01757 if(vec[i].code == ART_MOVETO_OPEN || vec[i].code == ART_MOVETO)
01758 {
01759 find = i;
01760 break;
01761 }
01762 }
01763
01764 index++;
01765
01766 if(vec.size() == (unsigned int) index)
01767 vec.resize(index + 1);
01768
01769 vec[index].code = (ArtPathcode)ART_END2;
01770 vec[index].x3 = vec[find].x3;
01771 vec[index].y3 = vec[find].y3;
01772 }
01773
01774 curx += tox;
01775 cury += toy;
01776
01777 index++;
01778
01779 d->helper->ensureSpace(vec, index);
01780
01781 vec[index].code = (index == 0) ? ART_MOVETO : ART_MOVETO_OPEN;
01782 vec[index].x3 = curx;
01783 vec[index].y3 = cury;
01784
01785 lastCommand = 'm';
01786 break;
01787 case 'M':
01788 ptr = getCoord(ptr, tox);
01789 ptr = getCoord(ptr, toy);
01790 if(index != -1 && lastCommand != 'z')
01791 {
01792
01793 int find = -1;
01794 for(int i = index; i >= 0; i--)
01795 {
01796 if(vec[i].code == ART_MOVETO_OPEN || vec[i].code == ART_MOVETO)
01797 {
01798 find = i;
01799 break;
01800 }
01801 }
01802
01803 index++;
01804
01805 if(vec.size() == (unsigned int) index)
01806 vec.resize(index + 1);
01807
01808 vec[index].code = (ArtPathcode)ART_END2;
01809 vec[index].x3 = vec[find].x3;
01810 vec[index].y3 = vec[find].y3;
01811 }
01812
01813 curx = tox;
01814 cury = toy;
01815
01816 index++;
01817
01818 d->helper->ensureSpace(vec, index);
01819
01820 vec[index].code = (index == 0) ? ART_MOVETO : ART_MOVETO_OPEN;
01821 vec[index].x3 = curx;
01822 vec[index].y3 = cury;
01823
01824 lastCommand = 'M';
01825 break;
01826 case 'l':
01827 ptr = getCoord(ptr, tox);
01828 ptr = getCoord(ptr, toy);
01829
01830 index++;
01831
01832 d->helper->ensureSpace(vec, index);
01833
01834 vec[index].code = ART_LINETO;
01835 vec[index].x3 = curx + tox;
01836 vec[index].y3 = cury + toy;
01837
01838 curx += tox;
01839 cury += toy;
01840
01841 lastCommand = 'l';
01842 break;
01843 case 'L':
01844 ptr = getCoord(ptr, tox);
01845 ptr = getCoord(ptr, toy);
01846
01847 index++;
01848
01849 d->helper->ensureSpace(vec, index);
01850
01851 vec[index].code = ART_LINETO;
01852 vec[index].x3 = tox;
01853 vec[index].y3 = toy;
01854
01855 curx = tox;
01856 cury = toy;
01857
01858 lastCommand = 'L';
01859 break;
01860 case 'h':
01861 ptr = getCoord(ptr, tox);
01862
01863 index++;
01864
01865 curx += tox;
01866
01867 d->helper->ensureSpace(vec, index);
01868
01869 vec[index].code = ART_LINETO;
01870 vec[index].x3 = curx;
01871 vec[index].y3 = cury;
01872
01873 lastCommand = 'h';
01874 break;
01875 case 'H':
01876 ptr = getCoord(ptr, tox);
01877
01878 index++;
01879
01880 curx = tox;
01881
01882 d->helper->ensureSpace(vec, index);
01883
01884 vec[index].code = ART_LINETO;
01885 vec[index].x3 = curx;
01886 vec[index].y3 = cury;
01887
01888 lastCommand = 'H';
01889 break;
01890 case 'v':
01891 ptr = getCoord(ptr, toy);
01892
01893 index++;
01894
01895 cury += toy;
01896
01897 d->helper->ensureSpace(vec, index);
01898
01899 vec[index].code = ART_LINETO;
01900 vec[index].x3 = curx;
01901 vec[index].y3 = cury;
01902
01903 lastCommand = 'v';
01904 break;
01905 case 'V':
01906 ptr = getCoord(ptr, toy);
01907
01908 index++;
01909
01910 cury = toy;
01911
01912 d->helper->ensureSpace(vec, index);
01913
01914 vec[index].code = ART_LINETO;
01915 vec[index].x3 = curx;
01916 vec[index].y3 = cury;
01917
01918 lastCommand = 'V';
01919 break;
01920 case 'c':
01921 ptr = getCoord(ptr, x1);
01922 ptr = getCoord(ptr, y1);
01923 ptr = getCoord(ptr, x2);
01924 ptr = getCoord(ptr, y2);
01925 ptr = getCoord(ptr, tox);
01926 ptr = getCoord(ptr, toy);
01927
01928 index++;
01929
01930 d->helper->ensureSpace(vec, index);
01931
01932 vec[index].code = ART_CURVETO;
01933 vec[index].x1 = curx + x1;
01934 vec[index].y1 = cury + y1;
01935 vec[index].x2 = curx + x2;
01936 vec[index].y2 = cury + y2;
01937 vec[index].x3 = curx + tox;
01938 vec[index].y3 = cury + toy;
01939
01940 curx += tox;
01941 cury += toy;
01942
01943 contrlx = vec[index].x2;
01944 contrly = vec[index].y2;
01945
01946 lastCommand = 'c';
01947 break;
01948 case 'C':
01949 ptr = getCoord(ptr, x1);
01950 ptr = getCoord(ptr, y1);
01951 ptr = getCoord(ptr, x2);
01952 ptr = getCoord(ptr, y2);
01953 ptr = getCoord(ptr, tox);
01954 ptr = getCoord(ptr, toy);
01955
01956 index++;
01957
01958 d->helper->ensureSpace(vec, index);
01959
01960 vec[index].code = ART_CURVETO;
01961 vec[index].x1 = x1;
01962 vec[index].y1 = y1;
01963 vec[index].x2 = x2;
01964 vec[index].y2 = y2;
01965 vec[index].x3 = tox;
01966 vec[index].y3 = toy;
01967
01968 curx = vec[index].x3;
01969 cury = vec[index].y3;
01970 contrlx = vec[index].x2;
01971 contrly = vec[index].y2;
01972
01973 lastCommand = 'C';
01974 break;
01975 case 's':
01976 ptr = getCoord(ptr, x2);
01977 ptr = getCoord(ptr, y2);
01978 ptr = getCoord(ptr, tox);
01979 ptr = getCoord(ptr, toy);
01980
01981 index++;
01982
01983 d->helper->ensureSpace(vec, index);
01984
01985 vec[index].code = ART_CURVETO;
01986 vec[index].x1 = 2 * curx - contrlx;
01987 vec[index].y1 = 2 * cury - contrly;
01988 vec[index].x2 = curx + x2;
01989 vec[index].y2 = cury + y2;
01990 vec[index].x3 = curx + tox;
01991 vec[index].y3 = cury + toy;
01992
01993 curx += tox;
01994 cury += toy;
01995
01996 contrlx = vec[index].x2;
01997 contrly = vec[index].y2;
01998
01999 lastCommand = 's';
02000 break;
02001 case 'S':
02002 ptr = getCoord(ptr, x2);
02003 ptr = getCoord(ptr, y2);
02004 ptr = getCoord(ptr, tox);
02005 ptr = getCoord(ptr, toy);
02006
02007 index++;
02008
02009 d->helper->ensureSpace(vec, index);
02010
02011 vec[index].code = ART_CURVETO;
02012 vec[index].x1 = 2 * curx - contrlx;
02013 vec[index].y1 = 2 * cury - contrly;
02014 vec[index].x2 = x2;
02015 vec[index].y2 = y2;
02016 vec[index].x3 = tox;
02017 vec[index].y3 = toy;
02018
02019 curx = vec[index].x3;
02020 cury = vec[index].y3;
02021 contrlx = vec[index].x2;
02022 contrly = vec[index].y2;
02023
02024 lastCommand = 'S';
02025 break;
02026 case 'q':
02027 ptr = getCoord(ptr, x1);
02028 ptr = getCoord(ptr, y1);
02029 ptr = getCoord(ptr, tox);
02030 ptr = getCoord(ptr, toy);
02031
02032 index++;
02033
02034 d->helper->ensureSpace(vec, index);
02035
02036 vec[index].code = ART_CURVETO;
02037 vec[index].x1 = (curx + 2 * (x1 + curx)) * (1.0 / 3.0);
02038 vec[index].y1 = (cury + 2 * (y1 + cury)) * (1.0 / 3.0);
02039 vec[index].x2 = ((curx + tox) + 2 * (x1 + curx)) * (1.0 / 3.0);
02040 vec[index].y2 = ((cury + toy) + 2 * (y1 + cury)) * (1.0 / 3.0);
02041 vec[index].x3 = curx + tox;
02042 vec[index].y3 = cury + toy;
02043
02044 contrlx = curx + x1;
02045 contrly = cury + y1;
02046 curx += tox;
02047 cury += toy;
02048
02049 lastCommand = 'q';
02050 break;
02051 case 'Q':
02052 ptr = getCoord(ptr, x1);
02053 ptr = getCoord(ptr, y1);
02054 ptr = getCoord(ptr, tox);
02055 ptr = getCoord(ptr, toy);
02056
02057 index++;
02058
02059 d->helper->ensureSpace(vec, index);
02060
02061
02062 vec[index].code = ART_CURVETO;
02063 vec[index].x1 = (curx + 2 * x1) * (1.0 / 3.0);
02064 vec[index].y1 = (cury + 2 * y1) * (1.0 / 3.0);
02065 vec[index].x2 = (tox + 2 * x1) * (1.0 / 3.0);
02066 vec[index].y2 = (toy + 2 * y1) * (1.0 / 3.0);
02067 vec[index].x3 = tox;
02068 vec[index].y3 = toy;
02069
02070 curx = vec[index].x3;
02071 cury = vec[index].y3;
02072 contrlx = vec[index].x2;
02073 contrly = vec[index].y2;
02074
02075 lastCommand = 'Q';
02076 break;
02077 case 't':
02078 ptr = getCoord(ptr, tox);
02079 ptr = getCoord(ptr, toy);
02080
02081 xc = 2 * curx - contrlx;
02082 yc = 2 * cury - contrly;
02083
02084 index++;
02085
02086 d->helper->ensureSpace(vec, index);
02087
02088 vec[index].code = ART_CURVETO;
02089 vec[index].x1 = (curx + 2 * xc) * (1.0 / 3.0);
02090 vec[index].y1 = (cury + 2 * yc) * (1.0 / 3.0);
02091 vec[index].x2 = ((curx + tox) + 2 * xc) * (1.0 / 3.0);
02092 vec[index].y2 = ((cury + toy) + 2 * yc) * (1.0 / 3.0);
02093
02094 vec[index].x3 = curx + tox;
02095 vec[index].y3 = cury + toy;
02096
02097 curx += tox;
02098 cury += toy;
02099 contrlx = xc;
02100 contrly = yc;
02101
02102 lastCommand = 't';
02103 break;
02104 case 'T':
02105 ptr = getCoord(ptr, tox);
02106 ptr = getCoord(ptr, toy);
02107
02108 xc = 2 * curx - contrlx;
02109 yc = 2 * cury - contrly;
02110
02111 index++;
02112
02113 d->helper->ensureSpace(vec, index);
02114
02115 vec[index].code = ART_CURVETO;
02116 vec[index].x1 = (curx + 2 * xc) * (1.0 / 3.0);
02117 vec[index].y1 = (cury + 2 * yc) * (1.0 / 3.0);
02118 vec[index].x2 = (tox + 2 * xc) * (1.0 / 3.0);
02119 vec[index].y2 = (toy + 2 * yc) * (1.0 / 3.0);
02120 vec[index].x3 = tox;
02121 vec[index].y3 = toy;
02122
02123 curx = tox;
02124 cury = toy;
02125 contrlx = xc;
02126 contrly = yc;
02127
02128 lastCommand = 'T';
02129 break;
02130 case 'z':
02131 case 'Z':
02132 int find;
02133 find = -1;
02134 for(int i = index; i >= 0; i--)
02135 {
02136 if(vec[i].code == ART_MOVETO_OPEN || vec[i].code == ART_MOVETO)
02137 {
02138 find = i;
02139 break;
02140 }
02141 }
02142
02143 if(find != -1)
02144 {
02145 if(vec[find].x3 != curx || vec[find].y3 != cury)
02146 {
02147 index++;
02148
02149 d->helper->ensureSpace(vec, index);
02150
02151 vec[index].code = ART_LINETO;
02152 vec[index].x3 = vec[find].x3;
02153 vec[index].y3 = vec[find].y3;
02154 }
02155 }
02156
02157
02158 curx = vec[find].x3;
02159 cury = vec[find].y3;
02160
02161 lastCommand = 'z';
02162 break;
02163 case 'a':
02164 ptr = getCoord(ptr, rx);
02165 ptr = getCoord(ptr, ry);
02166 ptr = getCoord(ptr, angle);
02167 ptr = getCoord(ptr, tox);
02168 largeArc = tox == 1;
02169 ptr = getCoord(ptr, tox);
02170 sweep = tox == 1;
02171 ptr = getCoord(ptr, tox);
02172 ptr = getCoord(ptr, toy);
02173
02174
02175 rx = fabs(rx);
02176 ry = fabs(ry);
02177
02178 d->helper->calculateArc(true, vec, index, curx, cury, angle, tox, toy, rx, ry, largeArc, sweep);
02179
02180 lastCommand = 'a';
02181 break;
02182 case 'A':
02183 ptr = getCoord(ptr, rx);
02184 ptr = getCoord(ptr, ry);
02185 ptr = getCoord(ptr, angle);
02186 ptr = getCoord(ptr, tox);
02187 largeArc = tox == 1;
02188 ptr = getCoord(ptr, tox);
02189 sweep = tox == 1;
02190 ptr = getCoord(ptr, tox);
02191 ptr = getCoord(ptr, toy);
02192
02193
02194 rx = fabs(rx);
02195 ry = fabs(ry);
02196
02197 d->helper->calculateArc(false, vec, index, curx, cury, angle, tox, toy, rx, ry, largeArc, sweep);
02198
02199 lastCommand = 'A';
02200 break;
02201 }
02202
02203 if(*ptr == '+' || *ptr == '-' || (*ptr >= '0' && *ptr <= '9'))
02204 {
02205
02206 if(command == 'M')
02207 command = 'L';
02208 else if(command == 'm')
02209 command = 'l';
02210 }
02211 else
02212 command = *(ptr++);
02213
02214
02215 if(lastCommand != 'C' && lastCommand != 'c' &&
02216 lastCommand != 'S' && lastCommand != 's' &&
02217 lastCommand != 'Q' && lastCommand != 'q' &&
02218 lastCommand != 'T' && lastCommand != 't')
02219 {
02220 contrlx = curx;
02221 contrly = cury;
02222 }
02223 }
02224
02225
02226 int find = -1;
02227 for(int i = index; i >= 0; i--)
02228 {
02229 if(vec[i].code == ART_MOVETO_OPEN || vec[i].code == ART_MOVETO)
02230 {
02231 find = i;
02232 break;
02233 }
02234 }
02235
02236
02237 if(curx != vec[find].x3 && cury != vec[find].y3)
02238 {
02239 if((int) curx == (int) vec[find].x3 && (int) cury == (int) vec[find].y3)
02240 {
02241 index++;
02242
02243 if(vec.size() == (unsigned int) index)
02244 vec.resize(index + 1);
02245
02246 vec[index].code = ART_LINETO;
02247 vec[index].x3 = vec[find].x3;
02248 vec[index].y3 = vec[find].y3;
02249
02250 curx = vec[find].x3;
02251 cury = vec[find].y3;
02252 }
02253 }
02254
02255
02256 if(filled)
02257 {
02258 if((int) curx != (int) vec[find].x3 || (int) cury != (int) vec[find].y3)
02259 {
02260 index++;
02261
02262 if(vec.size() == (unsigned int) index)
02263 vec.resize(index + 1);
02264
02265 vec[index].code = (ArtPathcode)ART_END2;
02266 vec[index].x3 = vec[find].x3;
02267 vec[index].y3 = vec[find].y3;
02268
02269 curx = vec[find].x3;
02270 cury = vec[find].y3;
02271 }
02272 }
02273
02274
02275 index++;
02276
02277 if(vec.size() == (unsigned int) index)
02278 vec.resize(index + 1);
02279
02280 vec[index].code = ART_END;
02281
02282
02283
02284 bool render = false;
02285 for(int i = index; i >= 0; i--)
02286 {
02287 if(vec[i].code != ART_MOVETO_OPEN && vec[i].code != ART_MOVETO && !(vec[i].code >= ART_END))
02288 {
02289 render = true;
02290 break;
02291 }
02292 }
02293
02294 if(render)
02295 d->helper->drawBPath(vec.data());
02296 }
02297
02298 void KSVGIconPainter::drawImage(double x, double y, QImage &image)
02299 {
02300 if(image.depth() != 32)
02301 image = image.convertDepth(32);
02302
02303 double affine[6];
02304 affine[0] = d->helper->m_worldMatrix->m11();
02305 affine[1] = d->helper->m_worldMatrix->m12();
02306 affine[2] = d->helper->m_worldMatrix->m21();
02307 affine[3] = d->helper->m_worldMatrix->m22();
02308 affine[4] = d->helper->m_worldMatrix->dx() + x;
02309 affine[5] = d->helper->m_worldMatrix->dy() + y;
02310
02311 d->helper->art_rgba_rgba_affine(d->helper->m_buffer, 0, 0, d->helper->m_width, d->helper->m_height,
02312 d->helper->m_rowstride, image.bits(), image.width(), image.height(),
02313 image.width() * 4, affine);
02314 }
02315
02316 QColor KSVGIconPainter::parseColor(const QString ¶m)
02317 {
02318 if(param.stripWhiteSpace().startsWith("#"))
02319 {
02320 QColor color;
02321 color.setNamedColor(param.stripWhiteSpace());
02322 return color;
02323 }
02324 else if(param.stripWhiteSpace().startsWith("rgb("))
02325 {
02326 QString parse = param.stripWhiteSpace();
02327 QStringList colors = QStringList::split(',', parse);
02328 QString r = colors[0].right((colors[0].length() - 4));
02329 QString g = colors[1];
02330 QString b = colors[2].left((colors[2].length() - 1));
02331
02332 if(r.contains("%"))
02333 {
02334 r = r.left(r.length() - 1);
02335 r = QString::number(int((double(255 * r.toDouble()) / 100.0)));
02336 }
02337
02338 if(g.contains("%"))
02339 {
02340 g = g.left(g.length() - 1);
02341 g = QString::number(int((double(255 * g.toDouble()) / 100.0)));
02342 }
02343
02344 if(b.contains("%"))
02345 {
02346 b = b.left(b.length() - 1);
02347 b = QString::number(int((double(255 * b.toDouble()) / 100.0)));
02348 }
02349
02350 return QColor(r.toInt(), g.toInt(), b.toInt());
02351 }
02352 else
02353 {
02354 QString rgbColor = param.stripWhiteSpace();
02355
02356 if(rgbColor == "aliceblue")
02357 return QColor(240, 248, 255);
02358 else if(rgbColor == "antiquewhite")
02359 return QColor(250, 235, 215);
02360 else if(rgbColor == "aqua")
02361 return QColor(0, 255, 255);
02362 else if(rgbColor == "aquamarine")
02363 return QColor(127, 255, 212);
02364 else if(rgbColor == "azure")
02365 return QColor(240, 255, 255);
02366 else if(rgbColor == "beige")
02367 return QColor(245, 245, 220);
02368 else if(rgbColor == "bisque")
02369 return QColor(255, 228, 196);
02370 else if(rgbColor == "black")
02371 return QColor(0, 0, 0);
02372 else if(rgbColor == "blanchedalmond")
02373 return QColor(255, 235, 205);
02374 else if(rgbColor == "blue")
02375 return QColor(0, 0, 255);
02376 else if(rgbColor == "blueviolet")
02377 return QColor(138, 43, 226);
02378 else if(rgbColor == "brown")
02379 return QColor(165, 42, 42);
02380 else if(rgbColor == "burlywood")
02381 return QColor(222, 184, 135);
02382 else if(rgbColor == "cadetblue")
02383 return QColor(95, 158, 160);
02384 else if(rgbColor == "chartreuse")
02385 return QColor(127, 255, 0);
02386 else if(rgbColor == "chocolate")
02387 return QColor(210, 105, 30);
02388 else if(rgbColor == "coral")
02389 return QColor(255, 127, 80);
02390 else if(rgbColor == "cornflowerblue")
02391 return QColor(100, 149, 237);
02392 else if(rgbColor == "cornsilk")
02393 return QColor(255, 248, 220);
02394 else if(rgbColor == "crimson")
02395 return QColor(220, 20, 60);
02396 else if(rgbColor == "cyan")
02397 return QColor(0, 255, 255);
02398 else if(rgbColor == "darkblue")
02399 return QColor(0, 0, 139);
02400 else if(rgbColor == "darkcyan")
02401 return QColor(0, 139, 139);
02402 else if(rgbColor == "darkgoldenrod")
02403 return QColor(184, 134, 11);
02404 else if(rgbColor == "darkgray")
02405 return QColor(169, 169, 169);
02406 else if(rgbColor == "darkgrey")
02407 return QColor(169, 169, 169);
02408 else if(rgbColor == "darkgreen")
02409 return QColor(0, 100, 0);
02410 else if(rgbColor == "darkkhaki")
02411 return QColor(189, 183, 107);
02412 else if(rgbColor == "darkmagenta")
02413 return QColor(139, 0, 139);
02414 else if(rgbColor == "darkolivegreen")
02415 return QColor(85, 107, 47);
02416 else if(rgbColor == "darkorange")
02417 return QColor(255, 140, 0);
02418 else if(rgbColor == "darkorchid")
02419 return QColor(153, 50, 204);
02420 else if(rgbColor == "darkred")
02421 return QColor(139, 0, 0);
02422 else if(rgbColor == "darksalmon")
02423 return QColor(233, 150, 122);
02424 else if(rgbColor == "darkseagreen")
02425 return QColor(143, 188, 143);
02426 else if(rgbColor == "darkslateblue")
02427 return QColor(72, 61, 139);
02428 else if(rgbColor == "darkslategray")
02429 return QColor(47, 79, 79);
02430 else if(rgbColor == "darkslategrey")
02431 return QColor(47, 79, 79);
02432 else if(rgbColor == "darkturquoise")
02433 return QColor(0, 206, 209);
02434 else if(rgbColor == "darkviolet")
02435 return QColor(148, 0, 211);
02436 else if(rgbColor == "deeppink")
02437 return QColor(255, 20, 147);
02438 else if(rgbColor == "deepskyblue")
02439 return QColor(0, 191, 255);
02440 else if(rgbColor == "dimgray")
02441 return QColor(105, 105, 105);
02442 else if(rgbColor == "dimgrey")
02443 return QColor(105, 105, 105);
02444 else if(rgbColor == "dodgerblue")
02445 return QColor(30, 144, 255);
02446 else if(rgbColor == "firebrick")
02447 return QColor(178, 34, 34);
02448 else if(rgbColor == "floralwhite")
02449 return QColor(255, 250, 240);
02450 else if(rgbColor == "forestgreen")
02451 return QColor(34, 139, 34);
02452 else if(rgbColor == "fuchsia")
02453 return QColor(255, 0, 255);
02454 else if(rgbColor == "gainsboro")
02455 return QColor(220, 220, 220);
02456 else if(rgbColor == "ghostwhite")
02457 return QColor(248, 248, 255);
02458 else if(rgbColor == "gold")
02459 return QColor(255, 215, 0);
02460 else if(rgbColor == "goldenrod")
02461 return QColor(218, 165, 32);
02462 else if(rgbColor == "gray")
02463 return QColor(128, 128, 128);
02464 else if(rgbColor == "grey")
02465 return QColor(128, 128, 128);
02466 else if(rgbColor == "green")
02467 return QColor(0, 128, 0);
02468 else if(rgbColor == "greenyellow")
02469 return QColor(173, 255, 47);
02470 else if(rgbColor == "honeydew")
02471 return QColor(240, 255, 240);
02472 else if(rgbColor == "hotpink")
02473 return QColor(255, 105, 180);
02474 else if(rgbColor == "indianred")
02475 return QColor(205, 92, 92);
02476 else if(rgbColor == "indigo")
02477 return QColor(75, 0, 130);
02478 else if(rgbColor == "ivory")
02479 return QColor(255, 255, 240);
02480 else if(rgbColor == "khaki")
02481 return QColor(240, 230, 140);
02482 else if(rgbColor == "lavender")
02483 return QColor(230, 230, 250);
02484 else if(rgbColor == "lavenderblush")
02485 return QColor(255, 240, 245);
02486 else if(rgbColor == "lawngreen")
02487 return QColor(124, 252, 0);
02488 else if(rgbColor == "lemonchiffon")
02489 return QColor(255, 250, 205);
02490 else if(rgbColor == "lightblue")
02491 return QColor(173, 216, 230);
02492 else if(rgbColor == "lightcoral")
02493 return QColor(240, 128, 128);
02494 else if(rgbColor == "lightcyan")
02495 return QColor(224, 255, 255);
02496 else if(rgbColor == "lightgoldenrodyellow")
02497 return QColor(250, 250, 210);
02498 else if(rgbColor == "lightgray")
02499 return QColor(211, 211, 211);
02500 else if(rgbColor == "lightgrey")
02501 return QColor(211, 211, 211);
02502 else if(rgbColor == "lightgreen")
02503 return QColor(144, 238, 144);
02504 else if(rgbColor == "lightpink")
02505 return QColor(255, 182, 193);
02506 else if(rgbColor == "lightsalmon")
02507 return QColor(255, 160, 122);
02508 else if(rgbColor == "lightseagreen")
02509 return QColor(32, 178, 170);
02510 else if(rgbColor == "lightskyblue")
02511 return QColor(135, 206, 250);
02512 else if(rgbColor == "lightslategray")
02513 return QColor(119, 136, 153);
02514 else if(rgbColor == "lightslategrey")
02515 return QColor(119, 136, 153);
02516 else if(rgbColor == "lightsteelblue")
02517 return QColor(176, 196, 222);
02518 else if(rgbColor == "lightyellow")
02519 return QColor(255, 255, 224);
02520 else if(rgbColor == "lime")
02521 return QColor(0, 255, 0);
02522 else if(rgbColor == "limegreen")
02523 return QColor(50, 205, 50);
02524 else if(rgbColor == "linen")
02525 return QColor(250, 240, 230);
02526 else if(rgbColor == "magenta")
02527 return QColor(255, 0, 255);
02528 else if(rgbColor == "maroon")
02529 return QColor(128, 0, 0);
02530 else if(rgbColor == "mediumaquamarine")
02531 return QColor(102, 205, 170);
02532 else if(rgbColor == "mediumblue")
02533 return QColor(0, 0, 205);
02534 else if(rgbColor == "mediumorchid")
02535 return QColor(186, 85, 211);
02536 else if(rgbColor == "mediumpurple")
02537 return QColor(147, 112, 219);
02538 else if(rgbColor == "mediumseagreen")
02539 return QColor(60, 179, 113);
02540 else if(rgbColor == "mediumslateblue")
02541 return QColor(123, 104, 238);
02542 else if(rgbColor == "mediumspringgreen")
02543 return QColor(0, 250, 154);
02544 else if(rgbColor == "mediumturquoise")
02545 return QColor(72, 209, 204);
02546 else if(rgbColor == "mediumvioletred")
02547 return QColor(199, 21, 133);
02548 else if(rgbColor == "midnightblue")
02549 return QColor(25, 25, 112);
02550 else if(rgbColor == "mintcream")
02551 return QColor(245, 255, 250);
02552 else if(rgbColor == "mistyrose")
02553 return QColor(255, 228, 225);
02554 else if(rgbColor == "moccasin")
02555 return QColor(255, 228, 181);
02556 else if(rgbColor == "navajowhite")
02557 return QColor(255, 222, 173);
02558 else if(rgbColor == "navy")
02559 return QColor(0, 0, 128);
02560 else if(rgbColor == "oldlace")
02561 return QColor(253, 245, 230);
02562 else if(rgbColor == "olive")
02563 return QColor(128, 128, 0);
02564 else if(rgbColor == "olivedrab")
02565 return QColor(107, 142, 35);
02566 else if(rgbColor == "orange")
02567 return QColor(255, 165, 0);
02568 else if(rgbColor == "orangered")
02569 return QColor(255, 69, 0);
02570 else if(rgbColor == "orchid")
02571 return QColor(218, 112, 214);
02572 else if(rgbColor == "palegoldenrod")
02573 return QColor(238, 232, 170);
02574 else if(rgbColor == "palegreen")
02575 return QColor(152, 251, 152);
02576 else if(rgbColor == "paleturquoise")
02577 return QColor(175, 238, 238);
02578 else if(rgbColor == "palevioletred")
02579 return QColor(219, 112, 147);
02580 else if(rgbColor == "papayawhip")
02581 return QColor(255, 239, 213);
02582 else if(rgbColor == "peachpuff")
02583 return QColor(255, 218, 185);
02584 else if(rgbColor == "peru")
02585 return QColor(205, 133, 63);
02586 else if(rgbColor == "pink")
02587 return QColor(255, 192, 203);
02588 else if(rgbColor == "plum")
02589 return QColor(221, 160, 221);
02590 else if(rgbColor == "powderblue")
02591 return QColor(176, 224, 230);
02592 else if(rgbColor == "purple")
02593 return QColor(128, 0, 128);
02594 else if(rgbColor == "red")
02595 return QColor(255, 0, 0);
02596 else if(rgbColor == "rosybrown")
02597 return QColor(188, 143, 143);
02598 else if(rgbColor == "royalblue")
02599 return QColor(65, 105, 225);
02600 else if(rgbColor == "saddlebrown")
02601 return QColor(139, 69, 19);
02602 else if(rgbColor == "salmon")
02603 return QColor(250, 128, 114);
02604 else if(rgbColor == "sandybrown")
02605 return QColor(244, 164, 96);
02606 else if(rgbColor == "seagreen")
02607 return QColor(46, 139, 87);
02608 else if(rgbColor == "seashell")
02609 return QColor(255, 245, 238);
02610 else if(rgbColor == "sienna")
02611 return QColor(160, 82, 45);
02612 else if(rgbColor == "silver")
02613 return QColor(192, 192, 192);
02614 else if(rgbColor == "skyblue")
02615 return QColor(135, 206, 235);
02616 else if(rgbColor == "slateblue")
02617 return QColor(106, 90, 205);
02618 else if(rgbColor == "slategray")
02619 return QColor(112, 128, 144);
02620 else if(rgbColor == "slategrey")
02621 return QColor(112, 128, 144);
02622 else if(rgbColor == "snow")
02623 return QColor(255, 250, 250);
02624 else if(rgbColor == "springgreen")
02625 return QColor(0, 255, 127);
02626 else if(rgbColor == "steelblue")
02627 return QColor(70, 130, 180);
02628 else if(rgbColor == "tan")
02629 return QColor(210, 180, 140);
02630 else if(rgbColor == "teal")
02631 return QColor(0, 128, 128);
02632 else if(rgbColor == "thistle")
02633 return QColor(216, 191, 216);
02634 else if(rgbColor == "tomato")
02635 return QColor(255, 99, 71);
02636 else if(rgbColor == "turquoise")
02637 return QColor(64, 224, 208);
02638 else if(rgbColor == "violet")
02639 return QColor(238, 130, 238);
02640 else if(rgbColor == "wheat")
02641 return QColor(245, 222, 179);
02642 else if(rgbColor == "white")
02643 return QColor(255, 255, 255);
02644 else if(rgbColor == "whitesmoke")
02645 return QColor(245, 245, 245);
02646 else if(rgbColor == "yellow")
02647 return QColor(255, 255, 0);
02648 else if(rgbColor == "yellowgreen")
02649 return QColor(154, 205, 50);
02650 }
02651
02652 return QColor();
02653 }
02654
02655 double KSVGIconPainter::dpi()
02656 {
02657 return 90.0;
02658 }
02659
02660 double KSVGIconPainter::toPixel(const QString &s, bool hmode)
02661 {
02662 if(s.isEmpty())
02663 return 0.0;
02664
02665 QString check = s;
02666
02667 double ret = 0.0;
02668
02669 bool ok = false;
02670
02671 double value = check.toDouble(&ok);
02672
02673 if(!ok)
02674 {
02675 check.replace(QRegExp("[0-9 .-]"), QString::null);
02676
02677 if(check.compare("px") == 0)
02678 ret = value;
02679 else if(check.compare("cm") == 0)
02680 ret = (value / 2.54) * dpi();
02681 else if(check.compare("pc") == 0)
02682 ret = (value / 6.0) * dpi();
02683 else if(check.compare("mm") == 0)
02684 ret = (value / 25.4) * dpi();
02685 else if(check.compare("in") == 0)
02686 ret = value * dpi();
02687 else if(check.compare("pt") == 0)
02688 ret = (value / 72.0) * dpi();
02689 else if(check.compare("%") == 0)
02690 {
02691 ret = value / 100.0;
02692
02693 if(hmode)
02694 ret *= d->drawWidth;
02695 else
02696 ret *= d->drawHeight;
02697 }
02698 else if(check.compare("em") == 0)
02699 {
02700 ret = value * 10.0;
02701 }
02702 }
02703 else
02704 ret = value;
02705
02706 return ret;
02707 }
02708
02709 ArtGradientLinear *KSVGIconPainter::linearGradient(const QString &id)
02710 {
02711 return d->helper->m_linearGradientMap[id];
02712 }
02713
02714 void KSVGIconPainter::addLinearGradient(const QString &id, ArtGradientLinear *gradient)
02715 {
02716 d->helper->m_linearGradientMap.insert(id, gradient);
02717 }
02718
02719 QDomElement KSVGIconPainter::linearGradientElement(ArtGradientLinear *linear)
02720 {
02721 return d->helper->m_linearGradientElementMap[linear];
02722 }
02723
02724 void KSVGIconPainter::addLinearGradientElement(ArtGradientLinear *gradient, QDomElement element)
02725 {
02726 d->helper->m_linearGradientElementMap.insert(gradient, element);
02727 }
02728
02729 ArtGradientRadial *KSVGIconPainter::radialGradient(const QString &id)
02730 {
02731 return d->helper->m_radialGradientMap[id];
02732 }
02733
02734 void KSVGIconPainter::addRadialGradient(const QString &id, ArtGradientRadial *gradient)
02735 {
02736 d->helper->m_radialGradientMap.insert(id, gradient);
02737 }
02738
02739 QDomElement KSVGIconPainter::radialGradientElement(ArtGradientRadial *radial)
02740 {
02741 return d->helper->m_radialGradientElementMap[radial];
02742 }
02743
02744 void KSVGIconPainter::addRadialGradientElement(ArtGradientRadial *gradient, QDomElement element)
02745 {
02746 d->helper->m_radialGradientElementMap.insert(gradient, element);
02747 }
02748
02749 Q_UINT32 KSVGIconPainter::toArtColor(const QColor &color)
02750 {
02751 return d->helper->toArtColor(color);
02752 }
02753
02754 QWMatrix KSVGIconPainter::parseTransform(const QString &transform)
02755 {
02756 QWMatrix result;
02757
02758
02759 QStringList subtransforms = QStringList::split(')', transform);
02760 QStringList::ConstIterator it = subtransforms.begin();
02761 QStringList::ConstIterator end = subtransforms.end();
02762 for(; it != end; ++it)
02763 {
02764 QStringList subtransform = QStringList::split('(', (*it));
02765
02766 subtransform[0] = subtransform[0].stripWhiteSpace().lower();
02767 subtransform[1] = subtransform[1].simplifyWhiteSpace();
02768 QRegExp reg("[a-zA-Z,( ]");
02769 QStringList params = QStringList::split(reg, subtransform[1]);
02770
02771 if(subtransform[0].startsWith(";") || subtransform[0].startsWith(","))
02772 subtransform[0] = subtransform[0].right(subtransform[0].length() - 1);
02773
02774 if(subtransform[0] == "rotate")
02775 {
02776 if(params.count() == 3)
02777 {
02778 float x = params[1].toFloat();
02779 float y = params[2].toFloat();
02780
02781 result.translate(x, y);
02782 result.rotate(params[0].toFloat());
02783 result.translate(-x, -y);
02784 }
02785 else
02786 result.rotate(params[0].toFloat());
02787 }
02788 else if(subtransform[0] == "translate")
02789 {
02790 if(params.count() == 2)
02791 result.translate(params[0].toFloat(), params[1].toFloat());
02792 else
02793 result.translate(params[0].toFloat() , 0);
02794 }
02795 else if(subtransform[0] == "scale")
02796 {
02797 if(params.count() == 2)
02798 result.scale(params[0].toFloat(), params[1].toFloat());
02799 else
02800 result.scale(params[0].toFloat(), params[0].toFloat());
02801 }
02802 else if(subtransform[0] == "skewx")
02803 result.shear(tan(params[0].toFloat() * deg2rad), 0.0F);
02804 else if(subtransform[0] == "skewy")
02805 result.shear(tan(params[0].toFloat() * deg2rad), 0.0F);
02806 else if(subtransform[0] == "skewy")
02807 result.shear(0.0F, tan(params[0].toFloat() * deg2rad));
02808 else if(subtransform[0] == "matrix")
02809 {
02810 if(params.count() >= 6)
02811 result.setMatrix(params[0].toFloat(), params[1].toFloat(), params[2].toFloat(), params[3].toFloat(), params[4].toFloat(), params[5].toFloat());
02812 }
02813 }
02814
02815 return result;
02816 }