mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-26 09:30:24 +00:00
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.
This commit is contained in:
parent
1e37ba5515
commit
06a8674eec
Notes:
sideshowbarker
2024-07-18 22:57:59 +09:00
Author: https://github.com/mattco98 Commit: https://github.com/SerenityOS/serenity/commit/06a8674eec Pull-request: https://github.com/SerenityOS/serenity/pull/23257
3 changed files with 37 additions and 31 deletions
|
@ -630,6 +630,8 @@ WebIDL::ExceptionOr<void> Animation::silently_set_current_time(Optional<double>
|
|||
// https://www.w3.org/TR/web-animations-1/#update-an-animations-finished-state
|
||||
void Animation::update_finished_state(DidSeek did_seek, SynchronouslyNotify synchronously_notify)
|
||||
{
|
||||
auto& realm = this->realm();
|
||||
|
||||
// 1. Let the unconstrained current time be the result of calculating the current time substituting an unresolved
|
||||
// time value for the hold time if did seek is false. If did seek is true, the unconstrained current time is
|
||||
// equal to the current time.
|
||||
|
@ -706,30 +708,23 @@ void Animation::update_finished_state(DidSeek did_seek, SynchronouslyNotify sync
|
|||
if (current_finished_state && !m_is_finished) {
|
||||
// 1. Let finish notification steps refer to the following procedure:
|
||||
JS::SafeFunction<void()> finish_notification_steps = [&]() {
|
||||
if (m_should_abort_finish_notification_microtask) {
|
||||
m_should_abort_finish_notification_microtask = false;
|
||||
m_has_finish_notification_microtask_scheduled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. If animation’s play state is not equal to finished, abort these steps.
|
||||
if (play_state() != Bindings::AnimationPlayState::Finished)
|
||||
return;
|
||||
|
||||
// 2. Resolve animation’s current finished promise object with animation.
|
||||
{
|
||||
HTML::TemporaryExecutionContext execution_context { Bindings::host_defined_environment_settings_object(realm()) };
|
||||
WebIDL::resolve_promise(realm(), current_finished_promise(), this);
|
||||
HTML::TemporaryExecutionContext execution_context { Bindings::host_defined_environment_settings_object(realm) };
|
||||
WebIDL::resolve_promise(realm, current_finished_promise(), this);
|
||||
}
|
||||
m_is_finished = true;
|
||||
|
||||
// 3. Create an AnimationPlaybackEvent, finishEvent.
|
||||
// 4. Set finishEvent’s type attribute to finish.
|
||||
// 5. Set finishEvent’s currentTime attribute to the current time of animation.
|
||||
auto& realm = this->realm();
|
||||
AnimationPlaybackEventInit init;
|
||||
init.current_time = current_time();
|
||||
auto finish_event = AnimationPlaybackEvent::create(realm, "finish"_fly_string, init);
|
||||
auto finish_event = AnimationPlaybackEvent::create(realm, HTML::EventNames::finish, init);
|
||||
|
||||
// 6. Set finishEvent’s timelineTime attribute to the current time of the timeline with which animation is
|
||||
// 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
|
|||
// Otherwise, queue a task to dispatch finishEvent at animation. The task source for this task is the DOM
|
||||
// manipulation task source.
|
||||
else {
|
||||
HTML::queue_global_task(HTML::Task::Source::DOMManipulation, realm.global_object(), [this, finish_event]() {
|
||||
// Manually create a task so its ID can be saved
|
||||
auto& document = verify_cast<HTML::Window>(realm.global_object()).associated_document();
|
||||
auto task = HTML::Task::create(HTML::Task::Source::DOMManipulation, &document, [this, finish_event]() {
|
||||
dispatch_event(finish_event);
|
||||
});
|
||||
m_pending_finish_microtask_id = task->id();
|
||||
HTML::main_thread_event_loop().task_queue().add(move(task));
|
||||
}
|
||||
|
||||
m_has_finish_notification_microtask_scheduled = false;
|
||||
};
|
||||
|
||||
// 2. If synchronously notify is true, cancel any queued microtask to run the finish notification steps for this
|
||||
// animation, and run the finish notification steps immediately.
|
||||
if (synchronously_notify == SynchronouslyNotify::Yes) {
|
||||
m_should_abort_finish_notification_microtask = false;
|
||||
if (m_pending_finish_microtask_id.has_value()) {
|
||||
HTML::main_thread_event_loop().task_queue().remove_tasks_matching([id = move(m_pending_finish_microtask_id)](auto const& task) {
|
||||
return task.id() == id;
|
||||
});
|
||||
}
|
||||
finish_notification_steps();
|
||||
m_should_abort_finish_notification_microtask = true;
|
||||
}
|
||||
// Otherwise, if synchronously notify is false, queue a microtask to run finish notification steps for
|
||||
// animation unless there is already a microtask queued to run those steps for animation.
|
||||
else {
|
||||
if (!m_has_finish_notification_microtask_scheduled)
|
||||
HTML::queue_a_microtask({}, move(finish_notification_steps));
|
||||
|
||||
m_has_finish_notification_microtask_scheduled = true;
|
||||
m_should_abort_finish_notification_microtask = false;
|
||||
else if (!m_pending_finish_microtask_id.has_value()) {
|
||||
auto& document = verify_cast<HTML::Window>(realm.global_object()).associated_document();
|
||||
auto task = HTML::Task::create(HTML::Task::Source::DOMManipulation, &document, move(finish_notification_steps));
|
||||
m_pending_finish_microtask_id = task->id();
|
||||
HTML::main_thread_event_loop().task_queue().add(move(task));
|
||||
}
|
||||
}
|
||||
|
||||
// 6. If current finished state is false and animation’s current finished promise is already resolved, set
|
||||
// animation’s current finished promise to a new promise in the relevant Realm of animation.
|
||||
if (!current_finished_state && m_is_finished) {
|
||||
m_current_finished_promise = WebIDL::create_promise(realm());
|
||||
{
|
||||
HTML::TemporaryExecutionContext execution_context { Bindings::host_defined_environment_settings_object(realm) };
|
||||
m_current_finished_promise = WebIDL::create_promise(realm);
|
||||
}
|
||||
m_is_finished = false;
|
||||
}
|
||||
|
||||
// Invalidate the style of our target element, if applicable
|
||||
if (m_effect) {
|
||||
if (auto target = m_effect->target())
|
||||
target->invalidate_style();
|
||||
}
|
||||
invalidate_effect();
|
||||
}
|
||||
|
||||
// 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
|
|||
return *m_current_finished_promise;
|
||||
}
|
||||
|
||||
void Animation::invalidate_effect()
|
||||
{
|
||||
if (m_effect) {
|
||||
if (auto target = m_effect->target())
|
||||
target->invalidate_style();
|
||||
}
|
||||
}
|
||||
|
||||
Animation::Animation(JS::Realm& realm)
|
||||
: DOM::EventTarget(realm)
|
||||
{
|
||||
|
|
|
@ -120,6 +120,8 @@ private:
|
|||
JS::NonnullGCPtr<WebIDL::Promise> current_ready_promise() const;
|
||||
JS::NonnullGCPtr<WebIDL::Promise> current_finished_promise() const;
|
||||
|
||||
void invalidate_effect();
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#dom-animation-id
|
||||
FlyString m_id;
|
||||
|
||||
|
@ -164,10 +166,7 @@ private:
|
|||
// https://www.w3.org/TR/web-animations-1/#pending-pause-task
|
||||
TaskState m_pending_pause_task { TaskState::None };
|
||||
|
||||
// Flags used to manage the finish notification microtask and ultimately prevent more than one finish notification
|
||||
// microtask from being queued at any given time
|
||||
bool m_should_abort_finish_notification_microtask { false };
|
||||
bool m_has_finish_notification_microtask_scheduled { false };
|
||||
Optional<int> m_pending_finish_microtask_id;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ namespace Web::HTML::EventNames {
|
|||
__ENUMERATE_HTML_EVENT(emptied) \
|
||||
__ENUMERATE_HTML_EVENT(ended) \
|
||||
__ENUMERATE_HTML_EVENT(error) \
|
||||
__ENUMERATE_HTML_EVENT(finish) \
|
||||
__ENUMERATE_HTML_EVENT(focus) \
|
||||
__ENUMERATE_HTML_EVENT(formdata) \
|
||||
__ENUMERATE_HTML_EVENT(hashchange) \
|
||||
|
|
Loading…
Reference in a new issue