Ignore:
Timestamp:
Feb 11, 2010, 11:19:06 PM (15 years ago)
Author:
Dmitry A. Kuminov
Message:

trunk: Merged in qt 4.6.1 sources.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/src/svg/qsvghandler.cpp

    r2 r561  
    22**
    33** 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)
    56**
    67** This file is part of the QtSvg module of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    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.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** 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.
    3838** $QT_END_LICENSE$
    3939**
    4040****************************************************************************/
     41
     42#include "qplatformdefs.h"
    4143
    4244#include "qsvghandler_p.h"
     
    6365#include "qmath.h"
    6466#include "qnumeric.h"
     67#include "qvarlengtharray.h"
    6568#include "private/qmath_p.h"
    6669
     
    6972QT_BEGIN_NAMESPACE
    7073
     74static const char *qt_inherit_text = "inherit";
     75#define QT_INHERIT QLatin1String(qt_inherit_text)
     76
    7177double qstrtod(const char *s00, char const **se, bool *ok);
    7278
     79// ======== duplicated from qcolor_p
     80
     81static 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
     92static inline int qsvg_hex2int(const char *s)
     93{
     94    return (qsvg_h2i(s[0]) << 4) | qsvg_h2i(s[1]);
     95}
     96
     97static inline int qsvg_hex2int(char s)
     98{
     99    int h = qsvg_h2i(s);
     100    return (h << 4) | h;
     101}
     102
     103bool 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
     137bool 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
    73150static bool parsePathDataFast(const QStringRef &data, QPainterPath &path);
    74 
    75 struct QSvgAttributes
    76 {
    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) const
    95 {
    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) const
    109 {
    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 }
    121151
    122152static inline QString someId(const QXmlStreamAttributes &attributes)
     
    127157    return id;
    128158}
    129 static inline QString someId(const QSvgAttributes &attributes)
    130 { return someId(attributes.m_xmlAttributes); }
    131 
    132 
     159
     160struct 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
     198QSvgAttributes::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}
    133403
    134404static const char * QSvgStyleSelector_nodeString[] = {
     
    283553};
    284554
     555// '0' is 0x30 and '9' is 0x39
     556static inline bool isDigit(ushort ch)
     557{
     558    static quint16 magic = 0x3ff;
     559    return ((ch >> 4) == 3) && (magic >> (ch & 15));
     560}
     561
    285562static qreal toDouble(const QChar *&str)
    286563{
     
    295572        ++str;
    296573    }
    297     while (*str >= QLatin1Char('0') && *str <= QLatin1Char('9') && pos < maxLen) {
     574    while (isDigit(str->unicode()) && pos < maxLen) {
    298575        temp[pos++] = str->toLatin1();
    299576        ++str;
     
    303580        ++str;
    304581    }
    305     while (*str >= QLatin1Char('0') && *str <= QLatin1Char('9') && pos < maxLen) {
     582    while (isDigit(str->unicode()) && pos < maxLen) {
    306583        temp[pos++] = str->toLatin1();
    307584        ++str;
     
    316593            ++str;
    317594        }
    318         while (*str >= QLatin1Char('0') && *str <= QLatin1Char('9') && pos < maxLen) {
     595        while (isDigit(str->unicode()) && pos < maxLen) {
    319596            temp[pos++] = str->toLatin1();
    320597            ++str;
    321598        }
    322599    }
     600
    323601    temp[pos] = '\0';
    324602
     
    353631            val = -val;
    354632    } else {
    355 #ifdef Q_WS_QWS
     633#if defined(Q_WS_QWS) && !defined(Q_OS_VXWORKS)
    356634        if(sizeof(qreal) == sizeof(float))
    357635            val = strtof(temp, 0);
     
    366644
    367645}
    368 static qreal toDouble(const QString &str)
     646static qreal toDouble(const QString &str, bool *ok = NULL)
    369647{
    370648    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
     656static qreal toDouble(const QStringRef &str, bool *ok = NULL)
    375657{
    376658    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;
    378664}
    379665
     
    385671    points.reserve(32);
    386672
    387     while (*str == QLatin1Char(' '))
     673    while (str->isSpace())
    388674        ++str;
    389     while ((*str >= QLatin1Char('0') && *str <= QLatin1Char('9')) ||
     675    while (isDigit(str->unicode()) ||
    390676           *str == QLatin1Char('-') || *str == QLatin1Char('+') ||
    391677           *str == QLatin1Char('.')) {
     
    393679        points.append(toDouble(str));
    394680
    395         while (*str == QLatin1Char(' '))
     681        while (str->isSpace())
    396682            ++str;
    397683        if (*str == QLatin1Char(','))
     
    399685
    400686        //eat the rest of space
    401         while (*str == QLatin1Char(' '))
     687        while (str->isSpace())
    402688            ++str;
    403689    }
    404690
    405691    return points;
     692}
     693
     694static 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    }
    406713}
    407714
     
    420727        points.append(toDouble(str));
    421728
    422         while (*str == QLatin1Char(' '))
     729        while (str->isSpace())
    423730            ++str;
    424731        if (*str == QLatin1Char('%'))
    425732            ++str;
    426         while (*str == QLatin1Char(' '))
     733        while (str->isSpace())
    427734            ++str;
    428735        if (*str == QLatin1Char(','))
     
    430737
    431738        //eat the rest of space
    432         while (*str == QLatin1Char(' '))
     739        while (str->isSpace())
    433740            ++str;
    434741    }
     
    456763}
    457764
     765static 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
    458787/**
    459788 * returns true when successfuly set the color. false signifies
    460789 * that the color should be inherited
    461790 */
    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"))  {
     791static bool resolveColor(const QStringRef &colorStr, QColor &color, QSvgHandler *handler)
     792{
     793    QStringRef colorStrTr = trimRef(colorStr);
     794    if (colorStrTr.isEmpty())
    484795        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());
    491853    return color.isValid();
    492854}
    493855
    494 static bool constructColor(const QString &colorStr, const QString &opacity,
     856static bool constructColor(const QStringRef &colorStr, const QStringRef &opacity,
    495857                           QColor &color, QSvgHandler *handler)
    496858{
     
    498860        return false;
    499861    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);
    504867    }
    505868    return true;
     
    507870
    508871static qreal parseLength(const QString &str, QSvgHandler::LengthType &type,
    509                          QSvgHandler *handler)
     872                         QSvgHandler *handler, bool *ok = NULL)
    510873{
    511874    QString numStr = str.trimmed();
     
    536899        //type = QSvgHandler::LT_OTHER;
    537900    }
    538     qreal len = toDouble(numStr);
     901    qreal len = toDouble(numStr, ok);
    539902    //qDebug()<<"len is "<<len<<", from '"<<numStr << "'";
    540903    return len;
    541904}
    542905
    543 static inline qreal convertToNumber(const QString &str, QSvgHandler *handler)
     906static inline qreal convertToNumber(const QString &str, QSvgHandler *handler, bool *ok = NULL)
    544907{
    545908    QSvgHandler::LengthType type;
    546     qreal num = parseLength(str, type, handler);
     909    qreal num = parseLength(str, type, handler, ok);
    547910    if (type == QSvgHandler::LT_PERCENT) {
    548911        num = num/100.0;
     
    604967                       QSvgHandler *handler)
    605968{
    606     QString colorStr = attributes.value(QLatin1String("color")).toString();
    607     QString opacity  = attributes.value(QLatin1String("color-opacity")).toString();
    608969    QColor color;
    609     if (constructColor(colorStr, opacity, color, handler)) {
     970    if (constructColor(attributes.color, attributes.colorOpacity, color, handler)) {
     971        handler->popColor();
    610972        handler->pushColor(color);
    611973    }
     
    614976static QSvgStyleProperty *styleFromUrl(QSvgNode *node, const QString &url)
    615977{
    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;
    625979}
    626980
     
    629983                       QSvgHandler *handler)
    630984{
    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));
    6501020            } 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
     1030static QMatrix parseTransformationMatrix(const QStringRef &value)
     1031{
     1032    if (value.isEmpty())
     1033        return QMatrix();
     1034
    7651035    QMatrix matrix;
    7661036    const QChar *str = value.constData();
    767 
    768     while (*str != QLatin1Char(0)) {
     1037    const QChar *end = str + value.length();
     1038
     1039    while (str < end) {
    7691040        if (str->isSpace() || *str == QLatin1Char(',')) {
    7701041            ++str;
     
    8311102
    8321103
    833         while (str->isSpace())
     1104        while (str < end && str->isSpace())
    8341105            ++str;
    8351106        if (*str != QLatin1Char('('))
    8361107            goto error;
    8371108        ++str;
    838         QVector<qreal> points = parseNumbersList(str);
     1109        QVarLengthArray<qreal, 8> points;
     1110        parseNumbersArray(str, points);
    8391111        if (*str != QLatin1Char(')'))
    8401112            goto error;
     
    8761148                goto error;
    8771149            const qreal deg2rad = qreal(0.017453292519943295769);
    878             matrix.shear(tan(points[0]*deg2rad), 0);
     1150            matrix.shear(qTan(points[0]*deg2rad), 0);
    8791151        } else if (state == SkewY) {
    8801152            if (points.count() != 1)
    8811153                goto error;
    8821154            const qreal deg2rad = qreal(0.017453292519943295769);
    883             matrix.shear(0, tan(points[0]*deg2rad));
     1155            matrix.shear(0, qTan(points[0]*deg2rad));
    8841156        }
    8851157    }
     
    8921164                     QSvgHandler *handler)
    8931165{
    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 
    9041166    //qDebug()<<"Node "<<node->type()<<", attrs are "<<value<<width;
    9051167
    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();
    9211180                    QSvgStyleProperty *style = styleFromUrl(node, value);
    9221181                    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));
    9301184                    } else {
    931                         qWarning() << "QSvgHandler::parsePen could not resolve property" << idFromUrl(value);
     1185                        QString id = idFromUrl(value);
     1186                        prop->setGradientId(id);
     1187                        prop->setGradientResolved(false);
    9321188                    }
    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();
    9731210                const QChar *s = dashArray.constData();
    9741211                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 
    9821212                // if the dash count is odd the dashes should be duplicated
    983                 if (dashes.size() % 2 != 0)
     1213                if ((dashes.size() & 1) != 0)
    9841214                    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    }
    11311261}
    11321262
     
    11351265                      QSvgHandler *handler)
    11361266{
    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);
    11741334}
    11751335
     
    11781338                           QSvgHandler *)
    11791339{
    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())
    11841341        return;
    1185     QMatrix matrix = parseTransformationMatrix(value);
     1342    QMatrix matrix = parseTransformationMatrix(trimRef(attributes.transform));
    11861343
    11871344    if (!matrix.isIdentity()) {
    1188         node->appendStyleProperty(new QSvgTransformStyle(QTransform(matrix)), myId);
     1345        node->appendStyleProperty(new QSvgTransformStyle(QTransform(matrix)), attributes.id);
    11891346    }
    11901347
     
    11951352                            QSvgHandler *)
    11961353{
    1197     QString value = attributes.value(QLatin1String("visibility")).toString();
    11981354    QSvgNode *parent = node->parent();
    11991355
    1200     if (parent && (value.isEmpty() || value == QLatin1String("inherit")))
     1356    if (parent && (attributes.visibility.isEmpty() || attributes.visibility == QT_INHERIT))
    12011357        node->setVisible(parent->isVisible());
    1202     else if (value == QLatin1String("hidden") || value == QLatin1String("collapse")) {
     1358    else if (attributes.visibility == QLatin1String("hidden") || attributes.visibility == QLatin1String("collapse")) {
    12031359        node->setVisible(false);
    12041360    } else
     
    13261482    /* (xc, yc) is center of the circle. */
    13271483
    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);
    13301486
    13311487    th_arc = th1 - th0;
     
    13551511
    13561512    while (str != end) {
    1357         while (*str == QLatin1Char(' '))
     1513        while (str->isSpace())
    13581514            ++str;
    13591515        QChar pathElem = *str;
    13601516        ++str;
    13611517        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);
    13641521        *const_cast<QChar *>(end) = endc;
    13651522        if (pathElem == QLatin1Char('z') || pathElem == QLatin1Char('Z'))
    13661523            arg.append(0);//dummy
    1367         while (!arg.isEmpty()) {
     1524        const qreal *num = arg.constData();
     1525        int count = arg.count();
     1526        while (count > 0) {
    13681527            qreal offsetX = x;        // correction offsets
    13691528            qreal offsetY = y;        // for relative commands
    13701529            switch (pathElem.unicode()) {
    13711530            case 'm': {
    1372                 if (arg.count() < 2) {
    1373                     arg.pop_front();
     1531                if (count < 2) {
     1532                    num++;
     1533                    count--;
    13741534                    break;
    13751535                }
    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;
    13781540                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');
    13801546            }
    13811547                break;
    13821548            case 'M': {
    1383                 if (arg.count() < 2) {
    1384                     arg.pop_front();
     1549                if (count < 2) {
     1550                    num++;
     1551                    count--;
    13851552                    break;
    13861553                }
    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;
    13901558                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');
    13921564            }
    13931565                break;
     
    13961568                x = x0;
    13971569                y = y0;
     1570                count--; // skip dummy
     1571                num++;
    13981572                path.closeSubpath();
    1399                 arg.pop_front();//pop dummy
    14001573            }
    14011574                break;
    14021575            case 'l': {
    1403                 if (arg.count() < 2) {
    1404                     arg.pop_front();
     1576                if (count < 2) {
     1577                    num++;
     1578                    count--;
    14051579                    break;
    14061580                }
    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;
    14111585                path.lineTo(x, y);
    14121586
     
    14141588                break;
    14151589            case 'L': {
    1416                 if (arg.count() < 2) {
    1417                     arg.pop_front();
     1590                if (count < 2) {
     1591                    num++;
     1592                    count--;
    14181593                    break;
    14191594                }
    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;
    14221599                path.lineTo(x, y);
    14231600            }
    14241601                break;
    14251602            case 'h': {
    1426                 x = arg.front() + offsetX; arg.pop_front();
     1603                x = num[0] + offsetX;
     1604                num++;
     1605                count--;
    14271606                path.lineTo(x, y);
    14281607            }
    14291608                break;
    14301609            case 'H': {
    1431                 x = arg[0];
     1610                x = num[0];
     1611                num++;
     1612                count--;
    14321613                path.lineTo(x, y);
    1433                 arg.pop_front();
    14341614            }
    14351615                break;
    14361616            case 'v': {
    1437                 y = arg[0] + offsetY;
     1617                y = num[0] + offsetY;
     1618                num++;
     1619                count--;
    14381620                path.lineTo(x, y);
    1439                 arg.pop_front();
    14401621            }
    14411622                break;
    14421623            case 'V': {
    1443                 y = arg[0];
     1624                y = num[0];
     1625                num++;
     1626                count--;
    14441627                path.lineTo(x, y);
    1445                 arg.pop_front();
    14461628            }
    14471629                break;
    14481630            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;
    14521634                    break;
    14531635                }
    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;
    14571641                path.cubicTo(c1, c2, e);
    14581642                ctrlPt = c2;
    14591643                x = e.x();
    14601644                y = e.y();
    1461                 arg.pop_front(); arg.pop_front();
    1462                 arg.pop_front(); arg.pop_front();
    1463                 arg.pop_front(); arg.pop_front();
    14641645                break;
    14651646            }
    14661647            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;
    14701651                    break;
    14711652                }
    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;
    14751658                path.cubicTo(c1, c2, e);
    14761659                ctrlPt = c2;
    14771660                x = e.x();
    14781661                y = e.y();
    1479                 arg.pop_front(); arg.pop_front();
    1480                 arg.pop_front(); arg.pop_front();
    1481                 arg.pop_front(); arg.pop_front();
    14821662                break;
    14831663            }
    14841664            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;
    14881668                    break;
    14891669                }
     
    14941674                else
    14951675                    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;
    14981680                path.cubicTo(c1, c2, e);
    14991681                ctrlPt = c2;
    15001682                x = e.x();
    15011683                y = e.y();
    1502                 arg.pop_front(); arg.pop_front();
    1503                 arg.pop_front(); arg.pop_front();
    15041684                break;
    15051685            }
    15061686            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;
    15101690                    break;
    15111691                }
     
    15161696                else
    15171697                    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;
    15201702                path.cubicTo(c1, c2, e);
    15211703                ctrlPt = c2;
    15221704                x = e.x();
    15231705                y = e.y();
    1524                 arg.pop_front(); arg.pop_front();
    1525                 arg.pop_front(); arg.pop_front();
    15261706                break;
    15271707            }
    15281708            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;
    15321712                    break;
    15331713                }
    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;
    15361718                path.quadTo(c, e);
    15371719                ctrlPt = c;
    15381720                x = e.x();
    15391721                y = e.y();
    1540                 arg.pop_front(); arg.pop_front();
    1541                 arg.pop_front(); arg.pop_front();
    15421722                break;
    15431723            }
    15441724            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;
    15481728                    break;
    15491729                }
    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;
    15521734                path.quadTo(c, e);
    15531735                ctrlPt = c;
    15541736                x = e.x();
    15551737                y = e.y();
    1556                 arg.pop_front(); arg.pop_front();
    1557                 arg.pop_front(); arg.pop_front();
    15581738                break;
    15591739            }
    15601740            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;
    15641744                    break;
    15651745                }
    1566                 QPointF e(arg[0]+offsetX, arg[1]+offsetY);
     1746                QPointF e(num[0] + offsetX, num[1] + offsetY);
     1747                num += 2;
     1748                count -= 2;
    15671749                QPointF c;
    15681750                if (lastMode == 'q' || lastMode == 'Q' ||
     
    15751757                x = e.x();
    15761758                y = e.y();
    1577                 arg.pop_front(); arg.pop_front();
    15781759                break;
    15791760            }
    15801761            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;
    15841765                    break;
    15851766                }
    1586                 QPointF e(arg[0], arg[1]);
     1767                QPointF e(num[0], num[1]);
     1768                num += 2;
     1769                count -= 2;
    15871770                QPointF c;
    15881771                if (lastMode == 'q' || lastMode == 'Q' ||
     
    15951778                x = e.x();
    15961779                y = e.y();
    1597                 arg.pop_front(); arg.pop_front();
    15981780                break;
    15991781            }
    16001782            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;
    16041786                    break;
    16051787                }
    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;
    16131796                qreal curx = x;
    16141797                qreal cury = y;
     
    16181801                x = ex;
    16191802                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();
    16251803            }
    16261804                break;
    16271805            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;
    16311809                    break;
    16321810                }
    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;
    16401819                qreal curx = x;
    16411820                qreal cury = y;
    16421821                pathArc(path, rx, ry, xAxisRotation, int(largeArcFlag),
    16431822                        int(sweepFlag), ex, ey, curx, cury);
     1823
    16441824                x = ex;
    16451825                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();
    16501826            }
    16511827                break;
     
    16741850        if (decl.d->property.isEmpty())
    16751851            continue;
    1676         if (decl.d->values.count() != 1)
    1677             continue;
    16781852        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        }
    16801865        if (val.type == QCss::Value::Uri) {
    16811866            valueStr.prepend(QLatin1String("url("));
     
    17901975}
    17911976
    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 
    18911977static inline QStringList stringToList(const QString &str)
    18921978{
     
    18981984                          const QXmlStreamAttributes &attributes)
    18991985{
    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    }
    19142022
    19152023    node->setRequiredFeatures(features);
     
    19182026    node->setRequiredFormats(formats);
    19192027    node->setRequiredFonts(fonts);
    1920     node->setNodeId(nodeIdStr);
     2028    node->setNodeId(someId(attributes));
    19212029    node->setXmlClass(xmlClassStr);
    19222030
     
    19282036                         QSvgHandler *)
    19292037{
    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();
    19322042
    19332043    bool ok = false;
     
    19352045
    19362046    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);
    19392049    }
    19402050}
     
    20022112                        QSvgHandler *)
    20032113{
    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();
    20062117
    20072118    if (!value.isEmpty()) {
    20082119        QSvgCompOpStyle *compop = new QSvgCompOpStyle(svgToQtCompositionMode(value));
    2009         node->appendStyleProperty(compop, someId(attributes));
     2120        node->appendStyleProperty(compop, attributes.id);
    20102121    }
    20112122}
     
    20472158    } else if (str == QLatin1String("none")) {
    20482159        return QSvgNode::NoneMode;
    2049     } else if (str == QLatin1String("inherit")) {
     2160    } else if (str == QT_INHERIT) {
    20502161        return QSvgNode::InheritMode;
    20512162    }
     
    20572168                        QSvgHandler *)
    20582169{
    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();
    20612173
    20622174    if (!displayStr.isEmpty()) {
     
    21362248{
    21372249    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"));
    21402252    QString valuesStr  = attributes.value(QLatin1String("values")).toString();
    21412253    QString beginStr   = attributes.value(QLatin1String("begin")).toString();
     
    21482260    if (valuesStr.isEmpty()) {
    21492261        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);
    21522264        colors.append(startColor);
    21532265        colors.append(endColor);
     
    21572269        for (itr = str.constBegin(); itr != str.constEnd(); ++itr) {
    21582270            QColor color;
    2159             constructColor(*itr, QString(), color, handler);
     2271            QString str = *itr;
     2272            resolveColor(QStringRef(&str), color, handler);
    21602273            colors.append(color);
    21612274        }
     
    21992312    Q_UNUSED(parent); Q_UNUSED(attributes);
    22002313    return true;
     2314}
     2315
     2316static 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);
    22012322}
    22022323
     
    22142335    QString fromStr    = attributes.value(QLatin1String("from")).toString();
    22152336    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;
    22162343
    22172344    QVector<qreal> vals;
    22182345    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        }
    22302374    } else {
    22312375        const QChar *s = values.constData();
    22322376        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);
    22382378            if (*s == QLatin1Char(0))
    22392379                break;
     
    22772417
    22782418    QSvgAnimateTransform *anim = new QSvgAnimateTransform(begin, end, 0);
    2279     anim->setArgs(type, vals);
     2419    anim->setArgs(type, additive, vals);
    22802420    anim->setFreeze(fillStr == QLatin1String("freeze"));
    22812421    anim->setRepeatCount(
     
    25422682    }
    25432683
     2684    if (image.format() == QImage::Format_ARGB32)
     2685        image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
     2686
    25442687    QSvgNode *img = new QSvgImage(parent,
    25452688                                  image,
     
    25762719{
    25772720    QString link   = attributes.value(QLatin1String("xlink:href")).toString();
    2578     QString trans  = attributes.value(QLatin1String("gradientTransform")).toString();
     2721    QStringRef trans  = attributes.value(QLatin1String("gradientTransform"));
    25792722    QString spread = attributes.value(QLatin1String("spreadMethod")).toString();
    25802723    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    }
    25812732
    25822733    QMatrix matrix;
     
    27142865    QVector<qreal> points = parseNumbersList(s);
    27152866    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));
    27242869    QSvgNode *polygon = new QSvgPolygon(parent, poly);
    27252870    return polygon;
     
    27362881    QVector<qreal> points = parseNumbersList(s);
    27372882    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));
    27462885
    27472886    QSvgNode *line = new QSvgPolyline(parent, poly);
     
    28623001{
    28633002    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"));
    28663005
    28673006    if (solidOpacityStr.isEmpty())
    2868         solidOpacityStr = attributes.value(QLatin1String("opacity")).toString();
     3007        solidOpacityStr = attributes.value(QLatin1String("opacity"));
    28693008
    28703009    QColor color;
     
    28963035    QVector<QCss::Declaration> decls = handler->selector()->declarationsForNode(cssNode);
    28973036
    2898     QSvgAttributes attrs(attributes, handler);
    2899 
     3037    QXmlStreamAttributes xmlAttr = attributes;
    29003038    for (int i = 0; i < decls.count(); ++i) {
    29013039        const QCss::Declaration &decl = decls.at(i);
     
    29113049            valueStr.append(QLatin1Char(')'));
    29123050        }
    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);
    29153054
    29163055    QSvgGradientStyle *style =
    29173056        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;
    29213059    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");
    29233066    if (colorStr.isEmpty()) {
    2924         colorStr = QLatin1String("#000000");
    2925     }
    2926 
    2927     bool colorOK = constructColor(colorStr, opacityStr, color, handler);
     3067        colorStr = QStringRef(&black);
     3068    }
     3069
     3070    constructColor(colorStr, attrs.stopOpacity, color, handler);
    29283071
    29293072    QGradient *grad = style->qgradient();
     
    29493092    grad->setColorAt(offset, color);
    29503093    style->setGradientStopsSet(true);
    2951     if (!colorOK)
    2952         style->addResolve(offset);
    29533094    return true;
    29543095}
     
    30043145    }
    30053146
    3006 
     3147    QStringList viewBoxValues;
    30073148    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();
    30163160
    30173161        QSvgHandler::LengthType lt;
     
    30223166
    30233167        node->setViewBox(QRectF(x, y, w, h));
    3024     } else if (width && height){
     3168
     3169    } else if (width && height) {
    30253170        if (type == QSvgHandler::LT_PT) {
    30263171            width = convertToPixels(width, false, type);
    30273172            height = convertToPixels(height, false, type);
    30283173        }
    3029 
    30303174        node->setViewBox(QRectF(0, 0, width, height));
    30313175    }
    3032 
    30333176    handler->setDefaultCoordinateSystem(QSvgHandler::LT_PX);
    30343177
     
    30513194    if (parent->type() != QSvgNode::TEXTAREA)
    30523195        return false;
    3053     static_cast<QSvgText*>(parent)->insertLineBreak();
     3196    static_cast<QSvgText*>(parent)->addLineBreak();
    30543197    return true;
    30553198}
     
    30663209    qreal ny = parseLength(y, type, handler);
    30673210
    3068     //### not to pixels but to the default coordinate system
    3069     //    and text should be already in the correct coordinate
    3070     //    system here
    3071     //nx = convertToPixels(nx, true, type);
    3072     //ny = convertToPixels(ny, true, type);
    3073 
    30743211    QSvgNode *text = new QSvgText(parent, QPointF(nx, ny));
    30753212    return text;
     
    30903227}
    30913228
     3229static QSvgNode *createTspanNode(QSvgNode *parent,
     3230                                    const QXmlStreamAttributes &,
     3231                                    QSvgHandler *)
     3232{
     3233    return new QSvgTspan(parent);
     3234}
     3235
    30923236static bool parseTitleNode(QSvgNode *parent,
    30933237                           const QXmlStreamAttributes &attributes,
     
    30963240    Q_UNUSED(parent); Q_UNUSED(attributes);
    30973241    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);
    31073242}
    31083243
     
    32203355        if (ref == QLatin1String("ext")) return createTextNode;
    32213356        if (ref == QLatin1String("extArea")) return createTextAreaNode;
     3357        if (ref == QLatin1String("span")) return createTspanNode;
    32223358        break;
    32233359    case 'u':
     
    32763412        if (ref == QLatin1String("break")) return parseTbreakNode;
    32773413        if (ref == QLatin1String("itle")) return parseTitleNode;
    3278         if (ref == QLatin1String("span")) return parseTspanNode;
    32793414        break;
    32803415    default:
     
    33673502    m_doc = 0;
    33683503    m_style = 0;
     3504    m_animEnd = 0;
    33693505    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);
    33713507    m_defaultPen.setMiterLimit(4);
    33723508    parse();
     
    34053541            break;
    34063542        default:
    3407             ;
    3408         }
    3409     }
     3543            break;
     3544        }
     3545    }
     3546    resolveGradients(m_doc);
    34103547}
    34113548
     
    34153552    QSvgNode *node = 0;
    34163553
    3417     if (m_colorTagCount.count()) {
    3418         int top = m_colorTagCount.pop();
    3419         ++top;
    3420         m_colorTagCount.push(top);
    3421     }
     3554    pushColorCopy();
    34223555
    34233556    /* The xml:space attribute may appear on any element. We do
     
    34253558     * the XML namespace can only be bound to prefix "xml." */
    34263559    const QStringRef xmlSpace(attributes.value(QLatin1String("xml:space")));
    3427     if(xmlSpace.isNull())
    3428     {
     3560    if (xmlSpace.isNull()) {
    34293561        // 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")) {
    34303566        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 {
    34383568        qWarning() << QString::fromLatin1("\"%1\" is an invalid value for attribute xml:space. "
    34393569                                          "Valid values are \"preserve\" and \"default\".").arg(xmlSpace.toString());
    3440 
    34413570        m_whitespaceMode.push(QSvgText::Default);
    34423571    }
     
    34843613            }
    34853614                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;
    34863625            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);
    34933635                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            }
    34963642        }
    34973643    } else if (ParseMethod method = findUtilFactory(localName)) {
     
    35043650        if (prop) {
    35053651            m_style = prop;
    3506             m_nodes.top()->appendStyleProperty(prop, someId(attributes), true);
     3652            m_nodes.top()->appendStyleProperty(prop, someId(attributes));
    35073653        } else {
    3508             qWarning("Couldn't parse node: %s", qPrintable(localName));
     3654            qWarning("Could not parse node: %s", qPrintable(localName));
    35093655        }
    35103656    } else if (StyleParseMethod method = findStyleUtilFactoryMethod(localName)) {
     
    35363682    m_whitespaceMode.pop();
    35373683
    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();
    35473685
    35483686    if (node == Unknown) {
     
    35503688    }
    35513689
    3552     if (m_inStyle && localName == QLatin1String("style")) {
     3690    if (m_inStyle && localName == QLatin1String("style"))
    35533691        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     }
    35593692
    35603693    if (node == Graphics)
     
    35643697
    35653698    return true;
     3699}
     3700
     3701void 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    }
    35663737}
    35673738
     
    35783749
    35793750    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());
    35823754    }
    35833755
     
    36043776    m_colorStack.push(color);
    36053777    m_colorTagCount.push(1);
     3778}
     3779
     3780void QSvgHandler::pushColorCopy()
     3781{
     3782    if (m_colorTagCount.count())
     3783        ++m_colorTagCount.top();
     3784    else
     3785        pushColor(Qt::black);
     3786}
     3787
     3788void QSvgHandler::popColor()
     3789{
     3790    if (m_colorTagCount.count()) {
     3791        if (!--m_colorTagCount.top()) {
     3792            m_colorStack.pop();
     3793            m_colorTagCount.pop();
     3794        }
     3795    }
    36063796}
    36073797
Note: See TracChangeset for help on using the changeset viewer.