Changeset 561 for trunk/src/svg


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:
24 edited

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/src/svg/qgraphicssvgitem.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**
     
    5353QT_BEGIN_NAMESPACE
    5454
    55 class QGraphicsSvgItemPrivate : public QObjectPrivate
     55class QGraphicsSvgItemPrivate : public QGraphicsItemPrivate
    5656{
    5757public:
     
    6363    }
    6464
    65     void init()
     65    void init(QGraphicsItem *parent)
    6666    {
    6767        Q_Q(QGraphicsSvgItem);
     68        q->setParentItem(parent);
    6869        renderer = new QSvgRenderer(q);
    6970        QObject::connect(renderer, SIGNAL(repaintNeeded()),
     
    100101/*!
    101102    \class QGraphicsSvgItem
    102     \ingroup multimedia
    103103    \ingroup graphicsview-api
    104104    \brief The QGraphicsSvgItem class is a QGraphicsItem that can be used to render
     
    139139*/
    140140QGraphicsSvgItem::QGraphicsSvgItem(QGraphicsItem *parent)
    141     : QObject(*new QGraphicsSvgItemPrivate(), 0), QGraphicsItem(parent)
    142 {
    143     Q_D(QGraphicsSvgItem);
    144     d->init();
     141    : QGraphicsObject(*new QGraphicsSvgItemPrivate(), 0, 0)
     142{
     143    Q_D(QGraphicsSvgItem);
     144    d->init(parent);
    145145}
    146146
     
    150150*/
    151151QGraphicsSvgItem::QGraphicsSvgItem(const QString &fileName, QGraphicsItem *parent)
    152     : QObject(*new QGraphicsSvgItemPrivate(), 0), QGraphicsItem(parent)
    153 {
    154     Q_D(QGraphicsSvgItem);
    155     d->init();
     152    : QGraphicsObject(*new QGraphicsSvgItemPrivate(), 0, 0)
     153{
     154    Q_D(QGraphicsSvgItem);
     155    d->init(parent);
    156156    d->renderer->load(fileName);
    157157    d->updateDefaultSize();
     
    187187{
    188188    const QRectF murect = painter->transform().mapRect(QRectF(0, 0, 1, 1));
    189     if (qFuzzyCompare(qMax(murect.width(), murect.height()) + 1, 1))
     189    if (qFuzzyIsNull(qMax(murect.width(), murect.height())))
    190190        return;
    191191
     
    266266}
    267267
     268/*!
     269  \property QGraphicsSvgItem::maximumCacheSize
     270
     271  This property holds the maximum size of the device coordinate cache
     272  for this item.
     273 */
    268274
    269275/*!
     
    306312
    307313/*!
    308     Sets the XML ID of the element that this item should render to \a
    309     id.
     314  \property QGraphicsSvgItem::elementId
     315
     316  This property holds the element's XML ID.
     317 */
     318
     319/*!
     320    Sets the XML ID of the element to \a id.
    310321*/
    311322void QGraphicsSvgItem::setElementId(const QString &id)
     
    319330/*!
    320331    Returns the XML ID the element that is currently
    321     being renderer. Returns an empty string if the whole
     332    being rendered. Returns an empty string if the whole
    322333    file is being rendered.
    323334*/
  • trunk/src/svg/qgraphicssvgitem.h

    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**
     
    4343
    4444#include <QtGui/qgraphicsitem.h>
    45 #include <QtCore/qobject.h>
    4645
    4746#ifndef QT_NO_GRAPHICSSVGITEM
     
    5655class QGraphicsSvgItemPrivate;
    5756
    58 class Q_SVG_EXPORT QGraphicsSvgItem : public QObject, public QGraphicsItem
     57class Q_SVG_EXPORT QGraphicsSvgItem : public QGraphicsObject
    5958{
    6059    Q_OBJECT
     60    Q_INTERFACES(QGraphicsItem)
     61    Q_PROPERTY(QString elementId READ elementId WRITE setElementId)
     62    Q_PROPERTY(QSize maximumCacheSize READ maximumCacheSize WRITE setMaximumCacheSize)
    6163
    6264public:
     
    8789private:
    8890    Q_DISABLE_COPY(QGraphicsSvgItem)
    89 
    90     // Q_DECLARE_PRIVATE_WITH_BASE(QGraphicsSvgItem, QObject)
    91     inline QGraphicsSvgItemPrivate *d_func()
    92     { return reinterpret_cast<QGraphicsSvgItemPrivate *>(QObject::d_ptr); }
    93     inline const QGraphicsSvgItemPrivate *d_func() const
    94     { return reinterpret_cast<const QGraphicsSvgItemPrivate *>(QObject::d_ptr); }
    95     friend class QGraphicsSvgItemPrivate;
     91    Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QGraphicsSvgItem)
    9692
    9793    Q_PRIVATE_SLOT(d_func(), void _q_repaintItem())
  • trunk/src/svg/qsvgfont.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**
  • trunk/src/svg/qsvgfont_p.h

    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**
  • trunk/src/svg/qsvggenerator.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**
     
    262262
    263263            if (!constantAlpha) {
    264                 const qreal spacing = 0.02;
     264                const qreal spacing = qreal(0.02);
    265265                QGradientStops newStops;
    266266                QRgb fromColor = PREMUL(stops.at(0).second.rgba());
     
    363363
    364364            // SVG uses absolute offset
    365             dashOffset = QString::fromLatin1("%1").arg(spen.dashOffset() * penWidth);
     365            dashOffset = QString::number(spen.dashOffset() * penWidth);
    366366
    367367            d_func()->attributes.stroke = color;
     
    404404        switch (spen.joinStyle()) {
    405405        case Qt::MiterJoin:
    406             stream() << "stroke-linejoin=\"miter\" ";
    407             stream() << "stroke-miterlimit=\""<<spen.miterLimit()<<"\" ";
     406            stream() << "stroke-linejoin=\"miter\" "
     407                        "stroke-miterlimit=\""<<spen.miterLimit()<<"\" ";
    408408            break;
    409409        case Qt::BevelJoin:
     
    414414            break;
    415415        case Qt::SvgMiterJoin:
    416             stream() << "stroke-linejoin=\"miter\" ";
    417             stream() << "stroke-miterlimit=\""<<spen.miterLimit()<<"\" ";
     416            stream() << "stroke-linejoin=\"miter\" "
     417                        "stroke-miterlimit=\""<<spen.miterLimit()<<"\" ";
    418418            break;
    419419        default:
     
    428428            QString color, colorOpacity;
    429429            translate_color(sbrush.color(), &color, &colorOpacity);
    430             stream() << "fill=\"" << color << "\" ";
    431             stream() << "fill-opacity=\""
     430            stream() << "fill=\"" << color << "\" "
     431                        "fill-opacity=\""
    432432                     << colorOpacity << "\" ";
    433433            d_func()->attributes.fill = color;
     
    494494
    495495        *d->stream << "font-family=\"" << d->attributes.font_family << "\" "
    496                    << "font-size=\"" << d->attributes.font_size << "\" "
    497                    << "font-weight=\"" << d->attributes.font_weight << "\" "
    498                    << "font-style=\"" << d->attributes.font_style << "\" "
     496                     "font-size=\"" << d->attributes.font_size << "\" "
     497                     "font-weight=\"" << d->attributes.font_weight << "\" "
     498                     "font-style=\"" << d->attributes.font_style << "\" "
    499499                   << endl;
    500500    }
     
    512512/*!
    513513    \class QSvgGenerator
    514     \ingroup multimedia
     514    \ingroup painting
    515515    \since 4.3
    516516    \brief The QSvgGenerator class provides a paint device that is used to create SVG drawings.
     
    568568        delete d->engine->outputDevice();
    569569    delete d->engine;
    570     delete d_ptr;
    571570}
    572571
     
    850849
    851850    if (d->viewBox.isValid()) {
    852         *d->stream << " viewBox=\"" << d->viewBox.left() << " " << d->viewBox.top();
    853         *d->stream << " " << d->viewBox.width() << " " << d->viewBox.height() << "\"" << endl;
     851        *d->stream << " viewBox=\"" << d->viewBox.left() << ' ' << d->viewBox.top();
     852        *d->stream << ' ' << d->viewBox.width() << ' ' << d->viewBox.height() << '\"' << endl;
    854853    }
    855854
    856855    *d->stream << " xmlns=\"http://www.w3.org/2000/svg\""
    857                << " xmlns:xlink=\"http://www.w3.org/1999/xlink\" "
    858                << " version=\"1.2\" baseProfile=\"tiny\">" << endl;
     856                 " xmlns:xlink=\"http://www.w3.org/1999/xlink\" "
     857                 " version=\"1.2\" baseProfile=\"tiny\">" << endl;
    859858
    860859    if (!d->attributes.document_title.isEmpty()) {
     
    919918    Q_UNUSED(flags);
    920919    stream() << "<image ";
    921     stream() << "x=\""<<r.x()<<"\" ";
    922     stream() << "y=\""<<r.y()<<"\" ";
    923     stream() << "width=\""<<r.width()<<"\" ";
    924     stream() << "height=\""<<r.height()<<"\" ";
     920    stream() << "x=\""<<r.x()<<"\" "
     921                "y=\""<<r.y()<<"\" "
     922                "width=\""<<r.width()<<"\" "
     923                "height=\""<<r.height()<<"\" "
     924                "preserveAspectRatio=\"none\" ";
    925925
    926926    QByteArray data;
     
    931931    stream() << "xlink:href=\"data:image/png;base64,"
    932932             << data.toBase64()
    933              <<"\" ";
    934     stream() << "/>\n";
     933             <<"\" />\n";
    935934}
    936935
     
    959958    if (flags & QPaintEngine::DirtyTransform) {
    960959        d->matrix = state.matrix();
    961         *d->stream << "transform=\"matrix(" << d->matrix.m11() << ","
    962                    << d->matrix.m12() << ","
    963                    << d->matrix.m21() << "," << d->matrix.m22() << ","
    964                    << d->matrix.dx() << "," << d->matrix.dy()
     960        *d->stream << "transform=\"matrix(" << d->matrix.m11() << ','
     961                   << d->matrix.m12() << ','
     962                   << d->matrix.m21() << ',' << d->matrix.m22() << ','
     963                   << d->matrix.dx() << ',' << d->matrix.dy()
    965964                   << ")\""
    966965                   << endl;
     
    972971
    973972    if (flags & QPaintEngine::DirtyOpacity) {
    974         if (!qFuzzyCompare(state.opacity(), 1))
     973        if (!qFuzzyIsNull(state.opacity() - 1))
    975974            stream() << "opacity=\""<<state.opacity()<<"\" ";
    976975    }
    977976
    978     *d->stream << ">" << endl;
     977    *d->stream << '>' << endl;
    979978
    980979    d->afterFirstUpdate = true;
     
    985984    Q_D(QSvgPaintEngine);
    986985
    987     *d->stream << "<path ";
    988 
    989 
    990     *d->stream << "fill-rule=";
     986    *d->stream << "<path "
     987                  "fill-rule=";
    991988    if (p.fillRule() == Qt::OddEvenFill)
    992989        *d->stream << "\"evenodd\" ";
     
    1000997        switch (e.type) {
    1001998        case QPainterPath::MoveToElement:
    1002             *d->stream << "M" << e.x << "," << e.y;
     999            *d->stream << 'M' << e.x << ',' << e.y;
    10031000            break;
    10041001        case QPainterPath::LineToElement:
    1005             *d->stream << "L" << e.x << "," << e.y;
     1002            *d->stream << 'L' << e.x << ',' << e.y;
    10061003            break;
    10071004        case QPainterPath::CurveToElement:
    1008             *d->stream << "C" << e.x << "," << e.y;
     1005            *d->stream << 'C' << e.x << ',' << e.y;
    10091006            ++i;
    10101007            while (i < p.elementCount()) {
     
    10141011                    break;
    10151012                } else
    1016                     *d->stream << " ";
    1017                 *d->stream << e.x << "," << e.y;
     1013                    *d->stream << ' ';
     1014                *d->stream << e.x << ',' << e.y;
    10181015                ++i;
    10191016            }
     
    10231020        }
    10241021        if (i != p.elementCount() - 1) {
    1025             *d->stream << " ";
     1022            *d->stream << ' ';
    10261023        }
    10271024    }
     
    10451042        for (int i = 0; i < pointCount; ++i) {
    10461043            const QPointF &pt = points[i];
    1047             stream() << pt.x() << "," << pt.y() << " ";
     1044            stream() << pt.x() << ',' << pt.y() << ' ';
    10481045        }
    10491046        stream() << "\" />" <<endl;
     
    10641061
    10651062    *d->stream << "<text "
    1066                << "fill=\"" << d->attributes.stroke << "\" "
    1067                << "fill-opacity=\"" << d->attributes.strokeOpacity << "\" "
    1068                << "stroke=\"none\" "
    1069                << "x=\"" << pt.x() << "\" y=\"" << pt.y() << "\" ";
     1063                  "fill=\"" << d->attributes.stroke << "\" "
     1064                  "fill-opacity=\"" << d->attributes.strokeOpacity << "\" "
     1065                  "stroke=\"none\" "
     1066                  "xml:space=\"preserve\" "
     1067                  "x=\"" << pt.x() << "\" y=\"" << pt.y() << "\" ";
    10701068    qfontToSvg(textItem.font());
    10711069    *d->stream << " >"
  • trunk/src/svg/qsvggenerator.h

    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**
     
    5050#include <QtCore/qiodevice.h>
    5151#include <QtCore/qobjectdefs.h>
     52#include <QtCore/qscopedpointer.h>
    5253
    5354QT_BEGIN_HEADER
     
    101102
    102103private:
    103     QSvgGeneratorPrivate *d_ptr;
     104    QScopedPointer<QSvgGeneratorPrivate> d_ptr;
    104105};
    105106
  • trunk/src/svg/qsvggraphics.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**
     
    5757QT_BEGIN_NAMESPACE
    5858
    59 #define QT_SVG_DRAW_SHAPE(command)                  \
    60     applyStyle(p, states);                          \
    61     qreal oldOpacity = p->opacity();                \
    62     QBrush oldBrush = p->brush();                   \
    63     QPen oldPen = p->pen();                         \
    64     p->setPen(Qt::NoPen);                           \
    65     p->setOpacity(oldOpacity * states.fillOpacity); \
    66     command;                                        \
    67     p->setOpacity(oldOpacity);                      \
    68     p->setPen(oldPen);                              \
    69     p->setBrush(Qt::NoBrush);                       \
    70     command;                                        \
    71     p->setBrush(oldBrush);                          \
    72     revertStyle(p, states);
     59#define QT_SVG_DRAW_SHAPE(command)                          \
     60    qreal oldOpacity = p->opacity();                        \
     61    QBrush oldBrush = p->brush();                           \
     62    QPen oldPen = p->pen();                                 \
     63    p->setPen(Qt::NoPen);                                   \
     64    p->setOpacity(oldOpacity * states.fillOpacity);         \
     65    command;                                                \
     66    p->setPen(oldPen);                                      \
     67    if (oldPen.widthF() != 0) {                             \
     68        p->setOpacity(oldOpacity * states.strokeOpacity);   \
     69        p->setBrush(Qt::NoBrush);                           \
     70        command;                                            \
     71        p->setBrush(oldBrush);                              \
     72    }                                                       \
     73    p->setOpacity(oldOpacity);
    7374
    7475
     
    9596{
    9697    qreal sw = strokeWidth();
    97     if (qFuzzyCompare(sw + 1, 1))
     98    if (qFuzzyIsNull(sw))
    9899        return m_bounds;
    99100    else {
     
    106107void QSvgCircle::draw(QPainter *p, QSvgExtraStates &states)
    107108{
     109    applyStyle(p, states);
    108110    QT_SVG_DRAW_SHAPE(p->drawEllipse(m_bounds));
     111    revertStyle(p, states);
    109112}
    110113
     
    118121{
    119122    applyStyle(p, states);
    120     p->drawPath(cubic);
     123    if (p->pen().widthF() != 0) {
     124        qreal oldOpacity = p->opacity();
     125        p->setOpacity(oldOpacity * states.strokeOpacity);
     126        p->drawPath(cubic);
     127        p->setOpacity(oldOpacity);
     128    }
    121129    revertStyle(p, states);
    122130}
     
    130138{
    131139    qreal sw = strokeWidth();
    132     if (qFuzzyCompare(sw + 1, 1))
     140    if (qFuzzyIsNull(sw))
    133141        return m_bounds;
    134142    else {
     
    141149void QSvgEllipse::draw(QPainter *p, QSvgExtraStates &states)
    142150{
     151    applyStyle(p, states);
    143152    QT_SVG_DRAW_SHAPE(p->drawEllipse(m_bounds));
     153    revertStyle(p, states);
    144154}
    145155
     
    172182{
    173183    applyStyle(p, states);
    174     p->drawLine(m_bounds);
     184    if (p->pen().widthF() != 0) {
     185        qreal oldOpacity = p->opacity();
     186        p->setOpacity(oldOpacity * states.strokeOpacity);
     187        p->drawLine(m_bounds);
     188        p->setOpacity(oldOpacity);
     189    }
    175190    revertStyle(p, states);
    176191}
     
    179194    : QSvgNode(parent), m_path(qpath)
    180195{
    181     //m_cachedBounds = m_path.controlPointRect();
    182     m_cachedBounds = m_path.boundingRect();
    183196}
    184197
    185198void QSvgPath::draw(QPainter *p, QSvgExtraStates &states)
    186199{
     200    applyStyle(p, states);
     201    m_path.setFillRule(states.fillRule);
    187202    QT_SVG_DRAW_SHAPE(p->drawPath(m_path));
     203    revertStyle(p, states);
    188204}
    189205
     
    191207{
    192208    qreal sw = strokeWidth();
    193     if (qFuzzyCompare(sw + 1, 1))
     209    if (qFuzzyIsNull(sw)) {
     210        if (m_cachedBounds.isNull())
     211            //m_cachedBounds = m_path.controlPointRect();
     212            m_cachedBounds = m_path.boundingRect();
     213
    194214        return m_cachedBounds;
     215    }
    195216    else {
    196217        return boundsOnStroke(m_path, sw);
     
    201222    : QSvgNode(parent), m_poly(poly)
    202223{
    203 
    204224}
    205225
     
    207227{
    208228    qreal sw = strokeWidth();
    209     if (qFuzzyCompare(sw + 1, 1))
     229    if (qFuzzyIsNull(sw))
    210230        return m_poly.boundingRect();
    211231    else {
     
    218238void QSvgPolygon::draw(QPainter *p, QSvgExtraStates &states)
    219239{
    220     QT_SVG_DRAW_SHAPE(p->drawPolygon(m_poly));
     240    applyStyle(p, states);
     241    QT_SVG_DRAW_SHAPE(p->drawPolygon(m_poly, states.fillRule));
     242    revertStyle(p, states);
    221243}
    222244
     
    231253{
    232254    applyStyle(p, states);
     255    qreal oldOpacity = p->opacity();
    233256    if (p->brush().style() != Qt::NoBrush) {
    234257        QPen save = p->pen();
    235258        p->setPen(QPen(Qt::NoPen));
    236         p->drawPolygon(m_poly);
     259        p->setOpacity(oldOpacity * states.fillOpacity);
     260        p->drawPolygon(m_poly, states.fillRule);
    237261        p->setPen(save);
    238262    }
    239     p->drawPolyline(m_poly);
     263    if (p->pen().widthF() != 0) {
     264        p->setOpacity(oldOpacity * states.strokeOpacity);
     265        p->drawPolyline(m_poly);
     266    }
     267    p->setOpacity(oldOpacity);
    240268    revertStyle(p, states);
    241269}
     
    250278{
    251279    qreal sw = strokeWidth();
    252     if (qFuzzyCompare(sw + 1, 1))
     280    if (qFuzzyIsNull(sw))
    253281        return m_rect;
    254282    else {
     
    261289void QSvgRect::draw(QPainter *p, QSvgExtraStates &states)
    262290{
     291    applyStyle(p, states);
    263292    if (m_rx || m_ry) {
    264293        QT_SVG_DRAW_SHAPE(p->drawRoundedRect(m_rect, m_rx, m_ry, Qt::RelativeSize));
     
    266295        QT_SVG_DRAW_SHAPE(p->drawRect(m_rect));
    267296    }
    268 }
     297    revertStyle(p, states);
     298}
     299
     300QSvgTspan * const QSvgText::LINEBREAK = 0;
    269301
    270302QSvgText::QSvgText(QSvgNode *parent, const QPointF &coord)
    271303    : QSvgNode(parent)
    272304    , m_coord(coord)
    273     , m_textAlignment(Qt::AlignLeft)
    274     , m_scale(1)
    275     , m_appendSpace(false)
    276305    , m_type(TEXT)
    277306    , m_size(0, 0)
    278 {
    279     m_paragraphs.push_back(QString());
    280     m_formatRanges.push_back(QList<QTextLayout::FormatRange>());
     307    , m_mode(Default)
     308{
    281309}
    282310
    283311QSvgText::~QSvgText()
    284312{
     313    for (int i = 0; i < m_tspans.size(); ++i) {
     314        if (m_tspans[i] != LINEBREAK)
     315            delete m_tspans[i];
     316    }
    285317}
    286318
     
    296328{
    297329    applyStyle(p, states);
    298 
    299     QSvgFontStyle *fontStyle = static_cast<QSvgFontStyle*>(
    300         styleProperty(QSvgStyleProperty::FONT));
    301     if (fontStyle && fontStyle->svgFont()) {
    302         // SVG fonts not fully supported...
    303         QString text = m_paragraphs.front();
    304         for (int i = 1; i < m_paragraphs.size(); ++i) {
    305             text.append(QLatin1Char('\n'));
    306             text.append(m_paragraphs[i]);
    307         }
    308         fontStyle->svgFont()->draw(p, m_coord, text, fontStyle->pointSize(), m_textAlignment);
    309         revertStyle(p, states);
    310         return;
    311     }
    312 
    313     // Scale the font to its correct size.
     330    qreal oldOpacity = p->opacity();
     331    p->setOpacity(oldOpacity * states.fillOpacity);
     332
     333    // Force the font to have a size of 100 pixels to avoid truncation problems
     334    // when the font is very small.
     335    qreal scale = 100.0 / p->font().pointSizeF();
     336    Qt::Alignment alignment = states.textAnchor;
     337
    314338    QTransform oldTransform = p->worldTransform();
    315     p->scale(1 / m_scale, 1 / m_scale);
     339    p->scale(1 / scale, 1 / scale);
    316340
    317341    qreal y = 0;
    318342    bool initial = true;
    319     qreal px = m_coord.x() * m_scale;
    320     qreal py = m_coord.y() * m_scale;
    321     QSizeF scaledSize = m_size * m_scale;
     343    qreal px = m_coord.x() * scale;
     344    qreal py = m_coord.y() * scale;
     345    QSizeF scaledSize = m_size * scale;
    322346
    323347    if (m_type == TEXTAREA) {
    324         if (m_textAlignment == Qt::AlignHCenter)
     348        if (alignment == Qt::AlignHCenter)
    325349            px += scaledSize.width() / 2;
    326         else if (m_textAlignment == Qt::AlignRight)
     350        else if (alignment == Qt::AlignRight)
    327351            px += scaledSize.width();
    328352    }
     
    330354    QRectF bounds;
    331355    if (m_size.height() != 0)
    332         bounds = QRectF(0, 0, 1, scaledSize.height());
    333 
    334     for (int i = 0; i < m_paragraphs.size(); ++i) {
    335         QTextLayout tl(m_paragraphs[i]);
    336         QTextOption op = tl.textOption();
    337         op.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
    338         tl.setTextOption(op);
    339         tl.setAdditionalFormats(m_formatRanges[i]);
    340         tl.beginLayout();
    341         forever {
    342             QTextLine line = tl.createLine();
    343             if (!line.isValid())
     356        bounds = QRectF(0, py, 1, scaledSize.height()); // x and width are not used.
     357
     358    bool appendSpace = false;
     359    QVector<QString> paragraphs;
     360    QStack<QTextCharFormat> formats;
     361    QVector<QList<QTextLayout::FormatRange> > formatRanges;
     362    paragraphs.push_back(QString());
     363    formatRanges.push_back(QList<QTextLayout::FormatRange>());
     364
     365    for (int i = 0; i < m_tspans.size(); ++i) {
     366        if (m_tspans[i] == LINEBREAK) {
     367            if (m_type == TEXTAREA) {
     368                if (paragraphs.back().isEmpty()) {
     369                    QFont font = p->font();
     370                    font.setPixelSize(font.pointSizeF() * scale);
     371
     372                    QTextLayout::FormatRange range;
     373                    range.start = 0;
     374                    range.length = 1;
     375                    range.format.setFont(font);
     376                    formatRanges.back().append(range);
     377
     378                    paragraphs.back().append(QLatin1Char(' '));;
     379                }
     380                appendSpace = false;
     381                paragraphs.push_back(QString());
     382                formatRanges.push_back(QList<QTextLayout::FormatRange>());
     383            }
     384        } else {
     385            WhitespaceMode mode = m_tspans[i]->whitespaceMode();
     386            m_tspans[i]->applyStyle(p, states);
     387
     388            QFont font = p->font();
     389            font.setPixelSize(font.pointSizeF() * scale);
     390
     391            QString newText(m_tspans[i]->text());
     392            newText.replace(QLatin1Char('\t'), QLatin1Char(' '));
     393            newText.replace(QLatin1Char('\n'), QLatin1Char(' '));
     394
     395            bool prependSpace = !appendSpace && !m_tspans[i]->isTspan() && (mode == Default) && !paragraphs.back().isEmpty() && newText.startsWith(QLatin1Char(' '));
     396            if (appendSpace || prependSpace)
     397                paragraphs.back().append(QLatin1Char(' '));
     398
     399            bool appendSpaceNext = (!m_tspans[i]->isTspan() && (mode == Default) && newText.endsWith(QLatin1Char(' ')));
     400
     401            if (mode == Default) {
     402                newText = newText.simplified();
     403                if (newText.isEmpty())
     404                    appendSpaceNext = false;
     405            }
     406
     407            QTextLayout::FormatRange range;
     408            range.start = paragraphs.back().length();
     409            range.length = newText.length();
     410            range.format.setFont(font);
     411            range.format.setTextOutline(p->pen());
     412            range.format.setForeground(p->brush());
     413
     414            if (appendSpace) {
     415                Q_ASSERT(!formatRanges.back().isEmpty());
     416                ++formatRanges.back().back().length;
     417            } else if (prependSpace) {
     418                --range.start;
     419                ++range.length;
     420            }
     421            formatRanges.back().append(range);
     422
     423            appendSpace = appendSpaceNext;
     424            paragraphs.back() += newText;
     425
     426            m_tspans[i]->revertStyle(p, states);
     427        }
     428    }
     429
     430    if (states.svgFont) {
     431        // SVG fonts not fully supported...
     432        QString text = paragraphs.front();
     433        for (int i = 1; i < paragraphs.size(); ++i) {
     434            text.append(QLatin1Char('\n'));
     435            text.append(paragraphs[i]);
     436        }
     437        states.svgFont->draw(p, m_coord * scale, text, p->font().pointSizeF() * scale, states.textAnchor);
     438    } else {
     439        for (int i = 0; i < paragraphs.size(); ++i) {
     440            QTextLayout tl(paragraphs[i]);
     441            QTextOption op = tl.textOption();
     442            op.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
     443            tl.setTextOption(op);
     444            tl.setAdditionalFormats(formatRanges[i]);
     445            tl.beginLayout();
     446
     447            forever {
     448                QTextLine line = tl.createLine();
     449                if (!line.isValid())
     450                    break;
     451                if (m_size.width() != 0)
     452                    line.setLineWidth(scaledSize.width());
     453            }
     454            tl.endLayout();
     455
     456            bool endOfBoundsReached = false;
     457            for (int i = 0; i < tl.lineCount(); ++i) {
     458                QTextLine line = tl.lineAt(i);
     459
     460                qreal x = 0;
     461                if (alignment == Qt::AlignHCenter)
     462                    x -= 0.5 * line.naturalTextWidth();
     463                else if (alignment == Qt::AlignRight)
     464                    x -= line.naturalTextWidth();
     465
     466                if (initial && m_type == TEXT)
     467                    y -= line.ascent();
     468                initial = false;
     469
     470                line.setPosition(QPointF(x, y));
     471
     472                // Check if the current line fits into the bounding rectangle.
     473                if ((m_size.width() != 0 && line.naturalTextWidth() > scaledSize.width())
     474                    || (m_size.height() != 0 && y + line.height() > scaledSize.height())) {
     475                    // I need to set the bounds height to 'y-epsilon' to avoid drawing the current
     476                    // line. Since the font is scaled to 100 units, 1 should be a safe epsilon.
     477                    bounds.setHeight(y - 1);
     478                    endOfBoundsReached = true;
     479                    break;
     480                }
     481
     482                y += 1.1 * line.height();
     483            }
     484            tl.draw(p, QPointF(px, py), QVector<QTextLayout::FormatRange>(), bounds);
     485
     486            if (endOfBoundsReached)
    344487                break;
    345 
    346             if (m_size.width() != 0)
    347                 line.setLineWidth(scaledSize.width());
    348488        }
    349         tl.endLayout();
    350 
    351         bool endOfBoundsReached = false;
    352         for (int i = 0; i < tl.lineCount(); ++i) {
    353             QTextLine line = tl.lineAt(i);
    354 
    355             qreal x = 0;
    356             if (m_textAlignment == Qt::AlignHCenter)
    357                 x -= line.naturalTextWidth() / 2;
    358             else if (m_textAlignment == Qt::AlignRight)
    359                 x -= line.naturalTextWidth();
    360 
    361             if (initial && m_type == TEXT)
    362                 y -= line.ascent();
    363             initial = false;
    364 
    365             line.setPosition(QPointF(x, y));
    366             if ((m_size.width() != 0 && line.naturalTextWidth() > scaledSize.width())
    367                 || (m_size.height() != 0 && y + line.height() > scaledSize.height())) {
    368                 bounds.setHeight(y);
    369                 endOfBoundsReached = true;
    370                 break;
    371             }
    372 
    373             y += 1.1 * line.height();
    374         }
    375         tl.draw(p, QPointF(px, py), QVector<QTextLayout::FormatRange>(), bounds);
    376 
    377         if (endOfBoundsReached)
    378             break;
    379489    }
    380490
    381491    p->setWorldTransform(oldTransform, false);
    382     revertStyle(p, states);
    383 }
    384 
    385 void QSvgText::insertText(const QString &text, WhitespaceMode mode)
    386 {
    387     bool isTSpan = (m_formats.count() == 2);
    388     QString newText(text);
    389     newText.replace(QLatin1Char('\t'), QLatin1Char(' '));
    390     newText.replace(QLatin1Char('\n'), QLatin1Char(' '));
    391 
    392     bool prependSpace = !m_appendSpace && !isTSpan && (mode == Default) && !m_paragraphs.back().isEmpty() && newText.startsWith(QLatin1Char(' '));
    393     if (m_appendSpace || prependSpace)
    394         m_paragraphs.back().append(QLatin1Char(' '));
    395 
    396     bool appendSpaceNext = (!isTSpan && (mode == Default) && newText.endsWith(QLatin1Char(' ')));
    397 
    398     if (mode == Default) {
    399         newText = newText.simplified();
    400         if (newText.isEmpty())
    401             appendSpaceNext = false;
    402     }
    403 
    404     if (!m_formats.isEmpty()) {
    405         QTextLayout::FormatRange range;
    406         range.start = m_paragraphs.back().length();
    407         range.length = newText.length();
    408         range.format = m_formats.top();
    409         if (m_appendSpace) {
    410             Q_ASSERT(!m_formatRanges.back().isEmpty());
    411             ++m_formatRanges.back().back().length;
    412         } else if (prependSpace) {
    413             --range.start;
    414             ++range.length;
    415         }
    416         m_formatRanges.back().append(range);
    417     }
    418 
    419     m_appendSpace = appendSpaceNext;
    420     m_paragraphs.back() += newText;
    421 }
    422 
    423 void QSvgText::insertFormat(const QTextCharFormat &format)
    424 {
    425     QTextCharFormat mergedFormat = format;
    426     if (!m_formats.isEmpty()) {
    427         mergedFormat = m_formats.top();
    428         mergedFormat.merge(format);
    429     }
    430     m_formats.push(mergedFormat);
    431 }
    432 
    433 void QSvgText::insertLineBreak()
    434 {
    435     if (m_type == TEXTAREA) {
    436         if (m_paragraphs.back().isEmpty())
    437             insertText(QLatin1String(" "), Preserve);
    438         m_appendSpace = false;
    439         m_paragraphs.push_back(QString());
    440         m_formatRanges.push_back(QList<QTextLayout::FormatRange>());
    441     }
    442 }
    443 
    444 void QSvgText::popFormat()
    445 {
    446     if (m_formats.count() > 1)
    447         m_formats.pop();
    448 }
    449 
    450 qreal QSvgText::scale() const
    451 {
    452     return m_scale;
    453 }
    454 
    455 void QSvgText::setScale(qreal scale)
    456 {
    457     m_scale = scale;
    458 }
    459 
    460 const QTextCharFormat &QSvgText::topFormat() const
    461 {
    462     return m_formats.top();
    463 }
    464 
    465 void QSvgText::setTextAlignment(const Qt::Alignment &alignment)
    466 {
    467     m_textAlignment = alignment;
     492    p->setOpacity(oldOpacity);
     493    revertStyle(p, states);
     494}
     495
     496void QSvgText::addText(const QString &text)
     497{
     498    m_tspans.append(new QSvgTspan(this, false));
     499    m_tspans.back()->setWhitespaceMode(m_mode);
     500    m_tspans.back()->addText(text);
    468501}
    469502
     
    597630{
    598631    qreal sw = strokeWidth();
    599     if (qFuzzyCompare(sw + 1, 1))
     632    if (qFuzzyIsNull(sw))
    600633        return m_poly.boundingRect();
    601634    else {
     
    609642{
    610643    qreal sw = strokeWidth();
    611     if (qFuzzyCompare(sw + 1, 1))
     644    if (qFuzzyIsNull(sw))
    612645        return m_cachedBounds;
    613646    else {
     
    624657{
    625658    qreal sw = strokeWidth();
    626     if (qFuzzyCompare(sw + 1, 1)) {
     659    if (qFuzzyIsNull(sw)) {
    627660        qreal minX = qMin(m_bounds.x1(), m_bounds.x2());
    628661        qreal minY = qMin(m_bounds.y1(), m_bounds.y2());
  • trunk/src/svg/qsvggraphics_p.h

    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**
     
    146146private:
    147147    QPainterPath m_path;
    148     QRectF m_cachedBounds;
     148    mutable QRectF m_cachedBounds;
    149149};
    150150
     
    182182    int m_rx, m_ry;
    183183};
     184
     185class  QSvgTspan;
    184186
    185187class  QSvgText : public QSvgNode
     
    198200    virtual void draw(QPainter *p, QSvgExtraStates &states);
    199201    virtual Type type() const;
    200     void insertText(const QString &text, WhitespaceMode mode);
    201     void insertFormat(const QTextCharFormat &format);
    202     void insertLineBreak();
    203     void popFormat();
    204     void setTextAlignment(const Qt::Alignment &alignment);
    205     const QTextCharFormat &topFormat() const;
    206     qreal scale() const;
    207     void setScale(qreal scale);
     202
     203    void addTspan(QSvgTspan *tspan) {m_tspans.append(tspan);}
     204    void addText(const QString &text);
     205    void addLineBreak() {m_tspans.append(LINEBREAK);}
     206    void setWhitespaceMode(WhitespaceMode mode) {m_mode = mode;}
     207
    208208    //virtual QRectF bounds() const;
    209209private:
     210    static QSvgTspan * const LINEBREAK;
     211
    210212    QPointF m_coord;
    211213
    212     QVector<QString> m_paragraphs;
    213     QStack<QTextCharFormat> m_formats;
    214     Qt::Alignment           m_textAlignment;
    215     QVector<QList<QTextLayout::FormatRange> > m_formatRanges;
    216     qreal m_scale;
    217     bool m_appendSpace;
     214    // 'm_tspans' is also used to store characters outside tspans and line breaks.
     215    // If a 'm_tspan' item is null, it indicates a line break.
     216    QVector<QSvgTspan *> m_tspans;
     217
    218218    Type m_type;
    219219    QSizeF m_size;
     220    WhitespaceMode m_mode;
     221};
     222
     223class  QSvgTspan : public QSvgNode
     224{
     225public:
     226    // tspans are also used to store normal text, so the 'isProperTspan' is used to separate text from tspan.
     227    QSvgTspan(QSvgNode *parent, bool isProperTspan = true)
     228        : QSvgNode(parent), m_mode(QSvgText::Default), m_isTspan(isProperTspan)
     229    {
     230    }
     231    ~QSvgTspan() { };
     232    virtual Type type() const {return TSPAN;}
     233    virtual void draw(QPainter *, QSvgExtraStates &) {Q_ASSERT(!"Tspans should be drawn through QSvgText::draw().");}
     234    void addText(const QString &text) {m_text += text;}
     235    const QString &text() const {return m_text;}
     236    bool isTspan() const {return m_isTspan;}
     237    void setWhitespaceMode(QSvgText::WhitespaceMode mode) {m_mode = mode;}
     238    QSvgText::WhitespaceMode whitespaceMode() const {return m_mode;}
     239private:
     240    QString m_text;
     241    QSvgText::WhitespaceMode m_mode;
     242    bool m_isTspan;
    220243};
    221244
  • 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
  • trunk/src/svg/qsvghandler_p.h

    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**
     
    112112
    113113    void pushColor(const QColor &color);
     114    void pushColorCopy();
     115    void popColor();
    114116    QColor currentColor() const;
    115117
     
    171173    QCss::Parser m_cssParser;
    172174    void parse();
     175    void resolveGradients(QSvgNode *node);
    173176
    174177    QPen m_defaultPen;
  • trunk/src/svg/qsvgnode.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**
     
    6161}
    6262
    63 void QSvgNode::appendStyleProperty(QSvgStyleProperty *prop, const QString &id,
    64                                    bool justLink)
     63void QSvgNode::appendStyleProperty(QSvgStyleProperty *prop, const QString &id)
    6564{
    6665    //qDebug()<<"appending "<<prop->type()<< " ("<< id <<") "<<"to "<<this<<this->type();
    67     if (!justLink) {
    68         switch (prop->type()) {
    69         case QSvgStyleProperty::QUALITY:
    70             m_style.quality = static_cast<QSvgQualityStyle*>(prop);
    71             break;
    72         case QSvgStyleProperty::FILL:
    73             m_style.fill = static_cast<QSvgFillStyle*>(prop);
    74             break;
    75         case QSvgStyleProperty::VIEWPORT_FILL:
    76             m_style.viewportFill = static_cast<QSvgViewportFillStyle*>(prop);
    77             break;
    78         case QSvgStyleProperty::FONT:
    79             m_style.font = static_cast<QSvgFontStyle*>(prop);
    80             break;
    81         case QSvgStyleProperty::STROKE:
    82             m_style.stroke = static_cast<QSvgStrokeStyle*>(prop);
    83             break;
    84         case QSvgStyleProperty::SOLID_COLOR:
    85             m_style.solidColor = static_cast<QSvgSolidColorStyle*>(prop);
    86             break;
    87         case QSvgStyleProperty::GRADIENT:
    88             m_style.gradient = static_cast<QSvgGradientStyle*>(prop);
    89             break;
    90         case QSvgStyleProperty::TRANSFORM:
    91             m_style.transform = static_cast<QSvgTransformStyle*>(prop);
    92             break;
    93         case QSvgStyleProperty::ANIMATE_COLOR:
    94             m_style.animateColor = static_cast<QSvgAnimateColor*>(prop);
    95             break;
    96         case QSvgStyleProperty::ANIMATE_TRANSFORM:
    97             m_style.animateTransforms.append(
    98                 static_cast<QSvgAnimateTransform*>(prop));
    99             break;
    100         case QSvgStyleProperty::OPACITY:
    101             m_style.opacity = static_cast<QSvgOpacityStyle*>(prop);
    102             break;
    103         case QSvgStyleProperty::COMP_OP:
    104             m_style.compop = static_cast<QSvgCompOpStyle*>(prop);
    105             break;
    106         default:
    107             qDebug("QSvgNode: Trying to append unknown property!");
    108             break;
    109         }
    110     }
    111     if (!id.isEmpty()) {
    112         m_styles.insert(id, prop);
     66    QSvgTinyDocument *doc;
     67    switch (prop->type()) {
     68    case QSvgStyleProperty::QUALITY:
     69        m_style.quality = static_cast<QSvgQualityStyle*>(prop);
     70        break;
     71    case QSvgStyleProperty::FILL:
     72        m_style.fill = static_cast<QSvgFillStyle*>(prop);
     73        break;
     74    case QSvgStyleProperty::VIEWPORT_FILL:
     75        m_style.viewportFill = static_cast<QSvgViewportFillStyle*>(prop);
     76        break;
     77    case QSvgStyleProperty::FONT:
     78        m_style.font = static_cast<QSvgFontStyle*>(prop);
     79        break;
     80    case QSvgStyleProperty::STROKE:
     81        m_style.stroke = static_cast<QSvgStrokeStyle*>(prop);
     82        break;
     83    case QSvgStyleProperty::SOLID_COLOR:
     84        m_style.solidColor = static_cast<QSvgSolidColorStyle*>(prop);
     85        doc = document();
     86        if (doc && !id.isEmpty())
     87            doc->addNamedStyle(id, m_style.solidColor);
     88        break;
     89    case QSvgStyleProperty::GRADIENT:
     90        m_style.gradient = static_cast<QSvgGradientStyle*>(prop);
     91        doc = document();
     92        if (doc && !id.isEmpty())
     93            doc->addNamedStyle(id, m_style.gradient);
     94        break;
     95    case QSvgStyleProperty::TRANSFORM:
     96        m_style.transform = static_cast<QSvgTransformStyle*>(prop);
     97        break;
     98    case QSvgStyleProperty::ANIMATE_COLOR:
     99        m_style.animateColor = static_cast<QSvgAnimateColor*>(prop);
     100        break;
     101    case QSvgStyleProperty::ANIMATE_TRANSFORM:
     102        m_style.animateTransforms.append(
     103            static_cast<QSvgAnimateTransform*>(prop));
     104        break;
     105    case QSvgStyleProperty::OPACITY:
     106        m_style.opacity = static_cast<QSvgOpacityStyle*>(prop);
     107        break;
     108    case QSvgStyleProperty::COMP_OP:
     109        m_style.compop = static_cast<QSvgCompOpStyle*>(prop);
     110        break;
     111    default:
     112        qDebug("QSvgNode: Trying to append unknown property!");
     113        break;
    113114    }
    114115}
     
    186187}
    187188
    188 QSvgStyleProperty * QSvgNode::styleProperty(const QString &id) const
     189QSvgFillStyleProperty * QSvgNode::styleProperty(const QString &id) const
    189190{
    190191    QString rid = id;
    191192    if (rid.startsWith(QLatin1Char('#')))
    192193        rid.remove(0, 1);
    193     const QSvgNode *node = this;
    194     while (node) {
    195         QSvgStyleProperty *style = node->m_styles[rid];
    196         if (style)
    197             return style;
    198         node = node->parent();
    199     }
    200 
    201     return 0;
     194    QSvgTinyDocument *doc = document();
     195    return doc ? doc->namedStyle(rid) : 0;
    202196}
    203197
     
    321315    QSvgStrokeStyle *stroke = static_cast<QSvgStrokeStyle*>(
    322316        styleProperty(QSvgStyleProperty::STROKE));
    323     if (!stroke || stroke->qpen().style() == Qt::NoPen)
     317    if (!stroke)
    324318        return 0;
    325     return stroke->qpen().widthF();
     319    if (stroke->stroke().brush().style() == Qt::NoBrush)
     320        return 0;
     321    return stroke->width();
    326322}
    327323
  • trunk/src/svg/qsvgnode_p.h

    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**
     
    8787        TEXT,
    8888        TEXTAREA,
     89        TSPAN,
    8990        USE,
    9091        VIDEO
     
    117118    QSvgNode *parent() const;
    118119
    119     void appendStyleProperty(QSvgStyleProperty *prop, const QString &id,
    120                              bool justLink=false);
     120    void appendStyleProperty(QSvgStyleProperty *prop, const QString &id);
    121121    void applyStyle(QPainter *p, QSvgExtraStates &states);
    122122    void revertStyle(QPainter *p, QSvgExtraStates &states);
    123123    QSvgStyleProperty *styleProperty(QSvgStyleProperty::Type type) const;
    124     QSvgStyleProperty *styleProperty(const QString &id) const;
     124    QSvgFillStyleProperty *styleProperty(const QString &id) const;
    125125
    126126    QSvgTinyDocument *document() const;
     
    162162private:
    163163    QSvgNode   *m_parent;
    164     QHash<QString, QSvgRefCounter<QSvgStyleProperty> > m_styles;
    165164
    166165    QStringList m_requiredFeatures;
  • trunk/src/svg/qsvgrenderer.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**
     
    5656/*!
    5757    \class QSvgRenderer
    58     \ingroup multimedia
     58    \ingroup painting
    5959
    6060    \brief The QSvgRenderer class is used to draw the contents of SVG files onto paint devices.
  • trunk/src/svg/qsvgrenderer.h

    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**
  • trunk/src/svg/qsvgstructure.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**
     
    4646#include "qsvgnode_p.h"
    4747#include "qsvgstyle_p.h"
     48#include "qsvgtinydocument_p.h"
    4849
    4950#include "qpainter.h"
     
    6970    applyStyle(p, states);
    7071
    71     if (displayMode() != QSvgNode::NoneMode) {
    72         while (itr != m_renderers.end()) {
    73             QSvgNode *node = *itr;
    74             if (node->isVisible())
    75                 node->draw(p, states);
    76             ++itr;
    77         }
     72    while (itr != m_renderers.end()) {
     73        QSvgNode *node = *itr;
     74        if ((node->isVisible()) && (node->displayMode() != QSvgNode::NoneMode))
     75            node->draw(p, states);
     76        ++itr;
    7877    }
    7978    revertStyle(p, states);
     
    9392QSvgNode * QSvgStructureNode::scopeNode(const QString &id) const
    9493{
    95     const QSvgStructureNode *group = this;
    96     while (group && group->type() != QSvgNode::DOC) {
    97         group = static_cast<QSvgStructureNode*>(group->parent());
    98     }
    99     if (group)
    100         return group->m_scope[id];
    101     return 0;
    102 }
    103 
    104 void QSvgStructureNode::addChild(QSvgNode *child, const QString &id, bool def)
    105 {
    106     if (!def)
    107         m_renderers.append(child);
    108 
    109     if (child->type() == QSvgNode::DEFS) {
    110         QSvgDefs *defs =
    111             static_cast<QSvgDefs*>(child);
    112         m_linkedScopes.append(defs);
    113     }
     94    QSvgTinyDocument *doc = document();
     95    return doc ? doc->namedNode(id) : 0;
     96}
     97
     98void QSvgStructureNode::addChild(QSvgNode *child, const QString &id)
     99{
     100    m_renderers.append(child);
    114101
    115102    if (id.isEmpty())
    116103        return; //we can't add it to scope without id
    117104
    118     QSvgStructureNode *group = this;
    119     while (group && group->type() != QSvgNode::DOC) {
    120         group = static_cast<QSvgStructureNode*>(group->parent());
    121     }
    122     if (group)
    123         group->m_scope.insert(id, child);
     105    QSvgTinyDocument *doc = document();
     106    if (doc)
     107        doc->addNamedNode(id, child);
    124108}
    125109
     
    138122    return DEFS;
    139123}
    140 
    141 QSvgStyleProperty * QSvgStructureNode::scopeStyle(const QString &id) const
    142 {
    143     const QSvgStructureNode *group = this;
    144     while (group) {
    145         QSvgStyleProperty *prop = group->styleProperty(id);
    146         if (prop)
    147             return prop;
    148         QList<QSvgStructureNode*>::const_iterator itr = group->m_linkedScopes.constBegin();
    149         while (itr != group->m_linkedScopes.constEnd()) {
    150             prop = (*itr)->styleProperty(id);
    151             if (prop)
    152                 return prop;
    153             ++itr;
    154         }
    155         group = static_cast<QSvgStructureNode*>(group->parent());
    156     }
    157     return 0;
    158 }
    159 
    160124
    161125/*
     
    322286    applyStyle(p, states);
    323287
    324     if (displayMode() != QSvgNode::NoneMode) {
    325         while (itr != m_renderers.end()) {
    326             QSvgNode *node = *itr;
    327             if (node->isVisible()) {
    328                 const QStringList &features  = node->requiredFeatures();
    329                 const QStringList &extensions = node->requiredExtensions();
    330                 const QStringList &languages = node->requiredLanguages();
    331                 const QStringList &formats = node->requiredFormats();
    332                 const QStringList &fonts = node->requiredFonts();
    333 
    334                 bool okToRender = true;
    335                 if (!features.isEmpty()) {
    336                     QStringList::const_iterator sitr = features.constBegin();
    337                     for (; sitr != features.constEnd(); ++sitr) {
    338                         if (!isSupportedSvgFeature(*sitr)) {
    339                             okToRender = false;
    340                             break;
    341                         }
     288    while (itr != m_renderers.end()) {
     289        QSvgNode *node = *itr;
     290        if (node->isVisible() && (node->displayMode() != QSvgNode::NoneMode)) {
     291            const QStringList &features  = node->requiredFeatures();
     292            const QStringList &extensions = node->requiredExtensions();
     293            const QStringList &languages = node->requiredLanguages();
     294            const QStringList &formats = node->requiredFormats();
     295            const QStringList &fonts = node->requiredFonts();
     296
     297            bool okToRender = true;
     298            if (!features.isEmpty()) {
     299                QStringList::const_iterator sitr = features.constBegin();
     300                for (; sitr != features.constEnd(); ++sitr) {
     301                    if (!isSupportedSvgFeature(*sitr)) {
     302                        okToRender = false;
     303                        break;
    342304                    }
    343305                }
    344 
    345                 if (okToRender && !extensions.isEmpty()) {
    346                     QStringList::const_iterator sitr = extensions.constBegin();
    347                     for (; sitr != extensions.constEnd(); ++sitr) {
    348                         if (!isSupportedSvgExtension(*sitr)) {
    349                             okToRender = false;
    350                             break;
    351                         }
     306            }
     307
     308            if (okToRender && !extensions.isEmpty()) {
     309                QStringList::const_iterator sitr = extensions.constBegin();
     310                for (; sitr != extensions.constEnd(); ++sitr) {
     311                    if (!isSupportedSvgExtension(*sitr)) {
     312                        okToRender = false;
     313                        break;
    352314                    }
    353315                }
    354 
    355                 if (okToRender && !languages.isEmpty()) {
    356                     QStringList::const_iterator sitr = languages.constBegin();
    357                     okToRender = false;
    358                     for (; sitr != languages.constEnd(); ++sitr) {
    359                         if ((*sitr).startsWith(m_systemLanguagePrefix)) {
    360                             okToRender = true;
    361                             break;
    362                         }
     316            }
     317
     318            if (okToRender && !languages.isEmpty()) {
     319                QStringList::const_iterator sitr = languages.constBegin();
     320                okToRender = false;
     321                for (; sitr != languages.constEnd(); ++sitr) {
     322                    if ((*sitr).startsWith(m_systemLanguagePrefix)) {
     323                        okToRender = true;
     324                        break;
    363325                    }
    364326                }
    365 
    366                 if (okToRender && !formats.isEmpty()) {
    367                     okToRender = false;
    368                 }
    369 
    370                 if (okToRender && !fonts.isEmpty()) {
    371                     okToRender = false;
    372                 }
    373 
    374                 if (okToRender) {
    375                     node->draw(p, states);
    376                     break;
    377                 }
    378             }
    379             ++itr;
     327            }
     328
     329            if (okToRender && !formats.isEmpty()) {
     330                okToRender = false;
     331            }
     332
     333            if (okToRender && !fonts.isEmpty()) {
     334                okToRender = false;
     335            }
     336
     337            if (okToRender) {
     338                node->draw(p, states);
     339                break;
     340            }
    380341        }
     342        ++itr;
    381343    }
    382344    revertStyle(p, states);
  • trunk/src/svg/qsvgstructure_p.h

    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**
     
    7474    ~QSvgStructureNode();
    7575    QSvgNode *scopeNode(const QString &id) const;
    76     QSvgStyleProperty *scopeStyle(const QString &id) const;
    77     void addChild(QSvgNode *child, const QString &id, bool def = false);
     76    void addChild(QSvgNode *child, const QString &id);
    7877    virtual QRectF bounds() const;
    7978    QSvgNode *previousSiblingNode(QSvgNode *n) const;
  • trunk/src/svg/qsvgstyle.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**
     
    6060QSvgExtraStates::QSvgExtraStates()
    6161    : fillOpacity(1.0)
     62    , strokeOpacity(1.0)
     63    , svgFont(0)
     64    , textAnchor(Qt::AlignLeft)
     65    , fontWeight(400)
     66    , fillRule(Qt::WindingFill)
     67    , strokeDashOffset(0)
     68    , vectorEffect(false)
    6269{
    6370}
     
    6673{
    6774}
     75
     76void QSvgFillStyleProperty::apply(QPainter *, const QRectF &, QSvgNode *, QSvgExtraStates &)
     77{
     78    Q_ASSERT(!"This should not be called!");
     79}
     80
     81void QSvgFillStyleProperty::revert(QPainter *, QSvgExtraStates &)
     82{
     83    Q_ASSERT(!"This should not be called!");
     84}
     85
    6886
    6987QSvgQualityStyle::QSvgQualityStyle(int color)
     
    8199}
    82100
    83 QSvgFillStyle::QSvgFillStyle(const QBrush &brush)
    84     : m_fill(brush), m_style(0), m_fillRuleSet(false), m_fillOpacitySet(false)
    85 {
    86 }
    87 
    88 QSvgFillStyle::QSvgFillStyle(QSvgStyleProperty *style)
    89     : m_style(style), m_fillRuleSet(false), m_fillOpacitySet(false)
     101QSvgFillStyle::QSvgFillStyle()
     102    : m_style(0)
     103    , m_fillRule(Qt::WindingFill)
     104    , m_oldFillRule(Qt::WindingFill)
     105    , m_fillOpacity(1.0)
     106    , m_oldFillOpacity(0)
     107    , m_gradientResolved(1)
     108    , m_fillRuleSet(0)
     109    , m_fillOpacitySet(0)
     110    , m_fillSet(0)
    90111{
    91112}
     
    93114void QSvgFillStyle::setFillRule(Qt::FillRule f)
    94115{
    95     m_fillRuleSet = true;
     116    m_fillRuleSet = 1;
    96117    m_fillRule = f;
    97118}
     
    99120void QSvgFillStyle::setFillOpacity(qreal opacity)
    100121{
    101     m_fillOpacitySet = true;
     122    m_fillOpacitySet = 1;
    102123    m_fillOpacity = opacity;
    103124}
    104125
    105 static void recursivelySetFill(QSvgNode *node, Qt::FillRule f)
    106 {
    107     if (node->type() == QSvgNode::PATH) {
    108         QSvgPath *path = static_cast<QSvgPath*>(node);
    109         path->qpath()->setFillRule(f);
    110     } else if (node->type() == QSvgNode::G) {
    111         QList<QSvgNode*> renderers = static_cast<QSvgG*>(node)->renderers();
    112         foreach(QSvgNode *n, renderers) {
    113             recursivelySetFill(n, f);
    114         }
    115     }
    116 }
    117 void QSvgFillStyle::apply(QPainter *p, const QRectF &rect, QSvgNode *node, QSvgExtraStates &states)
     126void QSvgFillStyle::setFillStyle(QSvgFillStyleProperty* style)
     127{
     128    m_style = style;
     129    m_fillSet = 1;
     130}
     131
     132void QSvgFillStyle::setBrush(QBrush brush)
     133{
     134    m_fill = brush;
     135    m_style = 0;
     136    m_fillSet = 1;
     137}
     138
     139void QSvgFillStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &states)
    118140{
    119141    m_oldFill = p->brush();
    120     m_oldOpacity = states.fillOpacity;
    121 
    122     if (m_fillRuleSet) {
    123         recursivelySetFill(node, m_fillRule);
    124         m_fillRuleSet = false;//set it only on the first run
    125     }
    126     p->setBrush(m_fill);
     142    m_oldFillRule = states.fillRule;
     143    m_oldFillOpacity = states.fillOpacity;
     144
     145    if (m_fillRuleSet)
     146        states.fillRule = m_fillRule;
     147    if (m_fillSet) {
     148        if (m_style)
     149            p->setBrush(m_style->brush(p, states));
     150        else
     151            p->setBrush(m_fill);
     152    }
    127153    if (m_fillOpacitySet)
    128154        states.fillOpacity = m_fillOpacity;
    129     if (m_style)
    130         m_style->apply(p, rect, node, states);
    131155}
    132156
    133157void QSvgFillStyle::revert(QPainter *p, QSvgExtraStates &states)
    134158{
    135     if (m_style)
    136         m_style->revert(p, states);
    137     p->setBrush(m_oldFill);
    138159    if (m_fillOpacitySet)
    139         states.fillOpacity = m_oldOpacity;
     160        states.fillOpacity = m_oldFillOpacity;
     161    if (m_fillSet)
     162        p->setBrush(m_oldFill);
     163    if (m_fillRuleSet)
     164        states.fillRule = m_oldFillRule;
    140165}
    141166
     
    157182
    158183QSvgFontStyle::QSvgFontStyle(QSvgFont *font, QSvgTinyDocument *doc)
    159     : m_font(font), m_pointSize(24), m_doc(doc)
    160 {
    161 }
    162 
    163 QSvgFontStyle::QSvgFontStyle(const QFont &font, QSvgTinyDocument *doc)
    164     : m_font(0), m_pointSize(24), m_doc(doc), m_qfont(font)
    165 {
    166 }
    167 
    168 
    169 void QSvgFontStyle::setPointSize(qreal size)
    170 {
    171     m_pointSize = size;
    172 }
    173 
    174 qreal QSvgFontStyle::pointSize() const
    175 {
    176     return m_pointSize;
    177 }
    178 
    179 void QSvgFontStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &)
    180 {
    181     if (!m_font) {
    182         m_oldFont = p->font();
    183         p->setFont(m_qfont);
    184     }
    185 }
    186 
    187 void QSvgFontStyle::revert(QPainter *p, QSvgExtraStates &)
    188 {
    189     if (!m_font) {
    190         p->setFont(m_oldFont);
    191     }
    192 }
    193 
    194 QSvgStrokeStyle::QSvgStrokeStyle(const QPen &pen)
    195     : m_stroke(pen)
    196 {
    197 }
    198 
    199 void QSvgStrokeStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &)
     184    : m_svgFont(font)
     185    , m_doc(doc)
     186    , m_familySet(0)
     187    , m_sizeSet(0)
     188    , m_styleSet(0)
     189    , m_variantSet(0)
     190    , m_weightSet(0)
     191    , m_textAnchorSet(0)
     192{
     193}
     194
     195QSvgFontStyle::QSvgFontStyle()
     196    : m_svgFont(0)
     197    , m_doc(0)
     198    , m_familySet(0)
     199    , m_sizeSet(0)
     200    , m_styleSet(0)
     201    , m_variantSet(0)
     202    , m_weightSet(0)
     203    , m_textAnchorSet(0)
     204{
     205}
     206
     207int QSvgFontStyle::SVGToQtWeight(int weight) {
     208    switch (weight) {
     209    case 100:
     210    case 200:
     211        return QFont::Light;
     212    case 300:
     213    case 400:
     214        return QFont::Normal;
     215    case 500:
     216    case 600:
     217        return QFont::DemiBold;
     218    case 700:
     219    case 800:
     220        return QFont::Bold;
     221    case 900:
     222        return QFont::Black;
     223    }
     224    return QFont::Normal;
     225}
     226
     227void QSvgFontStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &states)
     228{
     229    m_oldQFont = p->font();
     230    m_oldSvgFont = states.svgFont;
     231    m_oldTextAnchor = states.textAnchor;
     232    m_oldWeight = states.fontWeight;
     233
     234    if (m_textAnchorSet)
     235        states.textAnchor = m_textAnchor;
     236
     237    QFont font = m_oldQFont;
     238    if (m_familySet) {
     239        states.svgFont = m_svgFont;
     240        font.setFamily(m_qfont.family());
     241    }
     242
     243    if (m_sizeSet)
     244        font.setPointSize(m_qfont.pointSizeF());
     245
     246    if (m_styleSet)
     247        font.setStyle(m_qfont.style());
     248
     249    if (m_variantSet)
     250        font.setCapitalization(m_qfont.capitalization());
     251
     252    if (m_weightSet) {
     253        if (m_weight == BOLDER) {
     254            states.fontWeight = qMin(states.fontWeight + 100, 900);
     255        } else if (m_weight == LIGHTER) {
     256            states.fontWeight = qMax(states.fontWeight - 100, 100);
     257        } else {
     258            states.fontWeight = m_weight;
     259        }
     260        font.setWeight(SVGToQtWeight(states.fontWeight));
     261    }
     262
     263    p->setFont(font);
     264}
     265
     266void QSvgFontStyle::revert(QPainter *p, QSvgExtraStates &states)
     267{
     268    p->setFont(m_oldQFont);
     269    states.svgFont = m_oldSvgFont;
     270    states.textAnchor = m_oldTextAnchor;
     271    states.fontWeight = m_oldWeight;
     272}
     273
     274QSvgStrokeStyle::QSvgStrokeStyle()
     275    : m_strokeOpacity(1.0)
     276    , m_oldStrokeOpacity(0.0)
     277    , m_strokeDashOffset(0)
     278    , m_oldStrokeDashOffset(0)
     279    , m_style(0)
     280    , m_gradientResolved(1)
     281    , m_vectorEffect(0)
     282    , m_oldVectorEffect(0)
     283    , m_strokeSet(0)
     284    , m_strokeDashArraySet(0)
     285    , m_strokeDashOffsetSet(0)
     286    , m_strokeLineCapSet(0)
     287    , m_strokeLineJoinSet(0)
     288    , m_strokeMiterLimitSet(0)
     289    , m_strokeOpacitySet(0)
     290    , m_strokeWidthSet(0)
     291    , m_vectorEffectSet(0)
     292{
     293}
     294
     295void QSvgStrokeStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &states)
    200296{
    201297    m_oldStroke = p->pen();
    202     p->setPen(m_stroke);
    203 }
    204 
    205 void QSvgStrokeStyle::revert(QPainter *p, QSvgExtraStates &)
     298    m_oldStrokeOpacity = states.strokeOpacity;
     299    m_oldStrokeDashOffset = states.strokeDashOffset;
     300    m_oldVectorEffect = states.vectorEffect;
     301
     302    QPen pen = p->pen();
     303
     304    qreal oldWidth = pen.widthF();
     305    qreal width = m_stroke.widthF();
     306    if (oldWidth == 0)
     307        oldWidth = 1;
     308    if (width == 0)
     309        width = 1;
     310    qreal scale = oldWidth / width;
     311
     312    if (m_strokeOpacitySet)
     313        states.strokeOpacity = m_strokeOpacity;
     314
     315    if (m_vectorEffectSet)
     316        states.vectorEffect = m_vectorEffect;
     317
     318    if (m_strokeSet) {
     319        if (m_style)
     320            pen.setBrush(m_style->brush(p, states));
     321        else
     322            pen.setBrush(m_stroke.brush());
     323    }
     324
     325    if (m_strokeWidthSet)
     326        pen.setWidthF(m_stroke.widthF());
     327
     328    bool setDashOffsetNeeded = false;
     329
     330    if (m_strokeDashOffsetSet) {
     331        states.strokeDashOffset = m_strokeDashOffset;
     332        setDashOffsetNeeded = true;
     333    }
     334
     335    if (m_strokeDashArraySet) {
     336        if (m_stroke.style() == Qt::SolidLine) {
     337            pen.setStyle(Qt::SolidLine);
     338        } else if (m_strokeWidthSet || oldWidth == 1) {
     339            // If both width and dash array was set, the dash array is already scaled correctly.
     340            pen.setDashPattern(m_stroke.dashPattern());
     341            setDashOffsetNeeded = true;
     342        } else {
     343            // If dash array was set, but not the width, the dash array has to be scaled with respect to the old width.
     344            QVector<qreal> dashes = m_stroke.dashPattern();
     345            for (int i = 0; i < dashes.size(); ++i)
     346                dashes[i] /= oldWidth;
     347            pen.setDashPattern(dashes);
     348            setDashOffsetNeeded = true;
     349        }
     350    } else if (m_strokeWidthSet && pen.style() != Qt::SolidLine && scale != 1) {
     351        // If the width was set, but not the dash array, the old dash array must be scaled with respect to the new width.
     352        QVector<qreal> dashes = pen.dashPattern();
     353        for (int i = 0; i < dashes.size(); ++i)
     354            dashes[i] *= scale;
     355        pen.setDashPattern(dashes);
     356        setDashOffsetNeeded = true;
     357    }
     358
     359    if (m_strokeLineCapSet)
     360        pen.setCapStyle(m_stroke.capStyle());
     361    if (m_strokeLineJoinSet)
     362        pen.setJoinStyle(m_stroke.joinStyle());
     363    if (m_strokeMiterLimitSet)
     364        pen.setMiterLimit(m_stroke.miterLimit());
     365
     366    // You can have dash offset on solid strokes in SVG files, but not in Qt.
     367    // QPen::setDashOffset() will set the pen style to Qt::CustomDashLine,
     368    // so don't call the method if the pen is solid.
     369    if (setDashOffsetNeeded && pen.style() != Qt::SolidLine) {
     370        qreal currentWidth = pen.widthF();
     371        if (currentWidth == 0)
     372            currentWidth = 1;
     373        pen.setDashOffset(states.strokeDashOffset / currentWidth);
     374    }
     375
     376    pen.setCosmetic(states.vectorEffect);
     377
     378    p->setPen(pen);
     379}
     380
     381void QSvgStrokeStyle::revert(QPainter *p, QSvgExtraStates &states)
    206382{
    207383    p->setPen(m_oldStroke);
     384    states.strokeOpacity = m_oldStrokeOpacity;
     385    states.strokeDashOffset = m_oldStrokeDashOffset;
     386    states.vectorEffect = m_oldVectorEffect;
     387}
     388
     389void QSvgStrokeStyle::setDashArray(const QVector<qreal> &dashes)
     390{
     391    if (m_strokeWidthSet) {
     392        QVector<qreal> d = dashes;
     393        qreal w = m_stroke.widthF();
     394        if (w != 0 && w != 1) {
     395            for (int i = 0; i < d.size(); ++i)
     396                d[i] /= w;
     397        }
     398        m_stroke.setDashPattern(d);
     399    } else {
     400        m_stroke.setDashPattern(dashes);
     401    }
     402    m_strokeDashArraySet = 1;
    208403}
    209404
     
    213408}
    214409
    215 void QSvgSolidColorStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &)
    216 {
    217     m_oldFill = p->brush();
    218     m_oldStroke = p->pen();
    219     QBrush b = m_oldFill;
    220     b.setColor(m_solidColor);
    221     p->setBrush(b);
    222     QPen pen = m_oldStroke;
    223     pen.setColor(m_solidColor);
    224     p->setPen(pen);
    225 }
    226 
    227 void QSvgSolidColorStyle::revert(QPainter *p, QSvgExtraStates &)
    228 {
    229     p->setBrush(m_oldFill);
    230     p->setPen(m_oldStroke);
    231 }
    232 
    233410QSvgGradientStyle::QSvgGradientStyle(QGradient *grad)
    234411    : m_gradient(grad), m_gradientStopsSet(false)
     
    236413}
    237414
    238 void QSvgGradientStyle::apply(QPainter *p, const QRectF &/*rect*/, QSvgNode *, QSvgExtraStates &)
     415QBrush QSvgGradientStyle::brush(QPainter *, QSvgExtraStates &)
    239416{
    240417    if (!m_link.isEmpty()) {
    241418        resolveStops();
    242     }
    243 
    244     m_oldFill = p->brush();
    245 
    246     //resolving stop colors
    247     if (!m_resolvePoints.isEmpty()) {
    248         QColor color = p->brush().color();
    249         if (!color.isValid())
    250             color = p->pen().color();
    251         QList<qreal>::const_iterator itr = m_resolvePoints.constBegin();
    252         for (; itr != m_resolvePoints.constEnd(); ++itr) {
    253             //qDebug()<<"resolving "<<(*itr)<<" to "<<color;
    254             m_gradient->setColorAt(*itr, color);
    255         }
    256419    }
    257420
     
    262425    }
    263426
    264     QBrush brush;
    265     brush = QBrush(*m_gradient);
     427    QBrush b(*m_gradient);
    266428
    267429    if (!m_matrix.isIdentity())
    268         brush.setMatrix(m_matrix);
    269 
    270     p->setBrush(brush);
    271 }
    272 
    273 void QSvgGradientStyle::revert(QPainter *p, QSvgExtraStates &)
    274 {
    275     p->setBrush(m_oldFill);
     430        b.setMatrix(m_matrix);
     431
     432    return b;
    276433}
    277434
     
    280437{
    281438    m_matrix = mat;
    282 }
    283 
    284 void QSvgGradientStyle::addResolve(qreal offset)
    285 {
    286     m_resolvePoints.append(offset);
    287439}
    288440
     
    390542    if (stroke) {
    391543        stroke->apply(p, rect, node, states);
    392     }
    393 
    394     if (solidColor) {
    395         solidColor->apply(p, rect, node, states);
    396     }
    397 
    398     if (gradient) {
    399         gradient->apply(p, rect, node, states);
    400544    }
    401545
     
    411555    //_after_ the original object transformations
    412556    if (!animateTransforms.isEmpty()) {
    413         QList<QSvgRefCounter<QSvgAnimateTransform> >::const_iterator itr;
    414         for (itr = animateTransforms.constBegin(); itr != animateTransforms.constEnd();
    415              ++itr) {
    416             (*itr)->apply(p, rect, node, states);
     557        qreal totalTimeElapsed = node->document()->currentElapsed();
     558        // Find the last animateTransform with additive="replace", since this will override all
     559        // previous animateTransforms.
     560        QList<QSvgRefCounter<QSvgAnimateTransform> >::const_iterator itr = animateTransforms.constEnd();
     561        do {
     562            --itr;
     563            if ((*itr)->animActive(totalTimeElapsed)
     564                && (*itr)->additiveType() == QSvgAnimateTransform::Replace) {
     565                // An animateTransform with additive="replace" will replace the transform attribute.
     566                if (transform)
     567                    transform->revert(p, states);
     568                break;
     569            }
     570        } while (itr != animateTransforms.constBegin());
     571
     572        // Apply the animateTransforms after and including the last one with additive="replace".
     573        for (; itr != animateTransforms.constEnd(); ++itr) {
     574            if ((*itr)->animActive(totalTimeElapsed))
     575                (*itr)->apply(p, rect, node, states);
    417576        }
    418577    }
     
    447606    if (stroke) {
    448607        stroke->revert(p, states);
    449     }
    450 
    451     if (solidColor) {
    452         solidColor->revert(p, states);
    453     }
    454 
    455     if (gradient) {
    456         gradient->revert(p, states);
    457608    }
    458609
     
    460611    //the native transforms
    461612    if (!animateTransforms.isEmpty()) {
    462         QList<QSvgRefCounter<QSvgAnimateTransform> >::const_iterator itr;
    463         itr = animateTransforms.constBegin();
    464         //only need to rever the first one because that
    465         //one has the original world matrix for the primitve
    466         if (itr != animateTransforms.constEnd()) {
    467             (*itr)->revert(p, states);
     613        QList<QSvgRefCounter<QSvgAnimateTransform> >::const_iterator itr = animateTransforms.constBegin();
     614        for (; itr != animateTransforms.constEnd(); ++itr) {
     615            if ((*itr)->transformApplied()) {
     616                (*itr)->revert(p, states);
     617                break;
     618            }
    468619        }
     620        for (; itr != animateTransforms.constEnd(); ++itr)
     621            (*itr)->clearTransformApplied();
    469622    }
    470623
     
    489642    : QSvgStyleProperty(),
    490643      m_from(startMs), m_to(endMs), m_by(byMs),
    491       m_type(Empty), m_count(0), m_finished(false)
     644      m_type(Empty), m_additive(Replace), m_count(0), m_finished(false), m_transformApplied(false)
    492645{
    493646    m_totalRunningTime = m_to - m_from;
    494647}
    495648
    496 void QSvgAnimateTransform::setArgs(TransformType type, const QVector<qreal> &args)
     649void QSvgAnimateTransform::setArgs(TransformType type, Additive additive, const QVector<qreal> &args)
    497650{
    498651    m_type = type;
    499652    m_args = args;
     653    m_additive = additive;
    500654    Q_ASSERT(!(args.count()%3));
    501655    m_count = args.count() / 3;
     
    506660    m_oldWorldTransform = p->worldTransform();
    507661    resolveMatrix(node);
    508     if (!m_finished || m_freeze)
    509         p->setWorldTransform(m_transform, true);
     662    p->setWorldTransform(m_transform, true);
     663    m_transformApplied = true;
    510664}
    511665
    512666void QSvgAnimateTransform::revert(QPainter *p, QSvgExtraStates &)
    513667{
    514     if (!m_finished || m_freeze) {
    515         p->setWorldTransform(m_oldWorldTransform, false /* don't combine */);
    516     }
     668    p->setWorldTransform(m_oldWorldTransform, false /* don't combine */);
     669    m_transformApplied = false;
    517670}
    518671
     
    524677        return;
    525678
    526     qreal animationFrame = (totalTimeElapsed - m_from) / m_to;
    527 
    528     if (m_repeatCount >= 0 && m_repeatCount < animationFrame) {
    529         m_finished = true;
    530         animationFrame = m_repeatCount;
     679    qreal animationFrame = 0;
     680    if (m_totalRunningTime != 0) {
     681        animationFrame = (totalTimeElapsed - m_from) / m_totalRunningTime;
     682
     683        if (m_repeatCount >= 0 && m_repeatCount < animationFrame) {
     684            m_finished = true;
     685            animationFrame = m_repeatCount;
     686        }
    531687    }
    532688
     
    545701        startElem *= 3;
    546702        endElem   *= 3;
    547         qreal from1, from2, from3;
    548         qreal to1, to2, to3;
     703        qreal from1, from2;
     704        qreal to1, to2;
    549705        from1 = m_args[startElem++];
    550706        from2 = m_args[startElem++];
    551         from3 = m_args[startElem++];
    552707        to1   = m_args[endElem++];
    553708        to2   = m_args[endElem++];
    554         to3   = m_args[endElem++];
    555709
    556710        qreal transXDiff = (to1-from1) * percentOfAnimation;
     
    565719        startElem *= 3;
    566720        endElem   *= 3;
    567         qreal from1, from2, from3;
    568         qreal to1, to2, to3;
     721        qreal from1, from2;
     722        qreal to1, to2;
    569723        from1 = m_args[startElem++];
    570724        from2 = m_args[startElem++];
    571         from3 = m_args[startElem++];
    572725        to1   = m_args[endElem++];
    573726        to2   = m_args[endElem++];
    574         to3   = m_args[endElem++];
    575727
    576728        qreal transXDiff = (to1-from1) * percentOfAnimation;
     
    612764        startElem *= 3;
    613765        endElem   *= 3;
    614         qreal from1, from2, from3;
    615         qreal to1, to2, to3;
     766        qreal from1;
     767        qreal to1;
    616768        from1 = m_args[startElem++];
    617         from2 = m_args[startElem++];
    618         from3 = m_args[startElem++];
    619769        to1   = m_args[endElem++];
    620         to2   = m_args[endElem++];
    621         to3   = m_args[endElem++];
    622770
    623771        qreal transXDiff = (to1-from1) * percentOfAnimation;
    624772        qreal transX = from1 + transXDiff;
    625773        m_transform = QTransform();
    626         m_transform.shear(tan(transX * deg2rad), 0);
     774        m_transform.shear(qTan(transX * deg2rad), 0);
    627775        break;
    628776    }
     
    630778        startElem *= 3;
    631779        endElem   *= 3;
    632         qreal from1, from2, from3;
    633         qreal to1, to2, to3;
     780        qreal from1;
     781        qreal to1;
    634782        from1 = m_args[startElem++];
    635         from2 = m_args[startElem++];
    636         from3 = m_args[startElem++];
    637783        to1   = m_args[endElem++];
    638         to2   = m_args[endElem++];
    639         to3   = m_args[endElem++];
    640784
    641785
     
    643787        qreal transY = from1 + transYDiff;
    644788        m_transform = QTransform();
    645         m_transform.shear(0, tan(transY * deg2rad));
     789        m_transform.shear(0, qTan(transY * deg2rad));
    646790        break;
    647791    }
     
    697841        return;
    698842
    699     qreal animationFrame = (totalTimeElapsed - m_from) / m_to;
     843    qreal animationFrame = 0;
     844    if (m_totalRunningTime != 0)
     845        animationFrame = (totalTimeElapsed - m_from) / m_totalRunningTime;
    700846
    701847    if (m_repeatCount >= 0 && m_repeatCount < animationFrame) {
     
    761907}
    762908
    763 QString QSvgFontStyle::textAnchor() const
    764 {
    765     return m_textAnchor;
    766 }
    767 
    768 void QSvgFontStyle::setTextAnchor(const QString &anchor)
    769 {
    770     m_textAnchor = anchor;
    771 }
    772 
    773909QSvgOpacityStyle::QSvgOpacityStyle(qreal opacity)
    774     : m_opacity(opacity)
     910    : m_opacity(opacity), m_oldOpacity(0)
    775911{
    776912
     
    802938{
    803939    if (!m_link.isEmpty() && m_doc) {
    804         QSvgStyleProperty *prop = m_doc->scopeStyle(m_link);
     940        QSvgStyleProperty *prop = m_doc->styleProperty(m_link);
    805941        if (prop) {
    806942            if (prop->type() == QSvgStyleProperty::GRADIENT) {
     
    809945                st->resolveStops();
    810946                m_gradient->setStops(st->qgradient()->stops());
     947                m_gradientStopsSet = st->gradientStopsSet();
    811948            }
     949        } else {
     950            qWarning("Could not resolve property : %s", qPrintable(m_link));
    812951        }
    813952        m_link = QString();
  • trunk/src/svg/qsvgstyle_p.h

    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**
     
    142142{
    143143    QSvgExtraStates();
     144
    144145    qreal fillOpacity;
     146    qreal strokeOpacity;
     147    QSvgFont *svgFont;
     148    Qt::Alignment textAnchor;
     149    int fontWeight;
     150    Qt::FillRule fillRule;
     151    qreal strokeDashOffset;
     152    bool vectorEffect; // true if pen is cosmetic
    145153};
    146154
     
    170178};
    171179
     180class QSvgFillStyleProperty : public QSvgStyleProperty
     181{
     182public:
     183    virtual QBrush brush(QPainter *p, QSvgExtraStates &states) = 0;
     184    virtual void apply(QPainter *p, const QRectF &, QSvgNode *node, QSvgExtraStates &states);
     185    virtual void revert(QPainter *p, QSvgExtraStates &states);
     186};
     187
    172188class QSvgQualityStyle : public QSvgStyleProperty
    173189{
     
    217233{
    218234public:
    219     QSvgFillStyle(const QBrush &brush);
    220     QSvgFillStyle(QSvgStyleProperty *style);
     235    QSvgFillStyle();
    221236    virtual void apply(QPainter *p, const QRectF &, QSvgNode *node, QSvgExtraStates &states);
    222237    virtual void revert(QPainter *p, QSvgExtraStates &states);
     
    225240    void setFillRule(Qt::FillRule f);
    226241    void setFillOpacity(qreal opacity);
     242    void setFillStyle(QSvgFillStyleProperty* style);
     243    void setBrush(QBrush brush);
    227244
    228245    const QBrush & qbrush() const
     
    230247        return m_fill;
    231248    }
     249
     250    qreal fillOpacity() const
     251    {
     252        return m_fillOpacity;
     253    }
     254
     255    Qt::FillRule fillRule() const
     256    {
     257        return m_fillRule;
     258    }
     259
     260    QSvgFillStyleProperty* style() const
     261    {
     262        return m_style;
     263    }
     264
     265    void setGradientId(const QString &Id)
     266    {
     267        m_gradientId = Id;
     268    }
     269
     270    QString gradientId() const
     271    {
     272        return m_gradientId;
     273    }
     274
     275    void setGradientResolved(bool resolved)
     276    {
     277        m_gradientResolved = resolved;
     278    }
     279
     280    bool isGradientResolved() const
     281    {
     282        return m_gradientResolved;
     283    }
     284
    232285private:
    233286    // fill            v        v       'inherit' | <Paint.datatype>
     
    235288    QBrush m_fill;
    236289    QBrush m_oldFill;
    237     QSvgStyleProperty *m_style;
    238 
    239     bool         m_fillRuleSet;
     290    QSvgFillStyleProperty *m_style;
     291
    240292    Qt::FillRule m_fillRule;
    241     bool m_fillOpacitySet;
     293    Qt::FillRule m_oldFillRule;
    242294    qreal m_fillOpacity;
    243     qreal m_oldOpacity;
     295    qreal m_oldFillOpacity;
     296
     297    QString m_gradientId;
     298    uint m_gradientResolved : 1;
     299
     300    uint m_fillRuleSet : 1;
     301    uint m_fillOpacitySet : 1;
     302    uint m_fillSet : 1;
    244303};
    245304
     
    267326{
    268327public:
     328    static const int LIGHTER = -1;
     329    static const int BOLDER = 1;
     330
    269331    QSvgFontStyle(QSvgFont *font, QSvgTinyDocument *doc);
    270     QSvgFontStyle(const QFont &font, QSvgTinyDocument *doc);
    271     virtual void apply(QPainter *p, const QRectF &, QSvgNode *node, QSvgExtraStates &states);
    272     virtual void revert(QPainter *p, QSvgExtraStates &states);
    273     virtual Type type() const;
    274 
    275     void setPointSize(qreal size);
    276     qreal pointSize() const;
    277 
    278     //### hack to avoid having a separate style element for text-anchor
    279     QString textAnchor() const;
    280     void setTextAnchor(const QString &anchor);
     332    QSvgFontStyle();
     333    virtual void apply(QPainter *p, const QRectF &, QSvgNode *node, QSvgExtraStates &states);
     334    virtual void revert(QPainter *p, QSvgExtraStates &states);
     335    virtual Type type() const;
     336
     337    void setSize(qreal size)
     338    {
     339        // Store the _pixel_ size in the font. Since QFont::setPixelSize() only takes an int, call
     340        // QFont::SetPointSize() instead. Set proper font size just before rendering.
     341        m_qfont.setPointSize(size);
     342        m_sizeSet = 1;
     343    }
     344
     345    void setTextAnchor(Qt::Alignment anchor)
     346    {
     347        m_textAnchor = anchor;
     348        m_textAnchorSet = 1;
     349    }
     350
     351    void setFamily(const QString &family)
     352    {
     353        m_qfont.setFamily(family);
     354        m_familySet = 1;
     355    }
     356
     357    void setStyle(QFont::Style fontStyle) {
     358        m_qfont.setStyle(fontStyle);
     359        m_styleSet = 1;
     360    }
     361
     362    void setVariant(QFont::Capitalization fontVariant)
     363    {
     364        m_qfont.setCapitalization(fontVariant);
     365        m_variantSet = 1;
     366    }
     367
     368    static int SVGToQtWeight(int weight);
     369
     370    void setWeight(int weight)
     371    {
     372        m_weight = weight;
     373        m_weightSet = 1;
     374    }
    281375
    282376    QSvgFont * svgFont() const
    283377    {
    284         return m_font;
    285     }
    286     QSvgTinyDocument *doc() const
    287     {
    288         return m_doc;
    289     }
    290 
    291     const QFont & qfont() const
     378        return m_svgFont;
     379    }
     380
     381    const QFont &qfont() const
    292382    {
    293383        return m_qfont;
    294384    }
    295 private:
    296     QSvgFont *m_font;
    297     qreal     m_pointSize;
     385
     386    QSvgTinyDocument *doc() const {return m_doc;}
     387
     388private:
     389    QSvgFont *m_svgFont;
    298390    QSvgTinyDocument *m_doc;
    299 
    300     QString m_textAnchor;
    301 
    302391    QFont m_qfont;
    303     QFont m_oldFont;
     392
     393    int m_weight;
     394    Qt::Alignment m_textAnchor;
     395
     396    QSvgFont *m_oldSvgFont;
     397    QFont m_oldQFont;
     398    Qt::Alignment m_oldTextAnchor;
     399    int m_oldWeight;
     400
     401    uint m_familySet : 1;
     402    uint m_sizeSet : 1;
     403    uint m_styleSet : 1;
     404    uint m_variantSet : 1;
     405    uint m_weightSet : 1;
     406    uint m_textAnchorSet : 1;
    304407};
    305408
     
    307410{
    308411public:
    309     QSvgStrokeStyle(const QPen &pen);
    310     virtual void apply(QPainter *p, const QRectF &, QSvgNode *node, QSvgExtraStates &states);
    311     virtual void revert(QPainter *p, QSvgExtraStates &states);
    312     virtual Type type() const;
    313 
    314     const QPen & qpen() const
     412    QSvgStrokeStyle();
     413    virtual void apply(QPainter *p, const QRectF &, QSvgNode *node, QSvgExtraStates &states);
     414    virtual void revert(QPainter *p, QSvgExtraStates &states);
     415    virtual Type type() const;
     416
     417    void setStroke(QBrush brush)
     418    {
     419        m_stroke.setBrush(brush);
     420        m_style = 0;
     421        m_strokeSet = 1;
     422    }
     423
     424    void setStyle(QSvgFillStyleProperty *style)
     425    {
     426        m_style = style;
     427        m_strokeSet = 1;
     428    }
     429
     430    void setDashArray(const QVector<qreal> &dashes);
     431
     432    void setDashArrayNone()
     433    {
     434        m_stroke.setStyle(Qt::SolidLine);
     435        m_strokeDashArraySet = 1;
     436    }
     437
     438    void setDashOffset(qreal offset)
     439    {
     440        m_strokeDashOffset = offset;
     441        m_strokeDashOffsetSet = 1;
     442    }
     443
     444    void setLineCap(Qt::PenCapStyle cap)
     445    {
     446        m_stroke.setCapStyle(cap);
     447        m_strokeLineCapSet = 1;
     448    }
     449
     450    void setLineJoin(Qt::PenJoinStyle join)
     451    {
     452        m_stroke.setJoinStyle(join);
     453        m_strokeLineJoinSet = 1;
     454    }
     455
     456    void setMiterLimit(qreal limit)
     457    {
     458        m_stroke.setMiterLimit(limit);
     459        m_strokeMiterLimitSet = 1;
     460    }
     461
     462    void setOpacity(qreal opacity)
     463    {
     464        m_strokeOpacity = opacity;
     465        m_strokeOpacitySet = 1;
     466    }
     467
     468    void setWidth(qreal width)
     469    {
     470        m_stroke.setWidthF(width);
     471        m_strokeWidthSet = 1;
     472        Q_ASSERT(!m_strokeDashArraySet); // set width before dash array.
     473    }
     474
     475    qreal width()
     476    {
     477        return m_stroke.widthF();
     478    }
     479
     480    void setVectorEffect(bool nonScalingStroke)
     481    {
     482        m_vectorEffect = nonScalingStroke;
     483        m_vectorEffectSet = 1;
     484    }
     485
     486    QSvgFillStyleProperty* style() const
     487    {
     488        return m_style;
     489    }
     490
     491    void setGradientId(const QString &Id)
     492    {
     493        m_gradientId = Id;
     494    }
     495
     496    QString gradientId() const
     497    {
     498        return m_gradientId;
     499    }
     500
     501    void setGradientResolved(bool resolved)
     502    {
     503        m_gradientResolved = resolved;
     504    }
     505
     506    bool isGradientResolved() const
     507    {
     508        return m_gradientResolved;
     509    }
     510
     511    QPen stroke() const
    315512    {
    316513        return m_stroke;
    317514    }
     515
    318516private:
    319517    // stroke            v      v       'inherit' | <Paint.datatype>
     
    326524    // stroke-width      v      v       'inherit' | <StrokeWidthValue.datatype>
    327525    QPen m_stroke;
    328 
    329526    QPen m_oldStroke;
    330 };
    331 
    332 
    333 class QSvgSolidColorStyle : public QSvgStyleProperty
     527    qreal m_strokeOpacity;
     528    qreal m_oldStrokeOpacity;
     529    qreal m_strokeDashOffset;
     530    qreal m_oldStrokeDashOffset;
     531
     532    QSvgFillStyleProperty *m_style;
     533    QString m_gradientId;
     534    uint m_gradientResolved : 1;
     535    uint m_vectorEffect : 1;
     536    uint m_oldVectorEffect : 1;
     537
     538    uint m_strokeSet : 1;
     539    uint m_strokeDashArraySet : 1;
     540    uint m_strokeDashOffsetSet : 1;
     541    uint m_strokeLineCapSet : 1;
     542    uint m_strokeLineJoinSet : 1;
     543    uint m_strokeMiterLimitSet : 1;
     544    uint m_strokeOpacitySet : 1;
     545    uint m_strokeWidthSet : 1;
     546    uint m_vectorEffectSet : 1;
     547};
     548
     549class QSvgSolidColorStyle : public QSvgFillStyleProperty
    334550{
    335551public:
    336552    QSvgSolidColorStyle(const QColor &color);
    337     virtual void apply(QPainter *p, const QRectF &, QSvgNode *node, QSvgExtraStates &states);
    338     virtual void revert(QPainter *p, QSvgExtraStates &states);
    339553    virtual Type type() const;
    340554
     
    343557        return m_solidColor;
    344558    }
     559
     560    QBrush brush(QPainter *, QSvgExtraStates &)
     561    {
     562        return m_solidColor;
     563    }
     564
    345565private:
    346566    // solid-color       v      x       'inherit' | <SVGColor.datatype>
     
    352572};
    353573
    354 class QSvgGradientStyle : public QSvgStyleProperty
     574class QSvgGradientStyle : public QSvgFillStyleProperty
    355575{
    356576public:
    357577    QSvgGradientStyle(QGradient *grad);
    358578    ~QSvgGradientStyle() { delete m_gradient; }
    359     virtual void apply(QPainter *p, const QRectF &, QSvgNode *node, QSvgExtraStates &states);
    360     virtual void revert(QPainter *p, QSvgExtraStates &states);
    361579    virtual Type type() const;
    362580
     
    376594    }
    377595
    378     void addResolve(qreal offset);
    379 
    380596    bool gradientStopsSet() const
    381597    {
     
    387603        m_gradientStopsSet = set;
    388604    }
     605
     606    QBrush brush(QPainter *, QSvgExtraStates &);
    389607private:
    390608    QGradient      *m_gradient;
    391     QList<qreal>  m_resolvePoints;
    392 
    393     QBrush m_oldFill;
    394 
    395609    QMatrix m_matrix;
    396610
     
    431645        SkewY
    432646    };
     647    enum Additive
     648    {
     649        Sum,
     650        Replace
     651    };
    433652public:
    434653    QSvgAnimateTransform(int startMs, int endMs, int by = 0);
    435     void setArgs(TransformType type, const QVector<qreal> &args);
     654    void setArgs(TransformType type, Additive additive, const QVector<qreal> &args);
    436655    void setFreeze(bool freeze);
    437656    void setRepeatCount(qreal repeatCount);
     
    439658    virtual void revert(QPainter *p, QSvgExtraStates &states);
    440659    virtual Type type() const;
     660    QSvgAnimateTransform::Additive additiveType() const
     661    {
     662        return m_additive;
     663    }
     664
     665    bool animActive(qreal totalTimeElapsed)
     666    {
     667        if (totalTimeElapsed < m_from)
     668            return false;
     669        if (m_freeze || m_repeatCount < 0) // fill="freeze" or repeat="indefinite"
     670            return true;
     671        if (m_totalRunningTime == 0)
     672            return false;
     673        qreal animationFrame = (totalTimeElapsed - m_from) / m_totalRunningTime;
     674        if (animationFrame > m_repeatCount)
     675            return false;
     676        return true;
     677    }
     678
     679    bool transformApplied() const
     680    {
     681        return m_transformApplied;
     682    }
     683
     684    // Call this instead of revert if you know that revert is unnecessary.
     685    void clearTransformApplied()
     686    {
     687        m_transformApplied = false;
     688    }
     689
    441690protected:
    442691    void resolveMatrix(QSvgNode *node);
     
    445694    qreal m_totalRunningTime;
    446695    TransformType m_type;
     696    Additive m_additive;
    447697    QVector<qreal> m_args;
    448698    int m_count;
     
    452702    bool m_freeze;
    453703    qreal m_repeatCount;
     704    bool m_transformApplied;
    454705};
    455706
  • trunk/src/svg/qsvgtinydocument.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**
     
    6262
    6363QSvgTinyDocument::QSvgTinyDocument()
    64     : QSvgStructureNode(0),
    65       m_animated(false),
    66       m_animationDuration(0),
    67       m_fps(30)
     64    : QSvgStructureNode(0)
     65    , m_widthPercent(false)
     66    , m_heightPercent(false)
     67    , m_animated(false)
     68    , m_animationDuration(0)
     69    , m_fps(30)
    6870{
    6971}
     
    232234    }
    233235
     236    if (displayMode() == QSvgNode::NoneMode)
     237        return;
     238
    234239    p->save();
    235 
    236240    //sets default style on the painter
    237241    //### not the most optimal way
    238242    mapSourceToTarget(p, bounds);
    239     p->setPen(Qt::NoPen);
     243    QPen pen(Qt::NoBrush, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
     244    pen.setMiterLimit(4);
     245    p->setPen(pen);
    240246    p->setBrush(Qt::black);
    241247    p->setRenderHint(QPainter::Antialiasing);
     
    245251    while (itr != m_renderers.end()) {
    246252        QSvgNode *node = *itr;
    247         if (node->isVisible())
     253        if ((node->isVisible()) && (node->displayMode() != QSvgNode::NoneMode))
    248254            node->draw(p, m_states);
    249255        ++itr;
     
    263269        return;
    264270    }
     271    if (m_time.isNull()) {
     272        m_time.start();
     273    }
     274
     275    if (node->displayMode() == QSvgNode::NoneMode)
     276        return;
    265277
    266278    p->save();
     
    272284
    273285    //XXX set default style on the painter
    274     p->setPen(Qt::NoPen);
     286    QPen pen(Qt::NoBrush, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
     287    pen.setMiterLimit(4);
     288    p->setPen(pen);
    275289    p->setBrush(Qt::black);
    276290    p->setRenderHint(QPainter::Antialiasing);
     
    335349{
    336350    return m_fonts[family];
     351}
     352
     353void QSvgTinyDocument::addNamedNode(const QString &id, QSvgNode *node)
     354{
     355    m_namedNodes.insert(id, node);
     356}
     357
     358QSvgNode *QSvgTinyDocument::namedNode(const QString &id) const
     359{
     360    return m_namedNodes.value(id);
     361}
     362
     363void QSvgTinyDocument::addNamedStyle(const QString &id, QSvgFillStyleProperty *style)
     364{
     365    m_namedStyles.insert(id, style);
     366}
     367
     368QSvgFillStyleProperty *QSvgTinyDocument::namedStyle(const QString &id) const
     369{
     370    return m_namedStyles.value(id);
    337371}
    338372
  • trunk/src/svg/qsvgtinydocument_p.h

    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**
     
    109109    void addSvgFont(QSvgFont *);
    110110    QSvgFont *svgFont(const QString &family) const;
     111    void addNamedNode(const QString &id, QSvgNode *node);
     112    QSvgNode *namedNode(const QString &id) const;
     113    void addNamedStyle(const QString &id, QSvgFillStyleProperty *style);
     114    QSvgFillStyleProperty *namedStyle(const QString &id) const;
    111115
    112116    void restartAnimation();
     
    128132
    129133    QHash<QString, QSvgRefCounter<QSvgFont> > m_fonts;
     134    QHash<QString, QSvgNode *> m_namedNodes;
     135    QHash<QString, QSvgRefCounter<QSvgFillStyleProperty> > m_namedStyles;
    130136
    131137    QTime m_time;
  • trunk/src/svg/qsvgwidget.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**
     
    5353/*!
    5454    \class QSvgWidget
    55     \ingroup multimedia
     55    \ingroup painting
    5656
    5757    \brief The QSvgWidget class provides a widget that is used to display the contents of
     
    8484    Q_DECLARE_PUBLIC(QSvgWidget)
    8585public:
    86     QSvgWidgetPrivate()
    87         : QWidgetPrivate()
    88     {
    89         Q_Q(QSvgWidget);
    90         renderer = new QSvgRenderer(q);
    91     }
    92     QSvgWidgetPrivate(const QString &file)
    93         : QWidgetPrivate()
    94     {
    95         Q_Q(QSvgWidget);
    96         renderer = new QSvgRenderer(file, q);
    97     }
    9886    QSvgRenderer *renderer;
    9987};
     
    10593    : QWidget(*new QSvgWidgetPrivate, parent, 0)
    10694{
     95    d_func()->renderer = new QSvgRenderer(this);
    10796    QObject::connect(d_func()->renderer, SIGNAL(repaintNeeded()),
    10897                     this, SLOT(update()));
     
    114103*/
    115104QSvgWidget::QSvgWidget(const QString &file, QWidget *parent)
    116     : QWidget(*new QSvgWidgetPrivate(file), parent, 0)
     105    : QWidget(*new QSvgWidgetPrivate, parent, 0)
    117106{
     107    d_func()->renderer = new QSvgRenderer(file, this);
    118108    QObject::connect(d_func()->renderer, SIGNAL(repaintNeeded()),
    119109                     this, SLOT(update()));
  • trunk/src/svg/qsvgwidget.h

    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**
  • trunk/src/svg/svg.pro

    r2 r561  
    4141INCLUDEPATH += ../3rdparty/harfbuzz/src
    4242
     43symbian:TARGET.UID3=0x2001B2E2
     44
    4345#zlib support
    4446contains(QT_CONFIG, zlib) {
    4547   INCLUDEPATH += ../3rdparty/zlib
    4648} else:!contains(QT_CONFIG, no-zlib) {
    47    unix:LIBS += -lz
     49   unix:LIBS_PRIVATE += -lz
    4850}
Note: See TracChangeset for help on using the changeset viewer.