summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKim Motoyoshi Kalland <kim.kalland@nokia.com>2009-08-19 15:41:38 (GMT)
committerKim Motoyoshi Kalland <kim.kalland@nokia.com>2009-08-20 13:23:03 (GMT)
commit984773a54975ed26c5e7aef5d8ff095ca1dfad3d (patch)
tree5fe4954a17105ef7e51644f42113a6ee079e1b81
parent9162508604dc05c7de2a5ea02a20369681b06456 (diff)
downloadQt-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.svg26
-rw-r--r--src/svg/qsvghandler.cpp61
-rw-r--r--src/svg/qsvgstyle.cpp71
-rw-r--r--src/svg/qsvgstyle_p.h29
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: