50bool validateTransform(QList<QList<QSvgAnimatedPropertyTransform::TransformComponent>> &keyFrameComponents) {
52 if (keyFrameComponents.size() < 2)
55 qsizetype maxIndex = 0;
56 qsizetype maxSize = 0;
57 for (
int i = 1; i < keyFrameComponents.size(); i++) {
58 auto &listA = keyFrameComponents[i - 1];
59 auto &listB = keyFrameComponents[i];
60 for (
int j = 0; j < qMin(listA.size(), listB.size()); j++) {
61 auto typeA = listA.at(j).type;
62 auto typeB = listB.at(j).type;
68 if (listA.size() > maxSize) {
70 maxSize = listA.size();
73 if (listB.size() > maxSize) {
75 maxSize = listB.size();
79 const auto &longList = keyFrameComponents.at(maxIndex);
81 for (
auto &list : keyFrameComponents) {
82 qsizetype size = list.size();
84 for (
int j = size; j < maxSize; j++) {
85 QSvgAnimatedPropertyTransform::TransformComponent comp = longList.value(j);
87 case QSvgAnimatedPropertyTransform::TransformComponent::Translate:
88 case QSvgAnimatedPropertyTransform::TransformComponent::Skew:
92 case QSvgAnimatedPropertyTransform::TransformComponent::Rotate:
97 case QSvgAnimatedPropertyTransform::TransformComponent::Scale:
114 QList<QList<QSvgAnimatedPropertyTransform::TransformComponent>> keyFramesComponents;
116 for (CssKeyFrameValue keyFrame : keyFrames) {
117 QList<QSvgAnimatedPropertyTransform::TransformComponent> components;
118 for (QCss::Value val : keyFrame.values) {
119 if (val.type == QCss::Value::Function) {
120 QStringList lst = val.variant.toStringList();
121 QStringView transformType = lst.value(0);
122 QStringList args = lst.value(1).split(QStringLiteral(
","), Qt::SkipEmptyParts);
123 if (transformType == QStringLiteral(
"scale")) {
124 QSvgAnimatedPropertyTransform::TransformComponent component;
125 qreal scale0 = QSvgUtils::toDouble(args.value(0).trimmed());
126 qreal scale1 = QSvgUtils::toDouble(args.value(1).trimmed());
127 component.type = QSvgAnimatedPropertyTransform::TransformComponent::Scale;
128 component.values.append(scale0);
129 component.values.append(scale1);
130 components.append(component);
131 }
else if (transformType == QStringLiteral(
"translate")) {
132 QSvgAnimatedPropertyTransform::TransformComponent component;
133 QSvgUtils::LengthType type;
134 qreal translate0 = QSvgUtils::parseLength(args.value(0), &type);
135 translate0 = QSvgUtils::convertToPixels(translate0,
false, type);
136 qreal translate1 = QSvgUtils::parseLength(args.value(1), &type);
137 translate1 = QSvgUtils::convertToPixels(translate1,
false, type);
138 component.type = QSvgAnimatedPropertyTransform::TransformComponent::Translate;
139 component.values.append(translate0);
140 component.values.append(translate1);
141 components.append(component);
142 }
else if (transformType == QStringLiteral(
"rotate")) {
143 QSvgAnimatedPropertyTransform::TransformComponent component;
144 qreal rotationAngle = QSvgUtils::parseAngle(args.value(0)).value_or(0);
145 component.type = QSvgAnimatedPropertyTransform::TransformComponent::Rotate;
146 component.values.append(rotationAngle);
147 component.values.append(0);
148 component.values.append(0);
149 components.append(component);
150 }
else if (transformType == QStringLiteral(
"skew")) {
151 QSvgAnimatedPropertyTransform::TransformComponent component;
152 qreal skew0 = QSvgUtils::parseAngle(args.value(0)).value_or(0);
153 qreal skew1 = QSvgUtils::parseAngle(args.value(1)).value_or(0);
154 component.type = QSvgAnimatedPropertyTransform::TransformComponent::Skew;
155 component.values.append(skew0);
156 component.values.append(skew1);
157 components.append(component);
158 }
else if (transformType == QStringLiteral(
"matrix")) {
159 QSvgAnimatedPropertyTransform::TransformComponent component1, component2, component3;
160 QSvgUtils::LengthType type;
161 qreal translate0 = QSvgUtils::parseLength(args.value(4), &type);
162 translate0 = QSvgUtils::convertToPixels(translate0,
false, type);
163 qreal translate1 = QSvgUtils::parseLength(args.value(5), &type);
164 translate1 = QSvgUtils::convertToPixels(translate1,
false, type);
165 qreal scale0 = QSvgUtils::toDouble(args.value(0).trimmed());
166 qreal scale1 = QSvgUtils::toDouble(args.value(3).trimmed());
167 qreal skew0 = QSvgUtils::toDouble((args.value(1).trimmed()));
168 qreal skew1 = QSvgUtils::toDouble((args.value(2).trimmed()));
169 component1.type = QSvgAnimatedPropertyTransform::TransformComponent::Translate;
170 component1.values.append(translate0);
171 component1.values.append(translate1);
172 component2.type = QSvgAnimatedPropertyTransform::TransformComponent::Scale;
173 component2.values.append(scale0);
174 component2.values.append(scale1);
175 component3.type = QSvgAnimatedPropertyTransform::TransformComponent::Skew;
176 component3.values.append(skew0);
177 component3.values.append(skew1);
178 components.append(component1);
179 components.append(component2);
180 components.append(component3);
184 keyFramesComponents.append(components);
185 prop->appendKeyFrame(keyFrame.keyFrame);
188 if (!validateTransform(keyFramesComponents))
191 for (
auto comp : keyFramesComponents) {
192 prop->appendComponents(comp);
194 prop->setTransformCount(keyFramesComponents.first().size());
237QSvgCssAnimation *QSvgCssHandler::createAnimation(QStringView name)
239 if (!m_animations.contains(name))
242 QCss::AnimationRule animationRule = m_animations[name];
243 QHash<QString, QSvgAbstractAnimatedProperty*> animatedProperies;
244 QSvgCssAnimation *animation =
new QSvgCssAnimation;
249 QHash<QString, QList<CssKeyFrameValue>> keyFrameValues;
250 for (
const auto &ruleSet : std::as_const(animationRule.ruleSets)) {
251 for (QCss::Declaration decl : ruleSet.declarations) {
252 CssKeyFrameValue keyFrameValue = {ruleSet.keyFrame, decl.d->values};
253 QList<CssKeyFrameValue> &value = keyFrameValues[decl.d->property];
254 value.append(keyFrameValue);
258 for (
auto it = keyFrameValues.begin(); it != keyFrameValues.end(); it++) {
259 QStringView property = it.key();
260 const QList<CssKeyFrameValue> &keyFrames = it.value();
261 auto *prop = QSvgAbstractAnimatedProperty::createAnimatedProperty(property.toString());
266 if (property == QLatin1StringView(
"fill") || property == QLatin1StringView(
"stroke"))
267 result = fillColorProperty(keyFrames,
static_cast<QSvgAnimatedPropertyColor*>(prop));
268 else if (property == QLatin1StringView(
"transform"))
269 result = fillTransformProperty(keyFrames,
static_cast<QSvgAnimatedPropertyTransform*>(prop));
270 else if (property == QLatin1StringView(
"fill-opacity") || property == QLatin1StringView(
"stroke-opacity")
271 || property == QLatin1StringView(
"opacity"))
272 result = fillOpacityProperty(keyFrames,
static_cast<QSvgAnimatedPropertyFloat*>(prop));
273 else if (property == QLatin1StringView(
"offset-distance"))
274 result = fillOffsetDistanceProperty(keyFrames,
static_cast<QSvgAnimatedPropertyFloat*>(prop));
281 animatedProperies[property] = prop;
284 for (
auto it = animatedProperies.begin(); it != animatedProperies.end(); it++)
285 animation->appendProperty(it.value());
313void QSvgCssHandler::parseCSStoXMLAttrs(
const QList<QCss::Declaration> &declarations, QXmlStreamAttributes &attributes)
const
315 for (
int i = 0; i < declarations.size(); ++i) {
316 const QCss::Declaration &decl = declarations.at(i);
317 if (decl.d->property.isEmpty())
320 const int valCount = decl.d->values.size();
321 for (
int i = 0; i < valCount; ++i) {
322 QCss::Value val = decl.d->values.at(i);
324 case QCss::Value::TermOperatorComma:
325 valueStr += QLatin1Char(
';');
327 case QCss::Value::Uri:
329 QString temp = val.toString();
330 temp.prepend(QLatin1String(
"url("));
331 temp.append(QLatin1Char(
')'));
335 case QCss::Value::Function:
337 QStringList lst = val.variant.toStringList();
338 valueStr.append(lst.at(0));
339 valueStr.append(QLatin1Char(
'('));
340 for (
int i = 1; i < lst.size(); ++i) {
341 valueStr.append(lst.at(i));
342 if ((i +1) < lst.size())
343 valueStr.append(QLatin1Char(
','));
345 valueStr.append(QLatin1Char(
')'));
348 case QCss::Value::KnownIdentifier:
349 switch (val.variant.toInt()) {
350 case QCss::Value_None:
351 valueStr += QLatin1String(
"none");
353 case QCss::Value_Auto:
354 valueStr += QLatin1String(
"auto");
357 valueStr += val.toString();
361 case QCss::Value::Percentage:
362 valueStr += val.toString() + QLatin1Char(
'%');
365 valueStr += val.toString();
369 if (i + 1 < valCount)
370 valueStr += QLatin1Char(
' ');
373 attributes.append(QString(), decl.d->property, valueStr);
377void QSvgCssHandler::parseCSStoXMLAttrs(
const QString &css, QXmlStreamAttributes &attributes)
const
380 QCss::Parser parser(css);
383 while (parser.hasNext()) {
386 if (!parser.hasNext())
393 if (parser.hasEscapeSequences) {
394 key = parser.lexem();
397 const QCss::Symbol &sym = parser.symbol();
398 name = sym.text.mid(sym.start, sym.len);
402 if (!parser.test(QCss::COLON))
406 if (!parser.hasNext())
409 const int firstSymbol = parser.index;
414 }
while (parser.hasNext() && !parser.test(QCss::SEMICOLON));
416 bool canExtractValueByRef = !parser.hasEscapeSequences;
417 if (canExtractValueByRef) {
418 int len = parser.symbols.at(firstSymbol).len;
419 for (
int i = firstSymbol + 1; i < firstSymbol + symbolCount; ++i) {
420 len += parser.symbols.at(i).len;
422 if (parser.symbols.at(i - 1).start + parser.symbols.at(i - 1).len
423 != parser.symbols.at(i).start) {
424 canExtractValueByRef =
false;
428 if (canExtractValueByRef) {
429 const QCss::Symbol &sym = parser.symbols.at(firstSymbol);
430 value = sym.text.mid(sym.start, len);
433 if (!canExtractValueByRef) {
435 for (
int i = firstSymbol; i < parser.index - 1; ++i)
436 value += parser.symbols.at(i).lexem();
439 attributes.append(QString(), name, value);