diff --git a/Libraries/LibWeb/Animations/KeyframeEffect.cpp b/Libraries/LibWeb/Animations/KeyframeEffect.cpp index 1f1684fb492..8d0986c261a 100644 --- a/Libraries/LibWeb/Animations/KeyframeEffect.cpp +++ b/Libraries/LibWeb/Animations/KeyframeEffect.cpp @@ -935,25 +935,14 @@ void KeyframeEffect::update_computed_properties() auto& document = target->document(); document.style_computer().collect_animation_into(*target, pseudo_element_type(), *this, *style, CSS::StyleComputer::AnimationRefresh::Yes); + auto invalidation = compute_required_invalidation(animated_properties_before_update, style->animated_property_values()); + // 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_properties(); - if (!element_style || !element.layout_node()) - return TraversalDecision::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(static_cast(i), &element); - element_style->set_property(static_cast(i), *new_value, CSS::ComputedProperties::Inherited::Yes); - } - } - - element.layout_node()->apply_style(*element_style); + invalidation |= element.recompute_inherited_style(); return TraversalDecision::Continue; }); - auto invalidation = compute_required_invalidation(animated_properties_before_update, style->animated_property_values()); - if (!pseudo_element_type().has_value()) { if (target->layout_node()) target->layout_node()->apply_style(*style); diff --git a/Libraries/LibWeb/CSS/StyleComputer.h b/Libraries/LibWeb/CSS/StyleComputer.h index c3566b3384d..aa874338d7b 100644 --- a/Libraries/LibWeb/CSS/StyleComputer.h +++ b/Libraries/LibWeb/CSS/StyleComputer.h @@ -175,6 +175,8 @@ public: [[nodiscard]] GC::Ref compute_properties(DOM::Element&, Optional, CascadedProperties&) const; + void absolutize_values(ComputedProperties&) const; + private: enum class ComputeStyleMode { Normal, @@ -194,7 +196,6 @@ private: void compute_math_depth(ComputedProperties&, DOM::Element const*, Optional) const; void compute_defaulted_values(ComputedProperties&, DOM::Element const*, Optional) const; void start_needed_transitions(ComputedProperties const& old_style, ComputedProperties& new_style, DOM::Element&, Optional) const; - void absolutize_values(ComputedProperties&) const; void resolve_effective_overflow_values(ComputedProperties&) const; void transform_box_type_if_needed(ComputedProperties&, DOM::Element const&, Optional) const; diff --git a/Libraries/LibWeb/DOM/Document.cpp b/Libraries/LibWeb/DOM/Document.cpp index ca3b69549b1..78c8ac5be3c 100644 --- a/Libraries/LibWeb/DOM/Document.cpp +++ b/Libraries/LibWeb/DOM/Document.cpp @@ -1297,10 +1297,13 @@ void Document::update_layout() if (is(node)) { if (needs_full_style_update || node.needs_style_update()) { invalidation |= static_cast(node).recompute_style(); + } else if (node.needs_inherited_style_update()) { + invalidation |= static_cast(node).recompute_inherited_style(); } is_display_none = static_cast(node).computed_properties()->display().is_none(); } node.set_needs_style_update(false); + node.set_needs_inherited_style_update(false); if (needs_full_style_update || node.child_needs_style_update()) { if (node.is_element()) { @@ -1314,7 +1317,7 @@ void Document::update_layout() } node.for_each_child([&](auto& child) { - if (needs_full_style_update || child.needs_style_update() || child.child_needs_style_update()) { + if (needs_full_style_update || child.needs_style_update() || child.needs_inherited_style_update() || child.child_needs_style_update()) { auto subtree_invalidation = update_style_recursively(child, style_computer); if (!is_display_none) invalidation |= subtree_invalidation; diff --git a/Libraries/LibWeb/DOM/Element.cpp b/Libraries/LibWeb/DOM/Element.cpp index 89f751f36ce..132f3b7f9dc 100644 --- a/Libraries/LibWeb/DOM/Element.cpp +++ b/Libraries/LibWeb/DOM/Element.cpp @@ -554,6 +554,31 @@ CSS::RequiredInvalidationAfterStyleChange Element::recompute_style() return invalidation; } +CSS::RequiredInvalidationAfterStyleChange Element::recompute_inherited_style() +{ + // Traversal of the subtree is necessary to update the animated properties inherited from the target element. + auto computed_properties = this->computed_properties(); + if (!computed_properties || !layout_node()) + return {}; + + CSS::RequiredInvalidationAfterStyleChange invalidation; + + for (auto i = to_underlying(CSS::first_property_id); i <= to_underlying(CSS::last_property_id); ++i) { + auto property_id = static_cast(i); + if (!computed_properties->is_property_inherited(property_id)) + continue; + RefPtr old_value = computed_properties->maybe_null_property(property_id); + RefPtr new_value = CSS::StyleComputer::get_inherit_value(property_id, this); + computed_properties->set_property(property_id, *new_value, CSS::ComputedProperties::Inherited::Yes); + invalidation |= CSS::compute_property_invalidation(property_id, old_value, new_value); + } + + document().style_computer().absolutize_values(*computed_properties); + + layout_node()->apply_style(*computed_properties); + return invalidation; +} + GC::Ref Element::resolved_css_values(Optional type) { auto element_computed_style = CSS::ResolvedCSSStyleDeclaration::create(*this, type); diff --git a/Libraries/LibWeb/DOM/Element.h b/Libraries/LibWeb/DOM/Element.h index 96dd9472b1d..216bfa6f24a 100644 --- a/Libraries/LibWeb/DOM/Element.h +++ b/Libraries/LibWeb/DOM/Element.h @@ -178,6 +178,7 @@ public: void run_attribute_change_steps(FlyString const& local_name, Optional const& old_value, Optional const& value, Optional const& namespace_); CSS::RequiredInvalidationAfterStyleChange recompute_style(); + CSS::RequiredInvalidationAfterStyleChange recompute_inherited_style(); Optional use_pseudo_element() const { return m_use_pseudo_element; } void set_use_pseudo_element(Optional use_pseudo_element) { m_use_pseudo_element = move(use_pseudo_element); } diff --git a/Libraries/LibWeb/DOM/Node.cpp b/Libraries/LibWeb/DOM/Node.cpp index 4b458e032fc..ade0af01b85 100644 --- a/Libraries/LibWeb/DOM/Node.cpp +++ b/Libraries/LibWeb/DOM/Node.cpp @@ -1249,6 +1249,22 @@ EventTarget* Node::get_parent(Event const&) return parent(); } +void Node::set_needs_inherited_style_update(bool value) +{ + if (m_needs_inherited_style_update == value) + return; + m_needs_inherited_style_update = value; + + if (m_needs_inherited_style_update) { + for (auto* ancestor = parent_or_shadow_host(); ancestor; ancestor = ancestor->parent_or_shadow_host()) { + if (ancestor->m_child_needs_style_update) + break; + ancestor->m_child_needs_style_update = true; + } + document().schedule_style_update(); + } +} + void Node::set_needs_style_update(bool value) { if (m_needs_style_update == value) diff --git a/Libraries/LibWeb/DOM/Node.h b/Libraries/LibWeb/DOM/Node.h index 92fa32e31f2..dfe51be8a49 100644 --- a/Libraries/LibWeb/DOM/Node.h +++ b/Libraries/LibWeb/DOM/Node.h @@ -275,6 +275,9 @@ public: bool needs_style_update() const { return m_needs_style_update; } void set_needs_style_update(bool); + bool needs_inherited_style_update() const { return m_needs_inherited_style_update; } + void set_needs_inherited_style_update(bool); + bool child_needs_style_update() const { return m_child_needs_style_update; } void set_child_needs_style_update(bool b) { m_child_needs_style_update = b; } @@ -746,6 +749,7 @@ protected: GC::Ptr m_paintable; NodeType m_type { NodeType::INVALID }; bool m_needs_style_update { false }; + bool m_needs_inherited_style_update { false }; bool m_child_needs_style_update { false }; UniqueNodeID m_unique_id;