1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 04:57:44 +00:00

LibWeb: Transition StyleComputer to Web Animations

With this commit, we are finally running animations off of the web
animations spec! A lot of the work StyleComputer is doing is now done
elsewhere. For example, fill-forward animations are handled by
Animation::is_relevant() returning true in the after phase, meaning the
"active_state_if_fill_forward" map is no longer needed.
This commit is contained in:
Matthew Olsson 2024-02-22 13:56:15 +00:00 committed by Andreas Kling
parent b258ba2767
commit ae3326a447
7 changed files with 270 additions and 647 deletions

View file

@ -23,6 +23,8 @@
#include <LibWeb/Animations/AnimationTimeline.h>
#include <LibWeb/Animations/DocumentTimeline.h>
#include <LibWeb/Bindings/MainThreadVM.h>
#include <LibWeb/CSS/AnimationEvent.h>
#include <LibWeb/CSS/CSSAnimation.h>
#include <LibWeb/CSS/MediaQueryList.h>
#include <LibWeb/CSS/MediaQueryListEvent.h>
#include <LibWeb/CSS/StyleComputer.h>
@ -1889,6 +1891,19 @@ Element* Document::find_a_potential_indicated_element(FlyString const& fragment)
return nullptr;
}
// https://www.w3.org/TR/css-animations-2/#event-dispatch
void Document::dispatch_events_for_animation_if_necessary(JS::NonnullGCPtr<Animations::Animation> animation)
{
// Each time a new animation frame is established and the animation does not have a pending play task or pending
// pause task, the events to dispatch are determined by comparing the animations phase before and after
// establishing the new animation frame as follows:
auto effect = animation->effect();
if (!effect || !effect->is_keyframe_effect() || !animation->is_css_animation() || animation->pending())
return;
// TODO: Dispatch events
}
// https://html.spec.whatwg.org/multipage/browsing-the-web.html#scroll-to-the-fragment-identifier
void Document::scroll_to_the_fragment()
{
@ -3908,6 +3923,35 @@ void Document::remove_replaced_animations()
}
}
void Document::ensure_animation_timer()
{
constexpr static auto timer_delay_ms = 1000 / 60;
if (!m_animation_driver_timer) {
m_animation_driver_timer = Platform::Timer::create_repeating(timer_delay_ms, [this] {
bool has_animations = false;
for (auto& timeline : m_associated_animation_timelines) {
if (!timeline->associated_animations().is_empty()) {
has_animations = true;
break;
}
}
if (!has_animations) {
m_animation_driver_timer->stop();
return;
}
update_animations_and_send_events(MonotonicTime::now().milliseconds());
for (auto& timeline : m_associated_animation_timelines) {
for (auto& animation : timeline->associated_animations())
dispatch_events_for_animation_if_necessary(animation);
}
});
}
m_animation_driver_timer->start();
}
// https://html.spec.whatwg.org/multipage/dom.html#dom-document-nameditem-filter
static bool is_potentially_named_element(DOM::Element const& element)
{

View file

@ -561,6 +561,7 @@ public:
void append_pending_animation_event(PendingAnimationEvent const&);
void update_animations_and_send_events(Optional<double> const& timestamp);
void remove_replaced_animations();
void ensure_animation_timer();
bool ready_to_run_scripts() const { return m_ready_to_run_scripts; }
@ -620,6 +621,8 @@ private:
Element* find_a_potential_indicated_element(FlyString const& fragment) const;
void dispatch_events_for_animation_if_necessary(JS::NonnullGCPtr<Animations::Animation>);
JS::NonnullGCPtr<Page> m_page;
OwnPtr<CSS::StyleComputer> m_style_computer;
JS::GCPtr<CSS::StyleSheetList> m_style_sheets;
@ -815,6 +818,7 @@ private:
// https://www.w3.org/TR/web-animations-1/#pending-animation-event-queue
Vector<PendingAnimationEvent> m_pending_animation_event_queue;
RefPtr<Platform::Timer> m_animation_driver_timer;
bool m_needs_to_call_page_did_load { false };