blob: 924cca075ed1b153c6380fd1783cb1631a6ec57e [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt SVG module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qsvgstyle_p.h"
#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 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)
{
Q_UNUSED(color);
}
void QSvgQualityStyle::apply(QPainter *, const 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 = std::move(brush);
m_style = 0;
m_fillSet = 1;
}
void QSvgFillStyle::apply(QPainter *p, const 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 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 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.setFamilies(m_qfont.families());
}
if (m_sizeSet)
font.setPointSizeF(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 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<qreal> 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<qreal> 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());
// You can have dash offset on solid strokes in SVG files, but not in Qt.
// QPen::setDashOffset() will set the pen style to Qt::CustomDashLine,
// so don't call the method if the pen is solid.
if (setDashOffsetNeeded && pen.style() != Qt::SolidLine) {
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<qreal> &dashes)
{
if (m_strokeWidthSet) {
QVector<qreal> 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_transform.isIdentity())
b.setTransform(m_transform);
return b;
}
void QSvgGradientStyle::setTransform(const QTransform &transform)
{
m_transform = transform;
}
QSvgTransformStyle::QSvgTransformStyle(const QTransform &trans)
: m_transform(trans)
{
}
void QSvgTransformStyle::apply(QPainter *p, const 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 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 QSvgNode *node, QSvgExtraStates &states)
{
if (quality) {
quality->apply(p, node, states);
}
if (fill) {
fill->apply(p, node, states);
}
if (viewportFill) {
viewportFill->apply(p, node, states);
}
if (font) {
font->apply(p, node, states);
}
if (stroke) {
stroke->apply(p, node, states);
}
if (transform) {
transform->apply(p, node, states);
}
if (animateColor) {
animateColor->apply(p, 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<QSvgRefCounter<QSvgAnimateTransform> >::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, node, states);
}
}
if (opacity) {
opacity->apply(p, node, states);
}
if (compop) {
compop->apply(p, 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<QSvgRefCounter<QSvgAnimateTransform> >::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_totalRunningTime(endMs - startMs),
m_type(Empty),
m_additive(Replace),
m_count(0),
m_finished(false),
m_freeze(false),
m_repeatCount(-1.),
m_transformApplied(false)
{
Q_UNUSED(byMs);
}
void QSvgAnimateTransform::setArgs(TransformType type, Additive additive, const QVector<qreal> &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 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(const 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 endElem = qCeil(currentPosition);
int startElem = qMax(endElem - 1, 0);
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(qTan(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, qTan(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_totalRunningTime(endMs - startMs),
m_fill(false),
m_finished(false),
m_freeze(false),
m_repeatCount(-1.)
{
Q_UNUSED(byMs);
}
void QSvgAnimateColor::setArgs(bool fill,
const QList<QColor> &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 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 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()
{
QStringList visited;
resolveStops_helper(&visited);
}
void QSvgGradientStyle::resolveStops_helper(QStringList *visited)
{
if (!m_link.isEmpty() && m_doc) {
QSvgStyleProperty *prop = m_doc->styleProperty(m_link);
if (prop && !visited->contains(m_link)) {
visited->append(m_link);
if (prop->type() == QSvgStyleProperty::GRADIENT) {
QSvgGradientStyle *st =
static_cast<QSvgGradientStyle*>(prop);
st->resolveStops_helper(visited);
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