Title: [260525] trunk
Revision
260525
Author
grao...@webkit.org
Date
2020-04-22 11:47:36 -0700 (Wed, 22 Apr 2020)

Log Message

[Web Animations] Coordinate "update animations and send events" procedure across multiple timelines
https://bugs.webkit.org/show_bug.cgi?id=202109
<rdar://problem/59470821>

Reviewed by Dean Jackson.

LayoutTests/imported/w3c:

Mark a new test as PASS which shows that we correctly perform a single microstask checkpoint when updating multiple timelines.

* web-platform-tests/web-animations/timing-model/timelines/update-and-send-events-expected.txt:

Source/WebCore:

So far, although we did manage multiple animation timelines per document, we mostly operated
under the assumption that there really was a single timeline. In this patch we make the
"update animations and send events" procedure, which is central to the lifecycle of animations,
work with multiple timelines such that a single microtask checkpoint is performed even with multiple
timelines, whereas we would perform one per timeline before. To do this, we move much of the logic
DocumentTimeline::updateAnimationsAndSendEvents() to DocumentTimelinesController where each step is
run across each timeline, rather than running all steps for each timeline one after the other,
respecting the single microtask checkpoint in the middle of the process.

To minimize code churn at this stage, we still keep a fair bit of logic in DocumentTimeline and,
while we remove updateAnimationsAndSendEvents(), internalUpdateAnimationsAndSendEvents() and
updateCurrentTime(), we expose three methods that allow to run the pre-flight sequence in
documentWillUpdateAnimationsAndSendEvents(), collect pending events in
prepareForPendingAnimationEventsDispatch() and run the post-flight sequence
in documentDidUpdateAnimationsAndSendEvents().

None of the logic changes, this is just moving code around. In the future, more patches will move
code from DocumentTimeline up to DocumentTimelinesController such that events are enqueued there,
and animation scheduling as well. But this already lets us pass a new test that used to flakily
reject promises in the WPT test web-animations/timing-model/timelines/update-and-send-events.html.

* animation/AnimationTimeline.h:
(WebCore::AnimationTimeline::relevantAnimations const):
(WebCore::AnimationTimeline::allAnimations const):
* animation/DocumentTimeline.cpp:
(WebCore::DocumentTimeline::documentWillUpdateAnimationsAndSendEvents):
(WebCore::DocumentTimeline::documentDidUpdateAnimationsAndSendEvents):
(WebCore::DocumentTimeline::prepareForPendingAnimationEventsDispatch):
(WebCore::DocumentTimeline::updateCurrentTime): Deleted.
(WebCore::DocumentTimeline::updateAnimationsAndSendEvents): Deleted.
(WebCore::DocumentTimeline::internalUpdateAnimationsAndSendEvents): Deleted.
* animation/DocumentTimeline.h:
* animation/DocumentTimelinesController.cpp:
(WebCore::DocumentTimelinesController::DocumentTimelinesController):
(WebCore::DocumentTimelinesController::updateAnimationsAndSendEvents):
* animation/DocumentTimelinesController.h:
* animation/WebAnimationTypes.h:
* dom/Document.cpp:
(WebCore::Document::ensureTimelinesController):

LayoutTests:

Remove the flaky expectation for the improved test.

* TestExpectations:

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (260524 => 260525)


--- trunk/LayoutTests/ChangeLog	2020-04-22 18:38:36 UTC (rev 260524)
+++ trunk/LayoutTests/ChangeLog	2020-04-22 18:47:36 UTC (rev 260525)
@@ -1,5 +1,17 @@
 2020-04-22  Antoine Quint  <grao...@apple.com>
 
+        [Web Animations] Coordinate "update animations and send events" procedure across multiple timelines
+        https://bugs.webkit.org/show_bug.cgi?id=202109
+        <rdar://problem/59470821>
+
+        Reviewed by Dean Jackson.
+
+        Remove the flaky expectation for the improved test.
+
+        * TestExpectations:
+
+2020-04-22  Antoine Quint  <grao...@apple.com>
+
         [ Mojave wk1 Release ] animations/transition-and-animation-1.html is a flaky failure
         https://bugs.webkit.org/show_bug.cgi?id=210051
         <rdar://problem/61345177>

Modified: trunk/LayoutTests/TestExpectations (260524 => 260525)


