LibWeb: Support triggering multiple animations per animation property

We also now use the computed (rather than cascaded) values when
triggering animations.
This commit is contained in:
Callum Law 2025-10-26 18:44:31 +13:00 committed by Sam Atkins
parent 18477b0d84
commit 84762021b8
Notes: github-actions[bot] 2025-10-27 09:49:34 +00:00
11 changed files with 322 additions and 231 deletions

View file

@ -246,10 +246,11 @@ void Animatable::visit_edges(JS::Cell::Visitor& visitor)
{
auto& impl = ensure_impl();
visitor.visit(impl.associated_animations);
for (auto const& cached_animation_source : impl.cached_animation_name_source)
visitor.visit(cached_animation_source);
for (auto const& cached_animation_name : impl.cached_animation_name_animation)
visitor.visit(cached_animation_name);
for (auto const& css_animation : impl.css_defined_animations) {
if (css_animation)
visitor.visit(*css_animation);
}
for (auto const& transition : impl.transitions) {
if (transition) {
visitor.visit(transition->cached_transition_property_source);
@ -258,61 +259,21 @@ void Animatable::visit_edges(JS::Cell::Visitor& visitor)
}
}
GC::Ptr<CSS::CSSStyleDeclaration const> Animatable::cached_animation_name_source(Optional<CSS::PseudoElement> pseudo_element) const
{
if (!m_impl)
return {};
auto& impl = *m_impl;
if (pseudo_element.has_value()) {
if (!CSS::Selector::PseudoElementSelector::is_known_pseudo_element_type(pseudo_element.value())) {
return {};
}
return impl.cached_animation_name_source[to_underlying(pseudo_element.value()) + 1];
}
return impl.cached_animation_name_source[0];
}
void Animatable::set_cached_animation_name_source(GC::Ptr<CSS::CSSStyleDeclaration const> value, Optional<CSS::PseudoElement> pseudo_element)
HashMap<FlyString, GC::Ref<Animation>>* Animatable::css_defined_animations(Optional<CSS::PseudoElement> pseudo_element)
{
auto& impl = ensure_impl();
if (pseudo_element.has_value()) {
if (!CSS::Selector::PseudoElementSelector::is_known_pseudo_element_type(pseudo_element.value())) {
return;
}
impl.cached_animation_name_source[to_underlying(pseudo_element.value()) + 1] = value;
} else {
impl.cached_animation_name_source[0] = value;
}
}
GC::Ptr<Animations::Animation> Animatable::cached_animation_name_animation(Optional<CSS::PseudoElement> pseudo_element) const
{
if (!m_impl)
return {};
auto& impl = *m_impl;
if (pseudo_element.has_value() && !CSS::Selector::PseudoElementSelector::is_known_pseudo_element_type(pseudo_element.value()))
return nullptr;
if (pseudo_element.has_value()) {
if (!CSS::Selector::PseudoElementSelector::is_known_pseudo_element_type(pseudo_element.value())) {
return {};
}
auto index = pseudo_element
.map([](CSS::PseudoElement pseudo_element_value) { return to_underlying(pseudo_element_value) + 1; })
.value_or(0);
return impl.cached_animation_name_animation[to_underlying(pseudo_element.value()) + 1];
}
return impl.cached_animation_name_animation[0];
}
if (!impl.css_defined_animations[index])
impl.css_defined_animations[index] = make<HashMap<FlyString, GC::Ref<Animation>>>();
void Animatable::set_cached_animation_name_animation(GC::Ptr<Animations::Animation> value, Optional<CSS::PseudoElement> pseudo_element)
{
auto& impl = ensure_impl();
if (pseudo_element.has_value()) {
if (!CSS::Selector::PseudoElementSelector::is_known_pseudo_element_type(pseudo_element.value())) {
return;
}
impl.cached_animation_name_animation[to_underlying(pseudo_element.value()) + 1] = value;
} else {
impl.cached_animation_name_animation[0] = value;
}
return impl.css_defined_animations[index];
}
GC::Ptr<CSS::CSSStyleDeclaration const> Animatable::cached_transition_property_source(Optional<CSS::PseudoElement> pseudo_element) const

View file

@ -52,11 +52,9 @@ public:
void associate_with_animation(GC::Ref<Animation>);
void disassociate_with_animation(GC::Ref<Animation>);
GC::Ptr<CSS::CSSStyleDeclaration const> cached_animation_name_source(Optional<CSS::PseudoElement>) const;
void set_cached_animation_name_source(GC::Ptr<CSS::CSSStyleDeclaration const> value, Optional<CSS::PseudoElement>);
GC::Ptr<Animations::Animation> cached_animation_name_animation(Optional<CSS::PseudoElement>) const;
void set_cached_animation_name_animation(GC::Ptr<Animations::Animation> value, Optional<CSS::PseudoElement>);
HashMap<FlyString, GC::Ref<Animation>>* css_defined_animations(Optional<CSS::PseudoElement>);
void add_css_animation(FlyString name, Optional<CSS::PseudoElement>, GC::Ref<Animation>);
void remove_css_animation(FlyString name, Optional<CSS::PseudoElement>);
GC::Ptr<CSS::CSSStyleDeclaration const> cached_transition_property_source(Optional<CSS::PseudoElement>) const;
void set_cached_transition_property_source(Optional<CSS::PseudoElement>, GC::Ptr<CSS::CSSStyleDeclaration const> value);
@ -80,9 +78,7 @@ private:
Vector<GC::Ref<Animation>> associated_animations;
bool is_sorted_by_composite_order { true };
Array<GC::Ptr<CSS::CSSStyleDeclaration const>, to_underlying(CSS::PseudoElement::KnownPseudoElementCount) + 1> cached_animation_name_source;
Array<GC::Ptr<Animation>, to_underlying(CSS::PseudoElement::KnownPseudoElementCount) + 1> cached_animation_name_animation;
mutable Array<OwnPtr<HashMap<FlyString, GC::Ref<Animation>>>, to_underlying(CSS::PseudoElement::KnownPseudoElementCount) + 1> css_defined_animations;
mutable Array<OwnPtr<Transition>, to_underlying(CSS::PseudoElement::KnownPseudoElementCount) + 1> transitions;
~Impl();