diff options
author | Kim Motoyoshi Kalland <kim.kalland@nokia.com> | 2009-08-21 15:44:57 (GMT) |
---|---|---|
committer | Kim Motoyoshi Kalland <kim.kalland@nokia.com> | 2009-08-24 12:05:13 (GMT) |
commit | 5c9206d8290232e8adc1a6cdb992a7c19d67269a (patch) | |
tree | 2f93f9581d5a41e37b37d54a675c07088d237bb1 /src/svg/qsvgstyle.cpp | |
parent | fdf2a161b59de9e0a6fd059b1d6ba6407f768a25 (diff) | |
download | Qt-5c9206d8290232e8adc1a6cdb992a7c19d67269a.zip Qt-5c9206d8290232e8adc1a6cdb992a7c19d67269a.tar.gz Qt-5c9206d8290232e8adc1a6cdb992a7c19d67269a.tar.bz2 |
Fixed SVG stroke attributes to work with 'use' tags.
In the process of rewriting the stroke handling code, I also fixed
gradients on strokes.
Task-number: 202426, 250618
Reviewed-by: Trond
Diffstat (limited to 'src/svg/qsvgstyle.cpp')
-rw-r--r-- | src/svg/qsvgstyle.cpp | 284 |
1 files changed, 159 insertions, 125 deletions
diff --git a/src/svg/qsvgstyle.cpp b/src/svg/qsvgstyle.cpp index ef63443..6922ad9 100644 --- a/src/svg/qsvgstyle.cpp +++ b/src/svg/qsvgstyle.cpp @@ -59,9 +59,13 @@ 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) { } @@ -69,6 +73,17 @@ 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) { @@ -83,83 +98,55 @@ void QSvgQualityStyle::revert(QPainter *, QSvgExtraStates &) } -QSvgFillStyle::QSvgFillStyle(const QBrush &brush) - : m_fill(brush) - , m_style(0) - , m_fillRuleSet(false) - , m_fillRule(Qt::WindingFill) - , m_fillOpacitySet(false) - , m_fillOpacity(1.0) - , m_oldOpacity(0) - , m_gradientResolved(true) - , m_fillSet(true) -{ -} - -QSvgFillStyle::QSvgFillStyle(QSvgStyleProperty *style) - : m_style(style) - , m_fillRuleSet(false) +QSvgFillStyle::QSvgFillStyle() + : m_style(0) , m_fillRule(Qt::WindingFill) - , m_fillOpacitySet(false) + , m_oldFillRule(Qt::WindingFill) , m_fillOpacity(1.0) - , m_oldOpacity(0) - , m_gradientResolved(true) - , m_fillSet(style != 0) + , m_oldFillOpacity(0) + , m_gradientResolved(1) + , m_fillRuleSet(0) + , m_fillOpacitySet(0) + , m_fillSet(0) { } void QSvgFillStyle::setFillRule(Qt::FillRule f) { - m_fillRuleSet = true; + m_fillRuleSet = 1; m_fillRule = f; } void QSvgFillStyle::setFillOpacity(qreal opacity) { - m_fillOpacitySet = true; + m_fillOpacitySet = 1; m_fillOpacity = opacity; } -void QSvgFillStyle::setFillStyle(QSvgStyleProperty* style) +void QSvgFillStyle::setFillStyle(QSvgFillStyleProperty* style) { m_style = style; - m_fillSet = true; + m_fillSet = 1; } void QSvgFillStyle::setBrush(QBrush brush) { m_fill = brush; m_style = 0; - m_fillSet = true; + m_fillSet = 1; } -static void recursivelySetFill(QSvgNode *node, Qt::FillRule f) -{ - if (node->type() == QSvgNode::PATH) { - QSvgPath *path = static_cast<QSvgPath*>(node); - path->qpath()->setFillRule(f); - } else if (node->type() == QSvgNode::POLYGON) { - QSvgPolygon *polygon = static_cast<QSvgPolygon*>(node); - polygon->setFillRule(f); - } else if (node->type() == QSvgNode::G) { - QList<QSvgNode*> renderers = static_cast<QSvgG*>(node)->renderers(); - foreach(QSvgNode *n, renderers) { - recursivelySetFill(n, f); - } - } -} -void QSvgFillStyle::apply(QPainter *p, const QRectF &rect, QSvgNode *node, QSvgExtraStates &states) +void QSvgFillStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &states) { m_oldFill = p->brush(); - m_oldOpacity = states.fillOpacity; + m_oldFillRule = states.fillRule; + m_oldFillOpacity = states.fillOpacity; - if (m_fillRuleSet) { - recursivelySetFill(node, m_fillRule); - m_fillRuleSet = false;//set it only on the first run - } + if (m_fillRuleSet) + states.fillRule = m_fillRule; if (m_fillSet) { if (m_style) - m_style->apply(p, rect, node, states); + p->setBrush(m_style->brush(p, states)); else p->setBrush(m_fill); } @@ -170,13 +157,11 @@ void QSvgFillStyle::apply(QPainter *p, const QRectF &rect, QSvgNode *node, QSvgE void QSvgFillStyle::revert(QPainter *p, QSvgExtraStates &states) { if (m_fillOpacitySet) - states.fillOpacity = m_oldOpacity; - if (m_fillSet) { - if (m_style) - m_style->revert(p, states); - else - p->setBrush(m_oldFill); - } + states.fillOpacity = m_oldFillOpacity; + if (m_fillSet) + p->setBrush(m_oldFill); + if (m_fillRuleSet) + states.fillRule = m_oldFillRule; } QSvgViewportFillStyle::QSvgViewportFillStyle(const QBrush &brush) @@ -286,47 +271,135 @@ void QSvgFontStyle::revert(QPainter *p, QSvgExtraStates &states) states.fontWeight = m_oldWeight; } -QSvgStrokeStyle::QSvgStrokeStyle(const QPen &pen) - : m_stroke(pen), m_strokePresent(true) +QSvgStrokeStyle::QSvgStrokeStyle() + : m_strokeOpacity(1.0) + , m_oldStrokeOpacity(0.0) + , m_vectorEffect(0) + , m_oldVectorEffect(0) + , m_strokeDashOffset(0) + , m_oldStrokeDashOffset(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 &) +void QSvgStrokeStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &states) { m_oldStroke = p->pen(); - if (!m_strokePresent || !m_stroke.widthF() || !m_stroke.color().alphaF()) { - p->setPen(Qt::NoPen); - } else { - p->setPen(m_stroke); + 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()); } -} -void QSvgStrokeStyle::revert(QPainter *p, QSvgExtraStates &) -{ - p->setPen(m_oldStroke); + 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()); + + if (setDashOffsetNeeded) { + qreal currentWidth = pen.widthF(); + if (currentWidth == 0) + currentWidth = 1; + pen.setDashOffset(states.strokeDashOffset / currentWidth); + } + + pen.setCosmetic(states.vectorEffect); + + p->setPen(pen); } -QSvgSolidColorStyle::QSvgSolidColorStyle(const QColor &color) - : m_solidColor(color) +void QSvgStrokeStyle::revert(QPainter *p, QSvgExtraStates &states) { + p->setPen(m_oldStroke); + states.strokeOpacity = m_oldStrokeOpacity; + states.strokeDashOffset = m_oldStrokeDashOffset; + states.vectorEffect = m_oldVectorEffect; } -void QSvgSolidColorStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &) +void QSvgStrokeStyle::setDashArray(const QVector<qreal> &dashes) { - m_oldFill = p->brush(); - m_oldStroke = p->pen(); - QBrush b = m_oldFill; - b.setColor(m_solidColor); - p->setBrush(b); - QPen pen = m_oldStroke; - pen.setColor(m_solidColor); - p->setPen(pen); + 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; } -void QSvgSolidColorStyle::revert(QPainter *p, QSvgExtraStates &) +QSvgSolidColorStyle::QSvgSolidColorStyle(const QColor &color) + : m_solidColor(color) { - p->setBrush(m_oldFill); - p->setPen(m_oldStroke); } QSvgGradientStyle::QSvgGradientStyle(QGradient *grad) @@ -334,44 +407,24 @@ QSvgGradientStyle::QSvgGradientStyle(QGradient *grad) { } -void QSvgGradientStyle::apply(QPainter *p, const QRectF &/*rect*/, QSvgNode *, QSvgExtraStates &) +QBrush QSvgGradientStyle::brush(QPainter *, QSvgExtraStates &) { if (!m_link.isEmpty()) { resolveStops(); } - m_oldFill = p->brush(); - - //resolving stop colors - if (!m_resolvePoints.isEmpty()) { - QColor color = p->brush().color(); - if (!color.isValid()) - color = p->pen().color(); - QList<qreal>::const_iterator itr = m_resolvePoints.constBegin(); - for (; itr != m_resolvePoints.constEnd(); ++itr) { - //qDebug()<<"resolving "<<(*itr)<<" to "<<color; - m_gradient->setColorAt(*itr, color); - } - } - // 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 brush; - brush = QBrush(*m_gradient); + QBrush b(*m_gradient); if (!m_matrix.isIdentity()) - brush.setMatrix(m_matrix); - - p->setBrush(brush); -} + b.setMatrix(m_matrix); -void QSvgGradientStyle::revert(QPainter *p, QSvgExtraStates &) -{ - p->setBrush(m_oldFill); + return b; } @@ -380,11 +433,6 @@ void QSvgGradientStyle::setMatrix(const QMatrix &mat) m_matrix = mat; } -void QSvgGradientStyle::addResolve(qreal offset) -{ - m_resolvePoints.append(offset); -} - QSvgTransformStyle::QSvgTransformStyle(const QTransform &trans) : m_transform(trans) { @@ -490,14 +538,6 @@ void QSvgStyle::apply(QPainter *p, const QRectF &rect, QSvgNode *node, QSvgExtra stroke->apply(p, rect, node, states); } - if (solidColor) { - solidColor->apply(p, rect, node, states); - } - - if (gradient) { - gradient->apply(p, rect, node, states); - } - if (transform) { transform->apply(p, rect, node, states); } @@ -562,14 +602,6 @@ void QSvgStyle::revert(QPainter *p, QSvgExtraStates &states) stroke->revert(p, states); } - if (solidColor) { - solidColor->revert(p, states); - } - - if (gradient) { - gradient->revert(p, states); - } - //animated transforms need to be reverted _before_ //the native transforms if (!animateTransforms.isEmpty()) { @@ -815,7 +847,9 @@ void QSvgAnimateColor::apply(QPainter *p, const QRectF &, QSvgNode *node, QSvgEx if (totalTimeElapsed < m_from || m_finished) return; - qreal animationFrame = (totalTimeElapsed - m_from) / m_to; + qreal animationFrame = 0; + if (m_totalRunningTime != 0) + animationFrame = (totalTimeElapsed - m_from) / m_totalRunningTime; if (m_repeatCount >= 0 && m_repeatCount < animationFrame) { m_finished = true; |