Skip to content

Commit

Permalink
LibWeb: Stop spamming animation events on the wrong event target
Browse files Browse the repository at this point in the history
This patch fixes two issues:

- Animation events that should go to the target element now do
  (some were previously being dispatched on the animation itself.)
- We update the "previous phase" and "previous iteration" fields of
  animation effects, so that we can actually detect phase changes.
  This means we stop thinking animations always just started,
  something that caused each animation to send 60 animationstart
  events every second (to the wrong target!)
  • Loading branch information
awesomekling committed May 23, 2024
1 parent a68222f commit f4636a0
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
animationstart
animationend
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<!doctype html><style>
body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f0f0f0;
}

div {
width: 100px;
height: 100px;
background-color: #3498db;
position: relative;
animation: moveRight 0.1s linear;
animation-play-state: paused;
}

@keyframes moveRight {
0% {
left: 0;
}
100% {
left: 100px;
}
}
</style>
<body>
<script src="../../include.js"></script>
<div id="d"></div>
<script>
asyncTest(done => {
let div = document.getElementById("d");
div.addEventListener("animationstart", () => {
println("animationstart");
});
div.addEventListener("animationend", () => {
println("animationend");
div.style.animationPlayState = "paused";
div.style.display = "none";
done();
});
});
</script>
</body>
9 changes: 6 additions & 3 deletions Userland/Libraries/LibWeb/Animations/Animation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ void Animation::cancel(ShouldInvalidate should_invalidate)
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 });
document->append_pending_animation_event({ cancel_event, *this, *this, scheduled_event_time });
} else {
HTML::queue_global_task(HTML::Task::Source::DOMManipulation, realm.global_object(), JS::create_heap_function(heap(), [this, cancel_event]() {
dispatch_event(cancel_event);
Expand Down Expand Up @@ -1127,9 +1127,12 @@ void Animation::update_finished_state(DidSeek did_seek, SynchronouslyNotify sync
// animation event queue along with its target, animation. For the scheduled event time, use the result
// of converting animation’s associated effect end to an origin-relative time.
if (auto document_for_timing = this->document_for_timing()) {
document_for_timing->append_pending_animation_event({ .event = finish_event,
document_for_timing->append_pending_animation_event({
.event = finish_event,
.animation = *this,
.target = *this,
.scheduled_event_time = convert_a_timeline_time_to_an_origin_relative_time(associated_effect_end()) });
.scheduled_event_time = convert_a_timeline_time_to_an_origin_relative_time(associated_effect_end()),
});
}
// Otherwise, queue a task to dispatch finishEvent at animation. The task source for this task is the DOM
// manipulation task source.
Expand Down
23 changes: 16 additions & 7 deletions Userland/Libraries/LibWeb/DOM/Document.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2017,7 +2017,12 @@ void Document::dispatch_events_for_animation_if_necessary(JS::NonnullGCPtr<Anima
return;

auto& css_animation = verify_cast<CSS::CSSAnimation>(*animation);
if (auto target = effect->target(); target && target->paintable())

JS::GCPtr<Element> target = effect->target();
if (!target)
return;

if (target->paintable())
target->paintable()->set_needs_display();

auto previous_phase = effect->previous_phase();
Expand All @@ -2037,7 +2042,8 @@ void Document::dispatch_events_for_animation_if_necessary(JS::NonnullGCPtr<Anima
css_animation.id(),
elapsed_time,
}),
.target = animation,
.animation = css_animation,
.target = *target,
.scheduled_event_time = HighResolutionTime::unsafe_shared_current_time(),
});
};
Expand Down Expand Up @@ -2101,6 +2107,8 @@ void Document::dispatch_events_for_animation_if_necessary(JS::NonnullGCPtr<Anima
dispatch_event(HTML::EventNames::animationcancel, effect->active_time_using_fill(Bindings::FillMode::Both).value());
}
}
effect->set_previous_phase(current_phase);
effect->set_previous_current_iteration(current_iteration);
}

// https://html.spec.whatwg.org/multipage/browsing-the-web.html#scroll-to-the-fragment-identifier
Expand Down Expand Up @@ -4238,8 +4246,8 @@ void Document::update_animations_and_send_events(Optional<double> const& timesta

// 6. Perform a stable sort of the animation events in events to dispatch as follows:
auto sort_events_by_composite_order = [](auto const& a, auto const& b) {
auto& a_effect = verify_cast<Animations::KeyframeEffect>(*a.target->effect());
auto& b_effect = verify_cast<Animations::KeyframeEffect>(*b.target->effect());
auto& a_effect = verify_cast<Animations::KeyframeEffect>(*a.animation->effect());
auto& b_effect = verify_cast<Animations::KeyframeEffect>(*b.animation->effect());
return Animations::KeyframeEffect::composite_order(a_effect, b_effect) < 0;
};

Expand Down Expand Up @@ -4352,9 +4360,10 @@ void Document::remove_replaced_animations()
// timeline with which animation is associated.
if (auto document = animation->document_for_timing()) {
PendingAnimationEvent pending_animation_event {
remove_event,
animation,
animation->timeline()->convert_a_timeline_time_to_an_origin_relative_time(init.timeline_time),
.event = remove_event,
.animation = animation,
.target = animation,
.scheduled_event_time = animation->timeline()->convert_a_timeline_time_to_an_origin_relative_time(init.timeline_time),
};
document->append_pending_animation_event(pending_animation_event);
}
Expand Down
3 changes: 2 additions & 1 deletion Userland/Libraries/LibWeb/DOM/Document.h
Original file line number Diff line number Diff line change
Expand Up @@ -599,7 +599,8 @@ class Document

struct PendingAnimationEvent {
JS::NonnullGCPtr<DOM::Event> event;
JS::NonnullGCPtr<Animations::Animation> target;
JS::NonnullGCPtr<Animations::Animation> animation;
JS::NonnullGCPtr<DOM::EventTarget> target;
Optional<double> scheduled_event_time;
};
void append_pending_animation_event(PendingAnimationEvent const&);
Expand Down

0 comments on commit f4636a0

Please sign in to comment.