diff --git a/Userland/Libraries/LibWeb/Animations/Animation.cpp b/Userland/Libraries/LibWeb/Animations/Animation.cpp index cb6a503fcc1..a64b851ee40 100644 --- a/Userland/Libraries/LibWeb/Animations/Animation.cpp +++ b/Userland/Libraries/LibWeb/Animations/Animation.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -1315,8 +1316,8 @@ JS::NonnullGCPtr Animation::current_finished_promise() const void Animation::invalidate_effect() { if (m_effect) { - if (auto target = m_effect->target()) - target->invalidate_style(); + if (auto target = m_effect->target(); target && target->paintable()) + target->paintable()->set_needs_display(); } } diff --git a/Userland/Libraries/LibWeb/Animations/AnimationEffect.h b/Userland/Libraries/LibWeb/Animations/AnimationEffect.h index ec6e2454fe8..1e0a061862a 100644 --- a/Userland/Libraries/LibWeb/Animations/AnimationEffect.h +++ b/Userland/Libraries/LibWeb/Animations/AnimationEffect.h @@ -146,6 +146,8 @@ public: virtual DOM::Element* target() const { return {}; } virtual bool is_keyframe_effect() const { return false; } + virtual void update_style_properties() = 0; + protected: AnimationEffect(JS::Realm&); virtual ~AnimationEffect() = default; diff --git a/Userland/Libraries/LibWeb/Animations/KeyframeEffect.cpp b/Userland/Libraries/LibWeb/Animations/KeyframeEffect.cpp index 9fdc1a65223..71a12cb2dbb 100644 --- a/Userland/Libraries/LibWeb/Animations/KeyframeEffect.cpp +++ b/Userland/Libraries/LibWeb/Animations/KeyframeEffect.cpp @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include namespace Web::Animations { @@ -869,4 +871,56 @@ void KeyframeEffect::visit_edges(Cell::Visitor& visitor) visitor.visit(keyframe); } +void KeyframeEffect::update_style_properties() +{ + if (!target()) + return; + + if (pseudo_element_type().has_value()) { + // StyleProperties are not saved for pseudo-elements so there is nothing to patch + target()->invalidate_style(); + return; + } + + auto* style = target()->computed_css_values(); + if (!style) + return; + + auto style_before_animation_update = style->clone(); + + auto& document = target()->document(); + document.style_computer().collect_animation_into(*this, *style, CSS::StyleComputer::AnimationRefresh::Yes); + + // Traversal of the subtree is necessary to update the animated properties inherited from the target element. + target()->for_each_in_subtree_of_type([&](auto& element) { + auto* element_style = element.computed_css_values(); + if (!element_style || !element.layout_node()) + return IterationDecision::Continue; + + for (auto i = to_underlying(CSS::first_property_id); i <= to_underlying(CSS::last_property_id); ++i) { + if (element_style->is_property_inherited(static_cast(i))) { + auto new_value = CSS::StyleComputer::get_inherit_value(document.realm(), static_cast(i), &element); + element_style->set_property(static_cast(i), *new_value, nullptr, CSS::StyleProperties::Inherited::Yes); + } + } + + element.layout_node()->apply_style(*element_style); + return IterationDecision::Continue; + }); + + auto invalidation = DOM::Element::compute_required_invalidation(style_before_animation_update, *style); + + if (target()->layout_node()) + target()->layout_node()->apply_style(*style); + + if (invalidation.relayout) + document.set_needs_layout(); + if (invalidation.rebuild_layout_tree) + document.invalidate_layout(); + if (invalidation.repaint) + document.set_needs_to_resolve_paint_only_properties(); + if (invalidation.rebuild_stacking_context_tree) + document.invalidate_stacking_context_tree(); +} + } diff --git a/Userland/Libraries/LibWeb/Animations/KeyframeEffect.h b/Userland/Libraries/LibWeb/Animations/KeyframeEffect.h index 5b1707962e8..5ce0e59e647 100644 --- a/Userland/Libraries/LibWeb/Animations/KeyframeEffect.h +++ b/Userland/Libraries/LibWeb/Animations/KeyframeEffect.h @@ -103,6 +103,8 @@ public: virtual bool is_keyframe_effect() const override { return true; } + virtual void update_style_properties() override; + private: KeyframeEffect(JS::Realm&); virtual ~KeyframeEffect() override = default; diff --git a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp index a59c636ff02..e8b41cd170a 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp @@ -90,7 +90,6 @@ struct Traits : public DefaultTraits); -static NonnullRefPtr get_inherit_value(JS::Realm& initial_value_context_realm, CSS::PropertyID, DOM::Element const*, Optional); StyleComputer::StyleComputer(DOM::Document& document) : m_document(document) @@ -668,26 +667,27 @@ void StyleComputer::for_each_property_expanding_shorthands(PropertyID property_i set_longhand_property(property_id, value); } -void StyleComputer::set_property_expanding_shorthands(StyleProperties& style, CSS::PropertyID property_id, StyleValue const& value, CSS::CSSStyleDeclaration const* declaration, StyleProperties::PropertyValues const& properties_for_revert) +void StyleComputer::set_property_expanding_shorthands(StyleProperties& style, CSS::PropertyID property_id, StyleValue const& value, CSS::CSSStyleDeclaration const* declaration, StyleProperties::PropertyValues const& properties_for_revert, StyleProperties::Important important) { for_each_property_expanding_shorthands(property_id, value, [&](PropertyID shorthand_id, StyleValue const& shorthand_value) { if (shorthand_value.is_revert()) { auto& property_in_previous_cascade_origin = properties_for_revert[to_underlying(shorthand_id)]; if (property_in_previous_cascade_origin.has_value()) - style.set_property(shorthand_id, property_in_previous_cascade_origin->style, property_in_previous_cascade_origin->declaration); + style.set_property(shorthand_id, property_in_previous_cascade_origin->style, property_in_previous_cascade_origin->declaration, StyleProperties::Inherited::No, important); } else { - style.set_property(shorthand_id, shorthand_value, declaration); + style.set_property(shorthand_id, shorthand_value, declaration, StyleProperties::Inherited::No, important); } }); } -void StyleComputer::set_all_properties(DOM::Element& element, Optional pseudo_element, StyleProperties& style, StyleValue const& value, DOM::Document& document, CSS::CSSStyleDeclaration const* declaration, StyleProperties::PropertyValues const& properties_for_revert) const +void StyleComputer::set_all_properties(DOM::Element& element, Optional pseudo_element, StyleProperties& style, StyleValue const& value, DOM::Document& document, CSS::CSSStyleDeclaration const* declaration, StyleProperties::PropertyValues const& properties_for_revert, StyleProperties::Important important) const { for (auto i = to_underlying(CSS::first_longhand_property_id); i <= to_underlying(CSS::last_longhand_property_id); ++i) { auto property_id = (CSS::PropertyID)i; if (value.is_revert()) { style.m_property_values[to_underlying(property_id)] = properties_for_revert[to_underlying(property_id)]; + style.m_property_values[to_underlying(property_id)]->important = important; continue; } @@ -696,6 +696,7 @@ void StyleComputer::set_all_properties(DOM::Element& element, Optionalimportant = important; continue; } @@ -705,7 +706,9 @@ void StyleComputer::set_all_properties(DOM::Element& element, Optionalis_unresolved()) set_property_expanding_shorthands(style, property_id, property_value, declaration, properties_for_revert); - set_property_expanding_shorthands(style, property_id, value, declaration, properties_for_revert); + style.m_property_values[to_underlying(property_id)]->important = important; + + set_property_expanding_shorthands(style, property_id, value, declaration, properties_for_revert, important); } } @@ -719,7 +722,7 @@ void StyleComputer::cascade_declarations(StyleProperties& style, DOM::Element& e continue; if (property.property_id == CSS::PropertyID::All) { - set_all_properties(element, pseudo_element, style, property.value, m_document, &match.rule->declaration(), properties_for_revert); + set_all_properties(element, pseudo_element, style, property.value, m_document, &match.rule->declaration(), properties_for_revert, important == Important::Yes ? StyleProperties::Important::Yes : StyleProperties::Important::No); continue; } @@ -727,7 +730,7 @@ void StyleComputer::cascade_declarations(StyleProperties& style, DOM::Element& e if (property.value->is_unresolved()) property_value = Parser::Parser::resolve_unresolved_style_value({}, Parser::ParsingContext { document() }, element, pseudo_element, property.property_id, property.value->as_unresolved()); if (!property_value->is_unresolved()) - set_property_expanding_shorthands(style, property.property_id, property_value, &match.rule->declaration(), properties_for_revert); + set_property_expanding_shorthands(style, property.property_id, property_value, &match.rule->declaration(), properties_for_revert, important == Important::Yes ? StyleProperties::Important::Yes : StyleProperties::Important::No); } } @@ -738,7 +741,7 @@ void StyleComputer::cascade_declarations(StyleProperties& style, DOM::Element& e continue; if (property.property_id == CSS::PropertyID::All) { - set_all_properties(element, pseudo_element, style, property.value, m_document, inline_style, properties_for_revert); + set_all_properties(element, pseudo_element, style, property.value, m_document, inline_style, properties_for_revert, important == Important::Yes ? StyleProperties::Important::Yes : StyleProperties::Important::No); continue; } @@ -746,7 +749,7 @@ void StyleComputer::cascade_declarations(StyleProperties& style, DOM::Element& e if (property.value->is_unresolved()) property_value = Parser::Parser::resolve_unresolved_style_value({}, Parser::ParsingContext { document() }, element, pseudo_element, property.property_id, property.value->as_unresolved()); if (!property_value->is_unresolved()) - set_property_expanding_shorthands(style, property.property_id, property_value, inline_style, properties_for_revert); + set_property_expanding_shorthands(style, property.property_id, property_value, inline_style, properties_for_revert, important == Important::Yes ? StyleProperties::Important::Yes : StyleProperties::Important::No); } } } @@ -1276,7 +1279,7 @@ static ValueComparingRefPtr interpolate_property(DOM::Element& } } -void StyleComputer::collect_animation_into(JS::NonnullGCPtr effect, StyleProperties& style_properties) const +void StyleComputer::collect_animation_into(JS::NonnullGCPtr effect, StyleProperties& style_properties, AnimationRefresh refresh) const { auto animation = effect->associated_animation(); if (!animation) @@ -1329,6 +1332,8 @@ void StyleComputer::collect_animation_into(JS::NonnullGCPtr RefPtr { + if (refresh == AnimationRefresh::Yes) + return {}; return style_properties.maybe_null_property(it.key); }, [&](RefPtr value) { return value; }); @@ -1339,7 +1344,7 @@ void StyleComputer::collect_animation_into(JS::NonnullGCPtrto_string()); } continue; @@ -1356,13 +1361,17 @@ void StyleComputer::collect_animation_into(JS::NonnullGCPtrtarget(), it.key, *start, *end, progress_in_keyframe)) { dbgln_if(LIBWEB_CSS_ANIMATION_DEBUG, "Interpolated value for property {} at {}: {} -> {} = {}", string_from_property_id(it.key), progress_in_keyframe, start->to_string(), end->to_string(), next_value->to_string()); - style_properties.set_property(it.key, *next_value); + style_properties.set_animated_property(it.key, *next_value); } else { // If interpolate_property() fails, the element should not be rendered dbgln_if(LIBWEB_CSS_ANIMATION_DEBUG, "Interpolated value for property {} at {}: {} -> {} is invalid", string_from_property_id(it.key), progress_in_keyframe, start->to_string(), end->to_string()); - style_properties.set_property(PropertyID::Visibility, IdentifierStyleValue::create(ValueID::Hidden)); + style_properties.set_animated_property(PropertyID::Visibility, IdentifierStyleValue::create(ValueID::Hidden)); } } } @@ -1570,7 +1579,7 @@ DOM::Element const* element_to_inherit_style_from(DOM::Element const* element, O return parent_element; } -NonnullRefPtr get_inherit_value(JS::Realm& initial_value_context_realm, CSS::PropertyID property_id, DOM::Element const* element, Optional pseudo_element) +NonnullRefPtr StyleComputer::get_inherit_value(JS::Realm& initial_value_context_realm, CSS::PropertyID property_id, DOM::Element const* element, Optional pseudo_element) { auto* parent_element = element_to_inherit_style_from(element, pseudo_element); @@ -1586,7 +1595,7 @@ void StyleComputer::compute_defaulted_property_value(StyleProperties& style, DOM auto& value_slot = style.m_property_values[to_underlying(property_id)]; if (!value_slot.has_value()) { if (is_inherited_property(property_id)) - style.m_property_values[to_underlying(property_id)] = { { get_inherit_value(document().realm(), property_id, element, pseudo_element), nullptr } }; + style.m_property_values[to_underlying(property_id)] = { { get_inherit_value(document().realm(), property_id, element, pseudo_element), nullptr, StyleProperties::Important::No, StyleProperties::Inherited::Yes } }; else style.m_property_values[to_underlying(property_id)] = { { property_initial_value(document().realm(), property_id), nullptr } }; return; @@ -1599,6 +1608,7 @@ void StyleComputer::compute_defaulted_property_value(StyleProperties& style, DOM if (value_slot->style->is_inherit()) { value_slot->style = get_inherit_value(document().realm(), property_id, element, pseudo_element); + value_slot->inherited = StyleProperties::Inherited::Yes; return; } @@ -1608,6 +1618,7 @@ void StyleComputer::compute_defaulted_property_value(StyleProperties& style, DOM if (is_inherited_property(property_id)) { // then if it is an inherited property, this is treated as inherit, value_slot->style = get_inherit_value(document().realm(), property_id, element, pseudo_element); + value_slot->inherited = StyleProperties::Inherited::Yes; } else { // and if it is not, this is treated as initial. value_slot->style = property_initial_value(document().realm(), property_id); diff --git a/Userland/Libraries/LibWeb/CSS/StyleComputer.h b/Userland/Libraries/LibWeb/CSS/StyleComputer.h index cf5d60ffdd3..61e14f4f110 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleComputer.h +++ b/Userland/Libraries/LibWeb/CSS/StyleComputer.h @@ -55,7 +55,8 @@ struct FontFaceKey { class StyleComputer { public: static void for_each_property_expanding_shorthands(PropertyID, StyleValue const&, Function const& set_longhand_property); - static void set_property_expanding_shorthands(StyleProperties&, PropertyID, StyleValue const&, CSS::CSSStyleDeclaration const*, StyleProperties::PropertyValues const& properties_for_revert); + static void set_property_expanding_shorthands(StyleProperties&, PropertyID, StyleValue const&, CSS::CSSStyleDeclaration const*, StyleProperties::PropertyValues const& properties_for_revert, StyleProperties::Important = StyleProperties::Important::No); + static NonnullRefPtr get_inherit_value(JS::Realm& initial_value_context_realm, CSS::PropertyID, DOM::Element const*, Optional = {}); explicit StyleComputer(DOM::Document&); ~StyleComputer(); @@ -82,6 +83,12 @@ public: void set_viewport_rect(Badge, CSSPixelRect const& viewport_rect) { m_viewport_rect = viewport_rect; } + enum class AnimationRefresh { + No, + Yes, + }; + void collect_animation_into(JS::NonnullGCPtr animation, StyleProperties& style_properties, AnimationRefresh = AnimationRefresh::No) const; + private: enum class ComputeStyleMode { Normal, @@ -105,7 +112,7 @@ private: void compute_defaulted_property_value(StyleProperties&, DOM::Element const*, CSS::PropertyID, Optional) const; - void set_all_properties(DOM::Element&, Optional, StyleProperties&, StyleValue const&, DOM::Document&, CSS::CSSStyleDeclaration const*, StyleProperties::PropertyValues const& properties_for_revert) const; + void set_all_properties(DOM::Element&, Optional, StyleProperties&, StyleValue const&, DOM::Document&, CSS::CSSStyleDeclaration const*, StyleProperties::PropertyValues const& properties_for_revert, StyleProperties::Important = StyleProperties::Important::No) const; template void for_each_stylesheet(CascadeOrigin, Callback) const; @@ -142,8 +149,6 @@ private: RuleCache const& rule_cache_for_cascade_origin(CascadeOrigin) const; - void collect_animation_into(JS::NonnullGCPtr animation, StyleProperties& style_properties) const; - OwnPtr m_author_rule_cache; OwnPtr m_user_rule_cache; OwnPtr m_user_agent_rule_cache; diff --git a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp index 794365752e0..3448fcf2ab5 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp @@ -34,13 +34,49 @@ namespace Web::CSS { -void StyleProperties::set_property(CSS::PropertyID id, NonnullRefPtr value, CSS::CSSStyleDeclaration const* source_declaration) +NonnullRefPtr StyleProperties::clone() const { - m_property_values[to_underlying(id)] = StyleAndSourceDeclaration { move(value), source_declaration }; + auto clone = adopt_ref(*new StyleProperties); + clone->m_property_values = m_property_values; + clone->m_animated_property_values = m_animated_property_values; + clone->m_font_list = m_font_list; + clone->m_line_height = m_line_height; + clone->m_math_depth = m_math_depth; + return clone; +} + +bool StyleProperties::is_property_important(CSS::PropertyID property_id) const +{ + return m_property_values[to_underlying(property_id)].has_value() && m_property_values[to_underlying(property_id)]->important == Important::Yes; +} + +bool StyleProperties::is_property_inherited(CSS::PropertyID property_id) const +{ + return m_property_values[to_underlying(property_id)].has_value() && m_property_values[to_underlying(property_id)]->inherited == Inherited::Yes; +} + +void StyleProperties::set_property(CSS::PropertyID id, NonnullRefPtr value, CSS::CSSStyleDeclaration const* source_declaration, Inherited inherited, Important important) +{ + m_property_values[to_underlying(id)] = StyleAndSourceDeclaration { move(value), source_declaration, important, inherited }; +} + +void StyleProperties::set_animated_property(CSS::PropertyID id, NonnullRefPtr value) +{ + m_animated_property_values[to_underlying(id)] = move(value); +} + +void StyleProperties::reset_animated_properties() +{ + for (auto& animated_property : m_animated_property_values) + animated_property.clear(); } NonnullRefPtr StyleProperties::property(CSS::PropertyID property_id) const { + auto animated_value = m_animated_property_values[to_underlying(property_id)]; + if (animated_value.has_value()) + return *animated_value; + auto value = m_property_values[to_underlying(property_id)]; // By the time we call this method, all properties have values assigned. VERIFY(value.has_value()); @@ -49,6 +85,10 @@ NonnullRefPtr StyleProperties::property(CSS::PropertyID proper RefPtr StyleProperties::maybe_null_property(CSS::PropertyID property_id) const { + auto animated_value = m_animated_property_values[to_underlying(property_id)]; + if (animated_value.has_value()) + return *animated_value; + auto value = m_property_values[to_underlying(property_id)]; if (value.has_value()) return value->style; diff --git a/Userland/Libraries/LibWeb/CSS/StyleProperties.h b/Userland/Libraries/LibWeb/CSS/StyleProperties.h index 7518f6fa894..8f04378d355 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleProperties.h +++ b/Userland/Libraries/LibWeb/CSS/StyleProperties.h @@ -23,6 +23,8 @@ public: static NonnullRefPtr create() { return adopt_ref(*new StyleProperties); } + NonnullRefPtr clone() const; + template inline void for_each_property(Callback callback) const { @@ -32,16 +34,34 @@ public: } } + enum class Important { + No, + Yes + }; + + enum class Inherited { + No, + Yes + }; + struct StyleAndSourceDeclaration { NonnullRefPtr style; CSS::CSSStyleDeclaration const* declaration = nullptr; + Important important { Important::No }; + Inherited inherited { Inherited::No }; }; using PropertyValues = Array, to_underlying(CSS::last_property_id) + 1>; auto& properties() { return m_property_values; } auto const& properties() const { return m_property_values; } - void set_property(CSS::PropertyID, NonnullRefPtr value, CSS::CSSStyleDeclaration const* source_declaration = nullptr); + void reset_animated_properties(); + + bool is_property_important(CSS::PropertyID property_id) const; + bool is_property_inherited(CSS::PropertyID property_id) const; + + void set_property(CSS::PropertyID, NonnullRefPtr value, CSS::CSSStyleDeclaration const* source_declaration = nullptr, Inherited = Inherited::No, Important = Important::No); + void set_animated_property(CSS::PropertyID, NonnullRefPtr value); NonnullRefPtr property(CSS::PropertyID) const; RefPtr maybe_null_property(CSS::PropertyID) const; CSS::CSSStyleDeclaration const* property_source_declaration(CSS::PropertyID) const; @@ -166,6 +186,8 @@ private: friend class StyleComputer; PropertyValues m_property_values; + Array>, to_underlying(CSS::last_property_id) + 1> m_animated_property_values; + Optional overflow(CSS::PropertyID) const; Vector shadow(CSS::PropertyID, Layout::Node const&) const; diff --git a/Userland/Libraries/LibWeb/DOM/Document.cpp b/Userland/Libraries/LibWeb/DOM/Document.cpp index 5a0da0a2b90..5d0c0be217f 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.cpp +++ b/Userland/Libraries/LibWeb/DOM/Document.cpp @@ -1163,6 +1163,19 @@ void Document::update_style() { if (!browsing_context()) return; + + for (auto& timeline : m_associated_animation_timelines) { + for (auto& animation : timeline->associated_animations()) { + if (auto effect = animation->effect(); effect && effect->target()) + effect->target()->reset_animated_css_properties(); + } + + for (auto& animation : timeline->associated_animations()) { + if (auto effect = animation->effect()) + effect->update_style_properties(); + } + } + if (!needs_full_style_update() && !needs_style_update() && !child_needs_style_update()) return; @@ -1917,7 +1930,8 @@ void Document::dispatch_events_for_animation_if_necessary(JS::NonnullGCPtr(*animation); - css_animation.owning_element()->set_needs_style_update(true); + if (auto target = effect->target(); target && target->paintable()) + target->paintable()->set_needs_display(); auto previous_phase = effect->previous_phase(); auto current_phase = effect->phase(); diff --git a/Userland/Libraries/LibWeb/DOM/Element.cpp b/Userland/Libraries/LibWeb/DOM/Element.cpp index 4b04d89bcfa..525081f6e33 100644 --- a/Userland/Libraries/LibWeb/DOM/Element.cpp +++ b/Userland/Libraries/LibWeb/DOM/Element.cpp @@ -510,7 +510,7 @@ void Element::attribute_changed(FlyString const& name, Optional const& v } } -static Element::RequiredInvalidationAfterStyleChange compute_required_invalidation(CSS::StyleProperties const& old_style, CSS::StyleProperties const& new_style) +Element::RequiredInvalidationAfterStyleChange Element::compute_required_invalidation(CSS::StyleProperties const& old_style, CSS::StyleProperties const& new_style) { Element::RequiredInvalidationAfterStyleChange invalidation; @@ -519,12 +519,12 @@ static Element::RequiredInvalidationAfterStyleChange compute_required_invalidati for (auto i = to_underlying(CSS::first_property_id); i <= to_underlying(CSS::last_property_id); ++i) { auto property_id = static_cast(i); - auto const& old_value = old_style.properties()[i]; - auto const& new_value = new_style.properties()[i]; - if (!old_value.has_value() && !new_value.has_value()) + auto old_value = old_style.maybe_null_property(property_id); + auto new_value = new_style.maybe_null_property(property_id); + if (!old_value && !new_value) continue; - bool const property_value_changed = (!old_value.has_value() || !new_value.has_value()) || *old_value->style != *new_value->style; + bool const property_value_changed = (!old_value || !new_value) || *old_value != *new_value; if (!property_value_changed) continue; @@ -544,7 +544,7 @@ static Element::RequiredInvalidationAfterStyleChange compute_required_invalidati // OPTIMIZATION: Special handling for CSS `visibility`: if (property_id == CSS::PropertyID::Visibility) { // We don't need to relayout if the visibility changes from visible to hidden or vice versa. Only collapse requires relayout. - if ((old_value.has_value() && old_value->style->to_identifier() == CSS::ValueID::Collapse) != (new_value.has_value() && new_value->style->to_identifier() == CSS::ValueID::Collapse)) + if ((old_value && old_value->to_identifier() == CSS::ValueID::Collapse) != (new_value && new_value->to_identifier() == CSS::ValueID::Collapse)) invalidation.relayout = true; // Of course, we still have to repaint on any visibility change. invalidation.repaint = true; @@ -624,6 +624,13 @@ NonnullRefPtr Element::resolved_css_values() return properties; } +void Element::reset_animated_css_properties() +{ + if (!m_computed_css_values) + return; + m_computed_css_values->reset_animated_properties(); +} + DOMTokenList* Element::class_list() { if (!m_class_list) diff --git a/Userland/Libraries/LibWeb/DOM/Element.h b/Userland/Libraries/LibWeb/DOM/Element.h index 904de8fe331..e70eecd04e5 100644 --- a/Userland/Libraries/LibWeb/DOM/Element.h +++ b/Userland/Libraries/LibWeb/DOM/Element.h @@ -166,6 +166,8 @@ public: static RequiredInvalidationAfterStyleChange full() { return { true, true, true, true }; } }; + static Element::RequiredInvalidationAfterStyleChange compute_required_invalidation(CSS::StyleProperties const& old_style, CSS::StyleProperties const& new_style); + RequiredInvalidationAfterStyleChange recompute_style(); Optional use_pseudo_element() const { return m_use_pseudo_element; } @@ -179,6 +181,8 @@ public: void set_computed_css_values(RefPtr); NonnullRefPtr resolved_css_values(); + void reset_animated_css_properties(); + CSS::CSSStyleDeclaration const* inline_style() const; CSS::CSSStyleDeclaration* style_for_bindings();