From 6d911a6baaa78b9c28c68caf3e5eb364b504f4f4 Mon Sep 17 00:00:00 2001 From: Jelle Raaijmakers Date: Tue, 1 Apr 2025 11:01:15 +0200 Subject: [PATCH] LibWeb: Resolve block height correctly after line break with `clear: ..` If a block with inline children ends with a line break clearing any floats, we not only need to take the introduced clearance into account for the next line box, but the containing block needs to set the correct height as well. Since the spec calls for using the last line box' bottom as the resolved height (if treated as auto), we now correctly apply the clearance to the previous line box' bottom coordinate. Fixes #4058. --- .../LibWeb/Layout/InlineFormattingContext.cpp | 3 +-- Libraries/LibWeb/Layout/LineBuilder.cpp | 21 +++++++++++++-- Libraries/LibWeb/Layout/LineBuilder.h | 3 ++- ...at-clear-by-line-break-at-end-of-block.txt | 26 +++++++++++++++++++ ...-clear-by-line-break-followed-by-block.txt | 4 +-- ...t-clear-by-line-break-at-end-of-block.html | 26 +++++++++++++++++++ ...clear-by-line-break-followed-by-block.html | 18 ++++++------- 7 files changed, 85 insertions(+), 16 deletions(-) create mode 100644 Tests/LibWeb/Layout/expected/block-and-inline/float-clear-by-line-break-at-end-of-block.txt create mode 100644 Tests/LibWeb/Layout/input/block-and-inline/float-clear-by-line-break-at-end-of-block.html diff --git a/Libraries/LibWeb/Layout/InlineFormattingContext.cpp b/Libraries/LibWeb/Layout/InlineFormattingContext.cpp index d4db75123fc..c906e57c9e4 100644 --- a/Libraries/LibWeb/Layout/InlineFormattingContext.cpp +++ b/Libraries/LibWeb/Layout/InlineFormattingContext.cpp @@ -282,8 +282,7 @@ void InlineFormattingContext::generate_line_boxes() if (item.node) { auto introduce_clearance = parent().clear_floating_boxes(*item.node, *this); if (introduce_clearance == BlockFormattingContext::DidIntroduceClearance::Yes) { - if (vertical_float_clearance() > line_builder.current_block_offset()) - line_builder.set_current_block_offset(vertical_float_clearance()); + line_builder.did_introduce_clearance(vertical_float_clearance()); parent().reset_margin_state(); } } diff --git a/Libraries/LibWeb/Layout/LineBuilder.cpp b/Libraries/LibWeb/Layout/LineBuilder.cpp index e0f3b2a4ceb..1f70212f466 100644 --- a/Libraries/LibWeb/Layout/LineBuilder.cpp +++ b/Libraries/LibWeb/Layout/LineBuilder.cpp @@ -75,9 +75,8 @@ void LineBuilder::begin_new_line(bool increment_y, bool is_first_break_in_sequen m_last_line_needs_update = true; // FIXME: Support text-indent with "each-line". - if (m_containing_block_used_values.line_boxes.size() <= 1) { + if (m_containing_block_used_values.line_boxes.size() <= 1) ensure_last_line_box().m_inline_length += m_text_indent; - } } LineBox& LineBuilder::ensure_last_line_box() @@ -417,4 +416,22 @@ void LineBuilder::recalculate_available_space() m_containing_block_used_values.line_boxes.last().m_original_available_width = m_available_width_for_current_line; } +void LineBuilder::did_introduce_clearance(CSSPixels clearance) +{ + // If clearance was introduced but our current line box starts beyond it, we don't need to do anything. + if (clearance <= m_current_block_offset) + return; + + // Increase the height of the previous line box so it matches the clearance, because the element's height is first + // determined by the bottom of the last line box (after trimming empty/whitespace boxes). + auto& line_boxes = m_containing_block_used_values.line_boxes; + if (line_boxes.size() > 1) { + auto& previous_line_box = line_boxes[line_boxes.size() - 2]; + previous_line_box.m_bottom = clearance; + } + + // The current line box will start directly after any cleared floats. + m_current_block_offset = clearance; +} + } diff --git a/Libraries/LibWeb/Layout/LineBuilder.h b/Libraries/LibWeb/Layout/LineBuilder.h index 26525e6d9bb..0f4f971d2dc 100644 --- a/Libraries/LibWeb/Layout/LineBuilder.h +++ b/Libraries/LibWeb/Layout/LineBuilder.h @@ -42,13 +42,14 @@ public: void remove_last_line_if_empty(); CSSPixels current_block_offset() const { return m_current_block_offset; } - void set_current_block_offset(CSSPixels block_offset) { m_current_block_offset = block_offset; } void recalculate_available_space(); CSSPixels y_for_float_to_be_inserted_here(Box const&); auto& inline_formatting_context() { return m_context; } + void did_introduce_clearance(CSSPixels); + private: void begin_new_line(bool increment_y, bool is_first_break_in_sequence = true); diff --git a/Tests/LibWeb/Layout/expected/block-and-inline/float-clear-by-line-break-at-end-of-block.txt b/Tests/LibWeb/Layout/expected/block-and-inline/float-clear-by-line-break-at-end-of-block.txt new file mode 100644 index 00000000000..f9cf9ec1a8c --- /dev/null +++ b/Tests/LibWeb/Layout/expected/block-and-inline/float-clear-by-line-break-at-end-of-block.txt @@ -0,0 +1,26 @@ +Viewport <#document> at (0,0) content-size 800x600 children: not-inline + BlockContainer at (0,0) content-size 800x416 [BFC] children: not-inline + BlockContainer at (8,8) content-size 784x400 children: not-inline + BlockContainer at (8,8) content-size 784x200 children: inline + frag 0 from TextNode start: 1, length: 3, rect: [8,8 27.15625x17] baseline: 13.296875 + "foo" + TextNode <#text> + BlockContainer at (292,8) content-size 500x200 floating [BFC] children: not-inline + TextNode <#text> + BreakNode + TextNode <#text> + BlockContainer <(anonymous)> at (8,208) content-size 784x0 children: inline + TextNode <#text> + BlockContainer at (8,208) content-size 500x200 children: not-inline + BlockContainer <(anonymous)> at (8,408) content-size 784x0 children: inline + TextNode <#text> + +ViewportPaintable (Viewport<#document>) [0,0 800x600] + PaintableWithLines (BlockContainer) [0,0 800x416] + PaintableWithLines (BlockContainer) [8,8 784x400] + PaintableWithLines (BlockContainer
.a) [8,8 784x200] + PaintableWithLines (BlockContainer
.b) [292,8 500x200] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer(anonymous)) [8,208 784x0] + PaintableWithLines (BlockContainer
.d) [8,208 500x200] + PaintableWithLines (BlockContainer(anonymous)) [8,408 784x0] diff --git a/Tests/LibWeb/Layout/expected/block-and-inline/float-clear-by-line-break-followed-by-block.txt b/Tests/LibWeb/Layout/expected/block-and-inline/float-clear-by-line-break-followed-by-block.txt index a05bd3ab745..ba0a21eaab1 100644 --- a/Tests/LibWeb/Layout/expected/block-and-inline/float-clear-by-line-break-followed-by-block.txt +++ b/Tests/LibWeb/Layout/expected/block-and-inline/float-clear-by-line-break-followed-by-block.txt @@ -2,7 +2,7 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline BlockContainer at (0,0) content-size 800x157 [BFC] children: not-inline BlockContainer at (8,8) content-size 784x133 children: not-inline BlockContainer at (8,8) content-size 100x100 floating [BFC] children: not-inline - BlockContainer <(anonymous)> at (8,8) content-size 784x17 children: inline + BlockContainer <(anonymous)> at (8,8) content-size 784x100 children: inline TextNode <#text> BreakNode TextNode <#text> @@ -17,7 +17,7 @@ ViewportPaintable (Viewport<#document>) [0,0 800x600] PaintableWithLines (BlockContainer) [0,0 800x157] PaintableWithLines (BlockContainer) [8,8 784x133] PaintableWithLines (BlockContainer
.a) [8,8 100x100] - PaintableWithLines (BlockContainer(anonymous)) [8,8 784x17] + PaintableWithLines (BlockContainer(anonymous)) [8,8 784x100] PaintableWithLines (BlockContainer

) [8,124 784x17] TextPaintable (TextNode<#text>) PaintableWithLines (BlockContainer(anonymous)) [8,157 784x0] diff --git a/Tests/LibWeb/Layout/input/block-and-inline/float-clear-by-line-break-at-end-of-block.html b/Tests/LibWeb/Layout/input/block-and-inline/float-clear-by-line-break-at-end-of-block.html new file mode 100644 index 00000000000..c1d67c38691 --- /dev/null +++ b/Tests/LibWeb/Layout/input/block-and-inline/float-clear-by-line-break-at-end-of-block.html @@ -0,0 +1,26 @@ + + +

+
+ foo +
+
+
diff --git a/Tests/LibWeb/Layout/input/block-and-inline/float-clear-by-line-break-followed-by-block.html b/Tests/LibWeb/Layout/input/block-and-inline/float-clear-by-line-break-followed-by-block.html index b14b79a9186..a96d489b3b0 100644 --- a/Tests/LibWeb/Layout/input/block-and-inline/float-clear-by-line-break-followed-by-block.html +++ b/Tests/LibWeb/Layout/input/block-and-inline/float-clear-by-line-break-followed-by-block.html @@ -1,14 +1,14 @@