From 6a17a30e2e2a60472b4bfefa9b5bdff08f9dcc82 Mon Sep 17 00:00:00 2001 From: Andi Gallo Date: Wed, 5 Jul 2023 03:39:28 +0000 Subject: [PATCH] LibWeb: Handle overlapping floating box and left margin Allow the left margin of a box which creates a block formatting context to overlap with left floating boxes which are siblings in the document tree. Fixes #20233 and the comment layout on https://lobste.rs. --- ...block-with-hidden-overflow-after-float.txt | 4 ++ ...th-hidden-overflow-after-sibling-float.txt | 47 +++++++++++++++++++ ...lock-with-hidden-overflow-after-float.html | 4 +- ...h-hidden-overflow-after-sibling-float.html | 26 ++++++++++ .../LibWeb/Layout/BlockFormattingContext.cpp | 20 +++++++- .../LibWeb/Layout/FormattingContext.h | 1 + 6 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 Tests/LibWeb/Layout/expected/block-and-inline/block-with-hidden-overflow-after-sibling-float.txt create mode 100644 Tests/LibWeb/Layout/input/block-and-inline/block-with-hidden-overflow-after-sibling-float.html diff --git a/Tests/LibWeb/Layout/expected/block-and-inline/block-with-hidden-overflow-after-float.txt b/Tests/LibWeb/Layout/expected/block-and-inline/block-with-hidden-overflow-after-float.txt index 30cf7f8f412..f4c5e990e45 100644 --- a/Tests/LibWeb/Layout/expected/block-and-inline/block-with-hidden-overflow-after-float.txt +++ b/Tests/LibWeb/Layout/expected/block-and-inline/block-with-hidden-overflow-after-float.txt @@ -8,12 +8,16 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline BlockContainer at (108,8) content-size 684x17.46875 children: not-inline BlockContainer <(anonymous)> at (108,8) content-size 684x0 children: inline TextNode <#text> + BlockContainer
at (108,8) content-size 684x0 children: inline + TextNode <#text> BlockContainer at (108,8) content-size 14.265625x17.46875 floating [BFC] children: inline line 0 width: 14.265625, height: 17.46875, bottom: 17.46875, baseline: 13.53125 frag 0 from TextNode start: 0, length: 1, rect: [108,8 14.265625x17.46875] "A" TextNode <#text> TextNode <#text> + BlockContainer <(anonymous)> at (108,8) content-size 684x0 children: inline + TextNode <#text> BlockContainer at (122.265625,8) content-size 669.734375x17.46875 [BFC] children: inline line 0 width: 9.34375, height: 17.46875, bottom: 17.46875, baseline: 13.53125 frag 0 from TextNode start: 0, length: 1, rect: [122.265625,8 9.34375x17.46875] diff --git a/Tests/LibWeb/Layout/expected/block-and-inline/block-with-hidden-overflow-after-sibling-float.txt b/Tests/LibWeb/Layout/expected/block-and-inline/block-with-hidden-overflow-after-sibling-float.txt new file mode 100644 index 00000000000..03836010f30 --- /dev/null +++ b/Tests/LibWeb/Layout/expected/block-and-inline/block-with-hidden-overflow-after-sibling-float.txt @@ -0,0 +1,47 @@ +Viewport <#document> at (0,0) content-size 800x600 children: not-inline + BlockContainer at (0,0) content-size 800x600 [BFC] children: not-inline + BlockContainer at (8,8) content-size 784x34.9375 children: not-inline + BlockContainer
at (8,8) content-size 784x34.9375 children: not-inline + BlockContainer <(anonymous)> at (8,8) content-size 784x0 children: inline + TextNode <#text> + BlockContainer
at (8,8) content-size 784x0 children: inline + TextNode <#text> + BlockContainer at (8,8) content-size 57.0625x34.9375 floating [BFC] children: not-inline + BlockContainer <(anonymous)> at (8,8) content-size 57.0625x0 children: inline + TextNode <#text> + BlockContainer at (8,8) content-size 57.0625x17.46875 children: inline + line 0 width: 57.0625, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 4, rect: [8,8 57.0625x17.46875] + "AAAA" + TextNode <#text> + BlockContainer <(anonymous)> at (8,25.46875) content-size 57.0625x0 children: inline + TextNode <#text> + BlockContainer
at (8,25.46875) content-size 57.0625x17.46875 children: inline + line 0 width: 14.265625, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 1, rect: [8,25.46875 14.265625x17.46875] + "A" + TextNode <#text> + BlockContainer <(anonymous)> at (8,42.9375) content-size 57.0625x0 children: inline + TextNode <#text> + TextNode <#text> + BlockContainer <(anonymous)> at (8,8) content-size 784x0 children: inline + TextNode <#text> + BlockContainer
at (108,8) content-size 684x34.9375 children: not-inline + BlockContainer <(anonymous)> at (108,8) content-size 684x0 children: inline + TextNode <#text> + BlockContainer
at (108,8) content-size 684x17.46875 children: inline + line 0 width: 9.34375, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 1, rect: [108,8 9.34375x17.46875] + "B" + TextNode <#text> + BlockContainer <(anonymous)> at (108,25.46875) content-size 684x0 children: inline + TextNode <#text> + BlockContainer at (108,25.46875) content-size 684x17.46875 [BFC] children: inline + line 0 width: 10.3125, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 1, rect: [108,25.46875 10.3125x17.46875] + "C" + TextNode <#text> + BlockContainer <(anonymous)> at (108,42.9375) content-size 684x0 children: inline + TextNode <#text> + BlockContainer <(anonymous)> at (8,42.9375) content-size 784x0 children: inline + TextNode <#text> diff --git a/Tests/LibWeb/Layout/input/block-and-inline/block-with-hidden-overflow-after-float.html b/Tests/LibWeb/Layout/input/block-and-inline/block-with-hidden-overflow-after-float.html index a4c83839ce6..5cc0534169e 100644 --- a/Tests/LibWeb/Layout/input/block-and-inline/block-with-hidden-overflow-after-float.html +++ b/Tests/LibWeb/Layout/input/block-and-inline/block-with-hidden-overflow-after-float.html @@ -20,7 +20,9 @@
-
A
+
+
A
+
B
diff --git a/Tests/LibWeb/Layout/input/block-and-inline/block-with-hidden-overflow-after-sibling-float.html b/Tests/LibWeb/Layout/input/block-and-inline/block-with-hidden-overflow-after-sibling-float.html new file mode 100644 index 00000000000..95522929c9f --- /dev/null +++ b/Tests/LibWeb/Layout/input/block-and-inline/block-with-hidden-overflow-after-sibling-float.html @@ -0,0 +1,26 @@ + + +
+
+
+
AAAA
+
A
+
+
+
+
B
+
C
+
+
\ No newline at end of file diff --git a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp index 3a30bfd92d9..b5778078e7b 100644 --- a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp @@ -802,6 +802,18 @@ void BlockFormattingContext::place_block_level_element_in_normal_flow_vertically box_state.set_content_offset(CSSPixelPoint { box_state.offset.x(), y }); } +// 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); @@ -814,7 +826,12 @@ void BlockFormattingContext::place_block_level_element_in_normal_flow_horizontal auto box_in_root_rect = content_box_rect_in_ancestor_coordinate_space(child_box, 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; - x += space_and_containing_margin.left_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); } if (child_box.containing_block()->computed_values().text_align() == CSS::TextAlign::LibwebCenter) { @@ -1056,6 +1073,7 @@ BlockFormattingContext::SpaceUsedAndContainingMarginForFloats BlockFormattingCon + floating_box_state.content_width() + floating_box_state.margin_box_right(); space_and_containing_margin.left_total_containing_margin = offset_from_containing_block_chain_margins_between_here_and_root; + space_and_containing_margin.matching_left_float_box = floating_box.box.ptr(); break; } } diff --git a/Userland/Libraries/LibWeb/Layout/FormattingContext.h b/Userland/Libraries/LibWeb/Layout/FormattingContext.h index d6280279218..68eb0f0993f 100644 --- a/Userland/Libraries/LibWeb/Layout/FormattingContext.h +++ b/Userland/Libraries/LibWeb/Layout/FormattingContext.h @@ -121,6 +121,7 @@ protected: // Each block in the containing chain adds its own margin and we store the total here. CSSPixels left_total_containing_margin; CSSPixels right_total_containing_margin; + Box const* matching_left_float_box { nullptr }; }; struct ShrinkToFitResult {