src/svg/qsvgstyle.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtSvg module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qsvgstyle_p.h"
       
    43 
       
    44 #ifndef QT_NO_SVG
       
    45 
       
    46 #include "qsvgfont_p.h"
       
    47 #include "qsvggraphics_p.h"
       
    48 #include "qsvgnode_p.h"
       
    49 #include "qsvgtinydocument_p.h"
       
    50 
       
    51 #include "qpainter.h"
       
    52 #include "qpair.h"
       
    53 #include "qcolor.h"
       
    54 #include "qdebug.h"
       
    55 #include "qmath.h"
       
    56 #include "qnumeric.h"
       
    57 
       
    58 QT_BEGIN_NAMESPACE
       
    59 
       
    60 QSvgExtraStates::QSvgExtraStates()
       
    61     : 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)
       
    69 {
       
    70 }
       
    71 
       
    72 QSvgStyleProperty::~QSvgStyleProperty()
       
    73 {
       
    74 }
       
    75 
       
    76 void QSvgFillStyleProperty::apply(QPainter *, const QRectF &, QSvgNode *, QSvgExtraStates &)
       
    77 {
       
    78     Q_ASSERT(!"This should not be called!");
       
    79 }
       
    80 
       
    81 void QSvgFillStyleProperty::revert(QPainter *, QSvgExtraStates &)
       
    82 {
       
    83     Q_ASSERT(!"This should not be called!");
       
    84 }
       
    85 
       
    86 
       
    87 QSvgQualityStyle::QSvgQualityStyle(int color)
       
    88     : m_colorRendering(color)
       
    89 {
       
    90 
       
    91 }
       
    92 void QSvgQualityStyle::apply(QPainter *, const QRectF &, QSvgNode *, QSvgExtraStates &)
       
    93 {
       
    94 
       
    95 }
       
    96 void QSvgQualityStyle::revert(QPainter *, QSvgExtraStates &)
       
    97 {
       
    98 
       
    99 }
       
   100 
       
   101 QSvgFillStyle::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)
       
   111 {
       
   112 }
       
   113 
       
   114 void QSvgFillStyle::setFillRule(Qt::FillRule f)
       
   115 {
       
   116     m_fillRuleSet = 1;
       
   117     m_fillRule = f;
       
   118 }
       
   119 
       
   120 void QSvgFillStyle::setFillOpacity(qreal opacity)
       
   121 {
       
   122     m_fillOpacitySet = 1;
       
   123     m_fillOpacity = opacity;
       
   124 }
       
   125 
       
   126 void QSvgFillStyle::setFillStyle(QSvgFillStyleProperty* style)
       
   127 {
       
   128     m_style = style;
       
   129     m_fillSet = 1;
       
   130 }
       
   131 
       
   132 void QSvgFillStyle::setBrush(QBrush brush)
       
   133 {
       
   134     m_fill = brush;
       
   135     m_style = 0;
       
   136     m_fillSet = 1;
       
   137 }
       
   138 
       
   139 void QSvgFillStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &states)
       
   140 {
       
   141     m_oldFill = p->brush();
       
   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     }
       
   153     if (m_fillOpacitySet)
       
   154         states.fillOpacity = m_fillOpacity;
       
   155 }
       
   156 
       
   157 void QSvgFillStyle::revert(QPainter *p, QSvgExtraStates &states)
       
   158 {
       
   159     if (m_fillOpacitySet)
       
   160         states.fillOpacity = m_oldFillOpacity;
       
   161     if (m_fillSet)
       
   162         p->setBrush(m_oldFill);
       
   163     if (m_fillRuleSet)
       
   164         states.fillRule = m_oldFillRule;
       
   165 }
       
   166 
       
   167 QSvgViewportFillStyle::QSvgViewportFillStyle(const QBrush &brush)
       
   168     : m_viewportFill(brush)
       
   169 {
       
   170 }
       
   171 
       
   172 void QSvgViewportFillStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &)
       
   173 {
       
   174     m_oldFill = p->brush();
       
   175     p->setBrush(m_viewportFill);
       
   176 }
       
   177 
       
   178 void QSvgViewportFillStyle::revert(QPainter *p, QSvgExtraStates &)
       
   179 {
       
   180     p->setBrush(m_oldFill);
       
   181 }
       
   182 
       
   183 QSvgFontStyle::QSvgFontStyle(QSvgFont *font, QSvgTinyDocument *doc)
       
   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 
       
   195 QSvgFontStyle::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 
       
   207 int 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 
       
   227 void 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 
       
   266 void 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 
       
   274 QSvgStrokeStyle::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 
       
   295 void QSvgStrokeStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &states)
       
   296 {
       
   297     m_oldStroke = p->pen();
       
   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     if (setDashOffsetNeeded) {
       
   367         qreal currentWidth = pen.widthF();
       
   368         if (currentWidth == 0)
       
   369             currentWidth = 1;
       
   370         pen.setDashOffset(states.strokeDashOffset / currentWidth);
       
   371     }
       
   372 
       
   373     pen.setCosmetic(states.vectorEffect);
       
   374 
       
   375     p->setPen(pen);
       
   376 }
       
   377 
       
   378 void QSvgStrokeStyle::revert(QPainter *p, QSvgExtraStates &states)
       
   379 {
       
   380     p->setPen(m_oldStroke);
       
   381     states.strokeOpacity = m_oldStrokeOpacity;
       
   382     states.strokeDashOffset = m_oldStrokeDashOffset;
       
   383     states.vectorEffect = m_oldVectorEffect;
       
   384 }
       
   385 
       
   386 void QSvgStrokeStyle::setDashArray(const QVector<qreal> &dashes)
       
   387 {
       
   388     if (m_strokeWidthSet) {
       
   389         QVector<qreal> d = dashes;
       
   390         qreal w = m_stroke.widthF();
       
   391         if (w != 0 && w != 1) {
       
   392             for (int i = 0; i < d.size(); ++i)
       
   393                 d[i] /= w;
       
   394         }
       
   395         m_stroke.setDashPattern(d);
       
   396     } else {
       
   397         m_stroke.setDashPattern(dashes);
       
   398     }
       
   399     m_strokeDashArraySet = 1;
       
   400 }
       
   401 
       
   402 QSvgSolidColorStyle::QSvgSolidColorStyle(const QColor &color)
       
   403     : m_solidColor(color)
       
   404 {
       
   405 }
       
   406 
       
   407 QSvgGradientStyle::QSvgGradientStyle(QGradient *grad)
       
   408     : m_gradient(grad), m_gradientStopsSet(false)
       
   409 {
       
   410 }
       
   411 
       
   412 QBrush QSvgGradientStyle::brush(QPainter *, QSvgExtraStates &)
       
   413 {
       
   414     if (!m_link.isEmpty()) {
       
   415         resolveStops();
       
   416     }
       
   417 
       
   418     // If the gradient is marked as empty, insert transparent black
       
   419     if (!m_gradientStopsSet) {
       
   420         m_gradient->setStops(QGradientStops() << QGradientStop(0.0, QColor(0, 0, 0, 0)));
       
   421         m_gradientStopsSet = true;
       
   422     }
       
   423 
       
   424     QBrush b(*m_gradient);
       
   425 
       
   426     if (!m_matrix.isIdentity())
       
   427         b.setMatrix(m_matrix);
       
   428 
       
   429     return b;
       
   430 }
       
   431 
       
   432 
       
   433 void QSvgGradientStyle::setMatrix(const QMatrix &mat)
       
   434 {
       
   435     m_matrix = mat;
       
   436 }
       
   437 
       
   438 QSvgTransformStyle::QSvgTransformStyle(const QTransform &trans)
       
   439     : m_transform(trans)
       
   440 {
       
   441 }
       
   442 
       
   443 void QSvgTransformStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &)
       
   444 {
       
   445     m_oldWorldTransform = p->worldTransform();
       
   446     p->setWorldTransform(m_transform, true);
       
   447 }
       
   448 
       
   449 void QSvgTransformStyle::revert(QPainter *p, QSvgExtraStates &)
       
   450 {
       
   451     p->setWorldTransform(m_oldWorldTransform, false /* don't combine */);
       
   452 }
       
   453 
       
   454 QSvgStyleProperty::Type QSvgQualityStyle::type() const
       
   455 {
       
   456     return QUALITY;
       
   457 }
       
   458 
       
   459 QSvgStyleProperty::Type QSvgFillStyle::type() const
       
   460 {
       
   461     return FILL;
       
   462 }
       
   463 
       
   464 QSvgStyleProperty::Type QSvgViewportFillStyle::type() const
       
   465 {
       
   466     return VIEWPORT_FILL;
       
   467 }
       
   468 
       
   469 QSvgStyleProperty::Type QSvgFontStyle::type() const
       
   470 {
       
   471     return FONT;
       
   472 }
       
   473 
       
   474 QSvgStyleProperty::Type QSvgStrokeStyle::type() const
       
   475 {
       
   476     return STROKE;
       
   477 }
       
   478 
       
   479 QSvgStyleProperty::Type QSvgSolidColorStyle::type() const
       
   480 {
       
   481     return SOLID_COLOR;
       
   482 }
       
   483 
       
   484 QSvgStyleProperty::Type QSvgGradientStyle::type() const
       
   485 {
       
   486     return GRADIENT;
       
   487 }
       
   488 
       
   489 QSvgStyleProperty::Type QSvgTransformStyle::type() const
       
   490 {
       
   491     return TRANSFORM;
       
   492 }
       
   493 
       
   494 
       
   495 QSvgCompOpStyle::QSvgCompOpStyle(QPainter::CompositionMode mode)
       
   496     : m_mode(mode)
       
   497 {
       
   498 
       
   499 }
       
   500 
       
   501 void QSvgCompOpStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &)
       
   502 {
       
   503     m_oldMode = p->compositionMode();
       
   504     p->setCompositionMode(m_mode);
       
   505 }
       
   506 
       
   507 void QSvgCompOpStyle::revert(QPainter *p, QSvgExtraStates &)
       
   508 {
       
   509     p->setCompositionMode(m_oldMode);
       
   510 }
       
   511 
       
   512 QSvgStyleProperty::Type QSvgCompOpStyle::type() const
       
   513 {
       
   514     return COMP_OP;
       
   515 }
       
   516 
       
   517 QSvgStyle::~QSvgStyle()
       
   518 {
       
   519 }
       
   520 
       
   521 void QSvgStyle::apply(QPainter *p, const QRectF &rect, QSvgNode *node, QSvgExtraStates &states)
       
   522 {
       
   523     if (quality) {
       
   524         quality->apply(p, rect, node, states);
       
   525     }
       
   526 
       
   527     if (fill) {
       
   528         fill->apply(p, rect, node, states);
       
   529     }
       
   530 
       
   531     if (viewportFill) {
       
   532         viewportFill->apply(p, rect, node, states);
       
   533     }
       
   534 
       
   535     if (font) {
       
   536         font->apply(p, rect, node, states);
       
   537     }
       
   538 
       
   539     if (stroke) {
       
   540         stroke->apply(p, rect, node, states);
       
   541     }
       
   542 
       
   543     if (transform) {
       
   544         transform->apply(p, rect, node, states);
       
   545     }
       
   546 
       
   547     if (animateColor) {
       
   548         animateColor->apply(p, rect, node, states);
       
   549     }
       
   550 
       
   551     //animated transforms have to be applied
       
   552     //_after_ the original object transformations
       
   553     if (!animateTransforms.isEmpty()) {
       
   554         qreal totalTimeElapsed = node->document()->currentElapsed();
       
   555         // Find the last animateTransform with additive="replace", since this will override all
       
   556         // previous animateTransforms.
       
   557         QList<QSvgRefCounter<QSvgAnimateTransform> >::const_iterator itr = animateTransforms.constEnd();
       
   558         do {
       
   559             --itr;
       
   560             if ((*itr)->animActive(totalTimeElapsed)
       
   561                 && (*itr)->additiveType() == QSvgAnimateTransform::Replace) {
       
   562                 // An animateTransform with additive="replace" will replace the transform attribute.
       
   563                 if (transform)
       
   564                     transform->revert(p, states);
       
   565                 break;
       
   566             }
       
   567         } while (itr != animateTransforms.constBegin());
       
   568 
       
   569         // Apply the animateTransforms after and including the last one with additive="replace".
       
   570         for (; itr != animateTransforms.constEnd(); ++itr) {
       
   571             if ((*itr)->animActive(totalTimeElapsed))
       
   572                 (*itr)->apply(p, rect, node, states);
       
   573         }
       
   574     }
       
   575 
       
   576     if (opacity) {
       
   577         opacity->apply(p, rect, node, states);
       
   578     }
       
   579 
       
   580     if (compop) {
       
   581         compop->apply(p, rect, node, states);
       
   582     }
       
   583 }
       
   584 
       
   585 void QSvgStyle::revert(QPainter *p, QSvgExtraStates &states)
       
   586 {
       
   587     if (quality) {
       
   588         quality->revert(p, states);
       
   589     }
       
   590 
       
   591     if (fill) {
       
   592         fill->revert(p, states);
       
   593     }
       
   594 
       
   595     if (viewportFill) {
       
   596         viewportFill->revert(p, states);
       
   597     }
       
   598 
       
   599     if (font) {
       
   600         font->revert(p, states);
       
   601     }
       
   602 
       
   603     if (stroke) {
       
   604         stroke->revert(p, states);
       
   605     }
       
   606 
       
   607     //animated transforms need to be reverted _before_
       
   608     //the native transforms
       
   609     if (!animateTransforms.isEmpty()) {
       
   610         QList<QSvgRefCounter<QSvgAnimateTransform> >::const_iterator itr = animateTransforms.constBegin();
       
   611         for (; itr != animateTransforms.constEnd(); ++itr) {
       
   612             if ((*itr)->transformApplied()) {
       
   613                 (*itr)->revert(p, states);
       
   614                 break;
       
   615             }
       
   616         }
       
   617         for (; itr != animateTransforms.constEnd(); ++itr)
       
   618             (*itr)->clearTransformApplied();
       
   619     }
       
   620 
       
   621     if (transform) {
       
   622         transform->revert(p, states);
       
   623     }
       
   624 
       
   625     if (animateColor) {
       
   626         animateColor->revert(p, states);
       
   627     }
       
   628 
       
   629     if (opacity) {
       
   630         opacity->revert(p, states);
       
   631     }
       
   632 
       
   633     if (compop) {
       
   634         compop->revert(p, states);
       
   635     }
       
   636 }
       
   637 
       
   638 QSvgAnimateTransform::QSvgAnimateTransform(int startMs, int endMs, int byMs )
       
   639     : QSvgStyleProperty(),
       
   640       m_from(startMs), m_to(endMs), m_by(byMs),
       
   641       m_type(Empty), m_additive(Replace), m_count(0), m_finished(false), m_transformApplied(false)
       
   642 {
       
   643     m_totalRunningTime = m_to - m_from;
       
   644 }
       
   645 
       
   646 void QSvgAnimateTransform::setArgs(TransformType type, Additive additive, const QVector<qreal> &args)
       
   647 {
       
   648     m_type = type;
       
   649     m_args = args;
       
   650     m_additive = additive;
       
   651     Q_ASSERT(!(args.count()%3));
       
   652     m_count = args.count() / 3;
       
   653 }
       
   654 
       
   655 void QSvgAnimateTransform::apply(QPainter *p, const QRectF &, QSvgNode *node, QSvgExtraStates &)
       
   656 {
       
   657     m_oldWorldTransform = p->worldTransform();
       
   658     resolveMatrix(node);
       
   659     p->setWorldTransform(m_transform, true);
       
   660     m_transformApplied = true;
       
   661 }
       
   662 
       
   663 void QSvgAnimateTransform::revert(QPainter *p, QSvgExtraStates &)
       
   664 {
       
   665     p->setWorldTransform(m_oldWorldTransform, false /* don't combine */);
       
   666     m_transformApplied = false;
       
   667 }
       
   668 
       
   669 void QSvgAnimateTransform::resolveMatrix(QSvgNode *node)
       
   670 {
       
   671     static const qreal deg2rad = qreal(0.017453292519943295769);
       
   672     qreal totalTimeElapsed = node->document()->currentElapsed();
       
   673     if (totalTimeElapsed < m_from || m_finished)
       
   674         return;
       
   675 
       
   676     qreal animationFrame = 0;
       
   677     if (m_totalRunningTime != 0) {
       
   678         animationFrame = (totalTimeElapsed - m_from) / m_totalRunningTime;
       
   679 
       
   680         if (m_repeatCount >= 0 && m_repeatCount < animationFrame) {
       
   681             m_finished = true;
       
   682             animationFrame = m_repeatCount;
       
   683         }
       
   684     }
       
   685 
       
   686     qreal percentOfAnimation = animationFrame;
       
   687     if (percentOfAnimation > 1) {
       
   688         percentOfAnimation -= ((int)percentOfAnimation);
       
   689     }
       
   690 
       
   691     qreal currentPosition = percentOfAnimation * (m_count - 1);
       
   692     int startElem = qFloor(currentPosition);
       
   693     int endElem   = qCeil(currentPosition);
       
   694 
       
   695     switch(m_type)
       
   696     {
       
   697     case Translate: {
       
   698         startElem *= 3;
       
   699         endElem   *= 3;
       
   700         qreal from1, from2;
       
   701         qreal to1, to2;
       
   702         from1 = m_args[startElem++];
       
   703         from2 = m_args[startElem++];
       
   704         to1   = m_args[endElem++];
       
   705         to2   = m_args[endElem++];
       
   706 
       
   707         qreal transXDiff = (to1-from1) * percentOfAnimation;
       
   708         qreal transX = from1 + transXDiff;
       
   709         qreal transYDiff = (to2-from2) * percentOfAnimation;
       
   710         qreal transY = from2 + transYDiff;
       
   711         m_transform = QTransform();
       
   712         m_transform.translate(transX, transY);
       
   713         break;
       
   714     }
       
   715     case Scale: {
       
   716         startElem *= 3;
       
   717         endElem   *= 3;
       
   718         qreal from1, from2;
       
   719         qreal to1, to2;
       
   720         from1 = m_args[startElem++];
       
   721         from2 = m_args[startElem++];
       
   722         to1   = m_args[endElem++];
       
   723         to2   = m_args[endElem++];
       
   724 
       
   725         qreal transXDiff = (to1-from1) * percentOfAnimation;
       
   726         qreal transX = from1 + transXDiff;
       
   727         qreal transYDiff = (to2-from2) * percentOfAnimation;
       
   728         qreal transY = from2 + transYDiff;
       
   729         if (transY == 0)
       
   730             transY = transX;
       
   731         m_transform = QTransform();
       
   732         m_transform.scale(transX, transY);
       
   733         break;
       
   734     }
       
   735     case Rotate: {
       
   736         startElem *= 3;
       
   737         endElem   *= 3;
       
   738         qreal from1, from2, from3;
       
   739         qreal to1, to2, to3;
       
   740         from1 = m_args[startElem++];
       
   741         from2 = m_args[startElem++];
       
   742         from3 = m_args[startElem++];
       
   743         to1   = m_args[endElem++];
       
   744         to2   = m_args[endElem++];
       
   745         to3   = m_args[endElem++];
       
   746 
       
   747         qreal rotationDiff = (to1 - from1) * percentOfAnimation;
       
   748         //qreal rotation = from1 + rotationDiff;
       
   749 
       
   750         qreal transXDiff = (to2-from2) * percentOfAnimation;
       
   751         qreal transX = from2 + transXDiff;
       
   752         qreal transYDiff = (to3-from3) * percentOfAnimation;
       
   753         qreal transY = from3 + transYDiff;
       
   754         m_transform = QTransform();
       
   755         m_transform.translate(transX, transY);
       
   756         m_transform.rotate(rotationDiff);
       
   757         m_transform.translate(-transX, -transY);
       
   758         break;
       
   759     }
       
   760     case SkewX: {
       
   761         startElem *= 3;
       
   762         endElem   *= 3;
       
   763         qreal from1;
       
   764         qreal to1;
       
   765         from1 = m_args[startElem++];
       
   766         to1   = m_args[endElem++];
       
   767 
       
   768         qreal transXDiff = (to1-from1) * percentOfAnimation;
       
   769         qreal transX = from1 + transXDiff;
       
   770         m_transform = QTransform();
       
   771         m_transform.shear(tan(transX * deg2rad), 0);
       
   772         break;
       
   773     }
       
   774     case SkewY: {
       
   775         startElem *= 3;
       
   776         endElem   *= 3;
       
   777         qreal from1;
       
   778         qreal to1;
       
   779         from1 = m_args[startElem++];
       
   780         to1   = m_args[endElem++];
       
   781 
       
   782 
       
   783         qreal transYDiff = (to1 - from1) * percentOfAnimation;
       
   784         qreal transY = from1 + transYDiff;
       
   785         m_transform = QTransform();
       
   786         m_transform.shear(0, tan(transY * deg2rad));
       
   787         break;
       
   788     }
       
   789     default:
       
   790         break;
       
   791     }
       
   792 }
       
   793 
       
   794 QSvgStyleProperty::Type QSvgAnimateTransform::type() const
       
   795 {
       
   796     return ANIMATE_TRANSFORM;
       
   797 }
       
   798 
       
   799 void QSvgAnimateTransform::setFreeze(bool freeze)
       
   800 {
       
   801     m_freeze = freeze;
       
   802 }
       
   803 
       
   804 void QSvgAnimateTransform::setRepeatCount(qreal repeatCount)
       
   805 {
       
   806     m_repeatCount = repeatCount;
       
   807 }
       
   808 
       
   809 QSvgAnimateColor::QSvgAnimateColor(int startMs, int endMs, int byMs)
       
   810     : QSvgStyleProperty(),
       
   811       m_from(startMs), m_to(endMs), m_by(byMs),
       
   812       m_finished(false)
       
   813 {
       
   814     m_totalRunningTime = m_to - m_from;
       
   815 }
       
   816 
       
   817 void QSvgAnimateColor::setArgs(bool fill,
       
   818                                const QList<QColor> &colors)
       
   819 {
       
   820     m_fill = fill;
       
   821     m_colors = colors;
       
   822 }
       
   823 
       
   824 void QSvgAnimateColor::setFreeze(bool freeze)
       
   825 {
       
   826     m_freeze = freeze;
       
   827 }
       
   828 
       
   829 void QSvgAnimateColor::setRepeatCount(qreal repeatCount)
       
   830 {
       
   831     m_repeatCount = repeatCount;
       
   832 }
       
   833 
       
   834 void QSvgAnimateColor::apply(QPainter *p, const QRectF &, QSvgNode *node, QSvgExtraStates &)
       
   835 {
       
   836     qreal totalTimeElapsed = node->document()->currentElapsed();
       
   837     if (totalTimeElapsed < m_from || m_finished)
       
   838         return;
       
   839 
       
   840     qreal animationFrame = 0;
       
   841     if (m_totalRunningTime != 0)
       
   842         animationFrame = (totalTimeElapsed - m_from) / m_totalRunningTime;
       
   843 
       
   844     if (m_repeatCount >= 0 && m_repeatCount < animationFrame) {
       
   845         m_finished = true;
       
   846         animationFrame = m_repeatCount;
       
   847     }
       
   848 
       
   849     qreal percentOfAnimation = animationFrame;
       
   850     if (percentOfAnimation > 1) {
       
   851         percentOfAnimation -= ((int)percentOfAnimation);
       
   852     }
       
   853 
       
   854     qreal currentPosition = percentOfAnimation * (m_colors.count() - 1);
       
   855 
       
   856     int startElem = qFloor(currentPosition);
       
   857     int endElem   = qCeil(currentPosition);
       
   858     QColor start = m_colors[startElem];
       
   859     QColor end = m_colors[endElem];
       
   860 
       
   861     qreal percentOfColorMorph = currentPosition;
       
   862     if (percentOfColorMorph > 1) {
       
   863         percentOfColorMorph -= ((int)percentOfColorMorph);
       
   864     }
       
   865 
       
   866     // Interpolate between the two fixed colors start and end
       
   867     qreal aDiff = (end.alpha() - start.alpha()) * percentOfColorMorph;
       
   868     qreal rDiff = (end.red()   - start.red()) * percentOfColorMorph;
       
   869     qreal gDiff = (end.green() - start.green()) * percentOfColorMorph;
       
   870     qreal bDiff = (end.blue()  - start.blue()) * percentOfColorMorph;
       
   871 
       
   872     int alpha  = int(start.alpha() + aDiff);
       
   873     int red    = int(start.red() + rDiff);
       
   874     int green  = int(start.green() + gDiff);
       
   875     int blue   = int(start.blue() + bDiff);
       
   876 
       
   877     QColor color(red, green, blue, alpha);
       
   878 
       
   879     if (m_fill) {
       
   880         QBrush b = p->brush();
       
   881         m_oldBrush = b;
       
   882         b.setColor(color);
       
   883         p->setBrush(b);
       
   884     } else {
       
   885         QPen pen = p->pen();
       
   886         m_oldPen = pen;
       
   887         pen.setColor(color);
       
   888         p->setPen(pen);
       
   889     }
       
   890 }
       
   891 
       
   892 void QSvgAnimateColor::revert(QPainter *p, QSvgExtraStates &)
       
   893 {
       
   894     if (m_fill) {
       
   895         p->setBrush(m_oldBrush);
       
   896     } else {
       
   897         p->setPen(m_oldPen);
       
   898     }
       
   899 }
       
   900 
       
   901 QSvgStyleProperty::Type QSvgAnimateColor::type() const
       
   902 {
       
   903     return ANIMATE_COLOR;
       
   904 }
       
   905 
       
   906 QSvgOpacityStyle::QSvgOpacityStyle(qreal opacity)
       
   907     : m_opacity(opacity), m_oldOpacity(0)
       
   908 {
       
   909 
       
   910 }
       
   911 
       
   912 void QSvgOpacityStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &)
       
   913 {
       
   914     m_oldOpacity = p->opacity();
       
   915     p->setOpacity(m_opacity * m_oldOpacity);
       
   916 }
       
   917 
       
   918 void QSvgOpacityStyle::revert(QPainter *p, QSvgExtraStates &)
       
   919 {
       
   920     p->setOpacity(m_oldOpacity);
       
   921 }
       
   922 
       
   923 QSvgStyleProperty::Type QSvgOpacityStyle::type() const
       
   924 {
       
   925     return OPACITY;
       
   926 }
       
   927 
       
   928 void QSvgGradientStyle::setStopLink(const QString &link, QSvgTinyDocument *doc)
       
   929 {
       
   930     m_link = link;
       
   931     m_doc  = doc;
       
   932 }
       
   933 
       
   934 void QSvgGradientStyle::resolveStops()
       
   935 {
       
   936     if (!m_link.isEmpty() && m_doc) {
       
   937         QSvgStyleProperty *prop = m_doc->styleProperty(m_link);
       
   938         if (prop) {
       
   939             if (prop->type() == QSvgStyleProperty::GRADIENT) {
       
   940                 QSvgGradientStyle *st =
       
   941                     static_cast<QSvgGradientStyle*>(prop);
       
   942                 st->resolveStops();
       
   943                 m_gradient->setStops(st->qgradient()->stops());
       
   944                 m_gradientStopsSet = st->gradientStopsSet();
       
   945             }
       
   946         } else {
       
   947             qWarning("Could not resolve property : %s", qPrintable(m_link));
       
   948         }
       
   949         m_link = QString();
       
   950     }
       
   951 }
       
   952 
       
   953 QT_END_NAMESPACE
       
   954 
       
   955 #endif // QT_NO_SVG