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
qsvgcsshandler.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 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:critical reason:data-parser
4
6#include <QtSvg/private/qsvganimatedproperty_p.h>
7#include <QtSvg/private/qsvgutils_p.h>
8#include <QtGui/private/qmath_p.h>
9
11
12// Parses the angle from a string and convert it to degrees.
13static qreal qsvg_parseAngle(QStringView str, bool *ok = nullptr)
14{
15 QStringView numStr = str.trimmed();
16
17 if (numStr.isEmpty()) {
18 if (ok)
19 *ok = false;
20 return false;
21 }
22
23 qreal unitFactor;
24 if (numStr.endsWith(QLatin1String("deg"))) {
25 numStr.chop(3);
26 unitFactor = 1.0;
27 } else if (numStr.endsWith(QLatin1String("grad"))) {
28 numStr.chop(4);
29 // deg = grad * 0.9;
30 unitFactor = 0.9;
31 } else if (numStr.endsWith(QLatin1String("rad"))) {
32 numStr.chop(3);
33 unitFactor = 180.0 / Q_PI;
34 } else if (numStr.endsWith(QLatin1String("turn"))) {
35 numStr.chop(4);
36 // one circle = one turn
37 unitFactor = 360.0;
38 } else {
39 unitFactor = 0.0;
40 }
41
42 return QSvgUtils::toDouble(numStr, ok) * unitFactor;
43}
44
45void QSvgCssHandler::collectAnimations(const QCss::StyleSheet &sheet)
46{
47 auto sortFunction = [](QCss::AnimationRule::AnimationRuleSet r1, QCss::AnimationRule::AnimationRuleSet r2) {
48 return r1.keyFrame < r2.keyFrame;
49 };
50
51 QList<QCss::AnimationRule> animationRules = sheet.animationRules;
52 for (QCss::AnimationRule rule : animationRules) {
53 std::sort(rule.ruleSets.begin(), rule.ruleSets.end(), sortFunction);
54 m_animations[rule.animName] = rule;
55 }
56}
57
58QSvgCssAnimation *QSvgCssHandler::createAnimation(const QString &name)
59{
60 if (!m_animations.contains(name))
61 return nullptr;
62
63 QCss::AnimationRule animationRule = m_animations[name];
64 QHash<QString, QSvgAbstractAnimatedProperty*> animatedProperies;
65 QSvgCssAnimation *animation = new QSvgCssAnimation;
66
67 for (const auto &ruleSet : std::as_const(animationRule.ruleSets)) {
68 for (QCss::Declaration decl : ruleSet.declarations) {
69 if (decl.d->property == QStringLiteral("fill") || decl.d->property == QStringLiteral("stroke")) {
70 QSvgAnimatedPropertyColor *prop = nullptr;
71 if (!animatedProperies.contains(decl.d->property))
72 animatedProperies[decl.d->property] = QSvgAbstractAnimatedProperty::createAnimatedProperty(decl.d->property);
73 prop = static_cast<QSvgAnimatedPropertyColor *>(animatedProperies[decl.d->property]);
74 prop->appendKeyFrame(ruleSet.keyFrame);
75 updateColorProperty(decl, prop);
76 } else if (decl.d->property == QStringLiteral("transform")) {
77 QSvgAnimatedPropertyTransform *prop = nullptr;
78 if (!animatedProperies.contains(decl.d->property))
79 animatedProperies[decl.d->property] = QSvgAbstractAnimatedProperty::createAnimatedProperty(decl.d->property);
80 prop = static_cast<QSvgAnimatedPropertyTransform *>(animatedProperies[decl.d->property]);
81 prop->appendKeyFrame(ruleSet.keyFrame);
82 updateTransformProperty(decl, prop);
83 } else if (decl.d->property == QStringLiteral("fill-opacity") || decl.d->property == QStringLiteral("stroke-opacity")
84 || decl.d->property == QStringLiteral("opacity")) {
85 QSvgAnimatedPropertyFloat *prop = nullptr;
86 if (!animatedProperies.contains(decl.d->property))
87 animatedProperies[decl.d->property] = QSvgAbstractAnimatedProperty::createAnimatedProperty(decl.d->property);
88 prop = static_cast<QSvgAnimatedPropertyFloat *>(animatedProperies[decl.d->property]);
89 prop->appendKeyFrame(ruleSet.keyFrame);
90 QString opacity = decl.d->values.first().toString();
91 prop->appendValue(opacity.toDouble());
92 }
93 }
94 }
95
96 for (auto it = animatedProperies.begin(); it != animatedProperies.end(); it++)
97 animation->appendProperty(it.value());
98
99 return animation;
100}
101
102void QSvgCssHandler::updateColorProperty(const QCss::Declaration &decl, QSvgAnimatedPropertyColor *property)
103{
104 QString colorStr = decl.d->values.first().toString();
105 QColor color = QColor::fromString(colorStr);
106 property->appendColor(color);
107}
108
109void QSvgCssHandler::updateTransformProperty(const QCss::Declaration &decl, QSvgAnimatedPropertyTransform *property)
110{
111 for (QCss::Value val : decl.d->values) {
112 if (val.type == QCss::Value::Function) {
113 QStringList lst = val.variant.toStringList();
114 QStringView transformType = lst[0];
115 QStringList args = lst[1].split(QStringLiteral(","), Qt::SkipEmptyParts);
116 if (transformType == QStringLiteral("scale")) {
117 qreal scale0 = QSvgUtils::toDouble(args[0].trimmed());
118 qreal scale1 = QSvgUtils::toDouble(args[1].trimmed());
119 property->appendScale(QPointF(scale0, scale1));
120 } else if (transformType == QStringLiteral("translate")) {
121 QSvgUtils::LengthType type;
122 qreal translate0 = QSvgUtils::parseLength(args[0], &type);
123 translate0 = QSvgUtils::convertToPixels(translate0, false, type);
124 qreal translate1 = QSvgUtils::parseLength(args[1], &type);
125 translate1 = QSvgUtils::convertToPixels(translate1, false, type);
126 property->appendTranslation(QPointF(translate0, translate1));
127 } else if (transformType == QStringLiteral("rotate")) {
128 qreal rotationAngle = qsvg_parseAngle(args[0]);
129 property->appendRotation(rotationAngle);
130 property->appendCenterOfRotation(QPointF(0, 0));
131 } else if (transformType == QStringLiteral("skew")) {
132 qreal skew0 = qsvg_parseAngle(args[0]);
133 qreal skew1 = qsvg_parseAngle(args[1]);
134 property->appendSkew(QPointF(skew0, skew1));
135 } else if (transformType == QStringLiteral("matrix")) {
136 QSvgUtils::LengthType type;
137 qreal translate0 = QSvgUtils::parseLength(args[4], &type);
138 translate0 = QSvgUtils::convertToPixels(translate0, false, type);
139 qreal translate1 = QSvgUtils::parseLength(args[5], &type);
140 translate1 = QSvgUtils::convertToPixels(translate1, false, type);
141 qreal scale0 = QSvgUtils::toDouble(args[0].trimmed());
142 qreal scale1 = QSvgUtils::toDouble(args[3].trimmed());
143 qreal skew0 = QSvgUtils::toDouble((args[1].trimmed()));
144 qreal skew1 = QSvgUtils::toDouble((args[2].trimmed()));
145 property->appendSkew(QPointF(skew0, skew1));
146 property->appendTranslation(QPointF(translate0, translate1));
147 property->appendScale(QPointF(scale0, scale1));
148 }
149 }
150 }
151}
152
153QT_END_NAMESPACE
void collectAnimations(const QCss::StyleSheet &sheet)
static QT_BEGIN_NAMESPACE qreal qsvg_parseAngle(QStringView str, bool *ok=nullptr)