--- trunk/LayoutTests/TestExpectations	2020-04-22 18:38:36 UTC (rev 260524)
+++ trunk/LayoutTests/TestExpectations	2020-04-22 18:47:36 UTC (rev 260525)
@@ -4064,8 +4064,6 @@
 
 webkit.org/b/207262 imported/w3c/web-platform-tests/web-animations/timing-model/animations/sync-start-times.html [ Pass ImageOnlyFailure ]
 
-webkit.org/b/202109 imported/w3c/web-platform-tests/web-animations/timing-model/timelines/update-and-send-events.html [ Pass Failure ]
-
 # WebXR is being implemented
 webkit.org/b/208988 imported/w3c/web-platform-tests/webxr [ Skip ]
 

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (260524 => 260525)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2020-04-22 18:38:36 UTC (rev 260524)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2020-04-22 18:47:36 UTC (rev 260525)
@@ -1,3 +1,15 @@
+2020-04-22  Antoine Quint  <grao...@apple.com>
+
+        [Web Animations] Coordinate "update animations and send events" procedure across multiple timelines
+        https://bugs.webkit.org/show_bug.cgi?id=202109
+        <rdar://problem/59470821>
+
+        Reviewed by Dean Jackson.
+
+        Mark a new test as PASS which shows that we correctly perform a single microstask checkpoint when updating multiple timelines.
+
+        * web-platform-tests/web-animations/timing-model/timelines/update-and-send-events-expected.txt:
+
 2020-04-21  Sergio Villar Senin  <svil...@igalia.com>
 
         Import latest changes from web-platform-test/webxr/resources to enable testing in WebKit

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/web-animations/timing-model/timelines/update-and-send-events-expected.txt (260524 => 260525)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/web-animations/timing-model/timelines/update-and-send-events-expected.txt	2020-04-22 18:38:36 UTC (rev 260524)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/web-animations/timing-model/timelines/update-and-send-events-expected.txt	2020-04-22 18:47:36 UTC (rev 260525)
@@ -6,5 +6,5 @@
 PASS Queues a cancel event in transitionstart event callback 
 PASS Sorts events for the same transition 
 PASS Playback events with the same timeline retain the order in which they arequeued 
-FAIL All timelines are updated before running microtasks promise_test: Unhandled rejection with value: object "AbortError: The operation was aborted."
+PASS All timelines are updated before running microtasks 
 

Modified: trunk/Source/WebCore/ChangeLog (260524 => 260525)


--- trunk/Source/WebCore/ChangeLog	2020-04-22 18:38:36 UTC (rev 260524)
+++ trunk/Source/WebCore/ChangeLog	2020-04-22 18:47:36 UTC (rev 260525)
@@ -1,3 +1,51 @@
+2020-04-22  Antoine Quint  <grao...@apple.com>
+
+        [Web Animations] Coordinate "update animations and send events" procedure across multiple timelines
+        https://bugs.webkit.org/show_bug.cgi?id=202109
+        <rdar://problem/59470821>
+
+        Reviewed by Dean Jackson.
+
+        So far, although we did manage multiple animation timelines per document, we mostly operated
+        under the assumption that there really was a single timeline. In this patch we make the
+        "update animations and send events" procedure, which is central to the lifecycle of animations,
+        work with multiple timelines such that a single microtask checkpoint is performed even with multiple
+        timelines, whereas we would perform one per timeline before. To do this, we move much of the logic
+        DocumentTimeline::updateAnimationsAndSendEvents() to DocumentTimelinesController where each step is
+        run across each timeline, rather than running all steps for each timeline one after the other,
+        respecting the single microtask checkpoint in the middle of the process.
+
+        To minimize code churn at this stage, we still keep a fair bit of logic in DocumentTimeline and,
+        while we remove updateAnimationsAndSendEvents(), internalUpdateAnimationsAndSendEvents() and
+        updateCurrentTime(), we expose three methods that allow to run the pre-flight sequence in
+        documentWillUpdateAnimationsAndSendEvents(), collect pending events in
+        prepareForPendingAnimationEventsDispatch() and run the post-flight sequence
+        in documentDidUpdateAnimationsAndSendEvents().
+
+        None of the logic changes, this is just moving code around. In the future, more patches will move
+        code from DocumentTimeline up to DocumentTimelinesController such that events are enqueued there,
+        and animation scheduling as well. But this already lets us pass a new test that used to flakily
+        reject promises in the WPT test web-animations/timing-model/timelines/update-and-send-events.html.
+
+        * animation/AnimationTimeline.h:
+        (WebCore::AnimationTimeline::relevantAnimations const):
+        (WebCore::AnimationTimeline::allAnimations const):
+        * animation/DocumentTimeline.cpp:
+        (WebCore::DocumentTimeline::documentWillUpdateAnimationsAndSendEvents):
+        (WebCore::DocumentTimeline::documentDidUpdateAnimationsAndSendEvents):
+        (WebCore::DocumentTimeline::prepareForPendingAnimationEventsDispatch):
+        (WebCore::DocumentTimeline::updateCurrentTime): Deleted.
+        (WebCore::DocumentTimeline::updateAnimationsAndSendEvents): Deleted.
+        (WebCore::DocumentTimeline::internalUpdateAnimationsAndSendEvents): Deleted.
+        * animation/DocumentTimeline.h:
+        * animation/DocumentTimelinesController.cpp:
+        (WebCore::DocumentTimelinesController::DocumentTimelinesController):
+        (WebCore::DocumentTimelinesController::updateAnimationsAndSendEvents):
+        * animation/DocumentTimelinesController.h:
+        * animation/WebAnimationTypes.h:
+        * dom/Document.cpp:
+        (WebCore::Document::ensureTimelinesController):
+
 2020-04-22  Eric Carlson  <eric.carl...@apple.com>
 
         [iOS] Add a quirk to keep gizmodo videos visible when playing in fullscreen.

