Changeset 237587 in webkit
- Timestamp:
- Oct 30, 2018, 2:30:03 AM (8 years ago)
- Location:
- trunk
- Files:
-
- 23 edited
-
LayoutTests/ChangeLog (modified) (1 diff)
-
LayoutTests/TestExpectations (modified) (1 diff)
-
LayoutTests/fast/layers/no-clipping-overflow-hidden-added-after-transform.html (modified) (1 diff)
-
LayoutTests/imported/mozilla/ChangeLog (modified) (1 diff)
-
LayoutTests/imported/mozilla/css-animations/test_document-get-animations-expected.txt (modified) (1 diff)
-
LayoutTests/imported/w3c/ChangeLog (modified) (1 diff)
-
LayoutTests/imported/w3c/web-platform-tests/web-animations/timing-model/animations/current-time-expected.txt (modified) (2 diffs)
-
LayoutTests/imported/w3c/web-platform-tests/web-animations/timing-model/animations/updating-the-finished-state-expected.txt (modified) (1 diff)
-
Source/WebCore/ChangeLog (modified) (1 diff)
-
Source/WebCore/animation/AnimationTimeline.cpp (modified) (6 diffs)
-
Source/WebCore/animation/AnimationTimeline.h (modified) (3 diffs)
-
Source/WebCore/animation/CSSTransition.cpp (modified) (1 diff)
-
Source/WebCore/animation/CSSTransition.h (modified) (1 diff)
-
Source/WebCore/animation/DeclarativeAnimation.cpp (modified) (2 diffs)
-
Source/WebCore/animation/DeclarativeAnimation.h (modified) (3 diffs)
-
Source/WebCore/animation/DocumentAnimationScheduler.cpp (modified) (1 diff)
-
Source/WebCore/animation/DocumentAnimationScheduler.h (modified) (1 diff)
-
Source/WebCore/animation/DocumentTimeline.cpp (modified) (14 diffs)
-
Source/WebCore/animation/DocumentTimeline.h (modified) (3 diffs)
-
Source/WebCore/animation/WebAnimation.cpp (modified) (40 diffs)
-
Source/WebCore/animation/WebAnimation.h (modified) (10 diffs)
-
Source/WebCore/animation/WebAnimation.idl (modified) (1 diff)
-
Source/WebCore/dom/Element.cpp (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r237585 r237587 1 2018-10-28 Antoine Quint <graouts@apple.com> 2 3 [Web Animations] Implement the update animations and send events procedure 4 https://bugs.webkit.org/show_bug.cgi?id=191013 5 <rdar://problem/45620495> 6 7 Reviewed by Dean Jackson. 8 9 Several tests that broke when turning Web Animations CSS Integration on by default are now passing. In the case of one test, we had to ensure 10 that the final animation frame had been committed before terminating the test or there would be a tiny image reference issue. 11 12 * TestExpectations: 13 * fast/layers/no-clipping-overflow-hidden-added-after-transform.html: 14 1 15 2018-10-30 Youenn Fablet <youenn@apple.com> 2 16 -
trunk/LayoutTests/TestExpectations
r237568 r237587 2898 2898 webkit.org/b/190032 compositing/layer-creation/translate-scale-transition-overlap.html [ Failure ] 2899 2899 webkit.org/b/190032 compositing/layer-creation/translate-transition-overlap.html [ Failure ] 2900 webkit.org/b/190032 compositing/visible-rect/animated-from-none.html [ Failure ]2901 webkit.org/b/190032 fast/animation/css-animation-resuming-when-visible-with-style-change2.html [ Failure ]2902 2900 webkit.org/b/190032 imported/w3c/web-platform-tests/css/css-logical/animation-003.tentative.html [ Failure ] 2903 2901 webkit.org/b/190032 imported/w3c/web-platform-tests/css/css-scoping/keyframes-001.html [ Failure ] 2904 webkit.org/b/190032 imported/w3c/web-platform-tests/web-animations/animation-model/keyframe-effects/effect-value-context.html [ Failure ]2905 webkit.org/b/190032 imported/w3c/web-platform-tests/web-animations/interfaces/Animatable/animate.html [ Failure ]2906 webkit.org/b/190032 imported/w3c/web-platform-tests/web-animations/timing-model/animations/current-time.html [ Failure ]2907 2902 2908 2903 # FIXME: Need to implement MediaRecorder dataavailable event to support these testcases -
trunk/LayoutTests/fast/layers/no-clipping-overflow-hidden-added-after-transform.html
r171226 r237587 33 33 function transitionFinished() { 34 34 if (window.testRunner) 35 window.testRunner.notifyDone();35 requestAnimationFrame(() => window.testRunner.notifyDone()); 36 36 } 37 37 -
trunk/LayoutTests/imported/mozilla/ChangeLog
r237475 r237587 1 2018-10-28 Antoine Quint <graouts@apple.com> 2 3 [Web Animations] Implement the update animations and send events procedure 4 https://bugs.webkit.org/show_bug.cgi?id=191013 5 <rdar://problem/45620495> 6 7 Reviewed by Dean Jackson. 8 9 Progression in a couple of getAnimations() tests for CSS Animations. 10 11 * css-animations/test_document-get-animations-expected.txt: 12 1 13 2018-10-26 Antoine Quint <graouts@apple.com> 2 14 -
trunk/LayoutTests/imported/mozilla/css-animations/test_document-get-animations-expected.txt
r237475 r237587 5 5 FAIL Order of CSS Animations - across elements assert_equals: Order of second animation returned after tree surgery expected Element node <div style="animation: animLeft 100s"></div> but got Element node <div style="animation: animLeft 100s"></div> 6 6 PASS Order of CSS Animations - across and within elements 7 FAIL Order of CSS Animations - markup-bound vs free animations assert_equals: getAnimations returns markup-bound and free animations expected 2 but got 1 8 FAIL Order of CSS Animations - free animations assert_equals: getAnimations returns free animations expected 2 but got 0 7 PASS Order of CSS Animations - markup-bound vs free animations 8 PASS Order of CSS Animations - free animations 9 9 FAIL Order of CSS Animations and CSS Transitions assert_equals: Transition comes first expected "[object CSSTransition]" but got "[object CSSAnimation]" 10 10 PASS Finished but filling CSS Animations are returned -
trunk/LayoutTests/imported/w3c/ChangeLog
r237570 r237587 1 2018-10-28 Antoine Quint <graouts@apple.com> 2 3 [Web Animations] Implement the update animations and send events procedure 4 https://bugs.webkit.org/show_bug.cgi?id=191013 5 <rdar://problem/45620495> 6 7 Reviewed by Dean Jackson. 8 9 Progressions in a couple of Web Animations Web Platform Tests. 10 11 * web-platform-tests/web-animations/timing-model/animations/current-time-expected.txt: 12 * web-platform-tests/web-animations/timing-model/animations/updating-the-finished-state-expected.txt: 13 1 14 2018-10-29 Justin Michaud <justin_michaud@apple.com> 2 15 -
trunk/LayoutTests/imported/w3c/web-platform-tests/web-animations/timing-model/animations/current-time-expected.txt
r237475 r237587 1 2 Harness Error (TIMEOUT), message = null3 1 4 2 PASS The current time returns the hold time when set … … 6 4 PASS The current time is unresolved when the start time is unresolved (and no hold time is set) 7 5 PASS The current time is calculated from the timeline time, start time and playback rate 8 TIMEOUT The current time does not progress if playback rate is 0 Test timed out 6 PASS The current time does not progress if playback rate is 0 9 7 -
trunk/LayoutTests/imported/w3c/web-platform-tests/web-animations/timing-model/animations/updating-the-finished-state-expected.txt
r237475 r237587 11 11 PASS Updating the finished state when seeking before end 12 12 PASS Updating the finished state when seeking a reversed animation before end 13 TIMEOUT Updating the finished state when playback rate is zero and the current time is less than zero Test timed out 14 NOTRUNUpdating the finished state when playback rate is zero and the current time is less than end15 NOTRUNUpdating the finished state when playback rate is zero and the current time is greater than end16 NOTRUNUpdating the finished state when current time is unresolved13 PASS Updating the finished state when playback rate is zero and the current time is less than zero 14 PASS Updating the finished state when playback rate is zero and the current time is less than end 15 PASS Updating the finished state when playback rate is zero and the current time is greater than end 16 PASS Updating the finished state when current time is unresolved 17 17 PASS Updating the finished state when there is a pending task 18 NOTRUNUpdating the finished state when start time is unresolved and did seek = false18 PASS Updating the finished state when start time is unresolved and did seek = false 19 19 PASS Updating the finished state when start time is unresolved and did seek = true 20 NOTRUNFinish notification steps don't run when the animation seeks to finish and then seeks back again21 NOTRUNFinish notification steps run when the animation completes normally22 NOTRUNFinish notification steps run when the animation seeks past finish23 NOTRUNFinish notification steps run when the animation completes with .finish(), even if we then seek away24 NOTRUNAnimation finished promise is replaced after seeking back to start25 NOTRUNAnimation finished promise is replaced after replaying from start26 PASS Animation finish event is fired again after seeking back to start 27 PASS Animation finish event is fired again after replaying from start 20 PASS Finish notification steps don't run when the animation seeks to finish and then seeks back again 21 PASS Finish notification steps run when the animation completes normally 22 PASS Finish notification steps run when the animation seeks past finish 23 PASS Finish notification steps run when the animation completes with .finish(), even if we then seek away 24 PASS Animation finished promise is replaced after seeking back to start 25 PASS Animation finished promise is replaced after replaying from start 26 TIMEOUT Animation finish event is fired again after seeking back to start Test timed out 27 TIMEOUT Animation finish event is fired again after replaying from start Test timed out 28 28 -
trunk/Source/WebCore/ChangeLog
r237585 r237587 1 2018-10-28 Antoine Quint <graouts@apple.com> 2 3 [Web Animations] Implement the update animations and send events procedure 4 https://bugs.webkit.org/show_bug.cgi?id=191013 5 <rdar://problem/45620495> 6 7 Reviewed by Dean Jackson. 8 9 While we implemented the various parts of what the Web Animations specification refers to as the "update animations and send events" 10 procedure, we did not implement it as one function and in the correct order, specifically updating animations and sending events in 11 two separate tasks. We now have a single method on DocumentTimeline which runs as the DisplayRefreshMonitor fires to update each 12 "relevant" animation with the current time, perform a microtask checkpoint and dispatch events. 13 14 Implementing this procedure allowed us to make several enhancements: 15 16 1. We introduce the concept of a "relevant" animation, which is essentially an animation that is either pending or playing. All animations 17 in a different state are no longer owned by the DocumentTimeline and can thus be destroyed if the developer doesn't hold references in JS. 18 Maintaining such a list guarantees that we're only updating animations that would have changed state since the last time the "update animations 19 and send events" procedure was run. Note that DeclarativeAnimation instances are also considered to be relevant if they have queued DOM events 20 to dispatch as they could otherwise be destroyed before they can fully dispatch them. 21 22 2. We no longer conflate the timing model and effects. Until now the way we would update animations was to go through all elements for which 23 we had a registered animation, invalidate their style and finally forcing a style update on the document. We had a separate data structure where 24 we help animations without targets so we update these as well in a separate pass, in order to make sure that promises and events would fire for 25 them as expected. We now let the "update animations and send events" procedure update the timing of all relevant animations and let individual 26 animation effects invalidate their style as needed, the document style invalidation happening naturally without DocumentTimeline forcing it. 27 28 3. We use a single step to schedule the update of animations, which is to register for a display refresh monitor update provided a "relevant" 29 animation is known since the previous update. Until now we first had an "timing model invalidation" task scheduled upon any change of an animation's 30 timing model, which would then create a timer to the earliest moment any listed animation would require an update, finally registering a display 31 refresh monitor update, which used at least GenericTaskQueue<Timer> and potentially two, whereas we use none right now. 32 33 4. We allow for a display refresh monitor update to be canceled should the number of "relevant" animations since the last update goes back to 0. 34 35 To facilitate all of this, we have changed the m_animations ListHashSet to contain only the "relevant" animations, and no longer every animation created 36 that has this DocumentTimeline set as their "timeline" property. To keep this list current, every single change that changes a given animation's timing 37 ends up calling AnimationTimeline::animationTimingDidChange() passing the animation as the sole parameter and adding this animation to m_animations. We 38 immediately schedule a display refresh monitor update if one wasn't already scheduled. Then, when running the "update animations and send events" 39 procedure, we call a new WebAnimation::tick() method on each of those animations, which updates this animation's effect and relevance, using the newly 40 computed relevance to identify whether this animation should be kept in the m_animations ListHashSet. 41 42 This is only the first step towards a more efficient update and ownership model of animations by the document timeline since animations created as CSS 43 Animations and CSS Transitions are committed through CSS have dedicated data structures that are not updated in this particular patch, but this will be 44 addressed in a followup to keep this already significant patch smaller. Another issue that will be addressed later is the ability to not schedule display 45 refresh monitor udpates when only accelerated animations are running. 46 47 * animation/AnimationTimeline.cpp: 48 (WebCore::AnimationTimeline::animationTimingDidChange): Called by animations when any aspect of their timing model changes. The provided animation is then 49 added to the m_animations list unless its timeline is no longer this timeline. 50 (WebCore::AnimationTimeline::removeAnimation): Remove the provided animation from m_animations and remove any animation registered on the element-specific 51 animation lists if this animation has an effect with a target. 52 (WebCore::AnimationTimeline::animationWasAddedToElement): We no longer need to worry about the m_animationsWithoutTarget data structure since we removed it. 53 (WebCore::removeCSSTransitionFromMap): Fix a bug where we would remove any CSSTransition in the provided map that had a matching transition-property instead 54 of checking the CSSTransition registered for this transition-property was indeed the provided CSSTransition. The other code changes in this patch made this 55 code now cause regressions in the Web Platform Tests. 56 (WebCore::AnimationTimeline::animationWasRemovedFromElement): Stop updating m_animationsWithoutTarget since it no longer exists. 57 (WebCore::AnimationTimeline::elementWasRemoved): 58 (WebCore::AnimationTimeline::updateCSSAnimationsForElement): Fix a small error that caused a regression in the Web Platform Tests where we could attempt to 59 call setBackingAnimation() on a nullptr instead of a valid CSSAnimation. 60 (WebCore::AnimationTimeline::cancelOrRemoveDeclarativeAnimation): 61 (WebCore::AnimationTimeline::addAnimation): Deleted. 62 * animation/AnimationTimeline.h: 63 (WebCore::AnimationTimeline::hasElementAnimations const): Deleted. 64 (WebCore::AnimationTimeline:: const): Deleted. 65 (WebCore::AnimationTimeline::elementToAnimationsMap): Deleted. 66 (WebCore::AnimationTimeline::elementToCSSAnimationsMap): Deleted. 67 (WebCore::AnimationTimeline::elementToCSSTransitionsMap): Deleted. 68 * animation/CSSTransition.cpp: 69 (WebCore::CSSTransition::canBeListed const): Deleted. 70 * animation/CSSTransition.h: 71 * animation/DeclarativeAnimation.cpp: 72 (WebCore::DeclarativeAnimation::tick): Call the superclass's method and queue any necessary DOM events reflecting the timing model changes. 73 (WebCore::DeclarativeAnimation::needsTick const): Call the superclass's method and return true also if we have pending events since otherwise this animation 74 could be removed from m_animations on its AnimationTimeline and potentially destroyed before the GenericEventQueue had a chance to dispatch all events. 75 (WebCore::DeclarativeAnimation::startTime const): We removed the custom binding for this IDL property and renamed the method from bindingsStartTime to startTime. 76 (WebCore::DeclarativeAnimation::setStartTime): We removed the custom binding for this IDL property and renamed the method from setBindingsStartTime to setStartTime. 77 (WebCore::DeclarativeAnimation::bindingsStartTime const): Deleted. 78 (WebCore::DeclarativeAnimation::setBindingsStartTime): Deleted. 79 * animation/DeclarativeAnimation.h: 80 * animation/DocumentAnimationScheduler.cpp: 81 (WebCore::DocumentAnimationScheduler::unscheduleWebAnimationsResolution): Add a method to mark that we no longer need a display refresh monitor update for this 82 document's animation timeline. This is called when m_animations becomes empty. 83 * animation/DocumentAnimationScheduler.h: 84 * animation/DocumentTimeline.cpp: 85 (WebCore::DocumentTimeline::DocumentTimeline): 86 (WebCore::DocumentTimeline::detachFromDocument): Stop clearing two task queues and a timer that no longer exist and instead only clear the task queue to clear 87 the cached current time, which we queue any time we generate a new one (see DocumentTimeline::currentTime). 88 (WebCore::DocumentTimeline::getAnimations const): Use isRelevant() instead of canBeListed(). 89 (WebCore::DocumentTimeline::updateThrottlingState): 90 (WebCore::DocumentTimeline::suspendAnimations): 91 (WebCore::DocumentTimeline::resumeAnimations): 92 (WebCore::DocumentTimeline::numberOfActiveAnimationsForTesting const): 93 (WebCore::DocumentTimeline::currentTime): Queue a task in the new m_currentTimeClearingTaskQueue task queue to clear the current time that we've generated and cached 94 in the next run loop (provided all pending JS execution has also completed). 95 (WebCore::DocumentTimeline::maybeClearCachedCurrentTime): 96 (WebCore::DocumentTimeline::scheduleAnimationResolutionIfNeeded): Schedule a display refresh monitor update if we are not suspended and have "relevant" animations. 97 (WebCore::DocumentTimeline::animationTimingDidChange): Call scheduleAnimationResolutionIfNeeded() after calling the superclass's implementation. 98 (WebCore::DocumentTimeline::removeAnimation): Call unscheduleAnimationResolution() if the list of "relevant" animations is now empty. 99 (WebCore::DocumentTimeline::unscheduleAnimationResolution): Unschedule a pending display refresh monitor update. 100 (WebCore::DocumentTimeline::animationResolutionTimerFired): 101 (WebCore::DocumentTimeline::updateAnimationsAndSendEvents): Implement the "update animations and send events" procedure as specified by the Web Animations spec. 102 During this procedure, we call tick() on all animations listed in m_animations and create a list of animations to remove from that list if this animation is no 103 longer relevant following the call to tick(). 104 (WebCore::DocumentTimeline::enqueueAnimationPlaybackEvent): 105 (WebCore::DocumentTimeline::timingModelDidChange): Deleted. 106 (WebCore::DocumentTimeline::scheduleInvalidationTaskIfNeeded): Deleted. 107 (WebCore::DocumentTimeline::performInvalidationTask): Deleted. 108 (WebCore::DocumentTimeline::updateAnimationSchedule): Deleted. 109 (WebCore::DocumentTimeline::animationScheduleTimerFired): Deleted. 110 (WebCore::DocumentTimeline::updateAnimations): Deleted. 111 (WebCore::compareAnimationPlaybackEvents): Deleted. 112 (WebCore::DocumentTimeline::performEventDispatchTask): Deleted. 113 * animation/DocumentTimeline.h: 114 * animation/WebAnimation.cpp: The majority of the changes to this class is that we call the new timingDidChange() method when any code that modifies the timing model 115 is run. We also remove methods to set the pending play and pause tasks as well as the animation's start time and hold time since any time we're changing these instance 116 variables, we later already have a call to update the timing model and we were doing more work than needed. As a result we no longer need an internal method to set the 117 start time and can stop requiring a custom IDL binding for the "startTime" property. 118 (WebCore::WebAnimation::effectTimingPropertiesDidChange): 119 (WebCore::WebAnimation::setEffect): 120 (WebCore::WebAnimation::setEffectInternal): 121 (WebCore::WebAnimation::setTimeline): 122 (WebCore::WebAnimation::setTimelineInternal): 123 (WebCore::WebAnimation::startTime const): 124 (WebCore::WebAnimation::setStartTime): 125 (WebCore::WebAnimation::silentlySetCurrentTime): 126 (WebCore::WebAnimation::setCurrentTime): 127 (WebCore::WebAnimation::setPlaybackRate): 128 (WebCore::WebAnimation::cancel): 129 (WebCore::WebAnimation::resetPendingTasks): 130 (WebCore::WebAnimation::finish): 131 (WebCore::WebAnimation::timingDidChange): New method called any time a timing property changed where we run the "update the finished state" procedure and notify the 132 animation's timeline that its timing changed so that it can be considered the next time the "update animations and send events" procedure runs. 133 (WebCore::WebAnimation::invalidateEffect): 134 (WebCore::WebAnimation::updateFinishedState): Update the animation's relevance after running the procedure as specified. 135 (WebCore::WebAnimation::play): 136 (WebCore::WebAnimation::runPendingPlayTask): 137 (WebCore::WebAnimation::pause): 138 (WebCore::WebAnimation::runPendingPauseTask): 139 (WebCore::WebAnimation::needsTick const): 140 (WebCore::WebAnimation::tick): New method called during the "update animations and send events" procedure where we run the "update the finished state" procedure and run 141 the pending play and pause tasks. 142 (WebCore::WebAnimation::resolve): 143 (WebCore::WebAnimation::updateRelevance): 144 (WebCore::WebAnimation::computeRelevance): 145 (WebCore::WebAnimation::timingModelDidChange): Deleted. 146 (WebCore::WebAnimation::setHoldTime): Deleted. 147 (WebCore::WebAnimation::bindingsStartTime const): Deleted. 148 (WebCore::WebAnimation::setBindingsStartTime): Deleted. 149 (WebCore::WebAnimation::setTimeToRunPendingPlayTask): Deleted. 150 (WebCore::WebAnimation::setTimeToRunPendingPauseTask): Deleted. 151 (WebCore::WebAnimation::updatePendingTasks): Deleted. 152 (WebCore::WebAnimation::timeToNextRequiredTick const): Deleted. 153 (WebCore::WebAnimation::runPendingTasks): Deleted. 154 (WebCore::WebAnimation::canBeListed const): Deleted. 155 * animation/WebAnimation.h: 156 (WebCore::WebAnimation::isRelevant const): 157 (WebCore::WebAnimation::hasPendingPlayTask const): 158 (WebCore::WebAnimation::isEffectInvalidationSuspended): 159 * animation/WebAnimation.idl: 160 * dom/Element.cpp: 161 (WebCore::Element::getAnimations): Use isRelevant() instead of canBeListed(). 162 1 163 2018-10-30 Youenn Fablet <youenn@apple.com> 2 164 -
trunk/Source/WebCore/animation/AnimationTimeline.cpp
r237474 r237587 56 56 } 57 57 58 void AnimationTimeline::addAnimation(Ref<WebAnimation>&& animation) 59 { 60 m_animationsWithoutTarget.add(animation.ptr()); 61 m_animations.add(WTFMove(animation)); 62 timingModelDidChange(); 63 } 64 65 void AnimationTimeline::removeAnimation(Ref<WebAnimation>&& animation) 66 { 67 m_animationsWithoutTarget.remove(animation.ptr()); 68 m_animations.remove(WTFMove(animation)); 69 timingModelDidChange(); 58 void AnimationTimeline::animationTimingDidChange(WebAnimation& animation) 59 { 60 if (m_animations.add(&animation)) { 61 auto* timeline = animation.timeline(); 62 if (timeline && timeline != this) 63 timeline->removeAnimation(animation); 64 } 65 } 66 67 void AnimationTimeline::removeAnimation(WebAnimation& animation) 68 { 69 ASSERT(!animation.timeline() || animation.timeline() == this); 70 m_animations.remove(&animation); 71 if (is<KeyframeEffectReadOnly>(animation.effect())) { 72 if (auto* target = downcast<KeyframeEffectReadOnly>(animation.effect())->target()) 73 animationWasRemovedFromElement(animation, *target); 74 } 70 75 } 71 76 … … 89 94 void AnimationTimeline::animationWasAddedToElement(WebAnimation& animation, Element& element) 90 95 { 91 m_animationsWithoutTarget.remove(&animation);92 93 96 relevantMapForAnimation(animation).ensure(&element, [] { 94 97 return ListHashSet<RefPtr<WebAnimation>> { }; … … 103 106 104 107 auto& cssTransitionsByProperty = iterator->value; 105 cssTransitionsByProperty.remove(transition.property()); 108 109 auto transitionIterator = cssTransitionsByProperty.find(transition.property()); 110 if (transitionIterator == cssTransitionsByProperty.end() || transitionIterator->value != &transition) 111 return false; 112 113 cssTransitionsByProperty.remove(transitionIterator); 114 106 115 if (cssTransitionsByProperty.isEmpty()) 107 116 map.remove(&element); … … 111 120 void AnimationTimeline::animationWasRemovedFromElement(WebAnimation& animation, Element& element) 112 121 { 113 // This animation doesn't have a target for now.114 m_animationsWithoutTarget.add(&animation);115 116 122 // First, we clear this animation from one of the m_elementToCSSAnimationsMap, m_elementToCSSTransitionsMap, 117 123 // m_elementToAnimationsMap or m_elementToCompletedCSSTransitionByCSSPropertyID map, whichever is relevant to … … 255 261 // created a CSSAnimation object for it and need to ensure that this CSSAnimation is backed by the current 256 262 // animation object for this animation name. 257 cssAnimationsByName.get(name)->setBackingAnimation(currentAnimation); 263 if (auto cssAnimation = cssAnimationsByName.get(name)) 264 cssAnimation->setBackingAnimation(currentAnimation); 258 265 } else if (shouldConsiderAnimation(element, currentAnimation)) { 259 266 // Otherwise we are dealing with a new animation name and must create a CSSAnimation for it. … … 470 477 animation->cancel(); 471 478 animationWasRemovedFromElement(*animation, animation->target()); 472 removeAnimation( animation.releaseNonNull());479 removeAnimation(*animation); 473 480 } 474 481 -
trunk/Source/WebCore/animation/AnimationTimeline.h
r237474 r237587 48 48 public: 49 49 bool isDocumentTimeline() const { return m_classType == DocumentTimelineClass; } 50 void addAnimation(Ref<WebAnimation>&&); 51 void removeAnimation(Ref<WebAnimation>&&); 50 51 virtual void animationTimingDidChange(WebAnimation&); 52 virtual void removeAnimation(WebAnimation&); 53 52 54 std::optional<double> bindingsCurrentTime(); 53 55 virtual std::optional<Seconds> currentTime() { return m_currentTime; } … … 78 80 explicit AnimationTimeline(ClassType); 79 81 80 bool hasElementAnimations() const { return !m_elementToAnimationsMap.isEmpty() || !m_elementToCSSAnimationsMap.isEmpty() || !m_elementToCSSTransitionsMap.isEmpty(); } 81 82 const ListHashSet<WebAnimation*>& animationsWithoutTarget() const { return m_animationsWithoutTarget; } 83 const HashMap<Element*, ListHashSet<RefPtr<WebAnimation>>>& elementToAnimationsMap() { return m_elementToAnimationsMap; } 84 const HashMap<Element*, ListHashSet<RefPtr<WebAnimation>>>& elementToCSSAnimationsMap() { return m_elementToCSSAnimationsMap; } 85 const HashMap<Element*, ListHashSet<RefPtr<WebAnimation>>>& elementToCSSTransitionsMap() { return m_elementToCSSTransitionsMap; } 82 ListHashSet<RefPtr<WebAnimation>> m_animations; 86 83 87 84 private: … … 95 92 HashMap<Element*, ListHashSet<RefPtr<WebAnimation>>> m_elementToCSSAnimationsMap; 96 93 HashMap<Element*, ListHashSet<RefPtr<WebAnimation>>> m_elementToCSSTransitionsMap; 97 ListHashSet<RefPtr<WebAnimation>> m_animations;98 99 ListHashSet<WebAnimation*> m_animationsWithoutTarget;100 94 HashMap<Element*, HashMap<String, RefPtr<CSSAnimation>>> m_elementToCSSAnimationByName; 101 95 HashMap<Element*, HashMap<CSSPropertyID, RefPtr<CSSTransition>>> m_elementToRunningCSSTransitionByCSSPropertyID; -
trunk/Source/WebCore/animation/CSSTransition.cpp
r234166 r237587 75 75 } 76 76 77 bool CSSTransition::canBeListed() const78 {79 if (auto* transitionEffect = effect()) {80 if (is<KeyframeEffectReadOnly>(transitionEffect)) {81 if (!downcast<KeyframeEffectReadOnly>(effect())->hasBlendingKeyframes())82 return false;83 }84 }85 return WebAnimation::canBeListed();86 }87 88 77 } // namespace WebCore -
trunk/Source/WebCore/animation/CSSTransition.h
r233004 r237587 50 50 double reversingShorteningFactor() const { return m_reversingShorteningFactor; } 51 51 52 bool canBeListed() const final;53 52 void resolve(RenderStyle&) final; 54 53 -
trunk/Source/WebCore/animation/DeclarativeAnimation.cpp
r237498 r237587 50 50 } 51 51 52 void DeclarativeAnimation::tick() 53 { 54 WebAnimation::tick(); 55 invalidateDOMEvents(); 56 } 57 58 bool DeclarativeAnimation::needsTick() const 59 { 60 return WebAnimation::needsTick() || m_eventQueue.hasPendingEvents(); 61 } 62 52 63 void DeclarativeAnimation::remove() 53 64 { … … 85 96 } 86 97 87 std::optional<double> DeclarativeAnimation:: bindingsStartTime() const88 { 89 flushPendingStyleChanges(); 90 return WebAnimation:: bindingsStartTime();91 } 92 93 void DeclarativeAnimation::set BindingsStartTime(std::optional<double> startTime)94 { 95 flushPendingStyleChanges(); 96 return WebAnimation::set BindingsStartTime(startTime);98 std::optional<double> DeclarativeAnimation::startTime() const 99 { 100 flushPendingStyleChanges(); 101 return WebAnimation::startTime(); 102 } 103 104 void DeclarativeAnimation::setStartTime(std::optional<double> startTime) 105 { 106 flushPendingStyleChanges(); 107 return WebAnimation::setStartTime(startTime); 97 108 } 98 109 -
trunk/Source/WebCore/animation/DeclarativeAnimation.h
r237498 r237587 46 46 const Animation& backingAnimation() const { return m_backingAnimation; } 47 47 void setBackingAnimation(const Animation&); 48 void invalidateDOMEvents(Seconds elapsedTime = 0_s);49 48 50 std::optional<double> bindingsStartTime() const final;51 void set BindingsStartTime(std::optional<double>) final;49 std::optional<double> startTime() const final; 50 void setStartTime(std::optional<double>) final; 52 51 std::optional<double> bindingsCurrentTime() const final; 53 52 ExceptionOr<void> setBindingsCurrentTime(std::optional<double>) final; … … 62 61 void cancel() final; 63 62 63 bool needsTick() const override; 64 void tick() override; 65 64 66 protected: 65 67 DeclarativeAnimation(Element&, const Animation&); … … 67 69 virtual void initialize(const Element&, const RenderStyle* oldStyle, const RenderStyle& newStyle); 68 70 virtual void syncPropertiesWithBackingAnimation(); 71 void invalidateDOMEvents(Seconds elapsedTime = 0_s); 69 72 70 73 private: -
trunk/Source/WebCore/animation/DocumentAnimationScheduler.cpp
r233583 r237587 65 65 } 66 66 67 void DocumentAnimationScheduler::unscheduleWebAnimationsResolution() 68 { 69 m_scheduledWebAnimationsResolution = false; 70 71 if (!m_scheduledScriptedAnimationResolution) 72 DisplayRefreshMonitorManager::sharedManager().unregisterClient(*this); 73 } 74 67 75 bool DocumentAnimationScheduler::scheduleScriptedAnimationResolution() 68 76 { -
trunk/Source/WebCore/animation/DocumentAnimationScheduler.h
r233394 r237587 49 49 50 50 bool scheduleWebAnimationsResolution(); 51 void unscheduleWebAnimationsResolution(); 51 52 bool scheduleScriptedAnimationResolution(); 52 53 -
trunk/Source/WebCore/animation/DocumentTimeline.cpp
r237499 r237587 59 59 , m_document(&document) 60 60 , m_originTime(originTime) 61 , m_animationScheduleTimer(*this, &DocumentTimeline::animationScheduleTimerFired)62 61 #if !USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR) 63 62 , m_animationResolutionTimer(*this, &DocumentTimeline::animationResolutionTimerFired) … … 72 71 void DocumentTimeline::detachFromDocument() 73 72 { 74 m_invalidationTaskQueue.close(); 75 m_eventDispatchTaskQueue.close(); 76 m_animationScheduleTimer.stop(); 73 m_currentTimeClearingTaskQueue.close(); 77 74 m_elementsWithRunningAcceleratedAnimations.clear(); 78 75 79 auto& animationsToRemove = animations();76 auto& animationsToRemove = m_animations; 80 77 while (!animationsToRemove.isEmpty()) 81 78 animationsToRemove.first()->remove(); 82 79 80 unscheduleAnimationResolution(); 83 81 m_document = nullptr; 84 82 } … … 90 88 // FIXME: Filter and order the list as specified (webkit.org/b/179535). 91 89 Vector<RefPtr<WebAnimation>> animations; 92 for (const auto& animation : this->animations()) {93 if (animation-> canBeListed() && is<KeyframeEffectReadOnly>(animation->effect())) {90 for (const auto& animation : m_animations) { 91 if (animation->isRelevant() && is<KeyframeEffectReadOnly>(animation->effect())) { 94 92 if (auto* target = downcast<KeyframeEffectReadOnly>(animation->effect())->target()) { 95 93 if (target->isDescendantOf(*m_document)) … … 103 101 void DocumentTimeline::updateThrottlingState() 104 102 { 105 m_needsUpdateAnimationSchedule = false; 106 timingModelDidChange(); 103 scheduleAnimationResolutionIfNeeded(); 107 104 } 108 105 … … 119 116 return; 120 117 121 m_invalidationTaskQueue.cancelAllTasks(); 122 if (m_animationScheduleTimer.isActive()) 123 m_animationScheduleTimer.stop(); 124 125 for (const auto& animation : animations()) 118 for (const auto& animation : m_animations) 126 119 animation->setSuspended(true); 127 120 … … 129 122 130 123 applyPendingAcceleratedAnimations(); 124 125 unscheduleAnimationResolution(); 131 126 } 132 127 … … 138 133 m_isSuspended = false; 139 134 140 for (const auto& animation : animations())135 for (const auto& animation : m_animations) 141 136 animation->setSuspended(false); 142 137 143 m_needsUpdateAnimationSchedule = false; 144 timingModelDidChange(); 138 scheduleAnimationResolutionIfNeeded(); 145 139 } 146 140 … … 153 147 { 154 148 unsigned count = 0; 155 for (const auto& animation : animations()) {149 for (const auto& animation : m_animations) { 156 150 if (!animation->isSuspended()) 157 151 ++count; … … 197 191 // animations, so we schedule the invalidation task and register a whenIdle callback on the VM, which will 198 192 // fire syncronously if no JS is running. 199 scheduleInvalidationTaskIfNeeded();200 193 m_waitingOnVMIdle = true; 194 if (!m_currentTimeClearingTaskQueue.hasPendingTasks()) 195 m_currentTimeClearingTaskQueue.enqueueTask(std::bind(&DocumentTimeline::maybeClearCachedCurrentTime, this)); 201 196 m_document->vm().whenIdle([this, protectedThis = makeRefPtr(this)]() { 202 197 m_waitingOnVMIdle = false; … … 207 202 } 208 203 209 void DocumentTimeline::timingModelDidChange()210 {211 if (m_needsUpdateAnimationSchedule || m_isSuspended)212 return;213 214 m_needsUpdateAnimationSchedule = true;215 216 // We know that we will resolve animations again, so we can cancel the timer right away.217 if (m_animationScheduleTimer.isActive())218 m_animationScheduleTimer.stop();219 220 scheduleInvalidationTaskIfNeeded();221 }222 223 void DocumentTimeline::scheduleInvalidationTaskIfNeeded()224 {225 if (m_invalidationTaskQueue.hasPendingTasks())226 return;227 228 m_invalidationTaskQueue.enqueueTask(std::bind(&DocumentTimeline::performInvalidationTask, this));229 }230 231 void DocumentTimeline::performInvalidationTask()232 {233 // Now that the timing model has changed we can see if there are DOM events to dispatch for declarative animations.234 if (!m_isSuspended) {235 for (auto& animation : animations()) {236 if (is<DeclarativeAnimation>(animation))237 downcast<DeclarativeAnimation>(*animation).invalidateDOMEvents();238 }239 }240 241 applyPendingAcceleratedAnimations();242 243 updateAnimationSchedule();244 maybeClearCachedCurrentTime();245 }246 247 204 void DocumentTimeline::maybeClearCachedCurrentTime() 248 205 { … … 251 208 // we're guaranteed to have a consistent current time reported for all work happening in a given 252 209 // JS frame or throughout updating animations in WebCore. 253 if (!m_waitingOnVMIdle && !m_ invalidationTaskQueue.hasPendingTasks())210 if (!m_waitingOnVMIdle && !m_currentTimeClearingTaskQueue.hasPendingTasks()) 254 211 m_cachedCurrentTime = std::nullopt; 255 212 } 256 213 257 void DocumentTimeline::updateAnimationSchedule() 258 { 259 if (!m_needsUpdateAnimationSchedule) 260 return; 261 262 m_needsUpdateAnimationSchedule = false; 263 264 if (!m_acceleratedAnimationsPendingRunningStateChange.isEmpty()) { 214 void DocumentTimeline::scheduleAnimationResolutionIfNeeded() 215 { 216 if (!m_isSuspended && !m_animations.isEmpty()) 265 217 scheduleAnimationResolution(); 266 return; 267 } 268 269 Seconds scheduleDelay = Seconds::infinity(); 270 271 for (const auto& animation : animations()) { 272 auto animationTimeToNextRequiredTick = animation->timeToNextRequiredTick(); 273 if (animationTimeToNextRequiredTick < animationInterval()) { 274 scheduleAnimationResolution(); 275 return; 276 } 277 scheduleDelay = std::min(scheduleDelay, animationTimeToNextRequiredTick); 278 } 279 280 if (scheduleDelay < Seconds::infinity()) 281 m_animationScheduleTimer.startOneShot(scheduleDelay); 282 } 283 284 void DocumentTimeline::animationScheduleTimerFired() 285 { 286 scheduleAnimationResolution(); 218 } 219 220 void DocumentTimeline::animationTimingDidChange(WebAnimation& animation) 221 { 222 AnimationTimeline::animationTimingDidChange(animation); 223 scheduleAnimationResolutionIfNeeded(); 224 } 225 226 void DocumentTimeline::removeAnimation(WebAnimation& animation) 227 { 228 AnimationTimeline::removeAnimation(animation); 229 230 if (m_animations.isEmpty()) 231 unscheduleAnimationResolution(); 287 232 } 288 233 … … 298 243 } 299 244 245 void DocumentTimeline::unscheduleAnimationResolution() 246 { 247 #if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR) 248 m_document->animationScheduler().unscheduleWebAnimationsResolution(); 249 #else 250 // FIXME: We need to use the same logic as ScriptedAnimationController here, 251 // which will be addressed by the refactor tracked by webkit.org/b/179293. 252 m_animationResolutionTimer.stop(); 253 #endif 254 } 255 300 256 #if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR) 301 257 void DocumentTimeline::documentAnimationSchedulerDidFire() … … 304 260 #endif 305 261 { 306 updateAnimations ();307 } 308 309 void DocumentTimeline::updateAnimations ()262 updateAnimationsAndSendEvents(); 263 } 264 265 void DocumentTimeline::updateAnimationsAndSendEvents() 310 266 { 311 267 m_numberOfAnimationTimelineInvalidationsForTesting++; 312 268 313 for (const auto& animation : animations()) 314 animation->runPendingTasks(); 315 316 // Perform a microtask checkpoint such that all promises that may have resolved while 317 // running pending tasks can fire right away. 269 // https://drafts.csswg.org/web-animations/#update-animations-and-send-events 270 271 // 1. Update the current time of all timelines associated with doc passing now as the timestamp. 272 273 Vector<RefPtr<WebAnimation>> animationsToRemove; 274 275 for (auto& animation : m_animations) { 276 if (animation->timeline() != this) { 277 ASSERT(!animation->timeline()); 278 animationsToRemove.append(animation); 279 continue; 280 } 281 282 // This will notify the animation that timing has changed and will call automatically 283 // schedule invalidation if required for this animation. 284 animation->tick(); 285 286 if (!animation->isRelevant() && !animation->needsTick()) 287 animationsToRemove.append(animation); 288 } 289 290 // 2. Perform a microtask checkpoint. 318 291 MicrotaskQueue::mainThreadQueue().performMicrotaskCheckpoint(); 319 292 320 // Let's first resolve any animation that does not have a target. 321 for (auto* animation : animationsWithoutTarget()) 322 animation->resolve(); 323 324 // For the rest of the animations, we will resolve them via TreeResolver::createAnimatedElementUpdate() 325 // by invalidating their target element's style. 326 if (m_document && hasElementAnimations()) { 327 for (const auto& elementToAnimationsMapItem : elementToAnimationsMap()) 328 elementToAnimationsMapItem.key->invalidateStyleAndLayerComposition(); 329 for (const auto& elementToCSSAnimationsMapItem : elementToCSSAnimationsMap()) 330 elementToCSSAnimationsMapItem.key->invalidateStyleAndLayerComposition(); 331 for (const auto& elementToCSSTransitionsMapItem : elementToCSSTransitionsMap()) 332 elementToCSSTransitionsMapItem.key->invalidateStyleAndLayerComposition(); 333 m_document->updateStyleIfNeeded(); 334 } 335 336 // Time has advanced, the timing model requires invalidation now. 337 timingModelDidChange(); 293 // 3. Let events to dispatch be a copy of doc's pending animation event queue. 294 // 4. Clear doc's pending animation event queue. 295 auto pendingAnimationEvents = WTFMove(m_pendingAnimationEvents); 296 297 // 5. Perform a stable sort of the animation events in events to dispatch as follows. 298 std::stable_sort(pendingAnimationEvents.begin(), pendingAnimationEvents.end(), [] (const Ref<AnimationPlaybackEvent>& lhs, const Ref<AnimationPlaybackEvent>& rhs) { 299 // 1. Sort the events by their scheduled event time such that events that were scheduled to occur earlier, sort before events scheduled to occur later 300 // and events whose scheduled event time is unresolved sort before events with a resolved scheduled event time. 301 // 2. Within events with equal scheduled event times, sort by their composite order. FIXME: We don't do this. 302 if (lhs->timelineTime() && !rhs->timelineTime()) 303 return false; 304 if (!lhs->timelineTime() && rhs->timelineTime()) 305 return true; 306 if (!lhs->timelineTime() && !rhs->timelineTime()) 307 return true; 308 return lhs->timelineTime().value() < rhs->timelineTime().value(); 309 }); 310 311 // 6. Dispatch each of the events in events to dispatch at their corresponding target using the order established in the previous step. 312 for (auto& pendingEvent : pendingAnimationEvents) 313 pendingEvent->target()->dispatchEvent(pendingEvent); 314 315 // This will cancel any scheduled invalidation if we end up removing all animations. 316 for (auto& animation : animationsToRemove) 317 removeAnimation(*animation); 318 319 applyPendingAcceleratedAnimations(); 338 320 } 339 321 … … 504 486 { 505 487 m_pendingAnimationEvents.append(event); 506 507 if (!m_eventDispatchTaskQueue.hasPendingTasks())508 m_eventDispatchTaskQueue.enqueueTask(std::bind(&DocumentTimeline::performEventDispatchTask, this));509 }510 511 static inline bool compareAnimationPlaybackEvents(const Ref<WebCore::AnimationPlaybackEvent>& lhs, const Ref<WebCore::AnimationPlaybackEvent>& rhs)512 {513 // Sort the events by their scheduled event time such that events that were scheduled to occur earlier, sort before events scheduled to occur later514 // and events whose scheduled event time is unresolved sort before events with a resolved scheduled event time.515 if (lhs->timelineTime() && !rhs->timelineTime())516 return false;517 if (!lhs->timelineTime() && rhs->timelineTime())518 return true;519 if (!lhs->timelineTime() && !rhs->timelineTime())520 return true;521 return lhs->timelineTime().value() < rhs->timelineTime().value();522 }523 524 void DocumentTimeline::performEventDispatchTask()525 {526 if (m_pendingAnimationEvents.isEmpty())527 return;528 529 auto pendingAnimationEvents = WTFMove(m_pendingAnimationEvents);530 531 std::stable_sort(pendingAnimationEvents.begin(), pendingAnimationEvents.end(), compareAnimationPlaybackEvents);532 for (auto& pendingEvent : pendingAnimationEvents)533 pendingEvent->target()->dispatchEvent(pendingEvent);534 488 } 535 489 -
trunk/Source/WebCore/animation/DocumentTimeline.h
r237499 r237587 50 50 std::optional<Seconds> currentTime() override; 51 51 52 void timingModelDidChange() override;53 52 void animationTimingDidChange(WebAnimation&) override; 53 void removeAnimation(WebAnimation&) override; 54 54 void animationWasAddedToElement(WebAnimation&, Element&) final; 55 55 void animationWasRemovedFromElement(WebAnimation&, Element&) final; … … 86 86 DocumentTimeline(Document&, Seconds); 87 87 88 void scheduleAnimationResolutionIfNeeded(); 88 89 void scheduleInvalidationTaskIfNeeded(); 89 90 void performInvalidationTask(); 90 void updateAnimationSchedule();91 91 void animationScheduleTimerFired(); 92 92 void scheduleAnimationResolution(); 93 void updateAnimations(); 93 void unscheduleAnimationResolution(); 94 void updateAnimationsAndSendEvents(); 94 95 void performEventDispatchTask(); 95 96 void maybeClearCachedCurrentTime(); … … 101 102 bool m_waitingOnVMIdle { false }; 102 103 std::optional<Seconds> m_cachedCurrentTime; 103 GenericTaskQueue<Timer> m_invalidationTaskQueue; 104 GenericTaskQueue<Timer> m_eventDispatchTaskQueue; 105 bool m_needsUpdateAnimationSchedule { false }; 106 Timer m_animationScheduleTimer; 104 GenericTaskQueue<Timer> m_currentTimeClearingTaskQueue; 107 105 HashSet<RefPtr<WebAnimation>> m_acceleratedAnimationsPendingRunningStateChange; 108 106 Vector<Ref<AnimationPlaybackEvent>> m_pendingAnimationEvents; -
trunk/Source/WebCore/animation/WebAnimation.cpp
r237500 r237587 93 93 void WebAnimation::effectTimingPropertiesDidChange() 94 94 { 95 updateFinishedState(DidSeek::No, SynchronouslyNotify::Yes); 96 timingModelDidChange(); 97 } 98 99 void WebAnimation::timingModelDidChange() 100 { 101 if (!isEffectInvalidationSuspended() && m_effect) 102 m_effect->invalidate(); 103 if (m_timeline) 104 m_timeline->timingModelDidChange(); 95 timingDidChange(DidSeek::No, SynchronouslyNotify::Yes); 105 96 } 106 97 … … 123 114 // 4. If animation has a pending pause task, reschedule that task to run as soon as animation is ready. 124 115 if (hasPendingPauseTask()) 125 setTimeToRunPendingPauseTask(TimeToRunPendingTask::WhenReady);116 m_timeToRunPendingPauseTask = TimeToRunPendingTask::WhenReady; 126 117 127 118 // 5. If animation has a pending play task, reschedule that task to run as soon as animation is ready to play new effect. 128 119 if (hasPendingPlayTask()) 129 setTimeToRunPendingPlayTask(TimeToRunPendingTask::WhenReady);120 m_timeToRunPendingPlayTask = TimeToRunPendingTask::WhenReady; 130 121 131 122 // 6. If new effect is not null and if new effect is the target effect of another animation, previous animation, run the … … 139 130 // not break the timeline-to-animation relationship. 140 131 132 invalidateEffect(); 133 141 134 // This object could be deleted after clearing the effect relationship. 142 135 auto protectedThis = makeRef(*this); … … 145 138 // 8. Run the procedure to update an animation’s finished state for animation with the did seek flag set to false, 146 139 // and the synchronously notify flag set to false. 147 updateFinishedState(DidSeek::No, SynchronouslyNotify::No);148 149 timingModelDidChange();140 timingDidChange(DidSeek::No, SynchronouslyNotify::No); 141 142 invalidateEffect(); 150 143 } 151 144 … … 170 163 if (!doNotRemoveFromTimeline && m_timeline && previousTarget && previousTarget != newTarget) 171 164 m_timeline->animationWasRemovedFromElement(*this, *previousTarget); 165 updateRelevance(); 172 166 } 173 167 … … 190 184 // 4. If the animation start time of animation is resolved, make animation’s hold time unresolved. 191 185 if (m_startTime) 192 setHoldTime(std::nullopt);186 m_holdTime = std::nullopt; 193 187 194 188 if (is<KeyframeEffectReadOnly>(m_effect)) { … … 212 206 setSuspended(is<DocumentTimeline>(m_timeline) && downcast<DocumentTimeline>(*m_timeline).animationsAreSuspended()); 213 207 214 updatePendingTasks();215 216 208 // 5. Run the procedure to update an animation’s finished state for animation with the did seek flag set to false, 217 209 // and the synchronously notify flag set to false. 218 updateFinishedState(DidSeek::No, SynchronouslyNotify::No); 210 timingDidChange(DidSeek::No, SynchronouslyNotify::No); 211 212 invalidateEffect(); 219 213 } 220 214 … … 228 222 229 223 m_timeline = WTFMove(timeline); 230 231 if (m_timeline)232 m_timeline->addAnimation(*this);233 224 } 234 225 … … 245 236 } 246 237 247 void WebAnimation::setHoldTime(std::optional<Seconds> holdTime) 248 { 249 if (m_holdTime == holdTime) 250 return; 251 252 m_holdTime = holdTime; 253 timingModelDidChange(); 254 } 255 256 std::optional<double> WebAnimation::bindingsStartTime() const 238 std::optional<double> WebAnimation::startTime() const 257 239 { 258 240 if (!m_startTime) … … 261 243 } 262 244 263 void WebAnimation::set BindingsStartTime(std::optional<double> startTime)245 void WebAnimation::setStartTime(std::optional<double> startTime) 264 246 { 265 247 // 3.4.6 The procedure to set the start time of animation, animation, to new start time, is as follows: … … 279 261 // 2. If timeline time is unresolved and new start time is resolved, make animation's hold time unresolved. 280 262 if (!timelineTime && newStartTime) 281 setHoldTime(std::nullopt);263 m_holdTime = std::nullopt; 282 264 283 265 // 3. Let previous current time be animation's current time. … … 285 267 286 268 // 4. Set animation's start time to new start time. 287 setStartTime(newStartTime);269 m_startTime = newStartTime; 288 270 289 271 // 5. Update animation's hold time based on the first matching condition from the following, … … 292 274 // If animation’s playback rate is not zero, make animation’s hold time unresolved. 293 275 if (m_playbackRate) 294 setHoldTime(std::nullopt);276 m_holdTime = std::nullopt; 295 277 } else { 296 278 // Otherwise (new start time is unresolved), 297 279 // Set animation's hold time to previous current time even if previous current time is unresolved. 298 setHoldTime(previousCurrentTime);280 m_holdTime = previousCurrentTime; 299 281 } 300 282 301 283 // 6. If animation has a pending play task or a pending pause task, cancel that task and resolve animation's current ready promise with animation. 302 284 if (pending()) { 303 setTimeToRunPendingPauseTask(TimeToRunPendingTask::NotScheduled);304 setTimeToRunPendingPlayTask(TimeToRunPendingTask::NotScheduled);285 m_timeToRunPendingPauseTask = TimeToRunPendingTask::NotScheduled; 286 m_timeToRunPendingPlayTask = TimeToRunPendingTask::NotScheduled; 305 287 m_readyPromise->resolve(*this); 306 288 } 307 289 308 290 // 7. Run the procedure to update an animation’s finished state for animation with the did seek flag set to true, and the synchronously notify flag set to false. 309 updateFinishedState(DidSeek::Yes, SynchronouslyNotify::No); 310 311 timingModelDidChange(); 312 } 313 314 std::optional<Seconds> WebAnimation::startTime() const 315 { 316 return m_startTime; 317 } 318 319 void WebAnimation::setStartTime(std::optional<Seconds> newStartTime) 320 { 321 if (m_startTime == newStartTime) 322 return; 323 324 m_startTime = newStartTime; 325 timingModelDidChange(); 291 timingDidChange(DidSeek::Yes, SynchronouslyNotify::No); 292 293 invalidateEffect(); 326 294 } 327 295 … … 393 361 // where timeline time is the current time value of timeline associated with animation. 394 362 if (m_holdTime || !m_startTime || !m_timeline || !m_timeline->currentTime() || !m_playbackRate) 395 setHoldTime(seekTime);363 m_holdTime = seekTime; 396 364 else 397 setStartTime(m_timeline->currentTime().value() - (seekTime.value() / m_playbackRate));365 m_startTime = m_timeline->currentTime().value() - (seekTime.value() / m_playbackRate); 398 366 399 367 // 3. If animation has no associated timeline or the associated timeline is inactive, make animation's start time unresolved. 400 368 if (!m_timeline || !m_timeline->currentTime()) 401 setStartTime(std::nullopt);369 m_startTime = std::nullopt; 402 370 403 371 // 4. Make animation's previous current time unresolved. … … 420 388 if (hasPendingPauseTask()) { 421 389 // 1. Set animation's hold time to seek time. 422 setHoldTime(seekTime);390 m_holdTime = seekTime; 423 391 // 2. Make animation's start time unresolved. 424 setStartTime(std::nullopt);392 m_startTime = std::nullopt; 425 393 // 3. Cancel the pending pause task. 426 setTimeToRunPendingPauseTask(TimeToRunPendingTask::NotScheduled);394 m_timeToRunPendingPauseTask = TimeToRunPendingTask::NotScheduled; 427 395 // 4. Resolve animation's current ready promise with animation. 428 396 m_readyPromise->resolve(*this); … … 430 398 431 399 // 3. Run the procedure to update an animation's finished state for animation with the did seek flag set to true, and the synchronously notify flag set to false. 432 updateFinishedState(DidSeek::Yes, SynchronouslyNotify::No);400 timingDidChange(DidSeek::Yes, SynchronouslyNotify::No); 433 401 434 402 if (m_effect) 435 403 m_effect->animationDidSeek(); 404 405 invalidateEffect(); 436 406 437 407 return { }; … … 467 437 else 468 438 setCurrentTime(previousTime); 439 440 invalidateEffect(); 469 441 } 470 442 … … 511 483 { 512 484 cancel(Silently::No); 485 invalidateEffect(); 513 486 } 514 487 … … 550 523 551 524 // 2. Make animation's hold time unresolved. 552 setHoldTime(std::nullopt);525 m_holdTime = std::nullopt; 553 526 554 527 // 3. Make animation's start time unresolved. 555 setStartTime(std::nullopt); 528 m_startTime = std::nullopt; 529 530 timingDidChange(DidSeek::No, SynchronouslyNotify::No); 531 532 invalidateEffect(); 556 533 } 557 534 … … 587 564 // 2. If animation has a pending play task, cancel that task. 588 565 if (hasPendingPlayTask()) 589 setTimeToRunPendingPlayTask(TimeToRunPendingTask::NotScheduled);566 m_timeToRunPendingPlayTask = TimeToRunPendingTask::NotScheduled; 590 567 591 568 // 3. If animation has a pending pause task, cancel that task. 592 569 if (hasPendingPauseTask()) 593 setTimeToRunPendingPauseTask(TimeToRunPendingTask::NotScheduled);570 m_timeToRunPendingPauseTask = TimeToRunPendingTask::NotScheduled; 594 571 595 572 // 4. Reject animation's current ready promise with a DOMException named "AbortError". … … 624 601 // evaluating timeline time - (limit / playback rate) where timeline time is the current time value of the associated timeline. 625 602 if (!m_startTime && m_timeline && m_timeline->currentTime()) 626 setStartTime(m_timeline->currentTime().value() - (limit / m_playbackRate));603 m_startTime = m_timeline->currentTime().value() - (limit / m_playbackRate); 627 604 628 605 // 5. If there is a pending pause task and start time is resolved, 629 606 if (hasPendingPauseTask() && m_startTime) { 630 607 // 1. Let the hold time be unresolved. 631 setHoldTime(std::nullopt);608 m_holdTime = std::nullopt; 632 609 // 2. Cancel the pending pause task. 633 setTimeToRunPendingPauseTask(TimeToRunPendingTask::NotScheduled);610 m_timeToRunPendingPauseTask = TimeToRunPendingTask::NotScheduled; 634 611 // 3. Resolve the current ready promise of animation with animation. 635 612 m_readyPromise->resolve(*this); … … 638 615 // 6. If there is a pending play task and start time is resolved, cancel that task and resolve the current ready promise of animation with animation. 639 616 if (hasPendingPlayTask() && m_startTime) { 640 setTimeToRunPendingPlayTask(TimeToRunPendingTask::NotScheduled);617 m_timeToRunPendingPlayTask = TimeToRunPendingTask::NotScheduled; 641 618 m_readyPromise->resolve(*this); 642 619 } 643 620 644 621 // 7. Run the procedure to update an animation's finished state animation with the did seek flag set to true, and the synchronously notify flag set to true. 645 updateFinishedState(DidSeek::Yes, SynchronouslyNotify::Yes); 622 timingDidChange(DidSeek::Yes, SynchronouslyNotify::Yes); 623 624 invalidateEffect(); 646 625 647 626 return { }; 627 } 628 629 void WebAnimation::timingDidChange(DidSeek didSeek, SynchronouslyNotify synchronouslyNotify) 630 { 631 updateFinishedState(didSeek, synchronouslyNotify); 632 if (m_timeline) 633 m_timeline->animationTimingDidChange(*this); 634 }; 635 636 void WebAnimation::invalidateEffect() 637 { 638 if (!isEffectInvalidationSuspended() && m_effect) 639 m_effect->invalidate(); 648 640 } 649 641 … … 668 660 // If did seek is true, let the hold time be the value of unconstrained current time. 669 661 if (didSeek == DidSeek::Yes) 670 setHoldTime(unconstrainedCurrentTime);662 m_holdTime = unconstrainedCurrentTime; 671 663 // If did seek is false, let the hold time be the maximum value of previous current time and target effect end. If the previous current time is unresolved, let the hold time be target effect end. 672 664 else if (!m_previousCurrentTime) 673 setHoldTime(endTime);665 m_holdTime = endTime; 674 666 else 675 setHoldTime(std::max(m_previousCurrentTime.value(), endTime));667 m_holdTime = std::max(m_previousCurrentTime.value(), endTime); 676 668 } else if (m_playbackRate < 0 && unconstrainedCurrentTime <= 0_s) { 677 669 // If animation playback rate < 0 and unconstrained current time is less than or equal to 0, 678 670 // If did seek is true, let the hold time be the value of unconstrained current time. 679 671 if (didSeek == DidSeek::Yes) 680 setHoldTime(unconstrainedCurrentTime);672 m_holdTime = unconstrainedCurrentTime; 681 673 // If did seek is false, let the hold time be the minimum value of previous current time and zero. If the previous current time is unresolved, let the hold time be zero. 682 674 else if (!m_previousCurrentTime) 683 setHoldTime(0_s);675 m_holdTime = 0_s; 684 676 else 685 setHoldTime(std::min(m_previousCurrentTime.value(), 0_s));677 m_holdTime = std::min(m_previousCurrentTime.value(), 0_s); 686 678 } else if (m_playbackRate && m_timeline && m_timeline->currentTime()) { 687 679 // If animation playback rate ≠ 0, and animation is associated with an active timeline, … … 690 682 // where timeline time is the current time value of timeline associated with animation. 691 683 if (didSeek == DidSeek::Yes && m_holdTime) 692 setStartTime(m_timeline->currentTime().value() - (m_holdTime.value() / m_playbackRate));684 m_startTime = m_timeline->currentTime().value() - (m_holdTime.value() / m_playbackRate); 693 685 // 2. Let the hold time be unresolved. 694 setHoldTime(std::nullopt);686 m_holdTime = std::nullopt; 695 687 } 696 688 } … … 721 713 if (!currentFinishedState && m_finishedPromise->isFulfilled()) 722 714 m_finishedPromise = makeUniqueRef<FinishedPromise>(*this, &WebAnimation::finishedPromiseResolve); 715 716 updateRelevance(); 723 717 } 724 718 … … 795 789 // - current time ≥ target effect end, 796 790 // Set animation's hold time to zero. 797 setHoldTime(0_s);791 m_holdTime = 0_s; 798 792 } else if (m_playbackRate < 0 && autoRewind == AutoRewind::Yes && (!localTime || localTime.value() <= 0_s || localTime.value() > endTime)) { 799 793 // If animation playback rate < 0, the auto-rewind flag is true and either animation's: … … 804 798 if (endTime == Seconds::infinity()) 805 799 return Exception { InvalidStateError }; 806 setHoldTime(endTime);800 m_holdTime = endTime; 807 801 } else if (!m_playbackRate && !localTime) { 808 802 // If animation playback rate = 0 and animation's current time is unresolved, 809 803 // Set animation's hold time to zero. 810 setHoldTime(0_s);804 m_holdTime = 0_s; 811 805 } 812 806 … … 814 808 if (pending()) { 815 809 // 1. Cancel that task. 816 setTimeToRunPendingPauseTask(TimeToRunPendingTask::NotScheduled);817 setTimeToRunPendingPlayTask(TimeToRunPendingTask::NotScheduled);810 m_timeToRunPendingPauseTask = TimeToRunPendingTask::NotScheduled; 811 m_timeToRunPendingPlayTask = TimeToRunPendingTask::NotScheduled; 818 812 // 2. Set has pending ready promise to true. 819 813 hasPendingReadyPromise = true; … … 826 820 // 6. If animation's hold time is resolved, let its start time be unresolved. 827 821 if (m_holdTime) 828 setStartTime(std::nullopt);822 m_startTime = std::nullopt; 829 823 830 824 // 7. If has pending ready promise is false, let animation's current ready promise be a new (pending) Promise object. … … 833 827 834 828 // 8. Schedule a task to run as soon as animation is ready. 835 setTimeToRunPendingPlayTask(TimeToRunPendingTask::WhenReady);829 m_timeToRunPendingPlayTask = TimeToRunPendingTask::WhenReady; 836 830 837 831 // 9. Run the procedure to update an animation's finished state for animation with the did seek flag set to false, and the synchronously notify flag set to false. 838 updateFinishedState(DidSeek::No, SynchronouslyNotify::No); 832 timingDidChange(DidSeek::No, SynchronouslyNotify::No); 833 834 invalidateEffect(); 839 835 840 836 return { }; 841 }842 843 void WebAnimation::setTimeToRunPendingPlayTask(TimeToRunPendingTask timeToRunPendingTask)844 {845 if (m_timeToRunPendingPlayTask == timeToRunPendingTask)846 return;847 848 m_timeToRunPendingPlayTask = timeToRunPendingTask;849 updatePendingTasks();850 837 } 851 838 … … 876 863 // 2. If animation's playback rate is not 0, make animation's hold time unresolved. 877 864 if (m_playbackRate) 878 setHoldTime(std::nullopt);865 m_holdTime = std::nullopt; 879 866 // 3. Set the animation start time of animation to new start time. 880 setStartTime(newStartTime);867 m_startTime = newStartTime; 881 868 } 882 869 … … 886 873 887 874 // 5. Run the procedure to update an animation's finished state for animation with the did seek flag set to false, and the synchronously notify flag set to false. 888 updateFinishedState(DidSeek::No, SynchronouslyNotify::No); 875 timingDidChange(DidSeek::No, SynchronouslyNotify::No); 876 877 invalidateEffect(); 889 878 } 890 879 … … 908 897 if (m_playbackRate >= 0) { 909 898 // If animation's playback rate is ≥ 0, let animation's hold time be zero. 910 setHoldTime(0_s);899 m_holdTime = 0_s; 911 900 } else if (effectEndTime() == Seconds::infinity()) { 912 901 // Otherwise, if target effect end for animation is positive infinity, throw an InvalidStateError and abort these steps. … … 914 903 } else { 915 904 // Otherwise, let animation's hold time be target effect end. 916 setHoldTime(effectEndTime());905 m_holdTime = effectEndTime(); 917 906 } 918 907 } … … 923 912 // 5. If animation has a pending play task, cancel that task and let has pending ready promise be true. 924 913 if (hasPendingPlayTask()) { 925 setTimeToRunPendingPlayTask(TimeToRunPendingTask::NotScheduled);914 m_timeToRunPendingPlayTask = TimeToRunPendingTask::NotScheduled; 926 915 hasPendingReadyPromise = true; 927 916 } … … 933 922 // 7. Schedule a task to be executed at the first possible moment after the user agent has performed any processing necessary 934 923 // to suspend the playback of animation's target effect, if any. 935 setTimeToRunPendingPauseTask(TimeToRunPendingTask::ASAP);924 m_timeToRunPendingPauseTask = TimeToRunPendingTask::ASAP; 936 925 937 926 // 8. Run the procedure to update an animation's finished state for animation with the did seek flag set to false, and the synchronously notify flag set to false. 938 updateFinishedState(DidSeek::No, SynchronouslyNotify::No); 927 timingDidChange(DidSeek::No, SynchronouslyNotify::No); 928 929 invalidateEffect(); 939 930 940 931 return { }; … … 971 962 972 963 return { }; 973 }974 975 void WebAnimation::setTimeToRunPendingPauseTask(TimeToRunPendingTask timeToRunPendingTask)976 {977 if (m_timeToRunPendingPauseTask == timeToRunPendingTask)978 return;979 980 m_timeToRunPendingPauseTask = timeToRunPendingTask;981 updatePendingTasks();982 964 } 983 965 … … 1003 985 // C++14 builds (the latter using WTF's std::optional) and avoid null std::optional dereferencing 1004 986 // by defaulting to a Seconds(0) value. See https://bugs.webkit.org/show_bug.cgi?id=186189. 1005 setHoldTime((readyTime.value_or(0_s) - animationStartTime.value()) * m_playbackRate);987 m_holdTime = (readyTime.value_or(0_s) - animationStartTime.value()) * m_playbackRate; 1006 988 } 1007 989 1008 990 // 3. Make animation's start time unresolved. 1009 setStartTime(std::nullopt);991 m_startTime = std::nullopt; 1010 992 1011 993 // 4. Resolve animation's current ready promise with animation. … … 1015 997 // 5. Run the procedure to update an animation's finished state for animation with the did seek flag set to false, and the 1016 998 // synchronously notify flag set to false. 1017 updateFinishedState(DidSeek::No, SynchronouslyNotify::No); 1018 } 1019 1020 void WebAnimation::updatePendingTasks() 1021 { 1022 timingModelDidChange(); 1023 } 1024 1025 Seconds WebAnimation::timeToNextRequiredTick() const 1026 { 1027 // If we don't have a timeline, an effect, a start time or a playback rate other than 0, 1028 // there is no value to apply so we don't need to schedule invalidation. 1029 if (!m_timeline || !m_effect || !m_playbackRate) 1030 return Seconds::infinity(); 1031 1032 if (pending()) 1033 return 0_s; 1034 1035 if (!m_startTime) 1036 return Seconds::infinity(); 1037 1038 // If we're in or expected to be in the running state, we need to schedule invalidation as soon as possible. 1039 if (hasPendingPlayTask() || playState() == PlayState::Running) 1040 return 0_s; 1041 1042 if (auto animationCurrentTime = currentTime()) { 1043 // If our current time is negative, we need to be scheduled to be resolved at the inverse 1044 // of our current time, unless we fill backwards, in which case we want to invalidate as 1045 // soon as possible. 1046 auto localTime = animationCurrentTime.value(); 1047 if (localTime < 0_s) 1048 return -localTime; 1049 } 1050 1051 // In any other case, we're idle or already outside our active duration and have no need 1052 // to schedule an invalidation. 1053 return Seconds::infinity(); 1054 } 1055 1056 void WebAnimation::runPendingTasks() 1057 { 999 timingDidChange(DidSeek::No, SynchronouslyNotify::No); 1000 1001 invalidateEffect(); 1002 } 1003 1004 bool WebAnimation::needsTick() const 1005 { 1006 return pending() || playState() == PlayState::Running; 1007 } 1008 1009 void WebAnimation::tick() 1010 { 1011 updateFinishedState(DidSeek::No, SynchronouslyNotify::Yes); 1012 1013 // Run pending tasks, if any. 1058 1014 if (hasPendingPauseTask()) 1059 1015 runPendingPauseTask(); 1060 1061 1016 if (hasPendingPlayTask()) 1062 1017 runPendingPlayTask(); 1063 } 1064 1065 void WebAnimation::resolve() 1066 { 1067 updateFinishedState(DidSeek::No, SynchronouslyNotify::Yes); 1018 1019 invalidateEffect(); 1068 1020 } 1069 1021 1070 1022 void WebAnimation::resolve(RenderStyle& targetStyle) 1071 1023 { 1072 resolve();1024 timingDidChange(DidSeek::No, SynchronouslyNotify::Yes); 1073 1025 if (m_effect) 1074 1026 m_effect->apply(targetStyle); … … 1124 1076 } 1125 1077 1126 bool WebAnimation::canBeListed() const 1078 void WebAnimation::updateRelevance() 1079 { 1080 m_isRelevant = computeRelevance(); 1081 } 1082 1083 bool WebAnimation::computeRelevance() 1127 1084 { 1128 1085 // To be listed in getAnimations() an animation needs a target effect which is current or in effect. -
trunk/Source/WebCore/animation/WebAnimation.h
r237500 r237587 58 58 virtual bool isCSSTransition() const { return false; } 59 59 60 virtual bool canBeListed() const;61 62 60 const String& id() const { return m_id; } 63 61 void setId(const String& id) { m_id = id; } … … 67 65 AnimationTimeline* timeline() const { return m_timeline.get(); } 68 66 virtual void setTimeline(RefPtr<AnimationTimeline>&&); 69 70 std::optional<Seconds> startTime() const;71 void setStartTime(std::optional<Seconds>);72 67 73 68 std::optional<Seconds> currentTime() const; … … 96 91 ExceptionOr<void> reverse(); 97 92 98 virtual std::optional<double> bindingsStartTime() const;99 virtual void set BindingsStartTime(std::optional<double>);93 virtual std::optional<double> startTime() const; 94 virtual void setStartTime(std::optional<double>); 100 95 virtual std::optional<double> bindingsCurrentTime() const; 101 96 virtual ExceptionOr<void> setBindingsCurrentTime(std::optional<double>); … … 107 102 virtual ExceptionOr<void> bindingsPause() { return pause(); } 108 103 109 Seconds timeToNextRequiredTick() const;110 v oid resolve();104 virtual bool needsTick() const; 105 virtual void tick(); 111 106 virtual void resolve(RenderStyle&); 112 void runPendingTasks();113 107 void effectTargetDidChange(Element* previousTarget, Element* newTarget); 114 108 void acceleratedStateDidChange(); 115 109 void applyPendingAcceleratedActions(); 116 110 117 void timingModelDidChange();111 bool isRelevant() const { return m_isRelevant; } 118 112 void effectTimingPropertiesDidChange(); 119 113 void suspendEffectInvalidation(); … … 129 123 explicit WebAnimation(Document&); 130 124 131 bool isEffectInvalidationSuspended() { return m_suspendCount; }132 125 void stop() override; 133 126 … … 139 132 enum class TimeToRunPendingTask { NotScheduled, ASAP, WhenReady }; 140 133 134 void timingDidChange(DidSeek, SynchronouslyNotify); 141 135 void updateFinishedState(DidSeek, SynchronouslyNotify); 142 136 void enqueueAnimationPlaybackEvent(const AtomicString&, std::optional<Seconds>, std::optional<Seconds>); … … 144 138 WebAnimation& readyPromiseResolve(); 145 139 WebAnimation& finishedPromiseResolve(); 146 void setHoldTime(std::optional<Seconds>);147 140 std::optional<Seconds> currentTime(RespectHoldTime) const; 148 141 ExceptionOr<void> silentlySetCurrentTime(std::optional<Seconds>); … … 150 143 void scheduleMicrotaskIfNeeded(); 151 144 void performMicrotask(); 152 void setTimeToRunPendingPauseTask(TimeToRunPendingTask);153 void setTimeToRunPendingPlayTask(TimeToRunPendingTask);154 145 bool hasPendingPauseTask() const { return m_timeToRunPendingPauseTask != TimeToRunPendingTask::NotScheduled; } 155 146 bool hasPendingPlayTask() const { return m_timeToRunPendingPlayTask != TimeToRunPendingTask::NotScheduled; } 156 void updatePendingTasks();157 147 ExceptionOr<void> play(AutoRewind); 158 148 void runPendingPauseTask(); … … 161 151 void setEffectInternal(RefPtr<AnimationEffectReadOnly>&&, bool = false); 162 152 void setTimelineInternal(RefPtr<AnimationTimeline>&&); 153 bool isEffectInvalidationSuspended() { return m_suspendCount; } 154 bool computeRelevance(); 155 void updateRelevance(); 156 void invalidateEffect(); 163 157 164 158 String m_id; … … 174 168 bool m_finishNotificationStepsMicrotaskPending; 175 169 bool m_scheduledMicrotask; 170 bool m_isRelevant; 176 171 UniqueRef<ReadyPromise> m_readyPromise; 177 172 UniqueRef<FinishedPromise> m_finishedPromise; -
trunk/Source/WebCore/animation/WebAnimation.idl
r233051 r237587 41 41 attribute AnimationEffectReadOnly? effect; 42 42 attribute AnimationTimeline? timeline; 43 [ImplementedAs=bindingsStartTime]attribute double? startTime;43 attribute double? startTime; 44 44 [MayThrowException, ImplementedAs=bindingsCurrentTime] attribute double? currentTime; 45 45 attribute double playbackRate; -
trunk/Source/WebCore/dom/Element.cpp
r237468 r237587 4032 4032 if (auto timeline = document().existingTimeline()) { 4033 4033 for (auto& animation : timeline->animationsForElement(*this, AnimationTimeline::Ordering::Sorted)) { 4034 if (animation-> canBeListed())4034 if (animation->isRelevant()) 4035 4035 animations.append(animation); 4036 4036 }
Note:
See TracChangeset
for help on using the changeset viewer.