void SMILTimeContainer::setElapsed(SMILTime time) { // If the documment didn't begin yet, record a new start time, we'll seek to once its possible. if (!m_beginTime) { m_presetStartTime = time.value(); return; } if (m_beginTime) m_timer.stop(); double now = currentTime(); m_beginTime = now - time.value(); m_accumulatedPauseTime = 0; if (m_pauseTime) m_pauseTime = now; #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); }
void SMILTimeContainer::setElapsed(SMILTime time) { // If the documment didn't begin yet, record a new start time, we'll seek to once its possible. if (!m_beginTime) { m_presetStartTime = time.value(); return; } if (m_beginTime) m_timer.stop(); double now = monotonicallyIncreasingTime(); m_beginTime = now - time.value(); if (m_pauseTime) { m_resumeTime = m_pauseTime = now; m_accumulatedActiveTime = time.value(); } else m_resumeTime = m_beginTime; #ifndef NDEBUG m_preventScheduledAnimationsChanges = true; #endif for (auto& it : m_scheduledAnimations) { AnimationsVector* scheduled = it.value.get(); unsigned size = scheduled->size(); for (unsigned n = 0; n < size; n++) scheduled->at(n)->reset(); } #ifndef NDEBUG m_preventScheduledAnimationsChanges = false; #endif updateAnimations(time, true); }
void SMILTimeContainer::unschedule(SVGSMILElement* animation, SVGElement* target, const QualifiedName& attributeName) { ASSERT(animation->timeContainer() == this); #ifndef NDEBUG ASSERT(!m_preventScheduledAnimationsChanges); #endif ElementAttributePair key(target, attributeName); AnimationsVector* scheduled = m_scheduledAnimations.get(key); ASSERT(scheduled); bool removed = scheduled->removeFirst(animation); ASSERT_UNUSED(removed, removed); }
void SMILTimeContainer::unschedule(SVGSMILElement* animation, SVGElement* target, const QualifiedName& attributeName) { ASSERT(animation->timeContainer() == this); #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::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()) notifyIntervalsChanged(); }
void SMILTimeContainer::updateAnimations(SMILTime elapsed, bool seekToTime) { SMILTime earliestFireTime = SMILTime::unresolved(); #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 AnimationsVector animationsToApply; GroupedAnimationsMap::iterator end = m_scheduledAnimations.end(); for (GroupedAnimationsMap::iterator it = m_scheduledAnimations.begin(); it != end; ++it) { AnimationsVector* scheduled = it->second; // 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); 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()); // 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; } // This will calculate the contribution from the animation and add it to the resultsElement. if (!animation->progress(elapsed, resultElement, seekToTime) && resultElement == animation) resultElement = 0; SMILTime nextFireTime = animation->nextProgressTime(); if (nextFireTime.isFinite()) earliestFireTime = min(nextFireTime, earliestFireTime); } if (resultElement) animationsToApply.append(resultElement); } unsigned animationsToApplySize = animationsToApply.size(); if (!animationsToApplySize) { #ifndef NDEBUG m_preventScheduledAnimationsChanges = false; #endif startTimer(earliestFireTime, animationFrameDelay); return; } // Apply results to target elements. for (unsigned i = 0; i < animationsToApplySize; ++i) animationsToApply[i]->applyResultsToTarget(); #ifndef NDEBUG m_preventScheduledAnimationsChanges = false; #endif startTimer(earliestFireTime, animationFrameDelay); Document::updateStyleForAllDocuments(); }
void SMILTimeContainer::updateAnimations(SMILTime elapsed, bool seekToTime) { SMILTime earliestFireTime = SMILTime::unresolved(); #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 if (m_documentOrderIndexesDirty) updateDocumentOrderIndexes(); Vector<RefPtr<SVGSMILElement> > animationsToApply; GroupedAnimationsMap::iterator end = m_scheduledAnimations.end(); for (GroupedAnimationsMap::iterator it = m_scheduledAnimations.begin(); it != end; ++it) { AnimationsVector* scheduled = it->value.get(); // 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. std::sort(scheduled->begin(), scheduled->end(), PriorityCompare(elapsed)); 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()); // Results are accumulated to the first animation that animates and contributes to a particular element/attribute pair. // FIXME: we should ensure that resultElement is of an appropriate type. if (!resultElement) { if (!animation->hasValidAttributeType()) continue; 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; SMILTime nextFireTime = animation->nextProgressTime(); if (nextFireTime.isFinite()) earliestFireTime = min(nextFireTime, earliestFireTime); } if (resultElement) animationsToApply.append(resultElement); } std::sort(animationsToApply.begin(), animationsToApply.end(), PriorityCompare(elapsed)); unsigned animationsToApplySize = animationsToApply.size(); if (!animationsToApplySize) { #ifndef NDEBUG m_preventScheduledAnimationsChanges = false; #endif scheduleAnimationFrame(earliestFireTime); return; } // Apply results to target elements. for (unsigned i = 0; i < animationsToApplySize; ++i) animationsToApply[i]->applyResultsToTarget(); #ifndef NDEBUG m_preventScheduledAnimationsChanges = false; #endif scheduleAnimationFrame(earliestFireTime); for (unsigned i = 0; i < animationsToApplySize; ++i) { if (animationsToApply[i]->inDocument() && animationsToApply[i]->isSVGDiscardElement()) { RefPtr<SVGSMILElement> animDiscard = animationsToApply[i]; RefPtr<SVGElement> targetElement = animDiscard->targetElement(); if (targetElement && targetElement->inDocument()) { targetElement->remove(IGNORE_EXCEPTION); ASSERT(!targetElement->inDocument()); } if (animDiscard->inDocument()) { animDiscard->remove(IGNORE_EXCEPTION); ASSERT(!animDiscard->inDocument()); } } } }
SMILTime SMILTimeContainer::updateAnimations(SMILTime elapsed, bool seekToTime) { SMILTime earliestFireTime = SMILTime::unresolved(); #if ENABLE(ASSERT) // 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 if (m_documentOrderIndexesDirty) updateDocumentOrderIndexes(); WillBeHeapHashSet<ElementAttributePair> invalidKeys; using AnimationsVector = WillBeHeapVector<RefPtrWillBeMember<SVGSMILElement>>; AnimationsVector animationsToApply; for (const auto& entry : m_scheduledAnimations) { if (!entry.key.first || entry.value->isEmpty()) { invalidKeys.add(entry.key); continue; } AnimationsLinkedHashSet* scheduled = entry.value.get(); // 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. AnimationsVector scheduledAnimations; copyToVector(*scheduled, scheduledAnimations); std::sort(scheduledAnimations.begin(), scheduledAnimations.end(), PriorityCompare(elapsed)); SVGSMILElement* resultElement = nullptr; for (const auto& itAnimation : scheduledAnimations) { SVGSMILElement* animation = itAnimation.get(); ASSERT(animation->timeContainer() == this); ASSERT(animation->targetElement()); ASSERT(animation->hasValidAttributeName()); // Results are accumulated to the first animation that animates and contributes to a particular element/attribute pair. // FIXME: we should ensure that resultElement is of an appropriate type. if (!resultElement) { if (!animation->hasValidAttributeType()) continue; 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 = nullptr; SMILTime nextFireTime = animation->nextProgressTime(); if (nextFireTime.isFinite()) earliestFireTime = std::min(nextFireTime, earliestFireTime); } if (resultElement) animationsToApply.append(resultElement); } m_scheduledAnimations.removeAll(invalidKeys); std::sort(animationsToApply.begin(), animationsToApply.end(), PriorityCompare(elapsed)); unsigned animationsToApplySize = animationsToApply.size(); if (!animationsToApplySize) { #if ENABLE(ASSERT) m_preventScheduledAnimationsChanges = false; #endif return earliestFireTime; } // Apply results to target elements. for (unsigned i = 0; i < animationsToApplySize; ++i) animationsToApply[i]->applyResultsToTarget(); #if ENABLE(ASSERT) m_preventScheduledAnimationsChanges = false; #endif for (unsigned i = 0; i < animationsToApplySize; ++i) { if (animationsToApply[i]->inDocument() && animationsToApply[i]->isSVGDiscardElement()) { RefPtrWillBeRawPtr<SVGSMILElement> animDiscard = animationsToApply[i]; RefPtrWillBeRawPtr<SVGElement> targetElement = animDiscard->targetElement(); if (targetElement && targetElement->inDocument()) { targetElement->remove(IGNORE_EXCEPTION); ASSERT(!targetElement->inDocument()); } if (animDiscard->inDocument()) { animDiscard->remove(IGNORE_EXCEPTION); ASSERT(!animDiscard->inDocument()); } } } return earliestFireTime; }