Modified: trunk/Source/WebCore/animation/AnimationTimeline.h (260524 => 260525)


--- trunk/Source/WebCore/animation/AnimationTimeline.h	2020-04-22 18:38:36 UTC (rev 260524)
+++ trunk/Source/WebCore/animation/AnimationTimeline.h	2020-04-22 18:47:36 UTC (rev 260525)
@@ -50,6 +50,9 @@
 public:
     virtual bool isDocumentTimeline() const { return false; }
 
+    AnimationCollection relevantAnimations() const { return m_animations; }
+    Vector<WeakPtr<WebAnimation>> allAnimations() const { return m_allAnimations; }
+
     void forgetAnimation(WebAnimation*);
     virtual void animationTimingDidChange(WebAnimation&);
     virtual void removeAnimation(WebAnimation&);

Modified: trunk/Source/WebCore/animation/DocumentTimeline.cpp (260524 => 260525)


--- trunk/Source/WebCore/animation/DocumentTimeline.cpp	2020-04-22 18:38:36 UTC (rev 260524)
+++ trunk/Source/WebCore/animation/DocumentTimeline.cpp	2020-04-22 18:47:36 UTC (rev 260525)
@@ -33,7 +33,6 @@
 #include "DeclarativeAnimation.h"
 #include "Document.h"
 #include "DocumentTimelinesController.h"
-#include "EventLoop.h"
 #include "EventNames.h"
 #include "GraphicsLayer.h"
 #include "KeyframeEffect.h"
@@ -362,7 +361,7 @@
     return !m_animations.isEmpty() || !m_pendingAnimationEvents.isEmpty() || !m_acceleratedAnimationsPendingRunningStateChange.isEmpty();
 }
 
-void DocumentTimeline::updateCurrentTime(DOMHighResTimeStamp timestamp)
+DocumentTimeline::ShouldUpdateAnimationsAndSendEvents DocumentTimeline::documentWillUpdateAnimationsAndSendEvents(DOMHighResTimeStamp timestamp)
 {
     // We need to freeze the current time even if no animation is running.
     // document.timeline.currentTime may be called from a rAF callback and
@@ -369,29 +368,14 @@
     // it has to match the rAF timestamp.
     if (!m_isSuspended || !shouldRunUpdateAnimationsAndSendEventsIgnoringSuspensionState())
         cacheCurrentTime(timestamp);
-}
 
