| Index: Source/WebCore/svg/animation/SMILTimeContainer.cpp
|
| ===================================================================
|
| --- Source/WebCore/svg/animation/SMILTimeContainer.cpp (revision 132107)
|
| +++ Source/WebCore/svg/animation/SMILTimeContainer.cpp (working copy)
|
| @@ -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();
|
| }
|
|
|
|
|