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