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
19QSvgRefCounted::~QSvgRefCounted()
20 = default;
21
22QSvgExtraStates::QSvgExtraStates()
23 : fillOpacity(1.0),
24 strokeOpacity(1.0),
25 svgFont(0),
26 textAnchor(Qt::AlignLeft),
27 fontWeight(QFont::Normal),
28 fillRule(Qt::WindingFill),
29 strokeDashOffset(0),
30 vectorEffect(false),
31 imageRendering(QSvgQualityStyle::ImageRenderingAuto)
32{
33}
34
35QSvgStyleProperty::~QSvgStyleProperty()
36 = default;
37
38QSvgQualityStyle::QSvgQualityStyle(int color)
39 : m_imageRendering(QSvgQualityStyle::ImageRenderingAuto)
40 , m_oldImageRendering(QSvgQualityStyle::ImageRenderingAuto)
41 , m_imageRenderingSet(0)
42{
43 Q_UNUSED(color);
44}
45
46QSvgQualityStyle::~QSvgQualityStyle()
47 = default;
48
49void QSvgQualityStyle::setImageRendering(ImageRendering hint) {
50 m_imageRendering = hint;
51 m_imageRenderingSet = 1;
52}
53
54void QSvgQualityStyle::apply(QPainter *p, const QSvgNode *, QSvgExtraStates &states)
55{
56 m_oldImageRendering = states.imageRendering;
57 if (m_imageRenderingSet) {
58 states.imageRendering = m_imageRendering;
59 }
60 if (m_imageRenderingSet) {
61 bool smooth = false;
62 if (m_imageRendering == ImageRenderingAuto)
63 // auto (the spec says to prefer quality)
64 smooth = true;
65 else
66 smooth = (m_imageRendering == ImageRenderingOptimizeQuality);
67 p->setRenderHint(QPainter::SmoothPixmapTransform, smooth);
68 }
69}
70
71void QSvgQualityStyle::revert(QPainter *p, QSvgExtraStates &states)
72{
73 if (m_imageRenderingSet) {
74 states.imageRendering = m_oldImageRendering;
75 bool smooth = false;
76 if (m_oldImageRendering == ImageRenderingAuto)
77 smooth = true;
78 else
79 smooth = (m_oldImageRendering == ImageRenderingOptimizeQuality);
80 p->setRenderHint(QPainter::SmoothPixmapTransform, smooth);
81 }
82}
83
84QSvgFillStyle::QSvgFillStyle()
85 : m_fillRuleSet(0)
86 , m_fillOpacitySet(0)
87 , m_fillSet(0)
88{
89}
90
91QSvgFillStyle::~QSvgFillStyle()
92 = default;
93
94void QSvgFillStyle::setFillRule(Qt::FillRule f)
95{
96 m_fillRuleSet = 1;
97 m_fillRule = f;
98}
99
100void QSvgFillStyle::setFillOpacity(qreal opacity)
101{
102 m_fillOpacitySet = 1;
103 m_fillOpacity = opacity;
104}
105
106void QSvgFillStyle::setPaintServer(QSvgPaintServerSharedPtr paintServer)
107{
108 m_paintServer = std::move(paintServer);
109 m_fillSet = 1;
110}
111
112void QSvgFillStyle::setBrush(QBrush brush)
113{
114 m_fill = std::move(brush);
115 m_paintServer.reset();
116 m_fillSet = 1;
117}
118
119void QSvgFillStyle::apply(QPainter *p, const QSvgNode *n, QSvgExtraStates &states)
120{
121 m_oldFill = p->brush();
122 m_oldFillRule = states.fillRule;
123 m_oldFillOpacity = states.fillOpacity;
124
125 if (m_fillRuleSet)
126 states.fillRule = m_fillRule;
127 if (m_fillSet) {
128 if (m_paintServer)
129 p->setBrush(m_paintServer->brush(p, n, states));
130 else
131 p->setBrush(m_fill);
132 }
133 if (m_fillOpacitySet)
134 states.fillOpacity = m_fillOpacity;
135}
136
137void QSvgFillStyle::revert(QPainter *p, QSvgExtraStates &states)
138{
139 if (m_fillOpacitySet)
140 states.fillOpacity = m_oldFillOpacity;
141 if (m_fillSet)
142 p->setBrush(m_oldFill);
143 if (m_fillRuleSet)
144 states.fillRule = m_oldFillRule;
145}
146
147QSvgViewportFillStyle::QSvgViewportFillStyle(const QBrush &brush)
148 : m_viewportFill(brush)
149{
150}
151
152QSvgViewportFillStyle::~QSvgViewportFillStyle()
153 = default;
154
155void QSvgViewportFillStyle::apply(QPainter *p, const QSvgNode *, QSvgExtraStates &)
156{
157 m_oldFill = p->brush();
158 p->setBrush(m_viewportFill);
159}
160
161void QSvgViewportFillStyle::revert(QPainter *p, QSvgExtraStates &)
162{
163 p->setBrush(m_oldFill);
164}
165
166const int QSvgFontStyle::LIGHTER;
167const int QSvgFontStyle::BOLDER;
168
169QSvgFontStyle::QSvgFontStyle(QSvgFont *font, QSvgDocument *doc)
170 : m_svgFont(font)
171 , m_doc(doc)
172 , m_familySet(0)
173 , m_sizeSet(0)
174 , m_styleSet(0)
175 , m_variantSet(0)
176 , m_weightSet(0)
177 , m_textAnchorSet(0)
178{
179}
180
181QSvgFontStyle::QSvgFontStyle()
182 : m_svgFont(0)
183 , m_doc(0)
184 , m_familySet(0)
185 , m_sizeSet(0)
186 , m_styleSet(0)
187 , m_variantSet(0)
188 , m_weightSet(0)
189 , m_textAnchorSet(0)
190{
191}
192
193QSvgFontStyle::~QSvgFontStyle()
194 = default;
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, QFont::Weight::Black - 100) + 100;
224 } else if (m_weight == LIGHTER) {
225 states.fontWeight = qMax(states.fontWeight, QFont::Weight::Thin + 100) - 100;
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_vectorEffect(0)
247 , m_oldVectorEffect(0)
248 , m_strokeSet(0)
249 , m_strokeDashArraySet(0)
250 , m_strokeDashOffsetSet(0)
251 , m_strokeLineCapSet(0)
252 , m_strokeLineJoinSet(0)
253 , m_strokeMiterLimitSet(0)
254 , m_strokeOpacitySet(0)
255 , m_strokeWidthSet(0)
256 , m_vectorEffectSet(0)
257{
258}
259
260QSvgStrokeStyle::~QSvgStrokeStyle()
261 = default;
262
263void QSvgStrokeStyle::apply(QPainter *p, const QSvgNode *n, QSvgExtraStates &states)
264{
265 m_oldStroke = p->pen();
266 m_oldStrokeOpacity = states.strokeOpacity;
267 m_oldStrokeDashOffset = states.strokeDashOffset;
268 m_oldVectorEffect = states.vectorEffect;
269
270 QPen pen = p->pen();
271
272 qreal oldWidth = pen.widthF();
273 qreal width = m_stroke.widthF();
274 if (oldWidth == 0)
275 oldWidth = 1;
276 if (width == 0)
277 width = 1;
278 qreal scale = oldWidth / width;
279
280 if (m_strokeOpacitySet)
281 states.strokeOpacity = m_strokeOpacity;
282
283 if (m_vectorEffectSet)
284 states.vectorEffect = m_vectorEffect;
285
286 if (m_strokeSet) {
287 if (m_paintServer)
288 pen.setBrush(m_paintServer->brush(p, n, states));
289 else
290 pen.setBrush(m_stroke.brush());
291 }
292
293 if (m_strokeWidthSet)
294 pen.setWidthF(m_stroke.widthF());
295
296 bool setDashOffsetNeeded = false;
297
298 if (m_strokeDashOffsetSet) {
299 states.strokeDashOffset = m_strokeDashOffset;
300 setDashOffsetNeeded = true;
301 }
302
303 if (m_strokeDashArraySet) {
304 if (m_stroke.style() == Qt::SolidLine) {
305 pen.setStyle(Qt::SolidLine);
306 } else if (m_strokeWidthSet || oldWidth == 1) {
307 // If both width and dash array was set, the dash array is already scaled correctly.
308 pen.setDashPattern(m_stroke.dashPattern());
309 setDashOffsetNeeded = true;
310 } else {
311 // If dash array was set, but not the width, the dash array has to be scaled with respect to the old width.
312 QList<qreal> dashes = m_stroke.dashPattern();
313 for (int i = 0; i < dashes.size(); ++i)
314 dashes[i] /= oldWidth;
315 pen.setDashPattern(dashes);
316 setDashOffsetNeeded = true;
317 }
318 } else if (m_strokeWidthSet && pen.style() != Qt::SolidLine && scale != 1) {
319 // If the width was set, but not the dash array, the old dash array must be scaled with respect to the new width.
320 QList<qreal> dashes = pen.dashPattern();
321 for (int i = 0; i < dashes.size(); ++i)
322 dashes[i] *= scale;
323 pen.setDashPattern(dashes);
324 setDashOffsetNeeded = true;
325 }
326
327 if (m_strokeLineCapSet)
328 pen.setCapStyle(m_stroke.capStyle());
329 if (m_strokeLineJoinSet)
330 pen.setJoinStyle(m_stroke.joinStyle());
331 if (m_strokeMiterLimitSet)
332 pen.setMiterLimit(m_stroke.miterLimit());
333
334 // You can have dash offset on solid strokes in SVG files, but not in Qt.
335 // QPen::setDashOffset() will set the pen style to Qt::CustomDashLine,
336 // so don't call the method if the pen is solid.
337 if (setDashOffsetNeeded && pen.style() != Qt::SolidLine) {
338 qreal currentWidth = pen.widthF();
339 if (currentWidth == 0)
340 currentWidth = 1;
341 pen.setDashOffset(states.strokeDashOffset / currentWidth);
342 }
343
344 pen.setCosmetic(states.vectorEffect);
345
346 p->setPen(pen);
347}
348
349void QSvgStrokeStyle::revert(QPainter *p, QSvgExtraStates &states)
350{
351 p->setPen(m_oldStroke);
352 states.strokeOpacity = m_oldStrokeOpacity;
353 states.strokeDashOffset = m_oldStrokeDashOffset;
354 states.vectorEffect = m_oldVectorEffect;
355}
356
357void QSvgStrokeStyle::setDashArray(const QList<qreal> &dashes)
358{
359 if (m_strokeWidthSet) {
360 QList<qreal> d = dashes;
361 qreal w = m_stroke.widthF();
362 if (w != 0 && w != 1) {
363 for (int i = 0; i < d.size(); ++i)
364 d[i] /= w;
365 }
366 m_stroke.setDashPattern(d);
367 } else {
368 m_stroke.setDashPattern(dashes);
369 }
370 m_strokeDashArraySet = 1;
371}
372
373QSvgTransformStyle::QSvgTransformStyle(const QTransform &trans)
374 : m_transform(trans)
375{
376}
377
378QSvgTransformStyle::~QSvgTransformStyle()
379 = default;
380
381void QSvgTransformStyle::apply(QPainter *p, const QSvgNode *, QSvgExtraStates &)
382{
383 m_oldWorldTransform.push(p->worldTransform());
384 p->setWorldTransform(m_transform, true);
385}
386
387void QSvgTransformStyle::revert(QPainter *p, QSvgExtraStates &)
388{
389 p->setWorldTransform(m_oldWorldTransform.pop(), false /* don't combine */);
390}
391
392QSvgStyleProperty::Type QSvgQualityStyle::type() const
393{
394 return QUALITY;
395}
396
397QSvgStyleProperty::Type QSvgFillStyle::type() const
398{
399 return FILL;
400}
401
402QSvgStyleProperty::Type QSvgViewportFillStyle::type() const
403{
404 return VIEWPORT_FILL;
405}
406
407QSvgStyleProperty::Type QSvgFontStyle::type() const
408{
409 return FONT;
410}
411
412QSvgStyleProperty::Type QSvgStrokeStyle::type() const
413{
414 return STROKE;
415}
416
417QSvgStyleProperty::Type QSvgTransformStyle::type() const
418{
419 return TRANSFORM;
420}
421
422
423QSvgCompOpStyle::QSvgCompOpStyle(QPainter::CompositionMode mode)
424 : m_mode(mode)
425{
426
427}
428
429QSvgCompOpStyle::~QSvgCompOpStyle()
430 = default;
431
432void QSvgCompOpStyle::apply(QPainter *p, const QSvgNode *, QSvgExtraStates &)
433{
434 m_oldMode = p->compositionMode();
435 p->setCompositionMode(m_mode);
436}
437
438void QSvgCompOpStyle::revert(QPainter *p, QSvgExtraStates &)
439{
440 p->setCompositionMode(m_oldMode);
441}
442
443QSvgStyleProperty::Type QSvgCompOpStyle::type() const
444{
445 return COMP_OP;
446}
447
448QSvgOffsetStyle::~QSvgOffsetStyle()
449 = default;
450
451void QSvgOffsetStyle::apply(QPainter *, const QSvgNode *, QSvgExtraStates &)
452{
453}
454
455void QSvgOffsetStyle::revert(QPainter *, QSvgExtraStates &)
456{
457}
458
459QSvgStyleProperty::Type QSvgOffsetStyle::type() const
460{
461 return OFFSET;
462}
463
464QSvgOpacityStyle::QSvgOpacityStyle(qreal opacity)
465 : m_opacity(opacity), m_oldOpacity(0)
466{
467
468}
469
470QSvgOpacityStyle::~QSvgOpacityStyle()
471 = default;
472
473void QSvgOpacityStyle::apply(QPainter *p, const QSvgNode *, QSvgExtraStates &)
474{
475 m_oldOpacity = p->opacity();
476 p->setOpacity(m_opacity * m_oldOpacity);
477}
478
479void QSvgOpacityStyle::revert(QPainter *p, QSvgExtraStates &)
480{
481 p->setOpacity(m_oldOpacity);
482}
483
484QSvgStyleProperty::Type QSvgOpacityStyle::type() const
485{
486 return OPACITY;
487}
488
489QSvgStaticStyle::QSvgStaticStyle()
490 : quality(0)
491 , fill(0)
492 , viewportFill(0)
493 , font(0)
494 , stroke(0)
495 , transform(0)
496 , opacity(0)
497 , compop(0)
498{
499}
500
501QSvgStaticStyle::~QSvgStaticStyle()
502{
503}
504
505void QSvgStaticStyle::apply(QPainter *p, const QSvgNode *node, QSvgExtraStates &states)
506{
507 if (quality) {
508 quality->apply(p, node, states);
509 }
510
511 if (fill) {
512 fill->apply(p, node, states);
513 }
514
515 if (viewportFill) {
516 viewportFill->apply(p, node, states);
517 }
518
519 if (font) {
520 font->apply(p, node, states);
521 }
522
523 if (stroke) {
524 stroke->apply(p, node, states);
525 }
526
527 if (transform) {
528 transform->apply(p, node, states);
529 }
530
531 if (opacity) {
532 opacity->apply(p, node, states);
533 }
534
535 if (compop) {
536 compop->apply(p, node, states);
537 }
538}
539
540void QSvgStaticStyle::revert(QPainter *p, QSvgExtraStates &states)
541{
542 if (quality) {
543 quality->revert(p, states);
544 }
545
546 if (fill) {
547 fill->revert(p, states);
548 }
549
550 if (viewportFill) {
551 viewportFill->revert(p, states);
552 }
553
554 if (font) {
555 font->revert(p, states);
556 }
557
558 if (stroke) {
559 stroke->revert(p, states);
560 }
561
562 if (transform) {
563 transform->revert(p, states);
564 }
565
566 if (opacity) {
567 opacity->revert(p, states);
568 }
569
570 if (compop) {
571 compop->revert(p, states);
572 }
573}
574
575namespace {
576
577QColor sumValue(const QColor &c1, const QColor &c2)
578{
579 QRgb rgb1 = c1.rgba();
580 QRgb rgb2 = c2.rgba();
581 int sumRed = qRed(rgb1) + qRed(rgb2);
582 int sumGreen = qGreen(rgb1) + qGreen(rgb2);
583 int sumBlue = qBlue(rgb1) + qBlue(rgb2);
584
585 QRgb sumRgb = qRgba(qBound(0, sumRed, 255),
586 qBound(0, sumGreen, 255),
587 qBound(0, sumBlue, 255),
588 255);
589
590 return QColor(sumRgb);
591}
592
593qreal sumValue(qreal value1, qreal value2)
594{
595 qreal sumValue = value1 + value2;
596 return qBound(0.0, sumValue, 1.0);
597}
598
599}
600
601QSvgAnimatedStyle::QSvgAnimatedStyle()
602{
603}
604
605QSvgAnimatedStyle::~QSvgAnimatedStyle()
606{
607}
608
609void QSvgAnimatedStyle::apply(QPainter *p, const QSvgNode *node, QSvgExtraStates &states)
610{
611 QSharedPointer<QSvgAbstractAnimator> animator = node->document()->animator();
612 QList<QSvgAbstractAnimation *> nodeAnims = animator->animationsForNode(node);
613
614 savePaintingState(p, node, states);
615 if (nodeAnims.isEmpty())
616 return;
617
618 QSvgStyleState currentStyle = m_static;
619 for (const QSvgAbstractAnimation *anim : std::as_const(nodeAnims)) {
620 if (!anim->isActive())
621 continue;
622
623 fetchStyleState(anim, currentStyle);
624 }
625
626 applyStyle(p, states, currentStyle);
627}
628
629void QSvgAnimatedStyle::revert(QPainter *p, QSvgExtraStates &states)
630{
631 p->setWorldTransform(m_worldTransform);
632 p->setBrush(m_static.fill);
633 p->setPen(m_static.stroke);
634 p->setOpacity(m_static.opacity);
635 states.fillOpacity = m_static.fillOpacity;
636 states.strokeOpacity = m_static.strokeOpacity;
637}
638
639void QSvgAnimatedStyle::savePaintingState(const QPainter *p, const QSvgNode *node, QSvgExtraStates &states)
640{
641 QSvgStaticStyle style = node->style();
642 m_worldTransform = p->worldTransform();
643 if (style.transform)
644 m_static.transform = style.transform->qtransform();
645
646 if (style.offset) {
647 m_static.offsetPath = style.offset->path();
648 m_static.offsetRotateType = style.offset->rotateType();
649 m_static.offsetRotate = style.offset->rotateAngle();
650 }
651
652 m_static.fill = p->brush();
653 m_static.stroke = p->pen();
654 m_static.fillOpacity = states.fillOpacity;
655 m_static.strokeOpacity = states.strokeOpacity;
656 m_static.opacity = p->opacity();
657 m_transformToNode = m_static.transform.inverted() * m_worldTransform;
658}
659
660void QSvgAnimatedStyle::fetchStyleState(const QSvgAbstractAnimation *animation, QSvgStyleState &currentStyle)
661{
662 bool replace = animation->animationType() == QSvgAbstractAnimation::CSS ? true :
663 (static_cast<const QSvgAnimateNode *>(animation))->additiveType() == QSvgAnimateNode::Replace;
664
665 QList<QSvgAbstractAnimatedProperty *> properties = animation->properties();
666 for (const QSvgAbstractAnimatedProperty *property : std::as_const(properties)) {
667 if (property->propertyName() == QStringLiteral("fill")) {
668 QBrush brush = currentStyle.fill;
669 QColor brushColor = brush.color();
670 QColor animatedColor = property->interpolatedValue().value<QColor>();
671 QColor sumOrReplaceColor = replace ? animatedColor : sumValue(brushColor, animatedColor);
672 brush.setColor(sumOrReplaceColor);
673 currentStyle.fill = brush;
674 } else if (property->propertyName() == QStringLiteral("stroke")) {
675 QPen &pen = currentStyle.stroke;
676 QBrush penBrush = pen.brush();
677 QColor penColor = penBrush.color();
678 QColor animatedColor = property->interpolatedValue().value<QColor>();
679 QColor sumOrReplaceColor = replace ? animatedColor : sumValue(penColor, animatedColor);
680 penBrush.setColor(sumOrReplaceColor);
681 penBrush.setStyle(Qt::SolidPattern);
682 pen.setBrush(penBrush);
683 } else if (property->propertyName() == QStringLiteral("transform")) {
684 QTransform animatedTransform = property->interpolatedValue().value<QTransform>();
685 QTransform sumOrReplaceTransform = replace ? animatedTransform : animatedTransform * currentStyle.transform;
686 currentStyle.transform = sumOrReplaceTransform;
687 } else if (property->propertyName() == QStringLiteral("fill-opacity")) {
688 qreal animatedFillOpacity = property->interpolatedValue().value<qreal>();
689 qreal sumOrReplaceOpacity = replace ? animatedFillOpacity : sumValue(currentStyle.fillOpacity, animatedFillOpacity);
690 currentStyle.fillOpacity = sumOrReplaceOpacity;
691 } else if (property->propertyName() == QStringLiteral("stroke-opacity")) {
692 qreal animatedStrokeOpacity = property->interpolatedValue().value<qreal>();
693 qreal sumOrReplaceOpacity = replace ? animatedStrokeOpacity : sumValue(currentStyle.strokeOpacity, animatedStrokeOpacity);
694 currentStyle.strokeOpacity = sumOrReplaceOpacity;
695 } else if (property->propertyName() == QStringLiteral("opacity")) {
696 qreal animatedOpacity = property->interpolatedValue().value<qreal>();
697 qreal sumOrReplaceOpacity = replace ? animatedOpacity : sumValue(currentStyle.opacity, animatedOpacity);
698 currentStyle.opacity = sumOrReplaceOpacity;
699 } else if (property->propertyName() == QStringLiteral("offset-distance")) {
700 qreal offsetDistance = property->interpolatedValue().value<qreal>();
701 currentStyle.offsetDistance = offsetDistance;
702 }
703 }
704}
705
706void QSvgAnimatedStyle::applyStyle(QPainter *p, QSvgExtraStates &states, const QSvgStyleState &currentStyle)
707{
708 p->setBrush(currentStyle.fill);
709 states.fillOpacity = currentStyle.fillOpacity;
710 p->setPen(currentStyle.stroke);
711 states.strokeOpacity = currentStyle.strokeOpacity;
712 p->setOpacity(currentStyle.opacity);
713
714 QTransform transform = currentStyle.transform;
715 QTransform offset;
716 if (m_static.offsetPath) {
717 qreal offsetDistance = currentStyle.offsetDistance;
718 qreal angle = m_static.offsetPath.value().angleAtPercent(offsetDistance);
719 QPointF position = m_static.offsetPath.value().pointAtPercent(offsetDistance);
720 offset.translate(position.x(), position.y());
721
722 switch (m_static.offsetRotateType) {
723 case QtSvg::OffsetRotateType::Auto:
724 offset.rotate(-angle);
725 break;
726 case QtSvg::OffsetRotateType::Angle:
727 offset.rotate(m_static.offsetRotate);
728 break;
729 case QtSvg::OffsetRotateType::AutoAngle:
730 offset.rotate(m_static.offsetRotate - angle);
731 break;
732 case QtSvg::OffsetRotateType::Reverse:
733 offset.rotate(180 - angle);
734 break;
735 case QtSvg::OffsetRotateType::ReverseAngle:
736 offset.rotate(180 + m_static.offsetRotate - angle);
737 break;
738 }
739 }
740
741 QTransform combinedTransform = transform * offset * m_transformToNode;
742 p->setWorldTransform(combinedTransform);
743}
744
745QT_END_NAMESPACE
Combined button and popup list for selecting options.
#define QStringLiteral(str)
Definition qstring.h:1825