9#include "private/qsvganimate_p.h"
21QSvgExtraStates::QSvgExtraStates()
25 textAnchor(Qt::AlignLeft),
26 fontWeight(QFont::Normal),
27 fillRule(Qt::WindingFill),
30 imageRendering(QSvgQualityStyle::ImageRenderingAuto)
34QSvgStyleProperty::~QSvgStyleProperty()
38void QSvgPaintStyleProperty::apply(QPainter *,
const QSvgNode *, QSvgExtraStates &)
40 Q_ASSERT(!
"This should not be called!");
43void QSvgPaintStyleProperty::revert(QPainter *, QSvgExtraStates &)
45 Q_ASSERT(!
"This should not be called!");
49QSvgQualityStyle::QSvgQualityStyle(
int color)
50 : m_imageRendering(QSvgQualityStyle::ImageRenderingAuto)
51 , m_oldImageRendering(QSvgQualityStyle::ImageRenderingAuto)
52 , m_imageRenderingSet(0)
57void QSvgQualityStyle::setImageRendering(ImageRendering hint) {
58 m_imageRendering = hint;
59 m_imageRenderingSet = 1;
62void QSvgQualityStyle::apply(QPainter *p,
const QSvgNode *, QSvgExtraStates &states)
64 m_oldImageRendering = states.imageRendering;
65 if (m_imageRenderingSet) {
66 states.imageRendering = m_imageRendering;
68 if (m_imageRenderingSet) {
70 if (m_imageRendering == ImageRenderingAuto)
74 smooth = (m_imageRendering == ImageRenderingOptimizeQuality);
75 p->setRenderHint(QPainter::SmoothPixmapTransform, smooth);
79void QSvgQualityStyle::revert(QPainter *p, QSvgExtraStates &states)
81 if (m_imageRenderingSet) {
82 states.imageRendering = m_oldImageRendering;
84 if (m_oldImageRendering == ImageRenderingAuto)
87 smooth = (m_oldImageRendering == ImageRenderingOptimizeQuality);
88 p->setRenderHint(QPainter::SmoothPixmapTransform, smooth);
92QSvgFillStyle::QSvgFillStyle()
94 , m_fillRule(Qt::WindingFill)
95 , m_oldFillRule(Qt::WindingFill)
98 , m_paintStyleResolved(1)
100 , m_fillOpacitySet(0)
105void QSvgFillStyle::setFillRule(Qt::FillRule f)
111void QSvgFillStyle::setFillOpacity(qreal opacity)
113 m_fillOpacitySet = 1;
114 m_fillOpacity = opacity;
117void QSvgFillStyle::setFillStyle(QSvgPaintStyleProperty* style)
123void QSvgFillStyle::setBrush(QBrush brush)
125 m_fill = std::move(brush);
130void QSvgFillStyle::apply(QPainter *p,
const QSvgNode *n, QSvgExtraStates &states)
132 m_oldFill = p->brush();
133 m_oldFillRule = states.fillRule;
134 m_oldFillOpacity = states.fillOpacity;
137 states.fillRule = m_fillRule;
140 p->setBrush(m_style->brush(p, n, states));
144 if (m_fillOpacitySet)
145 states.fillOpacity = m_fillOpacity;
148void QSvgFillStyle::revert(QPainter *p, QSvgExtraStates &states)
150 if (m_fillOpacitySet)
151 states.fillOpacity = m_oldFillOpacity;
153 p->setBrush(m_oldFill);
155 states.fillRule = m_oldFillRule;
158QSvgViewportFillStyle::QSvgViewportFillStyle(
const QBrush &brush)
159 : m_viewportFill(brush)
163void QSvgViewportFillStyle::apply(QPainter *p,
const QSvgNode *, QSvgExtraStates &)
165 m_oldFill = p->brush();
166 p->setBrush(m_viewportFill);
169void QSvgViewportFillStyle::revert(QPainter *p, QSvgExtraStates &)
171 p->setBrush(m_oldFill);
174QSvgFontStyle::QSvgFontStyle(QSvgFont *font, QSvgTinyDocument *doc)
186QSvgFontStyle::QSvgFontStyle()
198void QSvgFontStyle::apply(QPainter *p,
const QSvgNode *, QSvgExtraStates &states)
200 m_oldQFont = p->font();
201 m_oldSvgFont = states.svgFont;
202 m_oldTextAnchor = states.textAnchor;
203 m_oldWeight = states.fontWeight;
206 states.textAnchor = m_textAnchor;
208 QFont font = m_oldQFont;
210 states.svgFont = m_svgFont;
211 font.setFamilies(m_qfont.families());
215 font.setPointSizeF(m_qfont.pointSizeF());
218 font.setStyle(m_qfont.style());
221 font.setCapitalization(m_qfont.capitalization());
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));
229 states.fontWeight = m_weight;
231 font.setWeight(QFont::Weight(qBound(
static_cast<
int>(QFont::Weight::Thin),
233 static_cast<
int>(QFont::Weight::Black))));
239void QSvgFontStyle::revert(QPainter *p, QSvgExtraStates &states)
241 p->setFont(m_oldQFont);
242 states.svgFont = m_oldSvgFont;
243 states.textAnchor = m_oldTextAnchor;
244 states.fontWeight = m_oldWeight;
247QSvgStrokeStyle::QSvgStrokeStyle()
248 : m_strokeOpacity(1.0)
249 , m_oldStrokeOpacity(0.0)
250 , m_strokeDashOffset(0)
251 , m_oldStrokeDashOffset(0)
253 , m_paintStyleResolved(1)
255 , m_oldVectorEffect(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)
268void QSvgStrokeStyle::apply(QPainter *p,
const QSvgNode *n, QSvgExtraStates &states)
270 m_oldStroke = p->pen();
271 m_oldStrokeOpacity = states.strokeOpacity;
272 m_oldStrokeDashOffset = states.strokeDashOffset;
273 m_oldVectorEffect = states.vectorEffect;
277 qreal oldWidth = pen.widthF();
278 qreal width = m_stroke.widthF();
283 qreal scale = oldWidth / width;
285 if (m_strokeOpacitySet)
286 states.strokeOpacity = m_strokeOpacity;
288 if (m_vectorEffectSet)
289 states.vectorEffect = m_vectorEffect;
293 pen.setBrush(m_style->brush(p, n, states));
295 pen.setBrush(m_stroke.brush());
298 if (m_strokeWidthSet)
299 pen.setWidthF(m_stroke.widthF());
301 bool setDashOffsetNeeded =
false;
303 if (m_strokeDashOffsetSet) {
304 states.strokeDashOffset = m_strokeDashOffset;
305 setDashOffsetNeeded =
true;
308 if (m_strokeDashArraySet) {
309 if (m_stroke.style() == Qt::SolidLine) {
310 pen.setStyle(Qt::SolidLine);
311 }
else if (m_strokeWidthSet || oldWidth == 1) {
313 pen.setDashPattern(m_stroke.dashPattern());
314 setDashOffsetNeeded =
true;
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;
323 }
else if (m_strokeWidthSet && pen.style() != Qt::SolidLine && scale != 1) {
325 QList<qreal> dashes = pen.dashPattern();
326 for (
int i = 0; i < dashes.size(); ++i)
328 pen.setDashPattern(dashes);
329 setDashOffsetNeeded =
true;
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());
342 if (setDashOffsetNeeded && pen.style() != Qt::SolidLine) {
343 qreal currentWidth = pen.widthF();
344 if (currentWidth == 0)
346 pen.setDashOffset(states.strokeDashOffset / currentWidth);
349 pen.setCosmetic(states.vectorEffect);
354void QSvgStrokeStyle::revert(QPainter *p, QSvgExtraStates &states)
356 p->setPen(m_oldStroke);
357 states.strokeOpacity = m_oldStrokeOpacity;
358 states.strokeDashOffset = m_oldStrokeDashOffset;
359 states.vectorEffect = m_oldVectorEffect;
362void QSvgStrokeStyle::setDashArray(
const QList<qreal> &dashes)
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)
371 m_stroke.setDashPattern(d);
373 m_stroke.setDashPattern(dashes);
375 m_strokeDashArraySet = 1;
378QSvgSolidColorStyle::QSvgSolidColorStyle(
const QColor &color)
379 : m_solidColor(color)
383QSvgGradientStyle::QSvgGradientStyle(QGradient *grad)
384 : m_gradient(grad), m_gradientStopsSet(
false)
388QBrush QSvgGradientStyle::brush(QPainter *,
const QSvgNode *, QSvgExtraStates &)
390 if (!m_link.isEmpty()) {
395 if (!m_gradientStopsSet) {
396 m_gradient->setStops(QGradientStops() << QGradientStop(0.0, QColor(0, 0, 0, 0)));
397 m_gradientStopsSet =
true;
400 QBrush b(*m_gradient);
402 if (!m_transform.isIdentity())
403 b.setTransform(m_transform);
409void QSvgGradientStyle::setTransform(
const QTransform &transform)
411 m_transform = transform;
414QSvgPatternStyle::QSvgPatternStyle(QSvgPattern *pattern)
420QBrush QSvgPatternStyle::brush(QPainter *p,
const QSvgNode *node, QSvgExtraStates &states)
422 QBrush b(m_pattern->patternImage(p, states, node));
423 b.setTransform(m_pattern->appliedTransform());
427QSvgTransformStyle::QSvgTransformStyle(
const QTransform &trans)
432void QSvgTransformStyle::apply(QPainter *p,
const QSvgNode *, QSvgExtraStates &)
434 m_oldWorldTransform.push(p->worldTransform());
435 p->setWorldTransform(m_transform,
true);
438void QSvgTransformStyle::revert(QPainter *p, QSvgExtraStates &)
440 p->setWorldTransform(m_oldWorldTransform.pop(),
false );
443QSvgStyleProperty::Type QSvgQualityStyle::type()
const
448QSvgStyleProperty::Type QSvgFillStyle::type()
const
453QSvgStyleProperty::Type QSvgViewportFillStyle::type()
const
455 return VIEWPORT_FILL;
458QSvgStyleProperty::Type QSvgFontStyle::type()
const
463QSvgStyleProperty::Type QSvgStrokeStyle::type()
const
468QSvgStyleProperty::Type QSvgSolidColorStyle::type()
const
473QSvgStyleProperty::Type QSvgGradientStyle::type()
const
478QSvgStyleProperty::Type QSvgPatternStyle::type()
const
483QSvgStyleProperty::Type QSvgTransformStyle::type()
const
489QSvgCompOpStyle::QSvgCompOpStyle(QPainter::CompositionMode mode)
495void QSvgCompOpStyle::apply(QPainter *p,
const QSvgNode *, QSvgExtraStates &)
497 m_oldMode = p->compositionMode();
498 p->setCompositionMode(m_mode);
501void QSvgCompOpStyle::revert(QPainter *p, QSvgExtraStates &)
503 p->setCompositionMode(m_oldMode);
506QSvgStyleProperty::Type QSvgCompOpStyle::type()
const
511void QSvgOffsetStyle::apply(QPainter *,
const QSvgNode *, QSvgExtraStates &)
515void QSvgOffsetStyle::revert(QPainter *, QSvgExtraStates &)
519QSvgStyleProperty::Type QSvgOffsetStyle::type()
const
524QSvgOpacityStyle::QSvgOpacityStyle(qreal opacity)
525 : m_opacity(opacity), m_oldOpacity(0)
530void QSvgOpacityStyle::apply(QPainter *p,
const QSvgNode *, QSvgExtraStates &)
532 m_oldOpacity = p->opacity();
533 p->setOpacity(m_opacity * m_oldOpacity);
536void QSvgOpacityStyle::revert(QPainter *p, QSvgExtraStates &)
538 p->setOpacity(m_oldOpacity);
541QSvgStyleProperty::Type QSvgOpacityStyle::type()
const
546void QSvgGradientStyle::setStopLink(
const QString &link, QSvgTinyDocument *doc)
552void QSvgGradientStyle::resolveStops()
555 resolveStops_helper(&visited);
558void QSvgGradientStyle::resolveStops_helper(QStringList *visited)
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();
572 qWarning(
"Could not resolve property : %s",
qPrintable(m_link));
578QSvgStaticStyle::QSvgStaticStyle()
593QSvgStaticStyle::~QSvgStaticStyle()
597void QSvgStaticStyle::apply(QPainter *p,
const QSvgNode *node, QSvgExtraStates &states)
600 quality->apply(p, node, states);
604 fill->apply(p, node, states);
608 viewportFill->apply(p, node, states);
612 font->apply(p, node, states);
616 stroke->apply(p, node, states);
620 transform->apply(p, node, states);
624 opacity->apply(p, node, states);
628 compop->apply(p, node, states);
632void QSvgStaticStyle::revert(QPainter *p, QSvgExtraStates &states)
635 quality->revert(p, states);
639 fill->revert(p, states);
643 viewportFill->revert(p, states);
647 font->revert(p, states);
651 stroke->revert(p, states);
655 transform->revert(p, states);
659 opacity->revert(p, states);
663 compop->revert(p, states);
669QColor sumValue(
const QColor &c1,
const QColor &c2)
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);
677 QRgb sumRgb = qRgba(qBound(0, sumRed, 255),
678 qBound(0, sumGreen, 255),
679 qBound(0, sumBlue, 255),
682 return QColor(sumRgb);
685qreal sumValue(qreal value1, qreal value2)
687 qreal sumValue = value1 + value2;
688 return qBound(0.0, sumValue, 1.0);
693QSvgAnimatedStyle::QSvgAnimatedStyle()
697QSvgAnimatedStyle::~QSvgAnimatedStyle()
701void QSvgAnimatedStyle::apply(QPainter *p,
const QSvgNode *node, QSvgExtraStates &states)
703 QSharedPointer<QSvgAbstractAnimator> animator = node->document()->animator();
704 QList<QSvgAbstractAnimation *> nodeAnims = animator->animationsForNode(node);
706 savePaintingState(p, node, states);
707 if (nodeAnims.isEmpty())
710 QSvgStyleState currentStyle = m_static;
711 for (
auto anim : nodeAnims) {
712 if (!anim->isActive())
715 fetchStyleState(anim, currentStyle);
718 applyStyle(p, states, currentStyle);
721void QSvgAnimatedStyle::revert(QPainter *p, QSvgExtraStates &states)
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;
731void QSvgAnimatedStyle::savePaintingState(
const QPainter *p,
const QSvgNode *node, QSvgExtraStates &states)
733 QSvgStaticStyle style = node->style();
734 m_worldTransform = p->worldTransform();
736 m_static.transform = style.transform->qtransform();
739 m_static.offsetPath = style.offset->path();
740 m_static.offsetRotateType = style.offset->rotateType();
741 m_static.offsetRotate = style.offset->rotateAngle();
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;
752void QSvgAnimatedStyle::fetchStyleState(
const QSvgAbstractAnimation *animation, QSvgStyleState ¤tStyle)
754 bool replace = animation->animationType() == QSvgAbstractAnimation::CSS ?
true :
755 (
static_cast<
const QSvgAnimateNode *>(animation))->additiveType() == QSvgAnimateNode::Replace;
757 QList<QSvgAbstractAnimatedProperty *> properties = animation->properties();
758 for (
const QSvgAbstractAnimatedProperty *property : std::as_const(properties)) {
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;
798void QSvgAnimatedStyle::applyStyle(QPainter *p, QSvgExtraStates &states,
const QSvgStyleState ¤tStyle)
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);
806 QTransform transform = currentStyle.transform;
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());
814 switch (m_static.offsetRotateType) {
815 case QtSvg::OffsetRotateType::Auto:
816 offset.rotate(-angle);
818 case QtSvg::OffsetRotateType::Angle:
819 offset.rotate(m_static.offsetRotate);
821 case QtSvg::OffsetRotateType::AutoAngle:
822 offset.rotate(m_static.offsetRotate - angle);
824 case QtSvg::OffsetRotateType::Reverse:
825 offset.rotate(180 - angle);
827 case QtSvg::OffsetRotateType::ReverseAngle:
828 offset.rotate(180 + m_static.offsetRotate - angle);
833 QTransform combinedTransform = transform * offset * m_transformToNode;
834 p->setWorldTransform(combinedTransform);
Combined button and popup list for selecting options.
#define qPrintable(string)
#define QStringLiteral(str)