From 123abe0e79354d4cfc005adc973688f6e378365a Mon Sep 17 00:00:00 2001 From: Jelle Raaijmakers Date: Fri, 9 May 2025 12:03:48 +0200 Subject: [PATCH] LibWeb: Overlap float space and left margins for all shared ancestors We would only correct for the left margin of the containing block of the child box that we are laying out, but we actually need to correct for all left margins up until the containing block that contains both the float and the child box. Fixes #4639. --- .../LibWeb/Layout/BlockFormattingContext.cpp | 31 +++++++--------- ...n-overflow-after-float-and-margin-left.txt | 37 +++++++++++++++++++ ...-overflow-after-float-and-margin-left.html | 23 ++++++++++++ 3 files changed, 73 insertions(+), 18 deletions(-) create mode 100644 Tests/LibWeb/Layout/expected/block-and-inline/block-with-hidden-overflow-after-float-and-margin-left.txt create mode 100644 Tests/LibWeb/Layout/input/block-and-inline/block-with-hidden-overflow-after-float-and-margin-left.html diff --git a/Libraries/LibWeb/Layout/BlockFormattingContext.cpp b/Libraries/LibWeb/Layout/BlockFormattingContext.cpp index 751f4631533..d6063ffbc0d 100644 --- a/Libraries/LibWeb/Layout/BlockFormattingContext.cpp +++ b/Libraries/LibWeb/Layout/BlockFormattingContext.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2020-2022, Andreas Kling + * Copyright (c) 2025, Jelle Raaijmakers * * SPDX-License-Identifier: BSD-2-Clause */ @@ -958,18 +959,6 @@ void BlockFormattingContext::place_block_level_element_in_normal_flow_vertically float_box->margin_box_rect_in_root_coordinate_space = margin_box_rect_in_ancestor_coordinate_space(float_box->used_values, root()); } -// Returns whether the given box has the given ancestor on the path to root, ignoring the anonymous blocks. -static bool box_has_ancestor_in_non_anonymous_containing_block_chain(Box const* box, Box const& ancestor, Box const& root) -{ - Box const* current_ancestor = box ? box->non_anonymous_containing_block() : &root; - while (current_ancestor != &root) { - if (current_ancestor == &ancestor) - return true; - current_ancestor = current_ancestor->non_anonymous_containing_block(); - } - return false; -} - void BlockFormattingContext::place_block_level_element_in_normal_flow_horizontally(Box const& child_box, AvailableSpace const& available_space) { auto& box_state = m_state.get_mutable(child_box); @@ -982,12 +971,18 @@ void BlockFormattingContext::place_block_level_element_in_normal_flow_horizontal auto box_in_root_rect = content_box_rect_in_ancestor_coordinate_space(box_state, root()); auto space_and_containing_margin = space_used_and_containing_margin_for_floats(box_in_root_rect.y()); available_width_within_containing_block -= space_and_containing_margin.left_used_space + space_and_containing_margin.right_used_space; - auto const& containing_box_state = m_state.get(*child_box.containing_block()); - if (box_has_ancestor_in_non_anonymous_containing_block_chain(space_and_containing_margin.matching_left_float_box, *child_box.non_anonymous_containing_block(), root())) - x = space_and_containing_margin.left_used_space; - else - // If the floating box doesn't share a containing block with the child box, the child box margin should overlap with the width of the floating box. - x = max(space_and_containing_margin.left_used_space - containing_box_state.margin_left, 0); + x = space_and_containing_margin.left_used_space; + + // All non-anonymous containing blocks that are ancestors of the child box, but are not ancestors of the left + // float box, might have left margins set that overlap with the used float space. + if (space_and_containing_margin.matching_left_float_box) { + Box const* current_ancestor = child_box.non_anonymous_containing_block(); + while (!current_ancestor->is_ancestor_of(*space_and_containing_margin.matching_left_float_box)) { + x -= m_state.get(*current_ancestor).margin_left; + current_ancestor = current_ancestor->non_anonymous_containing_block(); + } + x = max(x, 0); + } } if (child_box.containing_block()->computed_values().text_align() == CSS::TextAlign::LibwebCenter) { diff --git a/Tests/LibWeb/Layout/expected/block-and-inline/block-with-hidden-overflow-after-float-and-margin-left.txt b/Tests/LibWeb/Layout/expected/block-and-inline/block-with-hidden-overflow-after-float-and-margin-left.txt new file mode 100644 index 00000000000..ae157e26e1d --- /dev/null +++ b/Tests/LibWeb/Layout/expected/block-and-inline/block-with-hidden-overflow-after-float-and-margin-left.txt @@ -0,0 +1,37 @@ +Viewport <#document> at (0,0) content-size 800x600 children: not-inline + BlockContainer at (0,0) content-size 800x48 [BFC] children: not-inline + BlockContainer at (8,8) content-size 784x22 children: not-inline + BlockContainer <(anonymous)> at (8,8) content-size 784x0 children: inline + BlockContainer at (8,8) content-size 100x40 floating [BFC] children: not-inline + TextNode <#text> + BlockContainer at (109,9) content-size 682x20 children: not-inline + BlockContainer <(anonymous)> at (109,9) content-size 682x0 children: inline + TextNode <#text> + BlockContainer
at (109,9) content-size 682x20 children: not-inline + BlockContainer <(anonymous)> at (109,9) content-size 682x0 children: inline + TextNode <#text> + BlockContainer at (110,10) content-size 680x18 [BFC] children: inline + frag 0 from TextNode start: 0, length: 3, rect: [110,10 27.15625x18] baseline: 13.796875 + "foo" + TextNode <#text> + BlockContainer <(anonymous)> at (109,29) content-size 682x0 children: inline + TextNode <#text> + BlockContainer <(anonymous)> at (109,29) content-size 682x0 children: inline + TextNode <#text> + BlockContainer <(anonymous)> at (8,30) content-size 784x0 children: inline + TextNode <#text> + +ViewportPaintable (Viewport<#document>) [0,0 800x600] + PaintableWithLines (BlockContainer) [0,0 800x48] + PaintableWithLines (BlockContainer) [8,8 784x22] + PaintableWithLines (BlockContainer(anonymous)) [8,8 784x0] + PaintableWithLines (BlockContainer
#a) [8,8 100x40] + PaintableWithLines (BlockContainer
#b) [108,8 684x22] + PaintableWithLines (BlockContainer(anonymous)) [109,9 682x0] + PaintableWithLines (BlockContainer
) [109,9 682x20] + PaintableWithLines (BlockContainer(anonymous)) [109,9 682x0] + PaintableWithLines (BlockContainer
#c) [109,9 682x20] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer(anonymous)) [109,29 682x0] + PaintableWithLines (BlockContainer(anonymous)) [109,29 682x0] + PaintableWithLines (BlockContainer(anonymous)) [8,30 784x0] diff --git a/Tests/LibWeb/Layout/input/block-and-inline/block-with-hidden-overflow-after-float-and-margin-left.html b/Tests/LibWeb/Layout/input/block-and-inline/block-with-hidden-overflow-after-float-and-margin-left.html new file mode 100644 index 00000000000..79e549287c9 --- /dev/null +++ b/Tests/LibWeb/Layout/input/block-and-inline/block-with-hidden-overflow-after-float-and-margin-left.html @@ -0,0 +1,23 @@ + + +
+
+
+
foo
+
+