diff options
author | Kim Motoyoshi Kalland <kim.kalland@nokia.com> | 2009-08-19 15:41:38 (GMT) |
---|---|---|
committer | Kim Motoyoshi Kalland <kim.kalland@nokia.com> | 2009-08-20 13:23:03 (GMT) |
commit | 984773a54975ed26c5e7aef5d8ff095ca1dfad3d (patch) | |
tree | 5fe4954a17105ef7e51644f42113a6ee079e1b81 | |
parent | 9162508604dc05c7de2a5ea02a20369681b06456 (diff) | |
download | Qt-984773a54975ed26c5e7aef5d8ff095ca1dfad3d.zip Qt-984773a54975ed26c5e7aef5d8ff095ca1dfad3d.tar.gz Qt-984773a54975ed26c5e7aef5d8ff095ca1dfad3d.tar.bz2 |
Improved support for SVG animation.
Added support for from-by-animation and by-animation in the
animateTransform element. Updated bubbles.svg in the svgviewer example
to make it work like intended with the corrected animation code.
Task-number: Partially fixes 254784
Reviewed-by: Trond
-rw-r--r-- | examples/painting/svgviewer/files/bubbles.svg | 26 | ||||
-rw-r--r-- | src/svg/qsvghandler.cpp | 61 | ||||
-rw-r--r-- | src/svg/qsvgstyle.cpp | 71 | ||||
-rw-r--r-- | src/svg/qsvgstyle_p.h | 29 |
4 files changed, 94 insertions, 93 deletions
diff --git a/examples/painting/svgviewer/files/bubbles.svg b/examples/painting/svgviewer/files/bubbles.svg index 65867da..9fae8cc 100644 --- a/examples/painting/svgviewer/files/bubbles.svg +++ b/examples/painting/svgviewer/files/bubbles.svg @@ -91,56 +91,56 @@ <g transform="translate(200,700)"> <use xlink:href="#bubble" fill="url(#blueBubble)" /> - <animateTransform attributeName="transform" type="translate" + <animateTransform attributeName="transform" type="translate" additive="sum" values="0,0; 0,-800" begin="1s" dur="10s" fill="freeze" repeatCount="indefinite" /> </g> <g transform="translate(315,700)"> <g transform="scale(0.5,0.5)"> <use xlink:href="#bubble" fill="url(#redBubble)" /> </g> - <animateTransform attributeName="transform" type="translate" + <animateTransform attributeName="transform" type="translate" additive="sum" values="0,0; 0,-800" begin="3s" dur="7s" fill="freeze" repeatCount="indefinite" /> </g> <g transform="translate(80,700)"> <g transform="scale(0.65,0.65)"> <use xlink:href="#bubble" fill="url(#greenBubble)" /> </g> - <animateTransform attributeName="transform" type="translate" + <animateTransform attributeName="transform" type="translate" additive="sum" values="0,0; 0,-800" begin="5s" dur="9s" fill="freeze" repeatCount="indefinite" /> </g> <g transform="translate(255,700)"> <g transform="scale(0.3,0.3)"> <use xlink:href="#bubble" fill="url(#yellowBubble)" /> </g> - <animateTransform attributeName="transform" type="translate" + <animateTransform attributeName="transform" type="translate" additive="sum" values="0,0; 0,-800" begin="2s" dur="6s" fill="freeze" repeatCount="indefinite" /> </g> <g transform="translate(565,700)"> <g transform="scale(0.4,0.4)"> <use xlink:href="#bubble" fill="url(#blueBubble)" /> </g> - <animateTransform attributeName="transform" type="translate" + <animateTransform attributeName="transform" type="translate" additive="sum" values="0,0; 0,-800" begin="4s" dur="8s" fill="freeze" repeatCount="indefinite" /> </g> <g transform="translate(715,700)"> <g transform="scale(0.6,0.6)"> <use xlink:href="#bubble" fill="url(#redBubble)" /> </g> - <animateTransform attributeName="transform" type="translate" + <animateTransform attributeName="transform" type="translate" additive="sum" values="0,0; 0,-800" begin="1s" dur="4s" fill="freeze" repeatCount="indefinite" /> </g> <g transform="translate(645,700)"> <g transform="scale(0.375,0.375)"> <use xlink:href="#bubble" fill="url(#greenBubble)" /> </g> - <animateTransform attributeName="transform" type="translate" + <animateTransform attributeName="transform" type="translate" additive="sum" values="0,0; 0,-800" begin="0s" dur="11s" fill="freeze" repeatCount="indefinite" /> </g> <g transform="translate(555,700)"> <g transform="scale(0.9,0.9)"> <use xlink:href="#bubble" fill="url(#yellowBubble)" /> </g> - <animateTransform attributeName="transform" type="translate" + <animateTransform attributeName="transform" type="translate" additive="sum" values="0,0; 0,-800" begin="3s" dur="7.5s" fill="freeze" repeatCount="indefinite" /> </g> @@ -148,28 +148,28 @@ <g transform="scale(0.5,0.5)"> <use xlink:href="#bubble" fill="url(#blueBubble)" /> </g> - <animateTransform attributeName="transform" type="translate" + <animateTransform attributeName="transform" type="translate" additive="sum" values="0,0; 0,-800" begin="3s" dur="6s" fill="freeze" repeatCount="indefinite" /> </g> <g transform="translate(215,700)"> <g transform="scale(0.45,0.45)"> <use xlink:href="#bubble" fill="url(#redBubble)" /> </g> - <animateTransform attributeName="transform" type="translate" + <animateTransform attributeName="transform" type="translate" additive="sum" values="0,0; 0,-800" begin="5.5s" dur="7s" fill="freeze" repeatCount="indefinite" /> </g> <g transform="translate(420,700)"> <g transform="scale(0.75,0.75)"> <use xlink:href="#bubble" fill="url(#greenBubble)" /> </g> - <animateTransform attributeName="transform" type="translate" + <animateTransform attributeName="transform" type="translate" additive="sum" values="0,0; 0,-800" begin="1s" dur="9s" fill="freeze" repeatCount="indefinite" /> </g> <g transform="translate(815,700)"> <g transform="scale(0.6,0.6)"> <use xlink:href="#bubble" fill="url(#yellowBubble)" /> </g> - <animateTransform attributeName="transform" type="translate" + <animateTransform attributeName="transform" type="translate" additive="sum" values="0,0; 0,-800" begin="2s" dur="9.5s" fill="freeze" repeatCount="indefinite" /> </g> @@ -186,7 +186,7 @@ <circle fill="#a6ce39" cx="0" cy="0" r="33" /> <path fill="black" d="M 37,50 L 50,37 L 12,-1 L 22,-11 L 10,-24 L -24,10 L -11,22 L -1,12 Z" /> - <animateTransform attributeName="transform" type="rotate" values="0; 360" + <animateTransform attributeName="transform" type="rotate" additive="sum" values="0; 360" begin="0s" dur="10s" fill="freeze" repeatCount="indefinite" /> </g> <g transform="translate(200,375)"> diff --git a/src/svg/qsvghandler.cpp b/src/svg/qsvghandler.cpp index 2d07a1e..adfe468 100644 --- a/src/svg/qsvghandler.cpp +++ b/src/svg/qsvghandler.cpp @@ -2012,6 +2012,14 @@ static bool parseAimateMotionNode(QSvgNode *parent, return true; } +static void parseNumberTriplet(QVector<qreal> &values, const QChar *&s) +{ + QVector<qreal> list = parseNumbersList(s); + values << list; + for (int i = 3 - list.size(); i > 0; --i) + values.append(0.0); +} + static bool parseAnimateTransformNode(QSvgNode *parent, const QXmlStreamAttributes &attributes, QSvgHandler *handler) @@ -2025,29 +2033,47 @@ static bool parseAnimateTransformNode(QSvgNode *parent, QString fillStr = attributes.value(QLatin1String("fill")).toString(); QString fromStr = attributes.value(QLatin1String("from")).toString(); QString toStr = attributes.value(QLatin1String("to")).toString(); + QString byStr = attributes.value(QLatin1String("by")).toString(); QString addtv = attributes.value(QLatin1String("additive")).toString(); + QSvgAnimateTransform::Additive additive = QSvgAnimateTransform::Replace; + if (addtv == QLatin1String("sum")) + additive = QSvgAnimateTransform::Sum; + QVector<qreal> vals; if (values.isEmpty()) { - const QChar *s = fromStr.constData(); - QVector<qreal> lst = parseNumbersList(s); - while (lst.count() < 3) - lst.append(0.0); - vals << lst; - - s = toStr.constData(); - lst = parseNumbersList(s); - while (lst.count() < 3) - lst.append(0.0); - vals << lst; + const QChar *s; + if (fromStr.isEmpty()) { + if (!byStr.isEmpty()) { + // By-animation. + additive = QSvgAnimateTransform::Sum; + vals.append(0.0); + vals.append(0.0); + vals.append(0.0); + parseNumberTriplet(vals, s = byStr.constData()); + } else { + // To-animation not defined. + return false; + } + } else { + if (!toStr.isEmpty()) { + // From-to-animation. + parseNumberTriplet(vals, s = fromStr.constData()); + parseNumberTriplet(vals, s = toStr.constData()); + } else if (!byStr.isEmpty()) { + // From-by-animation. + parseNumberTriplet(vals, s = fromStr.constData()); + parseNumberTriplet(vals, s = byStr.constData()); + for (int i = vals.size() - 3; i < vals.size(); ++i) + vals[i] += vals[i - 3]; + } else { + return false; + } + } } else { const QChar *s = values.constData(); while (s && *s != QLatin1Char(0)) { - QVector<qreal> tmpVals = parseNumbersList(s); - while (tmpVals.count() < 3) - tmpVals.append(0.0); - - vals << tmpVals; + parseNumberTriplet(vals, s); if (*s == QLatin1Char(0)) break; ++s; @@ -2088,9 +2114,6 @@ static bool parseAnimateTransformNode(QSvgNode *parent, return false; } - QSvgAnimateTransform::Additive additive = QSvgAnimateTransform::Replace; - if (addtv == QLatin1String("sum")) - additive = QSvgAnimateTransform::Sum; QSvgAnimateTransform *anim = new QSvgAnimateTransform(begin, end, 0); anim->setArgs(type, additive, vals); anim->setFreeze(fillStr == QLatin1String("freeze")); diff --git a/src/svg/qsvgstyle.cpp b/src/svg/qsvgstyle.cpp index 915c512..e1a7049 100644 --- a/src/svg/qsvgstyle.cpp +++ b/src/svg/qsvgstyle.cpp @@ -509,36 +509,25 @@ void QSvgStyle::apply(QPainter *p, const QRectF &rect, QSvgNode *node, QSvgExtra //animated transforms have to be applied //_after_ the original object transformations if (!animateTransforms.isEmpty()) { - QList<QSvgRefCounter<QSvgAnimateTransform> >::const_iterator itr, temp, replace; - bool replaced = false; - qreal totalTimeElapsed = 0; - for (itr = animateTransforms.constBegin(); itr!= animateTransforms.constEnd(); ++itr) { - totalTimeElapsed = node->document()->currentElapsed(); - if ((totalTimeElapsed >= (*itr)->animStartTime()) && (!(*itr)->animFinished(totalTimeElapsed) || (*itr)->frozen())) { - if ((*itr)->additiveType() == QSvgAnimateTransform::Replace) { - if (!replaced) { - //set the flag to show replace is already encountered - //store the itr, which can be used if we encounter other animateTransform with additive = "replace" - replaced = true; - replace = itr; - //revert the first animateTransform with additive = "sum" - temp = animateTransforms.constBegin(); - if (temp != itr) - (*temp)->revert(p, states); - - //revert the transform if already applied - if (transform) - transform->revert(p, states); - } else { - //if animateTransform with additive = "replace" is encountered already - //then just revert that old animateTransform - (*replace)->revert(p,states); - replace = itr; //store the latest replace transform - } - } - (*itr)->apply(p, rect, node, states); - (*itr)->setTransformApplied(true); + qreal totalTimeElapsed = node->document()->currentElapsed(); + // Find the last animateTransform with additive="replace", since this will override all + // previous animateTransforms. + QList<QSvgRefCounter<QSvgAnimateTransform> >::const_iterator itr = animateTransforms.constEnd(); + do { + --itr; + if ((*itr)->animActive(totalTimeElapsed) + && (*itr)->additiveType() == QSvgAnimateTransform::Replace) { + // An animateTransform with additive="replace" will replace the transform attribute. + if (transform) + transform->revert(p, states); + break; } + } while (itr != animateTransforms.constBegin()); + + // Apply the animateTransforms after and including the last one with additive="replace". + for (; itr != animateTransforms.constEnd(); ++itr) { + if ((*itr)->animActive(totalTimeElapsed)) + (*itr)->apply(p, rect, node, states); } } @@ -584,25 +573,15 @@ void QSvgStyle::revert(QPainter *p, QSvgExtraStates &states) //animated transforms need to be reverted _before_ //the native transforms if (!animateTransforms.isEmpty()) { - QList<QSvgRefCounter<QSvgAnimateTransform> >::const_iterator itr; - bool reverted = false; - for (itr = animateTransforms.constEnd(); itr != animateTransforms.constBegin(); --itr) { - //if there is an animate transform with additive = "replace" - //then revert the last applied animateTransform with additive = "replace" - if (((*(itr-1))->transformApplied()) && ((*(itr-1))->additiveType() == QSvgAnimateTransform::Replace)) { - reverted = true; - (*(itr-1))->revert(p,states); + QList<QSvgRefCounter<QSvgAnimateTransform> >::const_iterator itr = animateTransforms.constBegin(); + for (; itr != animateTransforms.constEnd(); ++itr) { + if ((*itr)->transformApplied()) { + (*itr)->revert(p, states); break; } } - //if there are no animateTransform with additive = "replace" then - //revert the first applied animateTransform with additive = "sum" - if (!reverted) { - while (itr != animateTransforms.constEnd() && !(*itr)->transformApplied()) - itr++; - if (itr != animateTransforms.constEnd()) - (*itr)->revert(p, states); - } + for (; itr != animateTransforms.constEnd(); ++itr) + (*itr)->clearTransformApplied(); } if (transform) { @@ -644,11 +623,13 @@ void QSvgAnimateTransform::apply(QPainter *p, const QRectF &, QSvgNode *node, QS m_oldWorldTransform = p->worldTransform(); resolveMatrix(node); p->setWorldTransform(m_transform, true); + m_transformApplied = true; } void QSvgAnimateTransform::revert(QPainter *p, QSvgExtraStates &) { p->setWorldTransform(m_oldWorldTransform, false /* don't combine */); + m_transformApplied = false; } void QSvgAnimateTransform::resolveMatrix(QSvgNode *node) diff --git a/src/svg/qsvgstyle_p.h b/src/svg/qsvgstyle_p.h index 6f56574..056b73b 100644 --- a/src/svg/qsvgstyle_p.h +++ b/src/svg/qsvgstyle_p.h @@ -547,22 +547,18 @@ public: return m_additive; } - bool animFinished(qreal totalTimeElapsed) + bool animActive(qreal totalTimeElapsed) { - qreal animationFrame = (totalTimeElapsed - m_from) / m_to; - if (m_repeatCount >= 0 && m_repeatCount < animationFrame) + if (totalTimeElapsed < m_from) + return false; + if (m_freeze || m_repeatCount < 0) // fill="freeze" or repeat="indefinite" return true; - return false; - } - - qreal animStartTime() const - { - return m_from; - } - - void setTransformApplied(bool apply) - { - m_transformApplied = apply; + if (m_totalRunningTime == 0) + return false; + qreal animationFrame = (totalTimeElapsed - m_from) / m_totalRunningTime; + if (animationFrame > m_repeatCount) + return false; + return true; } bool transformApplied() const @@ -570,9 +566,10 @@ public: return m_transformApplied; } - bool frozen() + // Call this instead of revert if you know that revert is unnecessary. + void clearTransformApplied() { - return m_freeze; + m_transformApplied = false; } protected: |