From e3b1d4a1416492662f0b387e802d88a124dd1380 Mon Sep 17 00:00:00 2001
From: implicitfield <114500360+implicitfield@users.noreply.github.com>
Date: Sat, 2 Mar 2024 21:53:25 +0400
Subject: [PATCH] LibWeb: Compute content width before static position for
abspos elements
In some scenarios, correctly computing the static position may depend on
the content width having been calculated beforehand.
---
.../abspos-flexbox-with-auto-width.txt | 34 +++++++++++++++++++
.../input/abspos-flexbox-with-auto-width.html | 25 ++++++++++++++
.../LibWeb/Layout/FormattingContext.cpp | 17 +++++++---
3 files changed, 72 insertions(+), 4 deletions(-)
create mode 100644 Tests/LibWeb/Layout/expected/abspos-flexbox-with-auto-width.txt
create mode 100644 Tests/LibWeb/Layout/input/abspos-flexbox-with-auto-width.html
diff --git a/Tests/LibWeb/Layout/expected/abspos-flexbox-with-auto-width.txt b/Tests/LibWeb/Layout/expected/abspos-flexbox-with-auto-width.txt
new file mode 100644
index 0000000000..2445bfeb5b
--- /dev/null
+++ b/Tests/LibWeb/Layout/expected/abspos-flexbox-with-auto-width.txt
@@ -0,0 +1,34 @@
+Viewport <#document> at (0,0) content-size 800x600 children: not-inline
+ BlockContainer at (0,0) content-size 800x116 [BFC] children: not-inline
+ BlockContainer
at (8,8) content-size 784x100 children: not-inline
+ BlockContainer at (8,8) content-size 200x100 children: not-inline
+ BlockContainer <(anonymous)> at (8,8) content-size 200x0 children: inline
+ TextNode <#text>
+ Box
at (8,8) content-size 200x0 flex-container(row) [FFC] children: not-inline
+ BlockContainer <(anonymous)> (not painted) [BFC] children: inline
+ TextNode <#text>
+ BlockContainer
at (83,8) content-size 50x100 positioned [BFC] children: not-inline
+ BlockContainer <(anonymous)> at (83,8) content-size 50x0 children: inline
+ TextNode <#text>
+ BlockContainer
at (83,8) content-size 50x0 children: not-inline
+ BlockContainer <(anonymous)> at (83,8) content-size 50x0 children: inline
+ TextNode <#text>
+ BlockContainer <(anonymous)> (not painted) [BFC] children: inline
+ TextNode <#text>
+ BlockContainer <(anonymous)> at (8,8) content-size 200x0 children: inline
+ TextNode <#text>
+ BlockContainer <(anonymous)> at (8,108) content-size 784x0 children: inline
+ TextNode <#text>
+
+ViewportPaintable (Viewport<#document>) [0,0 800x600]
+ PaintableWithLines (BlockContainer) [0,0 800x116]
+ PaintableWithLines (BlockContainer) [8,8 784x100]
+ PaintableWithLines (BlockContainer#containing-block) [8,8 200x100]
+ PaintableWithLines (BlockContainer(anonymous)) [8,8 200x0]
+ PaintableBox (Box
#inner-flex) [8,8 200x0] overflow: [83,8 50x100]
+ PaintableWithLines (BlockContainer
) [83,8 50x100]
+ PaintableWithLines (BlockContainer(anonymous)) [83,8 50x0]
+ PaintableWithLines (BlockContainer
) [83,8 50x0]
+ PaintableWithLines (BlockContainer(anonymous)) [83,8 50x0]
+ PaintableWithLines (BlockContainer(anonymous)) [8,8 200x0]
+ PaintableWithLines (BlockContainer(anonymous)) [8,108 784x0]
diff --git a/Tests/LibWeb/Layout/input/abspos-flexbox-with-auto-width.html b/Tests/LibWeb/Layout/input/abspos-flexbox-with-auto-width.html
new file mode 100644
index 0000000000..2b5291a59c
--- /dev/null
+++ b/Tests/LibWeb/Layout/input/abspos-flexbox-with-auto-width.html
@@ -0,0 +1,25 @@
+
+
+
diff --git a/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp
index fad96bd837..61b775d6aa 100644
--- a/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp
+++ b/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp
@@ -656,7 +656,7 @@ CSSPixels FormattingContext::compute_height_for_replaced_element(Box const& box,
void FormattingContext::compute_width_for_absolutely_positioned_non_replaced_element(Box const& box, AvailableSpace const& available_space)
{
auto width_of_containing_block = available_space.width.to_px_or_zero();
- auto& computed_values = box.computed_values();
+ auto const& computed_values = box.computed_values();
auto zero_value = CSS::Length::make_px(0);
auto margin_left = CSS::Length::make_auto();
@@ -699,10 +699,20 @@ void FormattingContext::compute_width_for_absolutely_positioned_non_replaced_ele
// Then, if the 'direction' property of the element establishing the static-position containing block
// is 'ltr' set 'left' to the static position and apply rule number three below;
// otherwise, set 'right' to the static position and apply rule number one below.
- // FIXME: This is very hackish.
+
+ // NOTE: As with compute_height_for_absolutely_positioned_non_replaced_element, we actually apply these
+ // steps in the opposite order since the static position may depend on the width of the box.
+
+ auto result = calculate_shrink_to_fit_widths(box);
+ auto available_width = solve_for_width();
+ CSSPixels content_width = min(max(result.preferred_minimum_width, available_width.to_px(box)), result.preferred_width);
+ width = CSS::Length::make_px(content_width);
+ m_state.get_mutable(box).set_content_width(content_width);
+
auto static_position = calculate_static_position(box);
+
left = static_position.x();
- goto Rule3;
+ right = solve_for_right();
}
// If none of the three is auto:
@@ -765,7 +775,6 @@ void FormattingContext::compute_width_for_absolutely_positioned_non_replaced_ele
// 3. 'width' and 'right' are 'auto' and 'left' is not 'auto',
// then the width is shrink-to-fit. Then solve for 'right'
else if (width.is_auto() && computed_right.is_auto() && !computed_left.is_auto()) {
- Rule3:
auto result = calculate_shrink_to_fit_widths(box);
auto available_width = solve_for_width();
width = CSS::Length::make_px(min(max(result.preferred_minimum_width, available_width.to_px(box)), result.preferred_width));