- Revision
- 129670
- Author
- p...@google.com
- Date
- 2012-09-26 10:53:27 -0700 (Wed, 26 Sep 2012)
Log Message
Refactor SMILTimeContainer to maintain animation information instead of recalculating it every frame
https://bugs.webkit.org/show_bug.cgi?id=96697
Reviewed by Eric Seidel.
SVGTimeContainer can be improved by maintaining extra information about
animations during schedule/unschedule instead of re-calculating it
every frame.
After this patch, SMILTimeContainer maintains a GroupedAnimationsMap instead of
just a Vector. This map maps a list of animations to the specific ElementAttributePair
that will be animated.
On schedule/unschedule we modify this map instead of creating it in updateAnimations.
As a result, we need to be careful about always notifying (or, re-scheduling) the
time container when either an animation's target changes or an animation's attributeName
changes. This notification is managed by tracking changes with targetElementWillChange
and setAttributeName.
After this patch, updateAnimations only iterates over m_scheduledAnimations.
Furthermore, the sorting of animations by priority is now done over each Vector of
SVGSMILElements affecting a {SVGElement*, QualifiedName} pair instead of over all the
SVGSMILElements at once.
Lastly, a guard (m_preventScheduledAnimationsChanges) has been added
to prove that we do not modify the scheduled animations map out
from under ourselves.
No new tests as this is just a refactoring.
* svg/SVGAnimateElement.cpp:
(WebCore::SVGAnimateElement::hasValidAttributeType):
* svg/SVGAnimateMotionElement.cpp:
(WebCore::SVGAnimateMotionElement::hasValidAttributeName):
Per the spec, AnimateMotion is not affected by attributeName. Instead
of having a special case for this in SMILTimeContainer::updateAnimations
we simply implement this method.
(WebCore):
* svg/SVGAnimateMotionElement.h:
(SVGAnimateMotionElement):
* svg/SVGAnimationElement.cpp:
(WebCore::SVGAnimationElement::updateAnimation):
* svg/animation/SMILTimeContainer.cpp:
(WebCore):
(WebCore::SMILTimeContainer::SMILTimeContainer):
(WebCore::SMILTimeContainer::~SMILTimeContainer):
This method now cleans up the map since we have dynamically allocated
Vectors in it.
(WebCore::SMILTimeContainer::schedule):
Here we are just adding an entry to the map. There is some special handling
for creating the Vector of one does not exist.
(WebCore::SMILTimeContainer::unschedule):
(WebCore::SMILTimeContainer::notifyIntervalsChanged):
(WebCore::SMILTimeContainer::setElapsed):
(WebCore::SMILTimeContainer::startTimer):
(WebCore::SMILTimeContainer::updateAnimations):
* svg/animation/SMILTimeContainer.h:
(WebCore::SMILTimeContainer::create):
(SMILTimeContainer):
* svg/animation/SVGSMILElement.cpp:
(WebCore::SVGSMILElement::~SVGSMILElement):
(WebCore::SVGSMILElement::insertedInto):
(WebCore::SVGSMILElement::removedFrom):
(WebCore):
(WebCore::SVGSMILElement::hasValidAttributeName):
(WebCore::SVGSMILElement::svgAttributeChanged):
(WebCore::SVGSMILElement::setAttributeName):
(WebCore::SVGSMILElement::targetElementWillChange):
(WebCore::SVGSMILElement::resetTargetElement):
(WebCore::SVGSMILElement::resolveFirstInterval):
(WebCore::SVGSMILElement::beginListChanged):
(WebCore::SVGSMILElement::endListChanged):
(WebCore::SVGSMILElement::progress):
* svg/animation/SVGSMILElement.h:
(SVGSMILElement):
Modified Paths
Diff
Modified: trunk/Source/WebCore/ChangeLog (129669 => 129670)
--- trunk/Source/WebCore/ChangeLog 2012-09-26 17:51:42 UTC (rev 129669)
+++ trunk/Source/WebCore/ChangeLog 2012-09-26 17:53:27 UTC (rev 129670)
@@ -1,3 +1,88 @@
+2012-09-26 Philip Rogers <p...@google.com>
+
+ Refactor SMILTimeContainer to maintain animation information instead of recalculating it every frame
+ https://bugs.webkit.org/show_bug.cgi?id=96697
+
+ Reviewed by Eric Seidel.
+
+ SVGTimeContainer can be improved by maintaining extra information about
+ animations during schedule/unschedule instead of re-calculating it
+ every frame.
+
+ After this patch, SMILTimeContainer maintains a GroupedAnimationsMap instead of
+ just a Vector. This map maps a list of animations to the specific ElementAttributePair
+ that will be animated.
+
+ On schedule/unschedule we modify this map instead of creating it in updateAnimations.
+ As a result, we need to be careful about always notifying (or, re-scheduling) the
+ time container when either an animation's target changes or an animation's attributeName
+ changes. This notification is managed by tracking changes with targetElementWillChange
+ and setAttributeName.
+
+ After this patch, updateAnimations only iterates over m_scheduledAnimations.
+ Furthermore, the sorting of animations by priority is now done over each Vector of
+ SVGSMILElements affecting a {SVGElement*, QualifiedName} pair instead of over all the
+ SVGSMILElements at once.
+
+ Lastly, a guard (m_preventScheduledAnimationsChanges) has been added
+ to prove that we do not modify the scheduled animations map out
+ from under ourselves.
+
+ No new tests as this is just a refactoring.
+
+ * svg/SVGAnimateElement.cpp:
+ (WebCore::SVGAnimateElement::hasValidAttributeType):
+
+ * svg/SVGAnimateMotionElement.cpp:
+ (WebCore::SVGAnimateMotionElement::hasValidAttributeName):
+
+ Per the spec, AnimateMotion is not affected by attributeName. Instead
+ of having a special case for this in SMILTimeContainer::updateAnimations
+ we simply implement this method.
+
+ (WebCore):
+ * svg/SVGAnimateMotionElement.h:
+ (SVGAnimateMotionElement):
+ * svg/SVGAnimationElement.cpp:
+ (WebCore::SVGAnimationElement::updateAnimation):
+ * svg/animation/SMILTimeContainer.cpp:
+ (WebCore):
+ (WebCore::SMILTimeContainer::SMILTimeContainer):
+ (WebCore::SMILTimeContainer::~SMILTimeContainer):
+
+ This method now cleans up the map since we have dynamically allocated
+ Vectors in it.
+
+ (WebCore::SMILTimeContainer::schedule):
+
+ Here we are just adding an entry to the map. There is some special handling
+ for creating the Vector of one does not exist.
+
+ (WebCore::SMILTimeContainer::unschedule):
+ (WebCore::SMILTimeContainer::notifyIntervalsChanged):
+ (WebCore::SMILTimeContainer::setElapsed):
+ (WebCore::SMILTimeContainer::startTimer):
+ (WebCore::SMILTimeContainer::updateAnimations):
+ * svg/animation/SMILTimeContainer.h:
+ (WebCore::SMILTimeContainer::create):
+ (SMILTimeContainer):
+ * svg/animation/SVGSMILElement.cpp:
+ (WebCore::SVGSMILElement::~SVGSMILElement):
+ (WebCore::SVGSMILElement::insertedInto):
+ (WebCore::SVGSMILElement::removedFrom):
+ (WebCore):
+ (WebCore::SVGSMILElement::hasValidAttributeName):
+ (WebCore::SVGSMILElement::svgAttributeChanged):
+ (WebCore::SVGSMILElement::setAttributeName):
+ (WebCore::SVGSMILElement::targetElementWillChange):
+ (WebCore::SVGSMILElement::resetTargetElement):
+ (WebCore::SVGSMILElement::resolveFirstInterval):
+ (WebCore::SVGSMILElement::beginListChanged):
+ (WebCore::SVGSMILElement::endListChanged):
+ (WebCore::SVGSMILElement::progress):
+ * svg/animation/SVGSMILElement.h:
+ (SVGSMILElement):
+
2012-09-26 Michael Saboff <msab...@apple.com>
Update SVGFontData for 8 bit TextRun changes
Modified: trunk/Source/WebCore/svg/SVGAnimateMotionElement.cpp (129669 => 129670)
--- trunk/Source/WebCore/svg/SVGAnimateMotionElement.cpp 2012-09-26 17:51:42 UTC (rev 129669)
+++ trunk/Source/WebCore/svg/SVGAnimateMotionElement.cpp 2012-09-26 17:53:27 UTC (rev 129670)
@@ -87,6 +87,12 @@
return false;
}
+bool SVGAnimateMotionElement::hasValidAttributeName()
+{
+ // AnimateMotion does not use attributeName so it is always valid.
+ return true;
+}
+
bool SVGAnimateMotionElement::isSupportedAttribute(const QualifiedName& attrName)
{
DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
Modified: trunk/Source/WebCore/svg/SVGAnimateMotionElement.h (129669 => 129670)
--- trunk/Source/WebCore/svg/SVGAnimateMotionElement.h 2012-09-26 17:51:42 UTC (rev 129669)
+++ trunk/Source/WebCore/svg/SVGAnimateMotionElement.h 2012-09-26 17:53:27 UTC (rev 129670)
@@ -35,6 +35,7 @@
SVGAnimateMotionElement(const QualifiedName&, Document*);
virtual bool hasValidAttributeType();
+ virtual bool hasValidAttributeName();
bool isSupportedAttribute(const QualifiedName&);
virtual void parseAttribute(const Attribute&) OVERRIDE;
Modified: trunk/Source/WebCore/svg/animation/SMILTimeContainer.cpp (129669 => 129670)
--- trunk/Source/WebCore/svg/animation/SMILTimeContainer.cpp 2012-09-26 17:51:42 UTC (rev 129669)
+++ trunk/Source/WebCore/svg/animation/SMILTimeContainer.cpp 2012-09-26 17:53:27 UTC (rev 129670)
@@ -36,7 +36,7 @@
using namespace std;
namespace WebCore {
-
+
static const double animationFrameDelay = 0.025;
SMILTimeContainer::SMILTimeContainer(SVGSVGElement* owner)
@@ -47,38 +47,79 @@
, m_documentOrderIndexesDirty(false)
, m_timer(this, &SMILTimeContainer::timerFired)
, m_ownerSVGElement(owner)
+#ifndef NDEBUG
+ , m_preventScheduledAnimationsChanges(false)
+#endif
{
}
-void SMILTimeContainer::schedule(SVGSMILElement* animation)
+SMILTimeContainer::~SMILTimeContainer()
{
+#ifndef NDEBUG
+ ASSERT(!m_preventScheduledAnimationsChanges);
+#endif
+ deleteAllValues(m_scheduledAnimations);
+}
+
+void SMILTimeContainer::schedule(SVGSMILElement* animation, SVGElement* target, const QualifiedName& attributeName)
+{
ASSERT(animation->timeContainer() == this);
+ ASSERT(target);
+ ASSERT(animation->hasValidAttributeName());
+
+#ifndef NDEBUG
+ ASSERT(!m_preventScheduledAnimationsChanges);
+#endif
+
+ ElementAttributePair key(target, attributeName);
+ AnimationsVector* scheduled = m_scheduledAnimations.get(key);
+ if (!scheduled) {
+ scheduled = new AnimationsVector();
+ m_scheduledAnimations.set(key, scheduled);
+ }
+ ASSERT(!scheduled->contains(animation));
+ scheduled->append(animation);
+
SMILTime nextFireTime = animation->nextProgressTime();
- if (!nextFireTime.isFinite())
- return;
- m_scheduledAnimations.add(animation);
- startTimer(0);
+ if (nextFireTime.isFinite())
+ notifyIntervalsChanged();
}
-
-void SMILTimeContainer::unschedule(SVGSMILElement* animation)
+
+void SMILTimeContainer::unschedule(SVGSMILElement* animation, SVGElement* target, const QualifiedName& attributeName)
{
ASSERT(animation->timeContainer() == this);
- m_scheduledAnimations.remove(animation);
+#ifndef NDEBUG
+ ASSERT(!m_preventScheduledAnimationsChanges);
+#endif
+
+ ElementAttributePair key(target, attributeName);
+ AnimationsVector* scheduled = m_scheduledAnimations.get(key);
+ ASSERT(scheduled);
+ size_t idx = scheduled->find(animation);
+ ASSERT(idx != notFound);
+ scheduled->remove(idx);
}
+void SMILTimeContainer::notifyIntervalsChanged()
+{
+ // Schedule updateAnimations() to be called asynchronously so multiple intervals
+ // can change with updateAnimations() only called once at the end.
+ startTimer(0);
+}
+
SMILTime SMILTimeContainer::elapsed() const
{
if (!m_beginTime)
return 0;
return currentTime() - m_beginTime - m_accumulatedPauseTime;
}
-
+
bool SMILTimeContainer::isActive() const
{
return m_beginTime && !isPaused();
}
-
+
bool SMILTimeContainer::isPaused() const
{
return m_pauseTime;
@@ -144,10 +185,19 @@
if (m_pauseTime)
m_pauseTime = now;
- Vector<SVGSMILElement*> toReset;
- copyToVector(m_scheduledAnimations, toReset);
- for (unsigned n = 0; n < toReset.size(); ++n)
- toReset[n]->reset();
+#ifndef NDEBUG
+ m_preventScheduledAnimationsChanges = true;
+#endif
+ GroupedAnimationsMap::iterator end = m_scheduledAnimations.end();
+ for (GroupedAnimationsMap::iterator it = m_scheduledAnimations.begin(); it != end; ++it) {
+ AnimationsVector* scheduled = it->second;
+ unsigned size = scheduled->size();
+ for (unsigned n = 0; n < size; n++)
+ scheduled->at(n)->reset();
+ }
+#ifndef NDEBUG
+ m_preventScheduledAnimationsChanges = false;
+#endif
updateAnimations(time, true);
}
@@ -156,10 +206,10 @@
{
if (!m_beginTime || isPaused())
return;
-
+
if (!fireTime.isFinite())
return;
-
+
SMILTime delay = max(fireTime - elapsed(), minimumDelay);
m_timer.startOneShot(delay.value());
}
@@ -207,68 +257,71 @@
void SMILTimeContainer::updateAnimations(SMILTime elapsed, bool seekToTime)
{
- SMILTime earliersFireTime = SMILTime::unresolved();
+ SMILTime earliestFireTime = SMILTime::unresolved();
- Vector<SVGSMILElement*> toAnimate;
- copyToVector(m_scheduledAnimations, toAnimate);
+#ifndef NDEBUG
+ // This boolean will catch any attempts to schedule/unschedule scheduledAnimations during this critical section.
+ // Similarly, any elements removed will unschedule themselves, so this will catch modification of animationsToApply.
+ m_preventScheduledAnimationsChanges = true;
+#endif
- // Sort according to priority. Elements with later begin time have higher priority.
- // In case of a tie, document order decides.
- // FIXME: This should also consider timing relationships between the elements. Dependents
- // have higher priority.
- sortByPriority(toAnimate, elapsed);
+ AnimationsVector animationsToApply;
+ GroupedAnimationsMap::iterator end = m_scheduledAnimations.end();
+ for (GroupedAnimationsMap::iterator it = m_scheduledAnimations.begin(); it != end; ++it) {
+ AnimationsVector* scheduled = it->second;
- // Calculate animation contributions.
- typedef pair<SVGElement*, QualifiedName> ElementAttributePair;
- typedef HashMap<ElementAttributePair, SVGSMILElement*> ResultElementMap;
- ResultElementMap resultsElements;
- for (unsigned n = 0; n < toAnimate.size(); ++n) {
- SVGSMILElement* animation = toAnimate[n];
- ASSERT(animation->timeContainer() == this);
+ // Sort according to priority. Elements with later begin time have higher priority.
+ // In case of a tie, document order decides.
+ // FIXME: This should also consider timing relationships between the elements. Dependents
+ // have higher priority.
+ sortByPriority(*scheduled, elapsed);
- SVGElement* targetElement = animation->targetElement();
- if (!targetElement)
- continue;
+ SVGSMILElement* resultElement = 0;
+ unsigned size = scheduled->size();
+ for (unsigned n = 0; n < size; n++) {
+ SVGSMILElement* animation = scheduled->at(n);
+ ASSERT(animation->timeContainer() == this);
+ ASSERT(animation->targetElement());
+ ASSERT(animation->hasValidAttributeName());
- QualifiedName attributeName = animation->attributeName();
- if (attributeName == anyQName()) {
- if (animation->hasTagName(SVGNames::animateMotionTag))
- attributeName = SVGNames::animateMotionTag;
- else
- continue;
- }
+ // Results are accumulated to the first animation that animates and contributes to a particular element/attribute pair.
+ if (!resultElement) {
+ if (!animation->hasValidAttributeType())
+ continue;
+ resultElement = animation;
+ }
- // Results are accumulated to the first animation that animates and contributes to a particular element/attribute pair.
- ElementAttributePair key(targetElement, attributeName);
- SVGSMILElement* resultElement = resultsElements.get(key);
- if (!resultElement) {
- if (!animation->hasValidAttributeType())
- continue;
- resultElement = animation;
- } else
- ASSERT(resultElement != animation);
+ // This will calculate the contribution from the animation and add it to the resultsElement.
+ if (!animation->progress(elapsed, resultElement, seekToTime) && resultElement == animation)
+ resultElement = 0;
- // This will calculate the contribution from the animation and add it to the resultsElement.
- if (animation->progress(elapsed, resultElement, seekToTime) && resultElement == animation)
- resultsElements.add(key, resultElement);
+ SMILTime nextFireTime = animation->nextProgressTime();
+ if (nextFireTime.isFinite())
+ earliestFireTime = min(nextFireTime, earliestFireTime);
+ }
- SMILTime nextFireTime = animation->nextProgressTime();
- if (nextFireTime.isFinite())
- earliersFireTime = min(nextFireTime, earliersFireTime);
+ if (resultElement)
+ animationsToApply.append(resultElement);
}
- unsigned resultsToApplySize = resultsElements.size();
- if (!resultsToApplySize) {
- startTimer(earliersFireTime, animationFrameDelay);
+ unsigned animationsToApplySize = animationsToApply.size();
+ if (!animationsToApplySize) {
+#ifndef NDEBUG
+ m_preventScheduledAnimationsChanges = false;
+#endif
+ startTimer(earliestFireTime, animationFrameDelay);
return;
}
// Apply results to target elements.
- ResultElementMap::iterator end = resultsElements.end();
- for (ResultElementMap::iterator it = resultsElements.begin(); it != end; ++it)
- it->second->applyResultsToTarget();
+ for (unsigned i = 0; i < animationsToApplySize; ++i)
+ animationsToApply[i]->applyResultsToTarget();
- startTimer(earliersFireTime, animationFrameDelay);
+#ifndef NDEBUG
+ m_preventScheduledAnimationsChanges = false;
+#endif
+
+ startTimer(earliestFireTime, animationFrameDelay);
Document::updateStyleForAllDocuments();
}
Modified: trunk/Source/WebCore/svg/animation/SMILTimeContainer.h (129669 => 129670)
--- trunk/Source/WebCore/svg/animation/SMILTimeContainer.h 2012-09-26 17:51:42 UTC (rev 129669)
+++ trunk/Source/WebCore/svg/animation/SMILTimeContainer.h 2012-09-26 17:53:27 UTC (rev 129670)
@@ -46,17 +46,19 @@
class SMILTimeContainer : public RefCounted<SMILTimeContainer> {
public:
- static PassRefPtr<SMILTimeContainer> create(SVGSVGElement* owner) { return adoptRef(new SMILTimeContainer(owner)); }
+ static PassRefPtr<SMILTimeContainer> create(SVGSVGElement* owner) { return adoptRef(new SMILTimeContainer(owner)); }
+ ~SMILTimeContainer();
- void schedule(SVGSMILElement*);
- void unschedule(SVGSMILElement*);
-
+ void schedule(SVGSMILElement*, SVGElement*, const QualifiedName&);
+ void unschedule(SVGSMILElement*, SVGElement*, const QualifiedName&);
+ void notifyIntervalsChanged();
+
SMILTime elapsed() const;
bool isActive() const;
bool isPaused() const;
bool isStarted() const;
-
+
void begin();
void pause();
void resume();
@@ -66,14 +68,14 @@
private:
SMILTimeContainer(SVGSVGElement* owner);
-
+
void timerFired(Timer<SMILTimeContainer>*);
void startTimer(SMILTime fireTime, SMILTime minimumDelay = 0);
void updateAnimations(SMILTime elapsed, bool seekToTime = false);
void updateDocumentOrderIndexes();
void sortByPriority(Vector<SVGSMILElement*>& smilElements, SMILTime elapsed);
-
+
double m_beginTime;
double m_pauseTime;
double m_accumulatedPauseTime;
@@ -83,10 +85,16 @@
Timer<SMILTimeContainer> m_timer;
- typedef HashSet<SVGSMILElement*> TimingElementSet;
- TimingElementSet m_scheduledAnimations;
+ typedef pair<SVGElement*, QualifiedName> ElementAttributePair;
+ typedef Vector<SVGSMILElement*> AnimationsVector;
+ typedef HashMap<ElementAttributePair, AnimationsVector* > GroupedAnimationsMap;
+ GroupedAnimationsMap m_scheduledAnimations;
SVGSVGElement* m_ownerSVGElement;
+
+#ifndef NDEBUG
+ bool m_preventScheduledAnimationsChanges;
+#endif
};
}
Modified: trunk/Source/WebCore/svg/animation/SVGSMILElement.cpp (129669 => 129670)
--- trunk/Source/WebCore/svg/animation/SVGSMILElement.cpp 2012-09-26 17:51:42 UTC (rev 129669)
+++ trunk/Source/WebCore/svg/animation/SVGSMILElement.cpp 2012-09-26 17:53:27 UTC (rev 129670)
@@ -140,8 +140,8 @@
SVGSMILElement::~SVGSMILElement()
{
disconnectConditions();
- if (m_timeContainer)
- m_timeContainer->unschedule(this);
+ if (m_timeContainer && m_targetElement && hasValidAttributeName())
+ m_timeContainer->unschedule(this, m_targetElement, m_attributeName);
if (m_targetElement)
document()->accessSVGExtensions()->removeAnimationElementFromTarget(this, m_targetElement);
}
@@ -200,10 +200,11 @@
// Verify we are not in <use> instance tree.
ASSERT(!isInShadowTree());
- m_attributeName = constructQualifiedName(this, fastGetAttribute(SVGNames::attributeNameAttr));
+ setAttributeName(constructQualifiedName(this, fastGetAttribute(SVGNames::attributeNameAttr)));
SVGSVGElement* owner = ownerSVGElement();
if (!owner)
return InsertionDone;
+
m_timeContainer = owner->timeContainer();
ASSERT(m_timeContainer);
m_timeContainer->setDocumentOrderIndexesDirty();
@@ -215,7 +216,11 @@
if (m_isWaitingForFirstInterval)
resolveFirstInterval();
- reschedule();
+ // Force resolution of target element
+ if (!m_targetElement)
+ targetElement();
+ if (m_timeContainer)
+ m_timeContainer->notifyIntervalsChanged();
return InsertionDone;
}
@@ -224,7 +229,8 @@
{
if (rootParent->inDocument()) {
if (m_timeContainer) {
- m_timeContainer->unschedule(this);
+ if (m_targetElement && hasValidAttributeName())
+ m_timeContainer->unschedule(this, m_targetElement, m_attributeName);
m_timeContainer = 0;
}
// Calling disconnectConditions() may kill us if there are syncbase conditions.
@@ -234,14 +240,19 @@
// Clear target now, because disconnectConditions calls targetElement() which will recreate the target if we removed it sooner.
if (m_targetElement)
- resetTargetElement();
+ resetTargetElement(DoNotResolveNewTarget);
- m_attributeName = anyQName();
+ setAttributeName(anyQName());
}
SVGElement::removedFrom(rootParent);
}
-
+
+bool SVGSMILElement::hasValidAttributeName()
+{
+ return attributeName() != anyQName();
+}
+
SMILTime SVGSMILElement::parseOffsetValue(const String& data)
{
bool ok;
@@ -465,12 +476,13 @@
else if (attrName == SVGNames::endAttr)
endListChanged(elapsed());
else if (attrName == SVGNames::attributeNameAttr) {
- m_attributeName = constructQualifiedName(this, fastGetAttribute(SVGNames::attributeNameAttr));
+ setAttributeName(constructQualifiedName(this, fastGetAttribute(SVGNames::attributeNameAttr)));
if (m_targetElement) {
resetTargetElement();
return;
}
} else if (attrName.matches(XLinkNames::hrefAttr)) {
+ // targetElement is resolved lazily but targetElement() will handle calling targetElementWillChange().
if (SVGElement* targetElement = this->targetElement())
document()->accessSVGExtensions()->removeAllAnimationElementsFromTarget(targetElement);
}
@@ -543,10 +555,16 @@
}
}
-void SVGSMILElement::reschedule()
+void SVGSMILElement::setAttributeName(const QualifiedName& attributeName)
{
- if (m_timeContainer)
- m_timeContainer->schedule(this);
+ if (m_timeContainer && m_targetElement && m_attributeName != attributeName) {
+ if (hasValidAttributeName())
+ m_timeContainer->unschedule(this, m_targetElement, m_attributeName);
+ m_attributeName = attributeName;
+ if (hasValidAttributeName())
+ m_timeContainer->schedule(this, m_targetElement, m_attributeName);
+ } else
+ m_attributeName = attributeName;
}
SVGElement* SVGSMILElement::targetElement()
@@ -569,8 +587,15 @@
return m_targetElement;
}
-void SVGSMILElement::targetElementWillChange(SVGElement* currentTarget, SVGElement*)
+void SVGSMILElement::targetElementWillChange(SVGElement* currentTarget, SVGElement* newTarget)
{
+ if (m_timeContainer && hasValidAttributeName()) {
+ if (currentTarget)
+ m_timeContainer->unschedule(this, currentTarget, m_attributeName);
+ if (newTarget)
+ m_timeContainer->schedule(this, newTarget, m_attributeName);
+ }
+
// Only clear the animated type, if we had a target before.
if (currentTarget)
clearAnimatedType(currentTarget);
@@ -580,11 +605,16 @@
endedActiveInterval();
}
-void SVGSMILElement::resetTargetElement()
+void SVGSMILElement::resetTargetElement(ResolveTarget resolveTarget)
{
document()->accessSVGExtensions()->removeAnimationElementFromTarget(this, m_targetElement);
targetElementWillChange(m_targetElement, 0);
m_targetElement = 0;
+
+ // Immediately resolve the new targetElement (and call targetElementWillChange if needed) instead of doing it lazily.
+ if (resolveTarget == ResolveNewTarget)
+ targetElement();
+
animationAttributeChanged();
}
@@ -823,7 +853,9 @@
m_intervalEnd = end;
notifyDependentsIntervalChanged(wasUnresolved ? NewInterval : ExistingInterval);
m_nextProgressTime = min(m_nextProgressTime, m_intervalBegin);
- reschedule();
+
+ if (m_timeContainer)
+ m_timeContainer->notifyIntervalsChanged();
}
}
@@ -871,7 +903,9 @@
}
}
m_nextProgressTime = elapsed();
- reschedule();
+
+ if (m_timeContainer)
+ m_timeContainer->notifyIntervalsChanged();
}
void SVGSMILElement::endListChanged(SMILTime)
@@ -890,7 +924,9 @@
}
}
m_nextProgressTime = elapsed;
- reschedule();
+
+ if (m_timeContainer)
+ m_timeContainer->notifyIntervalsChanged();
}
void SVGSMILElement::checkRestart(SMILTime elapsed)
@@ -1018,10 +1054,10 @@
ASSERT(resultElement);
ASSERT(m_timeContainer);
ASSERT(m_isWaitingForFirstInterval || m_intervalBegin.isFinite());
-
+
if (!m_conditionsConnected)
connectConditions();
-
+
if (!m_intervalBegin.isFinite()) {
ASSERT(m_activeState == Inactive);
m_nextProgressTime = SMILTime::unresolved();
@@ -1035,7 +1071,7 @@
m_nextProgressTime = m_intervalBegin;
return false;
}
-
+
m_previousIntervalBegin = m_intervalBegin;
if (m_isWaitingForFirstInterval) {
Modified: trunk/Source/WebCore/svg/animation/SVGSMILElement.h (129669 => 129670)
--- trunk/Source/WebCore/svg/animation/SVGSMILElement.h 2012-09-26 17:51:42 UTC (rev 129669)
+++ trunk/Source/WebCore/svg/animation/SVGSMILElement.h 2012-09-26 17:53:27 UTC (rev 129670)
@@ -32,7 +32,9 @@
#include <wtf/HashMap.h>
namespace WebCore {
-
+
+enum ResolveTarget { DoNotResolveNewTarget, ResolveNewTarget };
+
class ConditionEventListener;
class SMILTimeContainer;
@@ -51,12 +53,13 @@
virtual void removedFrom(ContainerNode*) OVERRIDE;
virtual bool hasValidAttributeType() = 0;
+ virtual bool hasValidAttributeName();
virtual void animationAttributeChanged() = 0;
SMILTimeContainer* timeContainer() const { return m_timeContainer.get(); }
SVGElement* targetElement();
- void resetTargetElement();
+ void resetTargetElement(ResolveTarget = ResolveNewTarget);
const QualifiedName& attributeName() const { return m_attributeName; }
void beginByLinkActivation();
@@ -138,8 +141,9 @@
void checkRestart(SMILTime elapsed);
void beginListChanged(SMILTime eventTime);
void endListChanged(SMILTime eventTime);
- void reschedule();
+ void setAttributeName(const QualifiedName&);
+
// This represents conditions on elements begin or end list that need to be resolved on runtime
// for example <animate begin="otherElement.begin + 8s; button.click" ... />
struct Condition {