Title: [225790] trunk
Revision
225790
Author
grao...@webkit.org
Date
2017-12-12 11:01:18 -0800 (Tue, 12 Dec 2017)

Log Message

[Web Animations] Enqueue and dispatch animation events
https://bugs.webkit.org/show_bug.cgi?id=180657
<rdar://problem/35970103>

Reviewed by Chris Dumez.

Source/WebCore:

Now that we have support for the AnimationPlaybackEvent interface, we need a way to enqueue
such events for dispatch at the opportune time. The Web Animations spec defines two ways
to queue and dispatch events.

If the animation has a "document for timing", it should enqueue events on this document.
In our implementation, if the animation timeline is set to a DocumentTimeline, that means
it has a document for timing, and we let the DocumentTimeline enqueue those events, which
will be dispatched through a dedicated GenericTaskQueue<Timer>. These events will be sorted
by their respective timeline time before being dispatched.

If there is no document for timing, events should be dispatched as a standalone task.

* animation/DocumentTimeline.cpp:
(WebCore::DocumentTimeline::~DocumentTimeline): Close the event dispatch task queue when the
document timeline is torn down.
(WebCore::DocumentTimeline::enqueueAnimationPlaybackEvent): Add the provided event to the
pending animation events queue and, if one hasn't been registered yet, enqueue a task to
dispatch events using a GenericTaskQueue<Timer>.
(WebCore::compareAnimationPlaybackEvents): Comparator used to sort events in performEventDispatchTask()
where events are sorted such that unresolved timeline times come first, and then from the
earlier resolved timeline times to the later resolved timeline times. Events with unresolved
timeline times and equal resolved timeline times are sorted in the order they were enqueued.
(WebCore::DocumentTimeline::performEventDispatchTask): Run a stable sort on a copy of the pending list
of events to dispatch and dispatch the events individually on their respective animations.
* animation/DocumentTimeline.h:
* animation/WebAnimation.cpp:
(WebCore::WebAnimation::create): Pass in the document to the constructor.
(WebCore::WebAnimation::WebAnimation): Use the provided document to initialize ActiveDOMObject.
(WebCore::WebAnimation::enqueueAnimationPlaybackEvent): Create an AnimationPlaybackEvent with
the provided type, timeline time and animation time and enqueue it on the document timeline,
if one is available, or dispatch on this animation as a standalone task.
(WebCore::WebAnimation::acceleratedRunningStateDidChange):
(WebCore::WebAnimation::activeDOMObjectName const):
(WebCore::WebAnimation::canSuspendForDocumentSuspension const):
(WebCore::WebAnimation::stop):
* animation/WebAnimation.h: Define WebAnimation to be an EventTarget and an ActiveDOMObject.
* animation/WebAnimation.idl: Define WebAnimation to be an EventTarget and an ActiveDOMObject.
* dom/EventTargetFactory.in:

LayoutTests:

Rebase Web Platform Tests with some progressions based on the IDL changes. Progressions due
to dispatching events will become apparent when the next patch, where we dispatch actual
animation playback events, lands.

* http/wpt/web-animations/interfaces/Animation/idlharness-expected.txt:

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (225789 => 225790)


--- trunk/LayoutTests/ChangeLog	2017-12-12 18:48:13 UTC (rev 225789)
+++ trunk/LayoutTests/ChangeLog	2017-12-12 19:01:18 UTC (rev 225790)
@@ -1,3 +1,17 @@
+2017-12-11  Antoine Quint  <grao...@apple.com>
+
+        [Web Animations] Enqueue and dispatch animation events
+        https://bugs.webkit.org/show_bug.cgi?id=180657
+        <rdar://problem/35970103>
+
+        Reviewed by Chris Dumez.
+
+        Rebase Web Platform Tests with some progressions based on the IDL changes. Progressions due
+        to dispatching events will become apparent when the next patch, where we dispatch actual
+        animation playback events, lands.
+
+        * http/wpt/web-animations/interfaces/Animation/idlharness-expected.txt:
+
 2017-12-12  Youenn Fablet  <you...@apple.com>
 
         Allow AudioContext to start when getUserMedia is on

