mirror of
https://github.com/SerenityOS/serenity
synced 2024-10-15 20:33:10 +00:00
LibWeb: Stop spamming animation events on the wrong event target
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!)
This commit is contained in:
parent
a68222f654
commit
f4636a0cf5
|
@ -0,0 +1,2 @@
|
|||
animationstart
|
||||
animationend
|
|
@ -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>
|
|
@ -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);
|
||||
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
@ -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(),
|
||||
});
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -599,7 +599,8 @@ public:
|
|||
|
||||
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&);
|
||||
|
|
Loading…
Reference in a new issue