From 8b450c309adc295ac5c7f9edb2823d478c4dd403 Mon Sep 17 00:00:00 2001 From: Lorenz A Date: Tue, 4 Nov 2025 02:01:36 +0100 Subject: [PATCH] LibWeb: Propagate style values in deep anonymous wrappers The style propagation logic in `NodeWithStyle::apply_style()` was incomplete for anonymous nodes created during layout (e.g., within `wrap_in_button_layout_tree_if_needed`). 1. **Non-inherited CSS values** were not being propagated to the anonymous wrappers. 2. Propagation did not recurse into **nested anonymous wrappers** (descendants). This fix adds calls to `propagate_non_inherit_values(child)` and `child.propagate_style_to_anonymous_wrappers()`, ensuring all computed styles reach the entire anonymous wrapper hierarchy. --- Libraries/LibWeb/Layout/Node.cpp | 19 ++++++++++++------- Libraries/LibWeb/Layout/Node.h | 1 + .../expected/button-hover-text-color-ref.html | 8 ++++++++ .../Ref/input/button-hover-text-color.html | 16 ++++++++++++++++ 4 files changed, 37 insertions(+), 7 deletions(-) create mode 100644 Tests/LibWeb/Ref/expected/button-hover-text-color-ref.html create mode 100644 Tests/LibWeb/Ref/input/button-hover-text-color.html diff --git a/Libraries/LibWeb/Layout/Node.cpp b/Libraries/LibWeb/Layout/Node.cpp index 676f6444600e..3e2229f8f46d 100644 --- a/Libraries/LibWeb/Layout/Node.cpp +++ b/Libraries/LibWeb/Layout/Node.cpp @@ -913,6 +913,15 @@ void NodeWithStyle::apply_style(CSS::ComputedProperties const& computed_style) box_node->propagate_style_along_continuation(computed_style); } +void NodeWithStyle::propagate_non_inherit_values(NodeWithStyle& target_node) const +{ + // NOTE: These properties are not inherited, but we still have to propagate them to anonymous wrappers. + target_node.mutable_computed_values().set_text_decoration_line(computed_values().text_decoration_line()); + target_node.mutable_computed_values().set_text_decoration_thickness(computed_values().text_decoration_thickness()); + target_node.mutable_computed_values().set_text_decoration_color(computed_values().text_decoration_color()); + target_node.mutable_computed_values().set_text_decoration_style(computed_values().text_decoration_style()); +} + void NodeWithStyle::propagate_style_to_anonymous_wrappers() { // Update the style of any anonymous wrappers that inherit from this node. @@ -931,6 +940,8 @@ void NodeWithStyle::propagate_style_to_anonymous_wrappers() if (child.is_anonymous() && !is(child)) { auto& child_computed_values = static_cast(static_cast(const_cast(child.computed_values()))); child_computed_values.inherit_from(computed_values()); + propagate_non_inherit_values(child); + child.propagate_style_to_anonymous_wrappers(); } return IterationDecision::Continue; }); @@ -1010,13 +1021,7 @@ GC::Ref NodeWithStyle::create_anonymous_wrapper() const { auto wrapper = heap().allocate(const_cast(document()), nullptr, computed_values().clone_inherited_values()); wrapper->mutable_computed_values().set_display(CSS::Display(CSS::DisplayOutside::Block, CSS::DisplayInside::Flow)); - - // NOTE: These properties are not inherited, but we still have to propagate them to anonymous wrappers. - wrapper->mutable_computed_values().set_text_decoration_line(computed_values().text_decoration_line()); - wrapper->mutable_computed_values().set_text_decoration_thickness(computed_values().text_decoration_thickness()); - wrapper->mutable_computed_values().set_text_decoration_color(computed_values().text_decoration_color()); - wrapper->mutable_computed_values().set_text_decoration_style(computed_values().text_decoration_style()); - + propagate_non_inherit_values(*wrapper); // CSS 2.2 9.2.1.1 creates anonymous block boxes, but 9.4.1 states inline-block creates a BFC. // Set wrapper to inline-block to participate correctly in the IFC within the parent inline-block. if (display().is_inline_block() && !has_children()) { diff --git a/Libraries/LibWeb/Layout/Node.h b/Libraries/LibWeb/Layout/Node.h index 0d105ca816c6..55f4ed23b2fc 100644 --- a/Libraries/LibWeb/Layout/Node.h +++ b/Libraries/LibWeb/Layout/Node.h @@ -271,6 +271,7 @@ class WEB_API NodeWithStyle : public Node { virtual bool is_node_with_style() const final { return true; } void reset_table_box_computed_values_used_by_wrapper_to_init_values(); + void propagate_non_inherit_values(NodeWithStyle& target_node) const; void propagate_style_to_anonymous_wrappers(); NonnullOwnPtr m_computed_values; diff --git a/Tests/LibWeb/Ref/expected/button-hover-text-color-ref.html b/Tests/LibWeb/Ref/expected/button-hover-text-color-ref.html new file mode 100644 index 000000000000..79b486d37258 --- /dev/null +++ b/Tests/LibWeb/Ref/expected/button-hover-text-color-ref.html @@ -0,0 +1,8 @@ + + + diff --git a/Tests/LibWeb/Ref/input/button-hover-text-color.html b/Tests/LibWeb/Ref/input/button-hover-text-color.html new file mode 100644 index 000000000000..0ee8aa076e17 --- /dev/null +++ b/Tests/LibWeb/Ref/input/button-hover-text-color.html @@ -0,0 +1,16 @@ + + + + +