83bool validateTransform(QList<QList<QSvgAnimatedPropertyTransform::TransformComponent>> &keyFrameComponents) {
85 if (keyFrameComponents.size() < 2)
88 qsizetype maxIndex = 0;
89 qsizetype maxSize = 0;
90 for (
int i = 1; i < keyFrameComponents.size(); i++) {
91 auto &listA = keyFrameComponents[i - 1];
92 auto &listB = keyFrameComponents[i];
93 for (
int j = 0; j < qMin(listA.size(), listB.size()); j++) {
94 auto typeA = listA.at(j).type;
95 auto typeB = listB.at(j).type;
101 if (listA.size() > maxSize) {
103 maxSize = listA.size();
106 if (listB.size() > maxSize) {
108 maxSize = listB.size();
112 const auto &longList = keyFrameComponents.at(maxIndex);
114 for (
auto &list : keyFrameComponents) {
115 qsizetype size = list.size();
117 for (
int j = size; j < maxSize; j++) {
118 QSvgAnimatedPropertyTransform::TransformComponent comp = longList.value(j);
120 case QSvgAnimatedPropertyTransform::TransformComponent::Translate:
121 case QSvgAnimatedPropertyTransform::TransformComponent::Skew:
125 case QSvgAnimatedPropertyTransform::TransformComponent::Rotate:
130 case QSvgAnimatedPropertyTransform::TransformComponent::Scale:
147 QList<QList<QSvgAnimatedPropertyTransform::TransformComponent>> keyFramesComponents;
149 for (CssKeyFrameValue keyFrame : keyFrames) {
150 QList<QSvgAnimatedPropertyTransform::TransformComponent> components;
151 for (QCss::Value val : keyFrame.values) {
152 if (val.type == QCss::Value::Function) {
153 QStringList lst = val.variant.toStringList();
154 QStringView transformType = lst.value(0);
155 QStringList args = lst.value(1).split(QStringLiteral(
","), Qt::SkipEmptyParts);
156 if (transformType == QStringLiteral(
"scale")) {
157 QSvgAnimatedPropertyTransform::TransformComponent component;
158 qreal scale0 = QSvgUtils::toDouble(args.value(0).trimmed());
159 qreal scale1 = QSvgUtils::toDouble(args.value(1).trimmed());
160 component.type = QSvgAnimatedPropertyTransform::TransformComponent::Scale;
161 component.values.append(scale0);
162 component.values.append(scale1);
163 components.append(component);
164 }
else if (transformType == QStringLiteral(
"translate")) {
165 QSvgAnimatedPropertyTransform::TransformComponent component;
166 QSvgUtils::LengthType type;
167 qreal translate0 = QSvgUtils::parseLength(args.value(0), &type);
168 translate0 = QSvgUtils::convertToPixels(translate0,
false, type);
169 qreal translate1 = QSvgUtils::parseLength(args.value(1), &type);
170 translate1 = QSvgUtils::convertToPixels(translate1,
false, type);
171 component.type = QSvgAnimatedPropertyTransform::TransformComponent::Translate;
172 component.values.append(translate0);
173 component.values.append(translate1);
174 components.append(component);
175 }
else if (transformType == QStringLiteral(
"rotate")) {
176 QSvgAnimatedPropertyTransform::TransformComponent component;
177 qreal rotationAngle = qsvg_parseAngle(args.value(0));
178 component.type = QSvgAnimatedPropertyTransform::TransformComponent::Rotate;
179 component.values.append(rotationAngle);
180 component.values.append(0);
181 component.values.append(0);
182 components.append(component);
183 }
else if (transformType == QStringLiteral(
"skew")) {
184 QSvgAnimatedPropertyTransform::TransformComponent component;
185 qreal skew0 = qsvg_parseAngle(args.value(0));
186 qreal skew1 = qsvg_parseAngle(args.value(1));
187 component.type = QSvgAnimatedPropertyTransform::TransformComponent::Skew;
188 component.values.append(skew0);
189 component.values.append(skew1);
190 components.append(component);
191 }
else if (transformType == QStringLiteral(
"matrix")) {
192 QSvgAnimatedPropertyTransform::TransformComponent component1, component2, component3;
193 QSvgUtils::LengthType type;
194 qreal translate0 = QSvgUtils::parseLength(args.value(4), &type);
195 translate0 = QSvgUtils::convertToPixels(translate0,
false, type);
196 qreal translate1 = QSvgUtils::parseLength(args.value(5), &type);
197 translate1 = QSvgUtils::convertToPixels(translate1,
false, type);
198 qreal scale0 = QSvgUtils::toDouble(args.value(0).trimmed());
199 qreal scale1 = QSvgUtils::toDouble(args.value(3).trimmed());
200 qreal skew0 = QSvgUtils::toDouble((args.value(1).trimmed()));
201 qreal skew1 = QSvgUtils::toDouble((args.value(2).trimmed()));
202 component1.type = QSvgAnimatedPropertyTransform::TransformComponent::Translate;
203 component1.values.append(translate0);
204 component1.values.append(translate1);
205 component2.type = QSvgAnimatedPropertyTransform::TransformComponent::Scale;
206 component2.values.append(scale0);
207 component2.values.append(scale1);
208 component3.type = QSvgAnimatedPropertyTransform::TransformComponent::Skew;
209 component3.values.append(skew0);
210 component3.values.append(skew1);
211 components.append(component1);
212 components.append(component2);
213 components.append(component3);
217 keyFramesComponents.append(components);
218 prop->appendKeyFrame(keyFrame.keyFrame);
221 if (!validateTransform(keyFramesComponents))
224 for (
auto comp : keyFramesComponents) {
225 prop->appendComponents(comp);
227 prop->setTransformCount(keyFramesComponents.first().size());
248 if (!m_animations.contains(name))
251 QCss::AnimationRule animationRule = m_animations[name];
252 QHash<QString, QSvgAbstractAnimatedProperty*> animatedProperies;
253 QSvgCssAnimation *animation =
new QSvgCssAnimation;
258 QHash<QString, QList<CssKeyFrameValue>> keyFrameValues;
259 for (
const auto &ruleSet : std::as_const(animationRule.ruleSets)) {
260 for (QCss::Declaration decl : ruleSet.declarations) {
261 CssKeyFrameValue keyFrameValue = {ruleSet.keyFrame, decl.d->values};
262 QList<CssKeyFrameValue> &value = keyFrameValues[decl.d->property];
263 value.append(keyFrameValue);
267 for (
auto it = keyFrameValues.begin(); it != keyFrameValues.end(); it++) {
268 QStringView property = it.key();
269 const QList<CssKeyFrameValue> &keyFrames = it.value();
270 auto *prop = QSvgAbstractAnimatedProperty::createAnimatedProperty(property.toString());
275 if (property == QLatin1StringView(
"fill") || property == QLatin1StringView(
"stroke"))
276 result = fillColorProperty(keyFrames,
static_cast<QSvgAnimatedPropertyColor*>(prop));
277 else if (property == QLatin1StringView(
"transform"))
278 result = fillTransformProperty(keyFrames,
static_cast<QSvgAnimatedPropertyTransform*>(prop));
279 else if (property == QLatin1StringView(
"fill-opacity") || property == QLatin1StringView(
"stroke-opacity")
280 || property == QLatin1StringView(
"opacity"))
281 result = fillOpacityProperty(keyFrames,
static_cast<QSvgAnimatedPropertyFloat*>(prop));
288 animatedProperies[property] = prop;
291 for (
auto it = animatedProperies.begin(); it != animatedProperies.end(); it++)
292 animation->appendProperty(it.value());
322 for (
int i = 0; i < declarations.size(); ++i) {
323 const QCss::Declaration &decl = declarations.at(i);
324 if (decl.d->property.isEmpty())
327 const int valCount = decl.d->values.size();
328 for (
int i = 0; i < valCount; ++i) {
329 QCss::Value val = decl.d->values.at(i);
330 if (val.type == QCss::Value::TermOperatorComma) {
331 valueStr += QLatin1Char(
';');
332 }
else if (val.type == QCss::Value::Uri) {
333 valueStr.prepend(QLatin1String(
"url("));
334 valueStr.append(QLatin1Char(
')'));
335 }
else if (val.type == QCss::Value::Function) {
336 QStringList lst = val.variant.toStringList();
337 valueStr.append(lst.at(0));
338 valueStr.append(QLatin1Char(
'('));
339 for (
int i = 1; i < lst.size(); ++i) {
340 valueStr.append(lst.at(i));
341 if ((i +1) < lst.size())
342 valueStr.append(QLatin1Char(
','));
344 valueStr.append(QLatin1Char(
')'));
345 }
else if (val.type == QCss::Value::KnownIdentifier) {
346 switch (val.variant.toInt()) {
347 case QCss::Value_None:
348 valueStr = QLatin1String(
"none");
354 valueStr += val.toString();
356 if (i + 1 < valCount)
357 valueStr += QLatin1Char(
' ');
360 attributes.append(QString(), decl.d->property, valueStr);
367 QCss::Parser parser(css);
370 while (parser.hasNext()) {
373 if (!parser.hasNext())
380 if (parser.hasEscapeSequences) {
381 key = parser.lexem();
384 const QCss::Symbol &sym = parser.symbol();
385 name = sym.text.mid(sym.start, sym.len);
389 if (!parser.test(QCss::COLON))
393 if (!parser.hasNext())
396 const int firstSymbol = parser.index;
401 }
while (parser.hasNext() && !parser.test(QCss::SEMICOLON));
403 bool canExtractValueByRef = !parser.hasEscapeSequences;
404 if (canExtractValueByRef) {
405 int len = parser.symbols.at(firstSymbol).len;
406 for (
int i = firstSymbol + 1; i < firstSymbol + symbolCount; ++i) {
407 len += parser.symbols.at(i).len;
409 if (parser.symbols.at(i - 1).start + parser.symbols.at(i - 1).len
410 != parser.symbols.at(i).start) {
411 canExtractValueByRef =
false;
415 if (canExtractValueByRef) {
416 const QCss::Symbol &sym = parser.symbols.at(firstSymbol);
417 value = sym.text.mid(sym.start, len);
420 if (!canExtractValueByRef) {
422 for (
int i = firstSymbol; i < parser.index - 1; ++i)
423 value += parser.symbols.at(i).lexem();
426 attributes.append(QString(), name, value);