LibWeb: Ensure registered transitions are reflective of properties

Previously we would only update these if:
a) We had a cascaded value for `transition-property`
b) The source of that cascaded value had changed since we last
   registered transitions

This meant that there were a lot of changes we didn't apply:
 - Changes exclusively to properties other than `transition-property`
   (e.g. `transition-duration`, `transition-behavior`, etc)
 - Removing the `transition-property` property
 - Updating the `transition-property` property in a way that didn't
   change it's source (e.g. setting it within inline-style)

Unfortunately this does mean that we now register transitions for all
properties on most elements since "all" is the initial value for
"transition-property" which isn't great for performance, but that can be
looked at in later commits.
This commit is contained in:
Callum Law 2025-11-18 22:15:15 +13:00 committed by Jelle Raaijmakers
parent 46abc0e8e2
commit b2b889e1da
Notes: github-actions[bot] 2025-11-23 08:44:36 +00:00
13 changed files with 98 additions and 45 deletions

View file

@ -22,7 +22,6 @@ namespace Web::Animations {
struct Animatable::Transition {
HashMap<CSS::PropertyID, size_t> transition_attribute_indices;
Vector<TransitionAttributes> transition_attributes;
GC::Ptr<CSS::CSSStyleDeclaration const> cached_transition_property_source;
HashMap<CSS::PropertyID, GC::Ref<CSS::CSSTransition>> associated_transitions;
};
@ -255,7 +254,6 @@ void Animatable::visit_edges(JS::Cell::Visitor& visitor)
for (auto const& transition : impl.transitions) {
if (transition) {
visitor.visit(transition->cached_transition_property_source);
visitor.visit(transition->associated_transitions);
}
}
@ -291,22 +289,6 @@ HashMap<FlyString, GC::Ref<Animation>>* Animatable::css_defined_animations(Optio
return impl.css_defined_animations[index];
}
GC::Ptr<CSS::CSSStyleDeclaration const> Animatable::cached_transition_property_source(Optional<CSS::PseudoElement> pseudo_element) const
{
auto* maybe_transition = ensure_transition(pseudo_element);
if (!maybe_transition)
return {};
return maybe_transition->cached_transition_property_source;
}
void Animatable::set_cached_transition_property_source(Optional<CSS::PseudoElement> pseudo_element, GC::Ptr<CSS::CSSStyleDeclaration const> value)
{
auto* maybe_transition = ensure_transition(pseudo_element);
if (!maybe_transition)
return;
maybe_transition->cached_transition_property_source = value;
}
Animatable::Impl& Animatable::ensure_impl() const
{
if (!m_impl)

View file

@ -58,9 +58,6 @@ public:
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);
void add_transitioned_properties(Optional<CSS::PseudoElement>, Vector<Vector<CSS::PropertyID>> properties, CSS::StyleValueVector delays, CSS::StyleValueVector durations, CSS::StyleValueVector timing_functions, CSS::StyleValueVector transition_behaviors);
Vector<CSS::PropertyID> property_ids_with_matching_transition_property_entry(Optional<CSS::PseudoElement>) const;
Optional<TransitionAttributes const&> property_transition_attributes(Optional<CSS::PseudoElement>, CSS::PropertyID) const;

View file

@ -55,7 +55,6 @@ ComputedProperties::~ComputedProperties() = default;
void ComputedProperties::visit_edges(Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_transition_property_source);
}
bool ComputedProperties::is_property_important(PropertyID property_id) const

View file

@ -70,9 +70,6 @@ public:
StyleValue const& property(PropertyID, WithAnimationsApplied = WithAnimationsApplied::Yes) const;
void revert_property(PropertyID, ComputedProperties const& style_for_revert);
GC::Ptr<CSSStyleDeclaration const> transition_property_source() const { return m_transition_property_source; }
void set_transition_property_source(GC::Ptr<CSSStyleDeclaration const> declaration) { m_transition_property_source = declaration; }
Size size_value(PropertyID) const;
[[nodiscard]] Variant<LengthPercentage, NormalGap> gap_value(PropertyID) const;
Length length(PropertyID) const;
@ -291,8 +288,6 @@ private:
Vector<ShadowData> shadow(PropertyID, Layout::Node const&) const;
Position position_value(PropertyID) const;
GC::Ptr<CSSStyleDeclaration const> m_transition_property_source;
Array<RefPtr<StyleValue const>, number_of_longhand_properties> m_property_values;
Array<u8, ceil_div(number_of_longhand_properties, 8uz)> m_property_important {};
Array<u8, ceil_div(number_of_longhand_properties, 8uz)> m_property_inherited {};

View file

@ -1221,19 +1221,15 @@ static void apply_dimension_attribute(CascadedProperties& cascaded_properties, D
static void compute_transitioned_properties(ComputedProperties const& style, DOM::AbstractElement abstract_element)
{
auto const source_declaration = style.transition_property_source();
if (!source_declaration)
return;
// FIXME: For now we don't bother registering transitions on the first computation since they can't run (because
// there is nothing to transition from) but this will change once we implement @starting-style
if (!abstract_element.computed_properties())
return;
// FIXME: Add transition helpers on AbstractElement.
auto& element = abstract_element.element();
auto pseudo_element = abstract_element.pseudo_element();
if (source_declaration == element.cached_transition_property_source(pseudo_element))
return;
// Reparse this transition property
element.clear_registered_transitions(pseudo_element);
element.set_cached_transition_property_source(pseudo_element, *source_declaration);
auto coordinated_transition_list = style.assemble_coordinated_value_list(
PropertyID::TransitionProperty,
@ -2541,10 +2537,6 @@ GC::Ref<ComputedProperties> StyleComputer::compute_properties(DOM::AbstractEleme
computed_style->set_property(property_id, value.release_nonnull(), inherited, cascaded_properties.is_property_important(property_id) ? Important::Yes : Important::No);
if (animated_value.has_value())
computed_style->set_animated_property(property_id, animated_value.value(), inherited);
if (property_id == PropertyID::TransitionProperty) {
computed_style->set_transition_property_source(cascaded_properties.property_source(property_id));
}
}
// Compute the value of custom properties