-void DocumentTimeline::updateAnimationsAndSendEvents()
-{
     // Updating animations and sending events may invalidate the timing of some animations, so we must set the m_animationResolutionScheduled
     // flag to false prior to running that procedure to allow animation with timing model updates to schedule updates.
-    m_animationResolutionScheduled = false;
+    bool wasAnimationResolutionScheduled = std::exchange(m_animationResolutionScheduled, false);
 
-    if (m_isSuspended)
-        return;
+    if (!wasAnimationResolutionScheduled || m_isSuspended || !shouldRunUpdateAnimationsAndSendEventsIgnoringSuspensionState())
+        return DocumentTimeline::ShouldUpdateAnimationsAndSendEvents::No;
 
-    if (!shouldRunUpdateAnimationsAndSendEventsIgnoringSuspensionState())
-        return;
-
-    internalUpdateAnimationsAndSendEvents();
-    applyPendingAcceleratedAnimations();
-
-    if (!m_animationResolutionScheduled)
-        scheduleNextTick();
-}
-
-void DocumentTimeline::internalUpdateAnimationsAndSendEvents()
-{
     m_numberOfAnimationTimelineInvalidationsForTesting++;
 
     // enqueueAnimationEvent() calls scheduleAnimationResolution() to ensure that the "update animations and send events"
@@ -399,77 +383,15 @@
     // this procedure is running should not schedule animation resolution until the event queue has been cleared.
     m_shouldScheduleAnimationResolutionForNewPendingEvents = false;
 
-    // https://drafts.csswg.org/web-animations/#update-animations-and-send-events
+    return DocumentTimeline::ShouldUpdateAnimationsAndSendEvents::Yes;
+}
 
-    // 1. Update the current time of all timelines associated with doc passing now as the timestamp.
+void DocumentTimeline::documentDidUpdateAnimationsAndSendEvents()
+{
+    applyPendingAcceleratedAnimations();
 
-    Vector<RefPtr<WebAnimation>> animationsToRemove;
-    Vector<RefPtr<CSSTransition>> completedTransitions;
-
-    for (auto& animation : m_animations) {
-        if (animation->timeline() != this) {
-            ASSERT(!animation->timeline());
-            animationsToRemove.append(animation);
-            continue;
-        }
-
-        // This will notify the animation that timing has changed and will call automatically
-        // schedule invalidation if required for this animation.
-        animation->tick();
-
-        if (!animation->isRelevant() && !animation->needsTick())
-            animationsToRemove.append(animation);
-
-        if (!animation->needsTick() && is<CSSTransition>(animation) && animation->playState() == WebAnimation::PlayState::Finished) {
-            auto* transition = downcast<CSSTransition>(animation.get());
-            if (transition->owningElement())
-                completedTransitions.append(transition);
-        }
-    }
-
-    // 2. Remove replaced animations for doc.
-    removeReplacedAnimations();
-
-    // 3. Perform a microtask checkpoint.
-    if (auto document = makeRefPtr(this->document()))
-        document->eventLoop().performMicrotaskCheckpoint();
-
-    // 4. Let events to dispatch be a copy of doc's pending animation event queue.
-    // 5. Clear doc's pending animation event queue.
-    auto pendingAnimationEvents = WTFMove(m_pendingAnimationEvents);
-    m_shouldScheduleAnimationResolutionForNewPendingEvents = true;
-
-    // 6. Perform a stable sort of the animation events in events to dispatch as follows.
-    std::stable_sort(pendingAnimationEvents.begin(), pendingAnimationEvents.end(), [] (const Ref<AnimationEventBase>& lhs, const Ref<AnimationEventBase>& rhs) {
-        // 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
-        // and events whose scheduled event time is unresolved sort before events with a resolved scheduled event time.
-        // 2. Within events with equal scheduled event times, sort by their composite order. FIXME: We don't do this.
-        if (lhs->timelineTime() && !rhs->timelineTime())
-            return false;
-        if (!lhs->timelineTime() && rhs->timelineTime())
-            return true;
-        if (!lhs->timelineTime() && !rhs->timelineTime())
-            return true;
-        return lhs->timelineTime().value() < rhs->timelineTime().value();
-    });
-
-    // 7. Dispatch each of the events in events to dispatch at their corresponding target using the order established in the previous step.
-    for (auto& pendingAnimationEvent : pendingAnimationEvents)
-        pendingAnimationEvent->target()->dispatchEvent(pendingAnimationEvent);
-
-    // This will cancel any scheduled invalidation if we end up removing all animations.
-    for (auto& animation : animationsToRemove) {
-        // An animation that was initially marked as irrelevant may have changed while we were sending events, so we run the same
-        // check that we ran to add it to animationsToRemove in the first place.
-        if (!animation->isRelevant() && !animation->needsTick())
-            removeAnimation(*animation);
-    }
-
-    // Now that animations that needed removal have been removed, let's update the list of completed transitions.
-    // This needs to happen after dealing with the list of animations to remove as the animation may have been
-    // removed from the list of completed transitions otherwise.
-    for (auto& completedTransition : completedTransitions)
-        transitionDidComplete(completedTransition);
+    if (!m_animationResolutionScheduled)
+        scheduleNextTick();
 }
 
 bool DocumentTimeline::animationCanBeRemoved(WebAnimation& animation)
