summaryrefslogtreecommitdiffstats
path: root/src/svg/qsvgstyle.cpp
diff options
context:
space:
mode:
authorKim Motoyoshi Kalland <kim.kalland@nokia.com>2009-08-21 15:44:57 (GMT)
committerKim Motoyoshi Kalland <kim.kalland@nokia.com>2009-08-24 12:05:13 (GMT)
commit5c9206d8290232e8adc1a6cdb992a7c19d67269a (patch)
tree2f93f9581d5a41e37b37d54a675c07088d237bb1 /src/svg/qsvgstyle.cpp
parentfdf2a161b59de9e0a6fd059b1d6ba6407f768a25 (diff)
downloadQt-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.cpp284
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;