• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdecore
 

tdecore

  • tdecore
  • svgicons
ksvgiconpainter.cpp
1 /*
2  Copyright (C) 2002 Nikolas Zimmermann <wildfox@kde.org>
3  This file is part of the KDE project
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License as published by the Free Software Foundation; either
8  version 2 of the License, or (at your option) any later version.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Library General Public License for more details.
14 
15  You should have received a copy of the GNU Library General Public License
16  aint with this library; see the file COPYING.LIB. If not, write to
17  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  Boston, MA 02110-1301, USA.
19 */
20 
21 #include <tqvaluevector.h>
22 #include <tqstringlist.h>
23 #include <tqwmatrix.h>
24 #include <tqregexp.h>
25 #include <tqimage.h>
26 #include <tqdict.h>
27 #include <tqmap.h>
28 #include <tqdom.h>
29 
30 #include <math.h>
31 
32 #include <kdebug.h>
33 
34 #include <libart_lgpl/art_rgba.h>
35 #include <libart_lgpl/art_bpath.h>
36 #include <libart_lgpl/art_vpath.h>
37 #include <libart_lgpl/art_vpath_dash.h>
38 #include <libart_lgpl/art_affine.h>
39 #include <libart_lgpl/art_render_svp.h>
40 #include <libart_lgpl/art_svp.h>
41 #include <libart_lgpl/art_svp_vpath.h>
42 #include <libart_lgpl/art_svp_intersect.h>
43 #include <libart_lgpl/art_svp_vpath_stroke.h>
44 
45 #include "ksvgiconpainter.h"
46 
47 #define ART_END2 10
48 
49 const double deg2rad = 0.017453292519943295769; // pi/180
50 
51 class KSVGIconPainterHelper
52 {
53 public:
54  KSVGIconPainterHelper(int width, int height, KSVGIconPainter *painter)
55  {
56  m_painter = painter;
57 
58  m_clipSVP = 0;
59 
60  m_fillColor = Qt::black;
61 
62  m_useFill = true;
63  m_useStroke = false;
64 
65  m_useFillGradient = false;
66  m_useStrokeGradient = false;
67 
68  m_worldMatrix = new TQWMatrix();
69 
70  // Create new image with alpha support
71  m_image = new TQImage(width, height, 32);
72  m_image->setAlphaBuffer(true);
73 
74  m_strokeWidth = 1.0;
75  m_strokeMiterLimit = 4;
76  m_dashOffset = 0;
77  m_dashes = "";
78 
79  m_opacity = 0xff;
80  m_fillOpacity = 0xff;
81  m_strokeOpacity = 0xff;
82 
83  m_fillRule = "nonzero";
84 
85  m_width = width;
86  m_height = height;
87 
88  m_rowstride = m_width * 4;
89 
90  // Make internal libart rendering buffer transparent
91  m_buffer = art_new(art_u8, m_rowstride * m_height);
92  memset(m_buffer, 0, m_rowstride * m_height);
93 
94  m_tempBuffer = 0;
95  }
96 
97  ~KSVGIconPainterHelper()
98  {
99  if(m_clipSVP)
100  art_svp_free(m_clipSVP);
101 
102  art_free(m_buffer);
103 
104  delete m_image;
105  delete m_worldMatrix;
106 
107  for(TQMap<TQString, ArtGradientLinear *>::Iterator it = m_linearGradientMap.begin(); it != m_linearGradientMap.end(); ++it)
108  {
109  if (!it.data())
110  continue;
111  delete [] it.data()->stops;
112  delete it.data();
113  }
114  for(TQMap<TQString, ArtGradientRadial *>::Iterator it = m_radialGradientMap.begin(); it != m_radialGradientMap.end(); ++it)
115  {
116  if (!it.data())
117  continue;
118  delete [] it.data()->stops;
119  delete it.data();
120  }
121  }
122 
123  ArtVpath *allocVPath(int number)
124  {
125  return art_new(ArtVpath, number);
126  }
127 
128  ArtBpath *allocBPath(int number)
129  {
130  return art_new(ArtBpath, number);
131  }
132 
133  void ensureSpace(TQMemArray<ArtBpath> &vec, int index)
134  {
135  if(vec.size() == (unsigned int) index)
136  vec.resize(index + 1);
137  }
138 
139  void createBuffer()
140  {
141  m_tempBuffer = art_new(art_u8, m_rowstride * m_height);
142  memset(m_tempBuffer, 0, m_rowstride * m_height);
143 
144  // Swap buffers, so we work with the new one internally...
145  art_u8 *temp = m_buffer;
146  m_buffer = m_tempBuffer;
147  m_tempBuffer = temp;
148  }
149 
150  void mixBuffer(int opacity)
151  {
152  art_u8 *srcPixel = m_buffer;
153  art_u8 *dstPixel = m_tempBuffer;
154 
155  for(int y = 0; y < m_height; y++)
156  {
157  for(int x = 0; x < m_width; x++)
158  {
159  art_u8 r, g, b, a;
160 
161  a = srcPixel[4 * x + 3];
162 
163  if(a)
164  {
165  r = srcPixel[4 * x];
166  g = srcPixel[4 * x + 1];
167  b = srcPixel[4 * x + 2];
168 
169  int temp = a * opacity + 0x80;
170  a = (temp + (temp >> 8)) >> 8;
171  art_rgba_run_alpha(dstPixel + 4 * x, r, g, b, a, 1);
172  }
173  }
174 
175  srcPixel += m_rowstride;
176  dstPixel += m_rowstride;
177  }
178 
179  // Re-swap again...
180  art_u8 *temp = m_buffer;
181  m_buffer = m_tempBuffer;
182  m_tempBuffer = temp;
183 
184  art_free(m_tempBuffer);
185  m_tempBuffer = 0;
186  }
187 
188  TQ_UINT32 toArtColor(const TQColor &color)
189  {
190  // Convert in a libart suitable form
191  TQString tempName = color.name();
192  const char *str = tempName.latin1();
193 
194  int result = 0;
195 
196  for(int i = 1; str[i]; i++)
197  {
198  int hexval;
199  if(str[i] >= '0' && str[i] <= '9')
200  hexval = str[i] - '0';
201  else if (str[i] >= 'A' && str[i] <= 'F')
202  hexval = str[i] - 'A' + 10;
203  else if (str[i] >= 'a' && str[i] <= 'f')
204  hexval = str[i] - 'a' + 10;
205  else
206  break;
207 
208  result = (result << 4) + hexval;
209  }
210 
211  return result;
212  }
213 
214  void drawSVP(ArtSVP *svp, TQ_UINT32 rgb, int opacity)
215  {
216  if(!svp)
217  return;
218 
219  ArtRender *render = art_render_new(0, 0, m_width, m_height, m_buffer, m_rowstride, 3, 8, ART_ALPHA_SEPARATE, 0);
220  art_render_svp(render, svp);
221 
222  art_render_mask_solid(render, (opacity << 8) + opacity + (opacity >> 7));
223 
224  ArtPixMaxDepth color[3];
225  color[0] = ART_PIX_MAX_FROM_8(rgb >> 16);
226  color[1] = ART_PIX_MAX_FROM_8((rgb >> 8) & 0xff);
227  color[2] = ART_PIX_MAX_FROM_8(rgb & 0xff);
228 
229  art_render_image_solid(render, color);
230  art_render_invoke(render);
231  }
232 
233  void drawBPath(ArtBpath *bpath)
234  {
235  double affine[6];
236  affine[0] = m_worldMatrix->m11();
237  affine[1] = m_worldMatrix->m12();
238  affine[2] = m_worldMatrix->m21();
239  affine[3] = m_worldMatrix->m22();
240  affine[4] = m_worldMatrix->dx();
241  affine[5] = m_worldMatrix->dy();
242 
243  ArtBpath *temp = art_bpath_affine_transform(bpath, affine);
244  ArtVpath *vec = art_bez_path_to_vec(temp, 0.25);
245  art_free(temp);
246  drawPathInternal(vec, affine);
247  }
248 
249  void drawVPath(ArtVpath *vec)
250  {
251  double affine[6];
252  affine[0] = m_worldMatrix->m11();
253  affine[1] = m_worldMatrix->m12();
254  affine[2] = m_worldMatrix->m21();
255  affine[3] = m_worldMatrix->m22();
256  affine[4] = m_worldMatrix->dx();
257  affine[5] = m_worldMatrix->dy();
258 
259  ArtVpath *temp = art_vpath_affine_transform(vec, affine);
260  art_free(vec);
261  vec = temp;
262  drawPathInternal(vec, affine);
263  }
264 
265  void drawPathInternal(ArtVpath *vec, double *affine)
266  {
267  ArtSVP *svp;
268  ArtSVP *fillSVP = 0, *strokeSVP = 0;
269 
270  TQ_UINT32 fillColor = 0, strokeColor = 0;
271 
272  // Filling
273  {
274  int index = -1;
275  TQValueVector<int> toCorrect;
276  while(vec[++index].code != ART_END)
277  {
278  if(vec[index].code == ART_END2)
279  {
280  vec[index].code = ART_LINETO;
281  toCorrect.push_back(index);
282  }
283  }
284 
285  fillColor = toArtColor(m_fillColor);
286 
287  ArtSvpWriter *swr;
288  ArtSVP *temp;
289  temp = art_svp_from_vpath(vec);
290 
291  if(m_fillRule == "evenodd")
292  swr = art_svp_writer_rewind_new(ART_WIND_RULE_ODDEVEN);
293  else
294  swr = art_svp_writer_rewind_new(ART_WIND_RULE_NONZERO);
295 
296  art_svp_intersector(temp, swr);
297  svp = art_svp_writer_rewind_reap(swr);
298 
299  fillSVP = svp;
300 
301  art_svp_free(temp);
302 
303  TQValueVector<int>::iterator it;
304  for(it = toCorrect.begin(); it != toCorrect.end(); ++it)
305  vec[(*it)].code = (ArtPathcode)ART_END2;
306  }
307 
308  // There seems to be a problem when stroke width is zero, this is a quick
309  // fix (Rob).
310  if(m_strokeWidth <= 0)
311  m_useStroke = m_useStrokeGradient = false;
312 
313  // Stroking
314  if(m_useStroke || m_useStrokeGradient)
315  {
316  strokeColor = toArtColor(m_strokeColor);
317 
318  double ratio = art_affine_expansion(affine);
319  double strokeWidth = m_strokeWidth * ratio;
320 
321  ArtPathStrokeJoinType joinStyle = ART_PATH_STROKE_JOIN_MITER;
322  ArtPathStrokeCapType capStyle = ART_PATH_STROKE_CAP_BUTT;
323 
324  if(m_joinStyle == "miter")
325  joinStyle = ART_PATH_STROKE_JOIN_MITER;
326  else if(m_joinStyle == "round")
327  joinStyle = ART_PATH_STROKE_JOIN_ROUND;
328  else if(m_joinStyle == "bevel")
329  joinStyle = ART_PATH_STROKE_JOIN_BEVEL;
330 
331  if(m_capStyle == "butt")
332  capStyle = ART_PATH_STROKE_CAP_BUTT;
333  else if(m_capStyle == "round")
334  capStyle = ART_PATH_STROKE_CAP_ROUND;
335  else if(m_capStyle == "square")
336  capStyle = ART_PATH_STROKE_CAP_SQUARE;
337 
338  if(m_dashes.length() > 0)
339  {
340  TQRegExp reg("[, ]");
341  TQStringList dashList = TQStringList::split(reg, m_dashes);
342 
343  double *dashes = new double[dashList.count()];
344  for(unsigned int i = 0; i < dashList.count(); i++)
345  dashes[i] = m_painter->toPixel(dashList[i], true);
346 
347  ArtVpathDash dash;
348  dash.offset = m_dashOffset;
349  dash.n_dash = dashList.count();
350 
351  dash.dash = dashes;
352 
353  ArtVpath *vec2 = art_vpath_dash(vec, &dash);
354  art_free(vec);
355 
356  delete[] dashes;
357 
358  vec = vec2;
359  }
360 
361  svp = art_svp_vpath_stroke(vec, joinStyle, capStyle, strokeWidth, m_strokeMiterLimit, 0.25);
362 
363  strokeSVP = svp;
364  }
365 
366  // Apply opacity
367  int fillOpacity = static_cast<int>(m_fillOpacity);
368  int strokeOpacity = static_cast<int>(m_strokeOpacity);
369  int opacity = static_cast<int>(m_opacity);
370 
371  // Needed hack, to support both transparent
372  // paths and transparent gradients
373  if(fillOpacity == strokeOpacity && fillOpacity == opacity && !m_useFillGradient && !m_useStrokeGradient)
374  opacity = 255;
375 
376  if(fillOpacity != 255)
377  {
378  int temp = fillOpacity * opacity + 0x80;
379  fillOpacity = (temp + (temp >> 8)) >> 8;
380  }
381 
382  if(strokeOpacity != 255)
383  {
384  int temp = strokeOpacity * opacity + 0x80;
385  strokeOpacity = (temp + (temp >> 8)) >> 8;
386  }
387 
388  // Create temporary buffer if necessary
389  bool tempDone = false;
390  if(m_opacity != 0xff)
391  {
392  tempDone = true;
393  createBuffer();
394  }
395 
396  // Apply Gradients on fill/stroke
397  if(m_useFillGradient)
398  applyGradient(fillSVP, true);
399  else if(m_useFill)
400  drawSVP(fillSVP, fillColor, fillOpacity);
401 
402  if(m_useStrokeGradient)
403  applyGradient(strokeSVP, false);
404  else if(m_useStroke)
405  drawSVP(strokeSVP, strokeColor, strokeOpacity);
406 
407  // Mix in temporary buffer, if possible
408  if(tempDone)
409  mixBuffer(opacity);
410 
411  if(m_clipSVP)
412  {
413  art_svp_free(m_clipSVP);
414  m_clipSVP = 0;
415  }
416 
417  if(fillSVP)
418  art_svp_free(fillSVP);
419 
420  if(strokeSVP)
421  art_svp_free(strokeSVP);
422 
423  // Reset opacity values
424  m_opacity = 255.0;
425  m_fillOpacity = 255.0;
426  m_strokeOpacity = 255.0;
427 
428  art_free(vec);
429  }
430 
431  void applyLinearGradient(ArtSVP *svp, const TQString &ref)
432  {
433  ArtGradientLinear *linear = m_linearGradientMap[ref];
434  if(linear)
435  {
436  TQDomElement element = m_linearGradientElementMap[linear];
437 
438  double x1, y1, x2, y2;
439  if(element.hasAttribute("x1"))
440  x1 = m_painter->toPixel(element.attribute("x1"), true);
441  else
442  x1 = 0;
443 
444  if(element.hasAttribute("y1"))
445  y1 = m_painter->toPixel(element.attribute("y1"), false);
446  else
447  y1 = 0;
448 
449  if(element.hasAttribute("x2"))
450  x2 = m_painter->toPixel(element.attribute("x2"), true);
451  else
452  x2 = 100;
453 
454  if(element.hasAttribute("y2"))
455  y2 = m_painter->toPixel(element.attribute("y2"), false);
456  else
457  y2 = 0;
458 
459  // Adjust to gradientTransform
460  TQWMatrix m = m_painter->parseTransform(element.attribute("gradientTransform"));
461  m.map(x1, y1, &x1, &y1);
462  m.map(x2, y2, &x2, &y2);
463 
464  double x1n = x1 * m_worldMatrix->m11() + y1 * m_worldMatrix->m21() + m_worldMatrix->dx();
465  double y1n = x1 * m_worldMatrix->m12() + y1 * m_worldMatrix->m22() + m_worldMatrix->dy();
466  double x2n = x2 * m_worldMatrix->m11() + y2 * m_worldMatrix->m21() + m_worldMatrix->dx();
467  double y2n = x2 * m_worldMatrix->m12() + y2 * m_worldMatrix->m22() + m_worldMatrix->dy();
468 
469  double dx = x2n - x1n;
470  double dy = y2n - y1n;
471  double scale = 1.0 / (dx * dx + dy * dy);
472 
473  linear->a = dx * scale;
474  linear->b = dy * scale;
475  linear->c = -(x1n * linear->a + y1n * linear->b);
476 
477  ArtRender *render = art_render_new(0, 0, m_width, m_height, m_buffer, m_rowstride, 3, 8, ART_ALPHA_SEPARATE, 0);
478  art_render_svp(render, svp);
479 
480  art_render_gradient_linear(render, linear, ART_FILTER_HYPER);
481  art_render_invoke(render);
482  }
483  }
484 
485  void applyRadialGradient(ArtSVP *svp, const TQString &ref)
486  {
487  ArtGradientRadial *radial = m_radialGradientMap[ref];
488  if(radial)
489  {
490  TQDomElement element = m_radialGradientElementMap[radial];
491 
492  double cx, cy, r, fx, fy;
493  if(element.hasAttribute("cx"))
494  cx = m_painter->toPixel(element.attribute("cx"), true);
495  else
496  cx = 50;
497 
498  if(element.hasAttribute("cy"))
499  cy = m_painter->toPixel(element.attribute("cy"), false);
500  else
501  cy = 50;
502 
503  if(element.hasAttribute("r"))
504  r = m_painter->toPixel(element.attribute("r"), true);
505  else
506  r = 50;
507 
508  if(element.hasAttribute("fx"))
509  fx = m_painter->toPixel(element.attribute("fx"), false);
510  else
511  fx = cx;
512 
513  if(element.hasAttribute("fy"))
514  fy = m_painter->toPixel(element.attribute("fy"), false);
515  else
516  fy = cy;
517 
518  radial->affine[0] = m_worldMatrix->m11();
519  radial->affine[1] = m_worldMatrix->m12();
520  radial->affine[2] = m_worldMatrix->m21();
521  radial->affine[3] = m_worldMatrix->m22();
522  radial->affine[4] = m_worldMatrix->dx();
523  radial->affine[5] = m_worldMatrix->dy();
524 
525  radial->fx = (fx - cx) / r;
526  radial->fy = (fy - cy) / r;
527 
528  double aff1[6], aff2[6], gradTransform[6];
529 
530  // Respect gradientTransform
531  TQWMatrix m = m_painter->parseTransform(element.attribute("gradientTransform"));
532 
533  gradTransform[0] = m.m11();
534  gradTransform[1] = m.m12();
535  gradTransform[2] = m.m21();
536  gradTransform[3] = m.m22();
537  gradTransform[4] = m.dx();
538  gradTransform[5] = m.dy();
539 
540  art_affine_scale(aff1, r, r);
541  art_affine_translate(aff2, cx, cy);
542 
543  art_affine_multiply(aff1, aff1, aff2);
544  art_affine_multiply(aff1, aff1, gradTransform);
545  art_affine_multiply(aff1, aff1, radial->affine);
546  art_affine_invert(radial->affine, aff1);
547 
548  ArtRender *render = art_render_new(0, 0, m_width, m_height, m_buffer, m_rowstride, 3, 8, ART_ALPHA_SEPARATE, 0);
549  art_render_svp(render, svp);
550 
551  art_render_gradient_radial(render, radial, ART_FILTER_HYPER);
552  art_render_invoke(render);
553  }
554  }
555 
556  void applyGradient(ArtSVP *svp, const TQString &ref)
557  {
558  ArtGradientLinear *linear = m_linearGradientMap[ref];
559  if(linear)
560  {
561  TQDomElement element = m_linearGradientElementMap[linear];
562 
563  if(!element.hasAttribute("xlink:href"))
564  {
565  applyLinearGradient(svp, ref);
566  return;
567  }
568  else
569  {
570  ArtGradientLinear *linear = m_linearGradientMap[element.attribute("xlink:href").mid(1)];
571  TQDomElement newElement = m_linearGradientElementMap[linear];
572 
573  // Saved 'old' attributes
574  TQDict<TQString> refattrs;
575  refattrs.setAutoDelete(true);
576 
577  for(unsigned int i = 0; i < newElement.attributes().length(); ++i)
578  refattrs.insert(newElement.attributes().item(i).nodeName(), new TQString(newElement.attributes().item(i).nodeValue()));
579 
580  // Copy attributes
581  if(!newElement.isNull())
582  {
583  TQDomNamedNodeMap attr = element.attributes();
584 
585  for(unsigned int i = 0; i < attr.length(); i++)
586  {
587  TQString name = attr.item(i).nodeName();
588  if(name != "xlink:href" && name != "id")
589  newElement.setAttribute(name, attr.item(i).nodeValue());
590  }
591  }
592 
593  applyGradient(svp, element.attribute("xlink:href").mid(1));
594 
595  // Restore attributes
596  TQDictIterator<TQString> itr(refattrs);
597  for(; itr.current(); ++itr)
598  newElement.setAttribute(itr.currentKey(), *(itr.current()));
599 
600  return;
601  }
602  }
603 
604  ArtGradientRadial *radial = m_radialGradientMap[ref];
605  if(radial)
606  {
607  TQDomElement element = m_radialGradientElementMap[radial];
608 
609  if(!element.hasAttribute("xlink:href"))
610  {
611  applyRadialGradient(svp, ref);
612  return;
613  }
614  else
615  {
616  ArtGradientRadial *radial = m_radialGradientMap[element.attribute("xlink:href").mid(1)];
617  TQDomElement newElement = m_radialGradientElementMap[radial];
618 
619  // Saved 'old' attributes
620  TQDict<TQString> refattrs;
621  refattrs.setAutoDelete(true);
622 
623  for(unsigned int i = 0; i < newElement.attributes().length(); ++i)
624  refattrs.insert(newElement.attributes().item(i).nodeName(), new TQString(newElement.attributes().item(i).nodeValue()));
625 
626  // Copy attributes
627  if(!newElement.isNull())
628  {
629  TQDomNamedNodeMap attr = element.attributes();
630 
631  for(unsigned int i = 0; i < attr.length(); i++)
632  {
633  TQString name = attr.item(i).nodeName();
634  if(name != "xlink:href" && name != "id")
635  newElement.setAttribute(name, attr.item(i).nodeValue());
636  }
637  }
638 
639  applyGradient(svp, element.attribute("xlink:href").mid(1));
640 
641  // Restore attributes
642  TQDictIterator<TQString> itr(refattrs);
643  for(; itr.current(); ++itr)
644  newElement.setAttribute(itr.currentKey(), *(itr.current()));
645 
646  return;
647  }
648  }
649  }
650 
651  void applyGradient(ArtSVP *svp, bool fill)
652  {
653  TQString ref;
654 
655  if(fill)
656  {
657  m_useFillGradient = false;
658  ref = m_fillGradientReference;
659  }
660  else
661  {
662  m_useStrokeGradient = false;
663  ref = m_strokeGradientReference;
664  }
665 
666  applyGradient(svp, ref);
667  }
668 
669  void blit()
670  {
671  unsigned char *line = m_buffer;
672 
673  for(int y = 0; y < m_height; y++)
674  {
675  TQRgb *sl = reinterpret_cast<TQRgb *>(m_image->scanLine(y));
676  for(int x = 0; x < m_width; x++)
677  sl[x] = tqRgba(line[x * 4], line[x * 4 + 1], line[x * 4 + 2], line[x * 4 + 3]);
678 
679  line += m_rowstride;
680  }
681  }
682 
683  void calculateArc(bool relative, TQMemArray<ArtBpath> &vec, int &index, double &curx, double &cury, double angle, double x, double y, double r1, double r2, bool largeArcFlag, bool sweepFlag)
684  {
685  double sin_th, cos_th;
686  double a00, a01, a10, a11;
687  double x0, y0, x1, y1, xc, yc;
688  double d, sfactor, sfactor_sq;
689  double th0, th1, th_arc;
690  int i, n_segs;
691 
692  sin_th = sin(angle * (M_PI / 180.0));
693  cos_th = cos(angle * (M_PI / 180.0));
694 
695  double dx;
696 
697  if(!relative)
698  dx = (curx - x) / 2.0;
699  else
700  dx = -x / 2.0;
701 
702  double dy;
703 
704  if(!relative)
705  dy = (cury - y) / 2.0;
706  else
707  dy = -y / 2.0;
708 
709  double _x1 = cos_th * dx + sin_th * dy;
710  double _y1 = -sin_th * dx + cos_th * dy;
711  double Pr1 = r1 * r1;
712  double Pr2 = r2 * r2;
713  double Px = _x1 * _x1;
714  double Py = _y1 * _y1;
715 
716  // Spec : check if radii are large enough
717  double check = Px / Pr1 + Py / Pr2;
718  if(check > 1)
719  {
720  r1 = r1 * sqrt(check);
721  r2 = r2 * sqrt(check);
722  }
723 
724  a00 = cos_th / r1;
725  a01 = sin_th / r1;
726  a10 = -sin_th / r2;
727  a11 = cos_th / r2;
728 
729  x0 = a00 * curx + a01 * cury;
730  y0 = a10 * curx + a11 * cury;
731 
732  if(!relative)
733  x1 = a00 * x + a01 * y;
734  else
735  x1 = a00 * (curx + x) + a01 * (cury + y);
736 
737  if(!relative)
738  y1 = a10 * x + a11 * y;
739  else
740  y1 = a10 * (curx + x) + a11 * (cury + y);
741 
742  /* (x0, y0) is current point in transformed coordinate space.
743  (x1, y1) is new point in transformed coordinate space.
744 
745  The arc fits a unit-radius circle in this space.
746  */
747 
748  d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
749 
750  if (d)
751  {
752  sfactor_sq = 1.0 / d - 0.25;
753  }
754  else
755  {
756  sfactor_sq = 0;
757  }
758 
759  if(sfactor_sq < 0)
760  sfactor_sq = 0;
761 
762  sfactor = sqrt(sfactor_sq);
763 
764  if(sweepFlag == largeArcFlag)
765  sfactor = -sfactor;
766 
767  xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0);
768  yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0);
769 
770  /* (xc, yc) is center of the circle. */
771  th0 = atan2(y0 - yc, x0 - xc);
772  th1 = atan2(y1 - yc, x1 - xc);
773 
774  th_arc = th1 - th0;
775  if(th_arc < 0 && sweepFlag)
776  th_arc += 2 * M_PI;
777  else if(th_arc > 0 && !sweepFlag)
778  th_arc -= 2 * M_PI;
779 
780  n_segs = (int) ceil(fabs(th_arc / (M_PI * 0.5 + 0.001)));
781 
782  for(i = 0; i < n_segs; i++)
783  {
784  index++;
785 
786  ensureSpace(vec, index);
787 
788  {
789  double sin_th, cos_th;
790  double a00, a01, a10, a11;
791  double x1, y1, x2, y2, x3, y3;
792  double t;
793  double th_half;
794 
795  double _th0 = th0 + i * th_arc / n_segs;
796  double _th1 = th0 + (i + 1) * th_arc / n_segs;
797 
798  sin_th = sin(angle * (M_PI / 180.0));
799  cos_th = cos(angle * (M_PI / 180.0));
800 
801  /* inverse transform compared with rsvg_path_arc */
802  a00 = cos_th * r1;
803  a01 = -sin_th * r2;
804  a10 = sin_th * r1;
805  a11 = cos_th * r2;
806 
807  th_half = 0.5 * (_th1 - _th0);
808  t = (8.0 / 3.0) * sin(th_half * 0.5) * sin(th_half * 0.5) / sin(th_half);
809  x1 = xc + cos(_th0) - t * sin(_th0);
810  y1 = yc + sin(_th0) + t * cos(_th0);
811  x3 = xc + cos(_th1);
812  y3 = yc + sin(_th1);
813  x2 = x3 + t * sin(_th1);
814  y2 = y3 - t * cos(_th1);
815 
816  ensureSpace(vec, index);
817 
818  vec[index].code = ART_CURVETO;
819  vec[index].x1 = a00 * x1 + a01 * y1;
820  vec[index].y1 = a10 * x1 + a11 * y1;
821  vec[index].x2 = a00 * x2 + a01 * y2;
822  vec[index].y2 = a10 * x2 + a11 * y2;
823  vec[index].x3 = a00 * x3 + a01 * y3;
824  vec[index].y3 = a10 * x3 + a11 * y3;
825  }
826  }
827 
828  if(!relative)
829  curx = x;
830  else
831  curx += x;
832 
833  if(!relative)
834  cury = y;
835  else
836  cury += y;
837  }
838 
839  // For any docs, see the libart library
840  static void art_vpath_render_bez(ArtVpath **p_vpath, int *pn, int *pn_max,
841  double x0, double y0,
842  double x1, double y1,
843  double x2, double y2,
844  double x3, double y3,
845  double flatness)
846  {
847  double x3_0, y3_0, z3_0_dot, z1_dot, z2_dot;
848  double z1_perp, z2_perp, max_perp_sq;
849 
850  double x_m, y_m, xa1, ya1, xa2, ya2, xb1, yb1, xb2, yb2;
851 
852  x3_0 = x3 - x0;
853  y3_0 = y3 - y0;
854 
855  z3_0_dot = x3_0 * x3_0 + y3_0 * y3_0;
856 
857  if (z3_0_dot < 0.001)
858  goto nosubdivide;
859 
860  max_perp_sq = flatness * flatness * z3_0_dot;
861 
862  z1_perp = (y1 - y0) * x3_0 - (x1 - x0) * y3_0;
863  if (z1_perp * z1_perp > max_perp_sq)
864  goto subdivide;
865 
866  z2_perp = (y3 - y2) * x3_0 - (x3 - x2) * y3_0;
867  if (z2_perp * z2_perp > max_perp_sq)
868  goto subdivide;
869 
870  z1_dot = (x1 - x0) * x3_0 + (y1 - y0) * y3_0;
871  if (z1_dot < 0 && z1_dot * z1_dot > max_perp_sq)
872  goto subdivide;
873 
874  z2_dot = (x3 - x2) * x3_0 + (y3 - y2) * y3_0;
875  if (z2_dot < 0 && z2_dot * z2_dot > max_perp_sq)
876  goto subdivide;
877 
878  if (z1_dot + z1_dot > z3_0_dot)
879  goto subdivide;
880 
881  if (z2_dot + z2_dot > z3_0_dot)
882  goto subdivide;
883 
884  nosubdivide:
885  art_vpath_add_point (p_vpath, pn, pn_max, ART_LINETO, x3, y3);
886  return;
887 
888  subdivide:
889  xa1 = (x0 + x1) * 0.5;
890  ya1 = (y0 + y1) * 0.5;
891  xa2 = (x0 + 2 * x1 + x2) * 0.25;
892  ya2 = (y0 + 2 * y1 + y2) * 0.25;
893  xb1 = (x1 + 2 * x2 + x3) * 0.25;
894  yb1 = (y1 + 2 * y2 + y3) * 0.25;
895  xb2 = (x2 + x3) * 0.5;
896  yb2 = (y2 + y3) * 0.5;
897  x_m = (xa2 + xb1) * 0.5;
898  y_m = (ya2 + yb1) * 0.5;
899  art_vpath_render_bez (p_vpath, pn, pn_max, x0, y0, xa1, ya1, xa2, ya2, x_m, y_m, flatness);
900  art_vpath_render_bez (p_vpath, pn, pn_max, x_m, y_m, xb1, yb1, xb2, yb2, x3, y3, flatness);
901  }
902 
903  ArtVpath *art_bez_path_to_vec(const ArtBpath *bez, double flatness)
904  {
905  ArtVpath *vec;
906  int vec_n, vec_n_max;
907  int bez_index;
908  double x, y;
909 
910  vec_n = 0;
911  vec_n_max = (1 << 4);
912  vec = art_new (ArtVpath, vec_n_max);
913 
914  x = 0;
915  y = 0;
916 
917  bez_index = 0;
918  do
919  {
920  if(vec_n >= vec_n_max)
921  art_expand (vec, ArtVpath, vec_n_max);
922 
923  switch (bez[bez_index].code)
924  {
925  case ART_MOVETO_OPEN:
926  case ART_MOVETO:
927  case ART_LINETO:
928  x = bez[bez_index].x3;
929  y = bez[bez_index].y3;
930  vec[vec_n].code = bez[bez_index].code;
931  vec[vec_n].x = x;
932  vec[vec_n].y = y;
933  vec_n++;
934  break;
935  case ART_END:
936  vec[vec_n].code = ART_END;
937  vec[vec_n].x = 0;
938  vec[vec_n].y = 0;
939  vec_n++;
940  break;
941  case ART_END2:
942  vec[vec_n].code = (ArtPathcode)ART_END2;
943  vec[vec_n].x = bez[bez_index].x3;
944  vec[vec_n].y = bez[bez_index].y3;
945  vec_n++;
946  break;
947  case ART_CURVETO:
948  art_vpath_render_bez (&vec, &vec_n, &vec_n_max,
949  x, y,
950  bez[bez_index].x1, bez[bez_index].y1,
951  bez[bez_index].x2, bez[bez_index].y2,
952  bez[bez_index].x3, bez[bez_index].y3,
953  flatness);
954  x = bez[bez_index].x3;
955  y = bez[bez_index].y3;
956  break;
957  }
958  }
959 
960  while (bez[bez_index++].code != ART_END);
961  return vec;
962  }
963 
964  static void art_rgb_affine_run(int *p_x0, int *p_x1, int y,
965  int src_width, int src_height,
966  const double affine[6])
967  {
968  int x0, x1;
969  double z;
970  double x_intercept;
971  int xi;
972 
973  x0 = *p_x0;
974  x1 = *p_x1;
975 
976  if (affine[0] > 1e-6)
977  {
978  z = affine[2] * (y + 0.5) + affine[4];
979  x_intercept = -z / affine[0];
980  xi = (int) (int) ceil (x_intercept + 1e-6 - 0.5);
981  if (xi > x0)
982  x0 = xi;
983  x_intercept = (-z + src_width) / affine[0];
984  xi = (int) ceil (x_intercept - 1e-6 - 0.5);
985  if (xi < x1)
986  x1 = xi;
987  }
988  else if (affine[0] < -1e-6)
989  {
990  z = affine[2] * (y + 0.5) + affine[4];
991  x_intercept = (-z + src_width) / affine[0];
992  xi = (int) ceil (x_intercept + 1e-6 - 0.5);
993  if (xi > x0)
994  x0 = xi;
995  x_intercept = -z / affine[0];
996  xi = (int) ceil (x_intercept - 1e-6 - 0.5);
997  if (xi < x1)
998  x1 = xi;
999  }
1000  else
1001  {
1002  z = affine[2] * (y + 0.5) + affine[4];
1003  if (z < 0 || z >= src_width)
1004  {
1005  *p_x1 = *p_x0;
1006  return;
1007  }
1008  }
1009  if (affine[1] > 1e-6)
1010  {
1011  z = affine[3] * (y + 0.5) + affine[5];
1012  x_intercept = -z / affine[1];
1013  xi = (int) ceil (x_intercept + 1e-6 - 0.5);
1014  if (xi > x0)
1015  x0 = xi;
1016  x_intercept = (-z + src_height) / affine[1];
1017  xi = (int) ceil (x_intercept - 1e-6 - 0.5);
1018  if (xi < x1)
1019  x1 = xi;
1020  }
1021  else if (affine[1] < -1e-6)
1022  {
1023  z = affine[3] * (y + 0.5) + affine[5];
1024  x_intercept = (-z + src_height) / affine[1];
1025  xi = (int) ceil (x_intercept + 1e-6 - 0.5);
1026  if (xi > x0)
1027  x0 = xi;
1028  x_intercept = -z / affine[1];
1029  xi = (int) ceil (x_intercept - 1e-6 - 0.5);
1030  if (xi < x1)
1031  x1 = xi;
1032  }
1033  else
1034  {
1035  z = affine[3] * (y + 0.5) + affine[5];
1036  if (z < 0 || z >= src_height)
1037  {
1038  *p_x1 = *p_x0;
1039  return;
1040  }
1041  }
1042 
1043  *p_x0 = x0;
1044  *p_x1 = x1;
1045  }
1046 
1047  // Slightly modified version to support RGBA buffers, copied from gnome-print
1048  static void art_rgba_rgba_affine(art_u8 *dst,
1049  int x0, int y0, int x1, int y1, int dst_rowstride,
1050  const art_u8 *src,
1051  int src_width, int src_height, int src_rowstride,
1052  const double affine[6])
1053  {
1054  int x, y;
1055  double inv[6];
1056  art_u8 *dst_p, *dst_linestart;
1057  const art_u8 *src_p;
1058  ArtPoint pt, src_pt;
1059  int src_x, src_y;
1060  int alpha;
1061  art_u8 bg_r, bg_g, bg_b, bg_a, cr, cg, cb;
1062  art_u8 fg_r, fg_g, fg_b;
1063  int tmp;
1064  int run_x0, run_x1;
1065 
1066  dst_linestart = dst;
1067  art_affine_invert (inv, affine);
1068  for (y = y0; y < y1; y++)
1069  {
1070  pt.y = y + 0.5;
1071  run_x0 = x0;
1072  run_x1 = x1;
1073  art_rgb_affine_run (&run_x0, &run_x1, y, src_width, src_height,
1074  inv);
1075  dst_p = dst_linestart + (run_x0 - x0) * 4;
1076  for (x = run_x0; x < run_x1; x++)
1077  {
1078  pt.x = x + 0.5;
1079  art_affine_point (&src_pt, &pt, inv);
1080  src_x = (int) floor (src_pt.x);
1081  src_y = (int) floor (src_pt.y);
1082  src_p = src + (src_y * src_rowstride) + src_x * 4;
1083  if (src_x >= 0 && src_x < src_width &&
1084  src_y >= 0 && src_y < src_height)
1085  {
1086 
1087  alpha = src_p[3];
1088  if (alpha)
1089  {
1090  if (alpha == 255)
1091  {
1092  dst_p[0] = src_p[0];
1093  dst_p[1] = src_p[1];
1094  dst_p[2] = src_p[2];
1095  dst_p[3] = 255;
1096  }
1097  else
1098  {
1099  bg_r = dst_p[0];
1100  bg_g = dst_p[1];
1101  bg_b = dst_p[2];
1102  bg_a = dst_p[3];
1103 
1104  cr = (bg_r * bg_a + 0x80) >> 8;
1105  cg = (bg_g * bg_g + 0x80) >> 8;
1106  cb = (bg_b * bg_b + 0x80) >> 8;
1107 
1108  tmp = (src_p[0] - bg_r) * alpha;
1109  fg_r = bg_r + ((tmp + (tmp >> 8) + 0x80) >> 8);
1110  tmp = (src_p[1] - bg_g) * alpha;
1111  fg_g = bg_g + ((tmp + (tmp >> 8) + 0x80) >> 8);
1112  tmp = (src_p[2] - bg_b) * alpha;
1113  fg_b = bg_b + ((tmp + (tmp >> 8) + 0x80) >> 8);
1114 
1115  dst_p[0] = fg_r;
1116  dst_p[1] = fg_g;
1117  dst_p[2] = fg_b;
1118  dst_p[3] = bg_a + (((255 - bg_a) * alpha + 0x80) >> 8);
1119  }
1120  }
1121  } else { dst_p[0] = 255; dst_p[1] = 0; dst_p[2] = 0; dst_p[3] = 255;}
1122  dst_p += 4;
1123  }
1124  dst_linestart += dst_rowstride;
1125  }
1126  }
1127 
1128 private:
1129  friend class KSVGIconPainter;
1130  ArtSVP *m_clipSVP;
1131 
1132  TQImage *m_image;
1133  TQWMatrix *m_worldMatrix;
1134 
1135  TQString m_fillRule;
1136  TQString m_joinStyle;
1137  TQString m_capStyle;
1138 
1139  int m_strokeMiterLimit;
1140 
1141  TQString m_dashes;
1142  unsigned short m_dashOffset;
1143 
1144  TQColor m_fillColor;
1145  TQColor m_strokeColor;
1146 
1147  art_u8 *m_buffer;
1148  art_u8 *m_tempBuffer;
1149 
1150  int m_width;
1151  int m_height;
1152 
1153  int m_rowstride;
1154 
1155  double m_opacity;
1156  double m_fillOpacity;
1157  double m_strokeOpacity;
1158 
1159  bool m_useFill;
1160  bool m_useStroke;
1161 
1162  bool m_useFillGradient;
1163  bool m_useStrokeGradient;
1164 
1165  TQString m_fillGradientReference;
1166  TQString m_strokeGradientReference;
1167 
1168  TQMap<TQString, ArtGradientLinear *> m_linearGradientMap;
1169  TQMap<ArtGradientLinear *, TQDomElement> m_linearGradientElementMap;
1170 
1171  TQMap<TQString, ArtGradientRadial *> m_radialGradientMap;
1172  TQMap<ArtGradientRadial *, TQDomElement> m_radialGradientElementMap;
1173 
1174  KSVGIconPainter *m_painter;
1175 
1176  double m_strokeWidth;
1177 };
1178 
1179 struct KSVGIconPainter::Private
1180 {
1181  KSVGIconPainterHelper *helper;
1182 
1183  int drawWidth;
1184  int drawHeight;
1185 };
1186 
1187 KSVGIconPainter::KSVGIconPainter(int width, int height) : d(new Private())
1188 {
1189  d->helper = new KSVGIconPainterHelper(width, height, this);
1190 
1191  d->drawWidth = width;
1192  d->drawHeight = height;
1193 }
1194 
1195 KSVGIconPainter::~KSVGIconPainter()
1196 {
1197  delete d->helper;
1198  delete d;
1199 }
1200 
1201 void KSVGIconPainter::setDrawWidth(int dwidth)
1202 {
1203  d->drawWidth = dwidth;
1204 }
1205 
1206 void KSVGIconPainter::setDrawHeight(int dheight)
1207 {
1208  d->drawHeight = dheight;
1209 }
1210 
1211 void KSVGIconPainter::finish()
1212 {
1213  d->helper->blit();
1214 }
1215 
1216 TQImage *KSVGIconPainter::image()
1217 {
1218  return new TQImage(*d->helper->m_image);
1219 }
1220 
1221 TQWMatrix *KSVGIconPainter::worldMatrix()
1222 {
1223  return d->helper->m_worldMatrix;
1224 }
1225 
1226 void KSVGIconPainter::setWorldMatrix(TQWMatrix *matrix)
1227 {
1228  if(d->helper->m_worldMatrix)
1229  delete d->helper->m_worldMatrix;
1230 
1231  d->helper->m_worldMatrix = matrix;
1232 }
1233 
1234 void KSVGIconPainter::setStrokeWidth(double width)
1235 {
1236  d->helper->m_strokeWidth = width;
1237 }
1238 
1239 void KSVGIconPainter::setStrokeMiterLimit(const TQString &miter)
1240 {
1241  d->helper->m_strokeMiterLimit = miter.toInt();
1242 }
1243 
1244 void KSVGIconPainter::setStrokeDashOffset(const TQString &dashOffset)
1245 {
1246  d->helper->m_dashOffset = dashOffset.toUInt();
1247 }
1248 
1249 void KSVGIconPainter::setStrokeDashArray(const TQString &dashes)
1250 {
1251  d->helper->m_dashes = dashes;
1252 }
1253 
1254 void KSVGIconPainter::setCapStyle(const TQString &cap)
1255 {
1256  d->helper->m_capStyle = cap;
1257 }
1258 
1259 void KSVGIconPainter::setJoinStyle(const TQString &join)
1260 {
1261  d->helper->m_joinStyle = join;
1262 }
1263 
1264 void KSVGIconPainter::setStrokeColor(const TQString &stroke)
1265 {
1266  if(stroke.startsWith("url"))
1267  {
1268  d->helper->m_useStroke = false;
1269  d->helper->m_useStrokeGradient = true;
1270 
1271  TQString url = stroke;
1272 
1273  unsigned int start = url.find("#") + 1;
1274  unsigned int end = url.findRev(")");
1275 
1276  d->helper->m_strokeGradientReference = url.mid(start, end - start);
1277  }
1278  else
1279  {
1280  d->helper->m_strokeColor = parseColor(stroke);
1281 
1282  d->helper->m_useStrokeGradient = false;
1283  d->helper->m_strokeGradientReference = TQString::null;
1284 
1285  if(stroke.stripWhiteSpace().lower() != "none")
1286  setUseStroke(true);
1287  else
1288  setUseStroke(false);
1289  }
1290 }
1291 
1292 void KSVGIconPainter::setFillColor(const TQString &fill)
1293 {
1294  if(fill.startsWith("url"))
1295  {
1296  d->helper->m_useFill = false;
1297  d->helper->m_useFillGradient = true;
1298 
1299  TQString url = fill;
1300 
1301  unsigned int start = url.find("#") + 1;
1302  unsigned int end = url.findRev(")");
1303 
1304  d->helper->m_fillGradientReference = url.mid(start, end - start);
1305  }
1306  else
1307  {
1308  d->helper->m_fillColor = parseColor(fill);
1309 
1310  d->helper->m_useFillGradient = false;
1311  d->helper->m_fillGradientReference = TQString::null;
1312 
1313  if(fill.stripWhiteSpace().lower() != "none")
1314  setUseFill(true);
1315  else
1316  setUseFill(false);
1317  }
1318 }
1319 
1320 void KSVGIconPainter::setFillRule(const TQString &fillRule)
1321 {
1322  d->helper->m_fillRule = fillRule;
1323 }
1324 
1325 TQ_UINT32 KSVGIconPainter::parseOpacity(const TQString &data)
1326 {
1327  int opacity = 255;
1328 
1329  if(!data.isEmpty())
1330  {
1331  double temp;
1332 
1333  if(data.contains("%"))
1334  {
1335  TQString tempString = data.left(data.length() - 1);
1336  temp = double(255 * tempString.toDouble()) / 100.0;
1337  }
1338  else
1339  temp = data.toDouble();
1340 
1341  opacity = (int) floor(temp * 255 + 0.5);
1342  }
1343 
1344  return opacity;
1345 }
1346 
1347 void KSVGIconPainter::setFillOpacity(const TQString &fillOpacity)
1348 {
1349  d->helper->m_fillOpacity = parseOpacity(fillOpacity);
1350 }
1351 
1352 void KSVGIconPainter::setStrokeOpacity(const TQString &strokeOpacity)
1353 {
1354  d->helper->m_strokeOpacity = parseOpacity(strokeOpacity);
1355 }
1356 
1357 void KSVGIconPainter::setOpacity(const TQString &opacity)
1358 {
1359  d->helper->m_opacity = parseOpacity(opacity);
1360 }
1361 
1362 void KSVGIconPainter::setUseFill(bool fill)
1363 {
1364  d->helper->m_useFill = fill;
1365 }
1366 
1367 void KSVGIconPainter::setUseStroke(bool stroke)
1368 {
1369  d->helper->m_useStroke = stroke;
1370 }
1371 
1372 void KSVGIconPainter::setClippingRect(int x, int y, int w, int h)
1373 {
1374  ArtVpath *vec = d->helper->allocVPath(6);
1375 
1376  vec[0].code = ART_MOVETO;
1377  vec[0].x = x;
1378  vec[0].y = y;
1379 
1380  vec[1].code = ART_LINETO;
1381  vec[1].x = x;
1382  vec[1].y = y + h;
1383 
1384  vec[2].code = ART_LINETO;
1385  vec[2].x = x + w;
1386  vec[2].y = y + h;
1387 
1388  vec[3].code = ART_LINETO;
1389  vec[3].x = x + w;
1390  vec[3].y = y;
1391 
1392  vec[4].code = ART_LINETO;
1393  vec[4].x = x;
1394  vec[4].y = y;
1395 
1396  vec[5].code = ART_END;
1397 
1398  if(d->helper->m_clipSVP)
1399  art_svp_free(d->helper->m_clipSVP);
1400 
1401  d->helper->m_clipSVP = art_svp_from_vpath(vec);
1402 
1403  art_free(vec);
1404 }
1405 
1406 void KSVGIconPainter::drawRectangle(double x, double y, double w, double h, double rx, double ry)
1407 {
1408  if((int) rx != 0 && (int) ry != 0)
1409  {
1410  ArtVpath *res;
1411  ArtBpath *vec = d->helper->allocBPath(10);
1412 
1413  int i = 0;
1414 
1415  if(rx > w / 2)
1416  rx = w / 2;
1417 
1418  if(ry > h / 2)
1419  ry = h / 2;
1420 
1421  vec[i].code = ART_MOVETO_OPEN;
1422  vec[i].x3 = x + rx;
1423  vec[i].y3 = y;
1424 
1425  i++;
1426 
1427  vec[i].code = ART_CURVETO;
1428  vec[i].x1 = x + rx * (1 - 0.552);
1429  vec[i].y1 = y;
1430  vec[i].x2 = x;
1431  vec[i].y2 = y + ry * (1 - 0.552);
1432  vec[i].x3 = x;
1433  vec[i].y3 = y + ry;
1434 
1435  i++;
1436 
1437  if(ry < h / 2)
1438  {
1439  vec[i].code = ART_LINETO;
1440  vec[i].x3 = x;
1441  vec[i].y3 = y + h - ry;
1442 
1443  i++;
1444  }
1445 
1446  vec[i].code = ART_CURVETO;
1447  vec[i].x1 = x;
1448  vec[i].y1 = y + h - ry * (1 - 0.552);
1449  vec[i].x2 = x + rx * (1 - 0.552);
1450  vec[i].y2 = y + h;
1451  vec[i].x3 = x + rx;
1452  vec[i].y3 = y + h;
1453 
1454  i++;
1455 
1456  if(rx < w / 2)
1457  {
1458  vec[i].code = ART_LINETO;
1459  vec[i].x3 = x + w - rx;
1460  vec[i].y3 = y + h;
1461 
1462  i++;
1463  }
1464 
1465  vec[i].code = ART_CURVETO;
1466  vec[i].x1 = x + w - rx * (1 - 0.552);
1467  vec[i].y1 = y + h;
1468  vec[i].x2 = x + w;
1469  vec[i].y2 = y + h - ry * (1 - 0.552);
1470  vec[i].x3 = x + w;
1471 
1472  vec[i].y3 = y + h - ry;
1473 
1474  i++;
1475 
1476  if(ry < h / 2)
1477  {
1478  vec[i].code = ART_LINETO;
1479  vec[i].x3 = x + w;
1480  vec[i].y3 = y + ry;
1481 
1482  i++;
1483  }
1484 
1485  vec[i].code = ART_CURVETO;
1486  vec[i].x1 = x + w;
1487  vec[i].y1 = y + ry * (1 - 0.552);
1488  vec[i].x2 = x + w - rx * (1 - 0.552);
1489  vec[i].y2 = y;
1490  vec[i].x3 = x + w - rx;
1491  vec[i].y3 = y;
1492 
1493  i++;
1494 
1495  if(rx < w / 2)
1496  {
1497  vec[i].code = ART_LINETO;
1498  vec[i].x3 = x + rx;
1499  vec[i].y3 = y;
1500 
1501  i++;
1502  }
1503 
1504  vec[i].code = ART_END;
1505 
1506  res = d->helper->art_bez_path_to_vec(vec, 0.25);
1507  art_free(vec);
1508  d->helper->drawVPath(res);
1509  }
1510  else
1511  {
1512  ArtVpath *vec = d->helper->allocVPath(6);
1513 
1514  vec[0].code = ART_MOVETO;
1515  vec[0].x = x;
1516  vec[0].y = y;
1517 
1518  vec[1].code = ART_LINETO;
1519  vec[1].x = x;
1520  vec[1].y = y + h;
1521 
1522  vec[2].code = ART_LINETO;
1523  vec[2].x = x + w;
1524  vec[2].y = y + h;
1525 
1526  vec[3].code = ART_LINETO;
1527  vec[3].x = x + w;
1528  vec[3].y = y;
1529 
1530  vec[4].code = ART_LINETO;
1531  vec[4].x = x;
1532  vec[4].y = y;
1533 
1534  vec[5].code = ART_END;
1535 
1536  d->helper->drawVPath(vec);
1537  }
1538 }
1539 
1540 void KSVGIconPainter::drawEllipse(double cx, double cy, double rx, double ry)
1541 {
1542  ArtBpath *temp;
1543 
1544  temp = d->helper->allocBPath(6);
1545 
1546  double x1, y1, x2, y2, x3, y3;
1547  double len = 0.55228474983079356;
1548  double cos4[] = {1.0, 0.0, -1.0, 0.0, 1.0};
1549  double sin4[] = {0.0, 1.0, 0.0, -1.0, 0.0};
1550  int i = 0;
1551 
1552  temp[i].code = ART_MOVETO;
1553  temp[i].x3 = cx + rx;
1554  temp[i].y3 = cy;
1555 
1556  i++;
1557 
1558  while(i < 5)
1559  {
1560  x1 = cos4[i-1] + len * cos4[i];
1561  y1 = sin4[i-1] + len * sin4[i];
1562  x2 = cos4[i] + len * cos4[i-1];
1563  y2 = sin4[i] + len * sin4[i-1];
1564  x3 = cos4[i];
1565  y3 = sin4[i];
1566 
1567  temp[i].code = ART_CURVETO;
1568  temp[i].x1 = cx + x1 * rx;
1569  temp[i].y1 = cy + y1 * ry;
1570  temp[i].x2 = cx + x2 * rx;
1571  temp[i].y2 = cy + y2 * ry;
1572  temp[i].x3 = cx + x3 * rx;
1573  temp[i].y3 = cy + y3 * ry;
1574 
1575  i++;
1576  }
1577 
1578  temp[i].code = ART_END;
1579 
1580  d->helper->drawBPath(temp);
1581 
1582  art_free(temp);
1583 }
1584 
1585 void KSVGIconPainter::drawLine(double x1, double y1, double x2, double y2)
1586 {
1587  ArtVpath *vec;
1588 
1589  vec = d->helper->allocVPath(3);
1590 
1591  vec[0].code = ART_MOVETO_OPEN;
1592  vec[0].x = x1;
1593  vec[0].y = y1;
1594 
1595  vec[1].code = ART_LINETO;
1596  vec[1].x = x2;
1597  vec[1].y = y2;
1598 
1599  vec[2].code = ART_END;
1600 
1601  d->helper->drawVPath(vec);
1602 }
1603 
1604 void KSVGIconPainter::drawPolyline(TQPointArray polyArray, int points)
1605 {
1606  if(polyArray.point(0).x() == -1 || polyArray.point(0).y() == -1)
1607  return;
1608 
1609  ArtVpath *polyline;
1610 
1611  if(points == -1)
1612  points = polyArray.count();
1613 
1614  polyline = d->helper->allocVPath(3 + points);
1615  polyline[0].code = ART_MOVETO;
1616  polyline[0].x = polyArray.point(0).x();
1617  polyline[0].y = polyArray.point(0).y();
1618 
1619  int index;
1620  for(index = 1; index < points; index++)
1621  {
1622  TQPoint point = polyArray.point(index);
1623  polyline[index].code = ART_LINETO;
1624  polyline[index].x = point.x();
1625  polyline[index].y = point.y();
1626  }
1627 
1628  if(d->helper->m_useFill) // if the polyline must be filled, inform libart that it should not be closed.
1629  {
1630  polyline[index].code = (ArtPathcode)ART_END2;
1631  polyline[index].x = polyArray.point(0).x();
1632  polyline[index++].y = polyArray.point(0).y();
1633  }
1634 
1635  polyline[index].code = ART_END;
1636 
1637  d->helper->drawVPath(polyline);
1638 }
1639 
1640 void KSVGIconPainter::drawPolygon(TQPointArray polyArray)
1641 {
1642  ArtVpath *polygon;
1643 
1644  polygon = d->helper->allocVPath(3 + polyArray.count());
1645  polygon[0].code = ART_MOVETO;
1646  polygon[0].x = polyArray.point(0).x();
1647  polygon[0].y = polyArray.point(0).y();
1648 
1649  unsigned int index;
1650  for(index = 1; index < polyArray.count(); index++)
1651  {
1652  TQPoint point = polyArray.point(index);
1653  polygon[index].code = ART_LINETO;
1654  polygon[index].x = point.x();
1655  polygon[index].y = point.y();
1656  }
1657 
1658  polygon[index].code = ART_LINETO;
1659  polygon[index].x = polyArray.point(0).x();
1660  polygon[index].y = polyArray.point(0).y();
1661 
1662  index++;
1663  polygon[index].code = ART_END;
1664 
1665  d->helper->drawVPath(polygon);
1666 }
1667 
1668 // Path parsing tool
1669 // parses the coord into number and forwards to the next token
1670 static const char *getCoord(const char *ptr, double &number)
1671 {
1672  int integer, exponent;
1673  double decimal, frac;
1674  int sign, expsign;
1675 
1676  exponent = 0;
1677  integer = 0;
1678  frac = 1.0;
1679  decimal = 0;
1680  sign = 1;
1681  expsign = 1;
1682 
1683  // read the sign
1684  if(*ptr == '+')
1685  ptr++;
1686  else if(*ptr == '-')
1687  {
1688  ptr++;
1689  sign = -1;
1690  }
1691  // read the integer part
1692  while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
1693  integer = (integer * 10) + *(ptr++) - '0';
1694 
1695  if(*ptr == '.') // read the decimals
1696  {
1697  ptr++;
1698  while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
1699  decimal += (*(ptr++) - '0') * (frac *= 0.1);
1700  }
1701 
1702  if(*ptr == 'e' || *ptr == 'E') // read the exponent part
1703  {
1704  ptr++;
1705 
1706  // read the sign of the exponent
1707  if(*ptr == '+')
1708  ptr++;
1709  else if(*ptr == '-')
1710  {
1711  ptr++;
1712  expsign = -1;
1713  }
1714 
1715  exponent = 0;
1716  while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
1717  {
1718  exponent *= 10;
1719  exponent += *ptr - '0';
1720  ptr++;
1721  }
1722  }
1723 
1724  number = integer + decimal;
1725  number *= sign * pow(10.0, expsign * exponent);
1726 
1727  // skip the following space
1728  if(*ptr == ' ')
1729  ptr++;
1730 
1731  return ptr;
1732 }
1733 
1734 void KSVGIconPainter::drawPath(const TQString &data, bool filled)
1735 {
1736  if (!data.isEmpty())
1737  {
1738  TQString value = data;
1739 
1740  TQMemArray<ArtBpath> vec;
1741  int index = -1;
1742 
1743  double curx = 0.0, cury = 0.0, contrlx = 0.0, contrly = 0.0, xc, yc;
1744  unsigned int lastCommand = 0;
1745 
1746  TQCString _d = value.replace(",", " ").simplifyWhiteSpace().latin1();
1747  const char *ptr = _d.data();
1748  const char *end = _d.data() + _d.length();
1749 
1750  double tox, toy, x1, y1, x2, y2, rx, ry, angle;
1751  bool largeArc, sweep;
1752  char command = *ptr;
1753 
1754  while(ptr < end)
1755  {
1756 
1757  if(*ptr == '+' || *ptr == '-' || *ptr == '.' || (*ptr >= '0' && *ptr <= '9'))
1758  {
1759  // there are still coords in this command
1760  if(command == 'M')
1761  {
1762  command = 'L';
1763  }
1764  else if(command == 'm')
1765  {
1766  command = 'l';
1767  }
1768  }
1769  else
1770  {
1771  command = *(ptr++);
1772  }
1773 
1774  if(*ptr == ' ')
1775  ptr++;
1776 
1777  switch(command)
1778  {
1779  case 'm':
1780  ptr = getCoord(ptr, tox);
1781  ptr = getCoord(ptr, toy);
1782 
1783  if(index != -1 && lastCommand != 'z')
1784  {
1785  // Find last subpath
1786  int find = -1;
1787  for(int i = index; i >= 0; i--)
1788  {
1789  if(vec[i].code == ART_MOVETO_OPEN || vec[i].code == ART_MOVETO)
1790  {
1791  find = i;
1792  break;
1793  }
1794  }
1795 
1796  index++;
1797 
1798  if(vec.size() == (unsigned int) index)
1799  vec.resize(index + 1);
1800 
1801  vec[index].code = (ArtPathcode)ART_END2;
1802  vec[index].x3 = vec[find].x3;
1803  vec[index].y3 = vec[find].y3;
1804  }
1805 
1806  curx += tox;
1807  cury += toy;
1808 
1809  index++;
1810 
1811  d->helper->ensureSpace(vec, index);
1812 
1813  vec[index].code = (index == 0) ? ART_MOVETO : ART_MOVETO_OPEN;
1814  vec[index].x3 = curx;
1815  vec[index].y3 = cury;
1816 
1817  lastCommand = 'm';
1818  break;
1819  case 'M':
1820  ptr = getCoord(ptr, tox);
1821  ptr = getCoord(ptr, toy);
1822  if(index != -1 && lastCommand != 'z')
1823  {
1824  // Find last subpath
1825  int find = -1;
1826  for(int i = index; i >= 0; i--)
1827  {
1828  if(vec[i].code == ART_MOVETO_OPEN || vec[i].code == ART_MOVETO)
1829  {
1830  find = i;
1831  break;
1832  }
1833  }
1834 
1835  index++;
1836 
1837  if(vec.size() == (unsigned int) index)
1838  vec.resize(index + 1);
1839 
1840  vec[index].code = (ArtPathcode)ART_END2;
1841  vec[index].x3 = vec[find].x3;
1842  vec[index].y3 = vec[find].y3;
1843  }
1844 
1845  curx = tox;
1846  cury = toy;
1847 
1848  index++;
1849 
1850  d->helper->ensureSpace(vec, index);
1851 
1852  vec[index].code = (index == 0) ? ART_MOVETO : ART_MOVETO_OPEN;
1853  vec[index].x3 = curx;
1854  vec[index].y3 = cury;
1855 
1856  lastCommand = 'M';
1857  break;
1858  case 'l':
1859  ptr = getCoord(ptr, tox);
1860  ptr = getCoord(ptr, toy);
1861 
1862  index++;
1863 
1864  d->helper->ensureSpace(vec, index);
1865 
1866  vec[index].code = ART_LINETO;
1867  vec[index].x3 = curx + tox;
1868  vec[index].y3 = cury + toy;
1869 
1870  curx += tox;
1871  cury += toy;
1872 
1873  lastCommand = 'l';
1874  break;
1875  case 'L':
1876  ptr = getCoord(ptr, tox);
1877  ptr = getCoord(ptr, toy);
1878 
1879  index++;
1880 
1881  d->helper->ensureSpace(vec, index);
1882 
1883  vec[index].code = ART_LINETO;
1884  vec[index].x3 = tox;
1885  vec[index].y3 = toy;
1886 
1887  curx = tox;
1888  cury = toy;
1889 
1890  lastCommand = 'L';
1891  break;
1892  case 'h':
1893  ptr = getCoord(ptr, tox);
1894 
1895  index++;
1896 
1897  curx += tox;
1898 
1899  d->helper->ensureSpace(vec, index);
1900 
1901  vec[index].code = ART_LINETO;
1902  vec[index].x3 = curx;
1903  vec[index].y3 = cury;
1904 
1905  lastCommand = 'h';
1906  break;
1907  case 'H':
1908  ptr = getCoord(ptr, tox);
1909 
1910  index++;
1911 
1912  curx = tox;
1913 
1914  d->helper->ensureSpace(vec, index);
1915 
1916  vec[index].code = ART_LINETO;
1917  vec[index].x3 = curx;
1918  vec[index].y3 = cury;
1919 
1920  lastCommand = 'H';
1921  break;
1922  case 'v':
1923  ptr = getCoord(ptr, toy);
1924 
1925  index++;
1926 
1927  cury += toy;
1928 
1929  d->helper->ensureSpace(vec, index);
1930 
1931  vec[index].code = ART_LINETO;
1932  vec[index].x3 = curx;
1933  vec[index].y3 = cury;
1934 
1935  lastCommand = 'v';
1936  break;
1937  case 'V':
1938  ptr = getCoord(ptr, toy);
1939 
1940  index++;
1941 
1942  cury = toy;
1943 
1944  d->helper->ensureSpace(vec, index);
1945 
1946  vec[index].code = ART_LINETO;
1947  vec[index].x3 = curx;
1948  vec[index].y3 = cury;
1949 
1950  lastCommand = 'V';
1951  break;
1952  case 'c':
1953  ptr = getCoord(ptr, x1);
1954  ptr = getCoord(ptr, y1);
1955  ptr = getCoord(ptr, x2);
1956  ptr = getCoord(ptr, y2);
1957  ptr = getCoord(ptr, tox);
1958  ptr = getCoord(ptr, toy);
1959 
1960  index++;
1961 
1962  d->helper->ensureSpace(vec, index);
1963 
1964  vec[index].code = ART_CURVETO;
1965  vec[index].x1 = curx + x1;
1966  vec[index].y1 = cury + y1;
1967  vec[index].x2 = curx + x2;
1968  vec[index].y2 = cury + y2;
1969  vec[index].x3 = curx + tox;
1970  vec[index].y3 = cury + toy;
1971 
1972  curx += tox;
1973  cury += toy;
1974 
1975  contrlx = vec[index].x2;
1976  contrly = vec[index].y2;
1977 
1978  lastCommand = 'c';
1979  break;
1980  case 'C':
1981  ptr = getCoord(ptr, x1);
1982  ptr = getCoord(ptr, y1);
1983  ptr = getCoord(ptr, x2);
1984  ptr = getCoord(ptr, y2);
1985  ptr = getCoord(ptr, tox);
1986  ptr = getCoord(ptr, toy);
1987 
1988  index++;
1989 
1990  d->helper->ensureSpace(vec, index);
1991 
1992  vec[index].code = ART_CURVETO;
1993  vec[index].x1 = x1;
1994  vec[index].y1 = y1;
1995  vec[index].x2 = x2;
1996  vec[index].y2 = y2;
1997  vec[index].x3 = tox;
1998  vec[index].y3 = toy;
1999 
2000  curx = vec[index].x3;
2001  cury = vec[index].y3;
2002  contrlx = vec[index].x2;
2003  contrly = vec[index].y2;
2004 
2005  lastCommand = 'C';
2006  break;
2007  case 's':
2008  ptr = getCoord(ptr, x2);
2009  ptr = getCoord(ptr, y2);
2010  ptr = getCoord(ptr, tox);
2011  ptr = getCoord(ptr, toy);
2012 
2013  index++;
2014 
2015  d->helper->ensureSpace(vec, index);
2016 
2017  vec[index].code = ART_CURVETO;
2018  vec[index].x1 = 2 * curx - contrlx;
2019  vec[index].y1 = 2 * cury - contrly;
2020  vec[index].x2 = curx + x2;
2021  vec[index].y2 = cury + y2;
2022  vec[index].x3 = curx + tox;
2023  vec[index].y3 = cury + toy;
2024 
2025  curx += tox;
2026  cury += toy;
2027 
2028  contrlx = vec[index].x2;
2029  contrly = vec[index].y2;
2030 
2031  lastCommand = 's';
2032  break;
2033  case 'S':
2034  ptr = getCoord(ptr, x2);
2035  ptr = getCoord(ptr, y2);
2036  ptr = getCoord(ptr, tox);
2037  ptr = getCoord(ptr, toy);
2038 
2039  index++;
2040 
2041  d->helper->ensureSpace(vec, index);
2042 
2043  vec[index].code = ART_CURVETO;
2044  vec[index].x1 = 2 * curx - contrlx;
2045  vec[index].y1 = 2 * cury - contrly;
2046  vec[index].x2 = x2;
2047  vec[index].y2 = y2;
2048  vec[index].x3 = tox;
2049  vec[index].y3 = toy;
2050 
2051  curx = vec[index].x3;
2052  cury = vec[index].y3;
2053  contrlx = vec[index].x2;
2054  contrly = vec[index].y2;
2055 
2056  lastCommand = 'S';
2057  break;
2058  case 'q':
2059  ptr = getCoord(ptr, x1);
2060  ptr = getCoord(ptr, y1);
2061  ptr = getCoord(ptr, tox);
2062  ptr = getCoord(ptr, toy);
2063 
2064  index++;
2065 
2066  d->helper->ensureSpace(vec, index);
2067 
2068  vec[index].code = ART_CURVETO;
2069  vec[index].x1 = (curx + 2 * (x1 + curx)) * (1.0 / 3.0);
2070  vec[index].y1 = (cury + 2 * (y1 + cury)) * (1.0 / 3.0);
2071  vec[index].x2 = ((curx + tox) + 2 * (x1 + curx)) * (1.0 / 3.0);
2072  vec[index].y2 = ((cury + toy) + 2 * (y1 + cury)) * (1.0 / 3.0);
2073  vec[index].x3 = curx + tox;
2074  vec[index].y3 = cury + toy;
2075 
2076  contrlx = curx + x1;
2077  contrly = cury + y1;
2078  curx += tox;
2079  cury += toy;
2080 
2081  lastCommand = 'q';
2082  break;
2083  case 'Q':
2084  ptr = getCoord(ptr, x1);
2085  ptr = getCoord(ptr, y1);
2086  ptr = getCoord(ptr, tox);
2087  ptr = getCoord(ptr, toy);
2088 
2089  index++;
2090 
2091  d->helper->ensureSpace(vec, index);
2092 
2093  // TODO : if this fails make it more like QuadraticRel
2094  vec[index].code = ART_CURVETO;
2095  vec[index].x1 = (curx + 2 * x1) * (1.0 / 3.0);
2096  vec[index].y1 = (cury + 2 * y1) * (1.0 / 3.0);
2097  vec[index].x2 = (tox + 2 * x1) * (1.0 / 3.0);
2098  vec[index].y2 = (toy + 2 * y1) * (1.0 / 3.0);
2099  vec[index].x3 = tox;
2100  vec[index].y3 = toy;
2101 
2102  curx = vec[index].x3;
2103  cury = vec[index].y3;
2104  contrlx = vec[index].x2;
2105  contrly = vec[index].y2;
2106 
2107  lastCommand = 'Q';
2108  break;
2109  case 't':
2110  ptr = getCoord(ptr, tox);
2111  ptr = getCoord(ptr, toy);
2112 
2113  xc = 2 * curx - contrlx;
2114  yc = 2 * cury - contrly;
2115 
2116  index++;
2117 
2118  d->helper->ensureSpace(vec, index);
2119 
2120  vec[index].code = ART_CURVETO;
2121  vec[index].x1 = (curx + 2 * xc) * (1.0 / 3.0);
2122  vec[index].y1 = (cury + 2 * yc) * (1.0 / 3.0);
2123  vec[index].x2 = ((curx + tox) + 2 * xc) * (1.0 / 3.0);
2124  vec[index].y2 = ((cury + toy) + 2 * yc) * (1.0 / 3.0);
2125 
2126  vec[index].x3 = curx + tox;
2127  vec[index].y3 = cury + toy;
2128 
2129  curx += tox;
2130  cury += toy;
2131  contrlx = xc;
2132  contrly = yc;
2133 
2134  lastCommand = 't';
2135  break;
2136  case 'T':
2137  ptr = getCoord(ptr, tox);
2138  ptr = getCoord(ptr, toy);
2139 
2140  xc = 2 * curx - contrlx;
2141  yc = 2 * cury - contrly;
2142 
2143  index++;
2144 
2145  d->helper->ensureSpace(vec, index);
2146 
2147  vec[index].code = ART_CURVETO;
2148  vec[index].x1 = (curx + 2 * xc) * (1.0 / 3.0);
2149  vec[index].y1 = (cury + 2 * yc) * (1.0 / 3.0);
2150  vec[index].x2 = (tox + 2 * xc) * (1.0 / 3.0);
2151  vec[index].y2 = (toy + 2 * yc) * (1.0 / 3.0);
2152  vec[index].x3 = tox;
2153  vec[index].y3 = toy;
2154 
2155  curx = tox;
2156  cury = toy;
2157  contrlx = xc;
2158  contrly = yc;
2159 
2160  lastCommand = 'T';
2161  break;
2162  case 'z':
2163  case 'Z':
2164  int find;
2165  find = -1;
2166  for(int i = index; i >= 0; i--)
2167  {
2168  if(vec[i].code == ART_MOVETO_OPEN || vec[i].code == ART_MOVETO)
2169  {
2170  find = i;
2171  break;
2172  }
2173  }
2174 
2175  if(find != -1)
2176  {
2177  if(vec[find].x3 != curx || vec[find].y3 != cury)
2178  {
2179  index++;
2180 
2181  d->helper->ensureSpace(vec, index);
2182 
2183  vec[index].code = ART_LINETO;
2184  vec[index].x3 = vec[find].x3;
2185  vec[index].y3 = vec[find].y3;
2186  }
2187  }
2188 
2189  // reset for next (sub)path
2190  curx = vec[find].x3;
2191  cury = vec[find].y3;
2192 
2193  lastCommand = 'z';
2194  break;
2195  case 'a':
2196  ptr = getCoord(ptr, rx);
2197  ptr = getCoord(ptr, ry);
2198  ptr = getCoord(ptr, angle);
2199  // 'largeArc' and 'sweep' are single digit flags. Some non conforming svg files do not
2200  // separate those fields with separators, so we can't use getCoord() here.
2201  // See TDE/tde issue #46 on TGW
2202  largeArc = ((*ptr++) != '0');
2203  while (*ptr == ' ')
2204  {
2205  ptr++;
2206  }
2207  sweep = ((*ptr++) != '0');
2208  while (*ptr == ' ')
2209  {
2210  ptr++;
2211  }
2212  ptr = getCoord(ptr, tox);
2213  ptr = getCoord(ptr, toy);
2214 
2215  // Spec: radii are nonnegative numbers
2216  rx = fabs(rx);
2217  ry = fabs(ry);
2218 
2219  d->helper->calculateArc(true, vec, index, curx, cury, angle, tox, toy, rx, ry, largeArc, sweep);
2220 
2221  lastCommand = 'a';
2222  break;
2223  case 'A':
2224  ptr = getCoord(ptr, rx);
2225  ptr = getCoord(ptr, ry);
2226  ptr = getCoord(ptr, angle);
2227  // 'largeArc' and 'sweep' are single digit flags. Some non conforming svg files do not
2228  // separate those fields with separators, so we can't use getCoord() here.
2229  // See TDE/tde issue #46 on TGW
2230  largeArc = ((*ptr++) != '0');
2231  while (*ptr == ' ')
2232  {
2233  ptr++;
2234  }
2235  sweep = ((*ptr++) != '0');
2236  while (*ptr == ' ')
2237  {
2238  ptr++;
2239  }
2240  ptr = getCoord(ptr, tox);
2241  ptr = getCoord(ptr, toy);
2242 
2243  // Spec: radii are nonnegative numbers
2244  rx = fabs(rx);
2245  ry = fabs(ry);
2246 
2247  d->helper->calculateArc(false, vec, index, curx, cury, angle, tox, toy, rx, ry, largeArc, sweep);
2248 
2249  lastCommand = 'A';
2250  break;
2251  }
2252 
2253  // Detect reflection points
2254  if(lastCommand != 'C' && lastCommand != 'c' &&
2255  lastCommand != 'S' && lastCommand != 's' &&
2256  lastCommand != 'Q' && lastCommand != 'q' &&
2257  lastCommand != 'T' && lastCommand != 't')
2258  {
2259  contrlx = curx;
2260  contrly = cury;
2261  }
2262  }
2263 
2264  // Find last subpath
2265  int find = -1;
2266  for(int i = index; i >= 0; i--)
2267  {
2268  if(vec[i].code == ART_MOVETO_OPEN || vec[i].code == ART_MOVETO)
2269  {
2270  find = i;
2271  break;
2272  }
2273  }
2274 
2275  // Fix a problem where the .svg file used doubles as values... (sofico.svg)
2276  if(curx != vec[find].x3 && cury != vec[find].y3)
2277  {
2278  if((int) curx == (int) vec[find].x3 && (int) cury == (int) vec[find].y3)
2279  {
2280  index++;
2281 
2282  if(vec.size() == (unsigned int) index)
2283  vec.resize(index + 1);
2284 
2285  vec[index].code = ART_LINETO;
2286  vec[index].x3 = vec[find].x3;
2287  vec[index].y3 = vec[find].y3;
2288 
2289  curx = vec[find].x3;
2290  cury = vec[find].y3;
2291  }
2292  }
2293 
2294  // Handle filled paths that are not closed explicitly
2295  if(filled)
2296  {
2297  if((int) curx != (int) vec[find].x3 || (int) cury != (int) vec[find].y3)
2298  {
2299  index++;
2300 
2301  if(vec.size() == (unsigned int) index)
2302  vec.resize(index + 1);
2303 
2304  vec[index].code = (ArtPathcode)ART_END2;
2305  vec[index].x3 = vec[find].x3;
2306  vec[index].y3 = vec[find].y3;
2307 
2308  curx = vec[find].x3;
2309  cury = vec[find].y3;
2310  }
2311  }
2312 
2313  // Close
2314  index++;
2315 
2316  if(vec.size() == (unsigned int) index)
2317  vec.resize(index + 1);
2318 
2319  vec[index].code = ART_END;
2320 
2321  // There are pure-moveto paths which reference paint servers *bah*
2322  // Do NOT render them
2323  bool render = false;
2324  for(int i = index; i >= 0; i--)
2325  {
2326  if(vec[i].code != ART_MOVETO_OPEN && vec[i].code != ART_MOVETO && !(vec[i].code >= ART_END))
2327  {
2328  render = true;
2329  break;
2330  }
2331  }
2332 
2333  if(render)
2334  d->helper->drawBPath(vec.data());
2335  }
2336 }
2337 
2338 void KSVGIconPainter::drawImage(double x, double y, TQImage &image)
2339 {
2340  if(image.depth() != 32)
2341  image = image.convertDepth(32);
2342 
2343  double affine[6];
2344  affine[0] = d->helper->m_worldMatrix->m11();
2345  affine[1] = d->helper->m_worldMatrix->m12();
2346  affine[2] = d->helper->m_worldMatrix->m21();
2347  affine[3] = d->helper->m_worldMatrix->m22();
2348  // use the world matrix to convert the coordinates
2349  d->helper->m_worldMatrix->map(x, y, &affine[4], &affine[5]);
2350 
2351  d->helper->art_rgba_rgba_affine(d->helper->m_buffer, 0, 0, d->helper->m_width, d->helper->m_height,
2352  d->helper->m_rowstride, image.bits(), image.width(), image.height(),
2353  image.width() * 4, affine);
2354 }
2355 
2356 TQColor KSVGIconPainter::parseColor(const TQString &param)
2357 {
2358  if(param.stripWhiteSpace().startsWith("#"))
2359  {
2360  TQColor color;
2361  color.setNamedColor(param.stripWhiteSpace());
2362  return color;
2363  }
2364  else if(param.stripWhiteSpace().startsWith("rgb("))
2365  {
2366  TQString parse = param.stripWhiteSpace();
2367  TQStringList colors = TQStringList::split(',', parse);
2368  TQString r = colors[0].right((colors[0].length() - 4));
2369  TQString g = colors[1];
2370  TQString b = colors[2].left((colors[2].length() - 1));
2371 
2372  if(r.contains("%"))
2373  {
2374  r = r.left(r.length() - 1);
2375  r = TQString::number(int((double(255 * r.toDouble()) / 100.0)));
2376  }
2377 
2378  if(g.contains("%"))
2379  {
2380  g = g.left(g.length() - 1);
2381  g = TQString::number(int((double(255 * g.toDouble()) / 100.0)));
2382  }
2383 
2384  if(b.contains("%"))
2385  {
2386  b = b.left(b.length() - 1);
2387  b = TQString::number(int((double(255 * b.toDouble()) / 100.0)));
2388  }
2389 
2390  return TQColor(r.toInt(), g.toInt(), b.toInt());
2391  }
2392  else
2393  {
2394  TQString rgbColor = param.stripWhiteSpace();
2395 
2396  if(rgbColor == "aliceblue")
2397  return TQColor(240, 248, 255);
2398  else if(rgbColor == "antiquewhite")
2399  return TQColor(250, 235, 215);
2400  else if(rgbColor == "aqua")
2401  return TQColor(0, 255, 255);
2402  else if(rgbColor == "aquamarine")
2403  return TQColor(127, 255, 212);
2404  else if(rgbColor == "azure")
2405  return TQColor(240, 255, 255);
2406  else if(rgbColor == "beige")
2407  return TQColor(245, 245, 220);
2408  else if(rgbColor == "bisque")
2409  return TQColor(255, 228, 196);
2410  else if(rgbColor == "black")
2411  return TQColor(0, 0, 0);
2412  else if(rgbColor == "blanchedalmond")
2413  return TQColor(255, 235, 205);
2414  else if(rgbColor == "blue")
2415  return TQColor(0, 0, 255);
2416  else if(rgbColor == "blueviolet")
2417  return TQColor(138, 43, 226);
2418  else if(rgbColor == "brown")
2419  return TQColor(165, 42, 42);
2420  else if(rgbColor == "burlywood")
2421  return TQColor(222, 184, 135);
2422  else if(rgbColor == "cadetblue")
2423  return TQColor(95, 158, 160);
2424  else if(rgbColor == "chartreuse")
2425  return TQColor(127, 255, 0);
2426  else if(rgbColor == "chocolate")
2427  return TQColor(210, 105, 30);
2428  else if(rgbColor == "coral")
2429  return TQColor(255, 127, 80);
2430  else if(rgbColor == "cornflowerblue")
2431  return TQColor(100, 149, 237);
2432  else if(rgbColor == "cornsilk")
2433  return TQColor(255, 248, 220);
2434  else if(rgbColor == "crimson")
2435  return TQColor(220, 20, 60);
2436  else if(rgbColor == "cyan")
2437  return TQColor(0, 255, 255);
2438  else if(rgbColor == "darkblue")
2439  return TQColor(0, 0, 139);
2440  else if(rgbColor == "darkcyan")
2441  return TQColor(0, 139, 139);
2442  else if(rgbColor == "darkgoldenrod")
2443  return TQColor(184, 134, 11);
2444  else if(rgbColor == "darkgray")
2445  return TQColor(169, 169, 169);
2446  else if(rgbColor == "darkgrey")
2447  return TQColor(169, 169, 169);
2448  else if(rgbColor == "darkgreen")
2449  return TQColor(0, 100, 0);
2450  else if(rgbColor == "darkkhaki")
2451  return TQColor(189, 183, 107);
2452  else if(rgbColor == "darkmagenta")
2453  return TQColor(139, 0, 139);
2454  else if(rgbColor == "darkolivegreen")
2455  return TQColor(85, 107, 47);
2456  else if(rgbColor == "darkorange")
2457  return TQColor(255, 140, 0);
2458  else if(rgbColor == "darkorchid")
2459  return TQColor(153, 50, 204);
2460  else if(rgbColor == "darkred")
2461  return TQColor(139, 0, 0);
2462  else if(rgbColor == "darksalmon")
2463  return TQColor(233, 150, 122);
2464  else if(rgbColor == "darkseagreen")
2465  return TQColor(143, 188, 143);
2466  else if(rgbColor == "darkslateblue")
2467  return TQColor(72, 61, 139);
2468  else if(rgbColor == "darkslategray")
2469  return TQColor(47, 79, 79);
2470  else if(rgbColor == "darkslategrey")
2471  return TQColor(47, 79, 79);
2472  else if(rgbColor == "darkturquoise")
2473  return TQColor(0, 206, 209);
2474  else if(rgbColor == "darkviolet")
2475  return TQColor(148, 0, 211);
2476  else if(rgbColor == "deeppink")
2477  return TQColor(255, 20, 147);
2478  else if(rgbColor == "deepskyblue")
2479  return TQColor(0, 191, 255);
2480  else if(rgbColor == "dimgray")
2481  return TQColor(105, 105, 105);
2482  else if(rgbColor == "dimgrey")
2483  return TQColor(105, 105, 105);
2484  else if(rgbColor == "dodgerblue")
2485  return TQColor(30, 144, 255);
2486  else if(rgbColor == "firebrick")
2487  return TQColor(178, 34, 34);
2488  else if(rgbColor == "floralwhite")
2489  return TQColor(255, 250, 240);
2490  else if(rgbColor == "forestgreen")
2491  return TQColor(34, 139, 34);
2492  else if(rgbColor == "fuchsia")
2493  return TQColor(255, 0, 255);
2494  else if(rgbColor == "gainsboro")
2495  return TQColor(220, 220, 220);
2496  else if(rgbColor == "ghostwhite")
2497  return TQColor(248, 248, 255);
2498  else if(rgbColor == "gold")
2499  return TQColor(255, 215, 0);
2500  else if(rgbColor == "goldenrod")
2501  return TQColor(218, 165, 32);
2502  else if(rgbColor == "gray")
2503  return TQColor(128, 128, 128);
2504  else if(rgbColor == "grey")
2505  return TQColor(128, 128, 128);
2506  else if(rgbColor == "green")
2507  return TQColor(0, 128, 0);
2508  else if(rgbColor == "greenyellow")
2509  return TQColor(173, 255, 47);
2510  else if(rgbColor == "honeydew")
2511  return TQColor(240, 255, 240);
2512  else if(rgbColor == "hotpink")
2513  return TQColor(255, 105, 180);
2514  else if(rgbColor == "indianred")
2515  return TQColor(205, 92, 92);
2516  else if(rgbColor == "indigo")
2517  return TQColor(75, 0, 130);
2518  else if(rgbColor == "ivory")
2519  return TQColor(255, 255, 240);
2520  else if(rgbColor == "khaki")
2521  return TQColor(240, 230, 140);
2522  else if(rgbColor == "lavender")
2523  return TQColor(230, 230, 250);
2524  else if(rgbColor == "lavenderblush")
2525  return TQColor(255, 240, 245);
2526  else if(rgbColor == "lawngreen")
2527  return TQColor(124, 252, 0);
2528  else if(rgbColor == "lemonchiffon")
2529  return TQColor(255, 250, 205);
2530  else if(rgbColor == "lightblue")
2531  return TQColor(173, 216, 230);
2532  else if(rgbColor == "lightcoral")
2533  return TQColor(240, 128, 128);
2534  else if(rgbColor == "lightcyan")
2535  return TQColor(224, 255, 255);
2536  else if(rgbColor == "lightgoldenrodyellow")
2537  return TQColor(250, 250, 210);
2538  else if(rgbColor == "lightgray")
2539  return TQColor(211, 211, 211);
2540  else if(rgbColor == "lightgrey")
2541  return TQColor(211, 211, 211);
2542  else if(rgbColor == "lightgreen")
2543  return TQColor(144, 238, 144);
2544  else if(rgbColor == "lightpink")
2545  return TQColor(255, 182, 193);
2546  else if(rgbColor == "lightsalmon")
2547  return TQColor(255, 160, 122);
2548  else if(rgbColor == "lightseagreen")
2549  return TQColor(32, 178, 170);
2550  else if(rgbColor == "lightskyblue")
2551  return TQColor(135, 206, 250);
2552  else if(rgbColor == "lightslategray")
2553  return TQColor(119, 136, 153);
2554  else if(rgbColor == "lightslategrey")
2555  return TQColor(119, 136, 153);
2556  else if(rgbColor == "lightsteelblue")
2557  return TQColor(176, 196, 222);
2558  else if(rgbColor == "lightyellow")
2559  return TQColor(255, 255, 224);
2560  else if(rgbColor == "lime")
2561  return TQColor(0, 255, 0);
2562  else if(rgbColor == "limegreen")
2563  return TQColor(50, 205, 50);
2564  else if(rgbColor == "linen")
2565  return TQColor(250, 240, 230);
2566  else if(rgbColor == "magenta")
2567  return TQColor(255, 0, 255);
2568  else if(rgbColor == "maroon")
2569  return TQColor(128, 0, 0);
2570  else if(rgbColor == "mediumaquamarine")
2571  return TQColor(102, 205, 170);
2572  else if(rgbColor == "mediumblue")
2573  return TQColor(0, 0, 205);
2574  else if(rgbColor == "mediumorchid")
2575  return TQColor(186, 85, 211);
2576  else if(rgbColor == "mediumpurple")
2577  return TQColor(147, 112, 219);
2578  else if(rgbColor == "mediumseagreen")
2579  return TQColor(60, 179, 113);
2580  else if(rgbColor == "mediumslateblue")
2581  return TQColor(123, 104, 238);
2582  else if(rgbColor == "mediumspringgreen")
2583  return TQColor(0, 250, 154);
2584  else if(rgbColor == "mediumturquoise")
2585  return TQColor(72, 209, 204);
2586  else if(rgbColor == "mediumvioletred")
2587  return TQColor(199, 21, 133);
2588  else if(rgbColor == "midnightblue")
2589  return TQColor(25, 25, 112);
2590  else if(rgbColor == "mintcream")
2591  return TQColor(245, 255, 250);
2592  else if(rgbColor == "mistyrose")
2593  return TQColor(255, 228, 225);
2594  else if(rgbColor == "moccasin")
2595  return TQColor(255, 228, 181);
2596  else if(rgbColor == "navajowhite")
2597  return TQColor(255, 222, 173);
2598  else if(rgbColor == "navy")
2599  return TQColor(0, 0, 128);
2600  else if(rgbColor == "oldlace")
2601  return TQColor(253, 245, 230);
2602  else if(rgbColor == "olive")
2603  return TQColor(128, 128, 0);
2604  else if(rgbColor == "olivedrab")
2605  return TQColor(107, 142, 35);
2606  else if(rgbColor == "orange")
2607  return TQColor(255, 165, 0);
2608  else if(rgbColor == "orangered")
2609  return TQColor(255, 69, 0);
2610  else if(rgbColor == "orchid")
2611  return TQColor(218, 112, 214);
2612  else if(rgbColor == "palegoldenrod")
2613  return TQColor(238, 232, 170);
2614  else if(rgbColor == "palegreen")
2615  return TQColor(152, 251, 152);
2616  else if(rgbColor == "paleturquoise")
2617  return TQColor(175, 238, 238);
2618  else if(rgbColor == "palevioletred")
2619  return TQColor(219, 112, 147);
2620  else if(rgbColor == "papayawhip")
2621  return TQColor(255, 239, 213);
2622  else if(rgbColor == "peachpuff")
2623  return TQColor(255, 218, 185);
2624  else if(rgbColor == "peru")
2625  return TQColor(205, 133, 63);
2626  else if(rgbColor == "pink")
2627  return TQColor(255, 192, 203);
2628  else if(rgbColor == "plum")
2629  return TQColor(221, 160, 221);
2630  else if(rgbColor == "powderblue")
2631  return TQColor(176, 224, 230);
2632  else if(rgbColor == "purple")
2633  return TQColor(128, 0, 128);
2634  else if(rgbColor == "red")
2635  return TQColor(255, 0, 0);
2636  else if(rgbColor == "rosybrown")
2637  return TQColor(188, 143, 143);
2638  else if(rgbColor == "royalblue")
2639  return TQColor(65, 105, 225);
2640  else if(rgbColor == "saddlebrown")
2641  return TQColor(139, 69, 19);
2642  else if(rgbColor == "salmon")
2643  return TQColor(250, 128, 114);
2644  else if(rgbColor == "sandybrown")
2645  return TQColor(244, 164, 96);
2646  else if(rgbColor == "seagreen")
2647  return TQColor(46, 139, 87);
2648  else if(rgbColor == "seashell")
2649  return TQColor(255, 245, 238);
2650  else if(rgbColor == "sienna")
2651  return TQColor(160, 82, 45);
2652  else if(rgbColor == "silver")
2653  return TQColor(192, 192, 192);
2654  else if(rgbColor == "skyblue")
2655  return TQColor(135, 206, 235);
2656  else if(rgbColor == "slateblue")
2657  return TQColor(106, 90, 205);
2658  else if(rgbColor == "slategray")
2659  return TQColor(112, 128, 144);
2660  else if(rgbColor == "slategrey")
2661  return TQColor(112, 128, 144);
2662  else if(rgbColor == "snow")
2663  return TQColor(255, 250, 250);
2664  else if(rgbColor == "springgreen")
2665  return TQColor(0, 255, 127);
2666  else if(rgbColor == "steelblue")
2667  return TQColor(70, 130, 180);
2668  else if(rgbColor == "tan")
2669  return TQColor(210, 180, 140);
2670  else if(rgbColor == "teal")
2671  return TQColor(0, 128, 128);
2672  else if(rgbColor == "thistle")
2673  return TQColor(216, 191, 216);
2674  else if(rgbColor == "tomato")
2675  return TQColor(255, 99, 71);
2676  else if(rgbColor == "turquoise")
2677  return TQColor(64, 224, 208);
2678  else if(rgbColor == "violet")
2679  return TQColor(238, 130, 238);
2680  else if(rgbColor == "wheat")
2681  return TQColor(245, 222, 179);
2682  else if(rgbColor == "white")
2683  return TQColor(255, 255, 255);
2684  else if(rgbColor == "whitesmoke")
2685  return TQColor(245, 245, 245);
2686  else if(rgbColor == "yellow")
2687  return TQColor(255, 255, 0);
2688  else if(rgbColor == "yellowgreen")
2689  return TQColor(154, 205, 50);
2690  }
2691 
2692  return TQColor();
2693 }
2694 
2695 double KSVGIconPainter::dpi()
2696 {
2697  return 90.0; // TODO: make modal?
2698 }
2699 
2700 double KSVGIconPainter::toPixel(const TQString &s, bool hmode)
2701 {
2702  if(s.isEmpty())
2703  return 0.0;
2704 
2705  TQString check = s;
2706 
2707  double ret = 0.0;
2708 
2709  double value = 0;
2710  const char *start = check.latin1();
2711  const char *end = getCoord(start, value);
2712 
2713  if(uint(end - start) < check.length())
2714  {
2715  if(check.endsWith("px"))
2716  ret = value;
2717  else if(check.endsWith("cm"))
2718  ret = (value / 2.54) * dpi();
2719  else if(check.endsWith("pc"))
2720  ret = (value / 6.0) * dpi();
2721  else if(check.endsWith("mm"))
2722  ret = (value / 25.4) * dpi();
2723  else if(check.endsWith("in"))
2724  ret = value * dpi();
2725  else if(check.endsWith("pt"))
2726  ret = (value / 72.0) * dpi();
2727  else if(check.endsWith("%"))
2728  {
2729  ret = value / 100.0;
2730 
2731  if(hmode)
2732  ret *= d->drawWidth;
2733  else
2734  ret *= d->drawHeight;
2735  }
2736  else if(check.endsWith("em"))
2737  {
2738  ret = value * 10.0; // TODO make this depend on actual font size
2739  }
2740  }
2741  else
2742  ret = value;
2743 
2744  return ret;
2745 }
2746 
2747 ArtGradientLinear *KSVGIconPainter::linearGradient(const TQString &id)
2748 {
2749  return d->helper->m_linearGradientMap[id];
2750 }
2751 
2752 void KSVGIconPainter::addLinearGradient(const TQString &id, ArtGradientLinear *gradient)
2753 {
2754  d->helper->m_linearGradientMap.insert(id, gradient);
2755 }
2756 
2757 TQDomElement KSVGIconPainter::linearGradientElement(ArtGradientLinear *linear)
2758 {
2759  return d->helper->m_linearGradientElementMap[linear];
2760 }
2761 
2762 void KSVGIconPainter::addLinearGradientElement(ArtGradientLinear *gradient, TQDomElement element)
2763 {
2764  d->helper->m_linearGradientElementMap.insert(gradient, element);
2765 }
2766 
2767 ArtGradientRadial *KSVGIconPainter::radialGradient(const TQString &id)
2768 {
2769  return d->helper->m_radialGradientMap[id];
2770 }
2771 
2772 void KSVGIconPainter::addRadialGradient(const TQString &id, ArtGradientRadial *gradient)
2773 {
2774  d->helper->m_radialGradientMap.insert(id, gradient);
2775 }
2776 
2777 TQDomElement KSVGIconPainter::radialGradientElement(ArtGradientRadial *radial)
2778 {
2779  return d->helper->m_radialGradientElementMap[radial];
2780 }
2781 
2782 void KSVGIconPainter::addRadialGradientElement(ArtGradientRadial *gradient, TQDomElement element)
2783 {
2784  d->helper->m_radialGradientElementMap.insert(gradient, element);
2785 }
2786 
2787 TQ_UINT32 KSVGIconPainter::toArtColor(const TQColor &color)
2788 {
2789  return d->helper->toArtColor(color);
2790 }
2791 
2792 TQWMatrix KSVGIconPainter::parseTransform(const TQString &transform)
2793 {
2794  TQWMatrix result;
2795 
2796  // Split string for handling 1 transform statement at a time
2797  TQStringList subtransforms = TQStringList::split(')', transform);
2798  TQStringList::ConstIterator it = subtransforms.begin();
2799  TQStringList::ConstIterator end = subtransforms.end();
2800  for(; it != end; ++it)
2801  {
2802  TQStringList subtransform = TQStringList::split('(', (*it));
2803 
2804  subtransform[0] = subtransform[0].stripWhiteSpace().lower();
2805  subtransform[1] = subtransform[1].simplifyWhiteSpace();
2806  TQRegExp reg("([-]?\\d*\\.?\\d+(?:e[-]?\\d+)?)");
2807 
2808  int pos = 0;
2809  TQStringList params;
2810 
2811  while(pos >= 0)
2812  {
2813  pos = reg.search(subtransform[1], pos);
2814  if(pos != -1)
2815  {
2816  params += reg.cap(1);
2817  pos += reg.matchedLength();
2818  }
2819  }
2820 
2821  if(subtransform[0].startsWith(";") || subtransform[0].startsWith(","))
2822  subtransform[0] = subtransform[0].right(subtransform[0].length() - 1);
2823 
2824  if(subtransform[0] == "rotate")
2825  {
2826  if(params.count() == 3)
2827  {
2828  double x = params[1].toDouble();
2829  double y = params[2].toDouble();
2830 
2831  result.translate(x, y);
2832  result.rotate(params[0].toDouble());
2833  result.translate(-x, -y);
2834  }
2835  else
2836  result.rotate(params[0].toDouble());
2837  }
2838  else if(subtransform[0] == "translate")
2839  {
2840  if(params.count() == 2)
2841  result.translate(params[0].toDouble(), params[1].toDouble());
2842  else // Spec : if only one param given, assume 2nd param to be 0
2843  result.translate(params[0].toDouble() , 0);
2844  }
2845  else if(subtransform[0] == "scale")
2846  {
2847  if(params.count() == 2)
2848  result.scale(params[0].toDouble(), params[1].toDouble());
2849  else // Spec : if only one param given, assume uniform scaling
2850  result.scale(params[0].toDouble(), params[0].toDouble());
2851  }
2852  else if(subtransform[0] == "skewx")
2853  result.shear(tan(params[0].toDouble() * deg2rad), 0.0F);
2854  else if(subtransform[0] == "skewy")
2855  result.shear(tan(params[0].toDouble() * deg2rad), 0.0F);
2856  else if(subtransform[0] == "skewy")
2857  result.shear(0.0F, tan(params[0].toDouble() * deg2rad));
2858  else if(subtransform[0] == "matrix")
2859  {
2860  if(params.count() >= 6)
2861  {
2862  result.setMatrix(params[0].toDouble(), params[1].toDouble(), params[2].toDouble(), params[3].toDouble(), params[4].toDouble(), params[5].toDouble());
2863  }
2864  }
2865  }
2866 
2867  return result;
2868 }
TDEStdAccel::end
const TDEShortcut & end()
Goto end of the document.
Definition: tdestdaccel.cpp:289
KStdAction::name
const char * name(StdAction id)
KStdAction::find
TDEAction * find(const TQObject *recvr, const char *slot, TDEActionCollection *parent, const char *name=0)

tdecore

Skip menu "tdecore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

tdecore

Skip menu "tdecore"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  •     tdecore
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  • tdeioslave
  •   http
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdecore by doxygen 1.8.8
This website is maintained by Timothy Pearson.