Changeset 561 for trunk/src/svg/qsvghandler.cpp
- Timestamp:
- Feb 11, 2010, 11:19:06 PM (15 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/vendor/nokia/qt/4.6.1 merged eligible /branches/vendor/nokia/qt/current merged eligible /branches/vendor/trolltech/qt/current 3-149
-
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/src/svg/qsvghandler.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtSvg module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** 40 40 ****************************************************************************/ 41 42 #include "qplatformdefs.h" 41 43 42 44 #include "qsvghandler_p.h" … … 63 65 #include "qmath.h" 64 66 #include "qnumeric.h" 67 #include "qvarlengtharray.h" 65 68 #include "private/qmath_p.h" 66 69 … … 69 72 QT_BEGIN_NAMESPACE 70 73 74 static const char *qt_inherit_text = "inherit"; 75 #define QT_INHERIT QLatin1String(qt_inherit_text) 76 71 77 double qstrtod(const char *s00, char const **se, bool *ok); 72 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 73 150 static bool parsePathDataFast(const QStringRef &data, QPainterPath &path); 74 75 struct QSvgAttributes76 {77 QSvgAttributes(const QXmlStreamAttributes &xmlAttributes, QSvgHandler *handler);78 79 QStringRef value(const QLatin1String &name) const;80 QStringRef value(const QString &namespaceUri, const QLatin1String &name) const;81 82 QXmlStreamAttributes m_xmlAttributes;83 QVector<QSvgCssAttribute> m_cssAttributes;84 };85 86 QSvgAttributes::QSvgAttributes(const QXmlStreamAttributes &xmlAttributes, QSvgHandler *handler)87 : m_xmlAttributes(xmlAttributes)88 {89 QStringRef style = xmlAttributes.value(QLatin1String("style"));90 if (!style.isEmpty())91 handler->parseCSStoXMLAttrs(style.toString(), &m_cssAttributes);92 }93 94 QStringRef QSvgAttributes::value(const QLatin1String &name) const95 {96 QStringRef v = m_xmlAttributes.value(name);97 if (v.isEmpty()) {98 for (int i = 0; i < m_cssAttributes.count(); ++i) {99 if (m_cssAttributes.at(i).name == name) {100 v = m_cssAttributes.at(i).value;101 break;102 }103 }104 }105 return v;106 }107 108 QStringRef QSvgAttributes::value(const QString &namespaceUri, const QLatin1String &name) const109 {110 QStringRef v = m_xmlAttributes.value(namespaceUri, name);111 if (v.isEmpty()) {112 for (int i = 0; i < m_cssAttributes.count(); ++i) {113 if (m_cssAttributes.at(i).name == name) {114 v = m_cssAttributes.at(i).value;115 break;116 }117 }118 }119 return v;120 }121 151 122 152 static inline QString someId(const QXmlStreamAttributes &attributes) … … 127 157 return id; 128 158 } 129 static inline QString someId(const QSvgAttributes &attributes) 130 { return someId(attributes.m_xmlAttributes); } 131 132 159 160 struct QSvgAttributes 161 { 162 QSvgAttributes(const QXmlStreamAttributes &xmlAttributes, QSvgHandler *handler); 163 164 QString id; 165 166 QStringRef color; 167 QStringRef colorOpacity; 168 QStringRef fill; 169 QStringRef fillRule; 170 QStringRef fillOpacity; 171 QStringRef stroke; 172 QStringRef strokeDashArray; 173 QStringRef strokeDashOffset; 174 QStringRef strokeLineCap; 175 QStringRef strokeLineJoin; 176 QStringRef strokeMiterLimit; 177 QStringRef strokeOpacity; 178 QStringRef strokeWidth; 179 QStringRef vectorEffect; 180 QStringRef fontFamily; 181 QStringRef fontSize; 182 QStringRef fontStyle; 183 QStringRef fontWeight; 184 QStringRef fontVariant; 185 QStringRef textAnchor; 186 QStringRef transform; 187 QStringRef visibility; 188 QStringRef opacity; 189 QStringRef compOp; 190 QStringRef display; 191 QStringRef offset; 192 QStringRef stopColor; 193 QStringRef stopOpacity; 194 195 QVector<QSvgCssAttribute> m_cssAttributes; 196 }; 197 198 QSvgAttributes::QSvgAttributes(const QXmlStreamAttributes &xmlAttributes, QSvgHandler *handler) 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 } 133 403 134 404 static const char * QSvgStyleSelector_nodeString[] = { … … 283 553 }; 284 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 285 562 static qreal toDouble(const QChar *&str) 286 563 { … … 295 572 ++str; 296 573 } 297 while ( *str >= QLatin1Char('0') && *str <= QLatin1Char('9') && pos < maxLen) {574 while (isDigit(str->unicode()) && pos < maxLen) { 298 575 temp[pos++] = str->toLatin1(); 299 576 ++str; … … 303 580 ++str; 304 581 } 305 while ( *str >= QLatin1Char('0') && *str <= QLatin1Char('9') && pos < maxLen) {582 while (isDigit(str->unicode()) && pos < maxLen) { 306 583 temp[pos++] = str->toLatin1(); 307 584 ++str; … … 316 593 ++str; 317 594 } 318 while ( *str >= QLatin1Char('0') && *str <= QLatin1Char('9') && pos < maxLen) {595 while (isDigit(str->unicode()) && pos < maxLen) { 319 596 temp[pos++] = str->toLatin1(); 320 597 ++str; 321 598 } 322 599 } 600 323 601 temp[pos] = '\0'; 324 602 … … 353 631 val = -val; 354 632 } else { 355 #if def Q_WS_QWS633 #if defined(Q_WS_QWS) && !defined(Q_OS_VXWORKS) 356 634 if(sizeof(qreal) == sizeof(float)) 357 635 val = strtof(temp, 0); … … 366 644 367 645 } 368 static qreal toDouble(const QString &str )646 static qreal toDouble(const QString &str, bool *ok = NULL) 369 647 { 370 648 const QChar *c = str.constData(); 371 return toDouble(c); 372 } 373 374 static qreal toDouble(const QStringRef &str) 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) 375 657 { 376 658 const QChar *c = str.constData(); 377 return toDouble(c); 659 qreal res = toDouble(c); 660 if (ok) { 661 *ok = (c == (str.constData() + str.length())); 662 } 663 return res; 378 664 } 379 665 … … 385 671 points.reserve(32); 386 672 387 while ( *str == QLatin1Char(' '))673 while (str->isSpace()) 388 674 ++str; 389 while ( (*str >= QLatin1Char('0') && *str <= QLatin1Char('9')) ||675 while (isDigit(str->unicode()) || 390 676 *str == QLatin1Char('-') || *str == QLatin1Char('+') || 391 677 *str == QLatin1Char('.')) { … … 393 679 points.append(toDouble(str)); 394 680 395 while ( *str == QLatin1Char(' '))681 while (str->isSpace()) 396 682 ++str; 397 683 if (*str == QLatin1Char(',')) … … 399 685 400 686 //eat the rest of space 401 while ( *str == QLatin1Char(' '))687 while (str->isSpace()) 402 688 ++str; 403 689 } 404 690 405 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 } 406 713 } 407 714 … … 420 727 points.append(toDouble(str)); 421 728 422 while ( *str == QLatin1Char(' '))729 while (str->isSpace()) 423 730 ++str; 424 731 if (*str == QLatin1Char('%')) 425 732 ++str; 426 while ( *str == QLatin1Char(' '))733 while (str->isSpace()) 427 734 ++str; 428 735 if (*str == QLatin1Char(',')) … … 430 737 431 738 //eat the rest of space 432 while ( *str == QLatin1Char(' '))739 while (str->isSpace()) 433 740 ++str; 434 741 } … … 456 763 } 457 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 458 787 /** 459 788 * returns true when successfuly set the color. false signifies 460 789 * that the color should be inherited 461 790 */ 462 static bool resolveColor(const QString &colorStr, QColor &color, QSvgHandler *handler) 463 { 464 QString colorStrTr = colorStr.trimmed(); 465 if (colorStr.startsWith(QLatin1String("rgb("))) { 466 const QChar *s = colorStr.constData() + 4; 467 QVector<qreal> compo = parseNumbersList(s); 468 //1 means that it failed after reaching non-parsable 469 //character which is going to be "%" 470 if (compo.size() == 1) { 471 const QChar *s = colorStr.constData() + 4; 472 compo = parsePercentageList(s); 473 compo[0] *= (qreal)2.55; 474 compo[1] *= (qreal)2.55; 475 compo[2] *= (qreal)2.55; 476 } 477 478 color = QColor(int(compo[0]), 479 int(compo[1]), 480 int(compo[2])); 481 return true; 482 } else if (colorStr == QLatin1String("inherited") || 483 colorStr == QLatin1String("inherit")) { 791 static bool resolveColor(const QStringRef &colorStr, QColor &color, QSvgHandler *handler) 792 { 793 QStringRef colorStrTr = trimRef(colorStr); 794 if (colorStrTr.isEmpty()) 484 795 return false; 485 } else if (colorStr == QLatin1String("currentColor")) { 486 color = handler->currentColor(); 487 return true; 488 } 489 490 color = QColor(colorStrTr); 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()); 491 853 return color.isValid(); 492 854 } 493 855 494 static bool constructColor(const QString &colorStr, const QString&opacity,856 static bool constructColor(const QStringRef &colorStr, const QStringRef &opacity, 495 857 QColor &color, QSvgHandler *handler) 496 858 { … … 498 860 return false; 499 861 if (!opacity.isEmpty()) { 500 qreal op = toDouble(opacity); 501 if (op <= 1) 502 op *= 255; 503 color.setAlpha(int(op)); 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); 504 867 } 505 868 return true; … … 507 870 508 871 static qreal parseLength(const QString &str, QSvgHandler::LengthType &type, 509 QSvgHandler *handler )872 QSvgHandler *handler, bool *ok = NULL) 510 873 { 511 874 QString numStr = str.trimmed(); … … 536 899 //type = QSvgHandler::LT_OTHER; 537 900 } 538 qreal len = toDouble(numStr );901 qreal len = toDouble(numStr, ok); 539 902 //qDebug()<<"len is "<<len<<", from '"<<numStr << "'"; 540 903 return len; 541 904 } 542 905 543 static inline qreal convertToNumber(const QString &str, QSvgHandler *handler )906 static inline qreal convertToNumber(const QString &str, QSvgHandler *handler, bool *ok = NULL) 544 907 { 545 908 QSvgHandler::LengthType type; 546 qreal num = parseLength(str, type, handler );909 qreal num = parseLength(str, type, handler, ok); 547 910 if (type == QSvgHandler::LT_PERCENT) { 548 911 num = num/100.0; … … 604 967 QSvgHandler *handler) 605 968 { 606 QString colorStr = attributes.value(QLatin1String("color")).toString();607 QString opacity = attributes.value(QLatin1String("color-opacity")).toString();608 969 QColor color; 609 if (constructColor(colorStr, opacity, color, handler)) { 970 if (constructColor(attributes.color, attributes.colorOpacity, color, handler)) { 971 handler->popColor(); 610 972 handler->pushColor(color); 611 973 } … … 614 976 static QSvgStyleProperty *styleFromUrl(QSvgNode *node, const QString &url) 615 977 { 616 while (node && (node->type() != QSvgNode::DOC && 617 node->type() != QSvgNode::G && 618 node->type() != QSvgNode::DEFS && 619 node->type() != QSvgNode::SWITCH)) { 620 node = node->parent(); 621 } 622 if (!node) 623 return 0; 624 return static_cast<QSvgStructureNode*>(node)->scopeStyle(idFromUrl(url)); 978 return node ? node->styleProperty(idFromUrl(url)) : 0; 625 979 } 626 980 … … 629 983 QSvgHandler *handler) 630 984 { 631 QString value = attributes.value(QLatin1String("fill")).toString(); 632 QString fillRule = attributes.value(QLatin1String("fill-rule")).toString(); 633 QString opacity = attributes.value(QLatin1String("fill-opacity")).toString(); 634 QString myId = someId(attributes); 635 636 value = value.trimmed(); 637 fillRule = fillRule.trimmed(); 638 if (!value.isEmpty() || !fillRule.isEmpty()) { 639 Qt::FillRule f = Qt::WindingFill; 640 if (fillRule == QLatin1String("evenodd")) 641 f = Qt::OddEvenFill; 642 if (value.startsWith(QLatin1String("url"))) { 643 value = value.remove(0, 3); 644 QSvgStyleProperty *style = styleFromUrl(node, value); 645 if (style) { 646 QSvgFillStyle *prop = new QSvgFillStyle(style); 647 if (!opacity.isEmpty()) 648 prop->setFillOpacity(toDouble(opacity)); 649 node->appendStyleProperty(prop, myId); 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")) 991 prop->setFillRule(Qt::OddEvenFill); 992 else if (attributes.fillRule == QLatin1String("nonzero")) 993 prop->setFillRule(Qt::WindingFill); 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) { 1009 if (style->type() == QSvgStyleProperty::SOLID_COLOR || style->type() == QSvgStyleProperty::GRADIENT) 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)); 650 1020 } else { 651 qWarning("Couldn't resolve property: %s", qPrintable(idFromUrl(value))); 652 } 653 } else if (value != QLatin1String("none")) { 654 QColor color; 655 if (constructColor(value, opacity, color, handler)) { 656 QSvgFillStyle *prop = new QSvgFillStyle(QBrush(color)); 657 if (!fillRule.isEmpty()) 658 prop->setFillRule(f); 659 node->appendStyleProperty(prop, myId); 660 } 661 } else { 662 QSvgFillStyle *prop = new QSvgFillStyle(QBrush(Qt::NoBrush)); 663 if (!fillRule.isEmpty()) 664 prop->setFillRule(f); 665 node->appendStyleProperty(prop, myId); 666 } 667 } 668 } 669 670 static void parseQPen(QPen &pen, QSvgNode *node, 671 const QSvgAttributes &attributes, 672 QSvgHandler *handler) 673 { 674 QString value = attributes.value(QLatin1String("stroke")).toString(); 675 QString dashArray = attributes.value(QLatin1String("stroke-dasharray")).toString(); 676 QString dashOffset = attributes.value(QLatin1String("stroke-dashoffset")).toString(); 677 QString linecap = attributes.value(QLatin1String("stroke-linecap")).toString(); 678 QString linejoin = attributes.value(QLatin1String("stroke-linejoin")).toString(); 679 QString miterlimit = attributes.value(QLatin1String("stroke-miterlimit")).toString(); 680 QString opacity = attributes.value(QLatin1String("stroke-opacity")).toString(); 681 QString width = attributes.value(QLatin1String("stroke-width")).toString(); 682 QString myId = someId(attributes); 683 684 if (!value.isEmpty() || !width.isEmpty()) { 685 if (value != QLatin1String("none")) { 686 if (!value.isEmpty()) { 687 if (node && value.startsWith(QLatin1String("url"))) { 688 value = value.remove(0, 3); 689 QSvgStyleProperty *style = styleFromUrl(node, value); 690 if (style) { 691 if (style->type() == QSvgStyleProperty::GRADIENT) { 692 QBrush b(*((QSvgGradientStyle*)style)->qgradient()); 693 pen.setBrush(b); 694 } else if (style->type() == QSvgStyleProperty::SOLID_COLOR) { 695 pen.setColor( 696 ((QSvgSolidColorStyle*)style)->qcolor()); 697 } 698 } else { 699 qWarning()<<"QSvgHandler::parsePen could not resolve property" << idFromUrl(value); 700 } 701 } else { 702 QColor color; 703 if (constructColor(value, opacity, color, handler)) 704 pen.setColor(color); 705 } 706 //since we could inherit stroke="none" 707 //we need to reset the style of our stroke to something 708 pen.setStyle(Qt::SolidLine); 709 } 710 if (!width.isEmpty()) { 711 QSvgHandler::LengthType lt; 712 qreal widthF = parseLength(width, lt, handler); 713 //### fixme 714 if (!widthF) { 715 pen.setStyle(Qt::NoPen); 716 return; 717 } 718 pen.setWidthF(widthF); 719 } 720 qreal penw = pen.widthF(); 721 722 if (!linejoin.isEmpty()) { 723 if (linejoin == QLatin1String("miter")) 724 pen.setJoinStyle(Qt::SvgMiterJoin); 725 else if (linejoin == QLatin1String("round")) 726 pen.setJoinStyle(Qt::RoundJoin); 727 else if (linejoin == QLatin1String("bevel")) 728 pen.setJoinStyle(Qt::BevelJoin); 729 } 730 if (!miterlimit.isEmpty()) 731 pen.setMiterLimit(toDouble(miterlimit)); 732 733 if (!linecap.isEmpty()) { 734 if (linecap == QLatin1String("butt")) 735 pen.setCapStyle(Qt::FlatCap); 736 else if (linecap == QLatin1String("round")) 737 pen.setCapStyle(Qt::RoundCap); 738 else if (linecap == QLatin1String("square")) 739 pen.setCapStyle(Qt::SquareCap); 740 } 741 742 if (!dashArray.isEmpty()) { 743 const QChar *s = dashArray.constData(); 744 QVector<qreal> dashes = parseNumbersList(s); 745 qreal *d = dashes.data(); 746 if (penw != 0) 747 for (int i = 0; i < dashes.size(); ++i) { 748 *d /= penw; 749 ++d; 750 } 751 pen.setDashPattern(dashes); 752 } 753 if (!dashOffset.isEmpty()) { 754 pen.setDashOffset(toDouble(dashOffset)); 755 } 756 757 } else { 758 pen.setStyle(Qt::NoPen); 759 } 760 } 761 } 762 763 static QMatrix parseTransformationMatrix(const QString &value) 764 { 1021 prop->setBrush(QBrush(Qt::NoBrush)); 1022 } 1023 } 1024 node->appendStyleProperty(prop, attributes.id); 1025 } 1026 } 1027 1028 1029 1030 static QMatrix parseTransformationMatrix(const QStringRef &value) 1031 { 1032 if (value.isEmpty()) 1033 return QMatrix(); 1034 765 1035 QMatrix matrix; 766 1036 const QChar *str = value.constData(); 767 768 while (*str != QLatin1Char(0)) { 1037 const QChar *end = str + value.length(); 1038 1039 while (str < end) { 769 1040 if (str->isSpace() || *str == QLatin1Char(',')) { 770 1041 ++str; … … 831 1102 832 1103 833 while (str ->isSpace())1104 while (str < end && str->isSpace()) 834 1105 ++str; 835 1106 if (*str != QLatin1Char('(')) 836 1107 goto error; 837 1108 ++str; 838 QVector<qreal> points = parseNumbersList(str); 1109 QVarLengthArray<qreal, 8> points; 1110 parseNumbersArray(str, points); 839 1111 if (*str != QLatin1Char(')')) 840 1112 goto error; … … 876 1148 goto error; 877 1149 const qreal deg2rad = qreal(0.017453292519943295769); 878 matrix.shear( tan(points[0]*deg2rad), 0);1150 matrix.shear(qTan(points[0]*deg2rad), 0); 879 1151 } else if (state == SkewY) { 880 1152 if (points.count() != 1) 881 1153 goto error; 882 1154 const qreal deg2rad = qreal(0.017453292519943295769); 883 matrix.shear(0, tan(points[0]*deg2rad));1155 matrix.shear(0, qTan(points[0]*deg2rad)); 884 1156 } 885 1157 } … … 892 1164 QSvgHandler *handler) 893 1165 { 894 QString value = attributes.value(QLatin1String("stroke")).toString();895 QString dashArray = attributes.value(QLatin1String("stroke-dasharray")).toString();896 QString dashOffset = attributes.value(QLatin1String("stroke-dashoffset")).toString();897 QString linecap = attributes.value(QLatin1String("stroke-linecap")).toString();898 QString linejoin = attributes.value(QLatin1String("stroke-linejoin")).toString();899 QString miterlimit = attributes.value(QLatin1String("stroke-miterlimit")).toString();900 QString opacity = attributes.value(QLatin1String("stroke-opacity")).toString();901 QString width = attributes.value(QLatin1String("stroke-width")).toString();902 QString myId = someId(attributes);903 904 1166 //qDebug()<<"Node "<<node->type()<<", attrs are "<<value<<width; 905 1167 906 if (!value.isEmpty() || !width.isEmpty() || !linecap.isEmpty() || !linejoin.isEmpty()) { 907 if (value != QLatin1String("none")) { 908 QSvgStrokeStyle *inherited = 909 static_cast<QSvgStrokeStyle*>(node->styleProperty( 910 QSvgStyleProperty::STROKE)); 911 if (!inherited) 912 inherited = static_cast<QSvgStrokeStyle*>(node->parent()->styleProperty( 913 QSvgStyleProperty::STROKE)); 914 QPen pen(handler->defaultPen()); 915 if (inherited) 916 pen = inherited->qpen(); 917 918 if (!value.isEmpty()) { 919 if (value.startsWith(QLatin1String("url"))) { 920 value = value.remove(0, 3); 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(); 921 1180 QSvgStyleProperty *style = styleFromUrl(node, value); 922 1181 if (style) { 923 if (style->type() == QSvgStyleProperty::GRADIENT) { 924 QBrush b(*((QSvgGradientStyle*)style)->qgradient()); 925 pen.setBrush(b); 926 } else if (style->type() == QSvgStyleProperty::SOLID_COLOR) { 927 pen.setColor( 928 ((QSvgSolidColorStyle*)style)->qcolor()); 929 } 1182 if (style->type() == QSvgStyleProperty::SOLID_COLOR || style->type() == QSvgStyleProperty::GRADIENT) 1183 prop->setStyle(reinterpret_cast<QSvgFillStyleProperty *>(style)); 930 1184 } else { 931 qWarning() << "QSvgHandler::parsePen could not resolve property" << idFromUrl(value); 1185 QString id = idFromUrl(value); 1186 prop->setGradientId(id); 1187 prop->setGradientResolved(false); 932 1188 } 933 } else { 934 QColor color; 935 if (constructColor(value, opacity, color, handler)) 936 pen.setColor(color); 937 } 938 //since we could inherit stroke="none" 939 //we need to reset the style of our stroke to something 940 pen.setStyle(Qt::SolidLine); 941 } 942 if (!width.isEmpty()) { 943 QSvgHandler::LengthType lt; 944 qreal widthF = parseLength(width, lt, handler); 945 //### fixme 946 if (!widthF) { 947 pen.setStyle(Qt::NoPen); 948 return; 949 } 950 pen.setWidthF(widthF); 951 } 952 953 if (!linejoin.isEmpty()) { 954 if (linejoin == QLatin1String("miter")) 955 pen.setJoinStyle(Qt::SvgMiterJoin); 956 else if (linejoin == QLatin1String("round")) 957 pen.setJoinStyle(Qt::RoundJoin); 958 else if (linejoin == QLatin1String("bevel")) 959 pen.setJoinStyle(Qt::BevelJoin); 960 } 961 962 if (!linecap.isEmpty()) { 963 if (linecap == QLatin1String("butt")) 964 pen.setCapStyle(Qt::FlatCap); 965 else if (linecap == QLatin1String("round")) 966 pen.setCapStyle(Qt::RoundCap); 967 else if (linecap == QLatin1String("square")) 968 pen.setCapStyle(Qt::SquareCap); 969 } 970 971 qreal penw = pen.widthF(); 972 if (!dashArray.isEmpty()) { 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) { 1200 QSvgHandler::LengthType lt; 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(); 973 1210 const QChar *s = dashArray.constData(); 974 1211 QVector<qreal> dashes = parseNumbersList(s); 975 qreal *d = dashes.data();976 if(penw != 0)977 for (int i = 0; i < dashes.size(); ++i) {978 *d /= penw;979 ++d;980 }981 982 1212 // if the dash count is odd the dashes should be duplicated 983 if ( dashes.size() % 2!= 0)1213 if ((dashes.size() & 1) != 0) 984 1214 dashes << QVector<qreal>(dashes); 985 986 pen.setDashPattern(dashes); 987 } 988 if (!dashOffset.isEmpty()) { 989 qreal doffset = toDouble(dashOffset); 990 if (penw != 0) 991 doffset /= penw; 992 pen.setDashOffset(doffset); 993 } 994 if (!miterlimit.isEmpty()) 995 pen.setMiterLimit(toDouble(miterlimit)); 996 997 node->appendStyleProperty(new QSvgStrokeStyle(pen), myId); 998 } else { 999 QPen pen(handler->defaultPen()); 1000 pen.setStyle(Qt::NoPen); 1001 node->appendStyleProperty(new QSvgStrokeStyle(pen), myId); 1002 } 1003 } 1004 } 1005 1006 1007 static bool parseQBrush(const QSvgAttributes &attributes, QSvgNode *node, 1008 QBrush &brush, QSvgHandler *handler) 1009 { 1010 QString value = attributes.value(QLatin1String("fill")).toString(); 1011 QString opacity = attributes.value(QLatin1String("fill-opacity")).toString(); 1012 1013 QColor color; 1014 if (!value.isEmpty() || !opacity.isEmpty()) { 1015 if (value.startsWith(QLatin1String("url"))) { 1016 value = value.remove(0, 3); 1017 QSvgStyleProperty *style = styleFromUrl(node, value); 1018 if (style) { 1019 switch (style->type()) { 1020 case QSvgStyleProperty::FILL: 1021 { 1022 brush = static_cast<QSvgFillStyle*>(style)->qbrush(); 1023 break; 1024 } 1025 case QSvgStyleProperty::SOLID_COLOR: 1026 { 1027 brush = QBrush(static_cast<QSvgSolidColorStyle*>(style)->qcolor()); 1028 break; 1029 } 1030 case QSvgStyleProperty::GRADIENT: 1031 { 1032 brush = QBrush(*static_cast<QSvgGradientStyle*>(style)->qgradient()); 1033 break; 1034 } 1035 default: 1036 qWarning("Cannot use property \"%s\" as brush.", qPrintable(idFromUrl(value))); 1037 } 1038 } else { 1039 qWarning("Couldn't resolve property: %s", qPrintable(idFromUrl(value))); 1040 } 1041 } else if (value != QLatin1String("none")) { 1042 if (constructColor(value, opacity, color, handler)) { 1043 brush.setStyle(Qt::SolidPattern); 1044 brush.setColor(color); 1045 } 1046 } else { 1047 brush = QBrush(Qt::NoBrush); 1048 } 1049 return true; 1050 } 1051 return false; 1052 } 1053 1054 static bool parseQFont(const QSvgAttributes &attributes, 1055 QFont &font, qreal &fontSize, QSvgHandler *handler) 1056 { 1057 QString family = attributes.value(QLatin1String("font-family")).toString(); 1058 QString size = attributes.value(QLatin1String("font-size")).toString(); 1059 QString style = attributes.value(QLatin1String("font-style")).toString(); 1060 QString weight = attributes.value(QLatin1String("font-weight")).toString(); 1061 1062 if (!family.isEmpty() || !size.isEmpty() || 1063 !style.isEmpty() || !weight.isEmpty()) { 1064 1065 if (!family.isEmpty()) { 1066 font.setFamily(family.trimmed()); 1067 } 1068 if (!size.isEmpty()) { 1069 QSvgHandler::LengthType dummy; // should always be pixel size 1070 fontSize = parseLength(size, dummy, handler); 1071 if (fontSize <= 0) 1072 fontSize = 1; 1073 font.setPixelSize(qMax(1, int(fontSize))); 1074 } 1075 if (!style.isEmpty()) { 1076 if (style == QLatin1String("normal")) { 1077 font.setStyle(QFont::StyleNormal); 1078 } else if (style == QLatin1String("italic")) { 1079 font.setStyle(QFont::StyleItalic); 1080 } else if (style == QLatin1String("oblique")) { 1081 font.setStyle(QFont::StyleOblique); 1082 } else if (style == QLatin1String("inherit")) { 1083 //inherited already 1084 } 1085 } 1086 if (!weight.isEmpty()) { 1087 bool ok = false; 1088 int weightNum = weight.toInt(&ok); 1089 if (ok) { 1090 switch (weightNum) { 1091 case 100: 1092 case 200: 1093 font.setWeight(QFont::Light); 1094 break; 1095 case 300: 1096 case 400: 1097 font.setWeight(QFont::Normal); 1098 break; 1099 case 500: 1100 case 600: 1101 font.setWeight(QFont::DemiBold); 1102 break; 1103 case 700: 1104 case 800: 1105 font.setWeight(QFont::Bold); 1106 break; 1107 case 900: 1108 font.setWeight(QFont::Black); 1109 break; 1110 default: 1111 break; 1112 } 1113 } else { 1114 if (weight == QLatin1String("normal")) { 1115 font.setWeight(QFont::Normal); 1116 } else if (weight == QLatin1String("bold")) { 1117 font.setWeight(QFont::Bold); 1118 } else if (weight == QLatin1String("bolder")) { 1119 font.setWeight(QFont::DemiBold); 1120 } else if (weight == QLatin1String("lighter")) { 1121 font.setWeight(QFont::Light); 1122 } 1123 } 1124 } 1125 // QFontInfo fi(font); 1126 // font.setPointSize(fi.pointSize()); 1127 return true; 1128 } 1129 1130 return false; 1215 prop->setDashArray(dashes); 1216 } 1217 } 1218 1219 //stroke-linejoin attribute handling 1220 if (!attributes.strokeLineJoin.isEmpty()) { 1221 if (attributes.strokeLineJoin == QLatin1String("miter")) 1222 prop->setLineJoin(Qt::SvgMiterJoin); 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 } 1131 1261 } 1132 1262 … … 1135 1265 QSvgHandler *handler) 1136 1266 { 1137 QFont font; 1138 font.setPixelSize(12); 1139 qreal fontSize = font.pixelSize(); 1140 1141 QSvgFontStyle *inherited = 1142 static_cast<QSvgFontStyle*>(node->styleProperty( 1143 QSvgStyleProperty::FONT)); 1144 if (!inherited) 1145 inherited = 1146 static_cast<QSvgFontStyle*>(node->parent()->styleProperty( 1147 QSvgStyleProperty::FONT)); 1148 if (inherited) { 1149 font = inherited->qfont(); 1150 fontSize = inherited->pointSize(); 1151 } 1152 if (parseQFont(attributes, font, fontSize, handler)) { 1153 QString myId = someId(attributes); 1154 QString anchor = attributes.value(QLatin1String("text-anchor")).toString(); 1155 QSvgTinyDocument *doc = node->document(); 1156 QSvgFontStyle *fontStyle = 0; 1157 QString family = (font.family().isEmpty())?myId:font.family(); 1158 if (!family.isEmpty()) { 1159 QSvgFont *svgFont = doc->svgFont(family); 1160 if (svgFont) { 1161 fontStyle = new QSvgFontStyle(svgFont, doc); 1162 fontStyle->setPointSize(fontSize); 1163 } 1164 } 1165 if (!fontStyle) { 1166 fontStyle = new QSvgFontStyle(font, node->document()); 1167 fontStyle->setPointSize(fontSize); 1168 } 1169 if (!anchor.isEmpty()) 1170 fontStyle->setTextAnchor(anchor); 1171 1172 node->appendStyleProperty(fontStyle, myId); 1173 } 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 QSvgHandler::LengthType dummy; // should always be pixel size 1286 fontStyle->setSize(parseLength(attributes.fontSize.toString(), dummy, handler)); 1287 } 1288 1289 if (!attributes.fontStyle.isEmpty() && attributes.fontStyle != QT_INHERIT) { 1290 if (attributes.fontStyle == QLatin1String("normal")) { 1291 fontStyle->setStyle(QFont::StyleNormal); 1292 } else if (attributes.fontStyle == QLatin1String("italic")) { 1293 fontStyle->setStyle(QFont::StyleItalic); 1294 } else if (attributes.fontStyle == QLatin1String("oblique")) { 1295 fontStyle->setStyle(QFont::StyleOblique); 1296 } 1297 } 1298 1299 if (!attributes.fontWeight.isEmpty() && attributes.fontWeight != QT_INHERIT) { 1300 bool ok = false; 1301 int weightNum = attributes.fontWeight.toString().toInt(&ok); 1302 if (ok) { 1303 fontStyle->setWeight(weightNum); 1304 } else { 1305 if (attributes.fontWeight == QLatin1String("normal")) { 1306 fontStyle->setWeight(400); 1307 } else if (attributes.fontWeight == QLatin1String("bold")) { 1308 fontStyle->setWeight(700); 1309 } else if (attributes.fontWeight == QLatin1String("bolder")) { 1310 fontStyle->setWeight(QSvgFontStyle::BOLDER); 1311 } else if (attributes.fontWeight == QLatin1String("lighter")) { 1312 fontStyle->setWeight(QSvgFontStyle::LIGHTER); 1313 } 1314 } 1315 } 1316 1317 if (!attributes.fontVariant.isEmpty() && attributes.fontVariant != QT_INHERIT) { 1318 if (attributes.fontVariant == QLatin1String("normal")) 1319 fontStyle->setVariant(QFont::MixedCase); 1320 else if (attributes.fontVariant == QLatin1String("small-caps")) 1321 fontStyle->setVariant(QFont::SmallCaps); 1322 } 1323 1324 if (!attributes.textAnchor.isEmpty() && attributes.textAnchor != QT_INHERIT) { 1325 if (attributes.textAnchor == QLatin1String("start")) 1326 fontStyle->setTextAnchor(Qt::AlignLeft); 1327 if (attributes.textAnchor == QLatin1String("middle")) 1328 fontStyle->setTextAnchor(Qt::AlignHCenter); 1329 else if (attributes.textAnchor == QLatin1String("end")) 1330 fontStyle->setTextAnchor(Qt::AlignRight); 1331 } 1332 1333 node->appendStyleProperty(fontStyle, attributes.id); 1174 1334 } 1175 1335 … … 1178 1338 QSvgHandler *) 1179 1339 { 1180 QString value = attributes.value(QLatin1String("transform")).toString(); 1181 QString myId = someId(attributes); 1182 value = value.trimmed(); 1183 if (value.isEmpty()) 1340 if (attributes.transform.isEmpty()) 1184 1341 return; 1185 QMatrix matrix = parseTransformationMatrix( value);1342 QMatrix matrix = parseTransformationMatrix(trimRef(attributes.transform)); 1186 1343 1187 1344 if (!matrix.isIdentity()) { 1188 node->appendStyleProperty(new QSvgTransformStyle(QTransform(matrix)), myId);1345 node->appendStyleProperty(new QSvgTransformStyle(QTransform(matrix)), attributes.id); 1189 1346 } 1190 1347 … … 1195 1352 QSvgHandler *) 1196 1353 { 1197 QString value = attributes.value(QLatin1String("visibility")).toString();1198 1354 QSvgNode *parent = node->parent(); 1199 1355 1200 if (parent && ( value.isEmpty() || value == QLatin1String("inherit")))1356 if (parent && (attributes.visibility.isEmpty() || attributes.visibility == QT_INHERIT)) 1201 1357 node->setVisible(parent->isVisible()); 1202 else if ( value == QLatin1String("hidden") || value== QLatin1String("collapse")) {1358 else if (attributes.visibility == QLatin1String("hidden") || attributes.visibility == QLatin1String("collapse")) { 1203 1359 node->setVisible(false); 1204 1360 } else … … 1326 1482 /* (xc, yc) is center of the circle. */ 1327 1483 1328 th0 = atan2(y0 - yc, x0 - xc);1329 th1 = atan2(y1 - yc, x1 - xc);1484 th0 = qAtan2(y0 - yc, x0 - xc); 1485 th1 = qAtan2(y1 - yc, x1 - xc); 1330 1486 1331 1487 th_arc = th1 - th0; … … 1355 1511 1356 1512 while (str != end) { 1357 while ( *str == QLatin1Char(' '))1513 while (str->isSpace()) 1358 1514 ++str; 1359 1515 QChar pathElem = *str; 1360 1516 ++str; 1361 1517 QChar endc = *end; 1362 *const_cast<QChar *>(end) = 0; // parseNumbersList requires 0-termination that QStringRef cannot guarantee 1363 QVector<qreal> arg = parseNumbersList(str); 1518 *const_cast<QChar *>(end) = 0; // parseNumbersArray requires 0-termination that QStringRef cannot guarantee 1519 QVarLengthArray<qreal, 8> arg; 1520 parseNumbersArray(str, arg); 1364 1521 *const_cast<QChar *>(end) = endc; 1365 1522 if (pathElem == QLatin1Char('z') || pathElem == QLatin1Char('Z')) 1366 1523 arg.append(0);//dummy 1367 while (!arg.isEmpty()) { 1524 const qreal *num = arg.constData(); 1525 int count = arg.count(); 1526 while (count > 0) { 1368 1527 qreal offsetX = x; // correction offsets 1369 1528 qreal offsetY = y; // for relative commands 1370 1529 switch (pathElem.unicode()) { 1371 1530 case 'm': { 1372 if (arg.count() < 2) { 1373 arg.pop_front(); 1531 if (count < 2) { 1532 num++; 1533 count--; 1374 1534 break; 1375 1535 } 1376 x = x0 = arg[0] + offsetX; 1377 y = y0 = arg[1] + offsetY; 1536 x = x0 = num[0] + offsetX; 1537 y = y0 = num[1] + offsetY; 1538 num += 2; 1539 count -= 2; 1378 1540 path.moveTo(x0, y0); 1379 arg.pop_front(); arg.pop_front(); 1541 1542 // As per 1.2 spec 8.3.2 The "moveto" commands 1543 // If a 'moveto' is followed by multiple pairs of coordinates without explicit commands, 1544 // the subsequent pairs shall be treated as implicit 'lineto' commands. 1545 pathElem = QLatin1Char('l'); 1380 1546 } 1381 1547 break; 1382 1548 case 'M': { 1383 if (arg.count() < 2) { 1384 arg.pop_front(); 1549 if (count < 2) { 1550 num++; 1551 count--; 1385 1552 break; 1386 1553 } 1387 x = x0 = arg[0]; 1388 y = y0 = arg[1]; 1389 1554 x = x0 = num[0]; 1555 y = y0 = num[1]; 1556 num += 2; 1557 count -= 2; 1390 1558 path.moveTo(x0, y0); 1391 arg.pop_front(); arg.pop_front(); 1559 1560 // As per 1.2 spec 8.3.2 The "moveto" commands 1561 // If a 'moveto' is followed by multiple pairs of coordinates without explicit commands, 1562 // the subsequent pairs shall be treated as implicit 'lineto' commands. 1563 pathElem = QLatin1Char('L'); 1392 1564 } 1393 1565 break; … … 1396 1568 x = x0; 1397 1569 y = y0; 1570 count--; // skip dummy 1571 num++; 1398 1572 path.closeSubpath(); 1399 arg.pop_front();//pop dummy1400 1573 } 1401 1574 break; 1402 1575 case 'l': { 1403 if (arg.count() < 2) { 1404 arg.pop_front(); 1576 if (count < 2) { 1577 num++; 1578 count--; 1405 1579 break; 1406 1580 } 1407 x = arg.front()+ offsetX;1408 arg.pop_front();1409 y = arg.front() + offsetY;1410 arg.pop_front();1581 x = num[0] + offsetX; 1582 y = num[1] + offsetY; 1583 num += 2; 1584 count -= 2; 1411 1585 path.lineTo(x, y); 1412 1586 … … 1414 1588 break; 1415 1589 case 'L': { 1416 if (arg.count() < 2) { 1417 arg.pop_front(); 1590 if (count < 2) { 1591 num++; 1592 count--; 1418 1593 break; 1419 1594 } 1420 x = arg.front(); arg.pop_front(); 1421 y = arg.front(); arg.pop_front(); 1595 x = num[0]; 1596 y = num[1]; 1597 num += 2; 1598 count -= 2; 1422 1599 path.lineTo(x, y); 1423 1600 } 1424 1601 break; 1425 1602 case 'h': { 1426 x = arg.front() + offsetX; arg.pop_front(); 1603 x = num[0] + offsetX; 1604 num++; 1605 count--; 1427 1606 path.lineTo(x, y); 1428 1607 } 1429 1608 break; 1430 1609 case 'H': { 1431 x = arg[0]; 1610 x = num[0]; 1611 num++; 1612 count--; 1432 1613 path.lineTo(x, y); 1433 arg.pop_front();1434 1614 } 1435 1615 break; 1436 1616 case 'v': { 1437 y = arg[0] + offsetY; 1617 y = num[0] + offsetY; 1618 num++; 1619 count--; 1438 1620 path.lineTo(x, y); 1439 arg.pop_front();1440 1621 } 1441 1622 break; 1442 1623 case 'V': { 1443 y = arg[0]; 1624 y = num[0]; 1625 num++; 1626 count--; 1444 1627 path.lineTo(x, y); 1445 arg.pop_front();1446 1628 } 1447 1629 break; 1448 1630 case 'c': { 1449 if ( arg.count()< 6) {1450 while (arg.count())1451 arg.pop_front();1631 if (count < 6) { 1632 num += count; 1633 count = 0; 1452 1634 break; 1453 1635 } 1454 QPointF c1(arg[0]+offsetX, arg[1]+offsetY); 1455 QPointF c2(arg[2]+offsetX, arg[3]+offsetY); 1456 QPointF e(arg[4]+offsetX, arg[5]+offsetY); 1636 QPointF c1(num[0] + offsetX, num[1] + offsetY); 1637 QPointF c2(num[2] + offsetX, num[3] + offsetY); 1638 QPointF e(num[4] + offsetX, num[5] + offsetY); 1639 num += 6; 1640 count -= 6; 1457 1641 path.cubicTo(c1, c2, e); 1458 1642 ctrlPt = c2; 1459 1643 x = e.x(); 1460 1644 y = e.y(); 1461 arg.pop_front(); arg.pop_front();1462 arg.pop_front(); arg.pop_front();1463 arg.pop_front(); arg.pop_front();1464 1645 break; 1465 1646 } 1466 1647 case 'C': { 1467 if ( arg.count()< 6) {1468 while (arg.count())1469 arg.pop_front();1648 if (count < 6) { 1649 num += count; 1650 count = 0; 1470 1651 break; 1471 1652 } 1472 QPointF c1(arg[0], arg[1]); 1473 QPointF c2(arg[2], arg[3]); 1474 QPointF e(arg[4], arg[5]); 1653 QPointF c1(num[0], num[1]); 1654 QPointF c2(num[2], num[3]); 1655 QPointF e(num[4], num[5]); 1656 num += 6; 1657 count -= 6; 1475 1658 path.cubicTo(c1, c2, e); 1476 1659 ctrlPt = c2; 1477 1660 x = e.x(); 1478 1661 y = e.y(); 1479 arg.pop_front(); arg.pop_front();1480 arg.pop_front(); arg.pop_front();1481 arg.pop_front(); arg.pop_front();1482 1662 break; 1483 1663 } 1484 1664 case 's': { 1485 if ( arg.count()< 4) {1486 while (arg.count())1487 arg.pop_front();1665 if (count < 4) { 1666 num += count; 1667 count = 0; 1488 1668 break; 1489 1669 } … … 1494 1674 else 1495 1675 c1 = QPointF(x, y); 1496 QPointF c2(arg[0]+offsetX, arg[1]+offsetY); 1497 QPointF e(arg[2]+offsetX, arg[3]+offsetY); 1676 QPointF c2(num[0] + offsetX, num[1] + offsetY); 1677 QPointF e(num[2] + offsetX, num[3] + offsetY); 1678 num += 4; 1679 count -= 4; 1498 1680 path.cubicTo(c1, c2, e); 1499 1681 ctrlPt = c2; 1500 1682 x = e.x(); 1501 1683 y = e.y(); 1502 arg.pop_front(); arg.pop_front();1503 arg.pop_front(); arg.pop_front();1504 1684 break; 1505 1685 } 1506 1686 case 'S': { 1507 if ( arg.count()< 4) {1508 while (arg.count())1509 arg.pop_front();1687 if (count < 4) { 1688 num += count; 1689 count = 0; 1510 1690 break; 1511 1691 } … … 1516 1696 else 1517 1697 c1 = QPointF(x, y); 1518 QPointF c2(arg[0], arg[1]); 1519 QPointF e(arg[2], arg[3]); 1698 QPointF c2(num[0], num[1]); 1699 QPointF e(num[2], num[3]); 1700 num += 4; 1701 count -= 4; 1520 1702 path.cubicTo(c1, c2, e); 1521 1703 ctrlPt = c2; 1522 1704 x = e.x(); 1523 1705 y = e.y(); 1524 arg.pop_front(); arg.pop_front();1525 arg.pop_front(); arg.pop_front();1526 1706 break; 1527 1707 } 1528 1708 case 'q': { 1529 if ( arg.count()< 4) {1530 while (arg.count())1531 arg.pop_front();1709 if (count < 4) { 1710 num += count; 1711 count = 0; 1532 1712 break; 1533 1713 } 1534 QPointF c(arg[0]+offsetX, arg[1]+offsetY); 1535 QPointF e(arg[2]+offsetX, arg[3]+offsetY); 1714 QPointF c(num[0] + offsetX, num[1] + offsetY); 1715 QPointF e(num[2] + offsetX, num[3] + offsetY); 1716 num += 4; 1717 count -= 4; 1536 1718 path.quadTo(c, e); 1537 1719 ctrlPt = c; 1538 1720 x = e.x(); 1539 1721 y = e.y(); 1540 arg.pop_front(); arg.pop_front();1541 arg.pop_front(); arg.pop_front();1542 1722 break; 1543 1723 } 1544 1724 case 'Q': { 1545 if ( arg.count()< 4) {1546 while (arg.count())1547 arg.pop_front();1725 if (count < 4) { 1726 num += count; 1727 count = 0; 1548 1728 break; 1549 1729 } 1550 QPointF c(arg[0], arg[1]); 1551 QPointF e(arg[2], arg[3]); 1730 QPointF c(num[0], num[1]); 1731 QPointF e(num[2], num[3]); 1732 num += 4; 1733 count -= 4; 1552 1734 path.quadTo(c, e); 1553 1735 ctrlPt = c; 1554 1736 x = e.x(); 1555 1737 y = e.y(); 1556 arg.pop_front(); arg.pop_front();1557 arg.pop_front(); arg.pop_front();1558 1738 break; 1559 1739 } 1560 1740 case 't': { 1561 if ( arg.count()< 2) {1562 while (arg.count())1563 arg.pop_front();1741 if (count < 2) { 1742 num += count; 1743 count = 0; 1564 1744 break; 1565 1745 } 1566 QPointF e(arg[0]+offsetX, arg[1]+offsetY); 1746 QPointF e(num[0] + offsetX, num[1] + offsetY); 1747 num += 2; 1748 count -= 2; 1567 1749 QPointF c; 1568 1750 if (lastMode == 'q' || lastMode == 'Q' || … … 1575 1757 x = e.x(); 1576 1758 y = e.y(); 1577 arg.pop_front(); arg.pop_front();1578 1759 break; 1579 1760 } 1580 1761 case 'T': { 1581 if ( arg.count()< 2) {1582 while (arg.count())1583 arg.pop_front();1762 if (count < 2) { 1763 num += count; 1764 count = 0; 1584 1765 break; 1585 1766 } 1586 QPointF e(arg[0], arg[1]); 1767 QPointF e(num[0], num[1]); 1768 num += 2; 1769 count -= 2; 1587 1770 QPointF c; 1588 1771 if (lastMode == 'q' || lastMode == 'Q' || … … 1595 1778 x = e.x(); 1596 1779 y = e.y(); 1597 arg.pop_front(); arg.pop_front();1598 1780 break; 1599 1781 } 1600 1782 case 'a': { 1601 if ( arg.count()< 7) {1602 while (arg.count())1603 arg.pop_front();1783 if (count < 7) { 1784 num += count; 1785 count = 0; 1604 1786 break; 1605 1787 } 1606 qreal rx = arg[0]; 1607 qreal ry = arg[1]; 1608 qreal xAxisRotation = arg[2]; 1609 qreal largeArcFlag = arg[3]; 1610 qreal sweepFlag = arg[4]; 1611 qreal ex = arg[5] + offsetX; 1612 qreal ey = arg[6] + offsetY; 1788 qreal rx = (*num++); 1789 qreal ry = (*num++); 1790 qreal xAxisRotation = (*num++); 1791 qreal largeArcFlag = (*num++); 1792 qreal sweepFlag = (*num++); 1793 qreal ex = (*num++) + offsetX; 1794 qreal ey = (*num++) + offsetY; 1795 count -= 7; 1613 1796 qreal curx = x; 1614 1797 qreal cury = y; … … 1618 1801 x = ex; 1619 1802 y = ey; 1620 1621 arg.pop_front(); arg.pop_front();1622 arg.pop_front(); arg.pop_front();1623 arg.pop_front(); arg.pop_front();1624 arg.pop_front();1625 1803 } 1626 1804 break; 1627 1805 case 'A': { 1628 if ( arg.count()< 7) {1629 while (arg.count())1630 arg.pop_front();1806 if (count < 7) { 1807 num += count; 1808 count = 0; 1631 1809 break; 1632 1810 } 1633 qreal rx = arg[0]; 1634 qreal ry = arg[1]; 1635 qreal xAxisRotation = arg[2]; 1636 qreal largeArcFlag = arg[3]; 1637 qreal sweepFlag = arg[4]; 1638 qreal ex = arg[5]; 1639 qreal ey = arg[6]; 1811 qreal rx = (*num++); 1812 qreal ry = (*num++); 1813 qreal xAxisRotation = (*num++); 1814 qreal largeArcFlag = (*num++); 1815 qreal sweepFlag = (*num++); 1816 qreal ex = (*num++); 1817 qreal ey = (*num++); 1818 count -= 7; 1640 1819 qreal curx = x; 1641 1820 qreal cury = y; 1642 1821 pathArc(path, rx, ry, xAxisRotation, int(largeArcFlag), 1643 1822 int(sweepFlag), ex, ey, curx, cury); 1823 1644 1824 x = ex; 1645 1825 y = ey; 1646 arg.pop_front(); arg.pop_front();1647 arg.pop_front(); arg.pop_front();1648 arg.pop_front(); arg.pop_front();1649 arg.pop_front();1650 1826 } 1651 1827 break; … … 1674 1850 if (decl.d->property.isEmpty()) 1675 1851 continue; 1676 if (decl.d->values.count() != 1)1677 continue;1678 1852 QCss::Value val = decl.d->values.first(); 1679 QString valueStr = val.toString(); 1853 QString valueStr; 1854 if (decl.d->values.count() != 1) { 1855 for (int i=0; i<decl.d->values.count(); ++i) { 1856 const QString &value = decl.d->values[i].toString(); 1857 if (value.isEmpty()) 1858 valueStr += QLatin1Char(','); 1859 else 1860 valueStr += value; 1861 } 1862 } else { 1863 valueStr = val.toString(); 1864 } 1680 1865 if (val.type == QCss::Value::Uri) { 1681 1866 valueStr.prepend(QLatin1String("url(")); … … 1790 1975 } 1791 1976 1792 static bool parseDefaultTextStyle(QSvgNode *node,1793 const QXmlStreamAttributes &attributes,1794 bool initial,1795 QSvgHandler *handler)1796 {1797 Q_ASSERT(node->type() == QSvgText::TEXT || node->type() == QSvgNode::TEXTAREA);1798 QSvgText *textNode = static_cast<QSvgText*>(node);1799 1800 QSvgAttributes attrs(attributes, handler);1801 1802 QString fontFamily = attrs.value(QString(), QLatin1String("font-family")).toString();1803 1804 QString anchor = attrs.value(QString(), QLatin1String("text-anchor")).toString();1805 1806 QSvgFontStyle *fontStyle = static_cast<QSvgFontStyle*>(1807 node->styleProperty(QSvgStyleProperty::FONT));1808 if (fontStyle) {1809 QSvgTinyDocument *doc = fontStyle->doc();1810 if (doc && fontStyle->svgFont()) {1811 cssStyleLookup(node, handler, handler->selector());1812 parseStyle(node, attrs, handler);1813 return true;1814 }1815 } else if (!fontFamily.isEmpty()) {1816 QSvgTinyDocument *doc = node->document();1817 QSvgFont *svgFont = doc->svgFont(fontFamily);1818 if (svgFont) {1819 cssStyleLookup(node, handler, handler->selector());1820 parseStyle(node, attrs, handler);1821 return true;1822 }1823 }1824 1825 QTextCharFormat format;1826 QBrush brush(QColor(0, 0, 0));1827 QFont font;1828 font.setPixelSize(12);1829 qreal fontSize = font.pixelSize();1830 1831 if (!initial) {1832 font = textNode->topFormat().font();1833 fontSize = font.pixelSize() / textNode->scale();1834 brush = textNode->topFormat().foreground();1835 } else {1836 QSvgFontStyle *fontStyle = static_cast<QSvgFontStyle*>(1837 node->styleProperty(QSvgStyleProperty::FONT));1838 if (!fontStyle)1839 fontStyle = static_cast<QSvgFontStyle*>(1840 node->parent()->styleProperty(QSvgStyleProperty::FONT));1841 if (fontStyle) {1842 font = fontStyle->qfont();1843 fontSize = fontStyle->pointSize();1844 if (anchor.isEmpty())1845 anchor = fontStyle->textAnchor();1846 }1847 1848 Qt::Alignment align = Qt::AlignLeft;1849 if (anchor == QLatin1String("middle"))1850 align = Qt::AlignHCenter;1851 else if (anchor == QLatin1String("end"))1852 align = Qt::AlignRight;1853 textNode->setTextAlignment(align);1854 1855 QSvgFillStyle *fillStyle = static_cast<QSvgFillStyle*>(1856 node->styleProperty(QSvgStyleProperty::FILL));1857 if (fillStyle)1858 brush = fillStyle->qbrush();1859 }1860 1861 if (parseQFont(attrs, font, fontSize, handler) || initial) {1862 if (initial)1863 textNode->setScale(100 / fontSize);1864 font.setPixelSize(qMax(1, int(fontSize * textNode->scale())));1865 format.setFont(font);1866 }1867 1868 if (parseQBrush(attrs, node, brush, handler) || initial) {1869 if (brush.style() != Qt::NoBrush || initial)1870 format.setForeground(brush);1871 }1872 1873 QPen pen(Qt::NoPen);1874 // QSvgStrokeStyle *inherited =1875 // static_cast<QSvgStrokeStyle*>(node->parent()->styleProperty(1876 // QSvgStyleProperty::STROKE));1877 // if (inherited)1878 // pen = inherited->qpen();1879 parseQPen(pen, node, attrs, handler);1880 if (pen.style() != Qt::NoPen) {1881 format.setTextOutline(pen);1882 }1883 1884 parseTransform(node, attrs, handler);1885 1886 textNode->insertFormat(format);1887 1888 return true;1889 }1890 1891 1977 static inline QStringList stringToList(const QString &str) 1892 1978 { … … 1898 1984 const QXmlStreamAttributes &attributes) 1899 1985 { 1900 QString featuresStr = attributes.value(QLatin1String("requiredFeatures")).toString(); 1901 QString extensionsStr = attributes.value(QLatin1String("requiredExtensions")).toString(); 1902 QString languagesStr = attributes.value(QLatin1String("systemLanguage")).toString(); 1903 QString formatsStr = attributes.value(QLatin1String("requiredFormats")).toString(); 1904 QString fontsStr = attributes.value(QLatin1String("requiredFonts")).toString(); 1905 QString nodeIdStr = someId(attributes); 1906 QString xmlClassStr = attributes.value(QLatin1String("class")).toString(); 1907 1908 1909 QStringList features = stringToList(featuresStr); 1910 QStringList extensions = stringToList(extensionsStr); 1911 QStringList languages = stringToList(languagesStr); 1912 QStringList formats = stringToList(formatsStr); 1913 QStringList fonts = stringToList(fontsStr); 1986 QStringList features; 1987 QStringList extensions; 1988 QStringList languages; 1989 QStringList formats; 1990 QStringList fonts; 1991 QString xmlClassStr; 1992 1993 for (int i = 0; i < attributes.count(); ++i) { 1994 const QXmlStreamAttribute &attribute = attributes.at(i); 1995 QStringRef name = attribute.qualifiedName(); 1996 if (name.isEmpty()) 1997 continue; 1998 QStringRef value = attribute.value(); 1999 switch (name.at(0).unicode()) { 2000 case 'c': 2001 if (name == QLatin1String("class")) 2002 xmlClassStr = value.toString(); 2003 break; 2004 case 'r': 2005 if (name == QLatin1String("requiredFeatures")) 2006 features = stringToList(value.toString()); 2007 else if (name == QLatin1String("requiredExtensions")) 2008 extensions = stringToList(value.toString()); 2009 else if (name == QLatin1String("requiredFormats")) 2010 formats = stringToList(value.toString()); 2011 else if (name == QLatin1String("requiredFonts")) 2012 fonts = stringToList(value.toString()); 2013 break; 2014 case 's': 2015 if (name == QLatin1String("systemLanguage")) 2016 languages = stringToList(value.toString()); 2017 break; 2018 default: 2019 break; 2020 } 2021 } 1914 2022 1915 2023 node->setRequiredFeatures(features); … … 1918 2026 node->setRequiredFormats(formats); 1919 2027 node->setRequiredFonts(fonts); 1920 node->setNodeId( nodeIdStr);2028 node->setNodeId(someId(attributes)); 1921 2029 node->setXmlClass(xmlClassStr); 1922 2030 … … 1928 2036 QSvgHandler *) 1929 2037 { 1930 QString value = attributes.value(QLatin1String("opacity")).toString(); 1931 value = value.trimmed(); 2038 if (attributes.opacity.isEmpty()) 2039 return; 2040 2041 const QString value = attributes.opacity.toString().trimmed(); 1932 2042 1933 2043 bool ok = false; … … 1935 2045 1936 2046 if (ok) { 1937 QSvgOpacityStyle *opacity = new QSvgOpacityStyle( op);1938 node->appendStyleProperty(opacity, someId(attributes));2047 QSvgOpacityStyle *opacity = new QSvgOpacityStyle(qBound(qreal(0.0), op, qreal(1.0))); 2048 node->appendStyleProperty(opacity, attributes.id); 1939 2049 } 1940 2050 } … … 2002 2112 QSvgHandler *) 2003 2113 { 2004 QString value = attributes.value(QLatin1String("comp-op")).toString(); 2005 value = value.trimmed(); 2114 if (attributes.compOp.isEmpty()) 2115 return; 2116 QString value = attributes.compOp.toString().trimmed(); 2006 2117 2007 2118 if (!value.isEmpty()) { 2008 2119 QSvgCompOpStyle *compop = new QSvgCompOpStyle(svgToQtCompositionMode(value)); 2009 node->appendStyleProperty(compop, someId(attributes));2120 node->appendStyleProperty(compop, attributes.id); 2010 2121 } 2011 2122 } … … 2047 2158 } else if (str == QLatin1String("none")) { 2048 2159 return QSvgNode::NoneMode; 2049 } else if (str == Q Latin1String("inherit")) {2160 } else if (str == QT_INHERIT) { 2050 2161 return QSvgNode::InheritMode; 2051 2162 } … … 2057 2168 QSvgHandler *) 2058 2169 { 2059 QString displayStr = attributes.value(QLatin1String("display")).toString(); 2060 displayStr = displayStr.trimmed(); 2170 if (attributes.display.isEmpty()) 2171 return; 2172 QString displayStr = attributes.display.toString().trimmed(); 2061 2173 2062 2174 if (!displayStr.isEmpty()) { … … 2136 2248 { 2137 2249 QString typeStr = attributes.value(QLatin1String("type")).toString(); 2138 QString fromStr = attributes.value(QLatin1String("from")).toString();2139 QString toStr = attributes.value(QLatin1String("to")).toString();2250 QStringRef fromStr = attributes.value(QLatin1String("from")); 2251 QStringRef toStr = attributes.value(QLatin1String("to")); 2140 2252 QString valuesStr = attributes.value(QLatin1String("values")).toString(); 2141 2253 QString beginStr = attributes.value(QLatin1String("begin")).toString(); … … 2148 2260 if (valuesStr.isEmpty()) { 2149 2261 QColor startColor, endColor; 2150 constructColor(fromStr, QString(), startColor, handler);2151 constructColor(toStr, QString(), endColor, handler);2262 resolveColor(fromStr, startColor, handler); 2263 resolveColor(toStr, endColor, handler); 2152 2264 colors.append(startColor); 2153 2265 colors.append(endColor); … … 2157 2269 for (itr = str.constBegin(); itr != str.constEnd(); ++itr) { 2158 2270 QColor color; 2159 constructColor(*itr, QString(), color, handler); 2271 QString str = *itr; 2272 resolveColor(QStringRef(&str), color, handler); 2160 2273 colors.append(color); 2161 2274 } … … 2199 2312 Q_UNUSED(parent); Q_UNUSED(attributes); 2200 2313 return true; 2314 } 2315 2316 static void parseNumberTriplet(QVector<qreal> &values, const QChar *&s) 2317 { 2318 QVector<qreal> list = parseNumbersList(s); 2319 values << list; 2320 for (int i = 3 - list.size(); i > 0; --i) 2321 values.append(0.0); 2201 2322 } 2202 2323 … … 2214 2335 QString fromStr = attributes.value(QLatin1String("from")).toString(); 2215 2336 QString toStr = attributes.value(QLatin1String("to")).toString(); 2337 QString byStr = attributes.value(QLatin1String("by")).toString(); 2338 QString addtv = attributes.value(QLatin1String("additive")).toString(); 2339 2340 QSvgAnimateTransform::Additive additive = QSvgAnimateTransform::Replace; 2341 if (addtv == QLatin1String("sum")) 2342 additive = QSvgAnimateTransform::Sum; 2216 2343 2217 2344 QVector<qreal> vals; 2218 2345 if (values.isEmpty()) { 2219 const QChar *s = fromStr.constData(); 2220 QVector<qreal> lst = parseNumbersList(s); 2221 while (lst.count() < 3) 2222 lst.append(0.0); 2223 vals << lst; 2224 2225 s = toStr.constData(); 2226 lst = parseNumbersList(s); 2227 while (lst.count() < 3) 2228 lst.append(0.0); 2229 vals << lst; 2346 const QChar *s; 2347 if (fromStr.isEmpty()) { 2348 if (!byStr.isEmpty()) { 2349 // By-animation. 2350 additive = QSvgAnimateTransform::Sum; 2351 vals.append(0.0); 2352 vals.append(0.0); 2353 vals.append(0.0); 2354 parseNumberTriplet(vals, s = byStr.constData()); 2355 } else { 2356 // To-animation not defined. 2357 return false; 2358 } 2359 } else { 2360 if (!toStr.isEmpty()) { 2361 // From-to-animation. 2362 parseNumberTriplet(vals, s = fromStr.constData()); 2363 parseNumberTriplet(vals, s = toStr.constData()); 2364 } else if (!byStr.isEmpty()) { 2365 // From-by-animation. 2366 parseNumberTriplet(vals, s = fromStr.constData()); 2367 parseNumberTriplet(vals, s = byStr.constData()); 2368 for (int i = vals.size() - 3; i < vals.size(); ++i) 2369 vals[i] += vals[i - 3]; 2370 } else { 2371 return false; 2372 } 2373 } 2230 2374 } else { 2231 2375 const QChar *s = values.constData(); 2232 2376 while (s && *s != QLatin1Char(0)) { 2233 QVector<qreal> tmpVals = parseNumbersList(s); 2234 while (tmpVals.count() < 3) 2235 tmpVals.append(0.0); 2236 2237 vals << tmpVals; 2377 parseNumberTriplet(vals, s); 2238 2378 if (*s == QLatin1Char(0)) 2239 2379 break; … … 2277 2417 2278 2418 QSvgAnimateTransform *anim = new QSvgAnimateTransform(begin, end, 0); 2279 anim->setArgs(type, vals);2419 anim->setArgs(type, additive, vals); 2280 2420 anim->setFreeze(fillStr == QLatin1String("freeze")); 2281 2421 anim->setRepeatCount( … … 2542 2682 } 2543 2683 2684 if (image.format() == QImage::Format_ARGB32) 2685 image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); 2686 2544 2687 QSvgNode *img = new QSvgImage(parent, 2545 2688 image, … … 2576 2719 { 2577 2720 QString link = attributes.value(QLatin1String("xlink:href")).toString(); 2578 QString trans = attributes.value(QLatin1String("gradientTransform")).toString();2721 QStringRef trans = attributes.value(QLatin1String("gradientTransform")); 2579 2722 QString spread = attributes.value(QLatin1String("spreadMethod")).toString(); 2580 2723 QString units = attributes.value(QLatin1String("gradientUnits")).toString(); 2724 QStringRef colorStr = attributes.value(QLatin1String("color")); 2725 QStringRef colorOpacityStr = attributes.value(QLatin1String("color-opacity")); 2726 2727 QColor color; 2728 if (constructColor(colorStr, colorOpacityStr, color, handler)) { 2729 handler->popColor(); 2730 handler->pushColor(color); 2731 } 2581 2732 2582 2733 QMatrix matrix; … … 2714 2865 QVector<qreal> points = parseNumbersList(s); 2715 2866 QPolygonF poly(points.count()/2); 2716 int i = 0; 2717 QVector<qreal>::const_iterator itr = points.constBegin(); 2718 while (itr != points.constEnd()) { 2719 qreal one = *itr; ++itr; 2720 qreal two = *itr; ++itr; 2721 poly[i] = QPointF(one, two); 2722 ++i; 2723 } 2867 for (int i = 0; i < poly.size(); ++i) 2868 poly[i] = QPointF(points.at(2 * i), points.at(2 * i + 1)); 2724 2869 QSvgNode *polygon = new QSvgPolygon(parent, poly); 2725 2870 return polygon; … … 2736 2881 QVector<qreal> points = parseNumbersList(s); 2737 2882 QPolygonF poly(points.count()/2); 2738 int i = 0; 2739 QVector<qreal>::const_iterator itr = points.constBegin(); 2740 while (itr != points.constEnd()) { 2741 qreal one = *itr; ++itr; 2742 qreal two = *itr; ++itr; 2743 poly[i] = QPointF(one, two); 2744 ++i; 2745 } 2883 for (int i = 0; i < poly.size(); ++i) 2884 poly[i] = QPointF(points.at(2 * i), points.at(2 * i + 1)); 2746 2885 2747 2886 QSvgNode *line = new QSvgPolyline(parent, poly); … … 2862 3001 { 2863 3002 Q_UNUSED(parent); Q_UNUSED(attributes); 2864 QString solidColorStr = attributes.value(QLatin1String("solid-color")).toString();2865 QString solidOpacityStr = attributes.value(QLatin1String("solid-opacity")).toString();3003 QStringRef solidColorStr = attributes.value(QLatin1String("solid-color")); 3004 QStringRef solidOpacityStr = attributes.value(QLatin1String("solid-opacity")); 2866 3005 2867 3006 if (solidOpacityStr.isEmpty()) 2868 solidOpacityStr = attributes.value(QLatin1String("opacity")) .toString();3007 solidOpacityStr = attributes.value(QLatin1String("opacity")); 2869 3008 2870 3009 QColor color; … … 2896 3035 QVector<QCss::Declaration> decls = handler->selector()->declarationsForNode(cssNode); 2897 3036 2898 QSvgAttributes attrs(attributes, handler); 2899 3037 QXmlStreamAttributes xmlAttr = attributes; 2900 3038 for (int i = 0; i < decls.count(); ++i) { 2901 3039 const QCss::Declaration &decl = decls.at(i); … … 2911 3049 valueStr.append(QLatin1Char(')')); 2912 3050 } 2913 attrs.m_xmlAttributes.append(QString(), decl.d->property, valueStr); 2914 } 3051 xmlAttr.append(QString(), decl.d->property, valueStr); 3052 } 3053 QSvgAttributes attrs(xmlAttr, handler); 2915 3054 2916 3055 QSvgGradientStyle *style = 2917 3056 static_cast<QSvgGradientStyle*>(parent); 2918 QString offsetStr = attrs.value(QString(), QLatin1String("offset")).toString(); 2919 QString colorStr = attrs.value(QString(), QLatin1String("stop-color")).toString(); 2920 QString opacityStr = attrs.value(QString(), QLatin1String("stop-opacity")).toString(); 3057 QString offsetStr = attrs.offset.toString(); 3058 QStringRef colorStr = attrs.stopColor; 2921 3059 QColor color; 2922 qreal offset = convertToNumber(offsetStr, handler); 3060 3061 bool ok = true; 3062 qreal offset = convertToNumber(offsetStr, handler, &ok); 3063 if (!ok) 3064 offset = 0.0; 3065 QString black = QString::fromLatin1("#000000"); 2923 3066 if (colorStr.isEmpty()) { 2924 colorStr = Q Latin1String("#000000");2925 } 2926 2927 bool colorOK = constructColor(colorStr, opacityStr, color, handler);3067 colorStr = QStringRef(&black); 3068 } 3069 3070 constructColor(colorStr, attrs.stopOpacity, color, handler); 2928 3071 2929 3072 QGradient *grad = style->qgradient(); … … 2949 3092 grad->setColorAt(offset, color); 2950 3093 style->setGradientStopsSet(true); 2951 if (!colorOK)2952 style->addResolve(offset);2953 3094 return true; 2954 3095 } … … 3004 3145 } 3005 3146 3006 3147 QStringList viewBoxValues; 3007 3148 if (!viewBoxStr.isEmpty()) { 3008 QStringList lst = viewBoxStr.split(QLatin1Char(' '), QString::SkipEmptyParts); 3009 if (lst.count() != 4) 3010 lst = viewBoxStr.split(QLatin1Char(','), QString::SkipEmptyParts); 3011 QString xStr = lst.at(0).trimmed(); 3012 QString yStr = lst.at(1).trimmed(); 3013 QString widthStr = lst.at(2).trimmed(); 3014 QString heightStr = lst.at(3).trimmed(); 3015 3149 viewBoxStr = viewBoxStr.replace(QLatin1Char(' '), QLatin1Char(',')); 3150 viewBoxStr = viewBoxStr.replace(QLatin1Char('\r'), QLatin1Char(',')); 3151 viewBoxStr = viewBoxStr.replace(QLatin1Char('\n'), QLatin1Char(',')); 3152 viewBoxStr = viewBoxStr.replace(QLatin1Char('\t'), QLatin1Char(',')); 3153 viewBoxValues = viewBoxStr.split(QLatin1Char(','), QString::SkipEmptyParts); 3154 } 3155 if (viewBoxValues.count() == 4) { 3156 QString xStr = viewBoxValues.at(0).trimmed(); 3157 QString yStr = viewBoxValues.at(1).trimmed(); 3158 QString widthStr = viewBoxValues.at(2).trimmed(); 3159 QString heightStr = viewBoxValues.at(3).trimmed(); 3016 3160 3017 3161 QSvgHandler::LengthType lt; … … 3022 3166 3023 3167 node->setViewBox(QRectF(x, y, w, h)); 3024 } else if (width && height){ 3168 3169 } else if (width && height) { 3025 3170 if (type == QSvgHandler::LT_PT) { 3026 3171 width = convertToPixels(width, false, type); 3027 3172 height = convertToPixels(height, false, type); 3028 3173 } 3029 3030 3174 node->setViewBox(QRectF(0, 0, width, height)); 3031 3175 } 3032 3033 3176 handler->setDefaultCoordinateSystem(QSvgHandler::LT_PX); 3034 3177 … … 3051 3194 if (parent->type() != QSvgNode::TEXTAREA) 3052 3195 return false; 3053 static_cast<QSvgText*>(parent)-> insertLineBreak();3196 static_cast<QSvgText*>(parent)->addLineBreak(); 3054 3197 return true; 3055 3198 } … … 3066 3209 qreal ny = parseLength(y, type, handler); 3067 3210 3068 //### not to pixels but to the default coordinate system3069 // and text should be already in the correct coordinate3070 // system here3071 //nx = convertToPixels(nx, true, type);3072 //ny = convertToPixels(ny, true, type);3073 3074 3211 QSvgNode *text = new QSvgText(parent, QPointF(nx, ny)); 3075 3212 return text; … … 3090 3227 } 3091 3228 3229 static QSvgNode *createTspanNode(QSvgNode *parent, 3230 const QXmlStreamAttributes &, 3231 QSvgHandler *) 3232 { 3233 return new QSvgTspan(parent); 3234 } 3235 3092 3236 static bool parseTitleNode(QSvgNode *parent, 3093 3237 const QXmlStreamAttributes &attributes, … … 3096 3240 Q_UNUSED(parent); Q_UNUSED(attributes); 3097 3241 return true; 3098 }3099 3100 static bool parseTspanNode(QSvgNode *parent,3101 const QXmlStreamAttributes &attributes,3102 QSvgHandler *handler)3103 {3104 3105 cssStyleLookup(parent, handler, handler->selector());3106 return parseDefaultTextStyle(parent, attributes, false, handler);3107 3242 } 3108 3243 … … 3220 3355 if (ref == QLatin1String("ext")) return createTextNode; 3221 3356 if (ref == QLatin1String("extArea")) return createTextAreaNode; 3357 if (ref == QLatin1String("span")) return createTspanNode; 3222 3358 break; 3223 3359 case 'u': … … 3276 3412 if (ref == QLatin1String("break")) return parseTbreakNode; 3277 3413 if (ref == QLatin1String("itle")) return parseTitleNode; 3278 if (ref == QLatin1String("span")) return parseTspanNode;3279 3414 break; 3280 3415 default: … … 3367 3502 m_doc = 0; 3368 3503 m_style = 0; 3504 m_animEnd = 0; 3369 3505 m_defaultCoords = LT_PX; 3370 m_defaultPen = QPen(Qt::black, 1, Qt:: NoPen, Qt::FlatCap, Qt::SvgMiterJoin);3506 m_defaultPen = QPen(Qt::black, 1, Qt::SolidLine, Qt::FlatCap, Qt::SvgMiterJoin); 3371 3507 m_defaultPen.setMiterLimit(4); 3372 3508 parse(); … … 3405 3541 break; 3406 3542 default: 3407 ; 3408 } 3409 } 3543 break; 3544 } 3545 } 3546 resolveGradients(m_doc); 3410 3547 } 3411 3548 … … 3415 3552 QSvgNode *node = 0; 3416 3553 3417 if (m_colorTagCount.count()) { 3418 int top = m_colorTagCount.pop(); 3419 ++top; 3420 m_colorTagCount.push(top); 3421 } 3554 pushColorCopy(); 3422 3555 3423 3556 /* The xml:space attribute may appear on any element. We do … … 3425 3558 * the XML namespace can only be bound to prefix "xml." */ 3426 3559 const QStringRef xmlSpace(attributes.value(QLatin1String("xml:space"))); 3427 if(xmlSpace.isNull()) 3428 { 3560 if (xmlSpace.isNull()) { 3429 3561 // This element has no xml:space attribute. 3562 m_whitespaceMode.push(m_whitespaceMode.isEmpty() ? QSvgText::Default : m_whitespaceMode.top()); 3563 } else if (xmlSpace == QLatin1String("preserve")) { 3564 m_whitespaceMode.push(QSvgText::Preserve); 3565 } else if (xmlSpace == QLatin1String("default")) { 3430 3566 m_whitespaceMode.push(QSvgText::Default); 3431 } 3432 else if(xmlSpace == QLatin1String("preserve")) 3433 m_whitespaceMode.push(QSvgText::Preserve); 3434 else if(xmlSpace == QLatin1String("default")) 3435 m_whitespaceMode.push(QSvgText::Default); 3436 else 3437 { 3567 } else { 3438 3568 qWarning() << QString::fromLatin1("\"%1\" is an invalid value for attribute xml:space. " 3439 3569 "Valid values are \"preserve\" and \"default\".").arg(xmlSpace.toString()); 3440 3441 3570 m_whitespaceMode.push(QSvgText::Default); 3442 3571 } … … 3484 3613 } 3485 3614 break; 3615 case QSvgNode::TEXT: 3616 case QSvgNode::TEXTAREA: 3617 if (node->type() == QSvgNode::TSPAN) { 3618 static_cast<QSvgText *>(m_nodes.top())->addTspan(static_cast<QSvgTspan *>(node)); 3619 } else { 3620 qWarning("\'text\' or \'textArea\' element contains invalid element type."); 3621 delete node; 3622 node = 0; 3623 } 3624 break; 3486 3625 default: 3487 Q_ASSERT(!"not a grouping element is the parent"); 3488 } 3489 3490 parseCoreNode(node, attributes); 3491 cssStyleLookup(node, this, m_selector); 3492 if (node->type() != QSvgNode::TEXT && node->type() != QSvgNode::TEXTAREA) 3626 qWarning("Could not add child element to parent element because the types are incorrect."); 3627 delete node; 3628 node = 0; 3629 break; 3630 } 3631 3632 if (node) { 3633 parseCoreNode(node, attributes); 3634 cssStyleLookup(node, this, m_selector); 3493 3635 parseStyle(node, attributes, this); 3494 else 3495 parseDefaultTextStyle(node, attributes, true, this); 3636 if (node->type() == QSvgNode::TEXT || node->type() == QSvgNode::TEXTAREA) { 3637 static_cast<QSvgText *>(node)->setWhitespaceMode(m_whitespaceMode.top()); 3638 } else if (node->type() == QSvgNode::TSPAN) { 3639 static_cast<QSvgTspan *>(node)->setWhitespaceMode(m_whitespaceMode.top()); 3640 } 3641 } 3496 3642 } 3497 3643 } else if (ParseMethod method = findUtilFactory(localName)) { … … 3504 3650 if (prop) { 3505 3651 m_style = prop; 3506 m_nodes.top()->appendStyleProperty(prop, someId(attributes) , true);3652 m_nodes.top()->appendStyleProperty(prop, someId(attributes)); 3507 3653 } else { 3508 qWarning("Could n't parse node: %s", qPrintable(localName));3654 qWarning("Could not parse node: %s", qPrintable(localName)); 3509 3655 } 3510 3656 } else if (StyleParseMethod method = findStyleUtilFactoryMethod(localName)) { … … 3536 3682 m_whitespaceMode.pop(); 3537 3683 3538 if (m_colorTagCount.count()) { 3539 int top = m_colorTagCount.pop(); 3540 --top; 3541 if (!top) { 3542 m_colorStack.pop(); 3543 } else { 3544 m_colorTagCount.push(top); 3545 } 3546 } 3684 popColor(); 3547 3685 3548 3686 if (node == Unknown) { … … 3550 3688 } 3551 3689 3552 if (m_inStyle && localName == QLatin1String("style")) {3690 if (m_inStyle && localName == QLatin1String("style")) 3553 3691 m_inStyle = false; 3554 } else if (m_nodes.top()->type() == QSvgNode::TEXT || m_nodes.top()->type() == QSvgNode::TEXTAREA) {3555 QSvgText *node = static_cast<QSvgText*>(m_nodes.top());3556 if (localName == QLatin1String("tspan"))3557 node->popFormat();3558 }3559 3692 3560 3693 if (node == Graphics) … … 3564 3697 3565 3698 return true; 3699 } 3700 3701 void QSvgHandler::resolveGradients(QSvgNode *node) 3702 { 3703 if (!node || (node->type() != QSvgNode::DOC && node->type() != QSvgNode::G 3704 && node->type() != QSvgNode::DEFS && node->type() != QSvgNode::SWITCH)) { 3705 return; 3706 } 3707 QSvgStructureNode *structureNode = static_cast<QSvgStructureNode *>(node); 3708 3709 QList<QSvgNode *> ren = structureNode->renderers(); 3710 for (QList<QSvgNode *>::iterator it = ren.begin(); it != ren.end(); ++it) { 3711 QSvgFillStyle *fill = static_cast<QSvgFillStyle *>((*it)->styleProperty(QSvgStyleProperty::FILL)); 3712 if (fill && !fill->isGradientResolved()) { 3713 QString id = fill->gradientId(); 3714 QSvgFillStyleProperty *style = structureNode->styleProperty(id); 3715 if (style) { 3716 fill->setFillStyle(style); 3717 } else { 3718 qWarning("Could not resolve property : %s", qPrintable(id)); 3719 fill->setBrush(Qt::NoBrush); 3720 } 3721 } 3722 3723 QSvgStrokeStyle *stroke = static_cast<QSvgStrokeStyle *>((*it)->styleProperty(QSvgStyleProperty::STROKE)); 3724 if (stroke && !stroke->isGradientResolved()) { 3725 QString id = stroke->gradientId(); 3726 QSvgFillStyleProperty *style = structureNode->styleProperty(id); 3727 if (style) { 3728 stroke->setStyle(style); 3729 } else { 3730 qWarning("Could not resolve property : %s", qPrintable(id)); 3731 stroke->setStroke(Qt::NoBrush); 3732 } 3733 } 3734 3735 resolveGradients(*it); 3736 } 3566 3737 } 3567 3738 … … 3578 3749 3579 3750 if (m_nodes.top()->type() == QSvgNode::TEXT || m_nodes.top()->type() == QSvgNode::TEXTAREA) { 3580 QSvgText *node = static_cast<QSvgText*>(m_nodes.top()); 3581 node->insertText(str.toString(), m_whitespaceMode.top()); 3751 static_cast<QSvgText*>(m_nodes.top())->addText(str.toString()); 3752 } else if (m_nodes.top()->type() == QSvgNode::TSPAN) { 3753 static_cast<QSvgTspan*>(m_nodes.top())->addText(str.toString()); 3582 3754 } 3583 3755 … … 3604 3776 m_colorStack.push(color); 3605 3777 m_colorTagCount.push(1); 3778 } 3779 3780 void QSvgHandler::pushColorCopy() 3781 { 3782 if (m_colorTagCount.count()) 3783 ++m_colorTagCount.top(); 3784 else 3785 pushColor(Qt::black); 3786 } 3787 3788 void QSvgHandler::popColor() 3789 { 3790 if (m_colorTagCount.count()) { 3791 if (!--m_colorTagCount.top()) { 3792 m_colorStack.pop(); 3793 m_colorTagCount.pop(); 3794 } 3795 } 3606 3796 } 3607 3797
Note:
See TracChangeset
for help on using the changeset viewer.