Skip to content

Commit 06a8674

Browse files
mattco98awesomekling
authored andcommitted
LibWeb: Simplify Animation::update_finished_state a bit
This removes the two boolean hack in favor of using the existing mechanism to remove queued tasks. It also exposes the element invalidation behavior for call sites that don't necessarily want to update the finished state, but still need to invalidate the associated target.
1 parent 1e37ba5 commit 06a8674

File tree

3 files changed

+37
-31
lines changed

3 files changed

+37
-31
lines changed

Userland/Libraries/LibWeb/Animations/Animation.cpp

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,8 @@ WebIDL::ExceptionOr<void> Animation::silently_set_current_time(Optional<double>
630630
// https://www.w3.org/TR/web-animations-1/#update-an-animations-finished-state
631631
void Animation::update_finished_state(DidSeek did_seek, SynchronouslyNotify synchronously_notify)
632632
{
633+
auto& realm = this->realm();
634+
633635
// 1. Let the unconstrained current time be the result of calculating the current time substituting an unresolved
634636
// time value for the hold time if did seek is false. If did seek is true, the unconstrained current time is
635637
// equal to the current time.
@@ -706,30 +708,23 @@ void Animation::update_finished_state(DidSeek did_seek, SynchronouslyNotify sync
706708
if (current_finished_state && !m_is_finished) {
707709
// 1. Let finish notification steps refer to the following procedure:
708710
JS::SafeFunction<void()> finish_notification_steps = [&]() {
709-
if (m_should_abort_finish_notification_microtask) {
710-
m_should_abort_finish_notification_microtask = false;
711-
m_has_finish_notification_microtask_scheduled = false;
712-
return;
713-
}
714-
715711
// 1. If animation’s play state is not equal to finished, abort these steps.
716712
if (play_state() != Bindings::AnimationPlayState::Finished)
717713
return;
718714

719715
// 2. Resolve animation’s current finished promise object with animation.
720716
{
721-
HTML::TemporaryExecutionContext execution_context { Bindings::host_defined_environment_settings_object(realm()) };
722-
WebIDL::resolve_promise(realm(), current_finished_promise(), this);
717+
HTML::TemporaryExecutionContext execution_context { Bindings::host_defined_environment_settings_object(realm) };
718+
WebIDL::resolve_promise(realm, current_finished_promise(), this);
723719
}
724720
m_is_finished = true;
725721

726722
// 3. Create an AnimationPlaybackEvent, finishEvent.
727723
// 4. Set finishEvent’s type attribute to finish.
728724
// 5. Set finishEvent’s currentTime attribute to the current time of animation.
729-
auto& realm = this->realm();
730725
AnimationPlaybackEventInit init;
731726
init.current_time = current_time();
732-
auto finish_event = AnimationPlaybackEvent::create(realm, "finish"_fly_string, init);
727+
auto finish_event = AnimationPlaybackEvent::create(realm, HTML::EventNames::finish, init);
733728

734729
// 6. Set finishEvent’s timelineTime attribute to the current time of the timeline with which animation is
735730
// associated. If animation is not associated with a timeline, or the timeline is inactive, let
@@ -750,44 +745,47 @@ void Animation::update_finished_state(DidSeek did_seek, SynchronouslyNotify sync
750745
// Otherwise, queue a task to dispatch finishEvent at animation. The task source for this task is the DOM
751746
// manipulation task source.
752747
else {
753-
HTML::queue_global_task(HTML::Task::Source::DOMManipulation, realm.global_object(), [this, finish_event]() {
748+
// Manually create a task so its ID can be saved
749+
auto& document = verify_cast<HTML::Window>(realm.global_object()).associated_document();
750+
auto task = HTML::Task::create(HTML::Task::Source::DOMManipulation, &document, [this, finish_event]() {
754751
dispatch_event(finish_event);
755752
});
753+
m_pending_finish_microtask_id = task->id();
754+
HTML::main_thread_event_loop().task_queue().add(move(task));
756755
}
757-
758-
m_has_finish_notification_microtask_scheduled = false;
759756
};
760757

761758
// 2. If synchronously notify is true, cancel any queued microtask to run the finish notification steps for this
762759
// animation, and run the finish notification steps immediately.
763760
if (synchronously_notify == SynchronouslyNotify::Yes) {
764-
m_should_abort_finish_notification_microtask = false;
761+
if (m_pending_finish_microtask_id.has_value()) {
762+
HTML::main_thread_event_loop().task_queue().remove_tasks_matching([id = move(m_pending_finish_microtask_id)](auto const& task) {
763+
return task.id() == id;
764+
});
765+
}
765766
finish_notification_steps();
766-
m_should_abort_finish_notification_microtask = true;
767767
}
768768
// Otherwise, if synchronously notify is false, queue a microtask to run finish notification steps for
769769
// animation unless there is already a microtask queued to run those steps for animation.
770-
else {
771-
if (!m_has_finish_notification_microtask_scheduled)
772-
HTML::queue_a_microtask({}, move(finish_notification_steps));
773-
774-
m_has_finish_notification_microtask_scheduled = true;
775-
m_should_abort_finish_notification_microtask = false;
770+
else if (!m_pending_finish_microtask_id.has_value()) {
771+
auto& document = verify_cast<HTML::Window>(realm.global_object()).associated_document();
772+
auto task = HTML::Task::create(HTML::Task::Source::DOMManipulation, &document, move(finish_notification_steps));
773+
m_pending_finish_microtask_id = task->id();
774+
HTML::main_thread_event_loop().task_queue().add(move(task));
776775
}
777776
}
778777

779778
// 6. If current finished state is false and animation’s current finished promise is already resolved, set
780779
// animation’s current finished promise to a new promise in the relevant Realm of animation.
781780
if (!current_finished_state && m_is_finished) {
782-
m_current_finished_promise = WebIDL::create_promise(realm());
781+
{
782+
HTML::TemporaryExecutionContext execution_context { Bindings::host_defined_environment_settings_object(realm) };
783+
m_current_finished_promise = WebIDL::create_promise(realm);
784+
}
783785
m_is_finished = false;
784786
}
785787

786-
// Invalidate the style of our target element, if applicable
787-
if (m_effect) {
788-
if (auto target = m_effect->target())
789-
target->invalidate_style();
790-
}
788+
invalidate_effect();
791789
}
792790

793791
// Step 12 of https://www.w3.org/TR/web-animations-1/#playing-an-animation-section
@@ -881,6 +879,14 @@ JS::NonnullGCPtr<WebIDL::Promise> Animation::current_finished_promise() const
881879
return *m_current_finished_promise;
882880
}
883881

882+
void Animation::invalidate_effect()
883+
{
884+
if (m_effect) {
885+
if (auto target = m_effect->target())
886+
target->invalidate_style();
887+
}
888+
}
889+
884890
Animation::Animation(JS::Realm& realm)
885891
: DOM::EventTarget(realm)
886892
{

Userland/Libraries/LibWeb/Animations/Animation.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ class Animation : public DOM::EventTarget {
120120
JS::NonnullGCPtr<WebIDL::Promise> current_ready_promise() const;
121121
JS::NonnullGCPtr<WebIDL::Promise> current_finished_promise() const;
122122

123+
void invalidate_effect();
124+
123125
// https://www.w3.org/TR/web-animations-1/#dom-animation-id
124126
FlyString m_id;
125127

@@ -164,10 +166,7 @@ class Animation : public DOM::EventTarget {
164166
// https://www.w3.org/TR/web-animations-1/#pending-pause-task
165167
TaskState m_pending_pause_task { TaskState::None };
166168

167-
// Flags used to manage the finish notification microtask and ultimately prevent more than one finish notification
168-
// microtask from being queued at any given time
169-
bool m_should_abort_finish_notification_microtask { false };
170-
bool m_has_finish_notification_microtask_scheduled { false };
169+
Optional<int> m_pending_finish_microtask_id;
171170
};
172171

173172
}

Userland/Libraries/LibWeb/HTML/EventNames.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ namespace Web::HTML::EventNames {
4949
__ENUMERATE_HTML_EVENT(emptied) \
5050
__ENUMERATE_HTML_EVENT(ended) \
5151
__ENUMERATE_HTML_EVENT(error) \
52+
__ENUMERATE_HTML_EVENT(finish) \
5253
__ENUMERATE_HTML_EVENT(focus) \
5354
__ENUMERATE_HTML_EVENT(formdata) \
5455
__ENUMERATE_HTML_EVENT(hashchange) \

0 commit comments

Comments
 (0)