LibWeb: Overlap float space and left margins for all shared ancestors
Some checks are pending
CI / Lagom (x86_64, Fuzzers_CI, false, ubuntu-24.04, Linux, Clang) (push) Waiting to run
CI / Lagom (arm64, Sanitizer_CI, false, macos-15, macOS, Clang) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, false, ubuntu-24.04, Linux, GNU) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, true, ubuntu-24.04, Linux, Clang) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (arm64, macos-15, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (x86_64, ubuntu-24.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run

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.
This commit is contained in:
Jelle Raaijmakers 2025-05-09 12:03:48 +02:00 committed by Andreas Kling
commit 123abe0e79
Notes: github-actions[bot] 2025-05-09 12:14:00 +00:00
3 changed files with 73 additions and 18 deletions

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2020-2022, Andreas Kling <andreas@ladybird.org> * Copyright (c) 2020-2022, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2025, Jelle Raaijmakers <jelle@ladybird.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * 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()); 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) 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); 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 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()); 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; 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()); x = space_and_containing_margin.left_used_space;
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; // All non-anonymous containing blocks that are ancestors of the child box, but are not ancestors of the left
else // float box, might have left margins set that overlap with the used float space.
// 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. if (space_and_containing_margin.matching_left_float_box) {
x = max(space_and_containing_margin.left_used_space - containing_box_state.margin_left, 0); 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) { if (child_box.containing_block()->computed_values().text_align() == CSS::TextAlign::LibwebCenter) {

View file

@ -0,0 +1,37 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (0,0) content-size 800x48 [BFC] children: not-inline
BlockContainer <body> at (8,8) content-size 784x22 children: not-inline
BlockContainer <(anonymous)> at (8,8) content-size 784x0 children: inline
BlockContainer <div#a> at (8,8) content-size 100x40 floating [BFC] children: not-inline
TextNode <#text>
BlockContainer <div#b> at (109,9) content-size 682x20 children: not-inline
BlockContainer <(anonymous)> at (109,9) content-size 682x0 children: inline
TextNode <#text>
BlockContainer <div> at (109,9) content-size 682x20 children: not-inline
BlockContainer <(anonymous)> at (109,9) content-size 682x0 children: inline
TextNode <#text>
BlockContainer <div#c> 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<HTML>) [0,0 800x48]
PaintableWithLines (BlockContainer<BODY>) [8,8 784x22]
PaintableWithLines (BlockContainer(anonymous)) [8,8 784x0]
PaintableWithLines (BlockContainer<DIV>#a) [8,8 100x40]
PaintableWithLines (BlockContainer<DIV>#b) [108,8 684x22]
PaintableWithLines (BlockContainer(anonymous)) [109,9 682x0]
PaintableWithLines (BlockContainer<DIV>) [109,9 682x20]
PaintableWithLines (BlockContainer(anonymous)) [109,9 682x0]
PaintableWithLines (BlockContainer<DIV>#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]

View file

@ -0,0 +1,23 @@
<!DOCTYPE html>
<style>
#a {
background: green;
float: left;
height: 40px;
width: 100px;
}
#b {
border: 1px solid black;
margin-left: 100px;
}
#c {
border: 1px solid red;
overflow: hidden;
}
</style>
<div id="a"></div>
<div id="b">
<div>
<div id="c">foo</div>
</div>
</div>