LibWeb: Fix percentage insets resolution for grid items

compute_inset() was incorrectly retrieving the containing block size
because containing_block() is unaware of grid areas that form a
containing block for grid items but do not exist in the layout tree.
With this change, we explicitly pass the containing block into
compute_inset(), allowing it to correctly provide the containing block
sizes for grid items.
This commit is contained in:
Aliaksandr Kalenik 2024-11-11 15:54:21 +01:00 committed by Andreas Kling
parent 07d8ddb5fa
commit a8c1d12e84
Notes: github-actions[bot] 2024-11-11 19:21:44 +00:00
9 changed files with 102 additions and 12 deletions

View file

@ -793,7 +793,8 @@ void BlockFormattingContext::layout_block_level_box(Box const& box, BlockContain
m_margin_state.add_margin(box_state.margin_bottom);
m_margin_state.update_block_waiting_for_final_y_position();
compute_inset(box);
auto const& block_container_state = m_state.get(block_container);
compute_inset(box, content_box_rect(block_container_state).size());
// Now that our children are formatted we place the ListItemBox with the left space we remembered.
if (is<ListItemBox>(box)) {
@ -1012,7 +1013,8 @@ void BlockFormattingContext::layout_floating_box(Box const& box, BlockContainer
auto& box_state = m_state.get_mutable(box);
auto const& computed_values = box.computed_values();
resolve_vertical_box_model_metrics(box, m_state.get(block_container).content_width());
auto const& block_container_state = m_state.get(block_container);
resolve_vertical_box_model_metrics(box, block_container_state.content_width());
compute_width(box, available_space);
@ -1166,7 +1168,7 @@ void BlockFormattingContext::layout_floating_box(Box const& box, BlockContainer
if (line_builder)
line_builder->recalculate_available_space();
compute_inset(box);
compute_inset(box, content_box_rect(block_container_state).size());
if (independent_formatting_context)
independent_formatting_context->parent_context_did_dimension_child_root_box();

View file

@ -176,7 +176,7 @@ void FlexFormattingContext::run(AvailableSpace const& available_space)
if (auto independent_formatting_context = layout_inside(item.box, LayoutMode::Normal, item.used_values.available_inner_space_or_constraints_from(m_available_space_for_items->space)))
independent_formatting_context->parent_context_did_dimension_child_root_box();
compute_inset(item.box);
compute_inset(item.box, content_box_rect(m_flex_container_state).size());
}
}
}

View file

@ -1328,7 +1328,7 @@ void FormattingContext::compute_height_for_absolutely_positioned_replaced_elemen
}
// https://www.w3.org/TR/css-position-3/#relpos-insets
void FormattingContext::compute_inset(NodeWithStyleAndBoxModelMetrics const& box)
void FormattingContext::compute_inset(NodeWithStyleAndBoxModelMetrics const& box, CSSPixelSize containing_block_size)
{
if (box.computed_values().position() != CSS::Positioning::Relative)
return;
@ -1363,8 +1363,8 @@ void FormattingContext::compute_inset(NodeWithStyleAndBoxModelMetrics const& box
auto const& computed_values = box.computed_values();
// FIXME: Respect the containing block's writing-mode.
resolve_two_opposing_insets(computed_values.inset().left(), computed_values.inset().right(), box_state.inset_left, box_state.inset_right, containing_block_width_for(box));
resolve_two_opposing_insets(computed_values.inset().top(), computed_values.inset().bottom(), box_state.inset_top, box_state.inset_bottom, containing_block_height_for(box));
resolve_two_opposing_insets(computed_values.inset().left(), computed_values.inset().right(), box_state.inset_left, box_state.inset_right, containing_block_size.width());
resolve_two_opposing_insets(computed_values.inset().top(), computed_values.inset().bottom(), box_state.inset_top, box_state.inset_bottom, containing_block_size.height());
}
// https://drafts.csswg.org/css-sizing-3/#fit-content-size

View file

@ -106,7 +106,7 @@ public:
bool can_skip_is_anonymous_text_run(Box&);
void compute_inset(NodeWithStyleAndBoxModelMetrics const&);
void compute_inset(NodeWithStyleAndBoxModelMetrics const&, CSSPixelSize containing_block_size);
protected:
FormattingContext(Type, LayoutMode, LayoutState&, Box const&, FormattingContext* parent = nullptr);

View file

@ -2060,8 +2060,9 @@ void GridFormattingContext::run(AvailableSpace const& available_space)
for (auto& grid_item : m_grid_items) {
auto& grid_item_box_state = m_state.get_mutable(grid_item.box);
CSSPixelPoint margin_offset = { grid_item_box_state.margin_box_left(), grid_item_box_state.margin_box_top() };
grid_item_box_state.offset = get_grid_area_rect(grid_item).top_left() + margin_offset;
compute_inset(grid_item.box);
auto const grid_area_rect = get_grid_area_rect(grid_item);
grid_item_box_state.offset = grid_area_rect.top_left() + margin_offset;
compute_inset(grid_item.box, grid_area_rect.size());
auto available_space_for_children = AvailableSpace(AvailableSize::make_definite(grid_item_box_state.content_width()), AvailableSize::make_definite(grid_item_box_state.content_height()));
if (auto independent_formatting_context = layout_inside(grid_item.box, LayoutMode::Normal, available_space_for_children))

View file

@ -294,7 +294,7 @@ void InlineFormattingContext::generate_line_boxes()
}
case InlineLevelIterator::Item::Type::Element: {
auto& box = verify_cast<Layout::Box>(*item.node);
compute_inset(box);
compute_inset(box, content_box_rect(m_containing_block_used_values).size());
if (containing_block().computed_values().white_space() != CSS::WhiteSpace::Nowrap) {
auto minimum_space_needed_on_line = item.border_box_width();
if (item.margin_start < 0)

View file

@ -48,7 +48,7 @@ void InlineLevelIterator::enter_node_with_box_model_metrics(Layout::NodeWithStyl
m_extra_leading_metrics->padding += used_values.padding_left;
// Now's our chance to resolve the inset properties for this node.
m_inline_formatting_context.compute_inset(node);
m_inline_formatting_context.compute_inset(node, m_inline_formatting_context.content_box_rect(m_containing_block_used_values).size());
m_box_model_node_stack.append(node);
}

View file

@ -0,0 +1,54 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (0,0) content-size 800x318 [BFC] children: not-inline
BlockContainer <body> at (8,8) content-size 784x302 children: not-inline
Box <div.grid-container> at (9,9) content-size 300x300 [GFC] children: not-inline
BlockContainer <(anonymous)> (not painted) [BFC] children: inline
TextNode <#text>
Box <div.grid-item> at (20,20) content-size 123x123 flex-container(row) [FFC] children: not-inline
BlockContainer <(anonymous)> at (58.140625,73) content-size 46.71875x17 flex-item [BFC] children: inline
frag 0 from TextNode start: 0, length: 6, rect: [58.140625,73 46.71875x17] baseline: 13.296875
"Item 1"
TextNode <#text>
BlockContainer <(anonymous)> (not painted) [BFC] children: inline
TextNode <#text>
Box <div.grid-item.relative-item> at (247.5,97.5) content-size 123x123 positioned flex-container(row) [FFC] children: not-inline
BlockContainer <(anonymous)> at (284.40625,150.5) content-size 49.1875x17 flex-item [BFC] children: inline
frag 0 from TextNode start: 0, length: 6, rect: [284.40625,150.5 49.1875x17] baseline: 13.296875
"Item 2"
TextNode <#text>
BlockContainer <(anonymous)> (not painted) [BFC] children: inline
TextNode <#text>
Box <div.grid-item> at (20,175) content-size 123x123 flex-container(row) [FFC] children: not-inline
BlockContainer <(anonymous)> at (56.765625,228) content-size 49.46875x17 flex-item [BFC] children: inline
frag 0 from TextNode start: 0, length: 6, rect: [56.765625,228 49.46875x17] baseline: 13.296875
"Item 3"
TextNode <#text>
BlockContainer <(anonymous)> (not painted) [BFC] children: inline
TextNode <#text>
Box <div.grid-item> at (175,175) content-size 123x123 flex-container(row) [FFC] children: not-inline
BlockContainer <(anonymous)> at (212.4375,228) content-size 48.125x17 flex-item [BFC] children: inline
frag 0 from TextNode start: 0, length: 6, rect: [212.4375,228 48.125x17] baseline: 13.296875
"Item 4"
TextNode <#text>
BlockContainer <(anonymous)> (not painted) [BFC] children: inline
TextNode <#text>
BlockContainer <(anonymous)> at (8,310) content-size 784x0 children: inline
TextNode <#text>
ViewportPaintable (Viewport<#document>) [0,0 800x600]
PaintableWithLines (BlockContainer<HTML>) [0,0 800x318]
PaintableWithLines (BlockContainer<BODY>) [8,8 784x302]
PaintableBox (Box<DIV>.grid-container) [8,8 302x302] overflow: [9,9 372.5x300]
PaintableBox (Box<DIV>.grid-item) [9,9 145x145]
PaintableWithLines (BlockContainer(anonymous)) [58.140625,73 46.71875x17]
TextPaintable (TextNode<#text>)
PaintableBox (Box<DIV>.grid-item.relative-item) [236.5,86.5 145x145]
PaintableWithLines (BlockContainer(anonymous)) [284.40625,150.5 49.1875x17]
TextPaintable (TextNode<#text>)
PaintableBox (Box<DIV>.grid-item) [9,164 145x145]
PaintableWithLines (BlockContainer(anonymous)) [56.765625,228 49.46875x17]
TextPaintable (TextNode<#text>)
PaintableBox (Box<DIV>.grid-item) [164,164 145x145]
PaintableWithLines (BlockContainer(anonymous)) [212.4375,228 48.125x17]
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer(anonymous)) [8,310 784x0]

View file

@ -0,0 +1,33 @@
<!DOCTYPE html>
<style>
.grid-container {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 10px;
width: 300px;
height: 300px;
border: 1px solid #ccc;
}
.grid-item {
display: flex;
align-items: center;
justify-content: center;
background-color: #eee;
border: 1px solid #aaa;
padding: 10px;
}
.relative-item {
position: relative;
left: 50%;
top: 50%;
background-color: #cce;
}
</style>
<div class="grid-container">
<div class="grid-item">Item 1</div>
<div class="grid-item relative-item">Item 2</div>
<div class="grid-item">Item 3</div>
<div class="grid-item">Item 4</div>
</div>