10#include "private/qsvganimate_p.h"
19QSvgRefCounted::~QSvgRefCounted()
22QSvgExtraStates::QSvgExtraStates()
26 textAnchor(Qt::AlignLeft),
27 fontWeight(QFont::Normal),
28 fillRule(Qt::WindingFill),
31 imageRendering(QSvgQualityStyle::ImageRenderingAuto)
35QSvgStyleProperty::~QSvgStyleProperty()
38QSvgQualityStyle::QSvgQualityStyle(
int color)
39 : m_imageRendering(QSvgQualityStyle::ImageRenderingAuto)
40 , m_oldImageRendering(QSvgQualityStyle::ImageRenderingAuto)
41 , m_imageRenderingSet(0)
46QSvgQualityStyle::~QSvgQualityStyle()
49void QSvgQualityStyle::setImageRendering(ImageRendering hint) {
50 m_imageRendering = hint;
51 m_imageRenderingSet = 1;
54void QSvgQualityStyle::apply(QPainter *p,
const QSvgNode *, QSvgExtraStates &states)
56 m_oldImageRendering = states.imageRendering;
57 if (m_imageRenderingSet) {
58 states.imageRendering = m_imageRendering;
60 if (m_imageRenderingSet) {
62 if (m_imageRendering == ImageRenderingAuto)
66 smooth = (m_imageRendering == ImageRenderingOptimizeQuality);
67 p->setRenderHint(QPainter::SmoothPixmapTransform, smooth);
71void QSvgQualityStyle::revert(QPainter *p, QSvgExtraStates &states)
73 if (m_imageRenderingSet) {
74 states.imageRendering = m_oldImageRendering;
76 if (m_oldImageRendering == ImageRenderingAuto)
79 smooth = (m_oldImageRendering == ImageRenderingOptimizeQuality);
80 p->setRenderHint(QPainter::SmoothPixmapTransform, smooth);
84QSvgFillStyle::QSvgFillStyle()
91QSvgFillStyle::~QSvgFillStyle()
94void QSvgFillStyle::setFillRule(Qt::FillRule f)
100void QSvgFillStyle::setFillOpacity(qreal opacity)
102 m_fillOpacitySet = 1;
103 m_fillOpacity = opacity;
106void QSvgFillStyle::setPaintServer(QSvgPaintServerSharedPtr paintServer)
108 m_paintServer = std::move(paintServer);
112void QSvgFillStyle::setBrush(QBrush brush)
114 m_fill = std::move(brush);
115 m_paintServer.reset();
119void QSvgFillStyle::apply(QPainter *p,
const QSvgNode *n, QSvgExtraStates &states)
121 m_oldFill = p->brush();
122 m_oldFillRule = states.fillRule;
123 m_oldFillOpacity = states.fillOpacity;
126 states.fillRule = m_fillRule;
129 p->setBrush(m_paintServer->brush(p, n, states));
133 if (m_fillOpacitySet)
134 states.fillOpacity = m_fillOpacity;
137void QSvgFillStyle::revert(QPainter *p, QSvgExtraStates &states)
139 if (m_fillOpacitySet)
140 states.fillOpacity = m_oldFillOpacity;
142 p->setBrush(m_oldFill);
144 states.fillRule = m_oldFillRule;
147QSvgViewportFillStyle::QSvgViewportFillStyle(
const QBrush &brush)
148 : m_viewportFill(brush)
152QSvgViewportFillStyle::~QSvgViewportFillStyle()
155void QSvgViewportFillStyle::apply(QPainter *p,
const QSvgNode *, QSvgExtraStates &)
157 m_oldFill = p->brush();
158 p->setBrush(m_viewportFill);
161void QSvgViewportFillStyle::revert(QPainter *p, QSvgExtraStates &)
163 p->setBrush(m_oldFill);
166const int QSvgFontStyle::LIGHTER;
167const int QSvgFontStyle::BOLDER;
169QSvgFontStyle::QSvgFontStyle(QSvgFont *font, QSvgDocument *doc)
181QSvgFontStyle::QSvgFontStyle()
193QSvgFontStyle::~QSvgFontStyle()
196void QSvgFontStyle::apply(QPainter *p,
const QSvgNode *, QSvgExtraStates &states)
198 m_oldQFont = p->font();
199 m_oldSvgFont = states.svgFont;
200 m_oldTextAnchor = states.textAnchor;
201 m_oldWeight = states.fontWeight;
204 states.textAnchor = m_textAnchor;
206 QFont font = m_oldQFont;
208 states.svgFont = m_svgFont;
209 font.setFamilies(m_qfont.families());
213 font.setPointSizeF(m_qfont.pointSizeF());
216 font.setStyle(m_qfont.style());
219 font.setCapitalization(m_qfont.capitalization());
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;
227 states.fontWeight = m_weight;
229 font.setWeight(QFont::Weight(qBound(
static_cast<
int>(QFont::Weight::Thin),
231 static_cast<
int>(QFont::Weight::Black))));
237void QSvgFontStyle::revert(QPainter *p, QSvgExtraStates &states)
239 p->setFont(m_oldQFont);
240 states.svgFont = m_oldSvgFont;
241 states.textAnchor = m_oldTextAnchor;
242 states.fontWeight = m_oldWeight;
245QSvgStrokeStyle::QSvgStrokeStyle()
247 , m_oldVectorEffect(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)
260QSvgStrokeStyle::~QSvgStrokeStyle()
263void QSvgStrokeStyle::apply(QPainter *p,
const QSvgNode *n, QSvgExtraStates &states)
265 m_oldStroke = p->pen();
266 m_oldStrokeOpacity = states.strokeOpacity;
267 m_oldStrokeDashOffset = states.strokeDashOffset;
268 m_oldVectorEffect = states.vectorEffect;
272 qreal oldWidth = pen.widthF();
273 qreal width = m_stroke.widthF();
278 qreal scale = oldWidth / width;
280 if (m_strokeOpacitySet)
281 states.strokeOpacity = m_strokeOpacity;
283 if (m_vectorEffectSet)
284 states.vectorEffect = m_vectorEffect;
288 pen.setBrush(m_paintServer->brush(p, n, states));
290 pen.setBrush(m_stroke.brush());
293 if (m_strokeWidthSet)
294 pen.setWidthF(m_stroke.widthF());
296 bool setDashOffsetNeeded =
false;
298 if (m_strokeDashOffsetSet) {
299 states.strokeDashOffset = m_strokeDashOffset;
300 setDashOffsetNeeded =
true;
303 if (m_strokeDashArraySet) {
304 if (m_stroke.style() == Qt::SolidLine) {
305 pen.setStyle(Qt::SolidLine);
306 }
else if (m_strokeWidthSet || oldWidth == 1) {
308 pen.setDashPattern(m_stroke.dashPattern());
309 setDashOffsetNeeded =
true;
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;
318 }
else if (m_strokeWidthSet && pen.style() != Qt::SolidLine && scale != 1) {
320 QList<qreal> dashes = pen.dashPattern();
321 for (
int i = 0; i < dashes.size(); ++i)
323 pen.setDashPattern(dashes);
324 setDashOffsetNeeded =
true;
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());
337 if (setDashOffsetNeeded && pen.style() != Qt::SolidLine) {
338 qreal currentWidth = pen.widthF();
339 if (currentWidth == 0)
341 pen.setDashOffset(states.strokeDashOffset / currentWidth);
344 pen.setCosmetic(states.vectorEffect);
349void QSvgStrokeStyle::revert(QPainter *p, QSvgExtraStates &states)
351 p->setPen(m_oldStroke);
352 states.strokeOpacity = m_oldStrokeOpacity;
353 states.strokeDashOffset = m_oldStrokeDashOffset;
354 states.vectorEffect = m_oldVectorEffect;
357void QSvgStrokeStyle::setDashArray(
const QList<qreal> &dashes)
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)
366 m_stroke.setDashPattern(d);
368 m_stroke.setDashPattern(dashes);
370 m_strokeDashArraySet = 1;
373QSvgTransformStyle::QSvgTransformStyle(
const QTransform &trans)
378QSvgTransformStyle::~QSvgTransformStyle()
381void QSvgTransformStyle::apply(QPainter *p,
const QSvgNode *, QSvgExtraStates &)
383 m_oldWorldTransform.push(p->worldTransform());
384 p->setWorldTransform(m_transform,
true);
387void QSvgTransformStyle::revert(QPainter *p, QSvgExtraStates &)
389 p->setWorldTransform(m_oldWorldTransform.pop(),
false );
392QSvgStyleProperty::Type QSvgQualityStyle::type()
const
397QSvgStyleProperty::Type QSvgFillStyle::type()
const
402QSvgStyleProperty::Type QSvgViewportFillStyle::type()
const
404 return VIEWPORT_FILL;
407QSvgStyleProperty::Type QSvgFontStyle::type()
const
412QSvgStyleProperty::Type QSvgStrokeStyle::type()
const
417QSvgStyleProperty::Type QSvgTransformStyle::type()
const
423QSvgCompOpStyle::QSvgCompOpStyle(QPainter::CompositionMode mode)
429QSvgCompOpStyle::~QSvgCompOpStyle()
432void QSvgCompOpStyle::apply(QPainter *p,
const QSvgNode *, QSvgExtraStates &)
434 m_oldMode = p->compositionMode();
435 p->setCompositionMode(m_mode);
438void QSvgCompOpStyle::revert(QPainter *p, QSvgExtraStates &)
440 p->setCompositionMode(m_oldMode);
443QSvgStyleProperty::Type QSvgCompOpStyle::type()
const
448QSvgOffsetStyle::~QSvgOffsetStyle()
451void QSvgOffsetStyle::apply(QPainter *,
const QSvgNode *, QSvgExtraStates &)
455void QSvgOffsetStyle::revert(QPainter *, QSvgExtraStates &)
459QSvgStyleProperty::Type QSvgOffsetStyle::type()
const
464QSvgOpacityStyle::QSvgOpacityStyle(qreal opacity)
465 : m_opacity(opacity), m_oldOpacity(0)
470QSvgOpacityStyle::~QSvgOpacityStyle()
473void QSvgOpacityStyle::apply(QPainter *p,
const QSvgNode *, QSvgExtraStates &)
475 m_oldOpacity = p->opacity();
476 p->setOpacity(m_opacity * m_oldOpacity);
479void QSvgOpacityStyle::revert(QPainter *p, QSvgExtraStates &)
481 p->setOpacity(m_oldOpacity);
484QSvgStyleProperty::Type QSvgOpacityStyle::type()
const
489QSvgStaticStyle::QSvgStaticStyle()
501QSvgStaticStyle::~QSvgStaticStyle()
505void QSvgStaticStyle::apply(QPainter *p,
const QSvgNode *node, QSvgExtraStates &states)
508 quality->apply(p, node, states);
512 fill->apply(p, node, states);
516 viewportFill->apply(p, node, states);
520 font->apply(p, node, states);
524 stroke->apply(p, node, states);
528 transform->apply(p, node, states);
532 opacity->apply(p, node, states);
536 compop->apply(p, node, states);
540void QSvgStaticStyle::revert(QPainter *p, QSvgExtraStates &states)
543 quality->revert(p, states);
547 fill->revert(p, states);
551 viewportFill->revert(p, states);
555 font->revert(p, states);
559 stroke->revert(p, states);
563 transform->revert(p, states);
567 opacity->revert(p, states);
571 compop->revert(p, states);
577QColor sumValue(
const QColor &c1,
const QColor &c2)
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);
585 QRgb sumRgb = qRgba(qBound(0, sumRed, 255),
586 qBound(0, sumGreen, 255),
587 qBound(0, sumBlue, 255),
590 return QColor(sumRgb);
593qreal sumValue(qreal value1, qreal value2)
595 qreal sumValue = value1 + value2;
596 return qBound(0.0, sumValue, 1.0);
601QSvgAnimatedStyle::QSvgAnimatedStyle()
605QSvgAnimatedStyle::~QSvgAnimatedStyle()
609void QSvgAnimatedStyle::apply(QPainter *p,
const QSvgNode *node, QSvgExtraStates &states)
611 QSharedPointer<QSvgAbstractAnimator> animator = node->document()->animator();
612 QList<QSvgAbstractAnimation *> nodeAnims = animator->animationsForNode(node);
614 savePaintingState(p, node, states);
615 if (nodeAnims.isEmpty())
618 QSvgStyleState currentStyle = m_static;
619 for (
const QSvgAbstractAnimation *anim : std::as_const(nodeAnims)) {
620 if (!anim->isActive())
623 fetchStyleState(anim, currentStyle);
626 applyStyle(p, states, currentStyle);
629void QSvgAnimatedStyle::revert(QPainter *p, QSvgExtraStates &states)
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;
639void QSvgAnimatedStyle::savePaintingState(
const QPainter *p,
const QSvgNode *node, QSvgExtraStates &states)
641 QSvgStaticStyle style = node->style();
642 m_worldTransform = p->worldTransform();
644 m_static.transform = style.transform->qtransform();
647 m_static.offsetPath = style.offset->path();
648 m_static.offsetRotateType = style.offset->rotateType();
649 m_static.offsetRotate = style.offset->rotateAngle();
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;
660void QSvgAnimatedStyle::fetchStyleState(
const QSvgAbstractAnimation *animation, QSvgStyleState ¤tStyle)
662 bool replace = animation->animationType() == QSvgAbstractAnimation::CSS ?
true :
663 (
static_cast<
const QSvgAnimateNode *>(animation))->additiveType() == QSvgAnimateNode::Replace;
665 QList<QSvgAbstractAnimatedProperty *> properties = animation->properties();
666 for (
const QSvgAbstractAnimatedProperty *property : std::as_const(properties)) {
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;
706void QSvgAnimatedStyle::applyStyle(QPainter *p, QSvgExtraStates &states,
const QSvgStyleState ¤tStyle)
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);
714 QTransform transform = currentStyle.transform;
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());
722 switch (m_static.offsetRotateType) {
723 case QtSvg::OffsetRotateType::Auto:
724 offset.rotate(-angle);
726 case QtSvg::OffsetRotateType::Angle:
727 offset.rotate(m_static.offsetRotate);
729 case QtSvg::OffsetRotateType::AutoAngle:
730 offset.rotate(m_static.offsetRotate - angle);
732 case QtSvg::OffsetRotateType::Reverse:
733 offset.rotate(180 - angle);
735 case QtSvg::OffsetRotateType::ReverseAngle:
736 offset.rotate(180 + m_static.offsetRotate - angle);
741 QTransform combinedTransform = transform * offset * m_transformToNode;
742 p->setWorldTransform(combinedTransform);
Combined button and popup list for selecting options.
#define QStringLiteral(str)