From 087601832a83bc36f0081a6c9868a29bf1211e03 Mon Sep 17 00:00:00 2001 From: Jelle Raaijmakers Date: Mon, 18 Aug 2025 11:20:27 +0200 Subject: [PATCH] LibWeb: Set fit-content width for buttons in used values, not computed For button layouts, we were overriding the computed `width` value with `fit-content` in `TreeBuilder::wrap_in_button_layout_if_needed()`. But the spec asks us to set the _used value_ instead, so we now actually calculate the fit-content width and set the box' content width to it. Fixes #2516. --- .../LibWeb/Layout/BlockFormattingContext.cpp | 11 ++++-- Libraries/LibWeb/Layout/FormattingContext.cpp | 5 ++- Libraries/LibWeb/Layout/TreeBuilder.cpp | 7 ---- .../flex/button-layout-inside-flex.txt | 36 +++++++++++++++++++ .../input/flex/button-layout-inside-flex.html | 12 +++++++ 5 files changed, 59 insertions(+), 12 deletions(-) create mode 100644 Tests/LibWeb/Layout/expected/flex/button-layout-inside-flex.txt create mode 100644 Tests/LibWeb/Layout/input/flex/button-layout-inside-flex.html diff --git a/Libraries/LibWeb/Layout/BlockFormattingContext.cpp b/Libraries/LibWeb/Layout/BlockFormattingContext.cpp index f0c8dc1822f..310e8c199a4 100644 --- a/Libraries/LibWeb/Layout/BlockFormattingContext.cpp +++ b/Libraries/LibWeb/Layout/BlockFormattingContext.cpp @@ -98,8 +98,7 @@ void BlockFormattingContext::run(AvailableSpace const& available_space) auto new_y = -((legend_height) / 2) - fieldset_state.padding_top; legend_state.set_content_y(new_y); - // If the computed value of 'inline-size' is 'auto', - // then the used value is the fit-content inline size. + // If the computed value of 'inline-size' is 'auto', then the used value is the fit-content inline size. if (legend->computed_values().width().is_auto()) { auto width = calculate_fit_content_width(*legend, available_space); legend_state.set_content_width(width); @@ -224,6 +223,14 @@ void BlockFormattingContext::compute_width(Box const& box, AvailableSpace const& box_state.padding_left = padding_left.to_px(box); box_state.padding_right = padding_right.to_px(box); + // https://html.spec.whatwg.org/multipage/rendering.html#button-layout + // If the computed value of 'inline-size' is 'auto', then the used value is the fit-content inline size. + if (auto const* html_element = as_if(box.dom_node()); html_element + && html_element->uses_button_layout() && computed_values.width().is_auto()) { + box_state.set_content_width(calculate_fit_content_width(box, available_space)); + return; + } + // NOTE: If we are calculating the min-content or max-content width of this box, // and the width should be treated as auto, then we can simply return here, // as the preferred width and min/max constraints are irrelevant for intrinsic sizing. diff --git a/Libraries/LibWeb/Layout/FormattingContext.cpp b/Libraries/LibWeb/Layout/FormattingContext.cpp index ec71279c3c1..e26767e18ce 100644 --- a/Libraries/LibWeb/Layout/FormattingContext.cpp +++ b/Libraries/LibWeb/Layout/FormattingContext.cpp @@ -1403,9 +1403,8 @@ void FormattingContext::compute_inset(NodeWithStyleAndBoxModelMetrics const& box // https://drafts.csswg.org/css-sizing-3/#fit-content-size CSSPixels FormattingContext::calculate_fit_content_width(Layout::Box const& box, AvailableSpace const& available_space) const { - // If the available space in a given axis is definite, - // equal to clamp(min-content size, stretch-fit size, max-content size) - // (i.e. max(min-content size, min(max-content size, stretch-fit size))). + // If the available space in a given axis is definite, equal to clamp(min-content size, stretch-fit size, + // max-content size) (i.e. max(min-content size, min(max-content size, stretch-fit size))). if (available_space.width.is_definite()) { return max(calculate_min_content_width(box), min(calculate_stretch_fit_width(box, available_space.width), diff --git a/Libraries/LibWeb/Layout/TreeBuilder.cpp b/Libraries/LibWeb/Layout/TreeBuilder.cpp index 3fbd2c6d75e..23ae1958f1a 100644 --- a/Libraries/LibWeb/Layout/TreeBuilder.cpp +++ b/Libraries/LibWeb/Layout/TreeBuilder.cpp @@ -728,13 +728,6 @@ void TreeBuilder::wrap_in_button_layout_tree_if_needed(DOM::Node& dom_node, GC:: if (!html_element || !html_element->uses_button_layout()) return; - // https://html.spec.whatwg.org/multipage/rendering.html#button-layout - // If the computed value of 'inline-size' is 'auto', then the used value is the fit-content inline size. - if (dom_node.layout_node()->computed_values().width().is_auto()) { - auto& computed_values = as(*dom_node.layout_node()).mutable_computed_values(); - computed_values.set_width(CSS::Size::make_fit_content()); - } - // https://html.spec.whatwg.org/multipage/rendering.html#button-layout // If the element is an input element, or if it is a button element and its computed value for 'display' is not // 'inline-grid', 'grid', 'inline-flex', or 'flex', then the element's box has a child anonymous button content box diff --git a/Tests/LibWeb/Layout/expected/flex/button-layout-inside-flex.txt b/Tests/LibWeb/Layout/expected/flex/button-layout-inside-flex.txt new file mode 100644 index 00000000000..070166e3795 --- /dev/null +++ b/Tests/LibWeb/Layout/expected/flex/button-layout-inside-flex.txt @@ -0,0 +1,36 @@ +Viewport <#document> at (0,0) content-size 800x600 children: not-inline + BlockContainer at (0,0) content-size 800x56 [BFC] children: not-inline + BlockContainer at (8,8) content-size 784x40 children: not-inline + Box
at (8,8) content-size 784x22 flex-container(column) [FFC] children: not-inline + BlockContainer
+
bar