@@ -735,6 +657,12 @@
         scheduleAnimationResolution();
 }
 
+AnimationEvents DocumentTimeline::prepareForPendingAnimationEventsDispatch()
+{
+    m_shouldScheduleAnimationResolutionForNewPendingEvents = true;
+    return std::exchange(m_pendingAnimationEvents, { });
+}
+
 Vector<std::pair<String, double>> DocumentTimeline::acceleratedAnimationsForElement(Element& element) const
 {
     auto* renderer = element.renderer();

Modified: trunk/Source/WebCore/animation/DocumentTimeline.h (260524 => 260525)


--- trunk/Source/WebCore/animation/DocumentTimeline.h	2020-04-22 18:38:36 UTC (rev 260524)
+++ trunk/Source/WebCore/animation/DocumentTimeline.h	2020-04-22 18:47:36 UTC (rev 260525)
@@ -58,6 +58,7 @@
     void removeAnimation(WebAnimation&) override;
     void animationWasAddedToElement(WebAnimation&, Element&) final;
     void animationWasRemovedFromElement(WebAnimation&, Element&) final;
+    void transitionDidComplete(RefPtr<CSSTransition>);
 
     // If possible, compute the visual extent of any transform animation on the given renderer
     // using the given rect, returning the result in the rect. Return false if there is some
@@ -72,9 +73,11 @@
 
     void enqueueAnimationEvent(AnimationEventBase&);
     
-    bool scheduledUpdate() const { return m_animationResolutionScheduled; }
-    void updateCurrentTime(DOMHighResTimeStamp timestamp);
-    void updateAnimationsAndSendEvents();
+    enum class ShouldUpdateAnimationsAndSendEvents : uint8_t { Yes, No };
+    ShouldUpdateAnimationsAndSendEvents documentWillUpdateAnimationsAndSendEvents(DOMHighResTimeStamp);
+    void removeReplacedAnimations();
+    AnimationEvents prepareForPendingAnimationEventsDispatch();
+    void documentDidUpdateAnimationsAndSendEvents();
 
     void updateThrottlingState();
     WEBCORE_EXPORT Seconds animationInterval() const;
@@ -98,9 +101,7 @@
     void clearTickScheduleTimer();
     void internalUpdateAnimationsAndSendEvents();
     void updateListOfElementsWithRunningAcceleratedAnimationsForElement(Element&);
-    void transitionDidComplete(RefPtr<CSSTransition>);
     void scheduleNextTick();
-    void removeReplacedAnimations();
     bool animationCanBeRemoved(WebAnimation&);
     bool shouldRunUpdateAnimationsAndSendEventsIgnoringSuspensionState() const;
 
@@ -108,7 +109,7 @@
     GenericTaskQueue<Timer> m_currentTimeClearingTaskQueue;
     HashSet<RefPtr<WebAnimation>> m_acceleratedAnimationsPendingRunningStateChange;
     HashSet<Element*> m_elementsWithRunningAcceleratedAnimations;
-    Vector<Ref<AnimationEventBase>> m_pendingAnimationEvents;
+    AnimationEvents m_pendingAnimationEvents;
     WeakPtr<Document> m_document;
     Markable<Seconds, Seconds::MarkableTraits> m_cachedCurrentTime;
     Seconds m_originTime;

Modified: trunk/Source/WebCore/animation/DocumentTimelinesController.cpp (260524 => 260525)


--- trunk/Source/WebCore/animation/DocumentTimelinesController.cpp	2020-04-22 18:38:36 UTC (rev 260524)
+++ trunk/Source/WebCore/animation/DocumentTimelinesController.cpp	2020-04-22 18:47:36 UTC (rev 260525)
@@ -26,11 +26,18 @@
 #include "config.h"
 #include "DocumentTimelinesController.h"
 
+#include "AnimationEventBase.h"
+#include "CSSTransition.h"
+#include "Document.h"
 #include "DocumentTimeline.h"
+#include "EventLoop.h"
+#include "WebAnimation.h"
+#include "WebAnimationTypes.h"
 
 namespace WebCore {
 
-DocumentTimelinesController::DocumentTimelinesController()
+DocumentTimelinesController::DocumentTimelinesController(Document& document)
+    : m_document(document)
 {
 }
 
@@ -58,20 +65,95 @@
 {
     ASSERT(!m_timelines.hasNullReferences());
 
-    // We need to copy m_timelines before iterating over its members since calling updateAnimationsAndSendEvents() may mutate m_timelines.
-    Vector<RefPtr<DocumentTimeline>> timelines;
-    bool shouldUpdateAnimations = false;
-    for (auto& timeline : m_timelines) {
-        if (timeline.scheduledUpdate())
-            shouldUpdateAnimations = true;
-        timelines.append(&timeline);
+    // We need to copy m_timelines before iterating over its members since the steps in this procedure may mutate m_timelines.
+    Vector<RefPtr<DocumentTimeline>> protectedTimelines;
+    for (auto& timeline : m_timelines)
+        protectedTimelines.append(&timeline);
+
+    // 1. Update the current time of all timelines associated with doc passing now as the timestamp.
+    Vector<DocumentTimeline*> timelinesToUpdate;
+    Vector<RefPtr<WebAnimation>> animationsToRemove;
+    Vector<RefPtr<CSSTransition>> completedTransitions;
+    for (auto& timeline : protectedTimelines) {
+        auto shouldUpdateAnimationsAndSendEvents = timeline->documentWillUpdateAnimationsAndSendEvents(timestamp);
+        if (shouldUpdateAnimationsAndSendEvents == DocumentTimeline::ShouldUpdateAnimationsAndSendEvents::No)
+            continue;
+
+        timelinesToUpdate.append(timeline.get());
+
+        for (auto& animation : timeline->relevantAnimations()) {
+            if (animation->timeline() != timeline.get()) {
+                ASSERT(!animation->timeline());
+                animationsToRemove.append(animation);
+                continue;
+            }
+
+            // This will notify the animation that timing has changed and will call automatically
+            // schedule invalidation if required for this animation.
+            animation->tick();
+
+            if (!animation->isRelevant() && !animation->needsTick())
+                animationsToRemove.append(animation);
+
+            if (!animation->needsTick() && is<CSSTransition>(animation) && animation->playState() == WebAnimation::PlayState::Finished) {
+                auto* transition = downcast<CSSTransition>(animation.get());
+                if (transition->owningElement())
+                    completedTransitions.append(transition);
+            }
+        }
     }
 
-    for (auto& timeline : timelines) {
-        timeline->updateCurrentTime(timestamp);
-        if (shouldUpdateAnimations)
-            timeline->updateAnimationsAndSendEvents();
+    if (timelinesToUpdate.isEmpty())
+        return;
+
+    // 2. Remove replaced animations for doc.
+    for (auto& timeline : m_timelines)
+        timeline.removeReplacedAnimations();
+
+    // 3. Perform a microtask checkpoint.
+    auto document = makeRefPtr(m_document);
+    document->eventLoop().performMicrotaskCheckpoint();
+
+    // 4. Let events to dispatch be a copy of doc's pending animation event queue.
+    // 5. Clear doc's pending animation event queue.
+    AnimationEvents events;
+    for (auto& timeline : timelinesToUpdate)
+        events.appendVector(timeline->prepareForPendingAnimationEventsDispatch());
+
+    // 6. Perform a stable sort of the animation events in events to dispatch as follows.
+    std::stable_sort(events.begin(), events.end(), [] (const Ref<AnimationEventBase>& lhs, const Ref<AnimationEventBase>& rhs) {
+        // 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
+        // and events whose scheduled event time is unresolved sort before events with a resolved scheduled event time.
+        // 2. Within events with equal scheduled event times, sort by their composite order. FIXME: We don't do this.
+        if (lhs->timelineTime() && !rhs->timelineTime())
+            return false;
+        if (!lhs->timelineTime() && rhs->timelineTime())
+            return true;
+        if (!lhs->timelineTime() && !rhs->timelineTime())
+            return true;
+        return lhs->timelineTime().value() < rhs->timelineTime().value();
+    });
+
+    // 7. Dispatch each of the events in events to dispatch at their corresponding target using the order established in the previous step.
+    for (auto& event : events)
+        event->target()->dispatchEvent(event);
+
+    // This will cancel any scheduled invalidation if we end up removing all animations.
+    for (auto& animation : animationsToRemove) {
+        // An animation that was initially marked as irrelevant may have changed while we were sending events, so we run the same
+        // check that we ran to add it to animationsToRemove in the first place.
+        if (!animation->isRelevant() && !animation->needsTick())
+            animation->timeline()->removeAnimation(*animation);
     }
+
+    // Now that animations that needed removal have been removed, let's update the list of completed transitions.
+    // This needs to happen after dealing with the list of animations to remove as the animation may have been
+    // removed from the list of completed transitions otherwise.
+    for (auto& completedTransition : completedTransitions)
+        downcast<DocumentTimeline>(*completedTransition->timeline()).transitionDidComplete(completedTransition);
+
+    for (auto& timeline : timelinesToUpdate)
+        timeline->documentDidUpdateAnimationsAndSendEvents();
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/animation/DocumentTimelinesController.h (260524 => 260525)


--- trunk/Source/WebCore/animation/DocumentTimelinesController.h	2020-04-22 18:38:36 UTC (rev 260524)
+++ trunk/Source/WebCore/animation/DocumentTimelinesController.h	2020-04-22 18:47:36 UTC (rev 260525)
@@ -30,12 +30,15 @@
 
 namespace WebCore {
 
+class CSSTransition;
+class Document;
 class DocumentTimeline;
+class WebAnimation;
 
 class DocumentTimelinesController {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    explicit DocumentTimelinesController();
+    explicit DocumentTimelinesController(Document&);
     ~DocumentTimelinesController();
 
     void addTimeline(DocumentTimeline&);
@@ -44,8 +47,13 @@
     void updateAnimationsAndSendEvents(DOMHighResTimeStamp);
 
 private:
+    struct AnimationsToProcess {
+        Vector<RefPtr<WebAnimation>> animationsToRemove;
+        Vector<RefPtr<CSSTransition>> completedTransitions;
+    };
+
     WeakHashSet<DocumentTimeline> m_timelines;
+    Document& m_document;
 };
 
 } // namespace WebCore
-

Modified: trunk/Source/WebCore/animation/WebAnimationTypes.h (260524 => 260525)


--- trunk/Source/WebCore/animation/WebAnimationTypes.h	2020-04-22 18:38:36 UTC (rev 260524)
+++ trunk/Source/WebCore/animation/WebAnimationTypes.h	2020-04-22 18:47:36 UTC (rev 260525)
@@ -32,6 +32,7 @@
 
 namespace WebCore {
 
+class AnimationEventBase;
 class AnimationList;
 class CSSAnimation;
 class CSSTransition;
@@ -52,6 +53,7 @@
 using MarkableDouble = Markable<double, WebAnimationsMarkableDoubleTraits>;
 
 using AnimationCollection = ListHashSet<RefPtr<WebAnimation>>;
+using AnimationEvents = Vector<Ref<AnimationEventBase>>;
 using PropertyToTransitionMap = HashMap<CSSPropertyID, RefPtr<CSSTransition>>;
 using CSSAnimationCollection = ListHashSet<RefPtr<CSSAnimation>>;
 

Modified: trunk/Source/WebCore/dom/Document.cpp (260524 => 260525)


--- trunk/Source/WebCore/dom/Document.cpp	2020-04-22 18:38:36 UTC (rev 260524)
+++ trunk/Source/WebCore/dom/Document.cpp	2020-04-22 18:47:36 UTC (rev 260525)
@@ -8080,7 +8080,7 @@
 DocumentTimelinesController& Document::ensureTimelinesController()
 {
     if (!m_timelinesController)
-        m_timelinesController = makeUnique<DocumentTimelinesController>();
+        m_timelinesController = makeUnique<DocumentTimelinesController>(*this);
     return *m_timelinesController.get();
 }
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to