Modified: trunk/LayoutTests/http/wpt/web-animations/interfaces/Animation/idlharness-expected.txt (225789 => 225790)


--- trunk/LayoutTests/http/wpt/web-animations/interfaces/Animation/idlharness-expected.txt	2017-12-12 18:48:13 UTC (rev 225789)
+++ trunk/LayoutTests/http/wpt/web-animations/interfaces/Animation/idlharness-expected.txt	2017-12-12 19:01:18 UTC (rev 225790)
@@ -1,13 +1,9 @@
 
 PASS Animation interface automated IDL tests 
-FAIL Animation interface: existence and properties of interface object assert_equals: prototype of Animation is not EventTarget expected function "function EventTarget() {
-    [native code]
-}" but got function "function () {
-    [native code]
-}"
+PASS Animation interface: existence and properties of interface object 
 PASS Animation interface object length 
 PASS Animation interface object name 
-FAIL Animation interface: existence and properties of interface prototype object assert_equals: prototype of Animation.prototype is not EventTarget.prototype expected object "[object EventTargetPrototype]" but got object "[object Object]"
+PASS Animation interface: existence and properties of interface prototype object 
 PASS Animation interface: existence and properties of interface prototype object's "constructor" property 
 FAIL Animation interface: attribute id assert_true: The prototype object must have a property "id" expected true got false
 PASS Animation interface: attribute effect 

Modified: trunk/Source/WebCore/ChangeLog (225789 => 225790)


--- trunk/Source/WebCore/ChangeLog	2017-12-12 18:48:13 UTC (rev 225789)
+++ trunk/Source/WebCore/ChangeLog	2017-12-12 19:01:18 UTC (rev 225790)
@@ -1,3 +1,50 @@
+2017-12-11  Antoine Quint  <grao...@apple.com>
+
+        [Web Animations] Enqueue and dispatch animation events
+        https://bugs.webkit.org/show_bug.cgi?id=180657
+        <rdar://problem/35970103>
+
+        Reviewed by Chris Dumez.
+
+        Now that we have support for the AnimationPlaybackEvent interface, we need a way to enqueue
+        such events for dispatch at the opportune time. The Web Animations spec defines two ways
+        to queue and dispatch events.
+
+        If the animation has a "document for timing", it should enqueue events on this document.
+        In our implementation, if the animation timeline is set to a DocumentTimeline, that means
+        it has a document for timing, and we let the DocumentTimeline enqueue those events, which
+        will be dispatched through a dedicated GenericTaskQueue<Timer>. These events will be sorted
+        by their respective timeline time before being dispatched.
+
+        If there is no document for timing, events should be dispatched as a standalone task.
+
+        * animation/DocumentTimeline.cpp:
+        (WebCore::DocumentTimeline::~DocumentTimeline): Close the event dispatch task queue when the
+        document timeline is torn down.
+        (WebCore::DocumentTimeline::enqueueAnimationPlaybackEvent): Add the provided event to the
+        pending animation events queue and, if one hasn't been registered yet, enqueue a task to
+        dispatch events using a GenericTaskQueue<Timer>.
+        (WebCore::compareAnimationPlaybackEvents): Comparator used to sort events in performEventDispatchTask()
+        where events are sorted such that unresolved timeline times come first, and then from the
+        earlier resolved timeline times to the later resolved timeline times. Events with unresolved
+        timeline times and equal resolved timeline times are sorted in the order they were enqueued.
+        (WebCore::DocumentTimeline::performEventDispatchTask): Run a stable sort on a copy of the pending list
+        of events to dispatch and dispatch the events individually on their respective animations.
+        * animation/DocumentTimeline.h:
+        * animation/WebAnimation.cpp:
+        (WebCore::WebAnimation::create): Pass in the document to the constructor.
+        (WebCore::WebAnimation::WebAnimation): Use the provided document to initialize ActiveDOMObject.
+        (WebCore::WebAnimation::enqueueAnimationPlaybackEvent): Create an AnimationPlaybackEvent with
+        the provided type, timeline time and animation time and enqueue it on the document timeline,
+        if one is available, or dispatch on this animation as a standalone task.
+        (WebCore::WebAnimation::acceleratedRunningStateDidChange):
+        (WebCore::WebAnimation::activeDOMObjectName const):
+        (WebCore::WebAnimation::canSuspendForDocumentSuspension const):
+        (WebCore::WebAnimation::stop):
+        * animation/WebAnimation.h: Define WebAnimation to be an EventTarget and an ActiveDOMObject.
+        * animation/WebAnimation.idl: Define WebAnimation to be an EventTarget and an ActiveDOMObject.
+        * dom/EventTargetFactory.in:
+
 2017-12-12  Chris Dumez  <cdu...@apple.com>
 
         Simplify IPC code between WebProcess and StorageProcess for serviceWorker.postMessage()

