From c808f6c6374f4e4f7ebc705c77dbe4a53eb3d6c3 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Tue, 20 Jun 2023 13:20:08 +0200 Subject: [PATCH] LibWeb: Don't use BFC auto height for non-BFC abspos elements While CSS 2.2 does tell us to use the "auto height for BFC roots" calculation when resolving auto heights for abspos elements, that doesn't make sense for other formatting context roots, e.g flex. In lieu of implementing the entire new absolute positioning model from CSS-POSITION-3, this patch borrows one small nugget from it: using fit-content height as the auto height for non-BFC-root abspos elements. --- ...abspos-flex-container-with-auto-height.txt | 8 ++++ ...bspos-flex-container-with-auto-height.html | 20 +++++++++ .../LibWeb/Layout/FormattingContext.cpp | 43 ++++++++++++------- .../LibWeb/Layout/FormattingContext.h | 2 + 4 files changed, 58 insertions(+), 15 deletions(-) create mode 100644 Tests/LibWeb/Layout/expected/abspos-flex-container-with-auto-height.txt create mode 100644 Tests/LibWeb/Layout/input/abspos-flex-container-with-auto-height.html diff --git a/Tests/LibWeb/Layout/expected/abspos-flex-container-with-auto-height.txt b/Tests/LibWeb/Layout/expected/abspos-flex-container-with-auto-height.txt new file mode 100644 index 0000000000..85ce72af3c --- /dev/null +++ b/Tests/LibWeb/Layout/expected/abspos-flex-container-with-auto-height.txt @@ -0,0 +1,8 @@ +Viewport <#document> at (0,0) content-size 800x600 children: not-inline + BlockContainer at (1,1) content-size 798x0 [BFC] children: not-inline + Box at (9,9) content-size 512.859375x19.46875 positioned flex-container(column) [FFC] children: not-inline + BlockContainer
at (10,10) content-size 510.859375x17.46875 flex-item [BFC] children: inline + line 0 width: 510.859375, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 60, rect: [10,10 510.859375x17.46875] + "Diese Website nutzt Cookies und vergleichbare Funktionen zur" + TextNode <#text> diff --git a/Tests/LibWeb/Layout/input/abspos-flex-container-with-auto-height.html b/Tests/LibWeb/Layout/input/abspos-flex-container-with-auto-height.html new file mode 100644 index 0000000000..f113bd266e --- /dev/null +++ b/Tests/LibWeb/Layout/input/abspos-flex-container-with-auto-height.html @@ -0,0 +1,20 @@ +
Diese Website nutzt Cookies und vergleichbare Funktionen zur \ No newline at end of file diff --git a/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp index f8db4dcc1f..10499dc82f 100644 --- a/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp @@ -305,6 +305,22 @@ CSSPixelSize FormattingContext::solve_replaced_size_constraint(CSSPixels input_w return { w, h }; } +Optional FormattingContext::compute_auto_height_for_absolutely_positioned_element(Box const& box, AvailableSpace const& available_space, BeforeOrAfterInsideLayout before_or_after_inside_layout) const +{ + // NOTE: CSS 2.2 tells us to use the "auto height for block formatting context roots" here. + // That's fine as long as the box is a BFC root. + if (creates_block_formatting_context(box)) { + if (before_or_after_inside_layout == BeforeOrAfterInsideLayout::Before) + return {}; + return compute_auto_height_for_block_formatting_context_root(box); + } + + // NOTE: For anything else, we use the fit-content height. + // This should eventually be replaced by the new absolute positioning model: + // https://www.w3.org/TR/css-position-3/#abspos-layout + return calculate_fit_content_height(box, available_space); +} + // https://www.w3.org/TR/CSS22/visudet.html#root-height CSSPixels FormattingContext::compute_auto_height_for_block_formatting_context_root(Box const& root) const { @@ -798,10 +814,6 @@ void FormattingContext::compute_height_for_absolutely_positioned_non_replaced_el // If all three of top, height, and bottom are auto: if (top.is_auto() && height.is_auto() && bottom.is_auto()) { - // (If we haven't done inside layout yet, we can't compute the auto height.) - if (before_or_after_inside_layout == BeforeOrAfterInsideLayout::Before) - return; - // First set any auto values for margin-top and margin-bottom to 0, if (margin_top.is_auto()) margin_top = CSS::Length::make_px(0); @@ -813,7 +825,10 @@ void FormattingContext::compute_height_for_absolutely_positioned_non_replaced_el top = CSS::Length::make_px(static_position.y()); // and finally apply rule number three below. - height = CSS::Size::make_px(compute_auto_height_for_block_formatting_context_root(box)); + auto maybe_height = compute_auto_height_for_absolutely_positioned_element(box, available_space, before_or_after_inside_layout); + if (!maybe_height.has_value()) + return; + height = CSS::Size::make_px(maybe_height.value()); solve_for_bottom(); } @@ -853,12 +868,11 @@ void FormattingContext::compute_height_for_absolutely_positioned_non_replaced_el // 1. If top and height are auto and bottom is not auto, if (top.is_auto() && height.is_auto() && !bottom.is_auto()) { - // (If we haven't done inside layout yet, we can't compute the auto height.) - if (before_or_after_inside_layout == BeforeOrAfterInsideLayout::Before) - return; - // then the height is based on the Auto heights for block formatting context roots, - height = CSS::Size::make_px(compute_auto_height_for_block_formatting_context_root(box)); + auto maybe_height = compute_auto_height_for_absolutely_positioned_element(box, available_space, before_or_after_inside_layout); + if (!maybe_height.has_value()) + return; + height = CSS::Size::make_px(maybe_height.value()); // and solve for top. solve_for_top(); @@ -875,12 +889,11 @@ void FormattingContext::compute_height_for_absolutely_positioned_non_replaced_el // 3. If height and bottom are auto and top is not auto, else if (height.is_auto() && bottom.is_auto() && !top.is_auto()) { - // (If we haven't done inside layout yet, we can't compute the auto height.) - if (before_or_after_inside_layout == BeforeOrAfterInsideLayout::Before) - return; - // then the height is based on the Auto heights for block formatting context roots, - height = CSS::Size::make_px(compute_auto_height_for_block_formatting_context_root(box)); + auto maybe_height = compute_auto_height_for_absolutely_positioned_element(box, available_space, before_or_after_inside_layout); + if (!maybe_height.has_value()) + return; + height = CSS::Size::make_px(maybe_height.value()); // and solve for bottom. solve_for_bottom(); diff --git a/Userland/Libraries/LibWeb/Layout/FormattingContext.h b/Userland/Libraries/LibWeb/Layout/FormattingContext.h index a220cb1fea..40b1ed1ea6 100644 --- a/Userland/Libraries/LibWeb/Layout/FormattingContext.h +++ b/Userland/Libraries/LibWeb/Layout/FormattingContext.h @@ -146,6 +146,8 @@ protected: void compute_height_for_absolutely_positioned_non_replaced_element(Box const&, AvailableSpace const&, BeforeOrAfterInsideLayout); void compute_height_for_absolutely_positioned_replaced_element(Box const&, AvailableSpace const&, BeforeOrAfterInsideLayout); + [[nodiscard]] Optional compute_auto_height_for_absolutely_positioned_element(Box const&, AvailableSpace const&, BeforeOrAfterInsideLayout) const; + Type m_type {}; FormattingContext* m_parent { nullptr };