9#include "private/qsvganimate_p.h"
21QSvgExtraStates::QSvgExtraStates()
25 textAnchor(Qt::AlignLeft),
26 fontWeight(QFont::Normal),
27 fillRule(Qt::WindingFill),
30 imageRendering(QSvgQualityStyle::ImageRenderingAuto)
34QSvgStyleProperty::~QSvgStyleProperty()
38void QSvgPaintStyleProperty::apply(QPainter *,
const QSvgNode *, QSvgExtraStates &)
40 Q_ASSERT(!
"This should not be called!");
43void QSvgPaintStyleProperty::revert(QPainter *, QSvgExtraStates &)
45 Q_ASSERT(!
"This should not be called!");
49QSvgQualityStyle::QSvgQualityStyle(
int color)
50 : m_imageRendering(QSvgQualityStyle::ImageRenderingAuto)
51 , m_oldImageRendering(QSvgQualityStyle::ImageRenderingAuto)
52 , m_imageRenderingSet(0)
57void QSvgQualityStyle::setImageRendering(ImageRendering hint) {
58 m_imageRendering = hint;
59 m_imageRenderingSet = 1;
62void QSvgQualityStyle::apply(QPainter *p,
const QSvgNode *, QSvgExtraStates &states)
64 m_oldImageRendering = states.imageRendering;
65 if (m_imageRenderingSet) {
66 states.imageRendering = m_imageRendering;
68 if (m_imageRenderingSet) {
70 if (m_imageRendering == ImageRenderingAuto)
74 smooth = (m_imageRendering == ImageRenderingOptimizeQuality);
75 p->setRenderHint(QPainter::SmoothPixmapTransform, smooth);
79void QSvgQualityStyle::revert(QPainter *p, QSvgExtraStates &states)
81 if (m_imageRenderingSet) {
82 states.imageRendering = m_oldImageRendering;
84 if (m_oldImageRendering == ImageRenderingAuto)
87 smooth = (m_oldImageRendering == ImageRenderingOptimizeQuality);
88 p->setRenderHint(QPainter::SmoothPixmapTransform, smooth);
92QSvgFillStyle::QSvgFillStyle()
94 , m_fillRule(Qt::WindingFill)
95 , m_oldFillRule(Qt::WindingFill)
98 , m_paintStyleResolved(1)
100 , m_fillOpacitySet(0)
105void QSvgFillStyle::setFillRule(Qt::FillRule f)
111void QSvgFillStyle::setFillOpacity(qreal opacity)
113 m_fillOpacitySet = 1;
114 m_fillOpacity = opacity;
117void QSvgFillStyle::setFillStyle(QSvgPaintStyleProperty* style)
123void QSvgFillStyle::setBrush(QBrush brush)
125 m_fill = std::move(brush);
130void QSvgFillStyle::apply(QPainter *p,
const QSvgNode *n, QSvgExtraStates &states)
132 m_oldFill = p->brush();
133 m_oldFillRule = states.fillRule;
134 m_oldFillOpacity = states.fillOpacity;
137 states.fillRule = m_fillRule;
140 p->setBrush(m_style->brush(p, n, states));
144 if (m_fillOpacitySet)
145 states.fillOpacity = m_fillOpacity;
148void QSvgFillStyle::revert(QPainter *p, QSvgExtraStates &states)
150 if (m_fillOpacitySet)
151 states.fillOpacity = m_oldFillOpacity;
153 p->setBrush(m_oldFill);
155 states.fillRule = m_oldFillRule;
158QSvgViewportFillStyle::QSvgViewportFillStyle(
const QBrush &brush)
159 : m_viewportFill(brush)
163void QSvgViewportFillStyle::apply(QPainter *p,
const QSvgNode *, QSvgExtraStates &)
165 m_oldFill = p->brush();
166 p->setBrush(m_viewportFill);
169void QSvgViewportFillStyle::revert(QPainter *p, QSvgExtraStates &)
171 p->setBrush(m_oldFill);
174QSvgFontStyle::QSvgFontStyle(QSvgFont *font, QSvgTinyDocument *doc)
186QSvgFontStyle::QSvgFontStyle()
198void QSvgFontStyle::apply(QPainter *p,
const QSvgNode *, QSvgExtraStates &states)
200 m_oldQFont = p->font();
201 m_oldSvgFont = states.svgFont;
202 m_oldTextAnchor = states.textAnchor;
203 m_oldWeight = states.fontWeight;
206 states.textAnchor = m_textAnchor;
208 QFont font = m_oldQFont;
210 states.svgFont = m_svgFont;
211 font.setFamilies(m_qfont.families());
215 font.setPointSizeF(m_qfont.pointSizeF());
218 font.setStyle(m_qfont.style());
221 font.setCapitalization(m_qfont.capitalization());
224 if (m_weight == BOLDER) {
225 states.fontWeight = qMin(states.fontWeight + 100,
static_cast<
int>(QFont::Black));
226 }
else if (m_weight == LIGHTER) {
227 states.fontWeight = qMax(states.fontWeight - 100,
static_cast<
int>(QFont::Thin));
229 states.fontWeight = m_weight;
231 font.setWeight(QFont::Weight(qBound(
static_cast<
int>(QFont::Weight::Thin),
233 static_cast<
int>(QFont::Weight::Black))));
239void QSvgFontStyle::revert(QPainter *p, QSvgExtraStates &states)
241 p->setFont(m_oldQFont);
242 states.svgFont = m_oldSvgFont;
243 states.textAnchor = m_oldTextAnchor;
244 states.fontWeight = m_oldWeight;
247QSvgStrokeStyle::QSvgStrokeStyle()
248 : m_strokeOpacity(1.0)
249 , m_oldStrokeOpacity(0.0)
250 , m_strokeDashOffset(0)
251 , m_oldStrokeDashOffset(0)
253 , m_paintStyleResolved(1)
255 , m_oldVectorEffect(0)
257 , m_strokeDashArraySet(0)
258 , m_strokeDashOffsetSet(0)
259 , m_strokeLineCapSet(0)
260 , m_strokeLineJoinSet(0)
261 , m_strokeMiterLimitSet(0)
262 , m_strokeOpacitySet(0)
263 , m_strokeWidthSet(0)
264 , m_vectorEffectSet(0)
268void QSvgStrokeStyle::apply(QPainter *p,
const QSvgNode *n, QSvgExtraStates &states)
270 m_oldStroke = p->pen();
271 m_oldStrokeOpacity = states.strokeOpacity;
272 m_oldStrokeDashOffset = states.strokeDashOffset;
273 m_oldVectorEffect = states.vectorEffect;
277 qreal oldWidth = pen.widthF();
278 qreal width = m_stroke.widthF();
283 qreal scale = oldWidth / width;
285 if (m_strokeOpacitySet)
286 states.strokeOpacity = m_strokeOpacity;
288 if (m_vectorEffectSet)
289 states.vectorEffect = m_vectorEffect;
293 pen.setBrush(m_style->brush(p, n, states));
295 pen.setBrush(m_stroke.brush());
298 if (m_strokeWidthSet)
299 pen.setWidthF(m_stroke.widthF());
301 bool setDashOffsetNeeded =
false;
303 if (m_strokeDashOffsetSet) {
304 states.strokeDashOffset = m_strokeDashOffset;
305 setDashOffsetNeeded =
true;
308 if (m_strokeDashArraySet) {
309 if (m_stroke.style() == Qt::SolidLine) {
310 pen.setStyle(Qt::SolidLine);
311 }
else if (m_strokeWidthSet || oldWidth == 1) {
313 pen.setDashPattern(m_stroke.dashPattern());
314 setDashOffsetNeeded =
true;
317 QList<qreal> dashes = m_stroke.dashPattern();
318 for (
int i = 0; i < dashes.size(); ++i)
319 dashes[i] /= oldWidth;
320 pen.setDashPattern(dashes);
321 setDashOffsetNeeded =
true;
323 }
else if (m_strokeWidthSet && pen.style() != Qt::SolidLine && scale != 1) {
325 QList<qreal> dashes = pen.dashPattern();
326 for (
int i = 0; i < dashes.size(); ++i)
328 pen.setDashPattern(dashes);
329 setDashOffsetNeeded =
true;
332 if (m_strokeLineCapSet)
333 pen.setCapStyle(m_stroke.capStyle());
334 if (m_strokeLineJoinSet)
335 pen.setJoinStyle(m_stroke.joinStyle());
336 if (m_strokeMiterLimitSet)
337 pen.setMiterLimit(m_stroke.miterLimit());
342 if (setDashOffsetNeeded && pen.style() != Qt::SolidLine) {
343 qreal currentWidth = pen.widthF();
344 if (currentWidth == 0)
346 pen.setDashOffset(states.strokeDashOffset / currentWidth);
349 pen.setCosmetic(states.vectorEffect);
354void QSvgStrokeStyle::revert(QPainter *p, QSvgExtraStates &states)
356 p->setPen(m_oldStroke);
357 states.strokeOpacity = m_oldStrokeOpacity;
358 states.strokeDashOffset = m_oldStrokeDashOffset;
359 states.vectorEffect = m_oldVectorEffect;
362void QSvgStrokeStyle::setDashArray(
const QList<qreal> &dashes)
364 if (m_strokeWidthSet) {
365 QList<qreal> d = dashes;
366 qreal w = m_stroke.widthF();
367 if (w != 0 && w != 1) {
368 for (
int i = 0; i < d.size(); ++i)
371 m_stroke.setDashPattern(d);
373 m_stroke.setDashPattern(dashes);
375 m_strokeDashArraySet = 1;
378QSvgSolidColorStyle::QSvgSolidColorStyle(
const QColor &color)
379 : m_solidColor(color)
383QSvgGradientStyle::QSvgGradientStyle(QGradient *grad)
384 : m_gradient(grad), m_gradientStopsSet(
false)
388QBrush QSvgGradientStyle::brush(QPainter *,
const QSvgNode *, QSvgExtraStates &)
390 if (!m_link.isEmpty()) {
395 if (!m_gradientStopsSet) {
396 m_gradient->setStops(QGradientStops() << QGradientStop(0.0, QColor(0, 0, 0, 0)));
397 m_gradientStopsSet =
true;
400 QBrush b(*m_gradient);
402 if (!m_transform.isIdentity())
403 b.setTransform(m_transform);
409void QSvgGradientStyle::setTransform(
const QTransform &transform)
411 m_transform = transform;
414QSvgPatternStyle::QSvgPatternStyle(QSvgPattern *pattern)
420QBrush QSvgPatternStyle::brush(QPainter *p,
const QSvgNode *node, QSvgExtraStates &states)
422 QBrush b(m_pattern->patternImage(p, states, node));
423 b.setTransform(m_pattern->appliedTransform());
427QSvgTransformStyle::QSvgTransformStyle(
const QTransform &trans)
432void QSvgTransformStyle::apply(QPainter *p,
const QSvgNode *, QSvgExtraStates &)
434 m_oldWorldTransform.push(p->worldTransform());
435 p->setWorldTransform(m_transform,
true);
438void QSvgTransformStyle::revert(QPainter *p, QSvgExtraStates &)
440 p->setWorldTransform(m_oldWorldTransform.pop(),
false );
443QSvgStyleProperty::Type QSvgQualityStyle::type()
const
448QSvgStyleProperty::Type QSvgFillStyle::type()
const
453QSvgStyleProperty::Type QSvgViewportFillStyle::type()
const
455 return VIEWPORT_FILL;
458QSvgStyleProperty::Type QSvgFontStyle::type()
const
463QSvgStyleProperty::Type QSvgStrokeStyle::type()
const
468QSvgStyleProperty::Type QSvgSolidColorStyle::type()
const
473QSvgStyleProperty::Type QSvgGradientStyle::type()
const
478QSvgStyleProperty::Type QSvgPatternStyle::type()
const
483QSvgStyleProperty::Type QSvgTransformStyle::type()
const
489QSvgCompOpStyle::QSvgCompOpStyle(QPainter::CompositionMode mode)
495void QSvgCompOpStyle::apply(QPainter *p,
const QSvgNode *, QSvgExtraStates &)
497 m_oldMode = p->compositionMode();
498 p->setCompositionMode(m_mode);
501void QSvgCompOpStyle::revert(QPainter *p, QSvgExtraStates &)
503 p->setCompositionMode(m_oldMode);
506QSvgStyleProperty::Type QSvgCompOpStyle::type()
const
511QSvgOpacityStyle::QSvgOpacityStyle(qreal opacity)
512 : m_opacity(opacity), m_oldOpacity(0)
517void QSvgOpacityStyle::apply(QPainter *p,
const QSvgNode *, QSvgExtraStates &)
519 m_oldOpacity = p->opacity();
520 p->setOpacity(m_opacity * m_oldOpacity);
523void QSvgOpacityStyle::revert(QPainter *p, QSvgExtraStates &)
525 p->setOpacity(m_oldOpacity);
528QSvgStyleProperty::Type QSvgOpacityStyle::type()
const
533void QSvgGradientStyle::setStopLink(
const QString &link, QSvgTinyDocument *doc)
539void QSvgGradientStyle::resolveStops()
542 resolveStops_helper(&visited);
545void QSvgGradientStyle::resolveStops_helper(QStringList *visited)
547 if (!m_link.isEmpty() && m_doc) {
548 QSvgStyleProperty *prop = m_doc->styleProperty(m_link);
549 if (prop && !visited->contains(m_link)) {
550 visited->append(m_link);
551 if (prop->type() == QSvgStyleProperty::GRADIENT) {
552 QSvgGradientStyle *st =
553 static_cast<QSvgGradientStyle*>(prop);
554 st->resolveStops_helper(visited);
555 m_gradient->setStops(st->qgradient()->stops());
556 m_gradientStopsSet = st->gradientStopsSet();
559 qWarning(
"Could not resolve property : %s",
qPrintable(m_link));
565QSvgStaticStyle::QSvgStaticStyle()
580QSvgStaticStyle::~QSvgStaticStyle()
584void QSvgStaticStyle::apply(QPainter *p,
const QSvgNode *node, QSvgExtraStates &states)
587 quality->apply(p, node, states);
591 fill->apply(p, node, states);
595 viewportFill->apply(p, node, states);
599 font->apply(p, node, states);
603 stroke->apply(p, node, states);
607 transform->apply(p, node, states);
611 opacity->apply(p, node, states);
615 compop->apply(p, node, states);
619void QSvgStaticStyle::revert(QPainter *p, QSvgExtraStates &states)
622 quality->revert(p, states);
626 fill->revert(p, states);
630 viewportFill->revert(p, states);
634 font->revert(p, states);
638 stroke->revert(p, states);
642 transform->revert(p, states);
646 opacity->revert(p, states);
650 compop->revert(p, states);
656QColor sumValue(
const QColor &c1,
const QColor &c2)
658 QRgb rgb1 = c1.rgba();
659 QRgb rgb2 = c2.rgba();
660 int sumRed = qRed(rgb1) + qRed(rgb2);
661 int sumGreen = qGreen(rgb1) + qGreen(rgb2);
662 int sumBlue = qBlue(rgb1) + qBlue(rgb2);
664 QRgb sumRgb = qRgba(qBound(0, sumRed, 255),
665 qBound(0, sumGreen, 255),
666 qBound(0, sumBlue, 255),
669 return QColor(sumRgb);
672qreal sumValue(qreal value1, qreal value2)
674 qreal sumValue = value1 + value2;
675 return qBound(0.0, sumValue, 1.0);
680QSvgAnimatedStyle::QSvgAnimatedStyle()
684QSvgAnimatedStyle::~QSvgAnimatedStyle()
688void QSvgAnimatedStyle::apply(QPainter *p,
const QSvgNode *node, QSvgExtraStates &states)
690 QSharedPointer<QSvgAbstractAnimator> animator = node->document()->animator();
691 QList<QSvgAbstractAnimation *> nodeAnims = animator->animationsForNode(node);
693 savePaintingState(p, node, states);
694 if (nodeAnims.isEmpty())
697 for (
auto anim : nodeAnims) {
698 if (!anim->isActive())
701 bool replace = anim->animationType() == QSvgAbstractAnimation::CSS ?
true :
702 (
static_cast<QSvgAnimateNode *>(anim))->additiveType() == QSvgAnimateNode::Replace;
703 QList<QSvgAbstractAnimatedProperty *> props = anim->properties();
704 for (
auto prop : props)
705 applyPropertyAnimation(p, prop, replace, states);
709void QSvgAnimatedStyle::revert(QPainter *p, QSvgExtraStates &states)
711 p->setWorldTransform(m_worldTransform,
false);
712 p->setBrush(m_brush);
714 p->setOpacity(m_opacity);
715 states.fillOpacity = m_fillOpacity;
716 states.strokeOpacity = m_strokeOpacity;
719void QSvgAnimatedStyle::savePaintingState(
const QPainter *p,
const QSvgNode *node, QSvgExtraStates &states)
721 QSvgStaticStyle style = node->style();
722 m_worldTransform = m_transformToNode = p->worldTransform();
724 m_transformToNode = style.transform->qtransform().inverted() * m_transformToNode;
726 m_brush = p->brush();
728 m_fillOpacity = states.fillOpacity;
729 m_strokeOpacity = states.strokeOpacity;
730 m_opacity = p->opacity();
733void QSvgAnimatedStyle::applyPropertyAnimation(QPainter *p, QSvgAbstractAnimatedProperty *property,
734 bool replace, QSvgExtraStates &states)
737 QBrush brush = p->brush();
738 QColor brushColor = brush.color();
739 QColor animatedColor = property->interpolatedValue().value<QColor>();
740 QColor sumOrReplaceColor = replace ? animatedColor : sumValue(brushColor, animatedColor);
741 brush.setColor(sumOrReplaceColor);
743 }
else if (property->propertyName() ==
QStringLiteral(
"stroke")) {
745 QBrush penBrush = pen.brush();
746 QColor penColor = penBrush.color();
747 QColor animatedColor = property->interpolatedValue().value<QColor>();
748 QColor sumOrReplaceColor = replace ? animatedColor : sumValue(penColor, animatedColor);
749 penBrush.setColor(sumOrReplaceColor);
750 penBrush.setStyle(Qt::SolidPattern);
751 pen.setBrush(penBrush);
753 }
else if (property->propertyName() ==
QStringLiteral(
"transform")) {
754 QTransform animatedTransform = property->interpolatedValue().value<QTransform>();
755 QTransform sumOrReplaceTransform = replace ? animatedTransform * m_transformToNode :
756 animatedTransform * p->worldTransform();
757 p->setWorldTransform(sumOrReplaceTransform);
758 }
else if (property->propertyName() ==
QStringLiteral(
"fill-opacity")) {
759 qreal animatedFillOpacity = property->interpolatedValue().value<qreal>();
760 qreal sumOrReplaceOpacity = replace ? animatedFillOpacity : sumValue(m_fillOpacity, animatedFillOpacity);
761 states.fillOpacity = sumOrReplaceOpacity;
762 }
else if (property->propertyName() ==
QStringLiteral(
"stroke-opacity")) {
763 qreal animatedStrokeOpacity = property->interpolatedValue().value<qreal>();
764 qreal sumOrReplaceOpacity = replace ? animatedStrokeOpacity : sumValue(m_strokeOpacity, animatedStrokeOpacity);
765 states.strokeOpacity = sumOrReplaceOpacity;
766 }
else if (property->propertyName() ==
QStringLiteral(
"opacity")) {
767 qreal animatedOpacity = property->interpolatedValue().value<qreal>();
768 qreal sumOrReplaceOpacity = replace ? animatedOpacity : sumValue(m_opacity, animatedOpacity);
769 p->setOpacity(sumOrReplaceOpacity);
#define qPrintable(string)
#define QStringLiteral(str)