1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qsvgstyle_p.h"
5
6#include "qsvgfont_p.h"
7#include "qsvggraphics_p.h"
8#include "qsvgnode_p.h"
9#include "private/qsvganimate_p.h"
10#include "qsvgtinydocument_p.h"
11
12#include "qpainter.h"
13#include "qpair.h"
14#include "qcolor.h"
15#include "qdebug.h"
16#include "qmath.h"
17#include "qnumeric.h"
18
19QT_BEGIN_NAMESPACE
20
21QSvgExtraStates::QSvgExtraStates()
22 : fillOpacity(1.0),
23 strokeOpacity(1.0),
24 svgFont(0),
25 textAnchor(Qt::AlignLeft),
26 fontWeight(QFont::Normal),
27 fillRule(Qt::WindingFill),
28 strokeDashOffset(0),
29 vectorEffect(false),
30 imageRendering(QSvgQualityStyle::ImageRenderingAuto)
31{
32}
33
34QSvgStyleProperty::~QSvgStyleProperty()
35{
36}
37
38void QSvgPaintStyleProperty::apply(QPainter *, const QSvgNode *, QSvgExtraStates &)
39{
40 Q_ASSERT(!"This should not be called!");
41}
42
43void QSvgPaintStyleProperty::revert(QPainter *, QSvgExtraStates &)
44{
45 Q_ASSERT(!"This should not be called!");
46}
47
48
49QSvgQualityStyle::QSvgQualityStyle(int color)
50 : m_imageRendering(QSvgQualityStyle::ImageRenderingAuto)
51 , m_oldImageRendering(QSvgQualityStyle::ImageRenderingAuto)
52 , m_imageRenderingSet(0)
53{
54 Q_UNUSED(color);
55}
56
57void QSvgQualityStyle::setImageRendering(ImageRendering hint) {
58 m_imageRendering = hint;
59 m_imageRenderingSet = 1;
60}
61
62void QSvgQualityStyle::apply(QPainter *p, const QSvgNode *, QSvgExtraStates &states)
63{
64 m_oldImageRendering = states.imageRendering;
65 if (m_imageRenderingSet) {
66 states.imageRendering = m_imageRendering;
67 }
68 if (m_imageRenderingSet) {
69 bool smooth = false;
70 if (m_imageRendering == ImageRenderingAuto)
71 // auto (the spec says to prefer quality)
72 smooth = true;
73 else
74 smooth = (m_imageRendering == ImageRenderingOptimizeQuality);
75 p->setRenderHint(hint: QPainter::SmoothPixmapTransform, on: smooth);
76 }
77}
78
79void QSvgQualityStyle::revert(QPainter *p, QSvgExtraStates &states)
80{
81 if (m_imageRenderingSet) {
82 states.imageRendering = m_oldImageRendering;
83 bool smooth = false;
84 if (m_oldImageRendering == ImageRenderingAuto)
85 smooth = true;
86 else
87 smooth = (m_oldImageRendering == ImageRenderingOptimizeQuality);
88 p->setRenderHint(hint: QPainter::SmoothPixmapTransform, on: smooth);
89 }
90}
91
92QSvgFillStyle::QSvgFillStyle()
93 : m_style(0)
94 , m_fillRule(Qt::WindingFill)
95 , m_oldFillRule(Qt::WindingFill)
96 , m_fillOpacity(1.0)
97 , m_oldFillOpacity(0)
98 , m_paintStyleResolved(1)
99 , m_fillRuleSet(0)
100 , m_fillOpacitySet(0)
101 , m_fillSet(0)
102{
103}
104
105void QSvgFillStyle::setFillRule(Qt::FillRule f)
106{
107 m_fillRuleSet = 1;
108 m_fillRule = f;
109}
110
111void QSvgFillStyle::setFillOpacity(qreal opacity)
112{
113 m_fillOpacitySet = 1;
114 m_fillOpacity = opacity;
115}
116
117void QSvgFillStyle::setFillStyle(QSvgPaintStyleProperty* style)
118{
119 m_style = style;
120 m_fillSet = 1;
121}
122
123void QSvgFillStyle::setBrush(QBrush brush)
124{
125 m_fill = std::move(brush);
126 m_style = nullptr;
127 m_fillSet = 1;
128}
129
130void QSvgFillStyle::apply(QPainter *p, const QSvgNode *n, QSvgExtraStates &states)
131{
132 m_oldFill = p->brush();
133 m_oldFillRule = states.fillRule;
134 m_oldFillOpacity = states.fillOpacity;
135
136 if (m_fillRuleSet)
137 states.fillRule = m_fillRule;
138 if (m_fillSet) {
139 if (m_style)
140 p->setBrush(m_style->brush(p, node: n, states));
141 else
142 p->setBrush(m_fill);
143 }
144 if (m_fillOpacitySet)
145 states.fillOpacity = m_fillOpacity;
146}
147
148void QSvgFillStyle::revert(QPainter *p, QSvgExtraStates &states)
149{
150 if (m_fillOpacitySet)
151 states.fillOpacity = m_oldFillOpacity;
152 if (m_fillSet)
153 p->setBrush(m_oldFill);
154 if (m_fillRuleSet)
155 states.fillRule = m_oldFillRule;
156}
157
158QSvgViewportFillStyle::QSvgViewportFillStyle(const QBrush &brush)
159 : m_viewportFill(brush)
160{
161}
162
163void QSvgViewportFillStyle::apply(QPainter *p, const QSvgNode *, QSvgExtraStates &)
164{
165 m_oldFill = p->brush();
166 p->setBrush(m_viewportFill);
167}
168
169void QSvgViewportFillStyle::revert(QPainter *p, QSvgExtraStates &)
170{
171 p->setBrush(m_oldFill);
172}
173
174QSvgFontStyle::QSvgFontStyle(QSvgFont *font, QSvgTinyDocument *doc)
175 : m_svgFont(font)
176 , m_doc(doc)
177 , m_familySet(0)
178 , m_sizeSet(0)
179 , m_styleSet(0)
180 , m_variantSet(0)
181 , m_weightSet(0)
182 , m_textAnchorSet(0)
183{
184}
185
186QSvgFontStyle::QSvgFontStyle()
187 : m_svgFont(0)
188 , m_doc(0)
189 , m_familySet(0)
190 , m_sizeSet(0)
191 , m_styleSet(0)
192 , m_variantSet(0)
193 , m_weightSet(0)
194 , m_textAnchorSet(0)
195{
196}
197
198void QSvgFontStyle::apply(QPainter *p, const QSvgNode *, QSvgExtraStates &states)
199{
200 m_oldQFont = p->font();
201 m_oldSvgFont = states.svgFont;
202 m_oldTextAnchor = states.textAnchor;
203 m_oldWeight = states.fontWeight;
204
205 if (m_textAnchorSet)
206 states.textAnchor = m_textAnchor;
207
208 QFont font = m_oldQFont;
209 if (m_familySet) {
210 states.svgFont = m_svgFont;
211 font.setFamilies(m_qfont.families());
212 }
213
214 if (m_sizeSet)
215 font.setPointSizeF(m_qfont.pointSizeF());
216
217 if (m_styleSet)
218 font.setStyle(m_qfont.style());
219
220 if (m_variantSet)
221 font.setCapitalization(m_qfont.capitalization());
222
223 if (m_weightSet) {
224 if (m_weight == BOLDER) {
225 states.fontWeight = qMin(a: states.fontWeight + 100, b: static_cast<int>(QFont::Black));
226 } else if (m_weight == LIGHTER) {
227 states.fontWeight = qMax(a: states.fontWeight - 100, b: static_cast<int>(QFont::Thin));
228 } else {
229 states.fontWeight = m_weight;
230 }
231 font.setWeight(QFont::Weight(qBound(min: static_cast<int>(QFont::Weight::Thin),
232 val: states.fontWeight,
233 max: static_cast<int>(QFont::Weight::Black))));
234 }
235
236 p->setFont(font);
237}
238
239void QSvgFontStyle::revert(QPainter *p, QSvgExtraStates &states)
240{
241 p->setFont(m_oldQFont);
242 states.svgFont = m_oldSvgFont;
243 states.textAnchor = m_oldTextAnchor;
244 states.fontWeight = m_oldWeight;
245}
246
247QSvgStrokeStyle::QSvgStrokeStyle()
248 : m_strokeOpacity(1.0)
249 , m_oldStrokeOpacity(0.0)
250 , m_strokeDashOffset(0)
251 , m_oldStrokeDashOffset(0)
252 , m_style(0)
253 , m_paintStyleResolved(1)
254 , m_vectorEffect(0)
255 , m_oldVectorEffect(0)
256 , m_strokeSet(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)
265{
266}
267
268void QSvgStrokeStyle::apply(QPainter *p, const QSvgNode *n, QSvgExtraStates &states)
269{
270 m_oldStroke = p->pen();
271 m_oldStrokeOpacity = states.strokeOpacity;
272 m_oldStrokeDashOffset = states.strokeDashOffset;
273 m_oldVectorEffect = states.vectorEffect;
274
275 QPen pen = p->pen();
276
277 qreal oldWidth = pen.widthF();
278 qreal width = m_stroke.widthF();
279 if (oldWidth == 0)
280 oldWidth = 1;
281 if (width == 0)
282 width = 1;
283 qreal scale = oldWidth / width;
284
285 if (m_strokeOpacitySet)
286 states.strokeOpacity = m_strokeOpacity;
287
288 if (m_vectorEffectSet)
289 states.vectorEffect = m_vectorEffect;
290
291 if (m_strokeSet) {
292 if (m_style)
293 pen.setBrush(m_style->brush(p, node: n, states));
294 else
295 pen.setBrush(m_stroke.brush());
296 }
297
298 if (m_strokeWidthSet)
299 pen.setWidthF(m_stroke.widthF());
300
301 bool setDashOffsetNeeded = false;
302
303 if (m_strokeDashOffsetSet) {
304 states.strokeDashOffset = m_strokeDashOffset;
305 setDashOffsetNeeded = true;
306 }
307
308 if (m_strokeDashArraySet) {
309 if (m_stroke.style() == Qt::SolidLine) {
310 pen.setStyle(Qt::SolidLine);
311 } else if (m_strokeWidthSet || oldWidth == 1) {
312 // If both width and dash array was set, the dash array is already scaled correctly.
313 pen.setDashPattern(m_stroke.dashPattern());
314 setDashOffsetNeeded = true;
315 } else {
316 // If dash array was set, but not the width, the dash array has to be scaled with respect to the old width.
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;
322 }
323 } else if (m_strokeWidthSet && pen.style() != Qt::SolidLine && scale != 1) {
324 // If the width was set, but not the dash array, the old dash array must be scaled with respect to the new width.
325 QList<qreal> dashes = pen.dashPattern();
326 for (int i = 0; i < dashes.size(); ++i)
327 dashes[i] *= scale;
328 pen.setDashPattern(dashes);
329 setDashOffsetNeeded = true;
330 }
331
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());
338
339 // You can have dash offset on solid strokes in SVG files, but not in Qt.
340 // QPen::setDashOffset() will set the pen style to Qt::CustomDashLine,
341 // so don't call the method if the pen is solid.
342 if (setDashOffsetNeeded && pen.style() != Qt::SolidLine) {
343 qreal currentWidth = pen.widthF();
344 if (currentWidth == 0)
345 currentWidth = 1;
346 pen.setDashOffset(states.strokeDashOffset / currentWidth);
347 }
348
349 pen.setCosmetic(states.vectorEffect);
350
351 p->setPen(pen);
352}
353
354void QSvgStrokeStyle::revert(QPainter *p, QSvgExtraStates &states)
355{
356 p->setPen(m_oldStroke);
357 states.strokeOpacity = m_oldStrokeOpacity;
358 states.strokeDashOffset = m_oldStrokeDashOffset;
359 states.vectorEffect = m_oldVectorEffect;
360}
361
362void QSvgStrokeStyle::setDashArray(const QList<qreal> &dashes)
363{
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)
369 d[i] /= w;
370 }
371 m_stroke.setDashPattern(d);
372 } else {
373 m_stroke.setDashPattern(dashes);
374 }
375 m_strokeDashArraySet = 1;
376}
377
378QSvgSolidColorStyle::QSvgSolidColorStyle(const QColor &color)
379 : m_solidColor(color)
380{
381}
382
383QSvgGradientStyle::QSvgGradientStyle(QGradient *grad)
384 : m_gradient(grad), m_gradientStopsSet(false)
385{
386}
387
388QBrush QSvgGradientStyle::brush(QPainter *, const QSvgNode *, QSvgExtraStates &)
389{
390 if (!m_link.isEmpty()) {
391 resolveStops();
392 }
393
394 // If the gradient is marked as empty, insert transparent black
395 if (!m_gradientStopsSet) {
396 m_gradient->setStops(QGradientStops() << QGradientStop(0.0, QColor(0, 0, 0, 0)));
397 m_gradientStopsSet = true;
398 }
399
400 QBrush b(*m_gradient);
401
402 if (!m_transform.isIdentity())
403 b.setTransform(m_transform);
404
405 return b;
406}
407
408
409void QSvgGradientStyle::setTransform(const QTransform &transform)
410{
411 m_transform = transform;
412}
413
414QSvgPatternStyle::QSvgPatternStyle(QSvgPattern *pattern)
415 : m_pattern(pattern)
416{
417
418}
419
420QBrush QSvgPatternStyle::brush(QPainter *p, const QSvgNode *node, QSvgExtraStates &states)
421{
422 m_patternImage = m_pattern->patternImage(p, states, patternElement: node);
423 QBrush b(m_patternImage);
424 b.setTransform(m_pattern->appliedTransform());
425 return b;
426}
427
428QSvgTransformStyle::QSvgTransformStyle(const QTransform &trans)
429 : m_transform(trans)
430{
431}
432
433void QSvgTransformStyle::apply(QPainter *p, const QSvgNode *, QSvgExtraStates &)
434{
435 m_oldWorldTransform.push(t: p->worldTransform());
436 p->setWorldTransform(matrix: m_transform, combine: true);
437}
438
439void QSvgTransformStyle::revert(QPainter *p, QSvgExtraStates &)
440{
441 p->setWorldTransform(matrix: m_oldWorldTransform.pop(), combine: false /* don't combine */);
442}
443
444QSvgStyleProperty::Type QSvgQualityStyle::type() const
445{
446 return QUALITY;
447}
448
449QSvgStyleProperty::Type QSvgFillStyle::type() const
450{
451 return FILL;
452}
453
454QSvgStyleProperty::Type QSvgViewportFillStyle::type() const
455{
456 return VIEWPORT_FILL;
457}
458
459QSvgStyleProperty::Type QSvgFontStyle::type() const
460{
461 return FONT;
462}
463
464QSvgStyleProperty::Type QSvgStrokeStyle::type() const
465{
466 return STROKE;
467}
468
469QSvgStyleProperty::Type QSvgSolidColorStyle::type() const
470{
471 return SOLID_COLOR;
472}
473
474QSvgStyleProperty::Type QSvgGradientStyle::type() const
475{
476 return GRADIENT;
477}
478
479QSvgStyleProperty::Type QSvgPatternStyle::type() const
480{
481 return PATTERN;
482}
483
484QSvgStyleProperty::Type QSvgTransformStyle::type() const
485{
486 return TRANSFORM;
487}
488
489
490QSvgCompOpStyle::QSvgCompOpStyle(QPainter::CompositionMode mode)
491 : m_mode(mode)
492{
493
494}
495
496void QSvgCompOpStyle::apply(QPainter *p, const QSvgNode *, QSvgExtraStates &)
497{
498 m_oldMode = p->compositionMode();
499 p->setCompositionMode(m_mode);
500}
501
502void QSvgCompOpStyle::revert(QPainter *p, QSvgExtraStates &)
503{
504 p->setCompositionMode(m_oldMode);
505}
506
507QSvgStyleProperty::Type QSvgCompOpStyle::type() const
508{
509 return COMP_OP;
510}
511
512QSvgOpacityStyle::QSvgOpacityStyle(qreal opacity)
513 : m_opacity(opacity), m_oldOpacity(0)
514{
515
516}
517
518void QSvgOpacityStyle::apply(QPainter *p, const QSvgNode *, QSvgExtraStates &)
519{
520 m_oldOpacity = p->opacity();
521 p->setOpacity(m_opacity * m_oldOpacity);
522}
523
524void QSvgOpacityStyle::revert(QPainter *p, QSvgExtraStates &)
525{
526 p->setOpacity(m_oldOpacity);
527}
528
529QSvgStyleProperty::Type QSvgOpacityStyle::type() const
530{
531 return OPACITY;
532}
533
534void QSvgGradientStyle::setStopLink(const QString &link, QSvgTinyDocument *doc)
535{
536 m_link = link;
537 m_doc = doc;
538}
539
540void QSvgGradientStyle::resolveStops()
541{
542 QStringList visited;
543 resolveStops_helper(visited: &visited);
544}
545
546void QSvgGradientStyle::resolveStops_helper(QStringList *visited)
547{
548 if (!m_link.isEmpty() && m_doc) {
549 QSvgStyleProperty *prop = m_doc->styleProperty(id: m_link);
550 if (prop && !visited->contains(str: m_link)) {
551 visited->append(t: m_link);
552 if (prop->type() == QSvgStyleProperty::GRADIENT) {
553 QSvgGradientStyle *st =
554 static_cast<QSvgGradientStyle*>(prop);
555 st->resolveStops_helper(visited);
556 m_gradient->setStops(st->qgradient()->stops());
557 m_gradientStopsSet = st->gradientStopsSet();
558 }
559 } else {
560 qWarning(msg: "Could not resolve property : %s", qPrintable(m_link));
561 }
562 m_link = QString();
563 }
564}
565
566QSvgStaticStyle::QSvgStaticStyle()
567 : quality(0)
568 , fill(0)
569 , viewportFill(0)
570 , font(0)
571 , stroke(0)
572 , solidColor(0)
573 , gradient(0)
574 , pattern(0)
575 , transform(0)
576 , opacity(0)
577 , compop(0)
578{
579}
580
581QSvgStaticStyle::~QSvgStaticStyle()
582{
583}
584
585void QSvgStaticStyle::apply(QPainter *p, const QSvgNode *node, QSvgExtraStates &states)
586{
587 if (quality) {
588 quality->apply(p, node, states);
589 }
590
591 if (fill) {
592 fill->apply(p, n: node, states);
593 }
594
595 if (viewportFill) {
596 viewportFill->apply(p, node, states);
597 }
598
599 if (font) {
600 font->apply(p, node, states);
601 }
602
603 if (stroke) {
604 stroke->apply(p, n: node, states);
605 }
606
607 if (transform) {
608 transform->apply(p, node, states);
609 }
610
611 if (opacity) {
612 opacity->apply(p, node, states);
613 }
614
615 if (compop) {
616 compop->apply(p, node, states);
617 }
618}
619
620void QSvgStaticStyle::revert(QPainter *p, QSvgExtraStates &states)
621{
622 if (quality) {
623 quality->revert(p, states);
624 }
625
626 if (fill) {
627 fill->revert(p, states);
628 }
629
630 if (viewportFill) {
631 viewportFill->revert(p, states);
632 }
633
634 if (font) {
635 font->revert(p, states);
636 }
637
638 if (stroke) {
639 stroke->revert(p, states);
640 }
641
642 if (transform) {
643 transform->revert(p, states);
644 }
645
646 if (opacity) {
647 opacity->revert(p, states);
648 }
649
650 if (compop) {
651 compop->revert(p, states);
652 }
653}
654
655namespace {
656
657QColor sumValue(const QColor &c1, const QColor &c2)
658{
659 QRgb rgb1 = c1.rgba();
660 QRgb rgb2 = c2.rgba();
661 int sumRed = qRed(rgb: rgb1) + qRed(rgb: rgb2);
662 int sumGreen = qGreen(rgb: rgb1) + qGreen(rgb: rgb2);
663 int sumBlue = qBlue(rgb: rgb1) + qBlue(rgb: rgb2);
664
665 QRgb sumRgb = qRgba(r: qBound(min: 0, val: sumRed, max: 255),
666 g: qBound(min: 0, val: sumGreen, max: 255),
667 b: qBound(min: 0, val: sumBlue, max: 255),
668 a: 255);
669
670 return QColor(sumRgb);
671}
672
673qreal sumValue(qreal value1, qreal value2)
674{
675 qreal sumValue = value1 + value2;
676 return qBound(min: 0.0, val: sumValue, max: 1.0);
677}
678
679}
680
681QSvgAnimatedStyle::QSvgAnimatedStyle()
682{
683}
684
685QSvgAnimatedStyle::~QSvgAnimatedStyle()
686{
687}
688
689void QSvgAnimatedStyle::apply(QPainter *p, const QSvgNode *node, QSvgExtraStates &states)
690{
691 QSharedPointer<QSvgAbstractAnimator> animator = node->document()->animator();
692 QList<QSvgAbstractAnimation *> nodeAnims = animator->animationsForNode(node);
693
694 savePaintingState(p, node, states);
695 if (nodeAnims.isEmpty())
696 return;
697
698 for (auto anim : nodeAnims) {
699 if (!anim->isActive())
700 continue;
701
702 bool replace = anim->animationType() == QSvgAbstractAnimation::CSS ? true :
703 (static_cast<QSvgAnimateNode *>(anim))->additiveType() == QSvgAnimateNode::Replace;
704 QList<QSvgAbstractAnimatedProperty *> props = anim->properties();
705 for (auto prop : props)
706 applyPropertyAnimation(p, property: prop, replace, states);
707 }
708}
709
710void QSvgAnimatedStyle::revert(QPainter *p, QSvgExtraStates &states)
711{
712 p->setWorldTransform(matrix: m_worldTransform, combine: false);
713 p->setBrush(m_brush);
714 p->setPen(m_pen);
715 p->setOpacity(m_opacity);
716 states.fillOpacity = m_fillOpacity;
717 states.strokeOpacity = m_strokeOpacity;
718}
719
720void QSvgAnimatedStyle::savePaintingState(const QPainter *p, const QSvgNode *node, QSvgExtraStates &states)
721{
722 QSvgStaticStyle style = node->style();
723 m_worldTransform = m_transformToNode = p->worldTransform();
724 if (style.transform)
725 m_transformToNode = style.transform->qtransform().inverted() * m_transformToNode;
726
727 m_brush = p->brush();
728 m_pen = p->pen();
729 m_fillOpacity = states.fillOpacity;
730 m_strokeOpacity = states.strokeOpacity;
731 m_opacity = p->opacity();
732}
733
734void QSvgAnimatedStyle::applyPropertyAnimation(QPainter *p, QSvgAbstractAnimatedProperty *property,
735 bool replace, QSvgExtraStates &states)
736{
737 if (property->propertyName() == QStringLiteral("fill")) {
738 QBrush brush = p->brush();
739 QColor brushColor = brush.color();
740 QColor animatedColor = property->interpolatedValue().value<QColor>();
741 QColor sumOrReplaceColor = replace ? animatedColor : sumValue(c1: brushColor, c2: animatedColor);
742 brush.setColor(sumOrReplaceColor);
743 p->setBrush(brush);
744 } else if (property->propertyName() == QStringLiteral("stroke")) {
745 QPen pen = p->pen();
746 QBrush penBrush = pen.brush();
747 QColor penColor = penBrush.color();
748 QColor animatedColor = property->interpolatedValue().value<QColor>();
749 QColor sumOrReplaceColor = replace ? animatedColor : sumValue(c1: penColor, c2: animatedColor);
750 penBrush.setColor(sumOrReplaceColor);
751 penBrush.setStyle(Qt::SolidPattern);
752 pen.setBrush(penBrush);
753 p->setPen(pen);
754 } else if (property->propertyName() == QStringLiteral("transform")) {
755 QTransform animatedTransform = property->interpolatedValue().value<QTransform>();
756 QTransform sumOrReplaceTransform = replace ? animatedTransform * m_transformToNode :
757 animatedTransform * p->worldTransform();
758 p->setWorldTransform(matrix: sumOrReplaceTransform);
759 } else if (property->propertyName() == QStringLiteral("fill-opacity")) {
760 qreal animatedFillOpacity = property->interpolatedValue().value<qreal>();
761 qreal sumOrReplaceOpacity = replace ? animatedFillOpacity : sumValue(value1: m_fillOpacity, value2: animatedFillOpacity);
762 states.fillOpacity = sumOrReplaceOpacity;
763 } else if (property->propertyName() == QStringLiteral("stroke-opacity")) {
764 qreal animatedStrokeOpacity = property->interpolatedValue().value<qreal>();
765 qreal sumOrReplaceOpacity = replace ? animatedStrokeOpacity : sumValue(value1: m_strokeOpacity, value2: animatedStrokeOpacity);
766 states.strokeOpacity = sumOrReplaceOpacity;
767 } else if (property->propertyName() == QStringLiteral("opacity")) {
768 qreal animatedOpacity = property->interpolatedValue().value<qreal>();
769 qreal sumOrReplaceOpacity = replace ? animatedOpacity : sumValue(value1: m_opacity, value2: animatedOpacity);
770 p->setOpacity(sumOrReplaceOpacity);
771 }
772}
773
774QT_END_NAMESPACE
775

source code of qtsvg/src/svg/qsvgstyle.cpp