LibWeb: Fix abspos layout when box is contained by grid area
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

Before this change, `layout_absolutely_positioned_element()` in GFC
had an assumption that all contained by grid container abspos boxes were
also direct children of the grid container. This change adds handling
for the cases when it's not true and, in order to identify grid area
abspos box belongs to, we have to find ancestor grid item.
This commit is contained in:
Aliaksandr Kalenik 2025-08-17 16:57:31 +02:00 committed by Andreas Kling
commit 80c8e787a8
Notes: github-actions[bot] 2025-08-17 15:59:19 +00:00
3 changed files with 72 additions and 12 deletions

View file

@ -2109,27 +2109,48 @@ void GridFormattingContext::run(AvailableSpace const& available_space)
m_grid_container_used_values.set_grid_template_rows(CSS::GridTrackSizeListStyleValue::create(move(grid_track_rows)));
}
// https://www.w3.org/TR/css-grid-2/#abspos-items
void GridFormattingContext::layout_absolutely_positioned_element(Box const& box)
{
auto& box_state = m_state.get_mutable(box);
auto const& computed_values = box.computed_values();
auto grid_area_rect = [&] -> CSSPixelRect {
// NOTE: Grid areas form containing blocks for abspos elements, but
// `Node::containing_block()` is not aware of that. Therefore, we need to
// find the closest grid item ancestor in order to identify grid area it belongs to.
NodeWithStyle const* containing_grid_item = &box;
while (containing_grid_item->parent() && !containing_grid_item->parent()->display().is_grid_inside())
containing_grid_item = containing_grid_item->parent();
auto const& computed_values = containing_grid_item->computed_values();
VERIFY(containing_grid_item);
// NOTE: If abspos box is contained by in-flow grid item its grid position is already determined.
if (containing_grid_item->is_grid_item()) {
auto item = *m_grid_items.find_if([containing_grid_item](GridItem const& grid_item) {
return grid_item.box == containing_grid_item;
});
return get_grid_area_rect(item);
}
GridItem item { as<Box>(*containing_grid_item), box_state, {}, {}, {}, {} };
auto is_auto_row = is_auto_positioned_track(computed_values.grid_row_start(), computed_values.grid_row_end());
auto is_auto_column = is_auto_positioned_track(computed_values.grid_column_start(), computed_values.grid_column_end());
GridItem item { box, box_state, {}, {}, {}, {} };
if (!is_auto_row) {
auto row_placement_position = resolve_grid_position(box, GridDimension::Row);
auto column_placement_position = resolve_grid_position(box, GridDimension::Column);
if (!is_auto_row) {
item.row = row_placement_position.start;
item.row_span = row_placement_position.span;
}
if (!is_auto_column) {
auto column_placement_position = resolve_grid_position(box, GridDimension::Column);
item.column = column_placement_position.start;
item.column_span = column_placement_position.span;
}
return get_grid_area_rect(item);
}();
auto grid_area_rect = get_grid_area_rect(item);
auto available_width = AvailableSize::make_definite(grid_area_rect.width());
auto available_height = AvailableSize::make_definite(grid_area_rect.height());
AvailableSpace available_space { available_width, available_height };

View file

@ -0,0 +1,20 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (0,0) content-size 800x16 [BFC] children: not-inline
BlockContainer <body> at (8,8) content-size 784x0 children: not-inline
Box <div.gfc> at (8,8) content-size 800x600 positioned [GFC] children: not-inline
BlockContainer <div.grid-item> at (408,8) content-size 400x600 [BFC] children: not-inline
BlockContainer <div.abspos> at (408,8) content-size 100x18 positioned [BFC] children: inline
frag 0 from TextNode start: 0, length: 5, rect: [408,8 39.78125x18] baseline: 13.796875
"Hello"
TextNode <#text>
ViewportPaintable (Viewport<#document>) [0,0 800x600] overflow: [0,0 808x608]
PaintableWithLines (BlockContainer<HTML>) [0,0 800x16]
PaintableWithLines (BlockContainer<BODY>) [8,8 784x0]
PaintableBox (Box<DIV>.gfc) [8,8 800x600]
PaintableWithLines (BlockContainer<DIV>.grid-item) [408,8 400x600]
PaintableWithLines (BlockContainer<DIV>.abspos) [408,8 100x18]
TextPaintable (TextNode<#text>)
SC for Viewport<#document> [0,0 800x600] [children: 1] (z-index: auto)
SC for BlockContainer<HTML> [0,0 800x16] [children: 0] (z-index: auto)

View file

@ -0,0 +1,19 @@
<!DOCTYPE html><style>
.gfc {
display: grid;
grid-template-columns: 1fr [right-start] 1fr [grid-end];
position: absolute;
width: 100%;
height: 100%;
background-color: lightpink;
}
.grid-item {
grid-column: right-start/grid-end;
background-color: magenta;
}
.abspos {
position: absolute;
width: 100px;
background-color: orange;
}
</style><div class="gfc"><div class="grid-item"><div class="abspos">Hello</div></div></div>