diff --git a/Tests/LibWeb/Layout/expected/flex/intrinsic-height-of-column-items-with-different-kinds-of-width.txt b/Tests/LibWeb/Layout/expected/flex/intrinsic-height-of-column-items-with-different-kinds-of-width.txt new file mode 100644 index 0000000000..da73461643 --- /dev/null +++ b/Tests/LibWeb/Layout/expected/flex/intrinsic-height-of-column-items-with-different-kinds-of-width.txt @@ -0,0 +1,77 @@ +Viewport <#document> at (0,0) content-size 800x600 children: not-inline + BlockContainer at (1,1) content-size 798x142.8125 [BFC] children: not-inline + Box at (10,10) content-size 780x124.8125 flex-container(column) [FFC] children: not-inline + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (11,11) content-size 200x19.46875 flex-item [BFC] children: not-inline + Box at (12,12) content-size 198x17.46875 flex-container(row) [FFC] children: not-inline + BlockContainer <(anonymous)> at (12,12) content-size 19.125x17.46875 flex-item [BFC] children: inline + line 0 width: 19.125, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 2, rect: [12,12 19.125x17.46875] + "px" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (11,32.46875) content-size 50x19.46875 flex-item [BFC] children: not-inline + Box at (12,33.46875) content-size 48x17.46875 flex-container(row) [FFC] children: not-inline + BlockContainer <(anonymous)> at (12,33.46875) content-size 86.671875x17.46875 flex-item [BFC] children: inline + line 0 width: 86.671875, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 10, rect: [12,33.46875 86.671875x17.46875] + "percentage" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (11,53.9375) content-size 88.765625x19.46875 flex-item [BFC] children: not-inline + Box at (12,54.9375) content-size 86.765625x17.46875 flex-container(row) [FFC] children: not-inline + BlockContainer <(anonymous)> at (12,54.9375) content-size 86.765625x17.46875 flex-item [BFC] children: inline + line 0 width: 86.765625, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 11, rect: [12,54.9375 86.765625x17.46875] + "fit content" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (11,75.40625) content-size 102.15625x19.46875 flex-item [BFC] children: not-inline + Box at (12,76.40625) content-size 100.15625x17.46875 flex-container(row) [FFC] children: not-inline + BlockContainer <(anonymous)> at (12,76.40625) content-size 100.15625x17.46875 flex-item [BFC] children: inline + line 0 width: 100.15625, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 11, rect: [12,76.40625 100.15625x17.46875] + "max content" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (11,96.875) content-size 62.90625x36.9375 flex-item [BFC] children: not-inline + Box at (12,97.875) content-size 60.90625x34.9375 flex-container(row) [FFC] children: not-inline + BlockContainer <(anonymous)> at (12,97.875) content-size 60.90625x34.9375 flex-item [BFC] children: inline + line 0 width: 26.375, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 3, rect: [12,97.875 26.375x17.46875] + "min" + line 1 width: 60.90625, height: 17.46875, bottom: 34.9375, baseline: 13.53125 + frag 0 from TextNode start: 4, length: 7, rect: [12,115.34375 60.90625x17.46875] + "content" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + +PaintableWithLines (Viewport<#document>) [0,0 800x600] + PaintableWithLines (BlockContainer) [0,0 800x144.8125] + PaintableBox (Box) [9,9 782x126.8125] + PaintableWithLines (BlockContainer
.px) [10,10 202x21.46875] + PaintableBox (Box
.inner) [11,11 200x19.46875] + PaintableWithLines (BlockContainer(anonymous)) [12,12 19.125x17.46875] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.percentage) [10,31.46875 52x21.46875] overflow: [11,32.46875 87.671875x19.46875] + PaintableBox (Box
.inner) [11,32.46875 50x19.46875] overflow: [12,33.46875 86.671875x17.46875] + PaintableWithLines (BlockContainer(anonymous)) [12,33.46875 86.671875x17.46875] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.fit-content) [10,52.9375 90.765625x21.46875] + PaintableBox (Box
.inner) [11,53.9375 88.765625x19.46875] + PaintableWithLines (BlockContainer(anonymous)) [12,54.9375 86.765625x17.46875] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.max-content) [10,74.40625 104.15625x21.46875] + PaintableBox (Box
.inner) [11,75.40625 102.15625x19.46875] + PaintableWithLines (BlockContainer(anonymous)) [12,76.40625 100.15625x17.46875] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.min-content) [10,95.875 64.90625x38.9375] + PaintableBox (Box
.inner) [11,96.875 62.90625x36.9375] + PaintableWithLines (BlockContainer(anonymous)) [12,97.875 60.90625x34.9375] + TextPaintable (TextNode<#text>) diff --git a/Tests/LibWeb/Layout/input/flex/intrinsic-height-of-column-items-with-different-kinds-of-width.html b/Tests/LibWeb/Layout/input/flex/intrinsic-height-of-column-items-with-different-kinds-of-width.html new file mode 100644 index 0000000000..46a7811881 --- /dev/null +++ b/Tests/LibWeb/Layout/input/flex/intrinsic-height-of-column-items-with-different-kinds-of-width.html @@ -0,0 +1,19 @@ + +
px
+
percentage
+
fit content
+
max content
+
min content
diff --git a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp index 47651bb092..1d45f239f7 100644 --- a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp @@ -665,13 +665,12 @@ void FlexFormattingContext::determine_flex_base_size_and_hypothetical_main_size( // NOTE: This is one of many situations where that causes trouble: if this is a flex column layout, // we may need to calculate the intrinsic height of a flex item. This requires a width, but a // width won't be determined until later on in the flex layout algorithm. - // In the specific case above (E), the spec mentions using `fit-content` if "a cross size is - // needed to determine the main size", so that's exactly what we do. + // In the specific case above (E), the spec mentions using `fit-content` in place of `auto` + // if "a cross size is needed to determine the main size", so that's exactly what we do. - // NOTE: Substituting the fit-content size actually happens elsewhere, in the various helpers that - // calculate the intrinsic sizes of a flex item, e.g. calculate_min_content_main_size(). - // This means that *all* intrinsic heights computed within a flex formatting context will - // automatically use the fit-content width in case a used width is not known yet. + // NOTE: Finding a suitable width for intrinsic height determination actually happens elsewhere, + // in the various helpers that calculate the intrinsic sizes of a flex item, + // e.g. calculate_min_content_main_size(). if (item.used_flex_basis->has()) { return calculate_max_content_main_size(item); @@ -1138,14 +1137,29 @@ void FlexFormattingContext::determine_hypothetical_cross_size_of_item(FlexItem& return; } - if (should_treat_cross_size_as_auto(item.box)) { - // Item has automatic cross size, layout with "fit-content" + if (item.box->has_preferred_aspect_ratio() && item.main_size.has_value()) { + item.hypothetical_cross_size = calculate_cross_size_from_main_size_and_aspect_ratio(item.main_size.value(), item.box->preferred_aspect_ratio().value()); + return; + } - if (item.box->has_preferred_aspect_ratio() && item.main_size.has_value()) { - item.hypothetical_cross_size = calculate_cross_size_from_main_size_and_aspect_ratio(item.main_size.value(), item.box->preferred_aspect_ratio().value()); - return; - } + auto computed_cross_size = [&]() -> CSS::Size { + // "... treating auto as fit-content" + if (should_treat_cross_size_as_auto(item.box)) + return CSS::Size::make_fit_content(); + return this->computed_cross_size(item.box); + }(); + if (computed_cross_size.is_min_content()) { + item.hypothetical_cross_size = css_clamp(calculate_min_content_cross_size(item), clamp_min, clamp_max); + return; + } + + if (computed_cross_size.is_max_content()) { + item.hypothetical_cross_size = css_clamp(calculate_max_content_cross_size(item), clamp_min, clamp_max); + return; + } + + if (computed_cross_size.is_fit_content()) { CSSPixels fit_content_cross_size = 0; if (is_row_layout()) { auto available_width = item.main_size.has_value() ? AvailableSize::make_definite(item.main_size.value()) : AvailableSize::make_indefinite(); @@ -1969,14 +1983,24 @@ CSSPixels FlexFormattingContext::calculate_cross_max_content_contribution(FlexIt return item.add_cross_margin_box_sizes(clamped_inner_size); } -CSSPixels FlexFormattingContext::calculate_clamped_fit_content_width(Box const& box, AvailableSpace const& available_space) const +CSSPixels FlexFormattingContext::calculate_width_to_use_when_determining_intrinsic_height_of_item(FlexItem const& item) const { - auto const& computed_min_size = box.computed_values().min_width(); - auto const& computed_max_size = box.computed_values().max_width(); - auto clamp_min = (!computed_min_size.is_auto() && (!computed_min_size.contains_percentage())) ? specified_cross_min_size(box) : 0; - auto clamp_max = (!computed_max_size.is_none() && (!computed_max_size.contains_percentage())) ? specified_cross_max_size(box) : NumericLimits::max(); - auto size = FormattingContext::calculate_fit_content_width(box, available_space); - return css_clamp(size, clamp_min, clamp_max); + auto const& box = *item.box; + auto computed_width = box.computed_values().width(); + auto const& computed_min_width = box.computed_values().min_width(); + auto const& computed_max_width = box.computed_values().max_width(); + auto clamp_min = (!computed_min_width.is_auto() && (!computed_min_width.contains_percentage())) ? specified_cross_min_size(box) : 0; + auto clamp_max = (!computed_max_width.is_none() && (!computed_max_width.contains_percentage())) ? specified_cross_max_size(box) : NumericLimits::max(); + + CSSPixels width; + if (should_treat_width_as_auto(box, m_available_space_for_items->space) || computed_width.is_fit_content()) + width = calculate_fit_content_width(box, m_available_space_for_items->space); + else if (computed_width.is_min_content()) + width = calculate_min_content_width(box); + else if (computed_width.is_max_content()) + width = calculate_max_content_width(box); + + return css_clamp(width, clamp_min, clamp_max); } CSSPixels FlexFormattingContext::calculate_min_content_main_size(FlexItem const& item) const @@ -1986,7 +2010,7 @@ CSSPixels FlexFormattingContext::calculate_min_content_main_size(FlexItem const& } auto available_space = m_state.get(item.box).available_inner_space_or_constraints_from(m_available_space_for_items->space); if (available_space.width.is_indefinite()) { - available_space.width = AvailableSize::make_definite(calculate_clamped_fit_content_width(item.box, m_available_space_for_items->space)); + available_space.width = AvailableSize::make_definite(calculate_width_to_use_when_determining_intrinsic_height_of_item(item)); } return calculate_min_content_height(item.box, available_space.width); } @@ -1998,7 +2022,7 @@ CSSPixels FlexFormattingContext::calculate_max_content_main_size(FlexItem const& } auto available_space = m_state.get(item.box).available_inner_space_or_constraints_from(m_available_space_for_items->space); if (available_space.width.is_indefinite()) { - available_space.width = AvailableSize::make_definite(calculate_clamped_fit_content_width(item.box, m_available_space_for_items->space)); + available_space.width = AvailableSize::make_definite(calculate_width_to_use_when_determining_intrinsic_height_of_item(item)); } return calculate_max_content_height(item.box, available_space.width); } @@ -2022,7 +2046,7 @@ CSSPixels FlexFormattingContext::calculate_min_content_cross_size(FlexItem const if (is_row_layout()) { auto available_space = m_state.get(item.box).available_inner_space_or_constraints_from(m_available_space_for_flex_container->space); if (available_space.width.is_indefinite()) { - available_space.width = AvailableSize::make_definite(calculate_clamped_fit_content_width(item.box, m_available_space_for_items->space)); + available_space.width = AvailableSize::make_definite(calculate_width_to_use_when_determining_intrinsic_height_of_item(item)); } return calculate_min_content_height(item.box, available_space.width); } @@ -2034,7 +2058,7 @@ CSSPixels FlexFormattingContext::calculate_max_content_cross_size(FlexItem const if (is_row_layout()) { auto available_space = m_state.get(item.box).available_inner_space_or_constraints_from(m_available_space_for_flex_container->space); if (available_space.width.is_indefinite()) { - available_space.width = AvailableSize::make_definite(calculate_clamped_fit_content_width(item.box, m_available_space_for_items->space)); + available_space.width = AvailableSize::make_definite(calculate_width_to_use_when_determining_intrinsic_height_of_item(item)); } return calculate_max_content_height(item.box, available_space.width); } diff --git a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.h b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.h index d96b02d776..a710256dca 100644 --- a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.h +++ b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.h @@ -211,7 +211,7 @@ private: [[nodiscard]] CSSPixels calculate_fit_content_main_size(FlexItem const&) const; [[nodiscard]] CSSPixels calculate_fit_content_cross_size(FlexItem const&) const; - CSSPixels calculate_clamped_fit_content_width(Box const&, AvailableSpace const&) const; + [[nodiscard]] CSSPixels calculate_width_to_use_when_determining_intrinsic_height_of_item(FlexItem const&) const; virtual void parent_context_did_dimension_child_root_box() override;