From ce186dca708f836521d237f321c3ffca0f50d704 Mon Sep 17 00:00:00 2001 From: Andi Gallo Date: Tue, 13 Jun 2023 13:37:15 +0000 Subject: [PATCH] LibWeb: Fix the x coordinate of a block after a float The margin from the containing blocks shouldn't be included in the amount by which we increment x after a float was places. That coordinate should be relative to the containing block. Fixes the comments layout on https://lobste.rs. --- ...block-with-hidden-overflow-after-float.txt | 25 ++++++++++++++++ ...lock-with-hidden-overflow-after-float.html | 29 +++++++++++++++++++ .../LibWeb/Layout/BlockFormattingContext.cpp | 28 +++++++++--------- .../LibWeb/Layout/BlockFormattingContext.h | 2 +- .../LibWeb/Layout/FormattingContext.h | 10 +++++++ .../LibWeb/Layout/InlineFormattingContext.cpp | 11 +++---- 6 files changed, 86 insertions(+), 19 deletions(-) create mode 100644 Tests/LibWeb/Layout/expected/block-and-inline/block-with-hidden-overflow-after-float.txt create mode 100644 Tests/LibWeb/Layout/input/block-and-inline/block-with-hidden-overflow-after-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 new file mode 100644 index 0000000000..30cf7f8f41 --- /dev/null +++ b/Tests/LibWeb/Layout/expected/block-and-inline/block-with-hidden-overflow-after-float.txt @@ -0,0 +1,25 @@ +Viewport <#document> at (0,0) content-size 800x600 children: not-inline + BlockContainer at (0,0) content-size 800x33.46875 [BFC] children: not-inline + BlockContainer <(anonymous)> at (0,0) content-size 800x0 children: inline + TextNode <#text> + BlockContainer at (8,8) content-size 784x17.46875 children: not-inline + BlockContainer <(anonymous)> at (8,8) content-size 784x0 children: inline + TextNode <#text> + 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 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 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] + "B" + TextNode <#text> + BlockContainer <(anonymous)> at (108,25.46875) content-size 684x0 children: inline + TextNode <#text> + BlockContainer <(anonymous)> at (8,25.46875) 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 new file mode 100644 index 0000000000..a4c83839ce --- /dev/null +++ b/Tests/LibWeb/Layout/input/block-and-inline/block-with-hidden-overflow-after-float.html @@ -0,0 +1,29 @@ + + + + + Block with hidden overflow after float + + + + +
+
A
+
B
+
+ + + + \ No newline at end of file diff --git a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp index 25f2d741cd..ce612d16cf 100644 --- a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp @@ -808,9 +808,9 @@ void BlockFormattingContext::place_block_level_element_in_normal_flow_horizontal if ((!m_left_floats.current_boxes.is_empty() || !m_right_floats.current_boxes.is_empty()) && creates_block_formatting_context(child_box)) { auto box_in_root_rect = content_box_rect_in_ancestor_coordinate_space(child_box, root()); - auto space = space_used_by_floats(box_in_root_rect.y()); - available_width_within_containing_block -= space.left + space.right; - x += space.left; + 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; } if (child_box.containing_block()->computed_values().text_align() == CSS::TextAlign::LibwebCenter) { @@ -1027,9 +1027,9 @@ void BlockFormattingContext::layout_list_item_marker(ListItemBox const& list_ite list_item_state.set_content_height(marker_state.content_height()); } -BlockFormattingContext::SpaceUsedByFloats BlockFormattingContext::space_used_by_floats(CSSPixels y) const +BlockFormattingContext::SpaceUsedAndContainingMarginForFloats BlockFormattingContext::space_used_and_containing_margin_for_floats(CSSPixels y) const { - SpaceUsedByFloats space_used_by_floats; + SpaceUsedAndContainingMarginForFloats space_and_containing_margin; for (auto const& floating_box_ptr : m_left_floats.all_boxes.in_reverse()) { auto const& floating_box = *floating_box_ptr; @@ -1042,10 +1042,10 @@ BlockFormattingContext::SpaceUsedByFloats BlockFormattingContext::space_used_by_ auto const& containing_block_state = m_state.get(*containing_block); offset_from_containing_block_chain_margins_between_here_and_root += containing_block_state.margin_box_left(); } - space_used_by_floats.left = offset_from_containing_block_chain_margins_between_here_and_root - + floating_box.offset_from_edge + space_and_containing_margin.left_used_space = floating_box.offset_from_edge + 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; break; } } @@ -1061,14 +1061,14 @@ BlockFormattingContext::SpaceUsedByFloats BlockFormattingContext::space_used_by_ auto const& containing_block_state = m_state.get(*containing_block); offset_from_containing_block_chain_margins_between_here_and_root += containing_block_state.margin_box_right(); } - space_used_by_floats.right = offset_from_containing_block_chain_margins_between_here_and_root - + floating_box.offset_from_edge + space_and_containing_margin.right_used_space = floating_box.offset_from_edge + floating_box_state.margin_box_left(); + space_and_containing_margin.right_total_containing_margin = offset_from_containing_block_chain_margins_between_here_and_root; break; } } - return space_used_by_floats; + return space_and_containing_margin; } FormattingContext::SpaceUsedByFloats BlockFormattingContext::intrusion_by_floats_into_box(Box const& box, CSSPixels y_in_box) const @@ -1076,16 +1076,18 @@ FormattingContext::SpaceUsedByFloats BlockFormattingContext::intrusion_by_floats // NOTE: Floats are relative to the BFC root box, not necessarily the containing block of this IFC. auto box_in_root_rect = content_box_rect_in_ancestor_coordinate_space(box, root()); CSSPixels y_in_root = box_in_root_rect.y() + y_in_box; - auto space_used_by_floats_in_root = space_used_by_floats(y_in_root); + auto space_and_containing_margin = space_used_and_containing_margin_for_floats(y_in_root); + auto left_side_floats_limit_to_right = space_and_containing_margin.left_total_containing_margin + space_and_containing_margin.left_used_space; + auto right_side_floats_limit_to_right = space_and_containing_margin.right_used_space + space_and_containing_margin.right_total_containing_margin; - auto left_intrusion = max(CSSPixels(0), space_used_by_floats_in_root.left - max(CSSPixels(0), box_in_root_rect.x())); + auto left_intrusion = max(CSSPixels(0), left_side_floats_limit_to_right - max(CSSPixels(0), box_in_root_rect.x())); CSSPixels offset_from_containing_block_chain_margins_between_here_and_root = 0; for (auto const* containing_block = static_cast(&box); containing_block && containing_block != &root(); containing_block = containing_block->containing_block()) { auto const& containing_block_state = m_state.get(*containing_block); offset_from_containing_block_chain_margins_between_here_and_root = max(offset_from_containing_block_chain_margins_between_here_and_root, containing_block_state.margin_box_right()); } - auto right_intrusion = max(CSSPixels(0), space_used_by_floats_in_root.right - offset_from_containing_block_chain_margins_between_here_and_root); + auto right_intrusion = max(CSSPixels(0), right_side_floats_limit_to_right - offset_from_containing_block_chain_margins_between_here_and_root); return { left_intrusion, right_intrusion }; } diff --git a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h index 88dd19d2c2..7f7ea6c549 100644 --- a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h +++ b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h @@ -39,7 +39,7 @@ public: void add_absolutely_positioned_box(Box const& box) { m_absolutely_positioned_boxes.append(box); } - SpaceUsedByFloats space_used_by_floats(CSSPixels y) const; + SpaceUsedAndContainingMarginForFloats space_used_and_containing_margin_for_floats(CSSPixels y) const; SpaceUsedByFloats intrusion_by_floats_into_box(Box const&, CSSPixels y_in_box) const; virtual CSSPixels greatest_child_width(Box const&) const override; diff --git a/Userland/Libraries/LibWeb/Layout/FormattingContext.h b/Userland/Libraries/LibWeb/Layout/FormattingContext.h index 6c5cceb0e1..3a0db1a3bb 100644 --- a/Userland/Libraries/LibWeb/Layout/FormattingContext.h +++ b/Userland/Libraries/LibWeb/Layout/FormattingContext.h @@ -107,6 +107,16 @@ protected: CSSPixels right { 0 }; }; + struct SpaceUsedAndContainingMarginForFloats { + // Width for left / right floats, including their own margins. + CSSPixels left_used_space; + CSSPixels right_used_space; + // Left / right total margins from the outermost containing block to the floating element. + // 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; + }; + struct ShrinkToFitResult { CSSPixels preferred_width { 0 }; CSSPixels preferred_minimum_width { 0 }; diff --git a/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp index 1b5a5b158d..ba201757e1 100644 --- a/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp @@ -41,15 +41,16 @@ CSSPixels InlineFormattingContext::leftmost_x_offset_at(CSSPixels y) const // NOTE: Floats are relative to the BFC root box, not necessarily the containing block of this IFC. auto box_in_root_rect = content_box_rect_in_ancestor_coordinate_space(containing_block(), parent().root()); CSSPixels y_in_root = box_in_root_rect.y() + y; - auto space = parent().space_used_by_floats(y_in_root); - if (box_in_root_rect.x() >= space.left) { + auto space_and_containing_margin = parent().space_used_and_containing_margin_for_floats(y_in_root); + auto left_side_floats_limit_to_right = space_and_containing_margin.left_total_containing_margin + space_and_containing_margin.left_used_space; + if (box_in_root_rect.x() >= left_side_floats_limit_to_right) { // The left edge of the containing block is to the right of the rightmost left-side float. // We start placing inline content at the left edge of the containing block. return 0; } // The left edge of the containing block is to the left of the rightmost left-side float. // We adjust the inline content insertion point by the overlap between the containing block and the float. - return space.left - max(CSSPixels(0), box_in_root_rect.x()); + return left_side_floats_limit_to_right - max(CSSPixels(0), box_in_root_rect.x()); } CSSPixels InlineFormattingContext::available_space_for_line(CSSPixels y) const @@ -319,8 +320,8 @@ bool InlineFormattingContext::any_floats_intrude_at_y(CSSPixels y) const { auto box_in_root_rect = content_box_rect_in_ancestor_coordinate_space(containing_block(), parent().root()); CSSPixels y_in_root = box_in_root_rect.y() + y; - auto space = parent().space_used_by_floats(y_in_root); - return space.left > 0 || space.right > 0; + auto space_and_containing_margin = parent().space_used_and_containing_margin_for_floats(y_in_root); + return space_and_containing_margin.left_used_space > 0 || space_and_containing_margin.right_used_space > 0; } bool InlineFormattingContext::can_fit_new_line_at_y(CSSPixels y) const