9#include "private/qsvganimate_p.h"
17QSvgExtraStates::QSvgExtraStates()
18 : imageRendering(QSvgQualityStyle::ImageRenderingAuto)
22QSvgExtraStates::QSvgExtraStates(
const QSvgDocument *doc) : QSvgExtraStates()
28QSvgStyleProperty::~QSvgStyleProperty()
31QSvgQualityStyle::QSvgQualityStyle(
int color)
32 : m_imageRendering(QSvgQualityStyle::ImageRenderingAuto)
33 , m_oldImageRendering(QSvgQualityStyle::ImageRenderingAuto)
34 , m_imageRenderingSet(0)
39QSvgQualityStyle::~QSvgQualityStyle()
42void QSvgQualityStyle::setImageRendering(ImageRendering hint) {
43 m_imageRendering = hint;
44 m_imageRenderingSet = 1;
47void QSvgQualityStyle::apply(QPainter *p,
const QSvgNode *, QSvgExtraStates &states)
49 m_oldImageRendering = states.imageRendering;
50 if (m_imageRenderingSet) {
51 states.imageRendering = m_imageRendering;
53 if (m_imageRenderingSet) {
55 if (m_imageRendering == ImageRenderingAuto)
59 smooth = (m_imageRendering == ImageRenderingOptimizeQuality);
60 p->setRenderHint(QPainter::SmoothPixmapTransform, smooth);
64void QSvgQualityStyle::revert(QPainter *p, QSvgExtraStates &states)
66 if (m_imageRenderingSet) {
67 states.imageRendering = m_oldImageRendering;
69 if (m_oldImageRendering == ImageRenderingAuto)
72 smooth = (m_oldImageRendering == ImageRenderingOptimizeQuality);
73 p->setRenderHint(QPainter::SmoothPixmapTransform, smooth);
77QSvgFillStyle::QSvgFillStyle()
84QSvgFillStyle::~QSvgFillStyle()
87void QSvgFillStyle::setFillRule(Qt::FillRule f)
93void QSvgFillStyle::setFillOpacity(qreal opacity)
96 m_fillOpacity = opacity;
99void QSvgFillStyle::setPaintServer(QSvgPaintServerSharedPtr paintServer)
101 m_paintServer = std::move(paintServer);
105void QSvgFillStyle::setBrush(QBrush brush)
107 m_fill = std::move(brush);
108 m_paintServer.reset();
112void QSvgFillStyle::apply(QPainter *p,
const QSvgNode *n, QSvgExtraStates &states)
114 m_oldFill = p->brush();
115 m_oldFillRule = states.fillRule;
116 m_oldFillOpacity = states.fillOpacity;
119 states.fillRule = m_fillRule;
122 p->setBrush(m_paintServer->brush(p, n, states));
126 if (m_fillOpacitySet)
127 states.fillOpacity = m_fillOpacity;
130void QSvgFillStyle::revert(QPainter *p, QSvgExtraStates &states)
132 if (m_fillOpacitySet)
133 states.fillOpacity = m_oldFillOpacity;
135 p->setBrush(m_oldFill);
137 states.fillRule = m_oldFillRule;
140QSvgViewportFillStyle::QSvgViewportFillStyle(
const QBrush &brush)
141 : m_viewportFill(brush)
145QSvgViewportFillStyle::~QSvgViewportFillStyle()
148void QSvgViewportFillStyle::apply(QPainter *p,
const QSvgNode *, QSvgExtraStates &)
150 m_oldFill = p->brush();
151 p->setBrush(m_viewportFill);
154void QSvgViewportFillStyle::revert(QPainter *p, QSvgExtraStates &)
156 p->setBrush(m_oldFill);
159const int QSvgFontStyle::LIGHTER;
160const int QSvgFontStyle::BOLDER;
162QSvgFontStyle::QSvgFontStyle()
172QSvgFontStyle::~QSvgFontStyle()
175void QSvgFontStyle::apply(QPainter *p,
const QSvgNode *, QSvgExtraStates &states)
177 m_oldQFont = p->font();
178 m_oldSvgFont = states.svgFont;
179 m_oldTextAnchor = states.textAnchor;
180 m_oldWeight = states.fontWeight;
183 states.textAnchor = m_textAnchor;
185 QFont font = m_oldQFont;
187 font.setFamilies(m_qfont.families());
188 states.svgFont = states.doc()->svgFont(m_qfont.family());
192 font.setPointSizeF(m_qfont.pointSizeF());
195 font.setStyle(m_qfont.style());
198 font.setCapitalization(m_qfont.capitalization());
201 if (m_weight == BOLDER) {
202 states.fontWeight = qMin(states.fontWeight, QFont::Weight::Black - 100) + 100;
203 }
else if (m_weight == LIGHTER) {
204 states.fontWeight = qMax(states.fontWeight, QFont::Weight::Thin + 100) - 100;
206 states.fontWeight = m_weight;
208 font.setWeight(QFont::Weight(qBound(
static_cast<
int>(QFont::Weight::Thin),
210 static_cast<
int>(QFont::Weight::Black))));
216void QSvgFontStyle::revert(QPainter *p, QSvgExtraStates &states)
218 p->setFont(m_oldQFont);
219 states.svgFont = m_oldSvgFont;
220 states.textAnchor = m_oldTextAnchor;
221 states.fontWeight = m_oldWeight;
224QSvgStrokeStyle::QSvgStrokeStyle()
226 , m_oldVectorEffect(0)
228 , m_strokeDashArraySet(0)
229 , m_strokeDashOffsetSet(0)
230 , m_strokeLineCapSet(0)
231 , m_strokeLineJoinSet(0)
232 , m_strokeMiterLimitSet(0)
233 , m_strokeOpacitySet(0)
234 , m_strokeWidthSet(0)
235 , m_vectorEffectSet(0)
239QSvgStrokeStyle::~QSvgStrokeStyle()
242void QSvgStrokeStyle::apply(QPainter *p,
const QSvgNode *n, QSvgExtraStates &states)
244 m_oldStroke = p->pen();
245 m_oldStrokeOpacity = states.strokeOpacity;
246 m_oldStrokeDashOffset = states.strokeDashOffset;
247 m_oldVectorEffect = states.vectorEffect;
251 qreal oldWidth = pen.widthF();
252 qreal width = m_stroke.widthF();
257 qreal scale = oldWidth / width;
259 if (m_strokeOpacitySet)
260 states.strokeOpacity = m_strokeOpacity;
262 if (m_vectorEffectSet)
263 states.vectorEffect = m_vectorEffect;
267 pen.setBrush(m_paintServer->brush(p, n, states));
269 pen.setBrush(m_stroke.brush());
272 if (m_strokeWidthSet)
273 pen.setWidthF(m_stroke.widthF());
275 bool setDashOffsetNeeded =
false;
277 if (m_strokeDashOffsetSet) {
278 states.strokeDashOffset = m_strokeDashOffset;
279 setDashOffsetNeeded =
true;
282 if (m_strokeDashArraySet) {
283 if (m_stroke.style() == Qt::SolidLine) {
284 pen.setStyle(Qt::SolidLine);
285 }
else if (m_strokeWidthSet || oldWidth == 1) {
287 pen.setDashPattern(m_stroke.dashPattern());
288 setDashOffsetNeeded =
true;
291 QList<qreal> dashes = m_stroke.dashPattern();
292 for (
int i = 0; i < dashes.size(); ++i)
293 dashes[i] /= oldWidth;
294 pen.setDashPattern(dashes);
295 setDashOffsetNeeded =
true;
297 }
else if (m_strokeWidthSet && pen.style() != Qt::SolidLine && scale != 1) {
299 QList<qreal> dashes = pen.dashPattern();
300 for (
int i = 0; i < dashes.size(); ++i)
302 pen.setDashPattern(dashes);
303 setDashOffsetNeeded =
true;
306 if (m_strokeLineCapSet)
307 pen.setCapStyle(m_stroke.capStyle());
308 if (m_strokeLineJoinSet)
309 pen.setJoinStyle(m_stroke.joinStyle());
310 if (m_strokeMiterLimitSet)
311 pen.setMiterLimit(m_stroke.miterLimit());
316 if (setDashOffsetNeeded && pen.style() != Qt::SolidLine) {
317 qreal currentWidth = pen.widthF();
318 if (currentWidth == 0)
320 pen.setDashOffset(states.strokeDashOffset / currentWidth);
323 pen.setCosmetic(states.vectorEffect);
328void QSvgStrokeStyle::revert(QPainter *p, QSvgExtraStates &states)
330 p->setPen(m_oldStroke);
331 states.strokeOpacity = m_oldStrokeOpacity;
332 states.strokeDashOffset = m_oldStrokeDashOffset;
333 states.vectorEffect = m_oldVectorEffect;
336void QSvgStrokeStyle::setDashArray(
const QList<qreal> &dashes)
338 if (m_strokeWidthSet) {
339 QList<qreal> d = dashes;
340 qreal w = m_stroke.widthF();
341 if (w != 0 && w != 1) {
342 for (
int i = 0; i < d.size(); ++i)
345 m_stroke.setDashPattern(d);
347 m_stroke.setDashPattern(dashes);
349 m_strokeDashArraySet = 1;
352QSvgTransformStyle::QSvgTransformStyle(
const QTransform &trans)
357QSvgTransformStyle::~QSvgTransformStyle()
360void QSvgTransformStyle::apply(QPainter *p,
const QSvgNode *, QSvgExtraStates &)
362 m_oldWorldTransform.push(p->worldTransform());
363 p->setWorldTransform(m_transform,
true);
366void QSvgTransformStyle::revert(QPainter *p, QSvgExtraStates &)
368 p->setWorldTransform(m_oldWorldTransform.pop(),
false );
371QSvgStyleProperty::Type QSvgQualityStyle::type()
const
376QSvgStyleProperty::Type QSvgFillStyle::type()
const
381QSvgStyleProperty::Type QSvgViewportFillStyle::type()
const
386QSvgStyleProperty::Type QSvgFontStyle::type()
const
391QSvgStyleProperty::Type QSvgStrokeStyle::type()
const
396QSvgStyleProperty::Type QSvgTransformStyle::type()
const
402QSvgCompOpStyle::QSvgCompOpStyle(QPainter::CompositionMode mode)
408QSvgCompOpStyle::~QSvgCompOpStyle()
411void QSvgCompOpStyle::apply(QPainter *p,
const QSvgNode *, QSvgExtraStates &)
413 m_oldMode = p->compositionMode();
414 p->setCompositionMode(m_mode);
417void QSvgCompOpStyle::revert(QPainter *p, QSvgExtraStates &)
419 p->setCompositionMode(m_oldMode);
422QSvgStyleProperty::Type QSvgCompOpStyle::type()
const
427QSvgOffsetStyle::~QSvgOffsetStyle()
430void QSvgOffsetStyle::apply(QPainter *,
const QSvgNode *, QSvgExtraStates &)
434void QSvgOffsetStyle::revert(QPainter *, QSvgExtraStates &)
438QSvgStyleProperty::Type QSvgOffsetStyle::type()
const
443QSvgOpacityStyle::QSvgOpacityStyle(qreal opacity)
449QSvgOpacityStyle::~QSvgOpacityStyle()
452void QSvgOpacityStyle::apply(QPainter *p,
const QSvgNode *, QSvgExtraStates &)
454 m_oldOpacity = p->opacity();
455 p->setOpacity(m_opacity * m_oldOpacity);
458void QSvgOpacityStyle::revert(QPainter *p, QSvgExtraStates &)
460 p->setOpacity(m_oldOpacity);
463QSvgStyleProperty::Type QSvgOpacityStyle::type()
const
468QSvgStaticStyle::QSvgStaticStyle()
470QSvgStaticStyle::~QSvgStaticStyle()
473void QSvgStaticStyle::apply(QPainter *p,
const QSvgNode *node, QSvgExtraStates &states)
475 for (
auto &prop : m_properties) {
477 prop->apply(p, node, states);
481void QSvgStaticStyle::revert(QPainter *p, QSvgExtraStates &states)
483 for (
auto &prop : m_properties) {
485 prop->revert(p, states);
491QColor sumValue(
const QColor &c1,
const QColor &c2)
493 QRgb rgb1 = c1.rgba();
494 QRgb rgb2 = c2.rgba();
495 int sumRed = qRed(rgb1) + qRed(rgb2);
496 int sumGreen = qGreen(rgb1) + qGreen(rgb2);
497 int sumBlue = qBlue(rgb1) + qBlue(rgb2);
499 QRgb sumRgb = qRgba(qBound(0, sumRed, 255),
500 qBound(0, sumGreen, 255),
501 qBound(0, sumBlue, 255),
504 return QColor(sumRgb);
507qreal sumValue(qreal value1, qreal value2)
509 qreal sumValue = value1 + value2;
510 return qBound(0.0, sumValue, 1.0);
515QSvgAnimatedStyle::QSvgAnimatedStyle()
519QSvgAnimatedStyle::~QSvgAnimatedStyle()
523void QSvgAnimatedStyle::apply(QPainter *p,
const QSvgNode *node, QSvgExtraStates &states)
525 QSharedPointer<QSvgAbstractAnimator> animator = states.doc()->animator();
526 QList<QSvgAbstractAnimation *> nodeAnims = animator->animationsForNode(node);
528 savePaintingState(p, node, states);
529 if (nodeAnims.isEmpty())
532 QSvgStyleState currentStyle = m_static;
533 for (
const QSvgAbstractAnimation *anim : std::as_const(nodeAnims)) {
534 if (!anim->isActive())
537 fetchStyleState(anim, currentStyle);
540 applyStyle(p, states, currentStyle);
543void QSvgAnimatedStyle::revert(QPainter *p, QSvgExtraStates &states)
545 p->setWorldTransform(m_worldTransform);
546 p->setBrush(m_static.fill);
547 p->setPen(m_static.stroke);
548 p->setOpacity(m_static.opacity);
549 states.fillOpacity = m_static.fillOpacity;
550 states.strokeOpacity = m_static.strokeOpacity;
553void QSvgAnimatedStyle::savePaintingState(
const QPainter *p,
const QSvgNode *node, QSvgExtraStates &states)
555 m_worldTransform = p->worldTransform();
556 if (
auto prop = node->style().property(QSvgStyleProperty::Transform))
557 m_static.transform = (
static_cast<QSvgTransformStyle*>(prop))->qtransform();
559 if (
auto prop = node->style().property(QSvgStyleProperty::Offset)) {
560 QSvgOffsetStyle *offset =
static_cast<QSvgOffsetStyle*>(prop);
561 m_static.offsetPath = offset->path();
562 m_static.offsetRotateType = offset->rotateType();
563 m_static.offsetRotate = offset->rotateAngle();
566 m_static.fill = p->brush();
567 m_static.stroke = p->pen();
568 m_static.fillOpacity = states.fillOpacity;
569 m_static.strokeOpacity = states.strokeOpacity;
570 m_static.opacity = p->opacity();
571 m_transformToNode = m_static.transform.inverted() * m_worldTransform;
574void QSvgAnimatedStyle::fetchStyleState(
const QSvgAbstractAnimation *animation, QSvgStyleState ¤tStyle)
576 bool replace = animation->animationType() == QSvgAbstractAnimation::CSS ?
true :
577 (
static_cast<
const QSvgAnimateNode *>(animation))->additiveType() == QSvgAnimateNode::Replace;
579 QList<QSvgAbstractAnimatedProperty *> properties = animation->properties();
580 for (
const QSvgAbstractAnimatedProperty *property : std::as_const(properties)) {
582 QBrush brush = currentStyle.fill;
583 QColor brushColor = brush.color();
584 QColor animatedColor = property->interpolatedValue().value<QColor>();
585 QColor sumOrReplaceColor = replace ? animatedColor : sumValue(brushColor, animatedColor);
586 brush.setColor(sumOrReplaceColor);
587 currentStyle.fill = brush;
588 }
else if (property->propertyName() ==
QStringLiteral(
"stroke")) {
589 QPen &pen = currentStyle.stroke;
590 QBrush penBrush = pen.brush();
591 QColor penColor = penBrush.color();
592 QColor animatedColor = property->interpolatedValue().value<QColor>();
593 QColor sumOrReplaceColor = replace ? animatedColor : sumValue(penColor, animatedColor);
594 penBrush.setColor(sumOrReplaceColor);
595 penBrush.setStyle(Qt::SolidPattern);
596 pen.setBrush(penBrush);
597 }
else if (property->propertyName() ==
QStringLiteral(
"transform")) {
598 QTransform animatedTransform = property->interpolatedValue().value<QTransform>();
599 QTransform sumOrReplaceTransform = replace ? animatedTransform : animatedTransform * currentStyle.transform;
600 currentStyle.transform = sumOrReplaceTransform;
601 }
else if (property->propertyName() ==
QStringLiteral(
"fill-opacity")) {
602 qreal animatedFillOpacity = property->interpolatedValue().value<qreal>();
603 qreal sumOrReplaceOpacity = replace ? animatedFillOpacity : sumValue(currentStyle.fillOpacity, animatedFillOpacity);
604 currentStyle.fillOpacity = sumOrReplaceOpacity;
605 }
else if (property->propertyName() ==
QStringLiteral(
"stroke-opacity")) {
606 qreal animatedStrokeOpacity = property->interpolatedValue().value<qreal>();
607 qreal sumOrReplaceOpacity = replace ? animatedStrokeOpacity : sumValue(currentStyle.strokeOpacity, animatedStrokeOpacity);
608 currentStyle.strokeOpacity = sumOrReplaceOpacity;
609 }
else if (property->propertyName() ==
QStringLiteral(
"opacity")) {
610 qreal animatedOpacity = property->interpolatedValue().value<qreal>();
611 qreal sumOrReplaceOpacity = replace ? animatedOpacity : sumValue(currentStyle.opacity, animatedOpacity);
612 currentStyle.opacity = sumOrReplaceOpacity;
613 }
else if (property->propertyName() ==
QStringLiteral(
"offset-distance")) {
614 qreal offsetDistance = property->interpolatedValue().value<qreal>();
615 currentStyle.offsetDistance = offsetDistance;
620void QSvgAnimatedStyle::applyStyle(QPainter *p, QSvgExtraStates &states,
const QSvgStyleState ¤tStyle)
622 p->setBrush(currentStyle.fill);
623 states.fillOpacity = currentStyle.fillOpacity;
624 p->setPen(currentStyle.stroke);
625 states.strokeOpacity = currentStyle.strokeOpacity;
626 p->setOpacity(currentStyle.opacity);
628 QTransform transform = currentStyle.transform;
630 if (m_static.offsetPath) {
631 qreal offsetDistance = currentStyle.offsetDistance;
632 qreal angle = m_static.offsetPath.value().angleAtPercent(offsetDistance);
633 QPointF position = m_static.offsetPath.value().pointAtPercent(offsetDistance);
634 offset.translate(position.x(), position.y());
636 switch (m_static.offsetRotateType) {
637 case QtSvg::OffsetRotateType::Auto:
638 offset.rotate(-angle);
640 case QtSvg::OffsetRotateType::Angle:
641 offset.rotate(m_static.offsetRotate);
643 case QtSvg::OffsetRotateType::AutoAngle:
644 offset.rotate(m_static.offsetRotate - angle);
646 case QtSvg::OffsetRotateType::Reverse:
647 offset.rotate(180 - angle);
649 case QtSvg::OffsetRotateType::ReverseAngle:
650 offset.rotate(180 + m_static.offsetRotate - angle);
655 QTransform combinedTransform = transform * offset * m_transformToNode;
656 p->setWorldTransform(combinedTransform);
Combined button and popup list for selecting options.
#define QStringLiteral(str)