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
4#include "qsvgstyle_p.h"
5
6#include "qsvgfont_p.h"
8#include "qsvgnode_p.h"
9#include "private/qsvganimate_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
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(QPainter::SmoothPixmapTransform, 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(QPainter::SmoothPixmapTransform, 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, 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(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));
228 } else {
229 states.fontWeight = m_weight;
230 }
231 font.setWeight(QFont::Weight(qBound(static_cast<int>(QFont::Weight::Thin),
232 states.fontWeight,
233 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, 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 QBrush b(m_pattern->patternImage(p, states, node));
423 b.setTransform(m_pattern->appliedTransform());
424 return b;
425}
426
427QSvgTransformStyle::QSvgTransformStyle(const QTransform &trans)
428 : m_transform(trans)
429{
430}
431
432void QSvgTransformStyle::apply(QPainter *p, const QSvgNode *, QSvgExtraStates &)
433{
434 m_oldWorldTransform.push(p->worldTransform());
435 p->setWorldTransform(m_transform, true);
436}
437
438void QSvgTransformStyle::revert(QPainter *p, QSvgExtraStates &)
439{
440 p->setWorldTransform(m_oldWorldTransform.pop(), false /* don't combine */);
441}
442
443QSvgStyleProperty::Type QSvgQualityStyle::type() const
444{
445 return QUALITY;
446}
447
448QSvgStyleProperty::Type QSvgFillStyle::type() const
449{
450 return FILL;
451}
452
453QSvgStyleProperty::Type QSvgViewportFillStyle::type() const
454{
455 return VIEWPORT_FILL;
456}
457
458QSvgStyleProperty::Type QSvgFontStyle::type() const
459{
460 return FONT;
461}
462
463QSvgStyleProperty::Type QSvgStrokeStyle::type() const
464{
465 return STROKE;
466}
467
468QSvgStyleProperty::Type QSvgSolidColorStyle::type() const
469{
470 return SOLID_COLOR;
471}
472
473QSvgStyleProperty::Type QSvgGradientStyle::type() const
474{
475 return GRADIENT;
476}
477
478QSvgStyleProperty::Type QSvgPatternStyle::type() const
479{
480 return PATTERN;
481}
482
483QSvgStyleProperty::Type QSvgTransformStyle::type() const
484{
485 return TRANSFORM;
486}
487
488
489QSvgCompOpStyle::QSvgCompOpStyle(QPainter::CompositionMode mode)
490 : m_mode(mode)
491{
492
493}
494
495void QSvgCompOpStyle::apply(QPainter *p, const QSvgNode *, QSvgExtraStates &)
496{
497 m_oldMode = p->compositionMode();
498 p->setCompositionMode(m_mode);
499}
500
501void QSvgCompOpStyle::revert(QPainter *p, QSvgExtraStates &)
502{
503 p->setCompositionMode(m_oldMode);
504}
505
506QSvgStyleProperty::Type QSvgCompOpStyle::type() const
507{
508 return COMP_OP;
509}
510
511void QSvgOffsetStyle::apply(QPainter *, const QSvgNode *, QSvgExtraStates &)
512{
513}
514
515void QSvgOffsetStyle::revert(QPainter *, QSvgExtraStates &)
516{
517}
518
519QSvgStyleProperty::Type QSvgOffsetStyle::type() const
520{
521 return OFFSET;
522}
523
524QSvgOpacityStyle::QSvgOpacityStyle(qreal opacity)
525 : m_opacity(opacity), m_oldOpacity(0)
526{
527
528}
529
530void QSvgOpacityStyle::apply(QPainter *p, const QSvgNode *, QSvgExtraStates &)
531{
532 m_oldOpacity = p->opacity();
533 p->setOpacity(m_opacity * m_oldOpacity);
534}
535
536void QSvgOpacityStyle::revert(QPainter *p, QSvgExtraStates &)
537{
538 p->setOpacity(m_oldOpacity);
539}
540
541QSvgStyleProperty::Type QSvgOpacityStyle::type() const
542{
543 return OPACITY;
544}
545
546void QSvgGradientStyle::setStopLink(const QString &link, QSvgTinyDocument *doc)
547{
548 m_link = link;
549 m_doc = doc;
550}
551
552void QSvgGradientStyle::resolveStops()
553{
554 QStringList visited;
555 resolveStops_helper(&visited);
556}
557
558void QSvgGradientStyle::resolveStops_helper(QStringList *visited)
559{
560 if (!m_link.isEmpty() && m_doc) {
561 QSvgStyleProperty *prop = m_doc->styleProperty(m_link);
562 if (prop && !visited->contains(m_link)) {
563 visited->append(m_link);
564 if (prop->type() == QSvgStyleProperty::GRADIENT) {
565 QSvgGradientStyle *st =
566 static_cast<QSvgGradientStyle*>(prop);
567 st->resolveStops_helper(visited);
568 m_gradient->setStops(st->qgradient()->stops());
569 m_gradientStopsSet = st->gradientStopsSet();
570 }
571 } else {
572 qWarning("Could not resolve property : %s", qPrintable(m_link));
573 }
574 m_link = QString();
575 }
576}
577
578QSvgStaticStyle::QSvgStaticStyle()
579 : quality(0)
580 , fill(0)
581 , viewportFill(0)
582 , font(0)
583 , stroke(0)
584 , solidColor(0)
585 , gradient(0)
586 , pattern(0)
587 , transform(0)
588 , opacity(0)
589 , compop(0)
590{
591}
592
593QSvgStaticStyle::~QSvgStaticStyle()
594{
595}
596
597void QSvgStaticStyle::apply(QPainter *p, const QSvgNode *node, QSvgExtraStates &states)
598{
599 if (quality) {
600 quality->apply(p, node, states);
601 }
602
603 if (fill) {
604 fill->apply(p, node, states);
605 }
606
607 if (viewportFill) {
608 viewportFill->apply(p, node, states);
609 }
610
611 if (font) {
612 font->apply(p, node, states);
613 }
614
615 if (stroke) {
616 stroke->apply(p, node, states);
617 }
618
619 if (transform) {
620 transform->apply(p, node, states);
621 }
622
623 if (opacity) {
624 opacity->apply(p, node, states);
625 }
626
627 if (compop) {
628 compop->apply(p, node, states);
629 }
630}
631
632void QSvgStaticStyle::revert(QPainter *p, QSvgExtraStates &states)
633{
634 if (quality) {
635 quality->revert(p, states);
636 }
637
638 if (fill) {
639 fill->revert(p, states);
640 }
641
642 if (viewportFill) {
643 viewportFill->revert(p, states);
644 }
645
646 if (font) {
647 font->revert(p, states);
648 }
649
650 if (stroke) {
651 stroke->revert(p, states);
652 }
653
654 if (transform) {
655 transform->revert(p, states);
656 }
657
658 if (opacity) {
659 opacity->revert(p, states);
660 }
661
662 if (compop) {
663 compop->revert(p, states);
664 }
665}
666
667namespace {
668
669QColor sumValue(const QColor &c1, const QColor &c2)
670{
671 QRgb rgb1 = c1.rgba();
672 QRgb rgb2 = c2.rgba();
673 int sumRed = qRed(rgb1) + qRed(rgb2);
674 int sumGreen = qGreen(rgb1) + qGreen(rgb2);
675 int sumBlue = qBlue(rgb1) + qBlue(rgb2);
676
677 QRgb sumRgb = qRgba(qBound(0, sumRed, 255),
678 qBound(0, sumGreen, 255),
679 qBound(0, sumBlue, 255),
680 255);
681
682 return QColor(sumRgb);
683}
684
685qreal sumValue(qreal value1, qreal value2)
686{
687 qreal sumValue = value1 + value2;
688 return qBound(0.0, sumValue, 1.0);
689}
690
691}
692
693QSvgAnimatedStyle::QSvgAnimatedStyle()
694{
695}
696
697QSvgAnimatedStyle::~QSvgAnimatedStyle()
698{
699}
700
701void QSvgAnimatedStyle::apply(QPainter *p, const QSvgNode *node, QSvgExtraStates &states)
702{
703 QSharedPointer<QSvgAbstractAnimator> animator = node->document()->animator();
704 QList<QSvgAbstractAnimation *> nodeAnims = animator->animationsForNode(node);
705
706 savePaintingState(p, node, states);
707 if (nodeAnims.isEmpty())
708 return;
709
710 QSvgStyleState currentStyle = m_static;
711 for (auto anim : nodeAnims) {
712 if (!anim->isActive())
713 continue;
714
715 fetchStyleState(anim, currentStyle);
716 }
717
718 applyStyle(p, states, currentStyle);
719}
720
721void QSvgAnimatedStyle::revert(QPainter *p, QSvgExtraStates &states)
722{
723 p->setWorldTransform(m_worldTransform);
724 p->setBrush(m_static.fill);
725 p->setPen(m_static.stroke);
726 p->setOpacity(m_static.opacity);
727 states.fillOpacity = m_static.fillOpacity;
728 states.strokeOpacity = m_static.strokeOpacity;
729}
730
731void QSvgAnimatedStyle::savePaintingState(const QPainter *p, const QSvgNode *node, QSvgExtraStates &states)
732{
733 QSvgStaticStyle style = node->style();
734 m_worldTransform = p->worldTransform();
735 if (style.transform)
736 m_static.transform = style.transform->qtransform();
737
738 if (style.offset) {
739 m_static.offsetPath = style.offset->path();
740 m_static.offsetRotateType = style.offset->rotateType();
741 m_static.offsetRotate = style.offset->rotateAngle();
742 }
743
744 m_static.fill = p->brush();
745 m_static.stroke = p->pen();
746 m_static.fillOpacity = states.fillOpacity;
747 m_static.strokeOpacity = states.strokeOpacity;
748 m_static.opacity = p->opacity();
749 m_transformToNode = m_static.transform.inverted() * m_worldTransform;
750}
751
752void QSvgAnimatedStyle::fetchStyleState(const QSvgAbstractAnimation *animation, QSvgStyleState &currentStyle)
753{
754 bool replace = animation->animationType() == QSvgAbstractAnimation::CSS ? true :
755 (static_cast<const QSvgAnimateNode *>(animation))->additiveType() == QSvgAnimateNode::Replace;
756
757 QList<QSvgAbstractAnimatedProperty *> properties = animation->properties();
758 for (const QSvgAbstractAnimatedProperty *property : std::as_const(properties)) {
759 if (property->propertyName() == QStringLiteral("fill")) {
760 QBrush brush = currentStyle.fill;
761 QColor brushColor = brush.color();
762 QColor animatedColor = property->interpolatedValue().value<QColor>();
763 QColor sumOrReplaceColor = replace ? animatedColor : sumValue(brushColor, animatedColor);
764 brush.setColor(sumOrReplaceColor);
765 currentStyle.fill = brush;
766 } else if (property->propertyName() == QStringLiteral("stroke")) {
767 QPen &pen = currentStyle.stroke;
768 QBrush penBrush = pen.brush();
769 QColor penColor = penBrush.color();
770 QColor animatedColor = property->interpolatedValue().value<QColor>();
771 QColor sumOrReplaceColor = replace ? animatedColor : sumValue(penColor, animatedColor);
772 penBrush.setColor(sumOrReplaceColor);
773 penBrush.setStyle(Qt::SolidPattern);
774 pen.setBrush(penBrush);
775 } else if (property->propertyName() == QStringLiteral("transform")) {
776 QTransform animatedTransform = property->interpolatedValue().value<QTransform>();
777 QTransform sumOrReplaceTransform = replace ? animatedTransform : animatedTransform * currentStyle.transform;
778 currentStyle.transform = sumOrReplaceTransform;
779 } else if (property->propertyName() == QStringLiteral("fill-opacity")) {
780 qreal animatedFillOpacity = property->interpolatedValue().value<qreal>();
781 qreal sumOrReplaceOpacity = replace ? animatedFillOpacity : sumValue(currentStyle.fillOpacity, animatedFillOpacity);
782 currentStyle.fillOpacity = sumOrReplaceOpacity;
783 } else if (property->propertyName() == QStringLiteral("stroke-opacity")) {
784 qreal animatedStrokeOpacity = property->interpolatedValue().value<qreal>();
785 qreal sumOrReplaceOpacity = replace ? animatedStrokeOpacity : sumValue(currentStyle.strokeOpacity, animatedStrokeOpacity);
786 currentStyle.strokeOpacity = sumOrReplaceOpacity;
787 } else if (property->propertyName() == QStringLiteral("opacity")) {
788 qreal animatedOpacity = property->interpolatedValue().value<qreal>();
789 qreal sumOrReplaceOpacity = replace ? animatedOpacity : sumValue(currentStyle.opacity, animatedOpacity);
790 currentStyle.opacity = sumOrReplaceOpacity;
791 } else if (property->propertyName() == QStringLiteral("offset-distance")) {
792 qreal offsetDistance = property->interpolatedValue().value<qreal>();
793 currentStyle.offsetDistance = offsetDistance;
794 }
795 }
796}
797
798void QSvgAnimatedStyle::applyStyle(QPainter *p, QSvgExtraStates &states, const QSvgStyleState &currentStyle)
799{
800 p->setBrush(currentStyle.fill);
801 states.fillOpacity = currentStyle.fillOpacity;
802 p->setPen(currentStyle.stroke);
803 states.strokeOpacity = currentStyle.strokeOpacity;
804 p->setOpacity(currentStyle.opacity);
805
806 QTransform transform = currentStyle.transform;
807 QTransform offset;
808 if (m_static.offsetPath) {
809 qreal offsetDistance = currentStyle.offsetDistance;
810 qreal angle = m_static.offsetPath.value().angleAtPercent(offsetDistance);
811 QPointF position = m_static.offsetPath.value().pointAtPercent(offsetDistance);
812 offset.translate(position.x(), position.y());
813
814 switch (m_static.offsetRotateType) {
815 case QtSvg::OffsetRotateType::Auto:
816 offset.rotate(-angle);
817 break;
818 case QtSvg::OffsetRotateType::Angle:
819 offset.rotate(m_static.offsetRotate);
820 break;
821 case QtSvg::OffsetRotateType::AutoAngle:
822 offset.rotate(m_static.offsetRotate - angle);
823 break;
824 case QtSvg::OffsetRotateType::Reverse:
825 offset.rotate(180 - angle);
826 break;
827 case QtSvg::OffsetRotateType::ReverseAngle:
828 offset.rotate(180 + m_static.offsetRotate - angle);
829 break;
830 }
831 }
832
833 QTransform combinedTransform = transform * offset * m_transformToNode;
834 p->setWorldTransform(combinedTransform);
835}
836
837QT_END_NAMESPACE
Combined button and popup list for selecting options.
#define qPrintable(string)
Definition qstring.h:1683
#define QStringLiteral(str)
Definition qstring.h:1824