diff -r 000000000000 -r 1918ee327afb src/svg/qsvgstyle.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/svg/qsvgstyle.cpp Mon Jan 11 14:00:40 2010 +0000 @@ -0,0 +1,955 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtSvg module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsvgstyle_p.h" + +#ifndef QT_NO_SVG + +#include "qsvgfont_p.h" +#include "qsvggraphics_p.h" +#include "qsvgnode_p.h" +#include "qsvgtinydocument_p.h" + +#include "qpainter.h" +#include "qpair.h" +#include "qcolor.h" +#include "qdebug.h" +#include "qmath.h" +#include "qnumeric.h" + +QT_BEGIN_NAMESPACE + +QSvgExtraStates::QSvgExtraStates() + : fillOpacity(1.0) + , strokeOpacity(1.0) + , svgFont(0) + , textAnchor(Qt::AlignLeft) + , fontWeight(400) + , fillRule(Qt::WindingFill) + , strokeDashOffset(0) + , vectorEffect(false) +{ +} + +QSvgStyleProperty::~QSvgStyleProperty() +{ +} + +void QSvgFillStyleProperty::apply(QPainter *, const QRectF &, QSvgNode *, QSvgExtraStates &) +{ + Q_ASSERT(!"This should not be called!"); +} + +void QSvgFillStyleProperty::revert(QPainter *, QSvgExtraStates &) +{ + Q_ASSERT(!"This should not be called!"); +} + + +QSvgQualityStyle::QSvgQualityStyle(int color) + : m_colorRendering(color) +{ + +} +void QSvgQualityStyle::apply(QPainter *, const QRectF &, QSvgNode *, QSvgExtraStates &) +{ + +} +void QSvgQualityStyle::revert(QPainter *, QSvgExtraStates &) +{ + +} + +QSvgFillStyle::QSvgFillStyle() + : m_style(0) + , m_fillRule(Qt::WindingFill) + , m_oldFillRule(Qt::WindingFill) + , m_fillOpacity(1.0) + , m_oldFillOpacity(0) + , m_gradientResolved(1) + , m_fillRuleSet(0) + , m_fillOpacitySet(0) + , m_fillSet(0) +{ +} + +void QSvgFillStyle::setFillRule(Qt::FillRule f) +{ + m_fillRuleSet = 1; + m_fillRule = f; +} + +void QSvgFillStyle::setFillOpacity(qreal opacity) +{ + m_fillOpacitySet = 1; + m_fillOpacity = opacity; +} + +void QSvgFillStyle::setFillStyle(QSvgFillStyleProperty* style) +{ + m_style = style; + m_fillSet = 1; +} + +void QSvgFillStyle::setBrush(QBrush brush) +{ + m_fill = brush; + m_style = 0; + m_fillSet = 1; +} + +void QSvgFillStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &states) +{ + m_oldFill = p->brush(); + m_oldFillRule = states.fillRule; + m_oldFillOpacity = states.fillOpacity; + + if (m_fillRuleSet) + states.fillRule = m_fillRule; + if (m_fillSet) { + if (m_style) + p->setBrush(m_style->brush(p, states)); + else + p->setBrush(m_fill); + } + if (m_fillOpacitySet) + states.fillOpacity = m_fillOpacity; +} + +void QSvgFillStyle::revert(QPainter *p, QSvgExtraStates &states) +{ + if (m_fillOpacitySet) + states.fillOpacity = m_oldFillOpacity; + if (m_fillSet) + p->setBrush(m_oldFill); + if (m_fillRuleSet) + states.fillRule = m_oldFillRule; +} + +QSvgViewportFillStyle::QSvgViewportFillStyle(const QBrush &brush) + : m_viewportFill(brush) +{ +} + +void QSvgViewportFillStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &) +{ + m_oldFill = p->brush(); + p->setBrush(m_viewportFill); +} + +void QSvgViewportFillStyle::revert(QPainter *p, QSvgExtraStates &) +{ + p->setBrush(m_oldFill); +} + +QSvgFontStyle::QSvgFontStyle(QSvgFont *font, QSvgTinyDocument *doc) + : m_svgFont(font) + , m_doc(doc) + , m_familySet(0) + , m_sizeSet(0) + , m_styleSet(0) + , m_variantSet(0) + , m_weightSet(0) + , m_textAnchorSet(0) +{ +} + +QSvgFontStyle::QSvgFontStyle() + : m_svgFont(0) + , m_doc(0) + , m_familySet(0) + , m_sizeSet(0) + , m_styleSet(0) + , m_variantSet(0) + , m_weightSet(0) + , m_textAnchorSet(0) +{ +} + +int QSvgFontStyle::SVGToQtWeight(int weight) { + switch (weight) { + case 100: + case 200: + return QFont::Light; + case 300: + case 400: + return QFont::Normal; + case 500: + case 600: + return QFont::DemiBold; + case 700: + case 800: + return QFont::Bold; + case 900: + return QFont::Black; + } + return QFont::Normal; +} + +void QSvgFontStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &states) +{ + m_oldQFont = p->font(); + m_oldSvgFont = states.svgFont; + m_oldTextAnchor = states.textAnchor; + m_oldWeight = states.fontWeight; + + if (m_textAnchorSet) + states.textAnchor = m_textAnchor; + + QFont font = m_oldQFont; + if (m_familySet) { + states.svgFont = m_svgFont; + font.setFamily(m_qfont.family()); + } + + if (m_sizeSet) + font.setPointSize(m_qfont.pointSizeF()); + + if (m_styleSet) + font.setStyle(m_qfont.style()); + + if (m_variantSet) + font.setCapitalization(m_qfont.capitalization()); + + if (m_weightSet) { + if (m_weight == BOLDER) { + states.fontWeight = qMin(states.fontWeight + 100, 900); + } else if (m_weight == LIGHTER) { + states.fontWeight = qMax(states.fontWeight - 100, 100); + } else { + states.fontWeight = m_weight; + } + font.setWeight(SVGToQtWeight(states.fontWeight)); + } + + p->setFont(font); +} + +void QSvgFontStyle::revert(QPainter *p, QSvgExtraStates &states) +{ + p->setFont(m_oldQFont); + states.svgFont = m_oldSvgFont; + states.textAnchor = m_oldTextAnchor; + states.fontWeight = m_oldWeight; +} + +QSvgStrokeStyle::QSvgStrokeStyle() + : m_strokeOpacity(1.0) + , m_oldStrokeOpacity(0.0) + , m_strokeDashOffset(0) + , m_oldStrokeDashOffset(0) + , m_style(0) + , m_gradientResolved(1) + , m_vectorEffect(0) + , m_oldVectorEffect(0) + , m_strokeSet(0) + , m_strokeDashArraySet(0) + , m_strokeDashOffsetSet(0) + , m_strokeLineCapSet(0) + , m_strokeLineJoinSet(0) + , m_strokeMiterLimitSet(0) + , m_strokeOpacitySet(0) + , m_strokeWidthSet(0) + , m_vectorEffectSet(0) +{ +} + +void QSvgStrokeStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &states) +{ + m_oldStroke = p->pen(); + m_oldStrokeOpacity = states.strokeOpacity; + m_oldStrokeDashOffset = states.strokeDashOffset; + m_oldVectorEffect = states.vectorEffect; + + QPen pen = p->pen(); + + qreal oldWidth = pen.widthF(); + qreal width = m_stroke.widthF(); + if (oldWidth == 0) + oldWidth = 1; + if (width == 0) + width = 1; + qreal scale = oldWidth / width; + + if (m_strokeOpacitySet) + states.strokeOpacity = m_strokeOpacity; + + if (m_vectorEffectSet) + states.vectorEffect = m_vectorEffect; + + if (m_strokeSet) { + if (m_style) + pen.setBrush(m_style->brush(p, states)); + else + pen.setBrush(m_stroke.brush()); + } + + if (m_strokeWidthSet) + pen.setWidthF(m_stroke.widthF()); + + bool setDashOffsetNeeded = false; + + if (m_strokeDashOffsetSet) { + states.strokeDashOffset = m_strokeDashOffset; + setDashOffsetNeeded = true; + } + + if (m_strokeDashArraySet) { + if (m_stroke.style() == Qt::SolidLine) { + pen.setStyle(Qt::SolidLine); + } else if (m_strokeWidthSet || oldWidth == 1) { + // If both width and dash array was set, the dash array is already scaled correctly. + pen.setDashPattern(m_stroke.dashPattern()); + setDashOffsetNeeded = true; + } else { + // If dash array was set, but not the width, the dash array has to be scaled with respect to the old width. + QVector dashes = m_stroke.dashPattern(); + for (int i = 0; i < dashes.size(); ++i) + dashes[i] /= oldWidth; + pen.setDashPattern(dashes); + setDashOffsetNeeded = true; + } + } else if (m_strokeWidthSet && pen.style() != Qt::SolidLine && scale != 1) { + // If the width was set, but not the dash array, the old dash array must be scaled with respect to the new width. + QVector dashes = pen.dashPattern(); + for (int i = 0; i < dashes.size(); ++i) + dashes[i] *= scale; + pen.setDashPattern(dashes); + setDashOffsetNeeded = true; + } + + if (m_strokeLineCapSet) + pen.setCapStyle(m_stroke.capStyle()); + if (m_strokeLineJoinSet) + pen.setJoinStyle(m_stroke.joinStyle()); + if (m_strokeMiterLimitSet) + pen.setMiterLimit(m_stroke.miterLimit()); + + if (setDashOffsetNeeded) { + qreal currentWidth = pen.widthF(); + if (currentWidth == 0) + currentWidth = 1; + pen.setDashOffset(states.strokeDashOffset / currentWidth); + } + + pen.setCosmetic(states.vectorEffect); + + p->setPen(pen); +} + +void QSvgStrokeStyle::revert(QPainter *p, QSvgExtraStates &states) +{ + p->setPen(m_oldStroke); + states.strokeOpacity = m_oldStrokeOpacity; + states.strokeDashOffset = m_oldStrokeDashOffset; + states.vectorEffect = m_oldVectorEffect; +} + +void QSvgStrokeStyle::setDashArray(const QVector &dashes) +{ + if (m_strokeWidthSet) { + QVector d = dashes; + qreal w = m_stroke.widthF(); + if (w != 0 && w != 1) { + for (int i = 0; i < d.size(); ++i) + d[i] /= w; + } + m_stroke.setDashPattern(d); + } else { + m_stroke.setDashPattern(dashes); + } + m_strokeDashArraySet = 1; +} + +QSvgSolidColorStyle::QSvgSolidColorStyle(const QColor &color) + : m_solidColor(color) +{ +} + +QSvgGradientStyle::QSvgGradientStyle(QGradient *grad) + : m_gradient(grad), m_gradientStopsSet(false) +{ +} + +QBrush QSvgGradientStyle::brush(QPainter *, QSvgExtraStates &) +{ + if (!m_link.isEmpty()) { + resolveStops(); + } + + // If the gradient is marked as empty, insert transparent black + if (!m_gradientStopsSet) { + m_gradient->setStops(QGradientStops() << QGradientStop(0.0, QColor(0, 0, 0, 0))); + m_gradientStopsSet = true; + } + + QBrush b(*m_gradient); + + if (!m_matrix.isIdentity()) + b.setMatrix(m_matrix); + + return b; +} + + +void QSvgGradientStyle::setMatrix(const QMatrix &mat) +{ + m_matrix = mat; +} + +QSvgTransformStyle::QSvgTransformStyle(const QTransform &trans) + : m_transform(trans) +{ +} + +void QSvgTransformStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &) +{ + m_oldWorldTransform = p->worldTransform(); + p->setWorldTransform(m_transform, true); +} + +void QSvgTransformStyle::revert(QPainter *p, QSvgExtraStates &) +{ + p->setWorldTransform(m_oldWorldTransform, false /* don't combine */); +} + +QSvgStyleProperty::Type QSvgQualityStyle::type() const +{ + return QUALITY; +} + +QSvgStyleProperty::Type QSvgFillStyle::type() const +{ + return FILL; +} + +QSvgStyleProperty::Type QSvgViewportFillStyle::type() const +{ + return VIEWPORT_FILL; +} + +QSvgStyleProperty::Type QSvgFontStyle::type() const +{ + return FONT; +} + +QSvgStyleProperty::Type QSvgStrokeStyle::type() const +{ + return STROKE; +} + +QSvgStyleProperty::Type QSvgSolidColorStyle::type() const +{ + return SOLID_COLOR; +} + +QSvgStyleProperty::Type QSvgGradientStyle::type() const +{ + return GRADIENT; +} + +QSvgStyleProperty::Type QSvgTransformStyle::type() const +{ + return TRANSFORM; +} + + +QSvgCompOpStyle::QSvgCompOpStyle(QPainter::CompositionMode mode) + : m_mode(mode) +{ + +} + +void QSvgCompOpStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &) +{ + m_oldMode = p->compositionMode(); + p->setCompositionMode(m_mode); +} + +void QSvgCompOpStyle::revert(QPainter *p, QSvgExtraStates &) +{ + p->setCompositionMode(m_oldMode); +} + +QSvgStyleProperty::Type QSvgCompOpStyle::type() const +{ + return COMP_OP; +} + +QSvgStyle::~QSvgStyle() +{ +} + +void QSvgStyle::apply(QPainter *p, const QRectF &rect, QSvgNode *node, QSvgExtraStates &states) +{ + if (quality) { + quality->apply(p, rect, node, states); + } + + if (fill) { + fill->apply(p, rect, node, states); + } + + if (viewportFill) { + viewportFill->apply(p, rect, node, states); + } + + if (font) { + font->apply(p, rect, node, states); + } + + if (stroke) { + stroke->apply(p, rect, node, states); + } + + if (transform) { + transform->apply(p, rect, node, states); + } + + if (animateColor) { + animateColor->apply(p, rect, node, states); + } + + //animated transforms have to be applied + //_after_ the original object transformations + if (!animateTransforms.isEmpty()) { + qreal totalTimeElapsed = node->document()->currentElapsed(); + // Find the last animateTransform with additive="replace", since this will override all + // previous animateTransforms. + QList >::const_iterator itr = animateTransforms.constEnd(); + do { + --itr; + if ((*itr)->animActive(totalTimeElapsed) + && (*itr)->additiveType() == QSvgAnimateTransform::Replace) { + // An animateTransform with additive="replace" will replace the transform attribute. + if (transform) + transform->revert(p, states); + break; + } + } while (itr != animateTransforms.constBegin()); + + // Apply the animateTransforms after and including the last one with additive="replace". + for (; itr != animateTransforms.constEnd(); ++itr) { + if ((*itr)->animActive(totalTimeElapsed)) + (*itr)->apply(p, rect, node, states); + } + } + + if (opacity) { + opacity->apply(p, rect, node, states); + } + + if (compop) { + compop->apply(p, rect, node, states); + } +} + +void QSvgStyle::revert(QPainter *p, QSvgExtraStates &states) +{ + if (quality) { + quality->revert(p, states); + } + + if (fill) { + fill->revert(p, states); + } + + if (viewportFill) { + viewportFill->revert(p, states); + } + + if (font) { + font->revert(p, states); + } + + if (stroke) { + stroke->revert(p, states); + } + + //animated transforms need to be reverted _before_ + //the native transforms + if (!animateTransforms.isEmpty()) { + QList >::const_iterator itr = animateTransforms.constBegin(); + for (; itr != animateTransforms.constEnd(); ++itr) { + if ((*itr)->transformApplied()) { + (*itr)->revert(p, states); + break; + } + } + for (; itr != animateTransforms.constEnd(); ++itr) + (*itr)->clearTransformApplied(); + } + + if (transform) { + transform->revert(p, states); + } + + if (animateColor) { + animateColor->revert(p, states); + } + + if (opacity) { + opacity->revert(p, states); + } + + if (compop) { + compop->revert(p, states); + } +} + +QSvgAnimateTransform::QSvgAnimateTransform(int startMs, int endMs, int byMs ) + : QSvgStyleProperty(), + m_from(startMs), m_to(endMs), m_by(byMs), + m_type(Empty), m_additive(Replace), m_count(0), m_finished(false), m_transformApplied(false) +{ + m_totalRunningTime = m_to - m_from; +} + +void QSvgAnimateTransform::setArgs(TransformType type, Additive additive, const QVector &args) +{ + m_type = type; + m_args = args; + m_additive = additive; + Q_ASSERT(!(args.count()%3)); + m_count = args.count() / 3; +} + +void QSvgAnimateTransform::apply(QPainter *p, const QRectF &, QSvgNode *node, QSvgExtraStates &) +{ + m_oldWorldTransform = p->worldTransform(); + resolveMatrix(node); + p->setWorldTransform(m_transform, true); + m_transformApplied = true; +} + +void QSvgAnimateTransform::revert(QPainter *p, QSvgExtraStates &) +{ + p->setWorldTransform(m_oldWorldTransform, false /* don't combine */); + m_transformApplied = false; +} + +void QSvgAnimateTransform::resolveMatrix(QSvgNode *node) +{ + static const qreal deg2rad = qreal(0.017453292519943295769); + qreal totalTimeElapsed = node->document()->currentElapsed(); + if (totalTimeElapsed < m_from || m_finished) + return; + + qreal animationFrame = 0; + if (m_totalRunningTime != 0) { + animationFrame = (totalTimeElapsed - m_from) / m_totalRunningTime; + + if (m_repeatCount >= 0 && m_repeatCount < animationFrame) { + m_finished = true; + animationFrame = m_repeatCount; + } + } + + qreal percentOfAnimation = animationFrame; + if (percentOfAnimation > 1) { + percentOfAnimation -= ((int)percentOfAnimation); + } + + qreal currentPosition = percentOfAnimation * (m_count - 1); + int startElem = qFloor(currentPosition); + int endElem = qCeil(currentPosition); + + switch(m_type) + { + case Translate: { + startElem *= 3; + endElem *= 3; + qreal from1, from2; + qreal to1, to2; + from1 = m_args[startElem++]; + from2 = m_args[startElem++]; + to1 = m_args[endElem++]; + to2 = m_args[endElem++]; + + qreal transXDiff = (to1-from1) * percentOfAnimation; + qreal transX = from1 + transXDiff; + qreal transYDiff = (to2-from2) * percentOfAnimation; + qreal transY = from2 + transYDiff; + m_transform = QTransform(); + m_transform.translate(transX, transY); + break; + } + case Scale: { + startElem *= 3; + endElem *= 3; + qreal from1, from2; + qreal to1, to2; + from1 = m_args[startElem++]; + from2 = m_args[startElem++]; + to1 = m_args[endElem++]; + to2 = m_args[endElem++]; + + qreal transXDiff = (to1-from1) * percentOfAnimation; + qreal transX = from1 + transXDiff; + qreal transYDiff = (to2-from2) * percentOfAnimation; + qreal transY = from2 + transYDiff; + if (transY == 0) + transY = transX; + m_transform = QTransform(); + m_transform.scale(transX, transY); + break; + } + case Rotate: { + startElem *= 3; + endElem *= 3; + qreal from1, from2, from3; + qreal to1, to2, to3; + from1 = m_args[startElem++]; + from2 = m_args[startElem++]; + from3 = m_args[startElem++]; + to1 = m_args[endElem++]; + to2 = m_args[endElem++]; + to3 = m_args[endElem++]; + + qreal rotationDiff = (to1 - from1) * percentOfAnimation; + //qreal rotation = from1 + rotationDiff; + + qreal transXDiff = (to2-from2) * percentOfAnimation; + qreal transX = from2 + transXDiff; + qreal transYDiff = (to3-from3) * percentOfAnimation; + qreal transY = from3 + transYDiff; + m_transform = QTransform(); + m_transform.translate(transX, transY); + m_transform.rotate(rotationDiff); + m_transform.translate(-transX, -transY); + break; + } + case SkewX: { + startElem *= 3; + endElem *= 3; + qreal from1; + qreal to1; + from1 = m_args[startElem++]; + to1 = m_args[endElem++]; + + qreal transXDiff = (to1-from1) * percentOfAnimation; + qreal transX = from1 + transXDiff; + m_transform = QTransform(); + m_transform.shear(tan(transX * deg2rad), 0); + break; + } + case SkewY: { + startElem *= 3; + endElem *= 3; + qreal from1; + qreal to1; + from1 = m_args[startElem++]; + to1 = m_args[endElem++]; + + + qreal transYDiff = (to1 - from1) * percentOfAnimation; + qreal transY = from1 + transYDiff; + m_transform = QTransform(); + m_transform.shear(0, tan(transY * deg2rad)); + break; + } + default: + break; + } +} + +QSvgStyleProperty::Type QSvgAnimateTransform::type() const +{ + return ANIMATE_TRANSFORM; +} + +void QSvgAnimateTransform::setFreeze(bool freeze) +{ + m_freeze = freeze; +} + +void QSvgAnimateTransform::setRepeatCount(qreal repeatCount) +{ + m_repeatCount = repeatCount; +} + +QSvgAnimateColor::QSvgAnimateColor(int startMs, int endMs, int byMs) + : QSvgStyleProperty(), + m_from(startMs), m_to(endMs), m_by(byMs), + m_finished(false) +{ + m_totalRunningTime = m_to - m_from; +} + +void QSvgAnimateColor::setArgs(bool fill, + const QList &colors) +{ + m_fill = fill; + m_colors = colors; +} + +void QSvgAnimateColor::setFreeze(bool freeze) +{ + m_freeze = freeze; +} + +void QSvgAnimateColor::setRepeatCount(qreal repeatCount) +{ + m_repeatCount = repeatCount; +} + +void QSvgAnimateColor::apply(QPainter *p, const QRectF &, QSvgNode *node, QSvgExtraStates &) +{ + qreal totalTimeElapsed = node->document()->currentElapsed(); + if (totalTimeElapsed < m_from || m_finished) + return; + + qreal animationFrame = 0; + if (m_totalRunningTime != 0) + animationFrame = (totalTimeElapsed - m_from) / m_totalRunningTime; + + if (m_repeatCount >= 0 && m_repeatCount < animationFrame) { + m_finished = true; + animationFrame = m_repeatCount; + } + + qreal percentOfAnimation = animationFrame; + if (percentOfAnimation > 1) { + percentOfAnimation -= ((int)percentOfAnimation); + } + + qreal currentPosition = percentOfAnimation * (m_colors.count() - 1); + + int startElem = qFloor(currentPosition); + int endElem = qCeil(currentPosition); + QColor start = m_colors[startElem]; + QColor end = m_colors[endElem]; + + qreal percentOfColorMorph = currentPosition; + if (percentOfColorMorph > 1) { + percentOfColorMorph -= ((int)percentOfColorMorph); + } + + // Interpolate between the two fixed colors start and end + qreal aDiff = (end.alpha() - start.alpha()) * percentOfColorMorph; + qreal rDiff = (end.red() - start.red()) * percentOfColorMorph; + qreal gDiff = (end.green() - start.green()) * percentOfColorMorph; + qreal bDiff = (end.blue() - start.blue()) * percentOfColorMorph; + + int alpha = int(start.alpha() + aDiff); + int red = int(start.red() + rDiff); + int green = int(start.green() + gDiff); + int blue = int(start.blue() + bDiff); + + QColor color(red, green, blue, alpha); + + if (m_fill) { + QBrush b = p->brush(); + m_oldBrush = b; + b.setColor(color); + p->setBrush(b); + } else { + QPen pen = p->pen(); + m_oldPen = pen; + pen.setColor(color); + p->setPen(pen); + } +} + +void QSvgAnimateColor::revert(QPainter *p, QSvgExtraStates &) +{ + if (m_fill) { + p->setBrush(m_oldBrush); + } else { + p->setPen(m_oldPen); + } +} + +QSvgStyleProperty::Type QSvgAnimateColor::type() const +{ + return ANIMATE_COLOR; +} + +QSvgOpacityStyle::QSvgOpacityStyle(qreal opacity) + : m_opacity(opacity), m_oldOpacity(0) +{ + +} + +void QSvgOpacityStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &) +{ + m_oldOpacity = p->opacity(); + p->setOpacity(m_opacity * m_oldOpacity); +} + +void QSvgOpacityStyle::revert(QPainter *p, QSvgExtraStates &) +{ + p->setOpacity(m_oldOpacity); +} + +QSvgStyleProperty::Type QSvgOpacityStyle::type() const +{ + return OPACITY; +} + +void QSvgGradientStyle::setStopLink(const QString &link, QSvgTinyDocument *doc) +{ + m_link = link; + m_doc = doc; +} + +void QSvgGradientStyle::resolveStops() +{ + if (!m_link.isEmpty() && m_doc) { + QSvgStyleProperty *prop = m_doc->styleProperty(m_link); + if (prop) { + if (prop->type() == QSvgStyleProperty::GRADIENT) { + QSvgGradientStyle *st = + static_cast(prop); + st->resolveStops(); + m_gradient->setStops(st->qgradient()->stops()); + m_gradientStopsSet = st->gradientStopsSet(); + } + } else { + qWarning("Could not resolve property : %s", qPrintable(m_link)); + } + m_link = QString(); + } +} + +QT_END_NAMESPACE + +#endif // QT_NO_SVG