10#include "private/qsvganimate_p.h"
19QSvgExtraStates::QSvgExtraStates()
23 textAnchor(Qt::AlignLeft),
24 fontWeight(QFont::Normal),
25 fillRule(Qt::WindingFill),
28 imageRendering(QSvgQualityStyle::ImageRenderingAuto)
32QSvgStyleProperty::~QSvgStyleProperty()
36void QSvgPaintStyleProperty::apply(QPainter *,
const QSvgNode *, QSvgExtraStates &)
38 Q_ASSERT(!
"This should not be called!");
41void QSvgPaintStyleProperty::revert(QPainter *, QSvgExtraStates &)
43 Q_ASSERT(!
"This should not be called!");
47QSvgQualityStyle::QSvgQualityStyle(
int color)
48 : m_imageRendering(QSvgQualityStyle::ImageRenderingAuto)
49 , m_oldImageRendering(QSvgQualityStyle::ImageRenderingAuto)
50 , m_imageRenderingSet(0)
55void QSvgQualityStyle::setImageRendering(ImageRendering hint) {
56 m_imageRendering = hint;
57 m_imageRenderingSet = 1;
60void QSvgQualityStyle::apply(QPainter *p,
const QSvgNode *, QSvgExtraStates &states)
62 m_oldImageRendering = states.imageRendering;
63 if (m_imageRenderingSet) {
64 states.imageRendering = m_imageRendering;
66 if (m_imageRenderingSet) {
68 if (m_imageRendering == ImageRenderingAuto)
72 smooth = (m_imageRendering == ImageRenderingOptimizeQuality);
73 p->setRenderHint(QPainter::SmoothPixmapTransform, smooth);
77void QSvgQualityStyle::revert(QPainter *p, QSvgExtraStates &states)
79 if (m_imageRenderingSet) {
80 states.imageRendering = m_oldImageRendering;
82 if (m_oldImageRendering == ImageRenderingAuto)
85 smooth = (m_oldImageRendering == ImageRenderingOptimizeQuality);
86 p->setRenderHint(QPainter::SmoothPixmapTransform, smooth);
90QSvgFillStyle::QSvgFillStyle()
92 , m_fillRule(Qt::WindingFill)
93 , m_oldFillRule(Qt::WindingFill)
96 , m_paintStyleResolved(1)
103void QSvgFillStyle::setFillRule(Qt::FillRule f)
109void QSvgFillStyle::setFillOpacity(qreal opacity)
111 m_fillOpacitySet = 1;
112 m_fillOpacity = opacity;
115void QSvgFillStyle::setFillStyle(QSvgPaintStyleProperty* style)
121void QSvgFillStyle::setBrush(QBrush brush)
123 m_fill = std::move(brush);
128void QSvgFillStyle::apply(QPainter *p,
const QSvgNode *n, QSvgExtraStates &states)
130 m_oldFill = p->brush();
131 m_oldFillRule = states.fillRule;
132 m_oldFillOpacity = states.fillOpacity;
135 states.fillRule = m_fillRule;
138 p->setBrush(m_style->brush(p, n, states));
142 if (m_fillOpacitySet)
143 states.fillOpacity = m_fillOpacity;
146void QSvgFillStyle::revert(QPainter *p, QSvgExtraStates &states)
148 if (m_fillOpacitySet)
149 states.fillOpacity = m_oldFillOpacity;
151 p->setBrush(m_oldFill);
153 states.fillRule = m_oldFillRule;
156QSvgViewportFillStyle::QSvgViewportFillStyle(
const QBrush &brush)
157 : m_viewportFill(brush)
161void QSvgViewportFillStyle::apply(QPainter *p,
const QSvgNode *, QSvgExtraStates &)
163 m_oldFill = p->brush();
164 p->setBrush(m_viewportFill);
167void QSvgViewportFillStyle::revert(QPainter *p, QSvgExtraStates &)
169 p->setBrush(m_oldFill);
172QSvgFontStyle::QSvgFontStyle(QSvgFont *font, QSvgDocument *doc)
184QSvgFontStyle::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 + 100,
static_cast<
int>(QFont::Black));
224 }
else if (m_weight == LIGHTER) {
225 states.fontWeight = qMax(states.fontWeight - 100,
static_cast<
int>(QFont::Thin));
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()
246 : m_strokeOpacity(1.0)
247 , m_oldStrokeOpacity(0.0)
248 , m_strokeDashOffset(0)
249 , m_oldStrokeDashOffset(0)
251 , m_paintStyleResolved(1)
253 , m_oldVectorEffect(0)
255 , m_strokeDashArraySet(0)
256 , m_strokeDashOffsetSet(0)
257 , m_strokeLineCapSet(0)
258 , m_strokeLineJoinSet(0)
259 , m_strokeMiterLimitSet(0)
260 , m_strokeOpacitySet(0)
261 , m_strokeWidthSet(0)
262 , m_vectorEffectSet(0)
266void QSvgStrokeStyle::apply(QPainter *p,
const QSvgNode *n, QSvgExtraStates &states)
268 m_oldStroke = p->pen();
269 m_oldStrokeOpacity = states.strokeOpacity;
270 m_oldStrokeDashOffset = states.strokeDashOffset;
271 m_oldVectorEffect = states.vectorEffect;
275 qreal oldWidth = pen.widthF();
276 qreal width = m_stroke.widthF();
281 qreal scale = oldWidth / width;
283 if (m_strokeOpacitySet)
284 states.strokeOpacity = m_strokeOpacity;
286 if (m_vectorEffectSet)
287 states.vectorEffect = m_vectorEffect;
291 pen.setBrush(m_style->brush(p, n, states));
293 pen.setBrush(m_stroke.brush());
296 if (m_strokeWidthSet)
297 pen.setWidthF(m_stroke.widthF());
299 bool setDashOffsetNeeded =
false;
301 if (m_strokeDashOffsetSet) {
302 states.strokeDashOffset = m_strokeDashOffset;
303 setDashOffsetNeeded =
true;
306 if (m_strokeDashArraySet) {
307 if (m_stroke.style() == Qt::SolidLine) {
308 pen.setStyle(Qt::SolidLine);
309 }
else if (m_strokeWidthSet || oldWidth == 1) {
311 pen.setDashPattern(m_stroke.dashPattern());
312 setDashOffsetNeeded =
true;
315 QList<qreal> dashes = m_stroke.dashPattern();
316 for (
int i = 0; i < dashes.size(); ++i)
317 dashes[i] /= oldWidth;
318 pen.setDashPattern(dashes);
319 setDashOffsetNeeded =
true;
321 }
else if (m_strokeWidthSet && pen.style() != Qt::SolidLine && scale != 1) {
323 QList<qreal> dashes = pen.dashPattern();
324 for (
int i = 0; i < dashes.size(); ++i)
326 pen.setDashPattern(dashes);
327 setDashOffsetNeeded =
true;
330 if (m_strokeLineCapSet)
331 pen.setCapStyle(m_stroke.capStyle());
332 if (m_strokeLineJoinSet)
333 pen.setJoinStyle(m_stroke.joinStyle());
334 if (m_strokeMiterLimitSet)
335 pen.setMiterLimit(m_stroke.miterLimit());
340 if (setDashOffsetNeeded && pen.style() != Qt::SolidLine) {
341 qreal currentWidth = pen.widthF();
342 if (currentWidth == 0)
344 pen.setDashOffset(states.strokeDashOffset / currentWidth);
347 pen.setCosmetic(states.vectorEffect);
352void QSvgStrokeStyle::revert(QPainter *p, QSvgExtraStates &states)
354 p->setPen(m_oldStroke);
355 states.strokeOpacity = m_oldStrokeOpacity;
356 states.strokeDashOffset = m_oldStrokeDashOffset;
357 states.vectorEffect = m_oldVectorEffect;
360void QSvgStrokeStyle::setDashArray(
const QList<qreal> &dashes)
362 if (m_strokeWidthSet) {
363 QList<qreal> d = dashes;
364 qreal w = m_stroke.widthF();
365 if (w != 0 && w != 1) {
366 for (
int i = 0; i < d.size(); ++i)
369 m_stroke.setDashPattern(d);
371 m_stroke.setDashPattern(dashes);
373 m_strokeDashArraySet = 1;
376QSvgSolidColorStyle::QSvgSolidColorStyle(
const QColor &color)
377 : m_solidColor(color)
381QSvgGradientStyle::QSvgGradientStyle(QGradient *grad)
383 , m_gradientStopsSet(
false)
387QBrush QSvgGradientStyle::brush(QPainter *,
const QSvgNode *, QSvgExtraStates &)
389 if (!m_link.isEmpty()) {
394 if (!m_gradientStopsSet) {
395 m_gradient->setStops(QGradientStops() << QGradientStop(0.0, QColor(0, 0, 0, 0)));
396 m_gradientStopsSet =
true;
399 QBrush b(*m_gradient);
401 if (!m_transform.isIdentity())
402 b.setTransform(m_transform);
408void QSvgGradientStyle::setTransform(
const QTransform &transform)
410 m_transform = transform;
413QSvgPatternStyle::QSvgPatternStyle(QSvgPattern *pattern)
419QBrush QSvgPatternStyle::brush(QPainter *p,
const QSvgNode *node, QSvgExtraStates &states)
421 QBrush b(m_pattern->patternImage(p, states, node));
422 b.setTransform(m_pattern->appliedTransform());
426QSvgTransformStyle::QSvgTransformStyle(
const QTransform &trans)
431void QSvgTransformStyle::apply(QPainter *p,
const QSvgNode *, QSvgExtraStates &)
433 m_oldWorldTransform.push(p->worldTransform());
434 p->setWorldTransform(m_transform,
true);
437void QSvgTransformStyle::revert(QPainter *p, QSvgExtraStates &)
439 p->setWorldTransform(m_oldWorldTransform.pop(),
false );
442QSvgStyleProperty::Type QSvgQualityStyle::type()
const
447QSvgStyleProperty::Type QSvgFillStyle::type()
const
452QSvgStyleProperty::Type QSvgViewportFillStyle::type()
const
454 return VIEWPORT_FILL;
457QSvgStyleProperty::Type QSvgFontStyle::type()
const
462QSvgStyleProperty::Type QSvgStrokeStyle::type()
const
467QSvgStyleProperty::Type QSvgSolidColorStyle::type()
const
472QSvgStyleProperty::Type QSvgGradientStyle::type()
const
477QSvgStyleProperty::Type QSvgPatternStyle::type()
const
482QSvgStyleProperty::Type QSvgTransformStyle::type()
const
488QSvgCompOpStyle::QSvgCompOpStyle(QPainter::CompositionMode mode)
494void QSvgCompOpStyle::apply(QPainter *p,
const QSvgNode *, QSvgExtraStates &)
496 m_oldMode = p->compositionMode();
497 p->setCompositionMode(m_mode);
500void QSvgCompOpStyle::revert(QPainter *p, QSvgExtraStates &)
502 p->setCompositionMode(m_oldMode);
505QSvgStyleProperty::Type QSvgCompOpStyle::type()
const
510void QSvgOffsetStyle::apply(QPainter *,
const QSvgNode *, QSvgExtraStates &)
514void QSvgOffsetStyle::revert(QPainter *, QSvgExtraStates &)
518QSvgStyleProperty::Type QSvgOffsetStyle::type()
const
523QSvgOpacityStyle::QSvgOpacityStyle(qreal opacity)
524 : m_opacity(opacity), m_oldOpacity(0)
529void QSvgOpacityStyle::apply(QPainter *p,
const QSvgNode *, QSvgExtraStates &)
531 m_oldOpacity = p->opacity();
532 p->setOpacity(m_opacity * m_oldOpacity);
535void QSvgOpacityStyle::revert(QPainter *p, QSvgExtraStates &)
537 p->setOpacity(m_oldOpacity);
540QSvgStyleProperty::Type QSvgOpacityStyle::type()
const
545void QSvgGradientStyle::setStopLink(
const QString &link, QSvgDocument *doc)
551void QSvgGradientStyle::resolveStops()
554 resolveStops_helper(&visited);
557void QSvgGradientStyle::resolveStops_helper(QStringList *visited)
559 if (!m_link.isEmpty() && m_doc) {
560 QSvgStyleProperty *prop = m_doc->styleProperty(m_link);
561 if (prop && !visited->contains(m_link)) {
562 visited->append(m_link);
563 if (prop->type() == QSvgStyleProperty::GRADIENT) {
564 QSvgGradientStyle *st =
565 static_cast<QSvgGradientStyle*>(prop);
566 st->resolveStops_helper(visited);
567 m_gradient->setStops(st->qgradient()->stops());
568 m_gradientStopsSet = st->gradientStopsSet();
571 qWarning(
"Could not resolve property : %s",
qPrintable(m_link));
577QSvgStaticStyle::QSvgStaticStyle()
592QSvgStaticStyle::~QSvgStaticStyle()
596void QSvgStaticStyle::apply(QPainter *p,
const QSvgNode *node, QSvgExtraStates &states)
599 quality->apply(p, node, states);
603 fill->apply(p, node, states);
607 viewportFill->apply(p, node, states);
611 font->apply(p, node, states);
615 stroke->apply(p, node, states);
619 transform->apply(p, node, states);
623 opacity->apply(p, node, states);
627 compop->apply(p, node, states);
631void QSvgStaticStyle::revert(QPainter *p, QSvgExtraStates &states)
634 quality->revert(p, states);
638 fill->revert(p, states);
642 viewportFill->revert(p, states);
646 font->revert(p, states);
650 stroke->revert(p, states);
654 transform->revert(p, states);
658 opacity->revert(p, states);
662 compop->revert(p, states);
668QColor sumValue(
const QColor &c1,
const QColor &c2)
670 QRgb rgb1 = c1.rgba();
671 QRgb rgb2 = c2.rgba();
672 int sumRed = qRed(rgb1) + qRed(rgb2);
673 int sumGreen = qGreen(rgb1) + qGreen(rgb2);
674 int sumBlue = qBlue(rgb1) + qBlue(rgb2);
676 QRgb sumRgb = qRgba(qBound(0, sumRed, 255),
677 qBound(0, sumGreen, 255),
678 qBound(0, sumBlue, 255),
681 return QColor(sumRgb);
684qreal sumValue(qreal value1, qreal value2)
686 qreal sumValue = value1 + value2;
687 return qBound(0.0, sumValue, 1.0);
692QSvgAnimatedStyle::QSvgAnimatedStyle()
696QSvgAnimatedStyle::~QSvgAnimatedStyle()
700void QSvgAnimatedStyle::apply(QPainter *p,
const QSvgNode *node, QSvgExtraStates &states)
702 QSharedPointer<QSvgAbstractAnimator> animator = node->document()->animator();
703 QList<QSvgAbstractAnimation *> nodeAnims = animator->animationsForNode(node);
705 savePaintingState(p, node, states);
706 if (nodeAnims.isEmpty())
709 QSvgStyleState currentStyle = m_static;
710 for (
const QSvgAbstractAnimation *anim : std::as_const(nodeAnims)) {
711 if (!anim->isActive())
714 fetchStyleState(anim, currentStyle);
717 applyStyle(p, states, currentStyle);
720void QSvgAnimatedStyle::revert(QPainter *p, QSvgExtraStates &states)
722 p->setWorldTransform(m_worldTransform);
723 p->setBrush(m_static.fill);
724 p->setPen(m_static.stroke);
725 p->setOpacity(m_static.opacity);
726 states.fillOpacity = m_static.fillOpacity;
727 states.strokeOpacity = m_static.strokeOpacity;
730void QSvgAnimatedStyle::savePaintingState(
const QPainter *p,
const QSvgNode *node, QSvgExtraStates &states)
732 QSvgStaticStyle style = node->style();
733 m_worldTransform = p->worldTransform();
735 m_static.transform = style.transform->qtransform();
738 m_static.offsetPath = style.offset->path();
739 m_static.offsetRotateType = style.offset->rotateType();
740 m_static.offsetRotate = style.offset->rotateAngle();
743 m_static.fill = p->brush();
744 m_static.stroke = p->pen();
745 m_static.fillOpacity = states.fillOpacity;
746 m_static.strokeOpacity = states.strokeOpacity;
747 m_static.opacity = p->opacity();
748 m_transformToNode = m_static.transform.inverted() * m_worldTransform;
751void QSvgAnimatedStyle::fetchStyleState(
const QSvgAbstractAnimation *animation, QSvgStyleState ¤tStyle)
753 bool replace = animation->animationType() == QSvgAbstractAnimation::CSS ?
true :
754 (
static_cast<
const QSvgAnimateNode *>(animation))->additiveType() == QSvgAnimateNode::Replace;
756 QList<QSvgAbstractAnimatedProperty *> properties = animation->properties();
757 for (
const QSvgAbstractAnimatedProperty *property : std::as_const(properties)) {
759 QBrush brush = currentStyle.fill;
760 QColor brushColor = brush.color();
761 QColor animatedColor = property->interpolatedValue().value<QColor>();
762 QColor sumOrReplaceColor = replace ? animatedColor : sumValue(brushColor, animatedColor);
763 brush.setColor(sumOrReplaceColor);
764 currentStyle.fill = brush;
765 }
else if (property->propertyName() ==
QStringLiteral(
"stroke")) {
766 QPen &pen = currentStyle.stroke;
767 QBrush penBrush = pen.brush();
768 QColor penColor = penBrush.color();
769 QColor animatedColor = property->interpolatedValue().value<QColor>();
770 QColor sumOrReplaceColor = replace ? animatedColor : sumValue(penColor, animatedColor);
771 penBrush.setColor(sumOrReplaceColor);
772 penBrush.setStyle(Qt::SolidPattern);
773 pen.setBrush(penBrush);
774 }
else if (property->propertyName() ==
QStringLiteral(
"transform")) {
775 QTransform animatedTransform = property->interpolatedValue().value<QTransform>();
776 QTransform sumOrReplaceTransform = replace ? animatedTransform : animatedTransform * currentStyle.transform;
777 currentStyle.transform = sumOrReplaceTransform;
778 }
else if (property->propertyName() ==
QStringLiteral(
"fill-opacity")) {
779 qreal animatedFillOpacity = property->interpolatedValue().value<qreal>();
780 qreal sumOrReplaceOpacity = replace ? animatedFillOpacity : sumValue(currentStyle.fillOpacity, animatedFillOpacity);
781 currentStyle.fillOpacity = sumOrReplaceOpacity;
782 }
else if (property->propertyName() ==
QStringLiteral(
"stroke-opacity")) {
783 qreal animatedStrokeOpacity = property->interpolatedValue().value<qreal>();
784 qreal sumOrReplaceOpacity = replace ? animatedStrokeOpacity : sumValue(currentStyle.strokeOpacity, animatedStrokeOpacity);
785 currentStyle.strokeOpacity = sumOrReplaceOpacity;
786 }
else if (property->propertyName() ==
QStringLiteral(
"opacity")) {
787 qreal animatedOpacity = property->interpolatedValue().value<qreal>();
788 qreal sumOrReplaceOpacity = replace ? animatedOpacity : sumValue(currentStyle.opacity, animatedOpacity);
789 currentStyle.opacity = sumOrReplaceOpacity;
790 }
else if (property->propertyName() ==
QStringLiteral(
"offset-distance")) {
791 qreal offsetDistance = property->interpolatedValue().value<qreal>();
792 currentStyle.offsetDistance = offsetDistance;
797void QSvgAnimatedStyle::applyStyle(QPainter *p, QSvgExtraStates &states,
const QSvgStyleState ¤tStyle)
799 p->setBrush(currentStyle.fill);
800 states.fillOpacity = currentStyle.fillOpacity;
801 p->setPen(currentStyle.stroke);
802 states.strokeOpacity = currentStyle.strokeOpacity;
803 p->setOpacity(currentStyle.opacity);
805 QTransform transform = currentStyle.transform;
807 if (m_static.offsetPath) {
808 qreal offsetDistance = currentStyle.offsetDistance;
809 qreal angle = m_static.offsetPath.value().angleAtPercent(offsetDistance);
810 QPointF position = m_static.offsetPath.value().pointAtPercent(offsetDistance);
811 offset.translate(position.x(), position.y());
813 switch (m_static.offsetRotateType) {
814 case QtSvg::OffsetRotateType::Auto:
815 offset.rotate(-angle);
817 case QtSvg::OffsetRotateType::Angle:
818 offset.rotate(m_static.offsetRotate);
820 case QtSvg::OffsetRotateType::AutoAngle:
821 offset.rotate(m_static.offsetRotate - angle);
823 case QtSvg::OffsetRotateType::Reverse:
824 offset.rotate(180 - angle);
826 case QtSvg::OffsetRotateType::ReverseAngle:
827 offset.rotate(180 + m_static.offsetRotate - angle);
832 QTransform combinedTransform = transform * offset * m_transformToNode;
833 p->setWorldTransform(combinedTransform);
Combined button and popup list for selecting options.
#define qPrintable(string)
#define QStringLiteral(str)