Changeset 256619 in webkit


Ignore:
Timestamp:
Feb 14, 2020 9:52:07 AM (4 years ago)
Author:
graouts@webkit.org
Message:

[Web Animations] Ensure CSS Transition and CSS Animation events are queued, sorted and dispatched by their timeline
https://bugs.webkit.org/show_bug.cgi?id=207364
<rdar://problem/59370413>

Reviewed by Simon Fraser.

LayoutTests/imported/w3c:

There are some progressions but also some "regressions". The progressions are real, showing the delivery of all animation events at the correct
time. However, the regressions are misleading. The fact that the "style change" tests would work was due to a design issue in the test which would
only wait one frame to detect whether a CSS Transition was started after a change made through the Web Animations API. These would work because
events were queued in the next frame, but delivered later due to the dedicated per-animation queue used, which meant the test was fooled into
thinking the CSS Transition did not start, as expected. Changing those test to use more than one frame to test for the lack of a CSS Transition
would have shown the FAIL results.

However, in order to not regress our WPT score, the issue of "style change" events will be addressed in a follow-up patch.

  • web-platform-tests/css/css-transitions/CSSTransition-startTime.tentative-expected.txt:
  • web-platform-tests/web-animations/interfaces/Animatable/animate-expected.txt:
  • web-platform-tests/web-animations/interfaces/Animation/style-change-events-expected.txt:
  • web-platform-tests/web-animations/interfaces/KeyframeEffect/style-change-events-expected.txt:
  • web-platform-tests/web-animations/timing-model/timelines/update-and-send-events-expected.txt:

Source/WebCore:

Until now, AnimationPlaybackEvent events, which are new events introduced by the Web Animations spec, were enqueued in a shared queue on the DocumentTimeline
and dispatched during the "update animations and send events" procedure. However, AnimationEvent and TransitionEvent events, dispatched by CSS Animations
and CSS Transitions, were dispatched via a dedicated per-animation queue, which meant typically that those events were dispathed one runloop after the
AnimationPlaybackEvent events.

We now remove the dedicated per-animation queue and enqueue all events in the shared DocumentTimeline queue for dispatch during the "update animations and send
events" procedure. To do this correctly, we need to do a couple of other things that ensure we don't regress tests.

First, we update the DocumentTimeline::shouldRunUpdateAnimationsAndSendEventsIgnoringSuspensionState() to account for whether there are pending animation events,
guaranteeing that an animation update is scheduled should there be any.

Second, when animation events are enqueued in DocumentTimeline::enqueueAnimationEvent() we schedule an animation update if needed, since we know we now
have pending events that will need to be delivered in an upcoming update. We also maintain a flag between the start of the "update animations and send events"
procedure and the moment when the pending animation events queue is cleared prior to dispatching events so that events enqueued in the meantime do not
prematurely schedule animation resolution. The need for a new animation resolution will be checked at the end of the procedure.

Finally, declarative animations used to have a special suclass of WebAnimation::needsTick() that would check whether they had any pending events, ensuring
they would not be removed prematurely. We now reset a flag to false as WebAnimation::tick() is called (as part of the "update animations and send events"
procedure) and set it to true in case an animation is enqueued. This flag is then used in needsTick() to guarantee the animation is not removed before
the DocumentTimeline has had a chance to dispatch the enqueued event.

Note also that, for clarity, the DocumentTimeline::unscheduleAnimationResolution() was renamed to DocumentTimeline::clearTickScheduleTimer() since it wouldn't
actually cancel a previous animation resolution schedule.

  • animation/CSSTransition.h: Fix a newly found build error due to the missing wtf/MonotonicTime.h header.
  • animation/DeclarativeAnimation.cpp: Remove all code related to the dedicated per-animation queue and instead call the new WebAnimation::enqueueAnimationEvent()

method to enqueue events on the DocumentTimeline.
(WebCore::DeclarativeAnimation::DeclarativeAnimation):
(WebCore::DeclarativeAnimation::tick):
(WebCore::DeclarativeAnimation::enqueueDOMEvent):

  • animation/DeclarativeAnimation.h:
  • animation/DocumentTimeline.cpp:

(WebCore::DocumentTimeline::detachFromDocument): Ensure the pending events queue is cleared when the timeline is detached from a document, ensuring that there no
longer events that would cause a ref-cycle (DocumentTimeline -> AnimationPlaybackEvent -> WebAnimation -> DocumentTimeline).
(WebCore::DocumentTimeline::suspendAnimations):
(WebCore::DocumentTimeline::removeAnimation):
(WebCore::DocumentTimeline::scheduleAnimationResolution):
(WebCore::DocumentTimeline::clearTickScheduleTimer):
(WebCore::DocumentTimeline::shouldRunUpdateAnimationsAndSendEventsIgnoringSuspensionState const):
(WebCore::DocumentTimeline::updateCurrentTime):
(WebCore::DocumentTimeline::updateAnimationsAndSendEvents):
(WebCore::DocumentTimeline::internalUpdateAnimationsAndSendEvents):
(WebCore::DocumentTimeline::scheduleNextTick):
(WebCore::DocumentTimeline::animationAcceleratedRunningStateDidChange):
(WebCore::DocumentTimeline::enqueueAnimationEvent):

  • animation/DocumentTimeline.h:
  • animation/WebAnimation.cpp:

