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