Qt 4.8
qsvghandler.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtSvg module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qplatformdefs.h"
43 
44 #include "qsvghandler_p.h"
45 
46 #ifndef QT_NO_SVG
47 
48 #include "qsvgtinydocument_p.h"
49 #include "qsvgstructure_p.h"
50 #include "qsvggraphics_p.h"
51 #include "qsvgnode_p.h"
52 #include "qsvgfont_p.h"
53 
54 #include "qapplication.h"
55 #include "qwidget.h"
56 #include "qpen.h"
57 #include "qpainterpath.h"
58 #include "qbrush.h"
59 #include "qcolor.h"
60 #include "qtextformat.h"
61 #include "qvector.h"
62 #include "qfileinfo.h"
63 #include "qfile.h"
64 #include "qdebug.h"
65 #include "qmath.h"
66 #include "qnumeric.h"
67 #include "qvarlengtharray.h"
68 #include "private/qmath_p.h"
69 
70 #include "float.h"
71 
73 
74 static const char *qt_inherit_text = "inherit";
75 #define QT_INHERIT QLatin1String(qt_inherit_text)
76 
77 Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok);
78 
79 // ======== duplicated from qcolor_p
80 
81 static inline int qsvg_h2i(char hex)
82 {
83  if (hex >= '0' && hex <= '9')
84  return hex - '0';
85  if (hex >= 'a' && hex <= 'f')
86  return hex - 'a' + 10;
87  if (hex >= 'A' && hex <= 'F')
88  return hex - 'A' + 10;
89  return -1;
90 }
91 
92 static inline int qsvg_hex2int(const char *s)
93 {
94  return (qsvg_h2i(s[0]) << 4) | qsvg_h2i(s[1]);
95 }
96 
97 static inline int qsvg_hex2int(char s)
98 {
99  int h = qsvg_h2i(s);
100  return (h << 4) | h;
101 }
102 
103 bool qsvg_get_hex_rgb(const char *name, QRgb *rgb)
104 {
105  if(name[0] != '#')
106  return false;
107  name++;
108  int len = qstrlen(name);
109  int r, g, b;
110  if (len == 12) {
111  r = qsvg_hex2int(name);
112  g = qsvg_hex2int(name + 4);
113  b = qsvg_hex2int(name + 8);
114  } else if (len == 9) {
115  r = qsvg_hex2int(name);
116  g = qsvg_hex2int(name + 3);
117  b = qsvg_hex2int(name + 6);
118  } else if (len == 6) {
119  r = qsvg_hex2int(name);
120  g = qsvg_hex2int(name + 2);
121  b = qsvg_hex2int(name + 4);
122  } else if (len == 3) {
123  r = qsvg_hex2int(name[0]);
124  g = qsvg_hex2int(name[1]);
125  b = qsvg_hex2int(name[2]);
126  } else {
127  r = g = b = -1;
128  }
129  if ((uint)r > 255 || (uint)g > 255 || (uint)b > 255) {
130  *rgb = 0;
131  return false;
132  }
133  *rgb = qRgb(r, g ,b);
134  return true;
135 }
136 
137 bool qsvg_get_hex_rgb(const QChar *str, int len, QRgb *rgb)
138 {
139  if (len > 13)
140  return false;
141  char tmp[16];
142  for(int i = 0; i < len; ++i)
143  tmp[i] = str[i].toLatin1();
144  tmp[len] = 0;
145  return qsvg_get_hex_rgb(tmp, rgb);
146 }
147 
148 // ======== end of qcolor_p duplicate
149 
150 static bool parsePathDataFast(const QStringRef &data, QPainterPath &path);
151 
152 static inline QString someId(const QXmlStreamAttributes &attributes)
153 {
154  QString id = attributes.value(QLatin1String("id")).toString();
155  if (id.isEmpty())
156  id = attributes.value(QLatin1String("xml:id")).toString();
157  return id;
158 }
159 
161 {
162  QSvgAttributes(const QXmlStreamAttributes &xmlAttributes, QSvgHandler *handler);
163 
165 
194 
196 };
197 
199 {
200  QStringRef style = xmlAttributes.value(QLatin1String("style"));
201  if (!style.isEmpty()) {
202  handler->parseCSStoXMLAttrs(style.toString(), &m_cssAttributes);
203  for (int j = 0; j < m_cssAttributes.count(); ++j) {
204  const QSvgCssAttribute &attribute = m_cssAttributes.at(j);
205  QStringRef name = attribute.name;
206  QStringRef value = attribute.value;
207  if (name.isEmpty())
208  continue;
209 
210  switch (name.at(0).unicode()) {
211 
212  case 'c':
213  if (name == QLatin1String("color"))
214  color = value;
215  else if (name == QLatin1String("color-opacity"))
216  colorOpacity = value;
217  else if (name == QLatin1String("comp-op"))
218  compOp = value;
219  break;
220 
221  case 'd':
222  if (name == QLatin1String("display"))
223  display = value;
224  break;
225 
226  case 'f':
227  if (name == QLatin1String("fill"))
228  fill = value;
229  else if (name == QLatin1String("fill-rule"))
230  fillRule = value;
231  else if (name == QLatin1String("fill-opacity"))
232  fillOpacity = value;
233  else if (name == QLatin1String("font-family"))
234  fontFamily = value;
235  else if (name == QLatin1String("font-size"))
236  fontSize = value;
237  else if (name == QLatin1String("font-style"))
238  fontStyle = value;
239  else if (name == QLatin1String("font-weight"))
240  fontWeight = value;
241  else if (name == QLatin1String("font-variant"))
242  fontVariant = value;
243  break;
244 
245  case 'o':
246  if (name == QLatin1String("opacity"))
247  opacity = value;
248  else if (name == QLatin1String("offset"))
249  offset = value;
250  break;
251 
252  case 's':
253  if (name.length() > 5 && QStringRef(name.string(), name.position() + 1, 5) == QLatin1String("troke")) {
254  QStringRef strokeRef(name.string(), name.position() + 6, name.length() - 6);
255  if (strokeRef.isEmpty())
256  stroke = value;
257  else if (strokeRef == QLatin1String("-dasharray"))
258  strokeDashArray = value;
259  else if (strokeRef == QLatin1String("-dashoffset"))
260  strokeDashOffset = value;
261  else if (strokeRef == QLatin1String("-linecap"))
262  strokeLineCap = value;
263  else if (strokeRef == QLatin1String("-linejoin"))
264  strokeLineJoin = value;
265  else if (strokeRef == QLatin1String("-miterlimit"))
266  strokeMiterLimit = value;
267  else if (strokeRef == QLatin1String("-opacity"))
268  strokeOpacity = value;
269  else if (strokeRef == QLatin1String("-width"))
270  strokeWidth = value;
271  }
272  else if (name == QLatin1String("stop-color"))
273  stopColor = value;
274  else if (name == QLatin1String("stop-opacity"))
275  stopOpacity = value;
276  break;
277 
278  case 't':
279  if (name == QLatin1String("text-anchor"))
280  textAnchor = value;
281  else if (name == QLatin1String("transform"))
282  transform = value;
283  break;
284 
285  case 'v':
286  if (name == QLatin1String("vector-effect"))
287  vectorEffect = value;
288  else if (name == QLatin1String("visibility"))
289  visibility = value;
290  break;
291 
292  default:
293  break;
294  }
295  }
296  }
297 
298  for (int i = 0; i < xmlAttributes.count(); ++i) {
299  const QXmlStreamAttribute &attribute = xmlAttributes.at(i);
300  QStringRef name = attribute.qualifiedName();
301  if (name.isEmpty())
302  continue;
303  QStringRef value = attribute.value();
304 
305  switch (name.at(0).unicode()) {
306 
307  case 'c':
308  if (name == QLatin1String("color"))
309  color = value;
310  else if (name == QLatin1String("color-opacity"))
311  colorOpacity = value;
312  else if (name == QLatin1String("comp-op"))
313  compOp = value;
314  break;
315 
316  case 'd':
317  if (name == QLatin1String("display"))
318  display = value;
319  break;
320 
321  case 'f':
322  if (name == QLatin1String("fill"))
323  fill = value;
324  else if (name == QLatin1String("fill-rule"))
325  fillRule = value;
326  else if (name == QLatin1String("fill-opacity"))
327  fillOpacity = value;
328  else if (name == QLatin1String("font-family"))
329  fontFamily = value;
330  else if (name == QLatin1String("font-size"))
331  fontSize = value;
332  else if (name == QLatin1String("font-style"))
333  fontStyle = value;
334  else if (name == QLatin1String("font-weight"))
335  fontWeight = value;
336  else if (name == QLatin1String("font-variant"))
337  fontVariant = value;
338  break;
339 
340  case 'i':
341  if (name == QLatin1String("id"))
342  id = value.toString();
343  break;
344 
345  case 'o':
346  if (name == QLatin1String("opacity"))
347  opacity = value;
348  if (name == QLatin1String("offset"))
349  offset = value;
350  break;
351 
352  case 's':
353  if (name.length() > 5 && QStringRef(name.string(), name.position() + 1, 5) == QLatin1String("troke")) {
354  QStringRef strokeRef(name.string(), name.position() + 6, name.length() - 6);
355  if (strokeRef.isEmpty())
356  stroke = value;
357  else if (strokeRef == QLatin1String("-dasharray"))
358  strokeDashArray = value;
359  else if (strokeRef == QLatin1String("-dashoffset"))
360  strokeDashOffset = value;
361  else if (strokeRef == QLatin1String("-linecap"))
362  strokeLineCap = value;
363  else if (strokeRef == QLatin1String("-linejoin"))
364  strokeLineJoin = value;
365  else if (strokeRef == QLatin1String("-miterlimit"))
366  strokeMiterLimit = value;
367  else if (strokeRef == QLatin1String("-opacity"))
368  strokeOpacity = value;
369  else if (strokeRef == QLatin1String("-width"))
370  strokeWidth = value;
371  }
372  else if (name == QLatin1String("stop-color"))
373  stopColor = value;
374  else if (name == QLatin1String("stop-opacity"))
375  stopOpacity = value;
376  break;
377 
378  case 't':
379  if (name == QLatin1String("text-anchor"))
380  textAnchor = value;
381  else if (name == QLatin1String("transform"))
382  transform = value;
383  break;
384 
385  case 'v':
386  if (name == QLatin1String("vector-effect"))
387  vectorEffect = value;
388  else if (name == QLatin1String("visibility"))
389  visibility = value;
390  break;
391 
392  case 'x':
393  if (name == QLatin1String("xml:id") && id.isEmpty())
394  id = value.toString();
395  break;
396 
397  default:
398  break;
399  }
400  }
401 
402 }
403 
404 static const char * QSvgStyleSelector_nodeString[] = {
405  "svg",
406  "g",
407  "defs",
408  "switch",
409  "animation",
410  "arc",
411  "circle",
412  "ellipse",
413  "image",
414  "line",
415  "path",
416  "polygon",
417  "polyline",
418  "rect",
419  "text",
420  "textarea",
421  "use",
422  "video"
423 };
424 
426 {
427 public:
429  {
430  nameCaseSensitivity = Qt::CaseInsensitive;
431  }
433  {
434  }
435 
436  inline QString nodeToName(QSvgNode *node) const
437  {
439  }
440 
441  inline QSvgNode *svgNode(NodePtr node) const
442  {
443  return (QSvgNode*)node.ptr;
444  }
446  {
447  if (n &&
448  (n->type() == QSvgNode::DOC ||
449  n->type() == QSvgNode::G ||
450  n->type() == QSvgNode::DEFS ||
451  n->type() == QSvgNode::SWITCH)) {
452  return (QSvgStructureNode*)n;
453  }
454  return 0;
455  }
456 
458  {
459  QSvgNode *n = svgNode(node);
460  QSvgStructureNode *st = nodeToStructure(n);
461  return st;
462  }
463 
464  virtual bool nodeNameEquals(NodePtr node, const QString& nodeName) const
465  {
466  QSvgNode *n = svgNode(node);
467  if (!n)
468  return false;
469  QString name = nodeToName(n);
470  return QString::compare(name, nodeName, Qt::CaseInsensitive) == 0;
471  }
472  virtual QString attribute(NodePtr node, const QString &name) const
473  {
474  QSvgNode *n = svgNode(node);
475  if ((!n->nodeId().isEmpty() && (name == QLatin1String("id") ||
476  name == QLatin1String("xml:id"))))
477  return n->nodeId();
478  if (!n->xmlClass().isEmpty() && name == QLatin1String("class"))
479  return n->xmlClass();
480  return QString();
481  }
482  virtual bool hasAttributes(NodePtr node) const
483  {
484  QSvgNode *n = svgNode(node);
485  return (n &&
486  (!n->nodeId().isEmpty() || !n->xmlClass().isEmpty()));
487  }
488 
489  virtual QStringList nodeIds(NodePtr node) const
490  {
491  QSvgNode *n = svgNode(node);
492  QString nid;
493  if (n)
494  nid = n->nodeId();
495  QStringList lst; lst.append(nid);
496  return lst;
497  }
498 
499  virtual QStringList nodeNames(NodePtr node) const
500  {
501  QSvgNode *n = svgNode(node);
502  if (n)
503  return QStringList(nodeToName(n));
504  return QStringList();
505  }
506 
507  virtual bool isNullNode(NodePtr node) const
508  {
509  return !node.ptr;
510  }
511 
512  virtual NodePtr parentNode(NodePtr node) const
513  {
514  QSvgNode *n = svgNode(node);
515  NodePtr newNode;
516  newNode.ptr = 0;
517  newNode.id = 0;
518  if (n) {
519  QSvgNode *svgParent = n->parent();
520  if (svgParent) {
521  newNode.ptr = svgParent;
522  }
523  }
524  return newNode;
525  }
526  virtual NodePtr previousSiblingNode(NodePtr node) const
527  {
528  NodePtr newNode;
529  newNode.ptr = 0;
530  newNode.id = 0;
531 
532  QSvgNode *n = svgNode(node);
533  if (!n)
534  return newNode;
535  QSvgStructureNode *svgParent = nodeToStructure(n->parent());
536 
537  if (svgParent) {
538  newNode.ptr = svgParent->previousSiblingNode(n);
539  }
540  return newNode;
541  }
542  virtual NodePtr duplicateNode(NodePtr node) const
543  {
544  NodePtr n;
545  n.ptr = node.ptr;
546  n.id = node.id;
547  return n;
548  }
549  virtual void freeNode(NodePtr node) const
550  {
551  Q_UNUSED(node);
552  }
553 };
554 
555 // '0' is 0x30 and '9' is 0x39
556 static inline bool isDigit(ushort ch)
557 {
558  static quint16 magic = 0x3ff;
559  return ((ch >> 4) == 3) && (magic >> (ch & 15));
560 }
561 
562 static qreal toDouble(const QChar *&str)
563 {
564  const int maxLen = 255;//technically doubles can go til 308+ but whatever
565  char temp[maxLen+1];
566  int pos = 0;
567 
568  if (*str == QLatin1Char('-')) {
569  temp[pos++] = '-';
570  ++str;
571  } else if (*str == QLatin1Char('+')) {
572  ++str;
573  }
574  while (isDigit(str->unicode()) && pos < maxLen) {
575  temp[pos++] = str->toLatin1();
576  ++str;
577  }
578  if (*str == QLatin1Char('.') && pos < maxLen) {
579  temp[pos++] = '.';
580  ++str;
581  }
582  while (isDigit(str->unicode()) && pos < maxLen) {
583  temp[pos++] = str->toLatin1();
584  ++str;
585  }
586  bool exponent = false;
587  if ((*str == QLatin1Char('e') || *str == QLatin1Char('E')) && pos < maxLen) {
588  exponent = true;
589  temp[pos++] = 'e';
590  ++str;
591  if ((*str == QLatin1Char('-') || *str == QLatin1Char('+')) && pos < maxLen) {
592  temp[pos++] = str->toLatin1();
593  ++str;
594  }
595  while (isDigit(str->unicode()) && pos < maxLen) {
596  temp[pos++] = str->toLatin1();
597  ++str;
598  }
599  }
600 
601  temp[pos] = '\0';
602 
603  qreal val;
604  if (!exponent && pos < 10) {
605  int ival = 0;
606  const char *t = temp;
607  bool neg = false;
608  if(*t == '-') {
609  neg = true;
610  ++t;
611  }
612  while(*t && *t != '.') {
613  ival *= 10;
614  ival += (*t) - '0';
615  ++t;
616  }
617  if(*t == '.') {
618  ++t;
619  int div = 1;
620  while(*t) {
621  ival *= 10;
622  ival += (*t) - '0';
623  div *= 10;
624  ++t;
625  }
626  val = ((qreal)ival)/((qreal)div);
627  } else {
628  val = ival;
629  }
630  if (neg)
631  val = -val;
632  } else {
633 #if defined(Q_WS_QWS) && !defined(Q_OS_VXWORKS)
634  if(sizeof(qreal) == sizeof(float))
635  val = strtof(temp, 0);
636  else
637 #endif
638  {
639  bool ok = false;
640  val = qstrtod(temp, 0, &ok);
641  }
642  }
643  return val;
644 
645 }
646 static qreal toDouble(const QString &str, bool *ok = NULL)
647 {
648  const QChar *c = str.constData();
649  qreal res = toDouble(c);
650  if (ok) {
651  *ok = ((*c) == QLatin1Char('\0'));
652  }
653  return res;
654 }
655 
656 static qreal toDouble(const QStringRef &str, bool *ok = NULL)
657 {
658  const QChar *c = str.constData();
659  qreal res = toDouble(c);
660  if (ok) {
661  *ok = (c == (str.constData() + str.length()));
662  }
663  return res;
664 }
665 
667 {
668  QVector<qreal> points;
669  if (!str)
670  return points;
671  points.reserve(32);
672 
673  while (str->isSpace())
674  ++str;
675  while (isDigit(str->unicode()) ||
676  *str == QLatin1Char('-') || *str == QLatin1Char('+') ||
677  *str == QLatin1Char('.')) {
678 
679  points.append(toDouble(str));
680 
681  while (str->isSpace())
682  ++str;
683  if (*str == QLatin1Char(','))
684  ++str;
685 
686  //eat the rest of space
687  while (str->isSpace())
688  ++str;
689  }
690 
691  return points;
692 }
693 
694 static inline void parseNumbersArray(const QChar *&str, QVarLengthArray<qreal, 8> &points)
695 {
696  while (str->isSpace())
697  ++str;
698  while (isDigit(str->unicode()) ||
699  *str == QLatin1Char('-') || *str == QLatin1Char('+') ||
700  *str == QLatin1Char('.')) {
701 
702  points.append(toDouble(str));
703 
704  while (str->isSpace())
705  ++str;
706  if (*str == QLatin1Char(','))
707  ++str;
708 
709  //eat the rest of space
710  while (str->isSpace())
711  ++str;
712  }
713 }
714 
716 {
717  QVector<qreal> points;
718  if (!str)
719  return points;
720 
721  while (str->isSpace())
722  ++str;
723  while ((*str >= QLatin1Char('0') && *str <= QLatin1Char('9')) ||
724  *str == QLatin1Char('-') || *str == QLatin1Char('+') ||
725  *str == QLatin1Char('.')) {
726 
727  points.append(toDouble(str));
728 
729  while (str->isSpace())
730  ++str;
731  if (*str == QLatin1Char('%'))
732  ++str;
733  while (str->isSpace())
734  ++str;
735  if (*str == QLatin1Char(','))
736  ++str;
737 
738  //eat the rest of space
739  while (str->isSpace())
740  ++str;
741  }
742 
743  return points;
744 }
745 
746 static QString idFromUrl(const QString &url)
747 {
749  while ((*itr).isSpace())
750  ++itr;
751  if ((*itr) == QLatin1Char('('))
752  ++itr;
753  while ((*itr).isSpace())
754  ++itr;
755  if ((*itr) == QLatin1Char('#'))
756  ++itr;
757  QString id;
758  while ((*itr) != QLatin1Char(')')) {
759  id += *itr;
760  ++itr;
761  }
762  return id;
763 }
764 
765 static inline QStringRef trimRef(const QStringRef &str)
766 {
767  if (str.isEmpty())
768  return QStringRef();
769  const QChar *s = str.string()->constData() + str.position();
770  int end = str.length() - 1;
771  if (!s[0].isSpace() && !s[end].isSpace())
772  return str;
773 
774  int start = 0;
775  while (start<=end && s[start].isSpace()) // skip white space from start
776  start++;
777  if (start <= end) { // only white space
778  while (s[end].isSpace()) // skip white space from end
779  end--;
780  }
781  int l = end - start + 1;
782  if (l <= 0)
783  return QStringRef();
784  return QStringRef(str.string(), str.position() + start, l);
785 }
786 
791 static bool resolveColor(const QStringRef &colorStr, QColor &color, QSvgHandler *handler)
792 {
793  QStringRef colorStrTr = trimRef(colorStr);
794  if (colorStrTr.isEmpty())
795  return false;
796 
797  switch(colorStrTr.at(0).unicode()) {
798 
799  case '#':
800  {
801  // #rrggbb is very very common, so let's tackle it here
802  // rather than falling back to QColor
803  QRgb rgb;
804  bool ok = qsvg_get_hex_rgb(colorStrTr.unicode(), colorStrTr.length(), &rgb);
805  if (ok)
806  color.setRgb(rgb);
807  return ok;
808  }
809  break;
810 
811  case 'r':
812  {
813  // starts with "rgb(", ends with ")" and consists of at least 7 characters "rgb(,,)"
814  if (colorStrTr.length() >= 7 && colorStrTr.at(colorStrTr.length() - 1) == QLatin1Char(')')
815  && QStringRef(colorStrTr.string(), colorStrTr.position(), 4) == QLatin1String("rgb(")) {
816  const QChar *s = colorStrTr.constData() + 4;
817  QVector<qreal> compo = parseNumbersList(s);
818  //1 means that it failed after reaching non-parsable
819  //character which is going to be "%"
820  if (compo.size() == 1) {
821  s = colorStrTr.constData() + 4;
822  compo = parsePercentageList(s);
823  for (int i = 0; i < compo.size(); ++i)
824  compo[i] *= (qreal)2.55;
825  }
826 
827  if (compo.size() == 3) {
828  color = QColor(int(compo[0]),
829  int(compo[1]),
830  int(compo[2]));
831  return true;
832  }
833  return false;
834  }
835  }
836  break;
837 
838  case 'c':
839  if (colorStrTr == QLatin1String("currentColor")) {
840  color = handler->currentColor();
841  return true;
842  }
843  break;
844  case 'i':
845  if (colorStrTr == QT_INHERIT)
846  return false;
847  break;
848  default:
849  break;
850  }
851 
852  color = QColor(colorStrTr.toString());
853  return color.isValid();
854 }
855 
856 static bool constructColor(const QStringRef &colorStr, const QStringRef &opacity,
858 {
859  if (!resolveColor(colorStr, color, handler))
860  return false;
861  if (!opacity.isEmpty()) {
862  bool ok = true;
863  qreal op = qMin(qreal(1.0), qMax(qreal(0.0), toDouble(opacity, &ok)));
864  if (!ok)
865  op = 1.0;
866  color.setAlphaF(op);
867  }
868  return true;
869 }
870 
872  QSvgHandler *handler, bool *ok = NULL)
873 {
874  QString numStr = str.trimmed();
875 
876  if (numStr.endsWith(QLatin1Char('%'))) {
877  numStr.chop(1);
879  } else if (numStr.endsWith(QLatin1String("px"))) {
880  numStr.chop(2);
881  type = QSvgHandler::LT_PX;
882  } else if (numStr.endsWith(QLatin1String("pc"))) {
883  numStr.chop(2);
884  type = QSvgHandler::LT_PC;
885  } else if (numStr.endsWith(QLatin1String("pt"))) {
886  numStr.chop(2);
887  type = QSvgHandler::LT_PT;
888  } else if (numStr.endsWith(QLatin1String("mm"))) {
889  numStr.chop(2);
890  type = QSvgHandler::LT_MM;
891  } else if (numStr.endsWith(QLatin1String("cm"))) {
892  numStr.chop(2);
893  type = QSvgHandler::LT_CM;
894  } else if (numStr.endsWith(QLatin1String("in"))) {
895  numStr.chop(2);
896  type = QSvgHandler::LT_IN;
897  } else {
898  type = handler->defaultCoordinateSystem();
899  //type = QSvgHandler::LT_OTHER;
900  }
901  qreal len = toDouble(numStr, ok);
902  //qDebug()<<"len is "<<len<<", from '"<<numStr << "'";
903  return len;
904 }
905 
906 static inline qreal convertToNumber(const QString &str, QSvgHandler *handler, bool *ok = NULL)
907 {
909  qreal num = parseLength(str, type, handler, ok);
910  if (type == QSvgHandler::LT_PERCENT) {
911  num = num/100.0;
912  }
913  return num;
914 }
915 
916 static bool createSvgGlyph(QSvgFont *font, const QXmlStreamAttributes &attributes)
917 {
918  QStringRef uncStr = attributes.value(QLatin1String("unicode"));
919  QStringRef havStr = attributes.value(QLatin1String("horiz-adv-x"));
920  QStringRef pathStr = attributes.value(QLatin1String("d"));
921 
922  QChar unicode = (uncStr.isEmpty()) ? 0 : uncStr.at(0);
923  qreal havx = (havStr.isEmpty()) ? -1 : toDouble(havStr);
924  QPainterPath path;
926  parsePathDataFast(pathStr, path);
927 
928  font->addGlyph(unicode, path, havx);
929 
930  return true;
931 }
932 
933 // this should really be called convertToDefaultCoordinateSystem
934 // and convert when type != QSvgHandler::defaultCoordinateSystem
936 {
937 
938  switch (type) {
940  break;
941  case QSvgHandler::LT_PX:
942  break;
943  case QSvgHandler::LT_PC:
944  break;
945  case QSvgHandler::LT_PT:
946  return len * 1.25;
947  break;
948  case QSvgHandler::LT_MM:
949  return len * 3.543307;
950  break;
951  case QSvgHandler::LT_CM:
952  return len * 35.43307;
953  break;
954  case QSvgHandler::LT_IN:
955  return len * 90;
956  break;
958  break;
959  default:
960  break;
961  }
962  return len;
963 }
964 
965 static void parseColor(QSvgNode *,
966  const QSvgAttributes &attributes,
968 {
969  QColor color;
970  if (constructColor(attributes.color, attributes.colorOpacity, color, handler)) {
971  handler->popColor();
972  handler->pushColor(color);
973  }
974 }
975 
976 static QSvgStyleProperty *styleFromUrl(QSvgNode *node, const QString &url)
977 {
978  return node ? node->styleProperty(idFromUrl(url)) : 0;
979 }
980 
981 static void parseBrush(QSvgNode *node,
982  const QSvgAttributes &attributes,
984 {
985  if (!attributes.fill.isEmpty() || !attributes.fillRule.isEmpty() || !attributes.fillOpacity.isEmpty()) {
986  QSvgFillStyle *prop = new QSvgFillStyle;
987 
988  //fill-rule attribute handling
989  if (!attributes.fillRule.isEmpty() && attributes.fillRule != QT_INHERIT) {
990  if (attributes.fillRule == QLatin1String("evenodd"))
992  else if (attributes.fillRule == QLatin1String("nonzero"))
994  }
995 
996  //fill-opacity atttribute handling
997  if (!attributes.fillOpacity.isEmpty() && attributes.fillOpacity != QT_INHERIT) {
998  prop->setFillOpacity(qMin(qreal(1.0), qMax(qreal(0.0), toDouble(attributes.fillOpacity))));
999  }
1000 
1001  //fill attribute handling
1002  if ((!attributes.fill.isEmpty()) && (attributes.fill != QT_INHERIT) ) {
1003  if (attributes.fill.length() > 3 &&
1004  QStringRef(attributes.fill.string(), attributes.fill.position(), 3) == QLatin1String("url")) {
1005  QStringRef urlRef(attributes.fill.string(), attributes.fill.position() + 3, attributes.fill.length() - 3);
1006  QString value = urlRef.toString();
1007  QSvgStyleProperty *style = styleFromUrl(node, value);
1008  if (style) {
1010  prop->setFillStyle(reinterpret_cast<QSvgFillStyleProperty *>(style));
1011  } else {
1012  QString id = idFromUrl(value);
1013  prop->setGradientId(id);
1014  prop->setGradientResolved(false);
1015  }
1016  } else if (attributes.fill != QLatin1String("none")) {
1017  QColor color;
1018  if (resolveColor(attributes.fill, color, handler))
1019  prop->setBrush(QBrush(color));
1020  } else {
1021  prop->setBrush(QBrush(Qt::NoBrush));
1022  }
1023  }
1024  node->appendStyleProperty(prop, attributes.id);
1025  }
1026 }
1027 
1028 
1029 
1031 {
1032  if (value.isEmpty())
1033  return QMatrix();
1034 
1035  QMatrix matrix;
1036  const QChar *str = value.constData();
1037  const QChar *end = str + value.length();
1038 
1039  while (str < end) {
1040  if (str->isSpace() || *str == QLatin1Char(',')) {
1041  ++str;
1042  continue;
1043  }
1044  enum State {
1045  Matrix,
1046  Translate,
1047  Rotate,
1048  Scale,
1049  SkewX,
1050  SkewY
1051  };
1052  State state = Matrix;
1053  if (*str == QLatin1Char('m')) { //matrix
1054  const char *ident = "atrix";
1055  for (int i = 0; i < 5; ++i)
1056  if (*(++str) != QLatin1Char(ident[i]))
1057  goto error;
1058  ++str;
1059  state = Matrix;
1060  } else if (*str == QLatin1Char('t')) { //translate
1061  const char *ident = "ranslate";
1062  for (int i = 0; i < 8; ++i)
1063  if (*(++str) != QLatin1Char(ident[i]))
1064  goto error;
1065  ++str;
1066  state = Translate;
1067  } else if (*str == QLatin1Char('r')) { //rotate
1068  const char *ident = "otate";
1069  for (int i = 0; i < 5; ++i)
1070  if (*(++str) != QLatin1Char(ident[i]))
1071  goto error;
1072  ++str;
1073  state = Rotate;
1074  } else if (*str == QLatin1Char('s')) { //scale, skewX, skewY
1075  ++str;
1076  if (*str == QLatin1Char('c')) {
1077  const char *ident = "ale";
1078  for (int i = 0; i < 3; ++i)
1079  if (*(++str) != QLatin1Char(ident[i]))
1080  goto error;
1081  ++str;
1082  state = Scale;
1083  } else if (*str == QLatin1Char('k')) {
1084  if (*(++str) != QLatin1Char('e'))
1085  goto error;
1086  if (*(++str) != QLatin1Char('w'))
1087  goto error;
1088  ++str;
1089  if (*str == QLatin1Char('X'))
1090  state = SkewX;
1091  else if (*str == QLatin1Char('Y'))
1092  state = SkewY;
1093  else
1094  goto error;
1095  ++str;
1096  } else {
1097  goto error;
1098  }
1099  } else {
1100  goto error;
1101  }
1102 
1103 
1104  while (str < end && str->isSpace())
1105  ++str;
1106  if (*str != QLatin1Char('('))
1107  goto error;
1108  ++str;
1110  parseNumbersArray(str, points);
1111  if (*str != QLatin1Char(')'))
1112  goto error;
1113  ++str;
1114 
1115  if(state == Matrix) {
1116  if(points.count() != 6)
1117  goto error;
1118  matrix = matrix * QMatrix(points[0], points[1],
1119  points[2], points[3],
1120  points[4], points[5]);
1121  } else if (state == Translate) {
1122  if (points.count() == 1)
1123  matrix.translate(points[0], 0);
1124  else if (points.count() == 2)
1125  matrix.translate(points[0], points[1]);
1126  else
1127  goto error;
1128  } else if (state == Rotate) {
1129  if(points.count() == 1) {
1130  matrix.rotate(points[0]);
1131  } else if (points.count() == 3) {
1132  matrix.translate(points[1], points[2]);
1133  matrix.rotate(points[0]);
1134  matrix.translate(-points[1], -points[2]);
1135  } else {
1136  goto error;
1137  }
1138  } else if (state == Scale) {
1139  if (points.count() < 1 || points.count() > 2)
1140  goto error;
1141  qreal sx = points[0];
1142  qreal sy = sx;
1143  if(points.count() == 2)
1144  sy = points[1];
1145  matrix.scale(sx, sy);
1146  } else if (state == SkewX) {
1147  if (points.count() != 1)
1148  goto error;
1149  const qreal deg2rad = qreal(0.017453292519943295769);
1150  matrix.shear(qTan(points[0]*deg2rad), 0);
1151  } else if (state == SkewY) {
1152  if (points.count() != 1)
1153  goto error;
1154  const qreal deg2rad = qreal(0.017453292519943295769);
1155  matrix.shear(0, qTan(points[0]*deg2rad));
1156  }
1157  }
1158  error:
1159  return matrix;
1160 }
1161 
1162 static void parsePen(QSvgNode *node,
1163  const QSvgAttributes &attributes,
1165 {
1166  //qDebug()<<"Node "<<node->type()<<", attrs are "<<value<<width;
1167 
1168  if (!attributes.stroke.isEmpty() || !attributes.strokeDashArray.isEmpty() || !attributes.strokeDashOffset.isEmpty() || !attributes.strokeLineCap.isEmpty()
1169  || !attributes.strokeLineJoin.isEmpty() || !attributes.strokeMiterLimit.isEmpty() || !attributes.strokeOpacity.isEmpty() || !attributes.strokeWidth.isEmpty()
1170  || !attributes.vectorEffect.isEmpty()) {
1171 
1172  QSvgStrokeStyle *prop = new QSvgStrokeStyle;
1173 
1174  //stroke attribute handling
1175  if ((!attributes.stroke.isEmpty()) && (attributes.stroke != QT_INHERIT) ) {
1176  if (attributes.stroke.length() > 3 &&
1177  QStringRef(attributes.stroke.string(), attributes.stroke.position(), 3) == QLatin1String("url")) {
1178  QStringRef urlRef(attributes.stroke.string(), attributes.stroke.position() + 3, attributes.stroke.length() - 3);
1179  QString value = urlRef.toString();
1180  QSvgStyleProperty *style = styleFromUrl(node, value);
1181  if (style) {
1183  prop->setStyle(reinterpret_cast<QSvgFillStyleProperty *>(style));
1184  } else {
1185  QString id = idFromUrl(value);
1186  prop->setGradientId(id);
1187  prop->setGradientResolved(false);
1188  }
1189  } else if (attributes.stroke != QLatin1String("none")) {
1190  QColor color;
1191  if (resolveColor(attributes.stroke, color, handler))
1192  prop->setStroke(QBrush(color));
1193  } else {
1194  prop->setStroke(QBrush(Qt::NoBrush));
1195  }
1196  }
1197 
1198  //stroke-width handling
1199  if (!attributes.strokeWidth.isEmpty() && attributes.strokeWidth != QT_INHERIT) {
1201  prop->setWidth(parseLength(attributes.strokeWidth.toString(), lt, handler));
1202  }
1203 
1204  //stroke-dasharray
1205  if (!attributes.strokeDashArray.isEmpty() && attributes.strokeDashArray != QT_INHERIT) {
1206  if (attributes.strokeDashArray == QLatin1String("none")) {
1207  prop->setDashArrayNone();
1208  } else {
1209  QString dashArray = attributes.strokeDashArray.toString();
1210  const QChar *s = dashArray.constData();
1211  QVector<qreal> dashes = parseNumbersList(s);
1212  // if the dash count is odd the dashes should be duplicated
1213  if ((dashes.size() & 1) != 0)
1214  dashes << QVector<qreal>(dashes);
1215  prop->setDashArray(dashes);
1216  }
1217  }
1218 
1219  //stroke-linejoin attribute handling
1220  if (!attributes.strokeLineJoin.isEmpty()) {
1221  if (attributes.strokeLineJoin == QLatin1String("miter"))
1223  else if (attributes.strokeLineJoin == QLatin1String("round"))
1224  prop->setLineJoin(Qt::RoundJoin);
1225  else if (attributes.strokeLineJoin == QLatin1String("bevel"))
1226  prop->setLineJoin(Qt::BevelJoin);
1227  }
1228 
1229  //stroke-linecap attribute handling
1230  if (!attributes.strokeLineCap.isEmpty()) {
1231  if (attributes.strokeLineCap == QLatin1String("butt"))
1232  prop->setLineCap(Qt::FlatCap);
1233  else if (attributes.strokeLineCap == QLatin1String("round"))
1234  prop->setLineCap(Qt::RoundCap);
1235  else if (attributes.strokeLineCap == QLatin1String("square"))
1236  prop->setLineCap(Qt::SquareCap);
1237  }
1238 
1239  //stroke-dashoffset attribute handling
1240  if (!attributes.strokeDashOffset.isEmpty() && attributes.strokeDashOffset != QT_INHERIT)
1241  prop->setDashOffset(toDouble(attributes.strokeDashOffset));
1242 
1243  //vector-effect attribute handling
1244  if (!attributes.vectorEffect.isEmpty()) {
1245  if (attributes.vectorEffect == QLatin1String("non-scaling-stroke"))
1246  prop->setVectorEffect(true);
1247  else if (attributes.vectorEffect == QLatin1String("none"))
1248  prop->setVectorEffect(false);
1249  }
1250 
1251  //stroke-miterlimit
1252  if (!attributes.strokeMiterLimit.isEmpty() && attributes.strokeMiterLimit != QT_INHERIT)
1253  prop->setMiterLimit(toDouble(attributes.strokeMiterLimit));
1254 
1255  //stroke-opacity atttribute handling
1256  if (!attributes.strokeOpacity.isEmpty() && attributes.strokeOpacity != QT_INHERIT)
1257  prop->setOpacity(qMin(qreal(1.0), qMax(qreal(0.0), toDouble(attributes.strokeOpacity))));
1258 
1259  node->appendStyleProperty(prop, attributes.id);
1260  }
1261 }
1262 
1263 static void parseFont(QSvgNode *node,
1264  const QSvgAttributes &attributes,
1266 {
1267  if (attributes.fontFamily.isEmpty() && attributes.fontSize.isEmpty() && attributes.fontStyle.isEmpty() &&
1268  attributes.fontWeight.isEmpty() && attributes.fontVariant.isEmpty() && attributes.textAnchor.isEmpty())
1269  return;
1270 
1271  QSvgTinyDocument *doc = node->document();
1272  QSvgFontStyle *fontStyle = 0;
1273  if (!attributes.fontFamily.isEmpty()) {
1274  QSvgFont *svgFont = doc->svgFont(attributes.fontFamily.toString());
1275  if (svgFont)
1276  fontStyle = new QSvgFontStyle(svgFont, doc);
1277  }
1278  if (!fontStyle)
1279  fontStyle = new QSvgFontStyle;
1280 
1281  if (!attributes.fontFamily.isEmpty() && attributes.fontFamily != QT_INHERIT)
1282  fontStyle->setFamily(attributes.fontFamily.toString().trimmed());
1283 
1284  if (!attributes.fontSize.isEmpty() && attributes.fontSize != QT_INHERIT) {
1285  // TODO: Support relative sizes 'larger' and 'smaller'.
1286  QSvgHandler::LengthType dummy; // should always be pixel size
1287  qreal size = 0;
1288  static const qreal sizeTable[] = { qreal(6.9), qreal(8.3), qreal(10.0), qreal(12.0), qreal(14.4), qreal(17.3), qreal(20.7) };
1289  enum AbsFontSize { XXSmall, XSmall, Small, Medium, Large, XLarge, XXLarge };
1290  switch (attributes.fontSize.at(0).unicode()) {
1291  case 'x':
1292  if (attributes.fontSize == QLatin1String("xx-small"))
1293  size = sizeTable[XXSmall];
1294  else if (attributes.fontSize == QLatin1String("x-small"))
1295  size = sizeTable[XSmall];
1296  else if (attributes.fontSize == QLatin1String("x-large"))
1297  size = sizeTable[XLarge];
1298  else if (attributes.fontSize == QLatin1String("xx-large"))
1299  size = sizeTable[XXLarge];
1300  break;
1301  case 's':
1302  if (attributes.fontSize == QLatin1String("small"))
1303  size = sizeTable[Small];
1304  break;
1305  case 'm':
1306  if (attributes.fontSize == QLatin1String("medium"))
1307  size = sizeTable[Medium];
1308  break;
1309  case 'l':
1310  if (attributes.fontSize == QLatin1String("large"))
1311  size = sizeTable[Large];
1312  break;
1313  default:
1314  size = parseLength(attributes.fontSize.toString(), dummy, handler);
1315  break;
1316  }
1317  fontStyle->setSize(size);
1318  }
1319 
1320  if (!attributes.fontStyle.isEmpty() && attributes.fontStyle != QT_INHERIT) {
1321  if (attributes.fontStyle == QLatin1String("normal")) {
1322  fontStyle->setStyle(QFont::StyleNormal);
1323  } else if (attributes.fontStyle == QLatin1String("italic")) {
1324  fontStyle->setStyle(QFont::StyleItalic);
1325  } else if (attributes.fontStyle == QLatin1String("oblique")) {
1326  fontStyle->setStyle(QFont::StyleOblique);
1327  }
1328  }
1329 
1330  if (!attributes.fontWeight.isEmpty() && attributes.fontWeight != QT_INHERIT) {
1331  bool ok = false;
1332  int weightNum = attributes.fontWeight.toString().toInt(&ok);
1333  if (ok) {
1334  fontStyle->setWeight(weightNum);
1335  } else {
1336  if (attributes.fontWeight == QLatin1String("normal")) {
1337  fontStyle->setWeight(400);
1338  } else if (attributes.fontWeight == QLatin1String("bold")) {
1339  fontStyle->setWeight(700);
1340  } else if (attributes.fontWeight == QLatin1String("bolder")) {
1341  fontStyle->setWeight(QSvgFontStyle::BOLDER);
1342  } else if (attributes.fontWeight == QLatin1String("lighter")) {
1343  fontStyle->setWeight(QSvgFontStyle::LIGHTER);
1344  }
1345  }
1346  }
1347 
1348  if (!attributes.fontVariant.isEmpty() && attributes.fontVariant != QT_INHERIT) {
1349  if (attributes.fontVariant == QLatin1String("normal"))
1350  fontStyle->setVariant(QFont::MixedCase);
1351  else if (attributes.fontVariant == QLatin1String("small-caps"))
1352  fontStyle->setVariant(QFont::SmallCaps);
1353  }
1354 
1355  if (!attributes.textAnchor.isEmpty() && attributes.textAnchor != QT_INHERIT) {
1356  if (attributes.textAnchor == QLatin1String("start"))
1357  fontStyle->setTextAnchor(Qt::AlignLeft);
1358  if (attributes.textAnchor == QLatin1String("middle"))
1359  fontStyle->setTextAnchor(Qt::AlignHCenter);
1360  else if (attributes.textAnchor == QLatin1String("end"))
1361  fontStyle->setTextAnchor(Qt::AlignRight);
1362  }
1363 
1364  node->appendStyleProperty(fontStyle, attributes.id);
1365 }
1366 
1367 static void parseTransform(QSvgNode *node,
1368  const QSvgAttributes &attributes,
1369  QSvgHandler *)
1370 {
1371  if (attributes.transform.isEmpty())
1372  return;
1373  QMatrix matrix = parseTransformationMatrix(trimRef(attributes.transform));
1374 
1375  if (!matrix.isIdentity()) {
1376  node->appendStyleProperty(new QSvgTransformStyle(QTransform(matrix)), attributes.id);
1377  }
1378 
1379 }
1380 
1381 static void parseVisibility(QSvgNode *node,
1382  const QSvgAttributes &attributes,
1383  QSvgHandler *)
1384 {
1385  QSvgNode *parent = node->parent();
1386 
1387  if (parent && (attributes.visibility.isEmpty() || attributes.visibility == QT_INHERIT))
1388  node->setVisible(parent->isVisible());
1389  else if (attributes.visibility == QLatin1String("hidden") || attributes.visibility == QLatin1String("collapse")) {
1390  node->setVisible(false);
1391  } else
1392  node->setVisible(true);
1393 }
1394 
1395 static void pathArcSegment(QPainterPath &path,
1396  qreal xc, qreal yc,
1397  qreal th0, qreal th1,
1398  qreal rx, qreal ry, qreal xAxisRotation)
1399 {
1400  qreal sinTh, cosTh;
1401  qreal a00, a01, a10, a11;
1402  qreal x1, y1, x2, y2, x3, y3;
1403  qreal t;
1404  qreal thHalf;
1405 
1406  sinTh = qSin(xAxisRotation * (Q_PI / 180.0));
1407  cosTh = qCos(xAxisRotation * (Q_PI / 180.0));
1408 
1409  a00 = cosTh * rx;
1410  a01 = -sinTh * ry;
1411  a10 = sinTh * rx;
1412  a11 = cosTh * ry;
1413 
1414  thHalf = 0.5 * (th1 - th0);
1415  t = (8.0 / 3.0) * qSin(thHalf * 0.5) * qSin(thHalf * 0.5) / qSin(thHalf);
1416  x1 = xc + qCos(th0) - t * qSin(th0);
1417  y1 = yc + qSin(th0) + t * qCos(th0);
1418  x3 = xc + qCos(th1);
1419  y3 = yc + qSin(th1);
1420  x2 = x3 + t * qSin(th1);
1421  y2 = y3 - t * qCos(th1);
1422 
1423  path.cubicTo(a00 * x1 + a01 * y1, a10 * x1 + a11 * y1,
1424  a00 * x2 + a01 * y2, a10 * x2 + a11 * y2,
1425  a00 * x3 + a01 * y3, a10 * x3 + a11 * y3);
1426 }
1427 
1428 // the arc handling code underneath is from XSVG (BSD license)
1429 /*
1430  * Copyright 2002 USC/Information Sciences Institute
1431  *
1432  * Permission to use, copy, modify, distribute, and sell this software
1433  * and its documentation for any purpose is hereby granted without
1434  * fee, provided that the above copyright notice appear in all copies
1435  * and that both that copyright notice and this permission notice
1436  * appear in supporting documentation, and that the name of
1437  * Information Sciences Institute not be used in advertising or
1438  * publicity pertaining to distribution of the software without
1439  * specific, written prior permission. Information Sciences Institute
1440  * makes no representations about the suitability of this software for
1441  * any purpose. It is provided "as is" without express or implied
1442  * warranty.
1443  *
1444  * INFORMATION SCIENCES INSTITUTE DISCLAIMS ALL WARRANTIES WITH REGARD
1445  * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
1446  * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL INFORMATION SCIENCES
1447  * INSTITUTE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
1448  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
1449  * OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
1450  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1451  * PERFORMANCE OF THIS SOFTWARE.
1452  *
1453  */
1454 static void pathArc(QPainterPath &path,
1455  qreal rx,
1456  qreal ry,
1457  qreal x_axis_rotation,
1458  int large_arc_flag,
1459  int sweep_flag,
1460  qreal x,
1461  qreal y,
1462  qreal curx, qreal cury)
1463 {
1464  qreal sin_th, cos_th;
1465  qreal a00, a01, a10, a11;
1466  qreal x0, y0, x1, y1, xc, yc;
1467  qreal d, sfactor, sfactor_sq;
1468  qreal th0, th1, th_arc;
1469  int i, n_segs;
1470  qreal dx, dy, dx1, dy1, Pr1, Pr2, Px, Py, check;
1471 
1472  rx = qAbs(rx);
1473  ry = qAbs(ry);
1474 
1475  sin_th = qSin(x_axis_rotation * (Q_PI / 180.0));
1476  cos_th = qCos(x_axis_rotation * (Q_PI / 180.0));
1477 
1478  dx = (curx - x) / 2.0;
1479  dy = (cury - y) / 2.0;
1480  dx1 = cos_th * dx + sin_th * dy;
1481  dy1 = -sin_th * dx + cos_th * dy;
1482  Pr1 = rx * rx;
1483  Pr2 = ry * ry;
1484  Px = dx1 * dx1;
1485  Py = dy1 * dy1;
1486  /* Spec : check if radii are large enough */
1487  check = Px / Pr1 + Py / Pr2;
1488  if (check > 1) {
1489  rx = rx * qSqrt(check);
1490  ry = ry * qSqrt(check);
1491  }
1492 
1493  a00 = cos_th / rx;
1494  a01 = sin_th / rx;
1495  a10 = -sin_th / ry;
1496  a11 = cos_th / ry;
1497  x0 = a00 * curx + a01 * cury;
1498  y0 = a10 * curx + a11 * cury;
1499  x1 = a00 * x + a01 * y;
1500  y1 = a10 * x + a11 * y;
1501  /* (x0, y0) is current point in transformed coordinate space.
1502  (x1, y1) is new point in transformed coordinate space.
1503 
1504  The arc fits a unit-radius circle in this space.
1505  */
1506  d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
1507  sfactor_sq = 1.0 / d - 0.25;
1508  if (sfactor_sq < 0) sfactor_sq = 0;
1509  sfactor = qSqrt(sfactor_sq);
1510  if (sweep_flag == large_arc_flag) sfactor = -sfactor;
1511  xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0);
1512  yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0);
1513  /* (xc, yc) is center of the circle. */
1514 
1515  th0 = qAtan2(y0 - yc, x0 - xc);
1516  th1 = qAtan2(y1 - yc, x1 - xc);
1517 
1518  th_arc = th1 - th0;
1519  if (th_arc < 0 && sweep_flag)
1520  th_arc += 2 * Q_PI;
1521  else if (th_arc > 0 && !sweep_flag)
1522  th_arc -= 2 * Q_PI;
1523 
1524  n_segs = qCeil(qAbs(th_arc / (Q_PI * 0.5 + 0.001)));
1525 
1526  for (i = 0; i < n_segs; i++) {
1527  pathArcSegment(path, xc, yc,
1528  th0 + i * th_arc / n_segs,
1529  th0 + (i + 1) * th_arc / n_segs,
1530  rx, ry, x_axis_rotation);
1531  }
1532 }
1533 
1534 static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
1535 {
1536  qreal x0 = 0, y0 = 0; // starting point
1537  qreal x = 0, y = 0; // current point
1538  char lastMode = 0;
1539  QPointF ctrlPt;
1540  const QChar *str = dataStr.constData();
1541  const QChar *end = str + dataStr.size();
1542 
1543  while (str != end) {
1544  while (str->isSpace())
1545  ++str;
1546  QChar pathElem = *str;
1547  ++str;
1548  QChar endc = *end;
1549  *const_cast<QChar *>(end) = 0; // parseNumbersArray requires 0-termination that QStringRef cannot guarantee
1551  parseNumbersArray(str, arg);
1552  *const_cast<QChar *>(end) = endc;
1553  if (pathElem == QLatin1Char('z') || pathElem == QLatin1Char('Z'))
1554  arg.append(0);//dummy
1555  const qreal *num = arg.constData();
1556  int count = arg.count();
1557  while (count > 0) {
1558  qreal offsetX = x; // correction offsets
1559  qreal offsetY = y; // for relative commands
1560  switch (pathElem.unicode()) {
1561  case 'm': {
1562  if (count < 2) {
1563  num++;
1564  count--;
1565  break;
1566  }
1567  x = x0 = num[0] + offsetX;
1568  y = y0 = num[1] + offsetY;
1569  num += 2;
1570  count -= 2;
1571  path.moveTo(x0, y0);
1572 
1573  // As per 1.2 spec 8.3.2 The "moveto" commands
1574  // If a 'moveto' is followed by multiple pairs of coordinates without explicit commands,
1575  // the subsequent pairs shall be treated as implicit 'lineto' commands.
1576  pathElem = QLatin1Char('l');
1577  }
1578  break;
1579  case 'M': {
1580  if (count < 2) {
1581  num++;
1582  count--;
1583  break;
1584  }
1585  x = x0 = num[0];
1586  y = y0 = num[1];
1587  num += 2;
1588  count -= 2;
1589  path.moveTo(x0, y0);
1590 
1591  // As per 1.2 spec 8.3.2 The "moveto" commands
1592  // If a 'moveto' is followed by multiple pairs of coordinates without explicit commands,
1593  // the subsequent pairs shall be treated as implicit 'lineto' commands.
1594  pathElem = QLatin1Char('L');
1595  }
1596  break;
1597  case 'z':
1598  case 'Z': {
1599  x = x0;
1600  y = y0;
1601  count--; // skip dummy
1602  num++;
1603  path.closeSubpath();
1604  }
1605  break;
1606  case 'l': {
1607  if (count < 2) {
1608  num++;
1609  count--;
1610  break;
1611  }
1612  x = num[0] + offsetX;
1613  y = num[1] + offsetY;
1614  num += 2;
1615  count -= 2;
1616  path.lineTo(x, y);
1617 
1618  }
1619  break;
1620  case 'L': {
1621  if (count < 2) {
1622  num++;
1623  count--;
1624  break;
1625  }
1626  x = num[0];
1627  y = num[1];
1628  num += 2;
1629  count -= 2;
1630  path.lineTo(x, y);
1631  }
1632  break;
1633  case 'h': {
1634  x = num[0] + offsetX;
1635  num++;
1636  count--;
1637  path.lineTo(x, y);
1638  }
1639  break;
1640  case 'H': {
1641  x = num[0];
1642  num++;
1643  count--;
1644  path.lineTo(x, y);
1645  }
1646  break;
1647  case 'v': {
1648  y = num[0] + offsetY;
1649  num++;
1650  count--;
1651  path.lineTo(x, y);
1652  }
1653  break;
1654  case 'V': {
1655  y = num[0];
1656  num++;
1657  count--;
1658  path.lineTo(x, y);
1659  }
1660  break;
1661  case 'c': {
1662  if (count < 6) {
1663  num += count;
1664  count = 0;
1665  break;
1666  }
1667  QPointF c1(num[0] + offsetX, num[1] + offsetY);
1668  QPointF c2(num[2] + offsetX, num[3] + offsetY);
1669  QPointF e(num[4] + offsetX, num[5] + offsetY);
1670  num += 6;
1671  count -= 6;
1672  path.cubicTo(c1, c2, e);
1673  ctrlPt = c2;
1674  x = e.x();
1675  y = e.y();
1676  break;
1677  }
1678  case 'C': {
1679  if (count < 6) {
1680  num += count;
1681  count = 0;
1682  break;
1683  }
1684  QPointF c1(num[0], num[1]);
1685  QPointF c2(num[2], num[3]);
1686  QPointF e(num[4], num[5]);
1687  num += 6;
1688  count -= 6;
1689  path.cubicTo(c1, c2, e);
1690  ctrlPt = c2;
1691  x = e.x();
1692  y = e.y();
1693  break;
1694  }
1695  case 's': {
1696  if (count < 4) {
1697  num += count;
1698  count = 0;
1699  break;
1700  }
1701  QPointF c1;
1702  if (lastMode == 'c' || lastMode == 'C' ||
1703  lastMode == 's' || lastMode == 'S')
1704  c1 = QPointF(2*x-ctrlPt.x(), 2*y-ctrlPt.y());
1705  else
1706  c1 = QPointF(x, y);
1707  QPointF c2(num[0] + offsetX, num[1] + offsetY);
1708  QPointF e(num[2] + offsetX, num[3] + offsetY);
1709  num += 4;
1710  count -= 4;
1711  path.cubicTo(c1, c2, e);
1712  ctrlPt = c2;
1713  x = e.x();
1714  y = e.y();
1715  break;
1716  }
1717  case 'S': {
1718  if (count < 4) {
1719  num += count;
1720  count = 0;
1721  break;
1722  }
1723  QPointF c1;
1724  if (lastMode == 'c' || lastMode == 'C' ||
1725  lastMode == 's' || lastMode == 'S')
1726  c1 = QPointF(2*x-ctrlPt.x(), 2*y-ctrlPt.y());
1727  else
1728  c1 = QPointF(x, y);
1729  QPointF c2(num[0], num[1]);
1730  QPointF e(num[2], num[3]);
1731  num += 4;
1732  count -= 4;
1733  path.cubicTo(c1, c2, e);
1734  ctrlPt = c2;
1735  x = e.x();
1736  y = e.y();
1737  break;
1738  }
1739  case 'q': {
1740  if (count < 4) {
1741  num += count;
1742  count = 0;
1743  break;
1744  }
1745  QPointF c(num[0] + offsetX, num[1] + offsetY);
1746  QPointF e(num[2] + offsetX, num[3] + offsetY);
1747  num += 4;
1748  count -= 4;
1749  path.quadTo(c, e);
1750  ctrlPt = c;
1751  x = e.x();
1752  y = e.y();
1753  break;
1754  }
1755  case 'Q': {
1756  if (count < 4) {
1757  num += count;
1758  count = 0;
1759  break;
1760  }
1761  QPointF c(num[0], num[1]);
1762  QPointF e(num[2], num[3]);
1763  num += 4;
1764  count -= 4;
1765  path.quadTo(c, e);
1766  ctrlPt = c;
1767  x = e.x();
1768  y = e.y();
1769  break;
1770  }
1771  case 't': {
1772  if (count < 2) {
1773  num += count;
1774  count = 0;
1775  break;
1776  }
1777  QPointF e(num[0] + offsetX, num[1] + offsetY);
1778  num += 2;
1779  count -= 2;
1780  QPointF c;
1781  if (lastMode == 'q' || lastMode == 'Q' ||
1782  lastMode == 't' || lastMode == 'T')
1783  c = QPointF(2*x-ctrlPt.x(), 2*y-ctrlPt.y());
1784  else
1785  c = QPointF(x, y);
1786  path.quadTo(c, e);
1787  ctrlPt = c;
1788  x = e.x();
1789  y = e.y();
1790  break;
1791  }
1792  case 'T': {
1793  if (count < 2) {
1794  num += count;
1795  count = 0;
1796  break;
1797  }
1798  QPointF e(num[0], num[1]);
1799  num += 2;
1800  count -= 2;
1801  QPointF c;
1802  if (lastMode == 'q' || lastMode == 'Q' ||
1803  lastMode == 't' || lastMode == 'T')
1804  c = QPointF(2*x-ctrlPt.x(), 2*y-ctrlPt.y());
1805  else
1806  c = QPointF(x, y);
1807  path.quadTo(c, e);
1808  ctrlPt = c;
1809  x = e.x();
1810  y = e.y();
1811  break;
1812  }
1813  case 'a': {
1814  if (count < 7) {
1815  num += count;
1816  count = 0;
1817  break;
1818  }
1819  qreal rx = (*num++);
1820  qreal ry = (*num++);
1821  qreal xAxisRotation = (*num++);
1822  qreal largeArcFlag = (*num++);
1823  qreal sweepFlag = (*num++);
1824  qreal ex = (*num++) + offsetX;
1825  qreal ey = (*num++) + offsetY;
1826  count -= 7;
1827  qreal curx = x;
1828  qreal cury = y;
1829  pathArc(path, rx, ry, xAxisRotation, int(largeArcFlag),
1830  int(sweepFlag), ex, ey, curx, cury);
1831 
1832  x = ex;
1833  y = ey;
1834  }
1835  break;
1836  case 'A': {
1837  if (count < 7) {
1838  num += count;
1839  count = 0;
1840  break;
1841  }
1842  qreal rx = (*num++);
1843  qreal ry = (*num++);
1844  qreal xAxisRotation = (*num++);
1845  qreal largeArcFlag = (*num++);
1846  qreal sweepFlag = (*num++);
1847  qreal ex = (*num++);
1848  qreal ey = (*num++);
1849  count -= 7;
1850  qreal curx = x;
1851  qreal cury = y;
1852  pathArc(path, rx, ry, xAxisRotation, int(largeArcFlag),
1853  int(sweepFlag), ex, ey, curx, cury);
1854 
1855  x = ex;
1856  y = ey;
1857  }
1858  break;
1859  default:
1860  return false;
1861  }
1862  lastMode = pathElem.toLatin1();
1863  }
1864  }
1865  return true;
1866 }
1867 
1868 static bool parseStyle(QSvgNode *node,
1869  const QXmlStreamAttributes &attributes,
1870  QSvgHandler *);
1871 
1872 static bool parseStyle(QSvgNode *node,
1873  const QSvgAttributes &attributes,
1874  QSvgHandler *);
1875 
1877  QXmlStreamAttributes &attributes)
1878 {
1879  for (int i = 0; i < declarations.count(); ++i) {
1880  const QCss::Declaration &decl = declarations.at(i);
1881  if (decl.d->property.isEmpty())
1882  continue;
1883  QCss::Value val = decl.d->values.first();
1884  QString valueStr;
1885  if (decl.d->values.count() != 1) {
1886  for (int i=0; i<decl.d->values.count(); ++i) {
1887  const QString &value = decl.d->values[i].toString();
1888  if (value.isEmpty())
1889  valueStr += QLatin1Char(',');
1890  else
1891  valueStr += value;
1892  }
1893  } else {
1894  valueStr = val.toString();
1895  }
1896  if (val.type == QCss::Value::Uri) {
1897  valueStr.prepend(QLatin1String("url("));
1898  valueStr.append(QLatin1Char(')'));
1899  } else if (val.type == QCss::Value::Function) {
1900  QStringList lst = val.variant.toStringList();
1901  valueStr.append(lst.at(0));
1902  valueStr.append(QLatin1Char('('));
1903  for (int i = 1; i < lst.count(); ++i) {
1904  valueStr.append(lst.at(i));
1905  if ((i +1) < lst.count())
1906  valueStr.append(QLatin1Char(','));
1907  }
1908  valueStr.append(QLatin1Char(')'));
1909  } else if (val.type == QCss::Value::KnownIdentifier) {
1910  switch (val.variant.toInt()) {
1911  case QCss::Value_None:
1912  valueStr = QLatin1String("none");
1913  break;
1914  default:
1915  break;
1916  }
1917  }
1918 
1919  attributes.append(QString(), decl.d->property, valueStr);
1920  }
1921 }
1922 
1924 {
1925  // preprocess (for unicode escapes), tokenize and remove comments
1926  m_cssParser.init(css);
1927  QString key;
1928 
1929  attributes->reserve(10);
1930 
1931  while (m_cssParser.hasNext()) {
1932  m_cssParser.skipSpace();
1933 
1934  if (!m_cssParser.hasNext())
1935  break;
1936  m_cssParser.next();
1937 
1938  QStringRef name;
1939  if (m_cssParser.hasEscapeSequences) {
1940  key = m_cssParser.lexem();
1941  name = QStringRef(&key, 0, key.length());
1942  } else {
1943  const QCss::Symbol &sym = m_cssParser.symbol();
1944  name = QStringRef(&sym.text, sym.start, sym.len);
1945  }
1946 
1947  m_cssParser.skipSpace();
1948  if (!m_cssParser.test(QCss::COLON))
1949  break;
1950 
1951  m_cssParser.skipSpace();
1952  if (!m_cssParser.hasNext())
1953  break;
1954 
1955  QSvgCssAttribute attribute;
1956  attribute.name = QXmlStreamStringRef(name);
1957 
1958  const int firstSymbol = m_cssParser.index;
1959  int symbolCount = 0;
1960  do {
1961  m_cssParser.next();
1962  ++symbolCount;
1963  } while (m_cssParser.hasNext() && !m_cssParser.test(QCss::SEMICOLON));
1964 
1965  bool canExtractValueByRef = !m_cssParser.hasEscapeSequences;
1966  if (canExtractValueByRef) {
1967  int len = m_cssParser.symbols.at(firstSymbol).len;
1968  for (int i = firstSymbol + 1; i < firstSymbol + symbolCount; ++i) {
1969  len += m_cssParser.symbols.at(i).len;
1970 
1971  if (m_cssParser.symbols.at(i - 1).start + m_cssParser.symbols.at(i - 1).len
1972  != m_cssParser.symbols.at(i).start) {
1973  canExtractValueByRef = false;
1974  break;
1975  }
1976  }
1977  if (canExtractValueByRef) {
1978  const QCss::Symbol &sym = m_cssParser.symbols.at(firstSymbol);
1979  attribute.value = QXmlStreamStringRef(QStringRef(&sym.text, sym.start, len));
1980  }
1981  }
1982  if (!canExtractValueByRef) {
1983  QString value;
1984  for (int i = firstSymbol; i < m_cssParser.index - 1; ++i)
1985  value += m_cssParser.symbols.at(i).lexem();
1986  attribute.value = QXmlStreamStringRef(QStringRef(&value, 0, value.length()));
1987  }
1988 
1989  attributes->append(attribute);
1990 
1991  m_cssParser.skipSpace();
1992  }
1993 }
1994 
1995 static void cssStyleLookup(QSvgNode *node,
1997  QSvgStyleSelector *selector)
1998 {
2000  cssNode.ptr = node;
2001  QVector<QCss::Declaration> decls = selector->declarationsForNode(cssNode);
2002 
2003  QXmlStreamAttributes attributes;
2004  parseCSStoXMLAttrs(decls, attributes);
2005  parseStyle(node, attributes, handler);
2006 }
2007 
2008 static inline QStringList stringToList(const QString &str)
2009 {
2011  return lst;
2012 }
2013 
2014 static bool parseCoreNode(QSvgNode *node,
2015  const QXmlStreamAttributes &attributes)
2016 {
2017  QStringList features;
2019  QStringList languages;
2020  QStringList formats;
2021  QStringList fonts;
2022  QString xmlClassStr;
2023 
2024  for (int i = 0; i < attributes.count(); ++i) {
2025  const QXmlStreamAttribute &attribute = attributes.at(i);
2026  QStringRef name = attribute.qualifiedName();
2027  if (name.isEmpty())
2028  continue;
2029  QStringRef value = attribute.value();
2030  switch (name.at(0).unicode()) {
2031  case 'c':
2032  if (name == QLatin1String("class"))
2033  xmlClassStr = value.toString();
2034  break;
2035  case 'r':
2036  if (name == QLatin1String("requiredFeatures"))
2037  features = stringToList(value.toString());
2038  else if (name == QLatin1String("requiredExtensions"))
2039  extensions = stringToList(value.toString());
2040  else if (name == QLatin1String("requiredFormats"))
2041  formats = stringToList(value.toString());
2042  else if (name == QLatin1String("requiredFonts"))
2043  fonts = stringToList(value.toString());
2044  break;
2045  case 's':
2046  if (name == QLatin1String("systemLanguage"))
2047  languages = stringToList(value.toString());
2048  break;
2049  default:
2050  break;
2051  }
2052  }
2053 
2054  node->setRequiredFeatures(features);
2055  node->setRequiredExtensions(extensions);
2056  node->setRequiredLanguages(languages);
2057  node->setRequiredFormats(formats);
2058  node->setRequiredFonts(fonts);
2059  node->setNodeId(someId(attributes));
2060  node->setXmlClass(xmlClassStr);
2061 
2062  return true;
2063 }
2064 
2065 static void parseOpacity(QSvgNode *node,
2066  const QSvgAttributes &attributes,
2067  QSvgHandler *)
2068 {
2069  if (attributes.opacity.isEmpty())
2070  return;
2071 
2072  const QString value = attributes.opacity.toString().trimmed();
2073 
2074  bool ok = false;
2075  qreal op = value.toDouble(&ok);
2076 
2077  if (ok) {
2078  QSvgOpacityStyle *opacity = new QSvgOpacityStyle(qBound(qreal(0.0), op, qreal(1.0)));
2079  node->appendStyleProperty(opacity, attributes.id);
2080  }
2081 }
2082 
2084 {
2085 #define NOOP qDebug()<<"Operation: "<<op<<" is not implemented"
2086  if (op == QLatin1String("clear")) {
2088  } else if (op == QLatin1String("src")) {
2090  } else if (op == QLatin1String("dst")) {
2092  } else if (op == QLatin1String("src-over")) {
2094  } else if (op == QLatin1String("dst-over")) {
2096  } else if (op == QLatin1String("src-in")) {
2098  } else if (op == QLatin1String("dst-in")) {
2100  } else if (op == QLatin1String("src-out")) {
2102  } else if (op == QLatin1String("dst-out")) {
2104  } else if (op == QLatin1String("src-atop")) {
2106  } else if (op == QLatin1String("dst-atop")) {
2108  } else if (op == QLatin1String("xor")) {
2110  } else if (op == QLatin1String("plus")) {
2112  } else if (op == QLatin1String("multiply")) {
2114  } else if (op == QLatin1String("screen")) {
2116  } else if (op == QLatin1String("overlay")) {
2118  } else if (op == QLatin1String("darken")) {
2120  } else if (op == QLatin1String("lighten")) {
2122  } else if (op == QLatin1String("color-dodge")) {
2124  } else if (op == QLatin1String("color-burn")) {
2126  } else if (op == QLatin1String("hard-light")) {
2128  } else if (op == QLatin1String("soft-light")) {
2130  } else if (op == QLatin1String("difference")) {
2132  } else if (op == QLatin1String("exclusion")) {
2134  } else {
2135  NOOP;
2136  }
2137 
2139 }
2140 
2141 static void parseCompOp(QSvgNode *node,
2142  const QSvgAttributes &attributes,
2143  QSvgHandler *)
2144 {
2145  if (attributes.compOp.isEmpty())
2146  return;
2147  QString value = attributes.compOp.toString().trimmed();
2148 
2149  if (!value.isEmpty()) {
2151  node->appendStyleProperty(compop, attributes.id);
2152  }
2153 }
2154 
2156 {
2157  if (str == QLatin1String("inline")) {
2158  return QSvgNode::InlineMode;
2159  } else if (str == QLatin1String("block")) {
2160  return QSvgNode::BlockMode;
2161  } else if (str == QLatin1String("list-item")) {
2162  return QSvgNode::ListItemMode;
2163  } else if (str == QLatin1String("run-in")) {
2164  return QSvgNode::RunInMode;
2165  } else if (str == QLatin1String("compact")) {
2166  return QSvgNode::CompactMode;
2167  } else if (str == QLatin1String("marker")) {
2168  return QSvgNode::MarkerMode;
2169  } else if (str == QLatin1String("table")) {
2170  return QSvgNode::TableMode;
2171  } else if (str == QLatin1String("inline-table")) {
2173  } else if (str == QLatin1String("table-row")) {
2175  } else if (str == QLatin1String("table-header-group")) {
2177  } else if (str == QLatin1String("table-footer-group")) {
2179  } else if (str == QLatin1String("table-row")) {
2180  return QSvgNode::TableRowMode;
2181  } else if (str == QLatin1String("table-column-group")) {
2183  } else if (str == QLatin1String("table-column")) {
2185  } else if (str == QLatin1String("table-cell")) {
2186  return QSvgNode::TableCellMode;
2187  } else if (str == QLatin1String("table-caption")) {
2189  } else if (str == QLatin1String("none")) {
2190  return QSvgNode::NoneMode;
2191  } else if (str == QT_INHERIT) {
2192  return QSvgNode::InheritMode;
2193  }
2194  return QSvgNode::BlockMode;
2195 }
2196 
2197 static void parseOthers(QSvgNode *node,
2198  const QSvgAttributes &attributes,
2199  QSvgHandler *)
2200 {
2201  if (attributes.display.isEmpty())
2202  return;
2203  QString displayStr = attributes.display.toString().trimmed();
2204 
2205  if (!displayStr.isEmpty()) {
2206  node->setDisplayMode(displayStringToEnum(displayStr));
2207  }
2208 }
2209 
2210 static bool parseStyle(QSvgNode *node,
2211  const QSvgAttributes &attributes,
2213 {
2214  parseColor(node, attributes, handler);
2215  parseBrush(node, attributes, handler);
2216  parsePen(node, attributes, handler);
2217  parseFont(node, attributes, handler);
2218  parseTransform(node, attributes, handler);
2219  parseVisibility(node, attributes, handler);
2220  parseOpacity(node, attributes, handler);
2221  parseCompOp(node, attributes, handler);
2222  parseOthers(node, attributes, handler);
2223 #if 0
2224  value = attributes.value("audio-level");
2225 
2226  value = attributes.value("color-rendering");
2227 
2228  value = attributes.value("display-align");
2229 
2230  value = attributes.value("image-rendering");
2231 
2232  value = attributes.value("line-increment");
2233 
2234  value = attributes.value("pointer-events");
2235 
2236  value = attributes.value("shape-rendering");
2237 
2238  value = attributes.value("solid-color");
2239 
2240  value = attributes.value("solid-opacity");
2241 
2242  value = attributes.value("text-rendering");
2243 
2244  value = attributes.value("vector-effect");
2245 
2246  value = attributes.value("viewport-fill");
2247 
2248  value = attributes.value("viewport-fill-opacity");
2249 #endif
2250  return true;
2251 }
2252 
2253 static bool parseStyle(QSvgNode *node,
2254  const QXmlStreamAttributes &attrs,
2256 {
2257  return parseStyle(node, QSvgAttributes(attrs, handler), handler);
2258 }
2259 
2260 static bool parseAnchorNode(QSvgNode *parent,
2261  const QXmlStreamAttributes &attributes,
2262  QSvgHandler *)
2263 {
2264  Q_UNUSED(parent); Q_UNUSED(attributes);
2265  return true;
2266 }
2267 
2268 static bool parseAnimateNode(QSvgNode *parent,
2269  const QXmlStreamAttributes &attributes,
2270  QSvgHandler *)
2271 {
2272  Q_UNUSED(parent); Q_UNUSED(attributes);
2273  return true;
2274 }
2275 
2276 static bool parseAnimateColorNode(QSvgNode *parent,
2277  const QXmlStreamAttributes &attributes,
2279 {
2280  QString typeStr = attributes.value(QLatin1String("type")).toString();
2281  QStringRef fromStr = attributes.value(QLatin1String("from"));
2282  QStringRef toStr = attributes.value(QLatin1String("to"));
2283  QString valuesStr = attributes.value(QLatin1String("values")).toString();
2284  QString beginStr = attributes.value(QLatin1String("begin")).toString();
2285  QString durStr = attributes.value(QLatin1String("dur")).toString();
2286  QString targetStr = attributes.value(QLatin1String("attributeName")).toString();
2287  QString repeatStr = attributes.value(QLatin1String("repeatCount")).toString();
2288  QString fillStr = attributes.value(QLatin1String("fill")).toString();
2289 
2290  QList<QColor> colors;
2291  if (valuesStr.isEmpty()) {
2292  QColor startColor, endColor;
2293  resolveColor(fromStr, startColor, handler);
2294  resolveColor(toStr, endColor, handler);
2295  colors.append(startColor);
2296  colors.append(endColor);
2297  } else {
2298  QStringList str = valuesStr.split(QLatin1Char(';'));
2300  for (itr = str.constBegin(); itr != str.constEnd(); ++itr) {
2301  QColor color;
2302  QString str = *itr;
2303  resolveColor(QStringRef(&str), color, handler);
2304  colors.append(color);
2305  }
2306  }
2307 
2308  int ms = 1000;
2309  beginStr = beginStr.trimmed();
2310  if (beginStr.endsWith(QLatin1String("ms"))) {
2311  beginStr.chop(2);
2312  ms = 1;
2313  } else if (beginStr.endsWith(QLatin1String("s"))) {
2314  beginStr.chop(1);
2315  }
2316  durStr = durStr.trimmed();
2317  if (durStr.endsWith(QLatin1String("ms"))) {
2318  durStr.chop(2);
2319  ms = 1;
2320  } else if (durStr.endsWith(QLatin1String("s"))) {
2321  durStr.chop(1);
2322  }
2323  int begin = static_cast<int>(toDouble(beginStr) * ms);
2324  int end = static_cast<int>((toDouble(durStr) + begin) * ms);
2325 
2326  QSvgAnimateColor *anim = new QSvgAnimateColor(begin, end, 0);
2327  anim->setArgs((targetStr == QLatin1String("fill")), colors);
2328  anim->setFreeze(fillStr == QLatin1String("freeze"));
2329  anim->setRepeatCount(
2330  (repeatStr == QLatin1String("indefinite")) ? -1 :
2331  (repeatStr == QLatin1String("")) ? 1 : toDouble(repeatStr));
2332 
2333  parent->appendStyleProperty(anim, someId(attributes));
2334  parent->document()->setAnimated(true);
2335  handler->setAnimPeriod(begin, end);
2336  return true;
2337 }
2338 
2339 static bool parseAimateMotionNode(QSvgNode *parent,
2340  const QXmlStreamAttributes &attributes,
2341  QSvgHandler *)
2342 {
2343  Q_UNUSED(parent); Q_UNUSED(attributes);
2344  return true;
2345 }
2346 
2348 {
2349  QVector<qreal> list = parseNumbersList(s);
2350  values << list;
2351  for (int i = 3 - list.size(); i > 0; --i)
2352  values.append(0.0);
2353 }
2354 
2356  const QXmlStreamAttributes &attributes,
2358 {
2359  QString typeStr = attributes.value(QLatin1String("type")).toString();
2360  QString values = attributes.value(QLatin1String("values")).toString();
2361  QString beginStr = attributes.value(QLatin1String("begin")).toString();
2362  QString durStr = attributes.value(QLatin1String("dur")).toString();
2363  QString targetStr = attributes.value(QLatin1String("attributeName")).toString();
2364  QString repeatStr = attributes.value(QLatin1String("repeatCount")).toString();
2365  QString fillStr = attributes.value(QLatin1String("fill")).toString();
2366  QString fromStr = attributes.value(QLatin1String("from")).toString();
2367  QString toStr = attributes.value(QLatin1String("to")).toString();
2368  QString byStr = attributes.value(QLatin1String("by")).toString();
2369  QString addtv = attributes.value(QLatin1String("additive")).toString();
2370 
2372  if (addtv == QLatin1String("sum"))
2373  additive = QSvgAnimateTransform::Sum;
2374 
2375  QVector<qreal> vals;
2376  if (values.isEmpty()) {
2377  const QChar *s;
2378  if (fromStr.isEmpty()) {
2379  if (!byStr.isEmpty()) {
2380  // By-animation.
2381  additive = QSvgAnimateTransform::Sum;
2382  vals.append(0.0);
2383  vals.append(0.0);
2384  vals.append(0.0);
2385  parseNumberTriplet(vals, s = byStr.constData());
2386  } else {
2387  // To-animation not defined.
2388  return false;
2389  }
2390  } else {
2391  if (!toStr.isEmpty()) {
2392  // From-to-animation.
2393  parseNumberTriplet(vals, s = fromStr.constData());
2394  parseNumberTriplet(vals, s = toStr.constData());
2395  } else if (!byStr.isEmpty()) {
2396  // From-by-animation.
2397  parseNumberTriplet(vals, s = fromStr.constData());
2398  parseNumberTriplet(vals, s = byStr.constData());
2399  for (int i = vals.size() - 3; i < vals.size(); ++i)
2400  vals[i] += vals[i - 3];
2401  } else {
2402  return false;
2403  }
2404  }
2405  } else {
2406  const QChar *s = values.constData();
2407  while (s && *s != QLatin1Char(0)) {
2408  parseNumberTriplet(vals, s);
2409  if (*s == QLatin1Char(0))
2410  break;
2411  ++s;
2412  }
2413  }
2414 
2415  int ms = 1000;
2416  beginStr = beginStr.trimmed();
2417  if (beginStr.endsWith(QLatin1String("ms"))) {
2418  beginStr.chop(2);
2419  ms = 1;
2420  } else if (beginStr.endsWith(QLatin1String("s"))) {
2421  beginStr.chop(1);
2422  }
2423  int begin = static_cast<int>(toDouble(beginStr) * ms);
2424  durStr = durStr.trimmed();
2425  if (durStr.endsWith(QLatin1String("ms"))) {
2426  durStr.chop(2);
2427  ms = 1;
2428  } else if (durStr.endsWith(QLatin1String("s"))) {
2429  durStr.chop(1);
2430  ms = 1000;
2431  }
2432  int end = static_cast<int>(toDouble(durStr)*ms) + begin;
2433 
2435  if (typeStr == QLatin1String("translate")) {
2437  } else if (typeStr == QLatin1String("scale")) {
2439  } else if (typeStr == QLatin1String("rotate")) {
2441  } else if (typeStr == QLatin1String("skewX")) {
2443  } else if (typeStr == QLatin1String("skewY")) {
2445  } else {
2446  return false;
2447  }
2448 
2449  QSvgAnimateTransform *anim = new QSvgAnimateTransform(begin, end, 0);
2450  anim->setArgs(type, additive, vals);
2451  anim->setFreeze(fillStr == QLatin1String("freeze"));
2452  anim->setRepeatCount(
2453  (repeatStr == QLatin1String("indefinite"))? -1 :
2454  (repeatStr == QLatin1String(""))? 1 : toDouble(repeatStr));
2455 
2456  parent->appendStyleProperty(anim, someId(attributes));
2457  parent->document()->setAnimated(true);
2458  handler->setAnimPeriod(begin, end);
2459  return true;
2460 }
2461 
2463  const QXmlStreamAttributes &attributes,
2464  QSvgHandler *)
2465 {
2466  Q_UNUSED(parent); Q_UNUSED(attributes);
2467  return 0;
2468 }
2469 
2470 static bool parseAudioNode(QSvgNode *parent,
2471  const QXmlStreamAttributes &attributes,
2472  QSvgHandler *)
2473 {
2474  Q_UNUSED(parent); Q_UNUSED(attributes);
2475  return true;
2476 }
2477 
2479  const QXmlStreamAttributes &attributes,
2480  QSvgHandler *)
2481 {
2482  QString cx = attributes.value(QLatin1String("cx")).toString();
2483  QString cy = attributes.value(QLatin1String("cy")).toString();
2484  QString r = attributes.value(QLatin1String("r")).toString();
2485  qreal ncx = toDouble(cx);
2486  qreal ncy = toDouble(cy);
2487  qreal nr = toDouble(r);
2488 
2489  QRectF rect(ncx-nr, ncy-nr, nr*2, nr*2);
2490  QSvgNode *circle = new QSvgCircle(parent, rect);
2491  return circle;
2492 }
2493 
2495  const QXmlStreamAttributes &attributes,
2496  QSvgHandler *)
2497 {
2498  Q_UNUSED(attributes);
2499  QSvgDefs *defs = new QSvgDefs(parent);
2500  return defs;
2501 }
2502 
2503 static bool parseDescNode(QSvgNode *parent,
2504  const QXmlStreamAttributes &attributes,
2505  QSvgHandler *)
2506 {
2507  Q_UNUSED(parent); Q_UNUSED(attributes);
2508  return true;
2509 }
2510 
2511 static bool parseDiscardNode(QSvgNode *parent,
2512  const QXmlStreamAttributes &attributes,
2513  QSvgHandler *)
2514 {
2515  Q_UNUSED(parent); Q_UNUSED(attributes);
2516  return true;
2517 }
2518 
2520  const QXmlStreamAttributes &attributes,
2521  QSvgHandler *)
2522 {
2523  QString cx = attributes.value(QLatin1String("cx")).toString();
2524  QString cy = attributes.value(QLatin1String("cy")).toString();
2525  QString rx = attributes.value(QLatin1String("rx")).toString();
2526  QString ry = attributes.value(QLatin1String("ry")).toString();
2527  qreal ncx = toDouble(cx);
2528  qreal ncy = toDouble(cy);
2529  qreal nrx = toDouble(rx);
2530  qreal nry = toDouble(ry);
2531 
2532  QRectF rect(ncx-nrx, ncy-nry, nrx*2, nry*2);
2533  QSvgNode *ellipse = new QSvgEllipse(parent, rect);
2534  return ellipse;
2535 }
2536 
2538  const QXmlStreamAttributes &attributes,
2539  QSvgHandler *)
2540 {
2541  QString hax = attributes.value(QLatin1String("horiz-adv-x")).toString();
2542  QString myId = someId(attributes);
2543 
2544  qreal horizAdvX = toDouble(hax);
2545 
2546  while (parent && parent->type() != QSvgNode::DOC) {
2547  parent = parent->parent();
2548  }
2549 
2550  if (parent) {
2551  QSvgTinyDocument *doc = static_cast<QSvgTinyDocument*>(parent);
2552  QSvgFont *font = new QSvgFont(horizAdvX);
2553  font->setFamilyName(myId);
2554  if (!font->familyName().isEmpty()) {
2555  if (!doc->svgFont(font->familyName()))
2556  doc->addSvgFont(font);
2557  }
2558  return new QSvgFontStyle(font, doc);
2559  }
2560  return 0;
2561 }
2562 
2564  const QXmlStreamAttributes &attributes,
2565  QSvgHandler *)
2566 {
2567  if (parent->type() != QSvgStyleProperty::FONT) {
2568  return false;
2569  }
2570 
2571  QSvgFontStyle *style = static_cast<QSvgFontStyle*>(parent);
2572  QSvgFont *font = style->svgFont();
2573  QString name = attributes.value(QLatin1String("font-family")).toString();
2574  QString unitsPerEmStr = attributes.value(QLatin1String("units-per-em")).toString();
2575 
2576  qreal unitsPerEm = toDouble(unitsPerEmStr);
2577  if (!unitsPerEm)
2578  unitsPerEm = 1000;
2579 
2580  if (!name.isEmpty())
2581  font->setFamilyName(name);
2582  font->setUnitsPerEm(unitsPerEm);
2583 
2584  if (!font->familyName().isEmpty())
2585  if (!style->doc()->svgFont(font->familyName()))
2586  style->doc()->addSvgFont(font);
2587 
2588  return true;
2589 }
2590 
2592  const QXmlStreamAttributes &attributes,
2593  QSvgHandler *)
2594 {
2595  if (parent->type() != QSvgStyleProperty::FONT) {
2596  return false;
2597  }
2598 
2599  QSvgFontStyle *style = static_cast<QSvgFontStyle*>(parent);
2600  QSvgFont *font = style->svgFont();
2601  QString name = attributes.value(QLatin1String("name")).toString();
2602 
2603  if (!name.isEmpty())
2604  font->setFamilyName(name);
2605 
2606  if (!font->familyName().isEmpty())
2607  if (!style->doc()->svgFont(font->familyName()))
2608  style->doc()->addSvgFont(font);
2609 
2610  return true;
2611 }
2612 
2614  const QXmlStreamAttributes &attributes,
2615  QSvgHandler *)
2616 {
2617  Q_UNUSED(parent); Q_UNUSED(attributes);
2618  return true;
2619 }
2620 
2622  const QXmlStreamAttributes &attributes,
2623  QSvgHandler *)
2624 {
2625  Q_UNUSED(parent); Q_UNUSED(attributes);
2626  return true;
2627 }
2628 
2629 static bool parseForeignObjectNode(QSvgNode *parent,
2630  const QXmlStreamAttributes &attributes,
2631  QSvgHandler *)
2632 {
2633  Q_UNUSED(parent); Q_UNUSED(attributes);
2634  return true;
2635 }
2636 
2638  const QXmlStreamAttributes &attributes,
2639  QSvgHandler *)
2640 {
2641  Q_UNUSED(attributes);
2642  QSvgG *node = new QSvgG(parent);
2643  return node;
2644 }
2645 
2646 static bool parseGlyphNode(QSvgStyleProperty *parent,
2647  const QXmlStreamAttributes &attributes,
2648  QSvgHandler *)
2649 {
2650  if (parent->type() != QSvgStyleProperty::FONT) {
2651  return false;
2652  }
2653 
2654  QSvgFontStyle *style = static_cast<QSvgFontStyle*>(parent);
2655  QSvgFont *font = style->svgFont();
2656  createSvgGlyph(font, attributes);
2657  return true;
2658 }
2659 
2660 static bool parseHandlerNode(QSvgNode *parent,
2661  const QXmlStreamAttributes &attributes,
2662  QSvgHandler *)
2663 {
2664  Q_UNUSED(parent); Q_UNUSED(attributes);
2665  return true;
2666 }
2667 
2668 static bool parseHkernNode(QSvgNode *parent,
2669  const QXmlStreamAttributes &attributes,
2670  QSvgHandler *)
2671 {
2672  Q_UNUSED(parent); Q_UNUSED(attributes);
2673  return true;
2674 }
2675 
2677  const QXmlStreamAttributes &attributes,
2679 {
2680  QString x = attributes.value(QLatin1String("x")).toString();
2681  QString y = attributes.value(QLatin1String("y")).toString();
2682  QString width = attributes.value(QLatin1String("width")).toString();
2683  QString height = attributes.value(QLatin1String("height")).toString();
2684  QString filename = attributes.value(QLatin1String("xlink:href")).toString();
2685  qreal nx = toDouble(x);
2686  qreal ny = toDouble(y);
2688  qreal nwidth = parseLength(width, type, handler);
2689  nwidth = convertToPixels(nwidth, true, type);
2690 
2691  qreal nheight = parseLength(height, type, handler);
2692  nheight = convertToPixels(nheight, false, type);
2693 
2694 
2695  filename = filename.trimmed();
2696  QImage image;
2697  if (filename.startsWith(QLatin1String("data"))) {
2698  int idx = filename.lastIndexOf(QLatin1String("base64,"));
2699  if (idx != -1) {
2700  idx += 7;
2701  QString dataStr = filename.mid(idx);
2702  QByteArray data = QByteArray::fromBase64(dataStr.toAscii());
2703  image = QImage::fromData(data);
2704  } else {
2705  qDebug()<<"QSvgHandler::createImageNode: Unrecognized inline image format!";
2706  }
2707  } else
2708  image = QImage(filename);
2709 
2710  if (image.isNull()) {
2711  qDebug()<<"couldn't create image from "<<filename;
2712  return 0;
2713  }
2714 
2715  if (image.format() == QImage::Format_ARGB32)
2717 
2718  QSvgNode *img = new QSvgImage(parent,
2719  image,
2720  QRect(int(nx),
2721  int(ny),
2722  int(nwidth),
2723  int(nheight)));
2724  return img;
2725 }
2726 
2728  const QXmlStreamAttributes &attributes,
2729  QSvgHandler *)
2730 {
2731  QString x1 = attributes.value(QLatin1String("x1")).toString();
2732  QString y1 = attributes.value(QLatin1String("y1")).toString();
2733  QString x2 = attributes.value(QLatin1String("x2")).toString();
2734  QString y2 = attributes.value(QLatin1String("y2")).toString();
2735  qreal nx1 = toDouble(x1);
2736  qreal ny1 = toDouble(y1);
2737  qreal nx2 = toDouble(x2);
2738  qreal ny2 = toDouble(y2);
2739 
2740  QLineF lineBounds(nx1, ny1, nx2, ny2);
2741  QSvgNode *line = new QSvgLine(parent, lineBounds);
2742  return line;
2743 }
2744 
2745 
2746 static void parseBaseGradient(QSvgNode *node,
2747  const QXmlStreamAttributes &attributes,
2748  QSvgGradientStyle *gradProp,
2750 {
2751  QString link = attributes.value(QLatin1String("xlink:href")).toString();
2752  QStringRef trans = attributes.value(QLatin1String("gradientTransform"));
2753  QString spread = attributes.value(QLatin1String("spreadMethod")).toString();
2754  QString units = attributes.value(QLatin1String("gradientUnits")).toString();
2755  QStringRef colorStr = attributes.value(QLatin1String("color"));
2756  QStringRef colorOpacityStr = attributes.value(QLatin1String("color-opacity"));
2757 
2758  QColor color;
2759  if (constructColor(colorStr, colorOpacityStr, color, handler)) {
2760  handler->popColor();
2761  handler->pushColor(color);
2762  }
2763 
2764  QMatrix matrix;
2765  QGradient *grad = gradProp->qgradient();
2766  if (!link.isEmpty()) {
2767  QSvgStyleProperty *prop = node->styleProperty(link);
2768  //qDebug()<<"inherited "<<prop<<" ("<<link<<")";
2769  if (prop && prop->type() == QSvgStyleProperty::GRADIENT) {
2770  QSvgGradientStyle *inherited =
2771  static_cast<QSvgGradientStyle*>(prop);
2772  if (!inherited->stopLink().isEmpty()) {
2773  gradProp->setStopLink(inherited->stopLink(), handler->document());
2774  } else {
2775  grad->setStops(inherited->qgradient()->stops());
2776  gradProp->setGradientStopsSet(inherited->gradientStopsSet());
2777  }
2778 
2779  matrix = inherited->qmatrix();
2780  } else {
2781  gradProp->setStopLink(link, handler->document());
2782  }
2783  }
2784 
2785  if (!trans.isEmpty()) {
2786  matrix = parseTransformationMatrix(trans);
2787  gradProp->setMatrix(matrix);
2788  } else if (!matrix.isIdentity()) {
2789  gradProp->setMatrix(matrix);
2790  }
2791 
2792  if (!spread.isEmpty()) {
2793  if (spread == QLatin1String("pad")) {
2795  } else if (spread == QLatin1String("reflect")) {
2797  } else if (spread == QLatin1String("repeat")) {
2799  }
2800  }
2801 
2802  if (units.isEmpty() || units == QLatin1String("objectBoundingBox")) {
2804  }
2805 }
2806 
2808  const QXmlStreamAttributes &attributes,
2810 {
2811  QString x1 = attributes.value(QLatin1String("x1")).toString();
2812  QString y1 = attributes.value(QLatin1String("y1")).toString();
2813  QString x2 = attributes.value(QLatin1String("x2")).toString();
2814  QString y2 = attributes.value(QLatin1String("y2")).toString();
2815 
2816  qreal nx1 = 0.0;
2817  qreal ny1 = 0.0;
2818  qreal nx2 = 1.0;
2819  qreal ny2 = 0.0;
2820 
2821  if (!x1.isEmpty())
2822  nx1 = convertToNumber(x1, handler);
2823  if (!y1.isEmpty())
2824  ny1 = convertToNumber(y1, handler);
2825  if (!x2.isEmpty())
2826  nx2 = convertToNumber(x2, handler);
2827  if (!y2.isEmpty())
2828  ny2 = convertToNumber(y2, handler);
2829 
2830  QSvgNode *itr = node;
2831  while (itr && itr->type() != QSvgNode::DOC) {
2832  itr = itr->parent();
2833  }
2834 
2835  QLinearGradient *grad = new QLinearGradient(nx1, ny1, nx2, ny2);
2837  QSvgGradientStyle *prop = new QSvgGradientStyle(grad);
2838  parseBaseGradient(node, attributes, prop, handler);
2839 
2840  return prop;
2841 }
2842 
2843 static bool parseMetadataNode(QSvgNode *parent,
2844  const QXmlStreamAttributes &attributes,
2845  QSvgHandler *)
2846 {
2847  Q_UNUSED(parent); Q_UNUSED(attributes);
2848  return true;
2849 }
2850 
2852  const QXmlStreamAttributes &attributes,
2853  QSvgHandler *)
2854 {
2855  if (parent->type() != QSvgStyleProperty::FONT) {
2856  return false;
2857  }
2858 
2859  QSvgFontStyle *style = static_cast<QSvgFontStyle*>(parent);
2860  QSvgFont *font = style->svgFont();
2861  createSvgGlyph(font, attributes);
2862  return true;
2863 }
2864 
2865 static bool parseMpathNode(QSvgNode *parent,
2866  const QXmlStreamAttributes &attributes,
2867  QSvgHandler *)
2868 {
2869  Q_UNUSED(parent); Q_UNUSED(attributes);
2870  return true;
2871 }
2872 
2874  const QXmlStreamAttributes &attributes,
2875  QSvgHandler *)
2876 {
2877  QStringRef data = attributes.value(QLatin1String("d"));
2878 
2879  QPainterPath qpath;
2881  //XXX do error handling
2882  parsePathDataFast(data, qpath);
2883 
2884  QSvgNode *path = new QSvgPath(parent, qpath);
2885  return path;
2886 }
2887 
2889  const QXmlStreamAttributes &attributes,
2890  QSvgHandler *)
2891 {
2892  QString pointsStr = attributes.value(QLatin1String("points")).toString();
2893 
2894  //same QPolygon parsing is in createPolylineNode
2895  const QChar *s = pointsStr.constData();
2896  QVector<qreal> points = parseNumbersList(s);
2897  QPolygonF poly(points.count()/2);
2898  for (int i = 0; i < poly.size(); ++i)
2899  poly[i] = QPointF(points.at(2 * i), points.at(2 * i + 1));
2900  QSvgNode *polygon = new QSvgPolygon(parent, poly);
2901  return polygon;
2902 }
2903 
2905  const QXmlStreamAttributes &attributes,
2906  QSvgHandler *)
2907 {
2908  QString pointsStr = attributes.value(QLatin1String("points")).toString();
2909 
2910  //same QPolygon parsing is in createPolygonNode
2911  const QChar *s = pointsStr.constData();
2912  QVector<qreal> points = parseNumbersList(s);
2913  QPolygonF poly(points.count()/2);
2914  for (int i = 0; i < poly.size(); ++i)
2915  poly[i] = QPointF(points.at(2 * i), points.at(2 * i + 1));
2916 
2917  QSvgNode *line = new QSvgPolyline(parent, poly);
2918  return line;
2919 }
2920 
2921 static bool parsePrefetchNode(QSvgNode *parent,
2922  const QXmlStreamAttributes &attributes,
2923  QSvgHandler *)
2924 {
2925  Q_UNUSED(parent); Q_UNUSED(attributes);
2926  return true;
2927 }
2928 
2930  const QXmlStreamAttributes &attributes,
2932 {
2933  QString cx = attributes.value(QLatin1String("cx")).toString();
2934  QString cy = attributes.value(QLatin1String("cy")).toString();
2935  QString r = attributes.value(QLatin1String("r")).toString();
2936  QString fx = attributes.value(QLatin1String("fx")).toString();
2937  QString fy = attributes.value(QLatin1String("fy")).toString();
2938 
2939  qreal ncx = 0.5;
2940  qreal ncy = 0.5;
2941  qreal nr = 0.5;
2942  if (!cx.isEmpty())
2943  ncx = toDouble(cx);
2944  if (!cy.isEmpty())
2945  ncy = toDouble(cy);
2946  if (!r.isEmpty())
2947  nr = toDouble(r);
2948 
2949  qreal nfx = ncx;
2950  if (!fx.isEmpty())
2951  nfx = toDouble(fx);
2952  qreal nfy = ncy;
2953  if (!fy.isEmpty())
2954  nfy = toDouble(fy);
2955 
2956  QRadialGradient *grad = new QRadialGradient(ncx, ncy, nr, nfx, nfy);
2958 
2959  QSvgGradientStyle *prop = new QSvgGradientStyle(grad);
2960  parseBaseGradient(node, attributes, prop, handler);
2961 
2962  return prop;
2963 }
2964 
2966  const QXmlStreamAttributes &attributes,
2968 {
2969  QString x = attributes.value(QLatin1String("x")).toString();
2970  QString y = attributes.value(QLatin1String("y")).toString();
2971  QString width = attributes.value(QLatin1String("width")).toString();
2972  QString height = attributes.value(QLatin1String("height")).toString();
2973  QString rx = attributes.value(QLatin1String("rx")).toString();
2974  QString ry = attributes.value(QLatin1String("ry")).toString();
2975 
2977  qreal nwidth = parseLength(width, type, handler);
2978  nwidth = convertToPixels(nwidth, true, type);
2979 
2980  qreal nheight = parseLength(height, type, handler);
2981  nheight = convertToPixels(nheight, true, type);
2982  qreal nrx = toDouble(rx);
2983  qreal nry = toDouble(ry);
2984 
2985  QRectF bounds(toDouble(x), toDouble(y),
2986  nwidth, nheight);
2987 
2988  //9.2 The 'rect' element clearly specifies it
2989  // but the case might in fact be handled because
2990  // we draw rounded rectangles differently
2991  if (nrx > bounds.width()/2)
2992  nrx = bounds.width()/2;
2993  if (nry > bounds.height()/2)
2994  nry = bounds.height()/2;
2995 
2996  if (!rx.isEmpty() && ry.isEmpty())
2997  nry = nrx;
2998  else if (!ry.isEmpty() && rx.isEmpty())
2999  nrx = nry;
3000 
3001  //we draw rounded rect from 0...99
3002  //svg from 0...bounds.width()/2 so we're adjusting the
3003  //coordinates
3004  nrx *= (100/(bounds.width()/2));
3005  nry *= (100/(bounds.height()/2));
3006 
3007  QSvgNode *rect = new QSvgRect(parent, bounds,
3008  int(nrx),
3009  int(nry));
3010  return rect;
3011 }
3012 
3013 static bool parseScriptNode(QSvgNode *parent,
3014  const QXmlStreamAttributes &attributes,
3015  QSvgHandler *)
3016 {
3017  Q_UNUSED(parent); Q_UNUSED(attributes);
3018  return true;
3019 }
3020 
3021 static bool parseSetNode(QSvgNode *parent,
3022  const QXmlStreamAttributes &attributes,
3023  QSvgHandler *)
3024 {
3025  Q_UNUSED(parent); Q_UNUSED(attributes);
3026  return true;
3027 }
3028 
3030  const QXmlStreamAttributes &attributes,
3032 {
3033  Q_UNUSED(parent); Q_UNUSED(attributes);
3034  QStringRef solidColorStr = attributes.value(QLatin1String("solid-color"));
3035  QStringRef solidOpacityStr = attributes.value(QLatin1String("solid-opacity"));
3036 
3037  if (solidOpacityStr.isEmpty())
3038  solidOpacityStr = attributes.value(QLatin1String("opacity"));
3039 
3040  QColor color;
3041  if (!constructColor(solidColorStr, solidOpacityStr, color, handler))
3042  return 0;
3043  QSvgSolidColorStyle *style = new QSvgSolidColorStyle(color);
3044  return style;
3045 }
3046 
3047 static bool parseStopNode(QSvgStyleProperty *parent,
3048  const QXmlStreamAttributes &attributes,
3050 {
3051  if (parent->type() != QSvgStyleProperty::GRADIENT)
3052  return false;
3053  QString nodeIdStr = someId(attributes);
3054  QString xmlClassStr = attributes.value(QLatin1String("class")).toString();
3055 
3056  //### nasty hack because stop gradients are not in the rendering tree
3057  // we force a dummy node with the same id and class into a rendering
3058  // tree to figure out whether the selector has a style for it
3059  // QSvgStyleSelector should be coded in a way that could avoid it
3060  QSvgAnimation anim;
3061  anim.setNodeId(nodeIdStr);
3062  anim.setXmlClass(xmlClassStr);
3063 
3065  cssNode.ptr = &anim;
3066  QVector<QCss::Declaration> decls = handler->selector()->declarationsForNode(cssNode);
3067 
3068  QXmlStreamAttributes xmlAttr = attributes;
3069  for (int i = 0; i < decls.count(); ++i) {
3070  const QCss::Declaration &decl = decls.at(i);
3071 
3072  if (decl.d->property.isEmpty())
3073  continue;
3074  if (decl.d->values.count() != 1)
3075  continue;
3076  QCss::Value val = decl.d->values.first();
3077  QString valueStr = val.toString();
3078  if (val.type == QCss::Value::Uri) {
3079  valueStr.prepend(QLatin1String("url("));
3080  valueStr.append(QLatin1Char(')'));
3081  }
3082  xmlAttr.append(QString(), decl.d->property, valueStr);
3083  }
3084  QSvgAttributes attrs(xmlAttr, handler);
3085 
3086  QSvgGradientStyle *style =
3087  static_cast<QSvgGradientStyle*>(parent);
3088  QString offsetStr = attrs.offset.toString();
3089  QStringRef colorStr = attrs.stopColor;
3090  QColor color;
3091 
3092  bool ok = true;
3093  qreal offset = convertToNumber(offsetStr, handler, &ok);
3094  if (!ok)
3095  offset = 0.0;
3096  QString black = QString::fromLatin1("#000000");
3097  if (colorStr.isEmpty()) {
3098  colorStr = QStringRef(&black);
3099  }
3100 
3101  constructColor(colorStr, attrs.stopOpacity, color, handler);
3102 
3103  QGradient *grad = style->qgradient();
3104 
3105  offset = qMin(qreal(1), qMax(qreal(0), offset)); // Clamp to range [0, 1]
3106  QGradientStops stops;
3107  if (style->gradientStopsSet()) {
3108  stops = grad->stops();
3109  // If the stop offset equals the one previously added, add an epsilon to make it greater.
3110  if (offset <= stops.back().first)
3111  offset = stops.back().first + FLT_EPSILON;
3112  }
3113 
3114  // If offset is greater than one, it must be clamped to one.
3115  if (offset > 1.0) {
3116  if ((stops.size() == 1) || (stops.at(stops.size() - 2).first < 1.0 - FLT_EPSILON)) {
3117  stops.back().first = 1.0 - FLT_EPSILON;
3118  grad->setStops(stops);
3119  }
3120  offset = 1.0;
3121  }
3122 
3123  grad->setColorAt(offset, color);
3124  style->setGradientStopsSet(true);
3125  return true;
3126 }
3127 
3128 static bool parseStyleNode(QSvgNode *parent,
3129  const QXmlStreamAttributes &attributes,
3131 {
3132  Q_UNUSED(parent);
3133  QString type = attributes.value(QLatin1String("type")).toString();
3134  type = type.toLower();
3135 
3136  if (type == QLatin1String("text/css")) {
3137  handler->setInStyle(true);
3138  }
3139 
3140  return true;
3141 }
3142 
3144  const QXmlStreamAttributes &attributes,
3146 {
3147  Q_UNUSED(parent); Q_UNUSED(attributes);
3148 
3149  QString baseProfile = attributes.value(QLatin1String("baseProfile")).toString();
3150 #if 0
3151  if (baseProfile.isEmpty() && baseProfile != QLatin1String("tiny")) {
3152  qWarning("Profile is %s while we only support tiny!",
3153  qPrintable(baseProfile));
3154  }
3155 #endif
3156 
3157  QSvgTinyDocument *node = new QSvgTinyDocument();
3158  QString widthStr = attributes.value(QLatin1String("width")).toString();
3159  QString heightStr = attributes.value(QLatin1String("height")).toString();
3160  QString viewBoxStr = attributes.value(QLatin1String("viewBox")).toString();
3161 
3162  QSvgHandler::LengthType type = QSvgHandler::LT_PX; // FIXME: is the default correct?
3163  qreal width = 0;
3164  if (!widthStr.isEmpty()) {
3165  width = parseLength(widthStr, type, handler);
3166  if (type != QSvgHandler::LT_PT)
3167  width = convertToPixels(width, true, type);
3168  node->setWidth(int(width), type == QSvgHandler::LT_PERCENT);
3169  }
3170  qreal height = 0;
3171  if (!heightStr.isEmpty()) {
3172  height = parseLength(heightStr, type, handler);
3173  if (type != QSvgHandler::LT_PT)
3174  height = convertToPixels(height, false, type);
3175  node->setHeight(int(height), type == QSvgHandler::LT_PERCENT);
3176  }
3177 
3178  QStringList viewBoxValues;
3179  if (!viewBoxStr.isEmpty()) {
3180  viewBoxStr = viewBoxStr.replace(QLatin1Char(' '), QLatin1Char(','));
3181  viewBoxStr = viewBoxStr.replace(QLatin1Char('\r'), QLatin1Char(','));
3182  viewBoxStr = viewBoxStr.replace(QLatin1Char('\n'), QLatin1Char(','));
3183  viewBoxStr = viewBoxStr.replace(QLatin1Char('\t'), QLatin1Char(','));
3184  viewBoxValues = viewBoxStr.split(QLatin1Char(','), QString::SkipEmptyParts);
3185  }
3186  if (viewBoxValues.count() == 4) {
3187  QString xStr = viewBoxValues.at(0).trimmed();
3188  QString yStr = viewBoxValues.at(1).trimmed();
3189  QString widthStr = viewBoxValues.at(2).trimmed();
3190  QString heightStr = viewBoxValues.at(3).trimmed();
3191 
3193  qreal x = parseLength(xStr, lt, handler);
3194  qreal y = parseLength(yStr, lt, handler);
3195  qreal w = parseLength(widthStr, lt, handler);
3196  qreal h = parseLength(heightStr, lt, handler);
3197 
3198  node->setViewBox(QRectF(x, y, w, h));
3199 
3200  } else if (width && height) {
3201  if (type == QSvgHandler::LT_PT) {
3202  width = convertToPixels(width, false, type);
3203  height = convertToPixels(height, false, type);
3204  }
3205  node->setViewBox(QRectF(0, 0, width, height));
3206  }
3208 
3209  return node;
3210 }
3211 
3213  const QXmlStreamAttributes &attributes,
3214  QSvgHandler *)
3215 {
3216  Q_UNUSED(attributes);
3217  QSvgSwitch *node = new QSvgSwitch(parent);
3218  return node;
3219 }
3220 
3221 static bool parseTbreakNode(QSvgNode *parent,
3222  const QXmlStreamAttributes &,
3223  QSvgHandler *)
3224 {
3225  if (parent->type() != QSvgNode::TEXTAREA)
3226  return false;
3227  static_cast<QSvgText*>(parent)->addLineBreak();
3228  return true;
3229 }
3230 
3232  const QXmlStreamAttributes &attributes,
3234 {
3235  QString x = attributes.value(QLatin1String("x")).toString();
3236  QString y = attributes.value(QLatin1String("y")).toString();
3237  //### editable and rotate not handled
3239  qreal nx = parseLength(x, type, handler);
3240  qreal ny = parseLength(y, type, handler);
3241 
3242  QSvgNode *text = new QSvgText(parent, QPointF(nx, ny));
3243  return text;
3244 }
3245 
3247  const QXmlStreamAttributes &attributes,
3249 {
3250  QSvgText *node = static_cast<QSvgText *>(createTextNode(parent, attributes, handler));
3251  if (node) {
3253  qreal width = parseLength(attributes.value(QLatin1String("width")).toString(), type, handler);
3254  qreal height = parseLength(attributes.value(QLatin1String("height")).toString(), type, handler);
3255  node->setTextArea(QSizeF(width, height));
3256  }
3257  return node;
3258 }
3259 
3261  const QXmlStreamAttributes &,
3262  QSvgHandler *)
3263 {
3264  return new QSvgTspan(parent);
3265 }
3266 
3267 static bool parseTitleNode(QSvgNode *parent,
3268  const QXmlStreamAttributes &attributes,
3269  QSvgHandler *)
3270 {
3271  Q_UNUSED(parent); Q_UNUSED(attributes);
3272  return true;
3273 }
3274 
3276  const QXmlStreamAttributes &attributes,
3278 {
3279  QString linkId = attributes.value(QLatin1String("xlink:href")).toString().remove(0, 1);
3280  QString xStr = attributes.value(QLatin1String("x")).toString();
3281  QString yStr = attributes.value(QLatin1String("y")).toString();
3282  QSvgStructureNode *group = 0;
3283 
3284  if (linkId.isEmpty())
3285  linkId = attributes.value(QLatin1String("href")).toString().remove(0, 1);
3286  switch (parent->type()) {
3287  case QSvgNode::DOC:
3288  case QSvgNode::DEFS:
3289  case QSvgNode::G:
3290  case QSvgNode::SWITCH:
3291  group = static_cast<QSvgStructureNode*>(parent);
3292  break;
3293  default:
3294  break;
3295  }
3296 
3297  if (group) {
3298  QSvgNode *link = group->scopeNode(linkId);
3299  if (link) {
3300  QPointF pt;
3301  if (!xStr.isNull() || !yStr.isNull()) {
3303  qreal nx = parseLength(xStr, type, handler);
3304  nx = convertToPixels(nx, true, type);
3305 
3306  qreal ny = parseLength(yStr, type, handler);
3307  ny = convertToPixels(ny, true, type);
3308  pt = QPointF(nx, ny);
3309  }
3310 
3311  //delay link resolving till the first draw call on
3312  //use nodes, link 2might have not been created yet
3313  QSvgUse *node = new QSvgUse(pt, parent, link);
3314  return node;
3315  }
3316  }
3317 
3318  qWarning("link %s hasn't been detected!", qPrintable(linkId));
3319  return 0;
3320 }
3321 
3323  const QXmlStreamAttributes &attributes,
3324  QSvgHandler *)
3325 {
3326  Q_UNUSED(parent); Q_UNUSED(attributes);
3327  return 0;
3328 }
3329 
3330 typedef QSvgNode *(*FactoryMethod)(QSvgNode *, const QXmlStreamAttributes &, QSvgHandler *);
3331 
3333 {
3334  if (name.isEmpty())
3335  return 0;
3336 
3337  QStringRef ref(&name, 1, name.length() - 1);
3338  switch (name.at(0).unicode()) {
3339  case 'd':
3340  if (ref == QLatin1String("efs")) return createDefsNode;
3341  break;
3342  case 'g':
3343  if (ref.isEmpty()) return createGNode;
3344  break;
3345  case 's':
3346  if (ref == QLatin1String("vg")) return createSvgNode;
3347  if (ref == QLatin1String("witch")) return createSwitchNode;
3348  break;
3349  default:
3350  break;
3351  }
3352  return 0;
3353 }
3354 
3356 {
3357  if (name.isEmpty())
3358  return 0;
3359 
3360  QStringRef ref(&name, 1, name.length() - 1);
3361  switch (name.at(0).unicode()) {
3362  case 'a':
3363  if (ref == QLatin1String("nimation")) return createAnimationNode;
3364  break;
3365  case 'c':
3366  if (ref == QLatin1String("ircle")) return createCircleNode;
3367  break;
3368  case 'e':
3369  if (ref == QLatin1String("llipse")) return createEllipseNode;
3370  break;
3371  case 'i':
3372  if (ref == QLatin1String("mage")) return createImageNode;
3373  break;
3374  case 'l':
3375  if (ref == QLatin1String("ine")) return createLineNode;
3376  break;
3377  case 'p':
3378  if (ref == QLatin1String("ath")) return createPathNode;
3379  if (ref == QLatin1String("olygon")) return createPolygonNode;
3380  if (ref == QLatin1String("olyline")) return createPolylineNode;
3381  break;
3382  case 'r':
3383  if (ref == QLatin1String("ect")) return createRectNode;
3384  break;
3385  case 't':
3386  if (ref == QLatin1String("ext")) return createTextNode;
3387  if (ref == QLatin1String("extArea")) return createTextAreaNode;
3388  if (ref == QLatin1String("span")) return createTspanNode;
3389  break;
3390  case 'u':
3391  if (ref == QLatin1String("se")) return createUseNode;
3392  break;
3393  case 'v':
3394  if (ref == QLatin1String("ideo")) return createVideoNode;
3395  break;
3396  default:
3397  break;
3398  }
3399  return 0;
3400 }
3401 
3402 typedef bool (*ParseMethod)(QSvgNode *, const QXmlStreamAttributes &, QSvgHandler *);
3403 
3405 {
3406  if (name.isEmpty())
3407  return 0;
3408 
3409  QStringRef ref(&name, 1, name.length() - 1);
3410  switch (name.at(0).unicode()) {
3411  case 'a':
3412  if (ref.isEmpty()) return parseAnchorNode;
3413  if (ref == QLatin1String("nimate")) return parseAnimateNode;
3414  if (ref == QLatin1String("nimateColor")) return parseAnimateColorNode;
3415  if (ref == QLatin1String("nimateMotion")) return parseAimateMotionNode;
3416  if (ref == QLatin1String("nimateTransform")) return parseAnimateTransformNode;
3417  if (ref == QLatin1String("udio")) return parseAudioNode;
3418  break;
3419  case 'd':
3420  if (ref == QLatin1String("esc")) return parseDescNode;
3421  if (ref == QLatin1String("iscard")) return parseDiscardNode;
3422  break;
3423  case 'f':
3424  if (ref == QLatin1String("oreignObject")) return parseForeignObjectNode;
3425  break;
3426  case 'h':
3427  if (ref == QLatin1String("andler")) return parseHandlerNode;
3428  if (ref == QLatin1String("kern")) return parseHkernNode;
3429  break;
3430  case 'm':
3431  if (ref == QLatin1String("etadata")) return parseMetadataNode;
3432  if (ref == QLatin1String("path")) return parseMpathNode;
3433  break;
3434  case 'p':
3435  if (ref == QLatin1String("refetch")) return parsePrefetchNode;
3436  break;
3437  case 's':
3438  if (ref == QLatin1String("cript")) return parseScriptNode;
3439  if (ref == QLatin1String("et")) return parseSetNode;
3440  if (ref == QLatin1String("tyle")) return parseStyleNode;
3441  break;
3442  case 't':
3443  if (ref == QLatin1String("break")) return parseTbreakNode;
3444  if (ref == QLatin1String("itle")) return parseTitleNode;
3445  break;
3446  default:
3447  break;
3448  }
3449  return 0;
3450 }
3451 
3452 typedef QSvgStyleProperty *(*StyleFactoryMethod)(QSvgNode *,
3453  const QXmlStreamAttributes &,
3454  QSvgHandler *);
3455 
3457 {
3458  if (name.isEmpty())
3459  return 0;
3460 
3461  QStringRef ref(&name, 1, name.length() - 1);
3462  switch (name.at(0).unicode()) {
3463  case 'f':
3464  if (ref == QLatin1String("ont")) return createFontNode;
3465  break;
3466  case 'l':
3467  if (ref == QLatin1String("inearGradient")) return createLinearGradientNode;
3468  break;
3469  case 'r':
3470  if (ref == QLatin1String("adialGradient")) return createRadialGradientNode;
3471  break;
3472  case 's':
3473  if (ref == QLatin1String("olidColor")) return createSolidColorNode;
3474  break;
3475  default:
3476  break;
3477  }
3478  return 0;
3479 }
3480 
3482  const QXmlStreamAttributes &,
3483  QSvgHandler *);
3484 
3486 {
3487  if (name.isEmpty())
3488  return 0;
3489 
3490  QStringRef ref(&name, 1, name.length() - 1);
3491  switch (name.at(0).unicode()) {
3492  case 'f':
3493  if (ref == QLatin1String("ont-face")) return parseFontFaceNode;
3494  if (ref == QLatin1String("ont-face-name")) return parseFontFaceNameNode;
3495  if (ref == QLatin1String("ont-face-src")) return parseFontFaceSrcNode;
3496  if (ref == QLatin1String("ont-face-uri")) return parseFontFaceUriNode;
3497  break;
3498  case 'g':
3499  if (ref == QLatin1String("lyph")) return parseGlyphNode;
3500  break;
3501  case 'm':
3502  if (ref == QLatin1String("issing-glyph")) return parseMissingGlyphNode;
3503  break;
3504  case 's':
3505  if (ref == QLatin1String("top")) return parseStopNode;
3506  break;
3507  default:
3508  break;
3509  }
3510  return 0;
3511 }
3512 
3514  , m_ownsReader(true)
3515 {
3516  init();
3517 }
3518 
3520  , m_ownsReader(true)
3521 {
3522  init();
3523 }
3524 
3526  , m_ownsReader(false)
3527 {
3528  init();
3529 }
3530 
3532 {
3533  m_doc = 0;
3534  m_style = 0;
3535  m_animEnd = 0;
3539  parse();
3540 }
3541 
3543 {
3544  xml->setNamespaceProcessing(false);
3546  m_inStyle = false;
3547  bool done = false;
3548  while (!xml->atEnd() && !done) {
3549  switch (xml->readNext()) {
3551  // he we could/should verify the namespaces, and simply
3552  // call m_skipNodes(Unknown) if we don't know the
3553  // namespace. We do support http://www.w3.org/2000/svg
3554  // but also http://www.w3.org/2000/svg-20000303-stylable
3555  // And if the document uses an external dtd, the reported
3556  // namespaceUri is empty. The only possible strategy at
3557  // this point is to do what everyone else seems to do and
3558  // ignore the reported namespaceUri completely.
3559  if (!startElement(xml->name().toString(), xml->attributes())) {
3560  delete m_doc;
3561  m_doc = 0;
3562  return;
3563  }
3564  break;
3566  endElement(xml->name());
3567  // if we are using somebody else's qxmlstreamreader
3568  // we should not read until the end of the stream
3569  done = !m_ownsReader && (xml->name() == QLatin1String("svg"));
3570  break;
3572  characters(xml->text());
3573  break;
3576  break;
3577  default:
3578  break;
3579  }
3580  }
3582 }
3583 
3584 bool QSvgHandler::startElement(const QString &localName,
3585  const QXmlStreamAttributes &attributes)
3586 {
3587  QSvgNode *node = 0;
3588 
3589  pushColorCopy();
3590 
3591  /* The xml:space attribute may appear on any element. We do
3592  * a lookup by the qualified name here, but this is namespace aware, since
3593  * the XML namespace can only be bound to prefix "xml." */
3594  const QStringRef xmlSpace(attributes.value(QLatin1String("xml:space")));
3595  if (xmlSpace.isNull()) {
3596  // This element has no xml:space attribute.
3598  } else if (xmlSpace == QLatin1String("preserve")) {
3600  } else if (xmlSpace == QLatin1String("default")) {
3602  } else {
3603  qWarning() << QString::fromLatin1("\"%1\" is an invalid value for attribute xml:space. "
3604  "Valid values are \"preserve\" and \"default\".").arg(xmlSpace.toString());
3606  }
3607 
3608  if (!m_doc && localName != QLatin1String("svg"))
3609  return false;
3610 
3611  if (FactoryMethod method = findGroupFactory(localName)) {
3612  //group
3613  node = method(m_doc ? m_nodes.top() : 0, attributes, this);
3614  Q_ASSERT(node);
3615  if (!m_doc) {
3616  Q_ASSERT(node->type() == QSvgNode::DOC);
3617  m_doc = static_cast<QSvgTinyDocument*>(node);
3618  } else {
3619  switch (m_nodes.top()->type()) {
3620  case QSvgNode::DOC:
3621  case QSvgNode::G:
3622  case QSvgNode::DEFS:
3623  case QSvgNode::SWITCH:
3624  {
3625  QSvgStructureNode *group =
3626  static_cast<QSvgStructureNode*>(m_nodes.top());
3627  group->addChild(node, someId(attributes));
3628  }
3629  break;
3630  default:
3631  break;
3632  }
3633  }
3634  parseCoreNode(node, attributes);
3635  cssStyleLookup(node, this, m_selector);
3636  parseStyle(node, attributes, this);
3637  } else if (FactoryMethod method = findGraphicsFactory(localName)) {
3638  //rendering element
3639  Q_ASSERT(!m_nodes.isEmpty());
3640  node = method(m_nodes.top(), attributes, this);
3641  if (node) {
3642  switch (m_nodes.top()->type()) {
3643  case QSvgNode::DOC:
3644  case QSvgNode::G:
3645  case QSvgNode::DEFS:
3646  case QSvgNode::SWITCH:
3647  {
3648  QSvgStructureNode *group =
3649  static_cast<QSvgStructureNode*>(m_nodes.top());
3650  group->addChild(node, someId(attributes));
3651  }
3652  break;
3653  case QSvgNode::TEXT:
3654  case QSvgNode::TEXTAREA:
3655  if (node->type() == QSvgNode::TSPAN) {
3656  static_cast<QSvgText *>(m_nodes.top())->addTspan(static_cast<QSvgTspan *>(node));
3657  } else {
3658  qWarning("\'text\' or \'textArea\' element contains invalid element type.");
3659  delete node;
3660  node = 0;
3661  }
3662  break;
3663  default:
3664  qWarning("Could not add child element to parent element because the types are incorrect.");
3665  delete node;
3666  node = 0;
3667  break;
3668  }
3669 
3670  if (node) {
3671  parseCoreNode(node, attributes);
3672  cssStyleLookup(node, this, m_selector);
3673  parseStyle(node, attributes, this);
3674  if (node->type() == QSvgNode::TEXT || node->type() == QSvgNode::TEXTAREA) {
3675  static_cast<QSvgText *>(node)->setWhitespaceMode(m_whitespaceMode.top());
3676  } else if (node->type() == QSvgNode::TSPAN) {
3677  static_cast<QSvgTspan *>(node)->setWhitespaceMode(m_whitespaceMode.top());
3678  }
3679  }
3680  }
3681  } else if (ParseMethod method = findUtilFactory(localName)) {
3682  Q_ASSERT(!m_nodes.isEmpty());
3683  if (!method(m_nodes.top(), attributes, this)) {
3684  qWarning("Problem parsing %s", qPrintable(localName));
3685  }
3686  } else if (StyleFactoryMethod method = findStyleFactoryMethod(localName)) {
3687  QSvgStyleProperty *prop = method(m_nodes.top(), attributes, this);
3688  if (prop) {
3689  m_style = prop;
3690  m_nodes.top()->appendStyleProperty(prop, someId(attributes));
3691  } else {
3692  qWarning("Could not parse node: %s", qPrintable(localName));
3693  }
3694  } else if (StyleParseMethod method = findStyleUtilFactoryMethod(localName)) {
3695  if (m_style) {
3696  if (!method(m_style, attributes, this)) {
3697  qWarning("Problem parsing %s", qPrintable(localName));
3698  }
3699  }
3700  } else {
3701  //qWarning()<<"Skipping unknown element!"<<namespaceURI<<"::"<<localName;
3703  return true;
3704  }
3705 
3706  if (node) {
3707  m_nodes.push(node);
3709  } else {
3710  //qDebug()<<"Skipping "<<localName;
3712  }
3713  return true;
3714 }
3715 
3716 bool QSvgHandler::endElement(const QStringRef &localName)
3717 {
3718  CurrentNode node = m_skipNodes.top();
3719  m_skipNodes.pop();
3721 
3722  popColor();
3723 
3724  if (node == Unknown) {
3725  return true;
3726  }
3727 
3728  if (m_inStyle && localName == QLatin1String("style"))
3729  m_inStyle = false;
3730 
3731  if (node == Graphics)
3732  m_nodes.pop();
3733  else if (m_style && !m_skipNodes.isEmpty() && m_skipNodes.top() != Style)
3734  m_style = 0;
3735 
3736  return true;
3737 }
3738 
3740 {
3741  if (!node || (node->type() != QSvgNode::DOC && node->type() != QSvgNode::G
3742  && node->type() != QSvgNode::DEFS && node->type() != QSvgNode::SWITCH)) {
3743  return;
3744  }
3745  QSvgStructureNode *structureNode = static_cast<QSvgStructureNode *>(node);
3746 
3747  QList<QSvgNode *> ren = structureNode->renderers();
3748  for (QList<QSvgNode *>::iterator it = ren.begin(); it != ren.end(); ++it) {
3749  QSvgFillStyle *fill = static_cast<QSvgFillStyle *>((*it)->styleProperty(QSvgStyleProperty::FILL));
3750  if (fill && !fill->isGradientResolved()) {
3751  QString id = fill->gradientId();
3752  QSvgFillStyleProperty *style = structureNode->styleProperty(id);
3753  if (style) {
3754  fill->setFillStyle(style);
3755  } else {
3756  qWarning("Could not resolve property : %s", qPrintable(id));
3757  fill->setBrush(Qt::NoBrush);
3758  }
3759  }
3760 
3761  QSvgStrokeStyle *stroke = static_cast<QSvgStrokeStyle *>((*it)->styleProperty(QSvgStyleProperty::STROKE));
3762  if (stroke && !stroke->isGradientResolved()) {
3763  QString id = stroke->gradientId();
3764  QSvgFillStyleProperty *style = structureNode->styleProperty(id);
3765  if (style) {
3766  stroke->setStyle(style);
3767  } else {
3768  qWarning("Could not resolve property : %s", qPrintable(id));
3769  stroke->setStroke(Qt::NoBrush);
3770  }
3771  }
3772 
3773  resolveGradients(*it);
3774  }
3775 }
3776 
3778 {
3779  if (m_inStyle) {
3780  QString css = str.toString();
3781  QCss::StyleSheet sheet;
3782  QCss::Parser(css).parse(&sheet);
3783  m_selector->styleSheets.append(sheet);
3784  return true;
3785  } else if (m_skipNodes.isEmpty() || m_skipNodes.top() == Unknown || m_nodes.isEmpty())
3786  return true;
3787 
3788  if (m_nodes.top()->type() == QSvgNode::TEXT || m_nodes.top()->type() == QSvgNode::TEXTAREA) {
3789  static_cast<QSvgText*>(m_nodes.top())->addText(str.toString());
3790  } else if (m_nodes.top()->type() == QSvgNode::TSPAN) {
3791  static_cast<QSvgTspan*>(m_nodes.top())->addText(str.toString());
3792  }
3793 
3794  return true;
3795 }
3796 
3798 {
3799  return m_doc;
3800 }
3801 
3803 {
3804  return m_defaultCoords;
3805 }
3806 
3808 {
3810 }
3811 
3812 void QSvgHandler::pushColor(const QColor &color)
3813 {
3814  m_colorStack.push(color);
3815  m_colorTagCount.push(1);
3816 }
3817 
3819 {
3820  if (m_colorTagCount.count())
3821  ++m_colorTagCount.top();
3822  else
3824 }
3825 
3827 {
3828  if (m_colorTagCount.count()) {
3829  if (!--m_colorTagCount.top()) {
3830  m_colorStack.pop();
3831  m_colorTagCount.pop();
3832  }
3833  }
3834 }
3835 
3837 {
3838  if (!m_colorStack.isEmpty())
3839  return m_colorStack.top();
3840  else
3841  return QColor(0, 0, 0);
3842 }
3843 
3845 {
3846  m_inStyle = b;
3847 }
3848 
3850 {
3851  return m_inStyle;
3852 }
3853 
3855 {
3856  return m_selector;
3857 }
3858 
3859 bool QSvgHandler::processingInstruction(const QString &target, const QString &data)
3860 {
3861  if (target == QLatin1String("xml-stylesheet")) {
3862  QRegExp rx(QLatin1String("type=\\\"(.+)\\\""));
3863  rx.setMinimal(true);
3864  bool isCss = false;
3865  int pos = 0;
3866  while ((pos = rx.indexIn(data, pos)) != -1) {
3867  QString type = rx.cap(1);
3868  if (type.toLower() == QLatin1String("text/css")) {
3869  isCss = true;
3870  }
3871  pos += rx.matchedLength();
3872  }
3873 
3874  if (isCss) {
3875  QRegExp rx(QLatin1String("href=\\\"(.+)\\\""));
3876  rx.setMinimal(true);
3877  pos = 0;
3878  pos = rx.indexIn(data, pos);
3879  QString addr = rx.cap(1);
3880  QFileInfo fi(addr);
3881  //qDebug()<<"External CSS file "<<fi.absoluteFilePath()<<fi.exists();
3882  if (fi.exists()) {
3883  QFile file(fi.absoluteFilePath());
3884  if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
3885  return true;
3886  }
3887  QByteArray cssData = file.readAll();
3888  QString css = QString::fromUtf8(cssData);
3889 
3890  QCss::StyleSheet sheet;
3891  QCss::Parser(css).parse(&sheet);
3892  m_selector->styleSheets.append(sheet);
3893  }
3894 
3895  }
3896  }
3897 
3898  return true;
3899 }
3900 
3901 void QSvgHandler::setAnimPeriod(int start, int end)
3902 {
3903  Q_UNUSED(start);
3904  m_animEnd = qMax(end, m_animEnd);
3905 }
3906 
3908 {
3909  return m_animEnd;
3910 }
3911 
3913 {
3914  delete m_selector;
3915  m_selector = 0;
3916 
3917  if(m_ownsReader)
3918  delete xml;
3919 }
3920 
3922 
3923 #endif // QT_NO_SVG
static void parseCompOp(QSvgNode *node, const QSvgAttributes &attributes, QSvgHandler *)
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition: qcolor.h:67
double d
Definition: qnumeric_p.h:62
bool isGradientResolved() const
Definition: qsvgstyle_p.h:506
QString toString() const
Returns a copy of the string reference as a QString object.
Definition: qstring.cpp:8653
void setRgb(int r, int g, int b, int a=255)
Sets the RGB value to r, g, b and the alpha value to a.
Definition: qcolor.cpp:980
virtual Type type() const =0
const T * constData() const
const unsigned char magic[QSXE_MAGIC_BYTES]
virtual NodePtr previousSiblingNode(NodePtr node) const
QStringRef fontVariant
QStack< int > m_colorTagCount
virtual bool isNullNode(NodePtr node) const
unsigned int QRgb
Definition: qrgb.h:53
QXmlStreamStringRef name
Definition: qsvghandler_p.h:77
QString text
Definition: qcssparser_p.h:737
int type
Definition: qmetatype.cpp:239
void setTextAnchor(Qt::Alignment anchor)
Definition: qsvgstyle_p.h:345
double qreal
Definition: qglobal.h:1193
void setLineJoin(Qt::PenJoinStyle join)
Definition: qsvgstyle_p.h:450
unsigned char c[8]
Definition: qnumeric_p.h:62
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
Definition: qglobal.h:1215
void setColorAt(qreal pos, const QColor &color)
Creates a stop point at the given position with the given color.
Definition: qbrush.cpp:1475
QString cap(int nth=0) const
Returns the text captured by the nth subexpression.
Definition: qregexp.cpp:4310
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
static QVector< qreal > parseNumbersList(const QChar *&str)
QStringRef vectorEffect
void appendStyleProperty(QSvgStyleProperty *prop, const QString &id)
Definition: qsvgnode.cpp:64
static QSvgStyleProperty * createFontNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
static QSvgNode * createVideoNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
void setWeight(int weight)
Definition: qsvgstyle_p.h:370
static QSvgNode * createPolygonNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
int length() const
Returns the number of characters referred to by the string reference.
Definition: qstring.h:1116
static bool parseFontFaceUriNode(QSvgStyleProperty *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
const QChar at(int i) const
Returns the character at the given index position in the string.
Definition: qstring.h:698
CompositionMode
Defines the modes supported for digital image compositing.
Definition: qpainter.h:138
void setOpacity(qreal opacity)
Definition: qsvgstyle_p.h:462
The QRegExp class provides pattern matching using regular expressions.
Definition: qregexp.h:61
int qCeil(qreal v)
Definition: qmath.h:63
QStringRef fontStyle
static QString idFromUrl(const QString &url)
#define NOOP
int toInt(bool *ok=0, int base=10) const
Returns the string converted to an int using base base, which is 10 by default and must be between 2 ...
Definition: qstring.cpp:6090
ushort unicode() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: qchar.h:251
The QMatrix class specifies 2D transformations of a coordinate system.
Definition: qmatrix.h:61
static QSvgStyleProperty * createRadialGradientNode(QSvgNode *node, const QXmlStreamAttributes &attributes, QSvgHandler *handler)
#define it(className, varName)
static bool parseDiscardNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
virtual QStringList nodeNames(NodePtr node) const
The QPainterPath class provides a container for painting operations, enabling graphical shapes to be ...
Definition: qpainterpath.h:67
int count(const T &t) const
Returns the number of occurrences of value in the vector.
Definition: qvector.h:742
void setGradientId(const QString &Id)
Definition: qsvgstyle_p.h:265
QStringRef strokeDashArray
void setRequiredExtensions(const QStringList &lst)
Definition: qsvgnode.cpp:255
void setWidth(int len, bool percent)
static bool constructColor(const QStringRef &colorStr, const QStringRef &opacity, QColor &color, QSvgHandler *handler)
QVector< QSvgCssAttribute > m_cssAttributes
static QSvgNode * createCircleNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
static bool parseFontFaceSrcNode(QSvgStyleProperty *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
#define error(msg)
bool isNull() const
Returns true if it is a null image, otherwise returns false.
Definition: qimage.cpp:1542
static void parseNumberTriplet(QVector< qreal > &values, const QChar *&s)
void setHeight(int len, bool percent)
QString & replace(int i, int len, QChar after)
Definition: qstring.cpp:2005
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
void chop(int n)
Removes n characters from the end of the string.
Definition: qstring.cpp:4623
int length() const
Returns the number of characters in this string.
Definition: qstring.h:696
QString & prepend(QChar c)
Definition: qstring.h:261
The QPointF class defines a point in the plane using floating point precision.
Definition: qpoint.h:214
virtual void freeNode(NodePtr node) const
void closeSubpath()
Closes the current subpath by drawing a line to the beginning of the subpath, automatically starting ...
T1 first
Definition: qpair.h:65
QString gradientId() const
Definition: qsvgstyle_p.h:270
static QMatrix parseTransformationMatrix(const QStringRef &value)
QStringRef value() const
Returns the attribute&#39;s value.
Definition: qxmlstream.h:156
iterator begin()
Returns an STL-style iterator pointing to the first item in the list.
Definition: qlist.h:267
QSvgTinyDocument * document() const
QStringRef visibility
QSvgFont * svgFont(const QString &family) const
const_iterator constBegin() const
Returns a const STL-style iterator pointing to the first item in the list.
Definition: qlist.h:269
QStringRef stopColor
int matchedLength() const
Returns the length of the last matched string, or -1 if there was no match.
Definition: qregexp.cpp:4193
static bool parseTbreakNode(QSvgNode *parent, const QXmlStreamAttributes &, QSvgHandler *)
QGradient * qgradient() const
Definition: qsvgstyle_p.h:591
bool(* ParseMethod)(QSvgNode *, const QXmlStreamAttributes &, QSvgHandler *)
QString stopLink() const
Definition: qsvgstyle_p.h:582
static void parseVisibility(QSvgNode *node, const QSvgAttributes &attributes, QSvgHandler *)
QSvgHandler(QIODevice *device)
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition: qstring.cpp:3734
QStringRef stroke
QString absoluteFilePath() const
Returns an absolute path including the file name.
Definition: qfileinfo.cpp:534
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
bool exists() const
Returns true if the file exists; otherwise returns false.
Definition: qfileinfo.cpp:675
static QSvgNode * createPolylineNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
QSvgNode * scopeNode(const QString &id) const
void setStyle(QFont::Style fontStyle)
Definition: qsvgstyle_p.h:357
QStringRef name() const
Returns the local name of a StartElement, EndElement, or an EntityReference.
int count(const T &t) const
Returns the number of occurrences of value in the list.
Definition: qlist.h:891
QList< QSvgNode * > renderers() const
void setXmlClass(const QString &str)
Definition: qsvgnode.cpp:320
QSvgFont * svgFont() const
Definition: qsvgstyle_p.h:376
static StyleParseMethod findStyleUtilFactoryMethod(const QString &name)
static QSvgStyleProperty * styleFromUrl(QSvgNode *node, const QString &url)
static QSvgNode * createDefsNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
QSvgNode *(* FactoryMethod)(QSvgNode *, const QXmlStreamAttributes &, QSvgHandler *)
QSvgAttributes(const QXmlStreamAttributes &xmlAttributes, QSvgHandler *handler)
The QRadialGradient class is used in combination with QBrush to specify a radial gradient brush...
Definition: qbrush.h:297
bool atEnd() const
Returns true if the reader has read until the end of the XML document, or if an error() has occurred ...
Definition: qxmlstream.cpp:590
QSvgNode * parent() const
Definition: qsvgnode_p.h:183
void setVectorEffect(bool nonScalingStroke)
Definition: qsvgstyle_p.h:480
The QString class provides a Unicode character string.
Definition: qstring.h:83
QStringRef fontWeight
static QSvgNode * createAnimationNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
static bool parseAimateMotionNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
static bool parseAnimateNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
static void parseTransform(QSvgNode *node, const QSvgAttributes &attributes, QSvgHandler *)
static ParseMethod findUtilFactory(const QString &name)
void setArgs(TransformType type, Additive additive, const QVector< qreal > &args)
Definition: qsvgstyle.cpp:649
Q_DECL_CONSTEXPR T qAbs(const T &t)
Definition: qglobal.h:1201
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
static bool parseForeignObjectNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
void setRepeatCount(qreal repeatCount)
Definition: qsvgstyle.cpp:832
QStringRef stopOpacity
static QString someId(const QXmlStreamAttributes &attributes)
const bool m_ownsReader
static QStringList stringToList(const QString &str)
Q_GUI_EXPORT QString extensions()
Definition: qegl.cpp:785
QMatrix & translate(qreal dx, qreal dy)
Moves the coordinate system dx along the x axis and dy along the y axis, and returns a reference to t...
Definition: qmatrix.cpp:922
static bool parseStyle(QSvgNode *node, const QXmlStreamAttributes &attributes, QSvgHandler *)
static bool parsePathDataFast(const QStringRef &data, QPainterPath &path)
The QPen class defines how a QPainter should draw lines and outlines of shapes.
Definition: qpen.h:64
The QSizeF class defines the size of a two-dimensional object using floating point precision...
Definition: qsize.h:202
QString toString() const
Definition: qcssparser.cpp:253
QXmlStreamReader *const xml
void append(const T &t)
static QSvgNode * createRectNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *handler)
QStringRef qualifiedName() const
Returns the attribute&#39;s qualified name.
Definition: qxmlstream.h:150
The QChar class provides a 16-bit Unicode character.
Definition: qchar.h:72
void setFillRule(Qt::FillRule f)
Definition: qsvgstyle.cpp:114
void moveTo(const QPointF &p)
Moves the current point to the given point, implicitly starting a new subpath and closing the previou...
static void parseOthers(QSvgNode *node, const QSvgAttributes &attributes, QSvgHandler *)
QVariant variant
Definition: qcssparser_p.h:372
static bool parseMissingGlyphNode(QSvgStyleProperty *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
Format format() const
Returns the format of the image.
Definition: qimage.cpp:2305
QMatrix qmatrix() const
Definition: qsvgstyle_p.h:586
static QSvgStyleProperty * createSolidColorNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *handler)
QSvgStyleSelector * selector() const
void setViewBox(const QRectF &rect)
Q_DECL_CONSTEXPR const T & qMax(const T &a, const T &b)
Definition: qglobal.h:1217
bool isSpace() const
Returns true if the character is a separator character (Separator_* categories); otherwise returns fa...
Definition: qchar.cpp:609
static int qsvg_hex2int(const char *s)
Definition: qsvghandler.cpp:92
static const char * QSvgStyleSelector_nodeString[]
virtual NodePtr parentNode(NodePtr node) const
void setRequiredLanguages(const QStringList &lst)
Definition: qsvgnode.cpp:265
qreal x() const
Returns the x-coordinate of this point.
Definition: qpoint.h:282
QStringRef value(const QString &namespaceUri, const QString &name) const
Returns the value of the attribute name in the namespace described with namespaceUri, or an empty string reference if the attribute is not defined.
The QLineF class provides a two-dimensional vector using floating point precision.
Definition: qline.h:212
int toInt(bool *ok=0) const
Returns the variant as an int if the variant has type() Int , Bool , ByteArray , Char ...
Definition: qvariant.cpp:2625
QStringRef strokeDashOffset
QExplicitlySharedDataPointer< DeclarationData > d
Definition: qcssparser_p.h:430
const_iterator constBegin() const
Returns a const STL-style iterator pointing to the first character in the string. ...
Definition: qstring.h:892
QStringRef fontSize
static QSvgNode * createGNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
T pop()
Removes the top item from the stack and returns it.
Definition: qstack.h:67
const QChar * constData() const
Same as unicode().
Definition: qstring.h:1159
The QXmlStreamAttribute class represents a single XML attribute.
Definition: qxmlstream.h:135
bool qsvg_get_hex_rgb(const char *name, QRgb *rgb)
void lineTo(const QPointF &p)
Adds a straight line from the current position to the given endPoint.
Q_CORE_EXPORT void qDebug(const char *,...)
QGradientStops stops() const
Returns the stop points for this gradient.
Definition: qbrush.cpp:1520
void setFillRule(Qt::FillRule fillRule)
Sets the fill rule of the painter path to the given fillRule.
friend class const_iterator
Definition: qlist.h:264
void setSpread(Spread spread)
Specifies the spread method that should be used for this gradient.
Definition: qbrush.h:277
static void parseOpacity(QSvgNode *node, const QSvgAttributes &attributes, QSvgHandler *)
void setAnimPeriod(int start, int end)
static QSvgNode * createSvgNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *handler)
QStringRef compOp
QStringList toStringList() const
Returns the variant as a QStringList if the variant has type() StringList, String ...
Definition: qvariant.cpp:2259
void pushColor(const QColor &color)
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
void setMinimal(bool minimal)
Enables or disables minimal matching.
Definition: qregexp.cpp:4068
bool isVisible() const
Definition: qsvgnode_p.h:188
int size() const
Returns the number of characters referred to by the string reference.
Definition: qstring.h:1114
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
The QRectF class defines a rectangle in the plane using floating point precision. ...
Definition: qrect.h:511
bool(* StyleParseMethod)(QSvgStyleProperty *, const QXmlStreamAttributes &, QSvgHandler *)
static const char * qt_inherit_text
Definition: qsvghandler.cpp:74
void setAnimated(bool a)
void setWidth(qreal width)
Definition: qsvgstyle_p.h:468
static bool isEmpty(const char *str)
QMatrix & rotate(qreal a)
Rotates the coordinate system the given degrees counterclockwise.
Definition: qmatrix.cpp:990
static bool parseAudioNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
QSvgStyleProperty *(* StyleFactoryMethod)(QSvgNode *, const QXmlStreamAttributes &, QSvgHandler *)
static void pathArcSegment(QPainterPath &path, qreal xc, qreal yc, qreal th0, qreal th1, qreal rx, qreal ry, qreal xAxisRotation)
int indexIn(const QString &str, int offset=0, CaretMode caretMode=CaretAtZero) const
Attempts to find a match in str from position offset (0 by default).
Definition: qregexp.cpp:4136
void setFreeze(bool freeze)
Definition: qsvgstyle.cpp:827
void setInterpolationMode(InterpolationMode mode)
Sets the interpolation mode of this gradient to mode.
Definition: qbrush.cpp:1623
QStringRef strokeMiterLimit
QString trimmed() const Q_REQUIRED_RESULT
Returns a string that has whitespace removed from the start and the end.
Definition: qstring.cpp:4506
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
qreal qSin(qreal v)
Definition: qmath.h:93
void setGradientResolved(bool resolved)
Definition: qsvgstyle_p.h:501
void setFillStyle(QSvgFillStyleProperty *style)
Definition: qsvgstyle.cpp:126
void addSvgFont(QSvgFont *)
virtual QString attribute(NodePtr node, const QString &name) const
QStringRef offset
QSvgNode * svgNode(NodePtr node) const
void setBrush(QBrush brush)
Definition: qsvgstyle.cpp:132
iterator end()
Returns an STL-style iterator pointing to the imaginary item after the last item in the list...
Definition: qlist.h:270
qreal height() const
Returns the height of the rectangle.
Definition: qrect.h:710
const char * name
const T & at(int i) const
Returns the item at index position i in the list.
Definition: qlist.h:468
void setGradientStopsSet(bool set)
Definition: qsvgstyle_p.h:601
The QStringList class provides a list of strings.
Definition: qstringlist.h:66
static bool parseAnimateColorNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *handler)
void setRequiredFormats(const QStringList &lst)
Definition: qsvgnode.cpp:275
void resolveGradients(QSvgNode *node)
The QPolygonF class provides a vector of points using floating point precision.
Definition: qpolygon.h:134
void addChild(QSvgNode *child, const QString &id)
static QString fromUtf8(const char *, int size=-1)
Returns a QString initialized with the first size bytes of the UTF-8 string str.
Definition: qstring.cpp:4302
void append(const T &t)
Inserts value at the end of the vector.
Definition: qvector.h:573
bool endElement(const QStringRef &localName)
unsigned short quint16
Definition: qglobal.h:936
Q_CORE_EXPORT void qWarning(const char *,...)
bool isEmpty() const
Returns true if the string reference has no characters; otherwise returns false.
Definition: qstring.h:1169
static bool parseFontFaceNode(QSvgStyleProperty *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
static bool resolveColor(const QStringRef &colorStr, QColor &color, QSvgHandler *handler)
void setRequiredFeatures(const QStringList &lst)
Definition: qsvgnode.cpp:245
static QVector< Declaration > declarations(const QVector< StyleRule > &styleRules, const QString &part, quint64 pseudoClass=PseudoClass_Unspecified)
The QImage class provides a hardware-independent image representation that allows direct access to th...
Definition: qimage.h:87
static void parseFont(QSvgNode *node, const QSvgAttributes &attributes, QSvgHandler *handler)
static bool parseScriptNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
static const char * data(const QByteArray &arr)
unsigned int uint
Definition: qglobal.h:996
void setArgs(bool fill, const QList< QColor > &colors)
Definition: qsvgstyle.cpp:820
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal...
Definition: qstring.h:654
QStack< QSvgNode * > m_nodes
virtual NodePtr duplicateNode(NodePtr node) const
The Translate object provides a way to move an Item without changing its x or y properties.
static const int BOLDER
Definition: qsvgstyle_p.h:329
qreal qAtan2(qreal x, qreal y)
Definition: qmath.h:189
static QSvgNode * createLineNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
qreal width() const
Returns the width of the rectangle.
Definition: qrect.h:707
QStringRef fontFamily
static void parseBrush(QSvgNode *node, const QSvgAttributes &attributes, QSvgHandler *handler)
const QChar * unicode() const
Returns a Unicode representation of the string reference.
Definition: qstring.h:1153
QVector< StyleSheet > styleSheets
Definition: qcssparser_p.h:675
virtual QStringList nodeIds(NodePtr node) const
static bool isDigit(ushort ch)
static void pathArc(QPainterPath &path, qreal rx, qreal ry, qreal x_axis_rotation, int large_arc_flag, int sweep_flag, qreal x, qreal y, qreal curx, qreal cury)
static bool parseCoreNode(QSvgNode *node, const QXmlStreamAttributes &attributes)
static QSvgNode * createTextNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *handler)
The State element defines configurations of objects and properties.
quint16 values[128]
static QSvgNode * createUseNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *handler)
int count() const
virtual ~QSvgStyleSelector()
void setMiterLimit(qreal limit)
Definition: qsvgstyle_p.h:456
QStringRef fillRule
void setFamilyName(const QString &name)
Definition: qsvgfont.cpp:130
QMatrix & shear(qreal sh, qreal sv)
Shears the coordinate system by sh horizontally and sv vertically, and returns a reference to the mat...
Definition: qmatrix.cpp:957
void push(const T &t)
Adds element t to the top of the stack.
Definition: qstack.h:60
static FactoryMethod findGroupFactory(const QString &name)
QStringRef fill
void setVariant(QFont::Capitalization fontVariant)
Definition: qsvgstyle_p.h:362
The QStringRef class provides a thin wrapper around QString substrings.
Definition: qstring.h:1099
static QStringRef trimRef(const QStringRef &str)
static void parseColor(QSvgNode *, const QSvgAttributes &attributes, QSvgHandler *handler)
bool inStyle() const
static bool parseGlyphNode(QSvgStyleProperty *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
static bool parseStyleNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *handler)
QStringRef transform
static FactoryMethod findGraphicsFactory(const QString &name)
const T & at(int i) const
Returns the item at index position i in the vector.
Definition: qvector.h:350
void setDashOffset(qreal offset)
Definition: qsvgstyle_p.h:438
The QList::iterator class provides an STL-style non-const iterator for QList and QQueue.
Definition: qlist.h:181
QString gradientId() const
Definition: qsvgstyle_p.h:496
TokenType readNext()
Reads the next token and returns its type.
Definition: qxmlstream.cpp:623
#define rgb(r, g, b)
Definition: qcolor_p.cpp:130
static bool parseFontFaceNameNode(QSvgStyleProperty *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
void setDashArrayNone()
Definition: qsvgstyle_p.h:432
static QSvgStyleProperty * createLinearGradientNode(QSvgNode *node, const QXmlStreamAttributes &attributes, QSvgHandler *handler)
static QSvgNode::DisplayMode displayStringToEnum(const QString &str)
LengthType defaultCoordinateSystem() const
static qreal convertToPixels(qreal len, bool, QSvgHandler::LengthType type)
static void parseCSStoXMLAttrs(const QVector< QCss::Declaration > &declarations, QXmlStreamAttributes &attributes)
static bool createSvgGlyph(QSvgFont *font, const QXmlStreamAttributes &attributes)
QRgb qRgb(int r, int g, int b)
Returns the ARGB quadruplet (255, {r}, {g}, {b}).
Definition: qrgb.h:69
The QBrush class defines the fill pattern of shapes drawn by QPainter.
Definition: qbrush.h:76
bool isNull() const
Returns true if this string is null; otherwise returns false.
Definition: qstring.h:505
static QVector< qreal > parsePercentageList(const QChar *&str)
void setMatrix(const QMatrix &matrix)
Definition: qsvgstyle.cpp:436
QString mid(int position, int n=-1) const Q_REQUIRED_RESULT
Returns a string that contains n characters of this string, starting at the specified position index...
Definition: qstring.cpp:3706
QString xmlClass() const
Definition: qsvgnode_p.h:198
static QByteArray fromBase64(const QByteArray &base64)
Returns a decoded copy of the Base64 array base64.
const qreal deg2rad
Definition: qmatrix.cpp:970
static bool parseMetadataNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
int position() const
Returns the starting position in the referenced string that is referred to by the string reference...
Definition: qstring.h:1113
QString arg(qlonglong a, int fieldwidth=0, int base=10, const QChar &fillChar=QLatin1Char(' ')) const Q_REQUIRED_RESULT
Definition: qstring.cpp:7186
static bool parseHkernNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
static QPainter::CompositionMode svgToQtCompositionMode(const QString &op)
void setFillOpacity(qreal opacity)
Definition: qsvgstyle.cpp:120
QImage convertToFormat(Format f, Qt::ImageConversionFlags flags=Qt::AutoColor) const Q_REQUIRED_RESULT
Returns a copy of the image in the given format.
Definition: qimage.cpp:3966
static bool parseAnchorNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
QString & append(QChar c)
Definition: qstring.cpp:1777
int compare(const QString &s) const
Definition: qstring.cpp:5037
void setFamily(const QString &family)
Definition: qsvgstyle_p.h:351
QSvgTinyDocument * doc() const
Definition: qsvgstyle_p.h:386
The Scale element provides a way to scale an Item.
The QFile class provides an interface for reading from and writing to files.
Definition: qfile.h:65
void setAlphaF(qreal alpha)
Sets the alpha of this color to alpha.
Definition: qcolor.cpp:1117
void setUnitsPerEm(qreal upem)
Definition: qsvgfont.cpp:135
#define Q_CORE_EXPORT
Definition: qglobal.h:1449
const QString * string() const
Returns a pointer to the string referred to by the string reference, or 0 if it does not reference a ...
Definition: qstring.h:1112
static const int LIGHTER
Definition: qsvgstyle_p.h:328
void setInStyle(bool b)
QStringRef display
The QLinearGradient class is used in combination with QBrush to specify a linear gradient brush...
Definition: qbrush.h:280
QSvgStyleProperty * styleProperty(QSvgStyleProperty::Type type) const
Definition: qsvgnode.cpp:128
The QXmlStreamAttributes class represents a vector of QXmlStreamAttribute.
Definition: qxmlstream.h:169
The QGradient class is used in combination with QBrush to specify gradient fills. ...
Definition: qbrush.h:201
QString nodeId() const
Definition: qsvgnode_p.h:193
unsigned short ushort
Definition: qglobal.h:995
QStack< CurrentNode > m_skipNodes
QStringRef fillOpacity
virtual Type type() const =0
QSvgStructureNode * nodeToStructure(QSvgNode *n) const
int lastIndexOf(QChar c, int from=-1, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.cpp:3000
static QString fromLatin1(const char *, int size=-1)
Returns a QString initialized with the first size characters of the Latin-1 string str...
Definition: qstring.cpp:4188
QStringRef strokeOpacity
static bool parseStopNode(QSvgStyleProperty *parent, const QXmlStreamAttributes &attributes, QSvgHandler *handler)
void setCoordinateMode(CoordinateMode mode)
Sets the coordinate mode of this gradient to mode.
Definition: qbrush.cpp:1578
static QSvgNode * createImageNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *handler)
void setSize(qreal size)
Definition: qsvgstyle_p.h:337
static QSvgNode * createTextAreaNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *handler)
uint qstrlen(const char *str)
Definition: qbytearray.h:79
QStringRef textAnchor
#define st(var, type, card)
int key
QString toLower() const Q_REQUIRED_RESULT
Returns a lowercase copy of the string.
Definition: qstring.cpp:5389
void setRepeatCount(qreal repeatCount)
Definition: qsvgstyle.cpp:807
Q_DECL_CONSTEXPR const T & qBound(const T &min, const T &val, const T &max)
Definition: qglobal.h:1219
void setStops(const QGradientStops &stops)
Replaces the current set of stop points with the given stopPoints.
Definition: qbrush.cpp:1504
reference back()
This function is provided for STL compatibility.
Definition: qvector.h:289
LengthType m_defaultCoords
double toDouble(bool *ok=0) const
Returns the string converted to a double value.
Definition: qstring.cpp:6227
void setDisplayMode(DisplayMode display)
Definition: qsvgnode.cpp:325
QString nodeToName(QSvgNode *node) const
QStringRef colorOpacity
void parseCSStoXMLAttrs(QString css, QVector< QSvgCssAttribute > *attributes)
QByteArray toAscii() const Q_REQUIRED_RESULT
Returns an 8-bit representation of the string as a QByteArray.
Definition: qstring.cpp:4014
void addGlyph(QChar unicode, const QPainterPath &path, qreal horizAdvX=-1)
Definition: qsvgfont.cpp:72
void setDefaultCoordinateSystem(LengthType type)
The QRect class defines a rectangle in the plane using integer precision.
Definition: qrect.h:58
QFactoryLoader * l
int animationDuration() const
virtual bool hasAttributes(NodePtr node) const
static bool parseTitleNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
void setLineCap(Qt::PenCapStyle cap)
Definition: qsvgstyle_p.h:444
QStringRef strokeWidth
static QSvgNode * createSwitchNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
QStringRef color
QVector< Declaration > declarationsForNode(NodePtr node, const char *extraPseudo=0)
qreal qTan(qreal v)
Definition: qmath.h:125
char toLatin1() const
Returns the Latin-1 character equivalent to the QChar, or 0.
Definition: qchar.h:376
void quadTo(const QPointF &ctrlPt, const QPointF &endPt)
Adds a quadratic Bezier curve between the current position and the given endPoint with the control po...
static bool parseMpathNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
void setStyle(QSvgFillStyleProperty *style)
Definition: qsvgstyle_p.h:424
QStringRef processingInstructionData() const
Returns the data of a ProcessingInstruction.
qreal y() const
Returns the y-coordinate of this point.
Definition: qpoint.h:287
QStringRef opacity
void cubicTo(const QPointF &ctrlPt1, const QPointF &ctrlPt2, const QPointF &endPt)
Adds a cubic Bezier curve between the current position and the given endPoint using the control point...
QTextStream & hex(QTextStream &stream)
Calls QTextStream::setIntegerBase(16) on stream and returns stream.
void setStroke(QBrush brush)
Definition: qsvgstyle_p.h:417
QStack< QColor > m_colorStack
QSvgNode * previousSiblingNode(QSvgNode *n) const
QStringRef strokeLineJoin
static bool parseDescNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
static qreal parseLength(const QString &str, QSvgHandler::LengthType &type, QSvgHandler *handler, bool *ok=NULL)
bool startElement(const QString &localName, const QXmlStreamAttributes &attributes)
bool characters(const QStringRef &str)
#define QT_INHERIT
Definition: qsvghandler.cpp:75
void setVisible(bool visible)
Definition: qsvgnode.cpp:295
static qreal toDouble(const QChar *&str)
void setFreeze(bool freeze)
Definition: qsvgstyle.cpp:802
static qreal convertToNumber(const QString &str, QSvgHandler *handler, bool *ok=NULL)
void setStopLink(const QString &link, QSvgTinyDocument *doc)
Definition: qsvgstyle.cpp:931
bool gradientStopsSet() const
Definition: qsvgstyle_p.h:596
void setDashArray(const QVector< qreal > &dashes)
Definition: qsvgstyle.cpp:389
QStringRef strokeLineCap
static void cssStyleLookup(QSvgNode *node, QSvgHandler *handler, QSvgStyleSelector *selector)
bool parse(StyleSheet *styleSheet, Qt::CaseSensitivity nameCaseSensitivity=Qt::CaseSensitive)
bool isEmpty() const
Returns true if the vector has size 0; otherwise returns false.
Definition: qvector.h:139
bool isIdentity() const
Returns true if the matrix is the identity matrix, otherwise returns false.
Definition: qmatrix.h:166
bool processingInstruction(const QString &target, const QString &data)
QStringList split(const QString &sep, SplitBehavior behavior=KeepEmptyParts, Qt::CaseSensitivity cs=Qt::CaseSensitive) const Q_REQUIRED_RESULT
Splits the string into substrings wherever sep occurs, and returns the list of those strings...
Definition: qstring.cpp:6526
virtual bool nodeNameEquals(NodePtr node, const QString &nodeName) const
The QXmlStreamReader class provides a fast parser for reading well-formed XML via a simple streaming ...
Definition: qxmlstream.h:290
static bool parseSetNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
void reserve(int size)
Attempts to allocate memory for at least size elements.
Definition: qvector.h:339
void setNodeId(const QString &i)
Definition: qsvgnode.cpp:315
bool isValid() const
Returns true if the color is valid; otherwise returns false.
Definition: qcolor.h:295
QStringRef processingInstructionTarget() const
Returns the target of a ProcessingInstruction.
QString familyName() const
Definition: qsvgfont.cpp:66
void setTextArea(const QSizeF &size)
QMatrix & scale(qreal sx, qreal sy)
Scales the coordinate system by sx horizontally and sy vertically, and returns a reference to the mat...
Definition: qmatrix.cpp:941
static bool parseAnimateTransformNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *handler)
bool isGradientResolved() const
Definition: qsvgstyle_p.h:280
QString & remove(int i, int len)
Removes n characters from the string, starting at the given position index, and returns a reference t...
Definition: qstring.cpp:1867
QSvgTinyDocument * document() const
Definition: qsvgnode.cpp:233
QStringRef text() const
Returns the text of Characters , Comment , DTD , or EntityReference.
static StyleFactoryMethod findStyleFactoryMethod(const QString &name)
void setRequiredFonts(const QStringList &lst)
Definition: qsvgnode.cpp:285
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
Definition: qstring.cpp:3796
static QSvgNode * createTspanNode(QSvgNode *parent, const QXmlStreamAttributes &, QSvgHandler *)
QSvgStructureNode * svgStructure(NodePtr node) const
void setNamespaceProcessing(bool)
Definition: qxmlstream.cpp:782
The QFileInfo class provides system-independent file information.
Definition: qfileinfo.h:60
QImageIOHandler * handler
void setGradientId(const QString &Id)
Definition: qsvgstyle_p.h:491
static bool parsePrefetchNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
static int qsvg_h2i(char hex)
Definition: qsvghandler.cpp:81
static const KeyPair *const end
void pushColorCopy()
The QIODevice class is the base interface class of all I/O devices in Qt.
Definition: qiodevice.h:66
QColor currentColor() const
void append(const QString &namespaceUri, const QString &name, const QString &value)
Appends a new attribute with name in the namespace described with namespaceUri, and value value...
#define qPrintable(string)
Definition: qglobal.h:1750
qreal qCos(qreal v)
Definition: qmath.h:109
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
qreal qSqrt(qreal v)
Definition: qmath.h:205
static bool parseHandlerNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
QSvgRefCounter< QSvgStyleProperty > m_style
int size() const
Returns the number of items in the vector.
Definition: qvector.h:137
static QImage fromData(const uchar *data, int size, const char *format=0)
Constructs a QImage from the first size bytes of the given binary data.
Definition: qimage.cpp:5313
Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok)
void setGradientResolved(bool resolved)
Definition: qsvgstyle_p.h:275
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:55
QXmlStreamAttributes attributes() const
Returns the attributes of a StartElement.
static QSvgNode * createPathNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
const QChar * constData() const
Returns a pointer to the data stored in the QString.
Definition: qstring.h:712
static QSvgNode * createEllipseNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *)
const QChar at(int i) const
Returns the character at the given index position in the string reference.
Definition: qstring.h:1174
static void parseNumbersArray(const QChar *&str, QVarLengthArray< qreal, 8 > &points)
QSvgStyleSelector * m_selector
#define text
Definition: qobjectdefs.h:80
QStack< QSvgText::WhitespaceMode > m_whitespaceMode
Follows the depths of elements.
QXmlStreamStringRef value
Definition: qsvghandler_p.h:78
QSvgTinyDocument * m_doc
The QTransform class specifies 2D transformations of a coordinate system.
Definition: qtransform.h:65
void setMiterLimit(qreal limit)
Sets the miter limit of this pen to the given limit.
Definition: qpen.cpp:611
T & top()
Returns a reference to the stack&#39;s top item.
Definition: qstack.h:72
const_iterator constEnd() const
Returns a const STL-style iterator pointing to the imaginary item after the last item in the list...
Definition: qlist.h:272
static void parsePen(QSvgNode *node, const QSvgAttributes &attributes, QSvgHandler *handler)
static void parseBaseGradient(QSvgNode *node, const QXmlStreamAttributes &attributes, QSvgGradientStyle *gradProp, QSvgHandler *handler)
static const qreal Q_PI
Definition: qmath_p.h:61