(WebCore::WebAnimation::enqueueAnimationPlaybackEvent):
(WebCore::WebAnimation::enqueueAnimationEvent):
(WebCore::WebAnimation::needsTick const):
(WebCore::WebAnimation::tick):

  • animation/WebAnimation.h:

LayoutTests:

Fix a couple of tests that made some incorrect assumptions.

  • TestExpectations: imported/w3c/web-platform-tests/web-animations/timing-model/timelines/update-and-send-events.html is no longer flaky.
  • compositing/backing/animate-into-view.html: Because the "animationstart" event is now dispatched during the "update animations and send events" procedure, which happens

during page rendering _before_ rAF callbacks are serviced, we must remove the rAF callback used prior to adding the "animationstart" event listener or else we would never
get it and the test would time out.

  • webanimations/css-transition-in-flight-reversal-accelerated.html: We must wait for the initial transition to start and then two frames before reversing the transition,

to be certain that the animation did start. Indeed, the "transitionstart" event will be fired right before the next rAF callback is called, as the animation starts in that
very same frame, and so progress will be 0 and the transition wouldn't be reversable until the next frame when the animation has progress > 0.

Location:
trunk
Files:
18 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r256618 r256619  
     12020-02-14  Antoine Quint  <graouts@webkit.org>
     2
     3        [Web Animations] Ensure CSS Transition and CSS Animation events are queued, sorted and dispatched by their timeline
     4        https://bugs.webkit.org/show_bug.cgi?id=207364
     5        <rdar://problem/59370413>
     6
     7        Reviewed by Simon Fraser.
     8
     9        Fix a couple of tests that made some incorrect assumptions.
     10
     11        * TestExpectations: imported/w3c/web-platform-tests/web-animations/timing-model/timelines/update-and-send-events.html is no longer flaky.
     12        * compositing/backing/animate-into-view.html: Because the "animationstart" event is now dispatched during the "update animations and send events" procedure, which happens
     13        during page rendering _before_ rAF callbacks are serviced, we must remove the rAF callback used prior to adding the "animationstart" event listener or else we would never
     14        get it and the test would time out.
     15        * webanimations/css-transition-in-flight-reversal-accelerated.html: We must wait for the initial transition to start and then two frames before reversing the transition,
     16        to be certain that the animation did start. Indeed, the "transitionstart" event will be fired right before the next rAF callback is called, as the animation starts in that
     17        very same frame, and so progress will be 0 and the transition wouldn't be reversable until the next frame when the animation has progress > 0.
     18
    1192020-02-14  Jacob Uphoff  <jacob_uphoff@apple.com>
    220
  • trunk/LayoutTests/TestExpectations

    r256501 r256619  
    26572657webkit.org/b/202107 imported/w3c/web-platform-tests/web-animations/interfaces/Animation/style-change-events.html [ Pass Failure ]
    26582658webkit.org/b/202108 imported/w3c/web-platform-tests/web-animations/interfaces/DocumentTimeline/style-change-events.html [ Pass Failure ]
    2659 webkit.org/b/202109 imported/w3c/web-platform-tests/web-animations/timing-model/timelines/update-and-send-events.html [ Pass Failure ]
    26602659
    26612660webkit.org/b/157068 [ Debug ] imported/w3c/web-platform-tests/fetch/nosniff/importscripts.html [ Pass Crash ]
  • trunk/LayoutTests/compositing/backing/animate-into-view.html

    r239268 r256619  
    6161
    6262        window.addEventListener('load', () => {
    63             requestAnimationFrame(() => {
    64                 let animator = document.getElementById('target');
    65                 animator.addEventListener('animationstart', () => {
    66                     requestAnimationFrame(() => {
    67                         dumpLayers();
    68                         if (window.testRunner)
    69                             testRunner.notifyDone();
    70                     });
     63            let animator = document.getElementById('target');
     64            animator.addEventListener('animationstart', () => {
     65                requestAnimationFrame(() => {
     66                    dumpLayers();
     67                    if (window.testRunner)
     68                        testRunner.notifyDone();
    7169                });
    72                 animator.classList.add('animating');
    7370            });
     71            animator.classList.add('animating');
    7472        }, false);
    7573    </script>
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r256445 r256619  
     12020-02-14  Antoine Quint  <graouts@webkit.org>
     2
     3        [Web Animations] Ensure CSS Transition and CSS Animation events are queued, sorted and dispatched by their timeline
     4        https://bugs.webkit.org/show_bug.cgi?id=207364
     5        <rdar://problem/59370413>
     6
     7        Reviewed by Simon Fraser.
     8
     9        There are some progressions but also some "regressions". The progressions are real, showing the delivery of all animation events at the correct
     10        time. However, the regressions are misleading. The fact that the "style change" tests would work was due to a design issue in the test which would
     11        only wait one frame to detect whether a CSS Transition was started after a change made through the Web Animations API. These would work because
     12        events were queued in the next frame, but delivered later due to the dedicated per-animation queue used, which meant the test was fooled into
     13        thinking the CSS Transition did not start, as expected. Changing those test to use more than one frame to test for the lack of a CSS Transition
     14        would have shown the FAIL results.
     15
     16        However, in order to not regress our WPT score, the issue of "style change" events will be addressed in a follow-up patch.
     17
     18        * web-platform-tests/css/css-transitions/CSSTransition-startTime.tentative-expected.txt:
     19        * web-platform-tests/web-animations/interfaces/Animatable/animate-expected.txt:
     20        * web-platform-tests/web-animations/interfaces/Animation/style-change-events-expected.txt:
     21        * web-platform-tests/web-animations/interfaces/KeyframeEffect/style-change-events-expected.txt:
     22        * web-platform-tests/web-animations/timing-model/timelines/update-and-send-events-expected.txt:
     23
    1242020-02-12  Rossana Monteriso  <rmonteriso@igalia.com>
    225
  • trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-transitions/CSSTransition-startTime.tentative-expected.txt

    r251591 r256619  
    44PASS The start time of a transition can be set
    55PASS The start time can be set to seek a transition
    6 FAIL Seeking a transition using start time dispatches transition events promise_test: Unhandled rejection with value: object "Error: Timed out waiting for Promise to resolve: transitionstart"
     6PASS Seeking a transition using start time dispatches transition events
    77
  • trunk/LayoutTests/imported/w3c/web-platform-tests/web-animations/interfaces/Animatable/animate-expected.txt

    r255821 r256619  
    133133PASS Element.animate() correctly sets the Animation's timeline when triggered on an element in a different document
    134134PASS Element.animate() calls play on the Animation
    135 PASS Element.animate() does NOT trigger a style change event
     135FAIL Element.animate() does NOT trigger a style change event assert_false: A transition should NOT have been triggered expected false got true
    136136PASS animate() with pseudoElement parameter creates an Animation object
    137137PASS animate() with pseudoElement parameter without content creates an Animation object
  • trunk/LayoutTests/imported/w3c/web-platform-tests/web-animations/interfaces/Animation/style-change-events-expected.txt

    r252969 r256619  
    2121FAIL Animation.updatePlaybackRate produces expected style change events assert_false: A transition should NOT have been triggered expected false got true
    2222FAIL Animation.reverse produces expected style change events assert_false: A transition should NOT have been triggered expected false got true
    23 PASS Animation.persist produces expected style change events
     23FAIL Animation.persist produces expected style change events assert_false: A transition should NOT have been triggered expected false got true
    2424FAIL Animation.commitStyles produces expected style change events assert_true: A transition should have been triggered expected true got false
    2525FAIL Animation.Animation constructor produces expected style change events assert_false: A transition should NOT have been triggered expected false got true
  • trunk/LayoutTests/imported/w3c/web-platform-tests/web-animations/interfaces/KeyframeEffect/style-change-events-expected.txt

    r255821 r256619  
    11
    22FAIL All property keys are recognized assert_in_array: Test property 'pseudoElement' should be one of the properties on  KeyframeEffect value "pseudoElement" not in array ["getTiming", "getComputedTiming", "updateTiming", "target", "iterationComposite", "composite", "getKeyframes", "setKeyframes", "KeyframeEffect constructor", "KeyframeEffect copy constructor"]
    3 PASS KeyframeEffect.getTiming does NOT trigger a style change event
    4 PASS KeyframeEffect.getComputedTiming does NOT trigger a style change event
    5 PASS KeyframeEffect.updateTiming does NOT trigger a style change event
    6 PASS KeyframeEffect.target does NOT trigger a style change event
    7 PASS KeyframeEffect.iterationComposite does NOT trigger a style change event
    8 PASS KeyframeEffect.composite does NOT trigger a style change event
    9 PASS KeyframeEffect.getKeyframes does NOT trigger a style change event
    10 PASS KeyframeEffect.setKeyframes does NOT trigger a style change event
    11 PASS KeyframeEffect.KeyframeEffect constructor does NOT trigger a style change event
    12 PASS KeyframeEffect.KeyframeEffect copy constructor does NOT trigger a style change event
     3FAIL KeyframeEffect.getTiming does NOT trigger a style change event assert_false: A transition should NOT have been triggered expected false got true
     4FAIL KeyframeEffect.getComputedTiming does NOT trigger a style change event assert_false: A transition should NOT have been triggered expected false got true
     5FAIL KeyframeEffect.updateTiming does NOT trigger a style change event assert_false: A transition should NOT have been triggered expected false got true
     6FAIL KeyframeEffect.target does NOT trigger a style change event assert_false: A transition should NOT have been triggered expected false got true
     7FAIL KeyframeEffect.iterationComposite does NOT trigger a style change event assert_false: A transition should NOT have been triggered expected false got true
     8FAIL KeyframeEffect.composite does NOT trigger a style change event assert_false: A transition should NOT have been triggered expected false got true
     9FAIL KeyframeEffect.getKeyframes does NOT trigger a style change event assert_false: A transition should NOT have been triggered expected false got true
     10FAIL KeyframeEffect.setKeyframes does NOT trigger a style change event assert_false: A transition should NOT have been triggered expected false got true
     11FAIL KeyframeEffect.KeyframeEffect constructor does NOT trigger a style change event assert_false: A transition should NOT have been triggered expected false got true
     12FAIL KeyframeEffect.KeyframeEffect copy constructor does NOT trigger a style change event assert_false: A transition should NOT have been triggered expected false got true
    1313
  • trunk/LayoutTests/imported/w3c/web-platform-tests/web-animations/timing-model/timelines/update-and-send-events-expected.txt

    r250263 r256619  
    33PASS Fires finish event before requestAnimationFrame
    44FAIL Sorts finish events by composite order assert_array_equals: finish events for various animation type should be sorted by composite order property 0, expected "CSSTransition:finish" but got "ScriptAnimation:finish"
    5 FAIL Sorts cancel events by composite order assert_array_equals: cancel events should be sorted by composite order lengths differ, expected 5 got 3
    6 FAIL Queues a cancel event in transitionstart event callback assert_approx_equals: A rAF callback should happen in the same frame expected 112 +/- 0.001 but got 96
    7 FAIL Sorts events for the same transition assert_array_equals: Playback and CSS events for the same transition should be sorted by schedule event time and composite order lengths differ, expected 2 got 1
     5FAIL Sorts cancel events by composite order assert_array_equals: cancel events should be sorted by composite order property 0, expected "CSSTransition:cancel" but got "ScriptAnimation:cancel"
     6PASS Queues a cancel event in transitionstart event callback
     7PASS Sorts events for the same transition
    88PASS Playback events with the same timeline retain the order in which they arequeued
    99FAIL All timelines are updated before running microtasks promise_test: Unhandled rejection with value: object "AbortError: The operation was aborted."
  • trunk/LayoutTests/webanimations/css-transition-in-flight-reversal-accelerated.html

    r252527 r256619  
    4747            assert_true(initialTransition instanceof CSSTransition, "There is one animation applied to the target after starting the initial transition.");
    4848
    49             // Wait for the initial transition to start and then another frame before reversing the transition.
     49            // Wait for the initial transition to start and then two frames before reversing the transition, to be certain that the animation did start.
     50            // Indeed, the "transitionstart" event will be fired right before the next rAF callback is called, as the animation starts in that very same
     51            // frame, and so progress will be 0 and the transition wouldn't be reversable until the next frame when the animation has progress > 0.
    5052            target.addEventListener("transitionstart", event => {
    5153                requestAnimationFrame(() => {
    52                     target.classList.remove("in-flight");
    53                     const animations = target.getAnimations();
    54                     assert_equals(animations.length, 1, "There is one animation applied to the target after reversing the initial transition.");
     54                    requestAnimationFrame(() => {
     55                        target.classList.remove("in-flight");
     56                        const animations = target.getAnimations();
     57                        assert_equals(animations.length, 1, "There is one animation applied to the target after reversing the initial transition.");
    5558
    56                     reversedTransition = animations[0];
    57                     assert_true(reversedTransition instanceof CSSTransition, "There is one animation applied to the target after reversing the initial transition.");
    58                     assert_not_equals(initialTransition, reversedTransition, "The animation applied to the target after reversing the initial transition is different than the original transition.");
     59                        reversedTransition = animations[0];
     60                        assert_true(reversedTransition instanceof CSSTransition, "There is one animation applied to the target after reversing the initial transition.");
     61                        assert_not_equals(initialTransition, reversedTransition, "The animation applied to the target after reversing the initial transition is different than the original transition.");
    5962
    60                     target.remove();
    61                     test.done();
     63                        target.remove();
     64                        test.done();
     65                    });
    6266                });
    6367            });
  • trunk/Source/WebCore/ChangeLog

    r256610 r256619  
     12020-02-14  Antoine Quint  <graouts@webkit.org>
     2
     3        [Web Animations] Ensure CSS Transition and CSS Animation events are queued, sorted and dispatched by their timeline
     4        https://bugs.webkit.org/show_bug.cgi?id=207364
     5        <rdar://problem/59370413>
     6
     7        Reviewed by Simon Fraser.
     8
     9        Until now, AnimationPlaybackEvent events, which are new events introduced by the Web Animations spec, were enqueued in a shared queue on the DocumentTimeline
     10        and dispatched during the "update animations and send events" procedure. However, AnimationEvent and TransitionEvent events, dispatched by CSS Animations
     11        and CSS Transitions, were dispatched via a dedicated per-animation queue, which meant typically that those events were dispathed one runloop after the
     12        AnimationPlaybackEvent events.
     13
     14        We now remove the dedicated per-animation queue and enqueue all events in the shared DocumentTimeline queue for dispatch during the "update animations and send
     15        events" procedure. To do this correctly, we need to do a couple of other things that ensure we don't regress tests.
     16
     17        First, we update the DocumentTimeline::shouldRunUpdateAnimationsAndSendEventsIgnoringSuspensionState() to account for whether there are pending animation events,
     18        guaranteeing that an animation update is scheduled should there be any.
     19
     20        Second, when animation events are enqueued in DocumentTimeline::enqueueAnimationEvent() we schedule an animation update if needed, since we know we now
     21        have pending events that will need to be delivered in an upcoming update. We also maintain a flag between the start of the "update animations and send events"
     22        procedure and the moment when the pending animation events queue is cleared prior to dispatching events so that events enqueued in the meantime do not
     23        prematurely schedule animation resolution. The need for a new animation resolution will be checked at the end of the procedure.
     24
     25        Finally, declarative animations used to have a special suclass of WebAnimation::needsTick() that would check whether they had any pending events, ensuring
     26        they would not be removed prematurely. We now reset a flag to false as WebAnimation::tick() is called (as part of the "update animations and send events"
     27        procedure) and set it to true in case an animation is enqueued. This flag is then used in needsTick() to guarantee the animation is not removed before
     28        the DocumentTimeline has had a chance to dispatch the enqueued event.
     29
     30        Note also that, for clarity, the DocumentTimeline::unscheduleAnimationResolution() was renamed to DocumentTimeline::clearTickScheduleTimer() since it wouldn't
     31        actually cancel a previous animation resolution schedule.
     32
     33        * animation/CSSTransition.h: Fix a newly found build error due to the missing wtf/MonotonicTime.h header.
     34        * animation/DeclarativeAnimation.cpp: Remove all code related to the dedicated per-animation queue and instead call the new WebAnimation::enqueueAnimationEvent()
     35        method to enqueue events on the DocumentTimeline.
     36        (WebCore::DeclarativeAnimation::DeclarativeAnimation):
     37        (WebCore::DeclarativeAnimation::tick):
     38        (WebCore::DeclarativeAnimation::enqueueDOMEvent):
     39        * animation/DeclarativeAnimation.h:
     40        * animation/DocumentTimeline.cpp:
     41        (WebCore::DocumentTimeline::detachFromDocument): Ensure the pending events queue is cleared when the timeline is detached from a document, ensuring that there no
     42        longer events that would cause a ref-cycle (DocumentTimeline -> AnimationPlaybackEvent -> WebAnimation -> DocumentTimeline).
     43        (WebCore::DocumentTimeline::suspendAnimations):
     44        (WebCore::DocumentTimeline::removeAnimation):
     45        (WebCore::DocumentTimeline::scheduleAnimationResolution):
     46        (WebCore::DocumentTimeline::clearTickScheduleTimer):
     47        (WebCore::DocumentTimeline::shouldRunUpdateAnimationsAndSendEventsIgnoringSuspensionState const):
     48        (WebCore::DocumentTimeline::updateCurrentTime):
     49        (WebCore::DocumentTimeline::updateAnimationsAndSendEvents):
     50        (WebCore::DocumentTimeline::internalUpdateAnimationsAndSendEvents):
     51        (WebCore::DocumentTimeline::scheduleNextTick):
     52        (WebCore::DocumentTimeline::animationAcceleratedRunningStateDidChange):
     53        (WebCore::DocumentTimeline::enqueueAnimationEvent):
     54        * animation/DocumentTimeline.h:
     55        * animation/WebAnimation.cpp:
     56        (WebCore::WebAnimation::enqueueAnimationPlaybackEvent):
     57        (WebCore::WebAnimation::enqueueAnimationEvent):
     58        (WebCore::WebAnimation::needsTick const):
     59        (WebCore::WebAnimation::tick):
     60        * animation/WebAnimation.h:
     61
     622020-02-14  Antoine Quint  <graouts@webkit.org>
     63
     64        [Web Animations] Make all animation event types inherit from the same base class
     65        https://bugs.webkit.org/show_bug.cgi?id=207629
     66
     67        Reviewed by Simon Fraser.
     68
     69        Currently we dispatch events CSS Transitions and CSS Animations events using a dedicated event queue on DeclarativeAnimation, while the events
     70        added by the Web Animations specification (of type AnimationPlaybackEvent) are dispatched using a shared queue on the DocumentTimeline that is
     71        processed during the "update animations and send events procedure". The Web Animations specification dictates that all events should be dispatched
     72        during that procedure, which includes sorting of such events based on their timeline time and associated animation relative composite order.
     73
     74        In this patch, we prepare the work towards spec compliance for animation events dispatch by making all event types (AnimationPlaybackEvent,
     75        TransitionEvent and AnimationEvent) inherit from a single AnimationEventBase interface. This will allow DocumentTimeline to enqueue, sort and
     76        dispatch all such events with a single queue in a future patch.
     77
     78        Due to CSSAnimationController, we must make the "timeline time" and "animation" parameters optional. When we drop support for CSSAnimationController
     79        we'll be able to enforce stronger requirements for these.
     80
     81        No new test since this should not introduce any behavior change.
     82
     83        * Sources.txt:
     84        * WebCore.xcodeproj/project.pbxproj:
     85        * animation/AnimationEventBase.cpp: Added.
     86        (WebCore::AnimationEventBase::AnimationEventBase):
     87        * animation/AnimationEventBase.h: Added.
     88        (WebCore::AnimationEventBase::create):
     89        (WebCore::AnimationEventBase::isAnimationPlaybackEvent const):
     90        (WebCore::AnimationEventBase::isAnimationEvent const):
     91        (WebCore::AnimationEventBase::isTransitionEvent const):
     92        (WebCore::AnimationEventBase::timelineTime const):
     93        (WebCore::AnimationEventBase::animation const):
     94        * animation/AnimationPlaybackEvent.cpp:
     95        (WebCore::AnimationPlaybackEvent::AnimationPlaybackEvent):
     96        (WebCore::AnimationPlaybackEvent::bindingsTimelineTime const):
     97        * animation/AnimationPlaybackEvent.h:
     98        * animation/CSSAnimation.cpp:
     99        (WebCore::CSSAnimation::createEvent):
     100        * animation/CSSAnimation.h:
     101        * animation/CSSTransition.cpp:
     102        (WebCore::CSSTransition::createEvent):
     103        * animation/CSSTransition.h:
     104        * animation/DeclarativeAnimation.cpp:
     105        (WebCore::DeclarativeAnimation::enqueueDOMEvent):
     106        * animation/DeclarativeAnimation.h:
     107        * animation/WebAnimation.cpp:
     108        (WebCore::WebAnimation::enqueueAnimationPlaybackEvent):
     109        * dom/AnimationEvent.cpp:
     110        (WebCore::AnimationEvent::AnimationEvent):
     111        * dom/AnimationEvent.h:
     112        * dom/TransitionEvent.cpp:
     113        (WebCore::TransitionEvent::TransitionEvent):
     114        * dom/TransitionEvent.h:
     115        * page/animation/CSSAnimationController.cpp:
     116        (WebCore::CSSAnimationControllerPrivate::fireEventsAndUpdateStyle):
     117
    11182020-02-14  Antoine Quint  <graouts@webkit.org>
    2119
  • trunk/Source/WebCore/animation/CSSTransition.h

    r256610 r256619  
    2828#include "CSSPropertyNames.h"
    2929#include "DeclarativeAnimation.h"
     30#include <wtf/MonotonicTime.h>
    3031#include <wtf/Ref.h>
    3132
  • trunk/Source/WebCore/animation/DeclarativeAnimation.cpp

    r256610 r256619  
    4343DeclarativeAnimation::DeclarativeAnimation(Element& owningElement, const Animation& backingAnimation)
    4444    : WebAnimation(owningElement.document())
    45     , m_eventQueue(MainThreadGenericEventQueue::create(owningElement))
    4645    , m_owningElement(&owningElement)
    4746    , m_backingAnimation(const_cast<Animation&>(backingAnimation))
     
    6463    // From this point on, this animation is like any other animation and should not appear in the
    6564    // maps containing running CSS Transitions and CSS Animations for a given element.
    66     if (wasRelevant && playState() == WebAnimation::PlayState::Idle) {
     65    if (wasRelevant && playState() == WebAnimation::PlayState::Idle)
    6766        disassociateFromOwningElement();
    68         m_eventQueue->close();
    69     }
    7067}
    7168
     
    8986        animationTimeline->removeDeclarativeAnimationFromListsForOwningElement(*this, *m_owningElement);
    9087    m_owningElement = nullptr;
    91 }
    92 
    93 bool DeclarativeAnimation::needsTick() const
    94 {
    95     return WebAnimation::needsTick() || m_eventQueue->hasPendingEvents();
    96 }
    97 
    98 void DeclarativeAnimation::remove()
    99 {
    100     m_eventQueue->close();
    101     WebAnimation::remove();
    10288}
    10389
     
    352338    const auto& pseudoId = PseudoElement::pseudoElementNameForEvents(m_owningElement->pseudoId());
    353339    auto timelineTime = timeline() ? timeline()->currentTime() : WTF::nullopt;
    354     m_eventQueue->enqueueEvent(createEvent(eventType, time, pseudoId, timelineTime));
     340    auto event = createEvent(eventType, time, pseudoId, timelineTime);
     341    event->setTarget(m_owningElement);
     342    enqueueAnimationEvent(WTFMove(event));
    355343}
    356344
  • trunk/Source/WebCore/animation/DeclarativeAnimation.h

    r256610 r256619  
    2828#include "AnimationEffect.h"
    2929#include "AnimationEffectPhase.h"
    30 #include "GenericEventQueue.h"
    3130#include "WebAnimation.h"
    3231#include <wtf/Ref.h>
     
    6665    void cancel() final;
    6766
    68     bool needsTick() const override;
    6967    void tick() override;
    7068
     
    8684    AnimationEffectPhase phaseWithoutEffect() const;
    8785    void enqueueDOMEvent(const AtomString&, Seconds);
    88     void remove() final;
    8986
    9087    bool m_wasPending { false };
    9188    AnimationEffectPhase m_previousPhase { AnimationEffectPhase::Idle };
    92 
    93     UniqueRef<MainThreadGenericEventQueue> m_eventQueue;
    9489
    9590    Element* m_owningElement;
  • trunk/Source/WebCore/animation/DocumentTimeline.cpp

    r256512 r256619  
    2727#include "DocumentTimeline.h"
    2828
    29 #include "AnimationPlaybackEvent.h"
     29#include "AnimationEventBase.h"
    3030#include "CSSAnimation.h"
    3131#include "CSSTransition.h"
     
    8989        m_document->removeTimeline(*this);
    9090
     91    m_pendingAnimationEvents.clear();
    9192    m_currentTimeClearingTaskQueue.close();
    9293    m_elementsWithRunningAcceleratedAnimations.clear();
     
    9697        animationsToRemove.first()->remove();
    9798
    98     unscheduleAnimationResolution();
     99    clearTickScheduleTimer();
    99100    m_document = nullptr;
    100101}
     
    235236    applyPendingAcceleratedAnimations();
    236237
    237     unscheduleAnimationResolution();
     238    clearTickScheduleTimer();
    238239}
    239240
     
    328329    AnimationTimeline::removeAnimation(animation);
    329330
     331    if (m_animations.isEmpty())
     332        clearTickScheduleTimer();
     333}
     334
     335void DocumentTimeline::scheduleAnimationResolution()
     336{
     337    if (m_isSuspended || m_animationResolutionScheduled || !m_document || !m_document->page())
     338        return;
     339
     340    // We need some relevant animations or pending events to proceed.
    330341    if (!shouldRunUpdateAnimationsAndSendEventsIgnoringSuspensionState())
    331         unscheduleAnimationResolution();
    332 }
    333 
    334 void DocumentTimeline::scheduleAnimationResolution()
    335 {
    336     if (m_isSuspended || m_animationResolutionScheduled || !shouldRunUpdateAnimationsAndSendEventsIgnoringSuspensionState())
    337342        return;
    338343
    339     if (!m_document || !m_document->page())
    340         return;
    341    
    342344    m_document->page()->renderingUpdateScheduler().scheduleTimedRenderingUpdate();
    343345    m_animationResolutionScheduled = true;
    344346}
    345347
    346 void DocumentTimeline::unscheduleAnimationResolution()
     348void DocumentTimeline::clearTickScheduleTimer()
    347349{
    348350    m_tickScheduleTimer.stop();
    349     m_animationResolutionScheduled = false;
    350351}
    351352
    352353bool DocumentTimeline::shouldRunUpdateAnimationsAndSendEventsIgnoringSuspensionState() const
    353354{
    354     return !m_animations.isEmpty() || !m_acceleratedAnimationsPendingRunningStateChange.isEmpty();
     355    return !m_animations.isEmpty() || !m_pendingAnimationEvents.isEmpty() || !m_acceleratedAnimationsPendingRunningStateChange.isEmpty();
    355356}
    356357
     
    360361    // document.timeline.currentTime may be called from a rAF callback and
    361362    // it has to match the rAF timestamp.
    362     if (!m_isSuspended)
     363    if (!m_isSuspended || !shouldRunUpdateAnimationsAndSendEventsIgnoringSuspensionState())
    363364        cacheCurrentTime(timestamp);
    364365}
     
    366367void DocumentTimeline::updateAnimationsAndSendEvents()
    367368{
    368     if (m_isSuspended || !shouldRunUpdateAnimationsAndSendEventsIgnoringSuspensionState())
    369         return;
    370369
    371370    // Updating animations and sending events may invalidate the timing of some animations, so we must set the m_animationResolutionScheduled
     
    373372    m_animationResolutionScheduled = false;
    374373
     374    if (m_isSuspended)
     375        return;
     376
     377    if (!shouldRunUpdateAnimationsAndSendEventsIgnoringSuspensionState())
     378        return;
     379
    375380    internalUpdateAnimationsAndSendEvents();
    376381    applyPendingAcceleratedAnimations();
     
    383388{
    384389    m_numberOfAnimationTimelineInvalidationsForTesting++;
     390
     391    // enqueueAnimationEvent() calls scheduleAnimationResolution() to ensure that the "update animations and send events"
     392    // procedure is run and enqueued events are dispatched in the next frame. However, events that are enqueued while
     393    // this procedure is running should not schedule animation resolution until the event queue has been cleared.
     394    m_shouldScheduleAnimationResolutionForNewPendingEvents = false;
    385395
    386396    // https://drafts.csswg.org/web-animations/#update-animations-and-send-events
     
    422432    // 5. Clear doc's pending animation event queue.
    423433    auto pendingAnimationEvents = WTFMove(m_pendingAnimationEvents);
     434    m_shouldScheduleAnimationResolutionForNewPendingEvents = true;
    424435
    425436    // 6. Perform a stable sort of the animation events in events to dispatch as follows.
    426     std::stable_sort(pendingAnimationEvents.begin(), pendingAnimationEvents.end(), [] (const Ref<AnimationPlaybackEvent>& lhs, const Ref<AnimationPlaybackEvent>& rhs) {
     437    std::stable_sort(pendingAnimationEvents.begin(), pendingAnimationEvents.end(), [] (const Ref<AnimationEventBase>& lhs, const Ref<AnimationEventBase>& rhs) {
    427438        // 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
    428439        // and events whose scheduled event time is unresolved sort before events with a resolved scheduled event time.
     
    438449
    439450    // 7. Dispatch each of the events in events to dispatch at their corresponding target using the order established in the previous step.
    440     for (auto& pendingEvent : pendingAnimationEvents)
    441         pendingEvent->target()->dispatchEvent(pendingEvent);
     451    for (auto& pendingAnimationEvent : pendingAnimationEvents)
     452        pendingAnimationEvent->target()->dispatchEvent(pendingAnimationEvent);
    442453
    443454    // This will cancel any scheduled invalidation if we end up removing all animations.
     
    548559void DocumentTimeline::scheduleNextTick()
    549560{
     561    // If we have pending animation events, we need to schedule an update right away.
     562    if (!m_pendingAnimationEvents.isEmpty())
     563        scheduleAnimationResolution();
     564
    550565    // There is no tick to schedule if we don't have any relevant animations.
    551566    if (m_animations.isEmpty())
     
    666681        scheduleAnimationResolution();
    667682    else
    668         unscheduleAnimationResolution();
     683        clearTickScheduleTimer();
    669684}
    670685
     
    709724}
    710725
    711 void DocumentTimeline::enqueueAnimationPlaybackEvent(AnimationPlaybackEvent& event)
     726void DocumentTimeline::enqueueAnimationEvent(AnimationEventBase& event)
    712727{
    713728    m_pendingAnimationEvents.append(event);
     729    if (m_shouldScheduleAnimationResolutionForNewPendingEvents)
     730        scheduleAnimationResolution();
    714731}
    715732
  • trunk/Source/WebCore/animation/DocumentTimeline.h

    r256512 r256619  
    3636namespace WebCore {
    3737
    38 class AnimationPlaybackEvent;
     38class AnimationEventBase;
    3939class RenderElement;
    4040
     
    7171    void detachFromDocument();
    7272
    73     void enqueueAnimationPlaybackEvent(AnimationPlaybackEvent&);
     73    void enqueueAnimationEvent(AnimationEventBase&);
    7474   
    7575    bool scheduledUpdate() const { return m_animationResolutionScheduled; }
     
    9393    void maybeClearCachedCurrentTime();
    9494    void scheduleInvalidationTaskIfNeeded();
    95     void performInvalidationTask();
    9695    void scheduleAnimationResolution();
    97     void unscheduleAnimationResolution();
     96    void clearTickScheduleTimer();
    9897    void internalUpdateAnimationsAndSendEvents();
    99     void performEventDispatchTask();
    10098    void updateListOfElementsWithRunningAcceleratedAnimationsForElement(Element&);
    10199    void transitionDidComplete(RefPtr<CSSTransition>);
     
    109107    HashSet<RefPtr<WebAnimation>> m_acceleratedAnimationsPendingRunningStateChange;
    110108    HashSet<Element*> m_elementsWithRunningAcceleratedAnimations;
    111     Vector<Ref<AnimationPlaybackEvent>> m_pendingAnimationEvents;
     109    Vector<Ref<AnimationEventBase>> m_pendingAnimationEvents;
    112110    RefPtr<Document> m_document;
    113111    Markable<Seconds, Seconds::MarkableTraits> m_cachedCurrentTime;
     
    117115    bool m_waitingOnVMIdle { false };
    118116    bool m_animationResolutionScheduled { false };
     117    bool m_shouldScheduleAnimationResolutionForNewPendingEvents { true };
    119118};
    120119
  • trunk/Source/WebCore/animation/WebAnimation.cpp

    r256610 r256619  
    686686    auto event = AnimationPlaybackEvent::create(type, currentTime, timelineTime, this);
    687687    event->setTarget(this);
    688 
     688    enqueueAnimationEvent(WTFMove(event));
     689}
     690
     691void WebAnimation::enqueueAnimationEvent(Ref<AnimationEventBase>&& event)
     692{
    689693    if (is<DocumentTimeline>(m_timeline)) {
    690694        // If animation has a document for timing, then append event to its document for timing's pending animation event queue along
     
    692696        // to origin-relative time, let the scheduled event time be the result of applying that procedure to timeline time. Otherwise, the
    693697        // scheduled event time is an unresolved time value.
    694         downcast<DocumentTimeline>(*m_timeline).enqueueAnimationPlaybackEvent(WTFMove(event));
     698        m_hasScheduledEventsDuringTick = true;
     699        downcast<DocumentTimeline>(*m_timeline).enqueueAnimationEvent(WTFMove(event));
    695700    } else {
    696701        // Otherwise, queue a task to dispatch event at animation. The task source for this task is the DOM manipulation task source.
     
    11991204bool WebAnimation::needsTick() const
    12001205{
    1201     return pending() || playState() == PlayState::Running;
     1206    return pending() || playState() == PlayState::Running || m_hasScheduledEventsDuringTick;
    12021207}
    12031208
    12041209void WebAnimation::tick()
    12051210{
     1211    m_hasScheduledEventsDuringTick = false;
    12061212    updateFinishedState(DidSeek::No, SynchronouslyNotify::Yes);
    12071213    m_shouldSkipUpdatingFinishedStateWhenResolving = true;
  • trunk/Source/WebCore/animation/WebAnimation.h

    r255663 r256619  
    4343
    4444class AnimationEffect;
    45 class AnimationPlaybackEvent;
     45class AnimationEventBase;
    4646class AnimationTimeline;
    4747class Document;
     
    117117    virtual ExceptionOr<void> bindingsPause() { return pause(); }
    118118
    119     virtual bool needsTick() const;
     119    bool needsTick() const;
    120120    virtual void tick();
    121121    Seconds timeToNextTick() const;
     
    136136    bool isSuspended() const { return m_isSuspended; }
    137137    bool isReplaceable() const;
    138     virtual void remove();
     138    void remove();
    139139    void enqueueAnimationPlaybackEvent(const AtomString&, Optional<Seconds>, Optional<Seconds>);
    140140
     
    155155protected:
    156156    explicit WebAnimation(Document&);
     157
     158    void enqueueAnimationEvent(Ref<AnimationEventBase>&&);
    157159
    158160private:
     
    202204    bool m_isRelevant;
    203205    bool m_shouldSkipUpdatingFinishedStateWhenResolving;
     206    bool m_hasScheduledEventsDuringTick { false };
    204207    TimeToRunPendingTask m_timeToRunPendingPlayTask { TimeToRunPendingTask::NotScheduled };
    205208    TimeToRunPendingTask m_timeToRunPendingPauseTask { TimeToRunPendingTask::NotScheduled };
Note: See TracChangeset for help on using the changeset viewer.