LibWeb: Honor "should treat as auto" cases in aspect-ratio decisions

This commit is contained in:
Andreas Kling 2025-08-04 15:55:19 +02:00 committed by Andreas Kling
commit 41e8211405
Notes: github-actions[bot] 2025-08-05 19:35:12 +00:00
6 changed files with 52 additions and 12 deletions

View file

@ -187,7 +187,7 @@ void BlockFormattingContext::compute_width(Box const& box, AvailableSpace const&
remaining_available_space.width = AvailableSize::make_definite(remaining_width); remaining_available_space.width = AvailableSize::make_definite(remaining_width);
} }
if (box_is_sized_as_replaced_element(box)) { if (box_is_sized_as_replaced_element(box, available_space)) {
// FIXME: This should not be done *by* ReplacedBox // FIXME: This should not be done *by* ReplacedBox
if (is<ReplacedBox>(box)) { if (is<ReplacedBox>(box)) {
auto& replaced = as<ReplacedBox>(box); auto& replaced = as<ReplacedBox>(box);
@ -297,7 +297,7 @@ void BlockFormattingContext::compute_width(Box const& box, AvailableSpace const&
}; };
auto input_width = [&] { auto input_width = [&] {
if (box_is_sized_as_replaced_element(box)) { if (box_is_sized_as_replaced_element(box, available_space)) {
// NOTE: Replaced elements had their width calculated independently above. // NOTE: Replaced elements had their width calculated independently above.
// We use that width as the input here to ensure that margins get resolved. // We use that width as the input here to ensure that margins get resolved.
return CSS::Length::make_px(box_state.content_width()); return CSS::Length::make_px(box_state.content_width());
@ -329,7 +329,7 @@ void BlockFormattingContext::compute_width(Box const& box, AvailableSpace const&
used_width = try_compute_width(CSS::Length::make_px(min_width)); used_width = try_compute_width(CSS::Length::make_px(min_width));
} }
if (!box_is_sized_as_replaced_element(box) && !used_width.is_auto()) if (!box_is_sized_as_replaced_element(box, available_space) && !used_width.is_auto())
box_state.set_content_width(used_width.to_px(box)); box_state.set_content_width(used_width.to_px(box));
box_state.margin_left = margin_left.to_px(box); box_state.margin_left = margin_left.to_px(box);
@ -522,7 +522,7 @@ void BlockFormattingContext::resolve_used_height_if_treated_as_auto(Box const& b
auto& box_state = m_state.get_mutable(box); auto& box_state = m_state.get_mutable(box);
CSSPixels height = 0; CSSPixels height = 0;
if (box_is_sized_as_replaced_element(box)) { if (box_is_sized_as_replaced_element(box, available_space)) {
height = compute_height_for_replaced_element(box, available_space); height = compute_height_for_replaced_element(box, available_space);
} else { } else {
if (box_formatting_context) { if (box_formatting_context) {

View file

@ -551,7 +551,7 @@ CSSPixels FormattingContext::tentative_width_for_replaced_element(Box const& box
void FormattingContext::compute_width_for_absolutely_positioned_element(Box const& box, AvailableSpace const& available_space) void FormattingContext::compute_width_for_absolutely_positioned_element(Box const& box, AvailableSpace const& available_space)
{ {
if (box_is_sized_as_replaced_element(box)) if (box_is_sized_as_replaced_element(box, available_space))
compute_width_for_absolutely_positioned_replaced_element(box, available_space); compute_width_for_absolutely_positioned_replaced_element(box, available_space);
else else
compute_width_for_absolutely_positioned_non_replaced_element(box, available_space); compute_width_for_absolutely_positioned_non_replaced_element(box, available_space);
@ -559,7 +559,7 @@ void FormattingContext::compute_width_for_absolutely_positioned_element(Box cons
void FormattingContext::compute_height_for_absolutely_positioned_element(Box const& box, AvailableSpace const& available_space, BeforeOrAfterInsideLayout before_or_after_inside_layout) void FormattingContext::compute_height_for_absolutely_positioned_element(Box const& box, AvailableSpace const& available_space, BeforeOrAfterInsideLayout before_or_after_inside_layout)
{ {
if (box_is_sized_as_replaced_element(box)) if (box_is_sized_as_replaced_element(box, available_space))
compute_height_for_absolutely_positioned_replaced_element(box, available_space, before_or_after_inside_layout); compute_height_for_absolutely_positioned_replaced_element(box, available_space, before_or_after_inside_layout);
else else
compute_height_for_absolutely_positioned_non_replaced_element(box, available_space, before_or_after_inside_layout); compute_height_for_absolutely_positioned_non_replaced_element(box, available_space, before_or_after_inside_layout);
@ -1888,7 +1888,7 @@ CSSPixelRect FormattingContext::margin_box_rect_in_ancestor_coordinate_space(Box
return margin_box_rect_in_ancestor_coordinate_space(m_state.get(box), ancestor_box); return margin_box_rect_in_ancestor_coordinate_space(m_state.get(box), ancestor_box);
} }
bool box_is_sized_as_replaced_element(Box const& box) bool FormattingContext::box_is_sized_as_replaced_element(Box const& box, AvailableSpace const& available_space) const
{ {
// When a box has a preferred aspect ratio, its automatic sizes are calculated the same as for a // When a box has a preferred aspect ratio, its automatic sizes are calculated the same as for a
// replaced element with a natural aspect ratio and no natural size in that axis, see e.g. CSS2 §10 // replaced element with a natural aspect ratio and no natural size in that axis, see e.g. CSS2 §10
@ -1906,8 +1906,8 @@ bool box_is_sized_as_replaced_element(Box const& box)
// AD-HOC: If box has preferred aspect ratio but width and height are not specified, then we should // AD-HOC: If box has preferred aspect ratio but width and height are not specified, then we should
// size it as a normal box to match other browsers. // size it as a normal box to match other browsers.
if (box.computed_values().height().is_auto() if (should_treat_width_as_auto(box, available_space)
&& box.computed_values().width().is_auto() && should_treat_height_as_auto(box, available_space)
&& !box.has_natural_width() && !box.has_natural_width()
&& !box.has_natural_height()) { && !box.has_natural_height()) {
return false; return false;

View file

@ -107,6 +107,8 @@ protected:
[[nodiscard]] bool should_treat_max_width_as_none(Box const&, AvailableSize const&) const; [[nodiscard]] bool should_treat_max_width_as_none(Box const&, AvailableSize const&) const;
[[nodiscard]] bool should_treat_max_height_as_none(Box const&, AvailableSize const&) const; [[nodiscard]] bool should_treat_max_height_as_none(Box const&, AvailableSize const&) const;
[[nodiscard]] bool box_is_sized_as_replaced_element(Box const&, AvailableSpace const&) const;
OwnPtr<FormattingContext> layout_inside(Box const&, LayoutMode, AvailableSpace const&); OwnPtr<FormattingContext> layout_inside(Box const&, LayoutMode, AvailableSpace const&);
struct SpaceUsedByFloats { struct SpaceUsedByFloats {
@ -165,6 +167,4 @@ protected:
LayoutState& m_state; LayoutState& m_state;
}; };
bool box_is_sized_as_replaced_element(Box const&);
} }

View file

@ -119,7 +119,7 @@ void InlineFormattingContext::dimension_box_on_line(Box const& box, LayoutMode l
box_state.border_bottom = computed_values.border_bottom().width; box_state.border_bottom = computed_values.border_bottom().width;
box_state.margin_bottom = computed_values.margin().bottom().to_px(box, width_of_containing_block); box_state.margin_bottom = computed_values.margin().bottom().to_px(box, width_of_containing_block);
if (box_is_sized_as_replaced_element(box)) { if (box_is_sized_as_replaced_element(box, *m_available_space)) {
box_state.set_content_width(compute_width_for_replaced_element(box, *m_available_space)); box_state.set_content_width(compute_width_for_replaced_element(box, *m_available_space));
box_state.set_content_height(compute_height_for_replaced_element(box, *m_available_space)); box_state.set_content_height(compute_height_for_replaced_element(box, *m_available_space));
auto independent_formatting_context = layout_inside(box, layout_mode, box_state.available_inner_space_or_constraints_from(*m_available_space)); auto independent_formatting_context = layout_inside(box, layout_mode, box_state.available_inner_space_or_constraints_from(*m_available_space));

View file

@ -0,0 +1,24 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (0,0) content-size 800x216 [BFC] children: not-inline
Box <body> at (8,8) content-size 300x200 flex-container(row) [FFC] children: not-inline
BlockContainer <main> at (8,8) content-size 27.640625x200 flex-item [BFC] children: not-inline
BlockContainer <article> at (8,8) content-size 27.640625x27.640625 children: inline
frag 0 from TextNode start: 0, length: 3, rect: [8,8 27.15625x18] baseline: 13.796875
"foo"
TextNode <#text>
BlockContainer <article> at (8,35.640625) content-size 27.640625x27.640625 children: inline
frag 0 from TextNode start: 0, length: 3, rect: [8,35.640625 27.640625x18] baseline: 13.796875
"bar"
TextNode <#text>
ViewportPaintable (Viewport<#document>) [0,0 800x600]
PaintableWithLines (BlockContainer<HTML>) [0,0 800x216]
PaintableBox (Box<BODY>) [8,8 300x200]
PaintableWithLines (BlockContainer<MAIN>) [8,8 27.640625x200]
PaintableWithLines (BlockContainer<ARTICLE>) [8,8 27.640625x27.640625]
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<ARTICLE>) [8,35.640625 27.640625x27.640625]
TextPaintable (TextNode<#text>)
SC for Viewport<#document> [0,0 800x600] [children: 1] (z-index: auto)
SC for BlockContainer<HTML> [0,0 800x216] [children: 0] (z-index: auto)

View file

@ -0,0 +1,16 @@
<!doctype html><style>
* { outline: 1px solid black; }
html { background: white; }
body {
background: pink;
width: 300px;
height: 200px;
display: flex;
flex-direction: row;
}
article {
background: orange;
aspect-ratio: 1 / 1;
width: 100%;
}
</style><body><main><article>foo</article><article>bar