void SMILTimeContainer::updateAnimations(SMILTime elapsed, double nextManualSampleTime, const String& nextSamplingTarget) { SMILTime earliersFireTime = SMILTime::unresolved(); Vector<SVGSMILElement*> toAnimate; copyToVector(m_scheduledAnimations, toAnimate); if (nextManualSampleTime) { SMILTime samplingDiff; for (unsigned n = 0; n < toAnimate.size(); ++n) { SVGSMILElement* animation = toAnimate[n]; ASSERT(animation->timeContainer() == this); SVGElement* targetElement = animation->targetElement(); // FIXME: This should probably be using getIdAttribute instead of idForStyleResolution. if (!targetElement || !targetElement->hasID() || targetElement->idForStyleResolution() != nextSamplingTarget) continue; samplingDiff = animation->intervalBegin(); break; } elapsed = SMILTime(nextManualSampleTime) + samplingDiff; } // 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); // Calculate animation contributions. typedef HashMap<ElementAttributePair, RefPtr<SVGSMILElement> > ResultElementMap; ResultElementMap resultsElements; for (unsigned n = 0; n < toAnimate.size(); ++n) { SVGSMILElement* animation = toAnimate[n]; ASSERT(animation->timeContainer() == this); SVGElement* targetElement = animation->targetElement(); if (!targetElement) continue; 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 a particular element/attribute pair. ElementAttributePair key(targetElement, attributeName); SVGSMILElement* resultElement = resultsElements.get(key).get(); if (!resultElement) { if (!animation->hasValidAttributeType()) continue; resultElement = animation; resultElement->resetToBaseValue(baseValueFor(key)); resultsElements.add(key, resultElement); } // This will calculate the contribution from the animation and add it to the resultsElement. animation->progress(elapsed, resultElement); SMILTime nextFireTime = animation->nextProgressTime(); if (nextFireTime.isFinite()) earliersFireTime = min(nextFireTime, earliersFireTime); } Vector<SVGSMILElement*> animationsToApply; ResultElementMap::iterator end = resultsElements.end(); for (ResultElementMap::iterator it = resultsElements.begin(); it != end; ++it) animationsToApply.append(it->second.get()); // Sort <animateTranform> to be the last one to be applied. <animate> may change transform attribute as // well (directly or indirectly by modifying <use> x/y) and this way transforms combine properly. sortByApplyOrder(animationsToApply); // Apply results to target elements. for (unsigned n = 0; n < animationsToApply.size(); ++n) animationsToApply[n]->applyResultsToTarget(); startTimer(earliersFireTime, animationFrameDelay); Document::updateStyleForAllDocuments(); }
void SMILTimeContainer::updateAnimations(SMILTime elapsed, bool seekToTime) { SMILTime earliersFireTime = SMILTime::unresolved(); Vector<SVGSMILElement*> toAnimate; copyToVector(m_scheduledAnimations, toAnimate); // 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); // Calculate animation contributions. typedef pair<SVGElement*, QualifiedName> ElementAttributePair; typedef HashMap<ElementAttributePair, RefPtr<SVGSMILElement> > ResultElementMap; ResultElementMap resultsElements; HashSet<SVGSMILElement*> contributingElements; for (unsigned n = 0; n < toAnimate.size(); ++n) { SVGSMILElement* animation = toAnimate[n]; ASSERT(animation->timeContainer() == this); SVGElement* targetElement = animation->targetElement(); if (!targetElement) continue; 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. ElementAttributePair key(targetElement, attributeName); SVGSMILElement* resultElement = resultsElements.get(key).get(); bool accumulatedResultElement = false; if (!resultElement) { if (!animation->hasValidAttributeType()) continue; resultElement = animation; resultsElements.add(key, resultElement); accumulatedResultElement = true; } // This will calculate the contribution from the animation and add it to the resultsElement. if (animation->progress(elapsed, resultElement, seekToTime)) contributingElements.add(resultElement); else if (accumulatedResultElement) resultsElements.remove(key); SMILTime nextFireTime = animation->nextProgressTime(); if (nextFireTime.isFinite()) earliersFireTime = min(nextFireTime, earliersFireTime); } Vector<SVGSMILElement*> animationsToApply; ResultElementMap::iterator end = resultsElements.end(); for (ResultElementMap::iterator it = resultsElements.begin(); it != end; ++it) { SVGSMILElement* animation = it->second.get(); if (contributingElements.contains(animation)) animationsToApply.append(animation); } unsigned animationsToApplySize = animationsToApply.size(); if (!animationsToApplySize) { startTimer(earliersFireTime, animationFrameDelay); return; } // Sort <animateTranform> to be the last one to be applied. <animate> may change transform attribute as // well (directly or indirectly by modifying <use> x/y) and this way transforms combine properly. sortByApplyOrder(animationsToApply); // Apply results to target elements. for (unsigned i = 0; i < animationsToApplySize; ++i) animationsToApply[i]->applyResultsToTarget(); startTimer(earliersFireTime, animationFrameDelay); Document::updateStyleForAllDocuments(); }