Modified: trunk/Source/WebCore/animation/DocumentTimeline.cpp (225789 => 225790)


--- trunk/Source/WebCore/animation/DocumentTimeline.cpp	2017-12-12 18:48:13 UTC (rev 225789)
+++ trunk/Source/WebCore/animation/DocumentTimeline.cpp	2017-12-12 19:01:18 UTC (rev 225790)
@@ -59,6 +59,7 @@
 DocumentTimeline::~DocumentTimeline()
 {
     m_invalidationTaskQueue.close();
+    m_eventDispatchTaskQueue.close();
 }
 
 void DocumentTimeline::detachFromDocument()
@@ -210,6 +211,39 @@
     return !animations.isEmpty();
 }
 
+void DocumentTimeline::enqueueAnimationPlaybackEvent(AnimationPlaybackEvent& event)
+{
+    m_pendingAnimationEvents.append(event);
+
+    if (!m_eventDispatchTaskQueue.hasPendingTasks())
+        m_eventDispatchTaskQueue.enqueueTask(std::bind(&DocumentTimeline::performEventDispatchTask, this));
+}
+
+static inline bool compareAnimationPlaybackEvents(const Ref<WebCore::AnimationPlaybackEvent>& lhs, const Ref<WebCore::AnimationPlaybackEvent>& rhs)
+{
+    // 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.
+    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();
+}
+
+void DocumentTimeline::performEventDispatchTask()
+{
+    if (m_pendingAnimationEvents.isEmpty())
+        return;
+
+    auto pendingAnimationEvents = WTFMove(m_pendingAnimationEvents);
+
+    std::stable_sort(pendingAnimationEvents.begin(), pendingAnimationEvents.end(), compareAnimationPlaybackEvents);
+    for (auto& pendingEvent : pendingAnimationEvents)
+        pendingEvent->target()->dispatchEvent(pendingEvent);
+}
+
 void DocumentTimeline::windowScreenDidChange(PlatformDisplayID displayID)
 {
 #if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)

Modified: trunk/Source/WebCore/animation/DocumentTimeline.h (225789 => 225790)


--- trunk/Source/WebCore/animation/DocumentTimeline.h	2017-12-12 18:48:13 UTC (rev 225789)
+++ trunk/Source/WebCore/animation/DocumentTimeline.h	2017-12-12 19:01:18 UTC (rev 225790)
@@ -37,6 +37,7 @@
 
 namespace WebCore {
 
+class AnimationPlaybackEvent;
 class RenderElement;
 
 class DocumentTimeline final : public AnimationTimeline
@@ -59,6 +60,8 @@
     bool runningAnimationsForElementAreAllAccelerated(Element&);
     void detachFromDocument();
 
+    void enqueueAnimationPlaybackEvent(AnimationPlaybackEvent&);
+
 private:
     DocumentTimeline(Document&, PlatformDisplayID);
 
@@ -68,14 +71,17 @@
     void animationScheduleTimerFired();
     void scheduleAnimationResolution();
     void updateAnimations();
+    void performEventDispatchTask();
 
     RefPtr<Document> m_document;
     bool m_paused { false };
     std::optional<Seconds> m_cachedCurrentTime;
     GenericTaskQueue<Timer> m_invalidationTaskQueue;
+    GenericTaskQueue<Timer> m_eventDispatchTaskQueue;
     bool m_needsUpdateAnimationSchedule { false };
     Timer m_animationScheduleTimer;
     HashSet<RefPtr<WebAnimation>> m_acceleratedAnimationsPendingRunningStateChange;
+    Vector<Ref<AnimationPlaybackEvent>> m_pendingAnimationEvents;
 
 #if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
     // Override for DisplayRefreshMonitorClient

Modified: trunk/Source/WebCore/animation/WebAnimation.cpp (225789 => 225790)


--- trunk/Source/WebCore/animation/WebAnimation.cpp	2017-12-12 18:48:13 UTC (rev 225789)
+++ trunk/Source/WebCore/animation/WebAnimation.cpp	2017-12-12 19:01:18 UTC (rev 225790)
@@ -27,6 +27,7 @@
 #include "WebAnimation.h"
 
 #include "AnimationEffect.h"
+#include "AnimationPlaybackEvent.h"
 #include "AnimationTimeline.h"
 #include "Document.h"
 #include "KeyframeEffect.h"
@@ -36,7 +37,7 @@
 
 Ref<WebAnimation> WebAnimation::create(Document& document, AnimationEffect* effect, AnimationTimeline* timeline)
 {
-    auto result = adoptRef(*new WebAnimation());
+    auto result = adoptRef(*new WebAnimation(document));
 
     result->setEffect(effect);
 
@@ -47,8 +48,10 @@
     return result;
 }
 
-WebAnimation::WebAnimation()
+WebAnimation::WebAnimation(Document& document)
+    : ActiveDOMObject(&document)
 {
+    suspendIfNeeded();
 }
 
 WebAnimation::~WebAnimation()
@@ -214,6 +217,26 @@
         setCurrentTime(previousTime);
 }
 
+void WebAnimation::enqueueAnimationPlaybackEvent(const AtomicString& type, std::optional<Seconds> currentTime, std::optional<Seconds> timelineTime)
+{
+    auto event = AnimationPlaybackEvent::create(type, currentTime, timelineTime);
+    event->setTarget(this);
+
+    if (is<DocumentTimeline>(m_timeline)) {
+        // If animation has a document for timing, then append event to its document for timing's pending animation event queue along
+        // with its target, animation. If animation is associated with an active timeline that defines a procedure to convert timeline times
+        // to origin-relative time, let the scheduled event time be the result of applying that procedure to timeline time. Otherwise, the
+        // scheduled event time is an unresolved time value.
+        downcast<DocumentTimeline>(*m_timeline).enqueueAnimationPlaybackEvent(WTFMove(event));
+    } else {
+        // Otherwise, queue a task to dispatch event at animation. The task source for this task is the DOM manipulation task source.
+        callOnMainThread([this, pendingActivity = makePendingActivity(*this), event = WTFMove(event)]() {
+            if (!m_isStopped)
+                this->dispatchEvent(event);
+        });
+    }
+}
+
 Seconds WebAnimation::timeToNextRequiredTick(Seconds timelineTime) const
 {
     if (!m_timeline || !m_startTime || !m_effect || !m_playbackRate)
@@ -245,7 +268,7 @@
 
 void WebAnimation::acceleratedRunningStateDidChange()
 {
-    if (m_timeline && m_timeline->isDocumentTimeline())
+    if (is<DocumentTimeline>(m_timeline))
         downcast<DocumentTimeline>(*m_timeline).animationAcceleratedRunningStateDidChange(*this);
 }
 
@@ -260,4 +283,20 @@
     return "Animation";
 }
 
+const char* WebAnimation::activeDOMObjectName() const
+{
+    return "Animation";
+}
+
+bool WebAnimation::canSuspendForDocumentSuspension() const
+{
+    return !hasPendingActivity();
+}
+
+void WebAnimation::stop()
+{
+    m_isStopped = true;
+    removeAllEventListeners();
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/animation/WebAnimation.h (225789 => 225790)


--- trunk/Source/WebCore/animation/WebAnimation.h	2017-12-12 18:48:13 UTC (rev 225789)
+++ trunk/Source/WebCore/animation/WebAnimation.h	2017-12-12 19:01:18 UTC (rev 225790)
@@ -25,6 +25,8 @@
 
 #pragma once
 
+#include "ActiveDOMObject.h"
+#include "EventTarget.h"
 #include "ExceptionOr.h"
 #include <wtf/Forward.h>
 #include <wtf/Optional.h>
@@ -36,11 +38,12 @@
 namespace WebCore {
 
 class AnimationEffect;
+class AnimationPlaybackEvent;
 class AnimationTimeline;
 class Document;
 class RenderStyle;
 
-class WebAnimation final : public RefCounted<WebAnimation> {
+class WebAnimation final : public RefCounted<WebAnimation>, public EventTargetWithInlineData, public ActiveDOMObject {
 public:
     static Ref<WebAnimation> create(Document&, AnimationEffect*, AnimationTimeline*);
     ~WebAnimation();
@@ -70,13 +73,30 @@
 
     String description();
 
+    using RefCounted::ref;
+    using RefCounted::deref;
+
 private:
-    WebAnimation();
+    explicit WebAnimation(Document&);
 
+    void enqueueAnimationPlaybackEvent(const AtomicString&, std::optional<Seconds>, std::optional<Seconds>);
+    
     RefPtr<AnimationEffect> m_effect;
     RefPtr<AnimationTimeline> m_timeline;
     std::optional<Seconds> m_startTime;
     double m_playbackRate { 1 };
+    bool m_isStopped { false };
+
+    // ActiveDOMObject.
+    const char* activeDOMObjectName() const final;
+    bool canSuspendForDocumentSuspension() const final;
+    void stop() final;
+
+    // EventTarget
+    EventTargetInterface eventTargetInterface() const final { return WebAnimationEventTargetInterfaceType; }
+    void refEventTarget() final { ref(); }
+    void derefEventTarget() final { deref(); }
+    ScriptExecutionContext* scriptExecutionContext() const final { return ActiveDOMObject::scriptExecutionContext(); }
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/animation/WebAnimation.idl (225789 => 225790)


--- trunk/Source/WebCore/animation/WebAnimation.idl	2017-12-12 18:48:13 UTC (rev 225789)
+++ trunk/Source/WebCore/animation/WebAnimation.idl	2017-12-12 19:01:18 UTC (rev 225790)
@@ -24,12 +24,12 @@
  */
 
 [
+    ActiveDOMObject,
     EnabledAtRuntime=WebAnimations,
     InterfaceName=Animation,
-    ImplementationLacksVTable,
     ConstructorCallWith=Document,
     Constructor(optional AnimationEffect? effect = null, optional AnimationTimeline? timeline)
-] interface WebAnimation {
+] interface WebAnimation : EventTarget {
     attribute AnimationEffect? effect;
     attribute AnimationTimeline? timeline;
     [ImplementedAs=bindingsStartTime] attribute double? startTime;

Modified: trunk/Source/WebCore/dom/EventTargetFactory.in (225789 => 225790)


--- trunk/Source/WebCore/dom/EventTargetFactory.in	2017-12-12 18:48:13 UTC (rev 225789)
+++ trunk/Source/WebCore/dom/EventTargetFactory.in	2017-12-12 19:01:18 UTC (rev 225790)
@@ -44,6 +44,7 @@
 VRDisplay
 VideoTrackList conditional=VIDEO_TRACK
 VisualViewport
+WebAnimation
 WebKitMediaKeySession conditional=LEGACY_ENCRYPTED_MEDIA
 WebSocket
 Worker
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to