mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-20 03:25:13 +00:00
LibWeb: Correctly calculate static position rect when absolutely
positioned element is a descendant of inline-block Sets inline block offsets in InlineFormattingContext.cpp, but this is not enough. When static position rect is calculated during layout, not all ancestors of abspos box may have their offsets calculated yet (more info here: https://github.com/LadybirdBrowser/ladybird/pull/2583#issuecomment-2507140272). So now static position rect is calculated relative to static containing block during layout and calculation relative to actual containing block is done later in FormattingContext::layout_absolutely_positioned_element. Fixes wpt/css/CSS2/abspos/static-inside-inline-block.html
This commit is contained in:
parent
1821896ecf
commit
a6935299eb
Notes:
github-actions[bot]
2025-03-17 14:56:06 +00:00
Author: https://github.com/stasoid Commit: https://github.com/LadybirdBrowser/ladybird/commit/a6935299eba Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3845 Reviewed-by: https://github.com/kalenikaliaksandr ✅
11 changed files with 45 additions and 16 deletions
|
@ -672,8 +672,7 @@ void BlockFormattingContext::layout_block_level_box(Box const& box, BlockContain
|
|||
|
||||
if (box.is_absolutely_positioned()) {
|
||||
StaticPositionRect static_position;
|
||||
auto offset_to_static_parent = content_box_rect_in_static_position_ancestor_coordinate_space(box, *box.containing_block());
|
||||
static_position.rect = { offset_to_static_parent.location().translated(0, m_y_offset_of_current_block_container.value()), { 0, 0 } };
|
||||
static_position.rect = { { 0, m_y_offset_of_current_block_container.value() }, { 0, 0 } };
|
||||
box_state.set_static_position_rect(static_position);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -2253,14 +2253,11 @@ StaticPositionRect FlexFormattingContext::calculate_static_position_rect(Box con
|
|||
break;
|
||||
}
|
||||
|
||||
auto absolute_position_of_flex_container = absolute_content_rect(flex_container()).location();
|
||||
auto absolute_position_of_abspos_containing_block = absolute_content_rect(*box.containing_block()).location();
|
||||
|
||||
auto flex_container_width = is_row_layout() ? inner_main_size(m_flex_container_state) : inner_cross_size(m_flex_container_state);
|
||||
auto flex_container_height = is_row_layout() ? inner_cross_size(m_flex_container_state) : inner_main_size(m_flex_container_state);
|
||||
|
||||
StaticPositionRect static_position_rect;
|
||||
static_position_rect.rect = { absolute_position_of_flex_container - absolute_position_of_abspos_containing_block, { flex_container_width, flex_container_height } };
|
||||
static_position_rect.rect = { { 0, 0 }, { flex_container_width, flex_container_height } };
|
||||
static_position_rect.horizontal_alignment = is_row_layout() ? main_axis_alignment : cross_axis_alignment;
|
||||
static_position_rect.vertical_alignment = is_row_layout() ? cross_axis_alignment : main_axis_alignment;
|
||||
return static_position_rect;
|
||||
|
|
|
@ -1179,7 +1179,6 @@ void FormattingContext::compute_height_for_absolutely_positioned_non_replaced_el
|
|||
box_state.margin_bottom = margin_bottom.to_px(box, width_of_containing_block);
|
||||
}
|
||||
|
||||
// NOTE: This is different from content_box_rect_in_ancestor_coordinate_space() as this does *not* follow the containing block chain up, but rather the parent() chain.
|
||||
CSSPixelRect FormattingContext::content_box_rect_in_static_position_ancestor_coordinate_space(Box const& box, Box const& ancestor_box) const
|
||||
{
|
||||
auto rect = content_box_rect(box);
|
||||
|
@ -1261,6 +1260,8 @@ void FormattingContext::layout_absolutely_positioned_element(Box const& box, Ava
|
|||
CSSPixelPoint used_offset;
|
||||
|
||||
auto static_position = m_state.get(box).static_position();
|
||||
auto offset_to_static_parent = content_box_rect_in_static_position_ancestor_coordinate_space(box, *box.containing_block());
|
||||
static_position += offset_to_static_parent.location();
|
||||
|
||||
if (box.computed_values().inset().top().is_auto() && box.computed_values().inset().bottom().is_auto()) {
|
||||
used_offset.set_y(static_position.y());
|
||||
|
|
|
@ -2632,8 +2632,7 @@ StaticPositionRect GridFormattingContext::calculate_static_position_rect(Box con
|
|||
// layout_absolutely_positioned_element() defined for GFC knows how to handle this case.
|
||||
StaticPositionRect static_position;
|
||||
auto const& box_state = m_state.get(box);
|
||||
auto offset_to_static_parent = content_box_rect_in_static_position_ancestor_coordinate_space(box, *box.containing_block());
|
||||
static_position.rect = { offset_to_static_parent.location().translated(0, 0), { box_state.content_width(), box_state.content_height() } };
|
||||
static_position.rect = { { 0, 0 }, { box_state.content_width(), box_state.content_height() } };
|
||||
return static_position;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -411,6 +411,16 @@ void InlineFormattingContext::generate_line_boxes()
|
|||
}
|
||||
}
|
||||
|
||||
for (auto& line_box : line_boxes) {
|
||||
for (auto& fragment : line_box.fragments()) {
|
||||
if (fragment.layout_node().is_inline_block()) {
|
||||
auto& box = as<Box>(fragment.layout_node());
|
||||
auto& box_state = m_state.get_mutable(box);
|
||||
box_state.set_content_offset(fragment.offset());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto* box : absolute_boxes) {
|
||||
auto& box_state = m_state.get_mutable(*box);
|
||||
box_state.set_static_position_rect(calculate_static_position_rect(*box));
|
||||
|
@ -494,9 +504,8 @@ StaticPositionRect InlineFormattingContext::calculate_static_position_rect(Box c
|
|||
} else {
|
||||
// Easy case: no previous sibling, we're at the top of the containing block.
|
||||
}
|
||||
auto offset_to_static_parent = content_box_rect_in_static_position_ancestor_coordinate_space(box, *box.containing_block());
|
||||
StaticPositionRect static_position_rect;
|
||||
static_position_rect.rect = { offset_to_static_parent.location().translated(x, y), { 0, 0 } };
|
||||
static_position_rect.rect = { { x, y }, { 0, 0 } };
|
||||
return static_position_rect;
|
||||
}
|
||||
|
||||
|
|
|
@ -90,6 +90,7 @@ struct LayoutState {
|
|||
void set_content_x(CSSPixels x) { offset.set_x(x); }
|
||||
void set_content_y(CSSPixels y) { offset.set_y(y); }
|
||||
|
||||
// offset from top-left corner of content area of box's containing block to top-left corner of box's content area
|
||||
CSSPixelPoint offset;
|
||||
|
||||
SizeConstraint width_constraint { SizeConstraint::None };
|
||||
|
|
|
@ -140,6 +140,7 @@ Box const* Node::containing_block() const
|
|||
return nearest_ancestor_capable_of_forming_a_containing_block(*this);
|
||||
}
|
||||
|
||||
// returns containing block this node would have had if its position was static
|
||||
Box const* Node::static_position_containing_block() const
|
||||
{
|
||||
return nearest_ancestor_capable_of_forming_a_containing_block(*this);
|
||||
|
|
|
@ -1853,12 +1853,11 @@ CSSPixels TableFormattingContext::border_spacing_vertical() const
|
|||
return computed_values.border_spacing_vertical().to_px(table_box());
|
||||
}
|
||||
|
||||
StaticPositionRect TableFormattingContext::calculate_static_position_rect(Box const& box) const
|
||||
StaticPositionRect TableFormattingContext::calculate_static_position_rect(Box const&) const
|
||||
{
|
||||
// FIXME: Implement static position calculation for table descendants instead of always returning a rectangle with zero position and size.
|
||||
StaticPositionRect static_position;
|
||||
auto offset_to_static_parent = content_box_rect_in_static_position_ancestor_coordinate_space(box, *box.containing_block());
|
||||
static_position.rect = { offset_to_static_parent.location(), { 0, 0 } };
|
||||
static_position.rect = { { 0, 0 }, { 0, 0 } };
|
||||
return static_position;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline
|
|||
Box <tbody> at (10,10) content-size 0x0 table-row-group children: not-inline
|
||||
Box <tr> at (10,10) content-size 0x0 table-row children: not-inline
|
||||
BlockContainer <(anonymous)> at (10,10) content-size 0x0 table-cell [BFC] children: not-inline
|
||||
BlockContainer <td> at (9,9) content-size 0x0 positioned [BFC] children: not-inline
|
||||
BlockContainer <td> at (11,11) content-size 0x0 positioned [BFC] children: not-inline
|
||||
|
||||
ViewportPaintable (Viewport<#document>) [0,0 800x600]
|
||||
PaintableWithLines (BlockContainer<HTML>) [0,0 800x20]
|
||||
|
@ -16,4 +16,4 @@ ViewportPaintable (Viewport<#document>) [0,0 800x600]
|
|||
PaintableBox (Box<TBODY>) [10,10 0x0]
|
||||
PaintableBox (Box<TR>) [10,10 0x0]
|
||||
PaintableWithLines (BlockContainer(anonymous)) [10,10 0x0]
|
||||
PaintableWithLines (BlockContainer<TD>) [8,8 2x2]
|
||||
PaintableWithLines (BlockContainer<TD>) [10,10 2x2]
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<title>Static position inside inline-block</title>
|
||||
<link rel="author" title="Martin Robinson" href="mrobinson@igalia.com">
|
||||
<link rel="help" href="https://www.w3.org/TR/CSS22/visudet.html#abs-non-replaced-width" title="10.3.7 Absolutely positioned, non-replaced elements">
|
||||
|
||||
<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
|
||||
<div style="display: inline-block; width: 100px; height: 100px;"></div>
|
||||
<div style="display: inline-block; width: 100px; height: 100px; background: red;">
|
||||
<div style="width: 100px; height: 100px; background: green;"></div>
|
||||
</div>
|
||||
<div style="display: inline-block; width: 100px; height: 100px;"></div>
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<title>Static position inside inline-block</title>
|
||||
<link rel="author" title="Martin Robinson" href="mrobinson@igalia.com">
|
||||
<link rel="help" href="https://www.w3.org/TR/CSS22/visudet.html#abs-non-replaced-width" title="10.3.7 Absolutely positioned, non-replaced elements">
|
||||
<link rel="match" href="../../../../../expected/wpt-import/css/CSS2/abspos/static-inside-inline-block-ref.html">
|
||||
|
||||
<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
|
||||
<div style="display: inline-block; width: 100px; height: 100px;"></div>
|
||||
<div style="display: inline-block; width: 100px; height: 100px; background: red;">
|
||||
<div style="position: absolute; width: 100px; height: 100px; background: green;"></div>
|
||||
</div>
|
||||
<div style="display: inline-block; width: 100px; height: 100px;"></div>
|
Loading…
Add table
Reference in a new issue