LibWeb: Correctly position absolute inline boxes in last line
Some checks are pending
CI / macOS, arm64, Sanitizer, Clang (push) Waiting to run
CI / Linux, x86_64, Fuzzers, Clang (push) Waiting to run
CI / Linux, x86_64, Sanitizer, GNU (push) Waiting to run
CI / Linux, x86_64, Sanitizer, Clang (push) Waiting to run
Package the js repl as a binary artifact / Linux, arm64 (push) Waiting to run
Package the js repl as a binary artifact / macOS, arm64 (push) Waiting to run
Package the js repl as a binary artifact / 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

If we were calculating the static position for an absolutely positioned
inline box that resides in the last line of its containing block, we
would not have yet provided the fragments in that line with their
final positions. Additionally, we would always move the box beneath the
fragment, which was incorrect.

Fixes #5867.
This commit is contained in:
Jelle Raaijmakers 2025-08-28 00:03:09 +02:00 committed by Jelle Raaijmakers
commit c8d24d4966
Notes: github-actions[bot] 2025-08-28 11:46:46 +00:00
3 changed files with 33 additions and 20 deletions

View file

@ -443,12 +443,12 @@ void InlineFormattingContext::generate_line_boxes()
}
}
line_builder.update_last_line();
for (auto* box : absolute_boxes) {
auto& box_state = m_state.get_mutable(*box);
box_state.set_static_position_rect(calculate_static_position_rect(*box));
}
line_builder.update_last_line();
}
bool InlineFormattingContext::any_floats_intrude_at_block_offset(CSSPixels block_offset) const
@ -499,20 +499,13 @@ void InlineFormattingContext::set_vertical_float_clearance(CSSPixels vertical_fl
StaticPositionRect InlineFormattingContext::calculate_static_position_rect(Box const& box) const
{
CSSPixels x = 0;
CSSPixels y = 0;
VERIFY(box.parent());
VERIFY(box.parent()->children_are_inline());
// We're an abspos box with inline siblings. This is gonna get messy!
CSSPixelPoint position;
if (auto const* sibling = box.previous_sibling()) {
// Hard case: there's a previous sibling. This means there's already inline content
// preceding the hypothetical static position of `box` within its containing block.
// If we had been position:static, that inline content would have been wrapped in
// anonymous block box, so now we get to imagine what the world might have looked like
// in that scenario..
// Basically, we find its last associated line box fragment and place `box` under it.
// FIXME: I'm 100% sure this can be smarter, better and faster.
// We're calculating the position for an absolutely positioned box with a previous sibling in an IFC. We need to
// position the box at the top right corner of the last fragment of this sibling.
LineBoxFragment const* last_fragment = nullptr;
auto const& cb_state = m_state.get(*sibling->containing_block());
for (auto const& line_box : cb_state.line_boxes) {
@ -522,15 +515,12 @@ StaticPositionRect InlineFormattingContext::calculate_static_position_rect(Box c
}
}
if (last_fragment) {
x = last_fragment->offset().x() + last_fragment->width();
y = last_fragment->offset().y() + last_fragment->height();
position.set_x(last_fragment->offset().x() + last_fragment->width());
position.set_y(last_fragment->offset().y());
}
} else {
// Easy case: no previous sibling, we're at the top of the containing block.
}
StaticPositionRect static_position_rect;
static_position_rect.rect = { { x, y }, { 0, 0 } };
return static_position_rect;
return { .rect = { position, { 0, 0 } } };
}
}

View file

@ -0,0 +1,21 @@
Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-inline
BlockContainer <html> at [0,0] [0+0+0 800 0+0+0] [0+0+0 34 0+0+0] [BFC] children: not-inline
BlockContainer <body> at [8,8] [8+0+0 784 0+0+8] [8+0+0 18 0+0+8] children: inline
frag 0 from TextNode start: 0, length: 3, rect: [8,8 27.15625x18] baseline: 13.796875
"foo"
TextNode <#text> (not painted)
BlockContainer <span> at [35.15625,8] positioned [0+0+0 27.640625 0+0+0] [0+0+0 18 0+0+0] [BFC] children: inline
frag 0 from TextNode start: 0, length: 3, rect: [35.15625,8 27.640625x18] baseline: 13.796875
"bar"
TextNode <#text> (not painted)
TextNode <#text> (not painted)
ViewportPaintable (Viewport<#document>) [0,0 800x600]
PaintableWithLines (BlockContainer<HTML>) [0,0 800x34]
PaintableWithLines (BlockContainer<BODY>) [8,8 784x18]
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<SPAN>) [35.15625,8 27.640625x18]
TextPaintable (TextNode<#text>)
SC for Viewport<#document> [0,0 800x600] [children: 1] (z-index: auto)
SC for BlockContainer<HTML> [0,0 800x34] [children: 0] (z-index: auto)

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
foo <span style="position:absolute">bar</span>