diff options
5 files changed, 245 insertions, 84 deletions
diff --git a/third_party/WebKit/LayoutTests/animations/multiple-same-animations-asan-crash.html b/third_party/WebKit/LayoutTests/animations/multiple-same-animations-asan-crash.html index 42a4fdd..3a22397 100644 --- a/third_party/WebKit/LayoutTests/animations/multiple-same-animations-asan-crash.html +++ b/third_party/WebKit/LayoutTests/animations/multiple-same-animations-asan-crash.html @@ -16,8 +16,6 @@ requestAnimationFrame(function() { // Force the next style recalc to be non-animation triggered. target.style.color = 'blue'; requestAnimationFrame(function() { - // Clear the running animations to avoid hitting a debug assertion. (crbug.com/487092) - target.style.animation = 'none'; asyncHandle.done(); }); }); diff --git a/third_party/WebKit/LayoutTests/animations/multiple-same-name-css-animations.html b/third_party/WebKit/LayoutTests/animations/multiple-same-name-css-animations.html new file mode 100644 index 0000000..fe1c3f2 --- /dev/null +++ b/third_party/WebKit/LayoutTests/animations/multiple-same-name-css-animations.html @@ -0,0 +1,139 @@ +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<style> +@keyframes a {} +@keyframes b {} +</style> +<div id="target"></div> +<script> +function setAnimationProperty(value) { + target.style.animation = value; + target.offsetTop; +} + +function getAnimations() { + return document.timeline.getAnimations(); +} + +function clearAnimations() { + setAnimationProperty('none'); + assert_equals(getAnimations().length, 0); +} + +test(() => { + clearAnimations(); + setAnimationProperty('a 1000ms 1500ms forwards, a 2000ms 2500ms backwards, a 3000ms 3500ms both'); + var animations = getAnimations(); + assert_equals(animations.length, 3); + assert_equals(animations[0].effect.timing.duration, 1000); + assert_equals(animations[0].effect.timing.delay, 1500); + assert_equals(animations[0].effect.timing.fill, 'forwards'); + + assert_equals(animations[1].effect.timing.duration, 2000); + assert_equals(animations[1].effect.timing.delay, 2500); + assert_equals(animations[1].effect.timing.fill, 'backwards'); + + assert_equals(animations[2].effect.timing.duration, 3000); + assert_equals(animations[2].effect.timing.delay, 3500); + assert_equals(animations[2].effect.timing.fill, 'both'); +}, 'Multiple same animation names should start multiple animations.'); + +test(() => { + clearAnimations(); + + setAnimationProperty('a 1500ms paused, a 2500ms paused, a 3500ms paused'); + var animations = getAnimations(); + assert_equals(animations.length, 3); + animations[0].currentTime = 1000; + animations[1].currentTime = 2000; + animations[2].currentTime = 3000; + + setAnimationProperty('a 1750ms paused, a 2750ms paused, a 3750ms paused'); + animations = getAnimations(); + assert_equals(animations.length, 3); + + assert_equals(animations[0].currentTime, 1000); + assert_equals(animations[0].effect.timing.duration, 1750); + + assert_equals(animations[1].currentTime, 2000); + assert_equals(animations[1].effect.timing.duration, 2750); + + assert_equals(animations[2].currentTime, 3000); + assert_equals(animations[2].effect.timing.duration, 3750); +}, 'Multiple same animation names should persist with animation timing updates.'); + +test(() => { + clearAnimations(); + + setAnimationProperty('a 1500ms paused, a 2500ms paused, b 3500ms paused, b 4500ms paused'); + var animations = getAnimations(); + assert_equals(animations.length, 4); + animations[0].currentTime = 1000; + animations[1].currentTime = 2000; + animations[2].currentTime = 3000; + animations[3].currentTime = 4000; + + setAnimationProperty('a 1500ms paused, b 3500ms paused, a 2500ms paused, b 4500ms paused'); + animations = getAnimations(); + assert_equals(animations.length, 4); + + assert_equals(animations[0].currentTime, 1000); + assert_equals(animations[0].effect.timing.duration, 1500); + + assert_equals(animations[1].currentTime, 2000); + assert_equals(animations[1].effect.timing.duration, 2500); + + assert_equals(animations[2].currentTime, 3000); + assert_equals(animations[2].effect.timing.duration, 3500); + + assert_equals(animations[3].currentTime, 4000); + assert_equals(animations[3].effect.timing.duration, 4500); +}, 'Mixed multiple same animation names should persist based on their same name relative position'); + +test(() => { + clearAnimations(); + + setAnimationProperty('a 1500ms paused, a 2500ms paused, a 3500ms paused'); + var animations = getAnimations(); + assert_equals(animations.length, 3); + animations[0].currentTime = 1000; + animations[1].currentTime = 2000; + animations[2].currentTime = 3000; + + setAnimationProperty('a 1500ms paused, b 2500ms paused, a 3500ms paused'); + animations = getAnimations(); + assert_equals(animations.length, 3); + + assert_equals(animations[0].currentTime, 1000); + assert_equals(animations[0].effect.timing.duration, 1500); + + assert_equals(animations[1].currentTime, 2000); + assert_equals(animations[1].effect.timing.duration, 3500); + + assert_equals(animations[2].currentTime, null); + assert_equals(animations[2].effect.timing.duration, 2500); +}, 'Removing same animation names should cancel animations from the end of the name list.'); + +test(() => { + clearAnimations(); + + setAnimationProperty('a 1500ms paused, a 2500ms paused'); + var animations = getAnimations(); + assert_equals(animations.length, 2); + animations[0].currentTime = 1000; + animations[1].currentTime = 2000; + + setAnimationProperty('a 3500ms paused, a 2500ms paused, a 1500ms paused'); + animations = getAnimations(); + assert_equals(animations.length, 3); + + assert_equals(animations[0].currentTime, 1000); + assert_equals(animations[0].effect.timing.duration, 3500); + + assert_equals(animations[1].currentTime, 2000); + assert_equals(animations[1].effect.timing.duration, 2500); + + assert_equals(animations[2].currentTime, null); + assert_equals(animations[2].effect.timing.duration, 1500); +}, 'Adding same animation names should start additional animations from the end of the name list.'); +</script> diff --git a/third_party/WebKit/Source/core/animation/css/CSSAnimationUpdate.h b/third_party/WebKit/Source/core/animation/css/CSSAnimationUpdate.h index a45b0a9..5131ac4 100644 --- a/third_party/WebKit/Source/core/animation/css/CSSAnimationUpdate.h +++ b/third_party/WebKit/Source/core/animation/css/CSSAnimationUpdate.h @@ -36,8 +36,9 @@ public: { } - NewAnimation(AtomicString name, InertEffect* effect, Timing timing, PassRefPtrWillBeRawPtr<StyleRuleKeyframes> styleRule) + NewAnimation(AtomicString name, size_t nameIndex, InertEffect* effect, Timing timing, PassRefPtrWillBeRawPtr<StyleRuleKeyframes> styleRule) : name(name) + , nameIndex(nameIndex) , effect(effect) , timing(timing) , styleRule(styleRule) @@ -52,6 +53,7 @@ public: } AtomicString name; + size_t nameIndex; Member<InertEffect> effect; Timing timing; RefPtrWillBeMember<StyleRuleKeyframes> styleRule; @@ -66,8 +68,8 @@ public: { } - UpdatedAnimation(AtomicString name, Animation* animation, InertEffect* effect, Timing specifiedTiming, PassRefPtrWillBeRawPtr<StyleRuleKeyframes> styleRule) - : name(name) + UpdatedAnimation(size_t index, Animation* animation, InertEffect* effect, Timing specifiedTiming, PassRefPtrWillBeRawPtr<StyleRuleKeyframes> styleRule) + : index(index) , animation(animation) , effect(effect) , specifiedTiming(specifiedTiming) @@ -83,7 +85,7 @@ public: visitor->trace(styleRule); } - AtomicString name; + size_t index; Member<Animation> animation; Member<InertEffect> effect; Timing specifiedTiming; @@ -110,8 +112,8 @@ public: m_newTransitions = update.newTransitions(); m_activeInterpolationsForAnimations = update.activeInterpolationsForAnimations(); m_activeInterpolationsForTransitions = update.activeInterpolationsForTransitions(); - m_cancelledAnimationNames = update.cancelledAnimationNames(); - m_animationsWithPauseToggled = update.animationsWithPauseToggled(); + m_cancelledAnimationIndices = update.cancelledAnimationIndices(); + m_animationIndicesWithPauseToggled = update.animationIndicesWithPauseToggled(); m_cancelledTransitions = update.cancelledTransitions(); m_finishedTransitions = update.finishedTransitions(); m_updatedCompositorKeyframes = update.updatedCompositorKeyframes(); @@ -124,33 +126,33 @@ public: m_newTransitions.clear(); m_activeInterpolationsForAnimations.clear(); m_activeInterpolationsForTransitions.clear(); - m_cancelledAnimationNames.clear(); - m_animationsWithPauseToggled.clear(); + m_cancelledAnimationIndices.clear(); + m_animationIndicesWithPauseToggled.clear(); m_cancelledTransitions.clear(); m_finishedTransitions.clear(); m_updatedCompositorKeyframes.clear(); } - void startAnimation(const AtomicString& animationName, InertEffect* effect, const Timing& timing, PassRefPtrWillBeRawPtr<StyleRuleKeyframes> styleRule) + void startAnimation(const AtomicString& animationName, size_t nameIndex, InertEffect* effect, const Timing& timing, PassRefPtrWillBeRawPtr<StyleRuleKeyframes> styleRule) { effect->setName(animationName); - m_newAnimations.append(NewAnimation(animationName, effect, timing, styleRule)); + m_newAnimations.append(NewAnimation(animationName, nameIndex, effect, timing, styleRule)); } // Returns whether animation has been suppressed and should be filtered during style application. bool isSuppressedAnimation(const Animation* animation) const { return m_suppressedAnimations.contains(animation); } - void cancelAnimation(const AtomicString& name, Animation& animation) + void cancelAnimation(size_t index, const Animation& animation) { - m_cancelledAnimationNames.append(name); + m_cancelledAnimationIndices.append(index); m_suppressedAnimations.add(&animation); } - void toggleAnimationPaused(const AtomicString& name) + void toggleAnimationIndexPaused(size_t index) { - m_animationsWithPauseToggled.append(name); + m_animationIndicesWithPauseToggled.append(index); } - void updateAnimation(const AtomicString& name, Animation* animation, InertEffect* effect, const Timing& specifiedTiming, + void updateAnimation(size_t index, Animation* animation, InertEffect* effect, const Timing& specifiedTiming, PassRefPtrWillBeRawPtr<StyleRuleKeyframes> styleRule) { - m_animationsWithUpdates.append(UpdatedAnimation(name, animation, effect, specifiedTiming, styleRule)); + m_animationsWithUpdates.append(UpdatedAnimation(index, animation, effect, specifiedTiming, styleRule)); m_suppressedAnimations.add(animation); } void updateCompositorKeyframes(Animation* animation) @@ -173,9 +175,9 @@ public: void finishTransition(CSSPropertyID id) { m_finishedTransitions.add(id); } const HeapVector<NewAnimation>& newAnimations() const { return m_newAnimations; } - const Vector<AtomicString>& cancelledAnimationNames() const { return m_cancelledAnimationNames; } + const Vector<size_t>& cancelledAnimationIndices() const { return m_cancelledAnimationIndices; } const HeapHashSet<Member<const Animation>>& suppressedAnimations() const { return m_suppressedAnimations; } - const Vector<AtomicString>& animationsWithPauseToggled() const { return m_animationsWithPauseToggled; } + const Vector<size_t>& animationIndicesWithPauseToggled() const { return m_animationIndicesWithPauseToggled; } const HeapVector<UpdatedAnimation>& animationsWithUpdates() const { return m_animationsWithUpdates; } const HeapVector<Member<Animation>>& updatedCompositorKeyframes() const { return m_updatedCompositorKeyframes; } @@ -206,9 +208,9 @@ public: bool isEmpty() const { return m_newAnimations.isEmpty() - && m_cancelledAnimationNames.isEmpty() + && m_cancelledAnimationIndices.isEmpty() && m_suppressedAnimations.isEmpty() - && m_animationsWithPauseToggled.isEmpty() + && m_animationIndicesWithPauseToggled.isEmpty() && m_animationsWithUpdates.isEmpty() && m_newTransitions.isEmpty() && m_cancelledTransitions.isEmpty() @@ -233,9 +235,9 @@ private: // with the same name, due to the way in which we split up animations with // incomplete keyframes. HeapVector<NewAnimation> m_newAnimations; - Vector<AtomicString> m_cancelledAnimationNames; + Vector<size_t> m_cancelledAnimationIndices; HeapHashSet<Member<const Animation>> m_suppressedAnimations; - Vector<AtomicString> m_animationsWithPauseToggled; + Vector<size_t> m_animationIndicesWithPauseToggled; HeapVector<UpdatedAnimation> m_animationsWithUpdates; HeapVector<Member<Animation>> m_updatedCompositorKeyframes; diff --git a/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp b/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp index 13865e9..4070218 100644 --- a/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp +++ b/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp @@ -191,8 +191,8 @@ CSSAnimations::CSSAnimations() bool CSSAnimations::isAnimationForInspector(const Animation& animation) { - for (const auto& it : m_animations) { - if (it.value->animation->sequenceNumber() == animation.sequenceNumber()) + for (const auto& runningAnimation : m_runningAnimations) { + if (runningAnimation->animation->sequenceNumber() == animation.sequenceNumber()) return true; } return false; @@ -232,7 +232,7 @@ void CSSAnimations::calculateCompositorAnimationUpdate(CSSAnimationUpdate& updat return; CSSAnimations& cssAnimations = elementAnimations->cssAnimations(); - for (auto& runningAnimation : cssAnimations.m_animations.values()) { + for (auto& runningAnimation : cssAnimations.m_runningAnimations) { Animation& animation = *runningAnimation->animation; if (animation.effect() && animation.effect()->isKeyframeEffect()) { EffectModel* model = toKeyframeEffect(animation.effect())->model(); @@ -276,18 +276,24 @@ void CSSAnimations::calculateAnimationUpdate(CSSAnimationUpdate& update, const E const CSSAnimations* cssAnimations = elementAnimations ? &elementAnimations->cssAnimations() : nullptr; const Element* elementForScoping = animatingElement ? animatingElement : &element; - HashSet<AtomicString> inactive; - if (cssAnimations) { - for (const auto& entry : cssAnimations->m_animations) - inactive.add(entry.key); - } + Vector<bool> cancelRunningAnimationFlags(cssAnimations ? cssAnimations->m_runningAnimations.size() : 0); + for (bool& flag : cancelRunningAnimationFlags) + flag = true; - if (style.display() != NONE) { - for (size_t i = 0; animationData && i < animationData->nameList().size(); ++i) { - AtomicString animationName(animationData->nameList()[i]); - if (animationName == CSSAnimationData::initialName()) + if (animationData && style.display() != NONE) { + const Vector<AtomicString>& nameList = animationData->nameList(); + for (size_t i = 0; i < nameList.size(); ++i) { + AtomicString name = nameList[i]; + if (name == CSSAnimationData::initialName()) continue; + // Find n where this is the nth occurence of this animation name. + size_t nameIndex = 0; + for (size_t j = 0; j < i; j++) { + if (nameList[j] == name) + nameIndex++; + } + const bool isPaused = CSSTimingData::getRepeated(animationData->playStateList(), i) == AnimPlayStatePaused; Timing timing = animationData->convertToTiming(i); @@ -295,45 +301,54 @@ void CSSAnimations::calculateAnimationUpdate(CSSAnimationUpdate& update, const E RefPtr<TimingFunction> keyframeTimingFunction = timing.timingFunction; timing.timingFunction = Timing::defaults().timingFunction; - RefPtrWillBeRawPtr<StyleRuleKeyframes> keyframesRule = resolver->findKeyframesRule(elementForScoping, animationName); + RefPtrWillBeRawPtr<StyleRuleKeyframes> keyframesRule = resolver->findKeyframesRule(elementForScoping, name); if (!keyframesRule) continue; // Cancel the animation if there's no style rule for it. + const RunningAnimation* existingAnimation = nullptr; + size_t existingAnimationIndex = 0; + if (cssAnimations) { - AnimationMap::const_iterator existing(cssAnimations->m_animations.find(animationName)); - if (existing != cssAnimations->m_animations.end()) { - inactive.remove(animationName); - - const RunningAnimation* runningAnimation = existing->value.get(); - Animation* animation = runningAnimation->animation.get(); - - if (keyframesRule != runningAnimation->styleRule || keyframesRule->version() != runningAnimation->styleRuleVersion || runningAnimation->specifiedTiming != specifiedTiming) { - ASSERT(!isAnimationStyleChange); - update.updateAnimation(animationName, animation, InertEffect::create( - createKeyframeEffectModel(resolver, animatingElement, element, &style, parentStyle, animationName, keyframeTimingFunction.get(), i), - timing, isPaused, animation->unlimitedCurrentTimeInternal()), specifiedTiming, keyframesRule); + for (size_t i = 0; i < cssAnimations->m_runningAnimations.size(); i++) { + const RunningAnimation& runningAnimation = *cssAnimations->m_runningAnimations[i]; + if (runningAnimation.name == name && runningAnimation.nameIndex == nameIndex) { + existingAnimation = &runningAnimation; + existingAnimationIndex = i; + break; } + } + } - if (isPaused != animation->paused()) { - ASSERT(!isAnimationStyleChange); - update.toggleAnimationPaused(animationName); - } + if (existingAnimation) { + cancelRunningAnimationFlags[existingAnimationIndex] = false; + + Animation* animation = existingAnimation->animation.get(); - continue; + if (keyframesRule != existingAnimation->styleRule || keyframesRule->version() != existingAnimation->styleRuleVersion || existingAnimation->specifiedTiming != specifiedTiming) { + ASSERT(!isAnimationStyleChange); + update.updateAnimation(existingAnimationIndex, animation, InertEffect::create( + createKeyframeEffectModel(resolver, animatingElement, element, &style, parentStyle, name, keyframeTimingFunction.get(), i), + timing, isPaused, animation->unlimitedCurrentTimeInternal()), specifiedTiming, keyframesRule); } - } - ASSERT(!isAnimationStyleChange); - update.startAnimation(animationName, InertEffect::create( - createKeyframeEffectModel(resolver, animatingElement, element, &style, parentStyle, animationName, keyframeTimingFunction.get(), i), - timing, isPaused, 0), specifiedTiming, keyframesRule); + if (isPaused != animation->paused()) { + ASSERT(!isAnimationStyleChange); + update.toggleAnimationIndexPaused(existingAnimationIndex); + } + } else { + ASSERT(!isAnimationStyleChange); + update.startAnimation(name, nameIndex, InertEffect::create( + createKeyframeEffectModel(resolver, animatingElement, element, &style, parentStyle, name, keyframeTimingFunction.get(), i), + timing, isPaused, 0), specifiedTiming, keyframesRule); + } } } - ASSERT(inactive.isEmpty() || cssAnimations); - for (const AtomicString& animationName : inactive) { - ASSERT(!isAnimationStyleChange); - update.cancelAnimation(animationName, *cssAnimations->m_animations.get(animationName)->animation); + for (size_t i = 0; i < cancelRunningAnimationFlags.size(); i++) { + if (cancelRunningAnimationFlags[i]) { + ASSERT(cssAnimations && !isAnimationStyleChange); + update.cancelAnimation(i, *cssAnimations->m_runningAnimations[i]->animation); + } } } @@ -350,20 +365,23 @@ void CSSAnimations::maybeApplyPendingUpdate(Element* element) // https://code.google.com/p/chromium/issues/detail?id=339847 DisableCompositingQueryAsserts disabler; - for (const AtomicString& animationName : m_pendingUpdate.cancelledAnimationNames()) { - Animation* animation = m_animations.take(animationName)->animation; - animation->cancel(); - animation->update(TimingUpdateOnDemand); + const Vector<size_t>& cancelledIndices = m_pendingUpdate.cancelledAnimationIndices(); + for (size_t i = cancelledIndices.size(); i-- > 0;) { + ASSERT(i == cancelledIndices.size() - 1 || cancelledIndices[i] < cancelledIndices[i + 1]); + Animation& animation = *m_runningAnimations[cancelledIndices[i]]->animation; + animation.cancel(); + animation.update(TimingUpdateOnDemand); + m_runningAnimations.remove(cancelledIndices[i]); } - for (const AtomicString& animationName : m_pendingUpdate.animationsWithPauseToggled()) { - Animation* animation = m_animations.get(animationName)->animation.get(); - if (animation->paused()) - animation->unpause(); + for (size_t pausedIndex : m_pendingUpdate.animationIndicesWithPauseToggled()) { + Animation& animation = *m_runningAnimations[pausedIndex]->animation; + if (animation.paused()) + animation.unpause(); else - animation->pause(); - if (animation->outdated()) - animation->update(TimingUpdateOnDemand); + animation.pause(); + if (animation.outdated()) + animation.update(TimingUpdateOnDemand); } for (const auto& animation : m_pendingUpdate.updatedCompositorKeyframes()) @@ -375,7 +393,7 @@ void CSSAnimations::maybeApplyPendingUpdate(Element* element) effect->setModel(entry.effect->model()); effect->updateSpecifiedTiming(entry.effect->specifiedTiming()); - m_animations.find(entry.name)->value->update(entry); + m_runningAnimations[entry.index]->update(entry); } for (const auto& entry : m_pendingUpdate.newAnimations()) { @@ -388,7 +406,7 @@ void CSSAnimations::maybeApplyPendingUpdate(Element* element) animation->pause(); animation->update(TimingUpdateOnDemand); - m_animations.set(entry.name, new RunningAnimation(animation, entry)); + m_runningAnimations.append(new RunningAnimation(animation, entry)); } // Transitions that are run on the compositor only update main-thread state @@ -613,9 +631,9 @@ void CSSAnimations::calculateTransitionUpdate(CSSAnimationUpdate& update, const void CSSAnimations::cancel() { - for (const auto& entry : m_animations) { - entry.value->animation->cancel(); - entry.value->animation->update(TimingUpdateOnDemand); + for (const auto& runningAnimation : m_runningAnimations) { + runningAnimation->animation->cancel(); + runningAnimation->animation->update(TimingUpdateOnDemand); } for (const auto& entry : m_transitions) { @@ -623,7 +641,7 @@ void CSSAnimations::cancel() entry.value.animation->update(TimingUpdateOnDemand); } - m_animations.clear(); + m_runningAnimations.clear(); m_transitions.clear(); clearPendingUpdate(); } @@ -818,7 +836,7 @@ DEFINE_TRACE(CSSAnimations) { visitor->trace(m_transitions); visitor->trace(m_pendingUpdate); - visitor->trace(m_animations); + visitor->trace(m_runningAnimations); } } // namespace blink diff --git a/third_party/WebKit/Source/core/animation/css/CSSAnimations.h b/third_party/WebKit/Source/core/animation/css/CSSAnimations.h index b28a7e1..70437b7 100644 --- a/third_party/WebKit/Source/core/animation/css/CSSAnimations.h +++ b/third_party/WebKit/Source/core/animation/css/CSSAnimations.h @@ -73,7 +73,7 @@ public: m_pendingUpdate.clear(); } void maybeApplyPendingUpdate(Element*); - bool isEmpty() const { return m_animations.isEmpty() && m_transitions.isEmpty() && m_pendingUpdate.isEmpty(); } + bool isEmpty() const { return m_runningAnimations.isEmpty() && m_transitions.isEmpty() && m_pendingUpdate.isEmpty(); } void cancel(); DECLARE_TRACE(); @@ -83,6 +83,8 @@ private: public: RunningAnimation(Animation* animation, CSSAnimationUpdate::NewAnimation newAnimation) : animation(animation) + , name(newAnimation.name) + , nameIndex(newAnimation.nameIndex) , specifiedTiming(newAnimation.timing) , styleRule(newAnimation.styleRule) , styleRuleVersion(newAnimation.styleRuleVersion) @@ -91,6 +93,7 @@ private: void update(CSSAnimationUpdate::UpdatedAnimation update) { + ASSERT(update.animation == animation); styleRule = update.styleRule; styleRuleVersion = update.styleRuleVersion; specifiedTiming = update.specifiedTiming; @@ -103,6 +106,8 @@ private: } Member<Animation> animation; + AtomicString name; + size_t nameIndex; Timing specifiedTiming; RefPtrWillBeMember<StyleRuleKeyframes> styleRule; unsigned styleRuleVersion; @@ -121,8 +126,7 @@ private: const AnimatableValue* to; }; - using AnimationMap = HeapHashMap<AtomicString, Member<RunningAnimation>>; - AnimationMap m_animations; + HeapVector<Member<RunningAnimation>> m_runningAnimations; using TransitionMap = HeapHashMap<CSSPropertyID, RunningTransition>; TransitionMap m_transitions; |