From 55afa9d37e72f1a5e8ac760cc71984a04abe3ac4 Mon Sep 17 00:00:00 2001 From: Callum Law Date: Tue, 11 Nov 2025 16:08:42 +1300 Subject: [PATCH] LibWeb: Avoid unnecessary work when element display property changes `play_or_cancel_animations_after_display_property_change` is called whenever an element is inserted or removed, or it's display property changes, but it is only required to run if we actually have animations to play or cancel. Reduces time spent in the aforementioned function from ~2% to ~0.03% when loading https://en.wikipedia.org/wiki/2023_in_American_television --- Libraries/LibWeb/Animations/Animatable.cpp | 13 +++++++++++++ Libraries/LibWeb/Animations/Animatable.h | 3 +++ Libraries/LibWeb/CSS/StyleComputer.cpp | 1 + Libraries/LibWeb/DOM/Element.cpp | 4 ++++ 4 files changed, 21 insertions(+) diff --git a/Libraries/LibWeb/Animations/Animatable.cpp b/Libraries/LibWeb/Animations/Animatable.cpp index 2980bf21683..051c7d1ee20 100644 --- a/Libraries/LibWeb/Animations/Animatable.cpp +++ b/Libraries/LibWeb/Animations/Animatable.cpp @@ -279,6 +279,19 @@ void Animatable::visit_edges(JS::Cell::Visitor& visitor) } } +void Animatable::set_has_css_defined_animations() +{ + ensure_impl().has_css_defined_animations = true; +} + +bool Animatable::has_css_defined_animations() const +{ + if (!m_impl) + return false; + + return m_impl->has_css_defined_animations; +} + HashMap>* Animatable::css_defined_animations(Optional pseudo_element) { auto& impl = ensure_impl(); diff --git a/Libraries/LibWeb/Animations/Animatable.h b/Libraries/LibWeb/Animations/Animatable.h index ac0366cc09e..2929ddc9a9e 100644 --- a/Libraries/LibWeb/Animations/Animatable.h +++ b/Libraries/LibWeb/Animations/Animatable.h @@ -52,6 +52,8 @@ public: void associate_with_animation(GC::Ref); void disassociate_with_animation(GC::Ref); + void set_has_css_defined_animations(); + bool has_css_defined_animations() const; HashMap>* css_defined_animations(Optional); void add_css_animation(FlyString name, Optional, GC::Ref); void remove_css_animation(FlyString name, Optional); @@ -79,6 +81,7 @@ private: struct Impl { Vector> associated_animations; bool is_sorted_by_composite_order { true }; + bool has_css_defined_animations { false }; mutable Array>>, to_underlying(CSS::PseudoElement::KnownPseudoElementCount) + 1> css_defined_animations; mutable Array, to_underlying(CSS::PseudoElement::KnownPseudoElementCount) + 1> transitions; diff --git a/Libraries/LibWeb/CSS/StyleComputer.cpp b/Libraries/LibWeb/CSS/StyleComputer.cpp index e156b7496ce..179a931046f 100644 --- a/Libraries/LibWeb/CSS/StyleComputer.cpp +++ b/Libraries/LibWeb/CSS/StyleComputer.cpp @@ -1266,6 +1266,7 @@ void StyleComputer::process_animation_definitions(ComputedProperties const& comp } effect->set_target(&element); + element.set_has_css_defined_animations(); element_animations->set(animation_properties.name, animation); } diff --git a/Libraries/LibWeb/DOM/Element.cpp b/Libraries/LibWeb/DOM/Element.cpp index 7dfd3d28a81..df5c8c124b6 100644 --- a/Libraries/LibWeb/DOM/Element.cpp +++ b/Libraries/LibWeb/DOM/Element.cpp @@ -4177,6 +4177,10 @@ FlyString const& Element::html_uppercased_qualified_name() const void Element::play_or_cancel_animations_after_display_property_change() { + // OPTIMIZATION: We don't care about elements with no CSS defined animations + if (!has_css_defined_animations()) + return; + // OPTIMIZATION: We don't care about animations in disconnected subtrees. if (!is_connected()) return;