浏览代码

LibWeb: Implement Animation.cancel()

Matthew Olsson 1 年之前
父节点
当前提交
3c055ff76d

+ 90 - 0
Userland/Libraries/LibWeb/Animations/Animation.cpp

@@ -359,6 +359,66 @@ void Animation::set_replace_state(Bindings::AnimationReplaceState value)
     }
     }
 }
 }
 
 
+// https://www.w3.org/TR/web-animations-1/#dom-animation-cancel
+void Animation::cancel()
+{
+    auto& realm = this->realm();
+
+    // 1. If animation’s play state is not idle, perform the following steps:
+    if (play_state() != Bindings::AnimationPlayState::Idle) {
+        HTML::TemporaryExecutionContext execution_context { Bindings::host_defined_environment_settings_object(realm) };
+
+        // 1. Run the procedure to reset an animation’s pending tasks on animation.
+        reset_an_animations_pending_tasks();
+
+        // 2. Reject the current finished promise with a DOMException named "AbortError".
+        auto dom_exception = WebIDL::AbortError::create(realm, "Animation was cancelled"_fly_string);
+        WebIDL::reject_promise(realm, current_finished_promise(), dom_exception);
+
+        // 3. Set the [[PromiseIsHandled]] internal slot of the current finished promise to true.
+        WebIDL::mark_promise_as_handled(current_finished_promise());
+
+        // 4. Let current finished promise be a new promise in the relevant Realm of animation.
+        m_current_finished_promise = WebIDL::create_promise(realm);
+
+        // 5. Create an AnimationPlaybackEvent, cancelEvent.
+        // 6. Set cancelEvent’s type attribute to cancel.
+        // 7. Set cancelEvent’s currentTime to null.
+        // 8. Let timeline time be the current time of the timeline with which animation is associated. If animation is
+        //    not associated with an active timeline, let timeline time be an unresolved time value.
+        // 9. Set cancelEvent’s timelineTime to timeline time. If timeline time is unresolved, set it to null.
+        AnimationPlaybackEventInit init;
+        init.timeline_time = m_timeline && !m_timeline->is_inactive() ? m_timeline->current_time() : Optional<double> {};
+        auto cancel_event = AnimationPlaybackEvent::create(realm, HTML::EventNames::cancel, init);
+
+        // 10. If animation has a document for timing, then append cancelEvent 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.
+        //     Otherwise, queue a task to dispatch cancelEvent at animation. The task source for this task is the DOM
+        //     manipulation task source.
+        if (auto document = document_for_timing()) {
+            Optional<double> scheduled_event_time;
+            if (m_timeline && !m_timeline->is_inactive() && m_timeline->can_convert_a_timeline_time_to_an_origin_relative_time())
+                scheduled_event_time = m_timeline->convert_a_timeline_time_to_an_origin_relative_time(m_timeline->current_time());
+            document->append_pending_animation_event({ cancel_event, *this, scheduled_event_time });
+        } else {
+            HTML::queue_global_task(HTML::Task::Source::DOMManipulation, realm.global_object(), [this, cancel_event]() {
+                dispatch_event(cancel_event);
+            });
+        }
+    }
+
+    // 2. Make animation’s hold time unresolved.
+    m_hold_time = {};
+
+    // 3. Make animation’s start time unresolved.
+    m_start_time = {};
+
+    invalidate_effect();
+}
+
 // https://www.w3.org/TR/web-animations-1/#dom-animation-finish
 // https://www.w3.org/TR/web-animations-1/#dom-animation-finish
 WebIDL::ExceptionOr<void> Animation::finish()
 WebIDL::ExceptionOr<void> Animation::finish()
 {
 {
@@ -961,6 +1021,36 @@ void Animation::update_finished_state(DidSeek did_seek, SynchronouslyNotify sync
     invalidate_effect();
     invalidate_effect();
 }
 }
 
 
+// https://www.w3.org/TR/web-animations-1/#animation-reset-an-animations-pending-tasks
+void Animation::reset_an_animations_pending_tasks()
+{
+    auto& realm = this->realm();
+
+    // 1. If animation does not have a pending play task or a pending pause task, abort this procedure.
+    if (!pending())
+        return;
+
+    // 2. If animation has a pending play task, cancel that task.
+    m_pending_play_task = TaskState::None;
+
+    // 3. If animation has a pending pause task, cancel that task.
+    m_pending_pause_task = TaskState::None;
+
+    // 4. Apply any pending playback rate on animation.
+    apply_any_pending_playback_rate();
+
+    // 5. Reject animation’s current ready promise with a DOMException named "AbortError".
+    auto dom_exception = WebIDL::AbortError::create(realm, "Animation was cancelled"_fly_string);
+    WebIDL::reject_promise(realm, current_ready_promise(), dom_exception);
+
+    // 6. Set the [[PromiseIsHandled]] internal slot of animation’s current ready promise to true.
+    WebIDL::mark_promise_as_handled(current_ready_promise());
+
+    // 7. Let animation’s current ready promise be the result of creating a new resolved Promise object with value
+    //    animation in the relevant Realm of animation.
+    m_current_ready_promise = WebIDL::create_resolved_promise(realm, this);
+}
+
 // Step 12 of https://www.w3.org/TR/web-animations-1/#playing-an-animation-section
 // Step 12 of https://www.w3.org/TR/web-animations-1/#playing-an-animation-section
 void Animation::run_pending_play_task()
 void Animation::run_pending_play_task()
 {
 {

+ 2 - 0
Userland/Libraries/LibWeb/Animations/Animation.h

@@ -70,6 +70,7 @@ public:
         Yes,
         Yes,
         No,
         No,
     };
     };
+    void cancel();
     WebIDL::ExceptionOr<void> finish();
     WebIDL::ExceptionOr<void> finish();
     WebIDL::ExceptionOr<void> play();
     WebIDL::ExceptionOr<void> play();
     WebIDL::ExceptionOr<void> play_an_animation(AutoRewind);
     WebIDL::ExceptionOr<void> play_an_animation(AutoRewind);
@@ -118,6 +119,7 @@ private:
     void apply_any_pending_playback_rate();
     void apply_any_pending_playback_rate();
     WebIDL::ExceptionOr<void> silently_set_current_time(Optional<double>);
     WebIDL::ExceptionOr<void> silently_set_current_time(Optional<double>);
     void update_finished_state(DidSeek, SynchronouslyNotify);
     void update_finished_state(DidSeek, SynchronouslyNotify);
+    void reset_an_animations_pending_tasks();
 
 
     void run_pending_play_task();
     void run_pending_play_task();
     void run_pending_pause_task();
     void run_pending_pause_task();

+ 1 - 1
Userland/Libraries/LibWeb/Animations/Animation.idl

@@ -24,7 +24,7 @@ interface Animation : EventTarget {
     // FIXME: attribute EventHandler oncancel;
     // FIXME: attribute EventHandler oncancel;
     // FIXME: attribute EventHandler onremove;
     // FIXME: attribute EventHandler onremove;
 
 
-    // FIXME: undefined cancel();
+    undefined cancel();
     undefined finish();
     undefined finish();
     undefined play();
     undefined play();
     undefined pause();
     undefined pause();