layout: Generalize ContainingBlock's block size to a SizeConstraint (#34946)

It used to be an `AuOrAuto`, turning it into a `SizeConstraint` allows
passing the information about the min and max constraints when the
containing block doesn't have a definite block size.

This will be useful for table layout.

Note that in most cases we were already constructing the containing
block from a `SizeConstraint`, but we were calling `to_auto_or()` to
turn it into an `AuOrAuto`.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
Oriol Brufau 2025-01-13 02:25:33 -08:00 committed by GitHub
parent de780dcde4
commit f66cd172d6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 71 additions and 69 deletions

View file

@ -120,7 +120,7 @@ struct FlexItemLayoutResult {
containing_block_inline_size: Au, containing_block_inline_size: Au,
// The containing block block size used to generate this layout. // The containing block block size used to generate this layout.
containing_block_block_size: AuOrAuto, containing_block_block_size: SizeConstraint,
// Whether or not this layout depended on block constraints. // Whether or not this layout depended on block constraints.
depends_on_block_constraints: bool, depends_on_block_constraints: bool,
@ -662,7 +662,7 @@ impl FlexContainer {
container_definite_inner_size: self.config.flex_axis.vec2_to_flex_relative( container_definite_inner_size: self.config.flex_axis.vec2_to_flex_relative(
LogicalVec2 { LogicalVec2 {
inline: Some(containing_block.size.inline), inline: Some(containing_block.size.inline),
block: containing_block.size.block.non_auto(), block: containing_block.size.block.to_definite(),
}, },
), ),
}; };
@ -671,12 +671,14 @@ impl FlexContainer {
// https://drafts.csswg.org/css-flexbox/#algo-main-container // https://drafts.csswg.org/css-flexbox/#algo-main-container
let container_main_size = match self.config.flex_axis { let container_main_size = match self.config.flex_axis {
FlexAxis::Row => containing_block.size.inline, FlexAxis::Row => containing_block.size.inline,
FlexAxis::Column => containing_block.size.block.auto_is(|| { FlexAxis::Column => match containing_block.size.block {
self.main_content_sizes(layout_context, &containing_block.into(), || &flex_context) SizeConstraint::Definite(size) => size,
_ => self
.main_content_sizes(layout_context, &containing_block.into(), || &flex_context)
.sizes .sizes
.max_content .max_content
.clamp_between_extremums(container_min_size.main, container_max_size.main) .clamp_between_extremums(container_min_size.main, container_max_size.main),
}), },
}; };
// Actual length may be less, but we guess that usually not by a lot // Actual length may be less, but we guess that usually not by a lot
@ -1894,13 +1896,12 @@ impl FlexItem<'_> {
}); });
let cross_size = match used_cross_size_override { let cross_size = match used_cross_size_override {
Some(s) => AuOrAuto::LengthPercentage(s), Some(s) => SizeConstraint::Definite(s),
None => self.content_box_size.cross.map(|cross_size| { None => SizeConstraint::new(
cross_size.clamp_between_extremums( self.content_box_size.cross.non_auto(),
self.content_min_size.cross, self.content_min_size.cross,
self.content_max_size.cross, self.content_max_size.cross,
) ),
}),
}; };
let independent_formatting_context = &self.box_.independent_formatting_context; let independent_formatting_context = &self.box_.independent_formatting_context;
@ -1917,7 +1918,7 @@ impl FlexItem<'_> {
(used_main_size, cross_size) (used_main_size, cross_size)
} else { } else {
( (
cross_size.auto_is(|| { cross_size.to_definite().unwrap_or_else(|| {
let style = self.box_.style(); let style = self.box_.style();
let stretch_size = let stretch_size =
Au::zero().max(containing_block.size.inline - self.pbm_auto_is_zero.cross); Au::zero().max(containing_block.size.inline - self.pbm_auto_is_zero.cross);
@ -1947,9 +1948,9 @@ impl FlexItem<'_> {
if self.flex_base_size_is_definite || if self.flex_base_size_is_definite ||
flex_context.container_definite_inner_size.main.is_some() flex_context.container_definite_inner_size.main.is_some()
{ {
AuOrAuto::LengthPercentage(used_main_size) SizeConstraint::Definite(used_main_size)
} else { } else {
AuOrAuto::Auto SizeConstraint::default()
}, },
) )
}; };
@ -1965,7 +1966,9 @@ impl FlexItem<'_> {
item_style, item_style,
self.preferred_aspect_ratio, self.preferred_aspect_ratio,
&Sizes::new( &Sizes::new(
block_size.non_auto().map_or(Size::Initial, Size::Numeric), block_size
.to_definite()
.map_or(Size::Initial, Size::Numeric),
Size::Numeric(min_size.block), Size::Numeric(min_size.block),
max_size.block.map_or(Size::Initial, Size::Numeric), max_size.block.map_or(Size::Initial, Size::Numeric),
), ),
@ -2834,7 +2837,7 @@ impl FlexItemBox {
let item_as_containing_block = ContainingBlock { let item_as_containing_block = ContainingBlock {
size: ContainingBlockSize { size: ContainingBlockSize {
inline: inline_size, inline: inline_size,
block: AuOrAuto::Auto, block: SizeConstraint::default(),
}, },
style, style,
}; };

View file

@ -191,6 +191,6 @@ impl CachedBlockSizeContribution {
item_as_containing_block: &ContainingBlock, item_as_containing_block: &ContainingBlock,
) -> bool { ) -> bool {
item_as_containing_block.size.inline == self.containing_block_inline_size && item_as_containing_block.size.inline == self.containing_block_inline_size &&
item_as_containing_block.size.block.is_auto() !item_as_containing_block.size.block.is_definite()
} }
} }

View file

@ -24,7 +24,7 @@ use crate::cell::ArcRefCell;
use crate::fragment_tree::{ use crate::fragment_tree::{
BaseFragmentInfo, BoxFragment, CollapsedBlockMargins, Fragment, TextFragment, BaseFragmentInfo, BoxFragment, CollapsedBlockMargins, Fragment, TextFragment,
}; };
use crate::geom::{AuOrAuto, LogicalRect, LogicalVec2, PhysicalRect, ToLogical}; use crate::geom::{LogicalRect, LogicalVec2, PhysicalRect, ToLogical};
use crate::positioned::{ use crate::positioned::{
relative_adjustement, AbsolutelyPositionedBox, PositioningContext, PositioningContextLength, relative_adjustement, AbsolutelyPositionedBox, PositioningContext, PositioningContextLength,
}; };
@ -427,7 +427,7 @@ impl LineItemLayout<'_, '_> {
let inline_box_containing_block = ContainingBlock { let inline_box_containing_block = ContainingBlock {
size: ContainingBlockSize { size: ContainingBlockSize {
inline: content_rect.size.inline, inline: content_rect.size.inline,
block: AuOrAuto::Auto, block: Default::default(),
}, },
style: self.layout.containing_block.style, style: self.layout.containing_block.style,
}; };

View file

@ -145,7 +145,7 @@ impl BlockLevelBox {
let available_inline_size = let available_inline_size =
containing_block.size.inline - pbm.padding_border_sums.inline - margin.inline_sum(); containing_block.size.inline - pbm.padding_border_sums.inline - margin.inline_sum();
let available_block_size = containing_block.size.block.non_auto().map(|block_size| { let available_block_size = containing_block.size.block.to_definite().map(|block_size| {
Au::zero().max(block_size - pbm.padding_border_sums.block - margin.block_sum()) Au::zero().max(block_size - pbm.padding_border_sums.block - margin.block_sum())
}); });
@ -174,7 +174,7 @@ impl BlockLevelBox {
let containing_block_for_children = ContainingBlock { let containing_block_for_children = ContainingBlock {
size: ContainingBlockSize { size: ContainingBlockSize {
inline: inline_size, inline: inline_size,
block: tentative_block_size.to_auto_or(), block: tentative_block_size,
}, },
style, style,
}; };
@ -269,7 +269,7 @@ impl OutsideMarker {
let containing_block_for_children = ContainingBlock { let containing_block_for_children = ContainingBlock {
size: ContainingBlockSize { size: ContainingBlockSize {
inline: content_sizes.sizes.max_content, inline: content_sizes.sizes.max_content,
block: AuOrAuto::auto(), block: SizeConstraint::default(),
}, },
style: &self.marker_style, style: &self.marker_style,
}; };
@ -1202,7 +1202,7 @@ impl IndependentNonReplacedContents {
let available_block_size = containing_block let available_block_size = containing_block
.size .size
.block .block
.non_auto() .to_definite()
.map(|block_size| Au::zero().max(block_size - pbm_sums.block_sum())); .map(|block_size| Au::zero().max(block_size - pbm_sums.block_sum()));
let (preferred_block_size, min_block_size, max_block_size) = content_box_sizes let (preferred_block_size, min_block_size, max_block_size) = content_box_sizes
.block .block
@ -1265,7 +1265,7 @@ impl IndependentNonReplacedContents {
&ContainingBlock { &ContainingBlock {
size: ContainingBlockSize { size: ContainingBlockSize {
inline: inline_size, inline: inline_size,
block: tentative_block_size.to_auto_or(), block: tentative_block_size,
}, },
style, style,
}, },
@ -1335,7 +1335,7 @@ impl IndependentNonReplacedContents {
&ContainingBlock { &ContainingBlock {
size: ContainingBlockSize { size: ContainingBlockSize {
inline: proposed_inline_size, inline: proposed_inline_size,
block: tentative_block_size.to_auto_or(), block: tentative_block_size,
}, },
style, style,
}, },
@ -1662,7 +1662,7 @@ fn solve_containing_block_padding_and_border_for_in_flow_box<'a>(
let available_block_size = containing_block let available_block_size = containing_block
.size .size
.block .block
.non_auto() .to_definite()
.map(|block_size| Au::zero().max(block_size - pbm_sums.block_sum())); .map(|block_size| Au::zero().max(block_size - pbm_sums.block_sum()));
// https://drafts.csswg.org/css2/#the-height-property // https://drafts.csswg.org/css2/#the-height-property
@ -1698,7 +1698,7 @@ fn solve_containing_block_padding_and_border_for_in_flow_box<'a>(
let containing_block_for_children = ContainingBlock { let containing_block_for_children = ContainingBlock {
size: ContainingBlockSize { size: ContainingBlockSize {
inline: inline_size, inline: inline_size,
block: tentative_block_size.to_auto_or(), block: tentative_block_size,
}, },
style, style,
}; };
@ -2102,7 +2102,7 @@ fn block_size_is_zero_or_intrinsic(size: &StyleSize, containing_block: &Containi
StyleSize::LengthPercentage(ref lp) => { StyleSize::LengthPercentage(ref lp) => {
// TODO: Should this resolve definite percentages? Blink does it, Gecko and WebKit don't. // TODO: Should this resolve definite percentages? Blink does it, Gecko and WebKit don't.
lp.is_definitely_zero() || lp.is_definitely_zero() ||
(lp.0.has_percentage() && containing_block.size.block.is_auto()) (lp.0.has_percentage() && !containing_block.size.block.is_definite())
}, },
StyleSize::AnchorSizeFunction(_) => unreachable!("anchor-size() should be disabled"), StyleSize::AnchorSizeFunction(_) => unreachable!("anchor-size() should be disabled"),
} }
@ -2171,7 +2171,7 @@ impl IndependentFormattingContext {
let available_block_size = containing_block let available_block_size = containing_block
.size .size
.block .block
.non_auto() .to_definite()
.map(|block_size| (block_size - pbm_sums.block_sum()).max(Au::zero())); .map(|block_size| (block_size - pbm_sums.block_sum()).max(Au::zero()));
let tentative_block_size = content_box_sizes_and_pbm let tentative_block_size = content_box_sizes_and_pbm
.content_box_sizes .content_box_sizes
@ -2198,7 +2198,7 @@ impl IndependentFormattingContext {
let containing_block_for_children = ContainingBlock { let containing_block_for_children = ContainingBlock {
size: ContainingBlockSize { size: ContainingBlockSize {
inline: inline_size, inline: inline_size,
block: tentative_block_size.to_auto_or(), block: tentative_block_size,
}, },
style: self.style(), style: self.style(),
}; };

View file

@ -741,7 +741,9 @@ impl LogicalVec2<Size<LengthPercentage>> {
|inline_size| inline_size.map(|lp| lp.to_used_value(containing_block.size.inline)), |inline_size| inline_size.map(|lp| lp.to_used_value(containing_block.size.inline)),
|block_size| { |block_size| {
block_size block_size
.maybe_map(|lp| lp.maybe_to_used_value(containing_block.size.block.non_auto())) .maybe_map(|lp| {
lp.maybe_to_used_value(containing_block.size.block.to_definite())
})
.unwrap_or_default() .unwrap_or_default()
}, },
) )
@ -856,6 +858,11 @@ impl SizeConstraint {
) )
} }
#[inline]
pub(crate) fn is_definite(self) -> bool {
matches!(self, Self::Definite(_))
}
#[inline] #[inline]
pub(crate) fn to_definite(self) -> Option<Au> { pub(crate) fn to_definite(self) -> Option<Au> {
match self { match self {

View file

@ -97,7 +97,7 @@ impl<'a> From<&'_ ContainingBlock<'a>> for IndefiniteContainingBlock {
Self { Self {
size: LogicalVec2 { size: LogicalVec2 {
inline: AuOrAuto::LengthPercentage(containing_block.size.inline), inline: AuOrAuto::LengthPercentage(containing_block.size.inline),
block: containing_block.size.block, block: containing_block.size.block.to_auto_or(),
}, },
writing_mode: containing_block.style.writing_mode, writing_mode: containing_block.style.writing_mode,
} }
@ -118,7 +118,7 @@ impl<'a> From<&'_ DefiniteContainingBlock<'a>> for IndefiniteContainingBlock {
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub(crate) struct ContainingBlockSize { pub(crate) struct ContainingBlockSize {
inline: Au, inline: Au,
block: AuOrAuto, block: SizeConstraint,
} }
pub(crate) struct ContainingBlock<'a> { pub(crate) struct ContainingBlock<'a> {
@ -136,7 +136,7 @@ impl<'a> From<&'_ DefiniteContainingBlock<'a>> for ContainingBlock<'a> {
ContainingBlock { ContainingBlock {
size: ContainingBlockSize { size: ContainingBlockSize {
inline: definite.size.inline, inline: definite.size.inline,
block: AuOrAuto::LengthPercentage(definite.size.block), block: SizeConstraint::Definite(definite.size.block),
}, },
style: definite.style, style: definite.style,
} }

View file

@ -588,7 +588,7 @@ impl HoistedAbsolutelyPositionedBox {
let containing_block_for_children = ContainingBlock { let containing_block_for_children = ContainingBlock {
size: ContainingBlockSize { size: ContainingBlockSize {
inline: inline_size, inline: inline_size,
block: block_axis.size.to_auto_or(), block: block_axis.size,
}, },
style: &style, style: &style,
}; };
@ -1008,9 +1008,9 @@ pub(crate) fn relative_adjustement(
.box_offsets(containing_block.style.writing_mode) .box_offsets(containing_block.style.writing_mode)
.map_inline_and_block_axes( .map_inline_and_block_axes(
|value| value.map(|value| value.to_used_value(cbis)), |value| value.map(|value| value.to_used_value(cbis)),
|value| match cbbs.non_auto() { |value| match cbbs {
Some(cbbs) => value.map(|value| value.to_used_value(cbbs)), SizeConstraint::Definite(cbbs) => value.map(|value| value.to_used_value(cbbs)),
None => match value.non_auto().and_then(|value| value.to_length()) { _ => match value.non_auto().and_then(|value| value.to_length()) {
Some(value) => AuOrAuto::LengthPercentage(value.into()), Some(value) => AuOrAuto::LengthPercentage(value.into()),
None => AuOrAuto::Auto, None => AuOrAuto::Auto,
}, },

View file

@ -514,7 +514,7 @@ impl ReplacedContents {
let block_stretch_size = containing_block let block_stretch_size = containing_block
.size .size
.block .block
.non_auto() .to_definite()
.map(|block_size| Au::zero().max(block_size - pbm_sums.block)); .map(|block_size| Au::zero().max(block_size - pbm_sums.block));
// First, compute the inline size. Intrinsic values depend on the block sizing properties // First, compute the inline size. Intrinsic values depend on the block sizing properties

View file

@ -463,7 +463,10 @@ impl ComputedValuesExt for ComputedValues {
.min_box_size(containing_block.style.writing_mode) .min_box_size(containing_block.style.writing_mode)
.map_inline_and_block_sizes( .map_inline_and_block_sizes(
|lp| lp.to_used_value(containing_block.size.inline), |lp| lp.to_used_value(containing_block.size.inline),
|lp| lp.to_used_value(containing_block.size.block.auto_is(Au::zero)), |lp| {
let cbbs = containing_block.size.block.to_definite();
lp.to_used_value(cbbs.unwrap_or_else(Au::zero))
},
); );
self.content_min_box_size_for_min_size(min_size, pbm) self.content_min_box_size_for_min_size(min_size, pbm)
} }

View file

@ -35,7 +35,7 @@ use crate::fragment_tree::{
}; };
use crate::geom::{ use crate::geom::{
AuOrAuto, LogicalRect, LogicalSides, LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSides, AuOrAuto, LogicalRect, LogicalSides, LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSides,
Size, ToLogical, ToLogicalWithContainingBlock, Size, SizeConstraint, ToLogical, ToLogicalWithContainingBlock,
}; };
use crate::positioned::{relative_adjustement, PositioningContext, PositioningContextLength}; use crate::positioned::{relative_adjustement, PositioningContext, PositioningContextLength};
use crate::sizing::{ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult}; use crate::sizing::{ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult};
@ -1228,7 +1228,7 @@ impl<'a> TableLayout<'a> {
let containing_block_for_children = ContainingBlock { let containing_block_for_children = ContainingBlock {
size: ContainingBlockSize { size: ContainingBlockSize {
inline: total_cell_width, inline: total_cell_width,
block: AuOrAuto::Auto, block: SizeConstraint::default(),
}, },
style: &cell.base.style, style: &cell.base.style,
}; };
@ -1561,7 +1561,7 @@ impl<'a> TableLayout<'a> {
.content_box_size_deprecated(containing_block_for_table, &self.pbm) .content_box_size_deprecated(containing_block_for_table, &self.pbm)
.block .block
{ {
LengthPercentage(_) => containing_block_for_children.size.block, LengthPercentage(_) => containing_block_for_children.size.block.to_auto_or(),
Auto => style Auto => style
.content_min_box_size_deprecated(containing_block_for_table, &self.pbm) .content_min_box_size_deprecated(containing_block_for_table, &self.pbm)
.block .block
@ -1605,7 +1605,7 @@ impl<'a> TableLayout<'a> {
let containing_block = &ContainingBlock { let containing_block = &ContainingBlock {
size: ContainingBlockSize { size: ContainingBlockSize {
inline: self.table_width + self.pbm.padding_border_sums.inline, inline: self.table_width + self.pbm.padding_border_sums.inline,
block: AuOrAuto::Auto, block: SizeConstraint::default(),
}, },
style: &self.table.style, style: &self.table.style,
}; };
@ -2330,7 +2330,7 @@ impl<'a> RowFragmentLayout<'a> {
let containing_block = ContainingBlock { let containing_block = ContainingBlock {
size: ContainingBlockSize { size: ContainingBlockSize {
inline: rect.size.inline, inline: rect.size.inline,
block: AuOrAuto::LengthPercentage(rect.size.block), block: SizeConstraint::Definite(rect.size.block),
}, },
style: table_style, style: table_style,
}; };
@ -2360,7 +2360,7 @@ impl<'a> RowFragmentLayout<'a> {
self.rect.start_corner -= row_group_layout.rect.start_corner; self.rect.start_corner -= row_group_layout.rect.start_corner;
( (
row_group_layout.rect.size.inline, row_group_layout.rect.size.inline,
AuOrAuto::LengthPercentage(row_group_layout.rect.size.block), SizeConstraint::Definite(row_group_layout.rect.size.block),
) )
} else { } else {
( (

View file

@ -5,7 +5,6 @@
use app_units::Au; use app_units::Au;
use atomic_refcell::{AtomicRef, AtomicRefCell}; use atomic_refcell::{AtomicRef, AtomicRefCell};
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::values::generics::length::{GenericLengthPercentageOrAuto, LengthPercentageOrAuto};
use style::values::specified::align::AlignFlags; use style::values::specified::align::AlignFlags;
use style::values::specified::box_::DisplayInside; use style::values::specified::box_::DisplayInside;
use style::Zero; use style::Zero;
@ -122,13 +121,6 @@ impl taffy::LayoutPartialTree for TaffyContainerContext<'_> {
let mut child = (*self.source_child_nodes[usize::from(node_id)]).borrow_mut(); let mut child = (*self.source_child_nodes[usize::from(node_id)]).borrow_mut();
let child = &mut *child; let child = &mut *child;
fn option_f32_to_lpa(input: Option<f32>) -> LengthPercentageOrAuto<Au> {
match input {
None => LengthPercentageOrAuto::Auto,
Some(length) => LengthPercentageOrAuto::LengthPercentage(Au::from_f32_px(length)),
}
}
fn option_f32_to_size(input: Option<f32>) -> Size<Au> { fn option_f32_to_size(input: Option<f32>) -> Size<Au> {
match input { match input {
None => Size::Initial, None => Size::Initial,
@ -241,12 +233,13 @@ impl taffy::LayoutPartialTree for TaffyContainerContext<'_> {
}); });
} }
let maybe_block_size =
option_f32_to_lpa(content_box_known_dimensions.height);
let content_box_size_override = ContainingBlock { let content_box_size_override = ContainingBlock {
size: ContainingBlockSize { size: ContainingBlockSize {
inline: Au::from_f32_px(inline_size), inline: Au::from_f32_px(inline_size),
block: maybe_block_size, block: content_box_known_dimensions
.height
.map(Au::from_f32_px)
.map_or_else(SizeConstraint::default, SizeConstraint::Definite),
}, },
style, style,
}; };
@ -361,7 +354,7 @@ impl ComputeInlineContentSizes for TaffyContainer {
let containing_block = &ContainingBlock { let containing_block = &ContainingBlock {
size: ContainingBlockSize { size: ContainingBlockSize {
inline: Au::zero(), inline: Au::zero(),
block: GenericLengthPercentageOrAuto::Auto, block: SizeConstraint::default(),
}, },
style, style,
}; };
@ -432,13 +425,6 @@ impl TaffyContainer {
child_detailed_layout_infos: vec![None; self.children.len()], child_detailed_layout_infos: vec![None; self.children.len()],
}; };
fn auto_or_to_option<T>(input: GenericLengthPercentageOrAuto<T>) -> Option<T> {
match input {
LengthPercentageOrAuto::LengthPercentage(val) => Some(val),
LengthPercentageOrAuto::Auto => None,
}
}
let container_style = &content_box_size_override.style; let container_style = &content_box_size_override.style;
let align_items = container_style.clone_align_items(); let align_items = container_style.clone_align_items();
let justify_items = container_style.clone_justify_items(); let justify_items = container_style.clone_justify_items();
@ -449,14 +435,17 @@ impl TaffyContainer {
(content_box_size_override.size.inline + pbm.padding_border_sums.inline) (content_box_size_override.size.inline + pbm.padding_border_sums.inline)
.to_f32_px(), .to_f32_px(),
), ),
height: auto_or_to_option(content_box_size_override.size.block) height: content_box_size_override
.size
.block
.to_definite()
.map(Au::to_f32_px) .map(Au::to_f32_px)
.maybe_add(pbm.padding_border_sums.block.to_f32_px()), .maybe_add(pbm.padding_border_sums.block.to_f32_px()),
}; };
let taffy_containing_block = taffy::Size { let taffy_containing_block = taffy::Size {
width: Some(containing_block.size.inline.to_f32_px()), width: Some(containing_block.size.inline.to_f32_px()),
height: auto_or_to_option(containing_block.size.block).map(Au::to_f32_px), height: containing_block.size.block.to_definite().map(Au::to_f32_px),
}; };
let layout_input = taffy::LayoutInput { let layout_input = taffy::LayoutInput {