util/src/svg/qsvgstyle.cpp
changeset 7 f7bc934e204c
equal deleted inserted replaced
3:41300fa6a67c 7:f7bc934e204c
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 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     // 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 
       
   381 void QSvgStrokeStyle::revert(QPainter *p, QSvgExtraStates &states)
       
   382 {
       
   383     p->setPen(m_oldStroke);
       
   384     states.strokeOpacity = m_oldStrokeOpacity;
       
   385     states.strokeDashOffset = m_oldStrokeDashOffset;
       
   386     states.vectorEffect = m_oldVectorEffect;
       
   387 }
       
   388 
       
   389 void 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;
       
   403 }
       
   404 
       
   405 QSvgSolidColorStyle::QSvgSolidColorStyle(const QColor &color)
       
   406     : m_solidColor(color)
       
   407 {
       
   408 }
       
   409 
       
   410 QSvgGradientStyle::QSvgGradientStyle(QGradient *grad)
       
   411     : m_gradient(grad), m_gradientStopsSet(false)
       
   412 {
       
   413 }
       
   414 
       
   415 QBrush QSvgGradientStyle::brush(QPainter *, QSvgExtraStates &)
       
   416 {
       
   417     if (!m_link.isEmpty()) {
       
   418         resolveStops();
       
   419     }
       
   420 
       
   421     // If the gradient is marked as empty, insert transparent black
       
   422     if (!m_gradientStopsSet) {
       
   423         m_gradient->setStops(QGradientStops() << QGradientStop(0.0, QColor(0, 0, 0, 0)));
       
   424         m_gradientStopsSet = true;
       
   425     }
       
   426 
       
   427     QBrush b(*m_gradient);
       
   428 
       
   429     if (!m_matrix.isIdentity())
       
   430         b.setMatrix(m_matrix);
       
   431 
       
   432     return b;
       
   433 }
       
   434 
       
   435 
       
   436 void QSvgGradientStyle::setMatrix(const QMatrix &mat)
       
   437 {
       
   438     m_matrix = mat;
       
   439 }
       
   440 
       
   441 QSvgTransformStyle::QSvgTransformStyle(const QTransform &trans)
       
   442     : m_transform(trans)
       
   443 {
       
   444 }
       
   445 
       
   446 void QSvgTransformStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &)
       
   447 {
       
   448     m_oldWorldTransform = p->worldTransform();
       
   449     p->setWorldTransform(m_transform, true);
       
   450 }
       
   451 
       
   452 void QSvgTransformStyle::revert(QPainter *p, QSvgExtraStates &)
       
   453 {
       
   454     p->setWorldTransform(m_oldWorldTransform, false /* don't combine */);
       
   455 }
       
   456 
       
   457 QSvgStyleProperty::Type QSvgQualityStyle::type() const
       
   458 {
       
   459     return QUALITY;
       
   460 }
       
   461 
       
   462 QSvgStyleProperty::Type QSvgFillStyle::type() const
       
   463 {
       
   464     return FILL;
       
   465 }
       
   466 
       
   467 QSvgStyleProperty::Type QSvgViewportFillStyle::type() const
       
   468 {
       
   469     return VIEWPORT_FILL;
       
   470 }
       
   471 
       
   472 QSvgStyleProperty::Type QSvgFontStyle::type() const
       
   473 {
       
   474     return FONT;
       
   475 }
       
   476 
       
   477 QSvgStyleProperty::Type QSvgStrokeStyle::type() const
       
   478 {
       
   479     return STROKE;
       
   480 }
       
   481 
       
   482 QSvgStyleProperty::Type QSvgSolidColorStyle::type() const
       
   483 {
       
   484     return SOLID_COLOR;
       
   485 }
       
   486 
       
   487 QSvgStyleProperty::Type QSvgGradientStyle::type() const
       
   488 {
       
   489     return GRADIENT;
       
   490 }
       
   491 
       
   492 QSvgStyleProperty::Type QSvgTransformStyle::type() const
       
   493 {
       
   494     return TRANSFORM;
       
   495 }
       
   496 
       
   497 
       
   498 QSvgCompOpStyle::QSvgCompOpStyle(QPainter::CompositionMode mode)
       
   499     : m_mode(mode)
       
   500 {
       
   501 
       
   502 }
       
   503 
       
   504 void QSvgCompOpStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &)
       
   505 {
       
   506     m_oldMode = p->compositionMode();
       
   507     p->setCompositionMode(m_mode);
       
   508 }
       
   509 
       
   510 void QSvgCompOpStyle::revert(QPainter *p, QSvgExtraStates &)
       
   511 {
       
   512     p->setCompositionMode(m_oldMode);
       
   513 }
       
   514 
       
   515 QSvgStyleProperty::Type QSvgCompOpStyle::type() const
       
   516 {
       
   517     return COMP_OP;
       
   518 }
       
   519 
       
   520 QSvgStyle::~QSvgStyle()
       
   521 {
       
   522 }
       
   523 
       
   524 void QSvgStyle::apply(QPainter *p, const QRectF &rect, QSvgNode *node, QSvgExtraStates &states)
       
   525 {
       
   526     if (quality) {
       
   527         quality->apply(p, rect, node, states);
       
   528     }
       
   529 
       
   530     if (fill) {
       
   531         fill->apply(p, rect, node, states);
       
   532     }
       
   533 
       
   534     if (viewportFill) {
       
   535         viewportFill->apply(p, rect, node, states);
       
   536     }
       
   537 
       
   538     if (font) {
       
   539         font->apply(p, rect, node, states);
       
   540     }
       
   541 
       
   542     if (stroke) {
       
   543         stroke->apply(p, rect, node, states);
       
   544     }
       
   545 
       
   546     if (transform) {
       
   547         transform->apply(p, rect, node, states);
       
   548     }
       
   549 
       
   550     if (animateColor) {
       
   551         animateColor->apply(p, rect, node, states);
       
   552     }
       
   553 
       
   554     //animated transforms have to be applied
       
   555     //_after_ the original object transformations
       
   556     if (!animateTransforms.isEmpty()) {
       
   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);
       
   576         }
       
   577     }
       
   578 
       
   579     if (opacity) {
       
   580         opacity->apply(p, rect, node, states);
       
   581     }
       
   582 
       
   583     if (compop) {
       
   584         compop->apply(p, rect, node, states);
       
   585     }
       
   586 }
       
   587 
       
   588 void QSvgStyle::revert(QPainter *p, QSvgExtraStates &states)
       
   589 {
       
   590     if (quality) {
       
   591         quality->revert(p, states);
       
   592     }
       
   593 
       
   594     if (fill) {
       
   595         fill->revert(p, states);
       
   596     }
       
   597 
       
   598     if (viewportFill) {
       
   599         viewportFill->revert(p, states);
       
   600     }
       
   601 
       
   602     if (font) {
       
   603         font->revert(p, states);
       
   604     }
       
   605 
       
   606     if (stroke) {
       
   607         stroke->revert(p, states);
       
   608     }
       
   609 
       
   610     //animated transforms need to be reverted _before_
       
   611     //the native transforms
       
   612     if (!animateTransforms.isEmpty()) {
       
   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             }
       
   619         }
       
   620         for (; itr != animateTransforms.constEnd(); ++itr)
       
   621             (*itr)->clearTransformApplied();
       
   622     }
       
   623 
       
   624     if (transform) {
       
   625         transform->revert(p, states);
       
   626     }
       
   627 
       
   628     if (animateColor) {
       
   629         animateColor->revert(p, states);
       
   630     }
       
   631 
       
   632     if (opacity) {
       
   633         opacity->revert(p, states);
       
   634     }
       
   635 
       
   636     if (compop) {
       
   637         compop->revert(p, states);
       
   638     }
       
   639 }
       
   640 
       
   641 QSvgAnimateTransform::QSvgAnimateTransform(int startMs, int endMs, int byMs )
       
   642     : QSvgStyleProperty(),
       
   643       m_from(startMs), m_to(endMs), m_by(byMs),
       
   644       m_type(Empty), m_additive(Replace), m_count(0), m_finished(false), m_transformApplied(false)
       
   645 {
       
   646     m_totalRunningTime = m_to - m_from;
       
   647 }
       
   648 
       
   649 void QSvgAnimateTransform::setArgs(TransformType type, Additive additive, const QVector<qreal> &args)
       
   650 {
       
   651     m_type = type;
       
   652     m_args = args;
       
   653     m_additive = additive;
       
   654     Q_ASSERT(!(args.count()%3));
       
   655     m_count = args.count() / 3;
       
   656 }
       
   657 
       
   658 void QSvgAnimateTransform::apply(QPainter *p, const QRectF &, QSvgNode *node, QSvgExtraStates &)
       
   659 {
       
   660     m_oldWorldTransform = p->worldTransform();
       
   661     resolveMatrix(node);
       
   662     p->setWorldTransform(m_transform, true);
       
   663     m_transformApplied = true;
       
   664 }
       
   665 
       
   666 void QSvgAnimateTransform::revert(QPainter *p, QSvgExtraStates &)
       
   667 {
       
   668     p->setWorldTransform(m_oldWorldTransform, false /* don't combine */);
       
   669     m_transformApplied = false;
       
   670 }
       
   671 
       
   672 void QSvgAnimateTransform::resolveMatrix(QSvgNode *node)
       
   673 {
       
   674     static const qreal deg2rad = qreal(0.017453292519943295769);
       
   675     qreal totalTimeElapsed = node->document()->currentElapsed();
       
   676     if (totalTimeElapsed < m_from || m_finished)
       
   677         return;
       
   678 
       
   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         }
       
   687     }
       
   688 
       
   689     qreal percentOfAnimation = animationFrame;
       
   690     if (percentOfAnimation > 1) {
       
   691         percentOfAnimation -= ((int)percentOfAnimation);
       
   692     }
       
   693 
       
   694     qreal currentPosition = percentOfAnimation * (m_count - 1);
       
   695     int startElem = qFloor(currentPosition);
       
   696     int endElem   = qCeil(currentPosition);
       
   697 
       
   698     switch(m_type)
       
   699     {
       
   700     case Translate: {
       
   701         startElem *= 3;
       
   702         endElem   *= 3;
       
   703         qreal from1, from2;
       
   704         qreal to1, to2;
       
   705         from1 = m_args[startElem++];
       
   706         from2 = m_args[startElem++];
       
   707         to1   = m_args[endElem++];
       
   708         to2   = m_args[endElem++];
       
   709 
       
   710         qreal transXDiff = (to1-from1) * percentOfAnimation;
       
   711         qreal transX = from1 + transXDiff;
       
   712         qreal transYDiff = (to2-from2) * percentOfAnimation;
       
   713         qreal transY = from2 + transYDiff;
       
   714         m_transform = QTransform();
       
   715         m_transform.translate(transX, transY);
       
   716         break;
       
   717     }
       
   718     case Scale: {
       
   719         startElem *= 3;
       
   720         endElem   *= 3;
       
   721         qreal from1, from2;
       
   722         qreal to1, to2;
       
   723         from1 = m_args[startElem++];
       
   724         from2 = m_args[startElem++];
       
   725         to1   = m_args[endElem++];
       
   726         to2   = m_args[endElem++];
       
   727 
       
   728         qreal transXDiff = (to1-from1) * percentOfAnimation;
       
   729         qreal transX = from1 + transXDiff;
       
   730         qreal transYDiff = (to2-from2) * percentOfAnimation;
       
   731         qreal transY = from2 + transYDiff;
       
   732         if (transY == 0)
       
   733             transY = transX;
       
   734         m_transform = QTransform();
       
   735         m_transform.scale(transX, transY);
       
   736         break;
       
   737     }
       
   738     case Rotate: {
       
   739         startElem *= 3;
       
   740         endElem   *= 3;
       
   741         qreal from1, from2, from3;
       
   742         qreal to1, to2, to3;
       
   743         from1 = m_args[startElem++];
       
   744         from2 = m_args[startElem++];
       
   745         from3 = m_args[startElem++];
       
   746         to1   = m_args[endElem++];
       
   747         to2   = m_args[endElem++];
       
   748         to3   = m_args[endElem++];
       
   749 
       
   750         qreal rotationDiff = (to1 - from1) * percentOfAnimation;
       
   751         //qreal rotation = from1 + rotationDiff;
       
   752 
       
   753         qreal transXDiff = (to2-from2) * percentOfAnimation;
       
   754         qreal transX = from2 + transXDiff;
       
   755         qreal transYDiff = (to3-from3) * percentOfAnimation;
       
   756         qreal transY = from3 + transYDiff;
       
   757         m_transform = QTransform();
       
   758         m_transform.translate(transX, transY);
       
   759         m_transform.rotate(rotationDiff);
       
   760         m_transform.translate(-transX, -transY);
       
   761         break;
       
   762     }
       
   763     case SkewX: {
       
   764         startElem *= 3;
       
   765         endElem   *= 3;
       
   766         qreal from1;
       
   767         qreal to1;
       
   768         from1 = m_args[startElem++];
       
   769         to1   = m_args[endElem++];
       
   770 
       
   771         qreal transXDiff = (to1-from1) * percentOfAnimation;
       
   772         qreal transX = from1 + transXDiff;
       
   773         m_transform = QTransform();
       
   774         m_transform.shear(qTan(transX * deg2rad), 0);
       
   775         break;
       
   776     }
       
   777     case SkewY: {
       
   778         startElem *= 3;
       
   779         endElem   *= 3;
       
   780         qreal from1;
       
   781         qreal to1;
       
   782         from1 = m_args[startElem++];
       
   783         to1   = m_args[endElem++];
       
   784 
       
   785 
       
   786         qreal transYDiff = (to1 - from1) * percentOfAnimation;
       
   787         qreal transY = from1 + transYDiff;
       
   788         m_transform = QTransform();
       
   789         m_transform.shear(0, qTan(transY * deg2rad));
       
   790         break;
       
   791     }
       
   792     default:
       
   793         break;
       
   794     }
       
   795 }
       
   796 
       
   797 QSvgStyleProperty::Type QSvgAnimateTransform::type() const
       
   798 {
       
   799     return ANIMATE_TRANSFORM;
       
   800 }
       
   801 
       
   802 void QSvgAnimateTransform::setFreeze(bool freeze)
       
   803 {
       
   804     m_freeze = freeze;
       
   805 }
       
   806 
       
   807 void QSvgAnimateTransform::setRepeatCount(qreal repeatCount)
       
   808 {
       
   809     m_repeatCount = repeatCount;
       
   810 }
       
   811 
       
   812 QSvgAnimateColor::QSvgAnimateColor(int startMs, int endMs, int byMs)
       
   813     : QSvgStyleProperty(),
       
   814       m_from(startMs), m_to(endMs), m_by(byMs),
       
   815       m_finished(false)
       
   816 {
       
   817     m_totalRunningTime = m_to - m_from;
       
   818 }
       
   819 
       
   820 void QSvgAnimateColor::setArgs(bool fill,
       
   821                                const QList<QColor> &colors)
       
   822 {
       
   823     m_fill = fill;
       
   824     m_colors = colors;
       
   825 }
       
   826 
       
   827 void QSvgAnimateColor::setFreeze(bool freeze)
       
   828 {
       
   829     m_freeze = freeze;
       
   830 }
       
   831 
       
   832 void QSvgAnimateColor::setRepeatCount(qreal repeatCount)
       
   833 {
       
   834     m_repeatCount = repeatCount;
       
   835 }
       
   836 
       
   837 void QSvgAnimateColor::apply(QPainter *p, const QRectF &, QSvgNode *node, QSvgExtraStates &)
       
   838 {
       
   839     qreal totalTimeElapsed = node->document()->currentElapsed();
       
   840     if (totalTimeElapsed < m_from || m_finished)
       
   841         return;
       
   842 
       
   843     qreal animationFrame = 0;
       
   844     if (m_totalRunningTime != 0)
       
   845         animationFrame = (totalTimeElapsed - m_from) / m_totalRunningTime;
       
   846 
       
   847     if (m_repeatCount >= 0 && m_repeatCount < animationFrame) {
       
   848         m_finished = true;
       
   849         animationFrame = m_repeatCount;
       
   850     }
       
   851 
       
   852     qreal percentOfAnimation = animationFrame;
       
   853     if (percentOfAnimation > 1) {
       
   854         percentOfAnimation -= ((int)percentOfAnimation);
       
   855     }
       
   856 
       
   857     qreal currentPosition = percentOfAnimation * (m_colors.count() - 1);
       
   858 
       
   859     int startElem = qFloor(currentPosition);
       
   860     int endElem   = qCeil(currentPosition);
       
   861     QColor start = m_colors[startElem];
       
   862     QColor end = m_colors[endElem];
       
   863 
       
   864     qreal percentOfColorMorph = currentPosition;
       
   865     if (percentOfColorMorph > 1) {
       
   866         percentOfColorMorph -= ((int)percentOfColorMorph);
       
   867     }
       
   868 
       
   869     // Interpolate between the two fixed colors start and end
       
   870     qreal aDiff = (end.alpha() - start.alpha()) * percentOfColorMorph;
       
   871     qreal rDiff = (end.red()   - start.red()) * percentOfColorMorph;
       
   872     qreal gDiff = (end.green() - start.green()) * percentOfColorMorph;
       
   873     qreal bDiff = (end.blue()  - start.blue()) * percentOfColorMorph;
       
   874 
       
   875     int alpha  = int(start.alpha() + aDiff);
       
   876     int red    = int(start.red() + rDiff);
       
   877     int green  = int(start.green() + gDiff);
       
   878     int blue   = int(start.blue() + bDiff);
       
   879 
       
   880     QColor color(red, green, blue, alpha);
       
   881 
       
   882     if (m_fill) {
       
   883         QBrush b = p->brush();
       
   884         m_oldBrush = b;
       
   885         b.setColor(color);
       
   886         p->setBrush(b);
       
   887     } else {
       
   888         QPen pen = p->pen();
       
   889         m_oldPen = pen;
       
   890         pen.setColor(color);
       
   891         p->setPen(pen);
       
   892     }
       
   893 }
       
   894 
       
   895 void QSvgAnimateColor::revert(QPainter *p, QSvgExtraStates &)
       
   896 {
       
   897     if (m_fill) {
       
   898         p->setBrush(m_oldBrush);
       
   899     } else {
       
   900         p->setPen(m_oldPen);
       
   901     }
       
   902 }
       
   903 
       
   904 QSvgStyleProperty::Type QSvgAnimateColor::type() const
       
   905 {
       
   906     return ANIMATE_COLOR;
       
   907 }
       
   908 
       
   909 QSvgOpacityStyle::QSvgOpacityStyle(qreal opacity)
       
   910     : m_opacity(opacity), m_oldOpacity(0)
       
   911 {
       
   912 
       
   913 }
       
   914 
       
   915 void QSvgOpacityStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &)
       
   916 {
       
   917     m_oldOpacity = p->opacity();
       
   918     p->setOpacity(m_opacity * m_oldOpacity);
       
   919 }
       
   920 
       
   921 void QSvgOpacityStyle::revert(QPainter *p, QSvgExtraStates &)
       
   922 {
       
   923     p->setOpacity(m_oldOpacity);
       
   924 }
       
   925 
       
   926 QSvgStyleProperty::Type QSvgOpacityStyle::type() const
       
   927 {
       
   928     return OPACITY;
       
   929 }
       
   930 
       
   931 void QSvgGradientStyle::setStopLink(const QString &link, QSvgTinyDocument *doc)
       
   932 {
       
   933     m_link = link;
       
   934     m_doc  = doc;
       
   935 }
       
   936 
       
   937 void QSvgGradientStyle::resolveStops()
       
   938 {
       
   939     if (!m_link.isEmpty() && m_doc) {
       
   940         QSvgStyleProperty *prop = m_doc->styleProperty(m_link);
       
   941         if (prop) {
       
   942             if (prop->type() == QSvgStyleProperty::GRADIENT) {
       
   943                 QSvgGradientStyle *st =
       
   944                     static_cast<QSvgGradientStyle*>(prop);
       
   945                 st->resolveStops();
       
   946                 m_gradient->setStops(st->qgradient()->stops());
       
   947                 m_gradientStopsSet = st->gradientStopsSet();
       
   948             }
       
   949         } else {
       
   950             qWarning("Could not resolve property : %s", qPrintable(m_link));
       
   951         }
       
   952         m_link = QString();
       
   953     }
       
   954 }
       
   955 
       
   956 QT_END_NAMESPACE
       
   957 
       
   958 #endif // QT_NO_SVG