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,
// 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.
depends_on_block_constraints: bool,
@ -662,7 +662,7 @@ impl FlexContainer {
container_definite_inner_size: self.config.flex_axis.vec2_to_flex_relative(
LogicalVec2 {
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
let container_main_size = match self.config.flex_axis {
FlexAxis::Row => containing_block.size.inline,
FlexAxis::Column => containing_block.size.block.auto_is(|| {
self.main_content_sizes(layout_context, &containing_block.into(), || &flex_context)
FlexAxis::Column => match containing_block.size.block {
SizeConstraint::Definite(size) => size,
_ => self
.main_content_sizes(layout_context, &containing_block.into(), || &flex_context)
.sizes
.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
@ -1894,13 +1896,12 @@ impl FlexItem<'_> {
});
let cross_size = match used_cross_size_override {
Some(s) => AuOrAuto::LengthPercentage(s),
None => self.content_box_size.cross.map(|cross_size| {
cross_size.clamp_between_extremums(
self.content_min_size.cross,
self.content_max_size.cross,
)
}),
Some(s) => SizeConstraint::Definite(s),
None => SizeConstraint::new(
self.content_box_size.cross.non_auto(),
self.content_min_size.cross,
self.content_max_size.cross,
),
};
let independent_formatting_context = &self.box_.independent_formatting_context;
@ -1917,7 +1918,7 @@ impl FlexItem<'_> {
(used_main_size, cross_size)
} else {
(
cross_size.auto_is(|| {
cross_size.to_definite().unwrap_or_else(|| {
let style = self.box_.style();
let stretch_size =
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 ||
flex_context.container_definite_inner_size.main.is_some()
{
AuOrAuto::LengthPercentage(used_main_size)
SizeConstraint::Definite(used_main_size)
} else {
AuOrAuto::Auto
SizeConstraint::default()
},
)
};
@ -1965,7 +1966,9 @@ impl FlexItem<'_> {
item_style,
self.preferred_aspect_ratio,
&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),
max_size.block.map_or(Size::Initial, Size::Numeric),
),
@ -2834,7 +2837,7 @@ impl FlexItemBox {
let item_as_containing_block = ContainingBlock {
size: ContainingBlockSize {
inline: inline_size,
block: AuOrAuto::Auto,
block: SizeConstraint::default(),
},
style,
};

View file

@ -191,6 +191,6 @@ impl CachedBlockSizeContribution {
item_as_containing_block: &ContainingBlock,
) -> bool {
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::{
BaseFragmentInfo, BoxFragment, CollapsedBlockMargins, Fragment, TextFragment,
};
use crate::geom::{AuOrAuto, LogicalRect, LogicalVec2, PhysicalRect, ToLogical};
use crate::geom::{LogicalRect, LogicalVec2, PhysicalRect, ToLogical};
use crate::positioned::{
relative_adjustement, AbsolutelyPositionedBox, PositioningContext, PositioningContextLength,
};
@ -427,7 +427,7 @@ impl LineItemLayout<'_, '_> {
let inline_box_containing_block = ContainingBlock {
size: ContainingBlockSize {
inline: content_rect.size.inline,
block: AuOrAuto::Auto,
block: Default::default(),
},
style: self.layout.containing_block.style,
};

View file

@ -145,7 +145,7 @@ impl BlockLevelBox {
let available_inline_size =
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())
});
@ -174,7 +174,7 @@ impl BlockLevelBox {
let containing_block_for_children = ContainingBlock {
size: ContainingBlockSize {
inline: inline_size,
block: tentative_block_size.to_auto_or(),
block: tentative_block_size,
},
style,
};
@ -269,7 +269,7 @@ impl OutsideMarker {
let containing_block_for_children = ContainingBlock {
size: ContainingBlockSize {
inline: content_sizes.sizes.max_content,
block: AuOrAuto::auto(),
block: SizeConstraint::default(),
},
style: &self.marker_style,
};
@ -1202,7 +1202,7 @@ impl IndependentNonReplacedContents {
let available_block_size = containing_block
.size
.block
.non_auto()
.to_definite()
.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
.block
@ -1265,7 +1265,7 @@ impl IndependentNonReplacedContents {
&ContainingBlock {
size: ContainingBlockSize {
inline: inline_size,
block: tentative_block_size.to_auto_or(),
block: tentative_block_size,
},
style,
},
@ -1335,7 +1335,7 @@ impl IndependentNonReplacedContents {
&ContainingBlock {
size: ContainingBlockSize {
inline: proposed_inline_size,
block: tentative_block_size.to_auto_or(),
block: tentative_block_size,
},
style,
},
@ -1662,7 +1662,7 @@ fn solve_containing_block_padding_and_border_for_in_flow_box<'a>(
let available_block_size = containing_block
.size
.block
.non_auto()
.to_definite()
.map(|block_size| Au::zero().max(block_size - pbm_sums.block_sum()));
// 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 {
size: ContainingBlockSize {
inline: inline_size,
block: tentative_block_size.to_auto_or(),
block: tentative_block_size,
},
style,
};
@ -2102,7 +2102,7 @@ fn block_size_is_zero_or_intrinsic(size: &StyleSize, containing_block: &Containi
StyleSize::LengthPercentage(ref lp) => {
// TODO: Should this resolve definite percentages? Blink does it, Gecko and WebKit don't.
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"),
}
@ -2171,7 +2171,7 @@ impl IndependentFormattingContext {
let available_block_size = containing_block
.size
.block
.non_auto()
.to_definite()
.map(|block_size| (block_size - pbm_sums.block_sum()).max(Au::zero()));
let tentative_block_size = content_box_sizes_and_pbm
.content_box_sizes
@ -2198,7 +2198,7 @@ impl IndependentFormattingContext {
let containing_block_for_children = ContainingBlock {
size: ContainingBlockSize {
inline: inline_size,
block: tentative_block_size.to_auto_or(),
block: tentative_block_size,
},
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)),
|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()
},
)
@ -856,6 +858,11 @@ impl SizeConstraint {
)
}
#[inline]
pub(crate) fn is_definite(self) -> bool {
matches!(self, Self::Definite(_))
}
#[inline]
pub(crate) fn to_definite(self) -> Option<Au> {
match self {

View file

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

View file

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

View file

@ -514,7 +514,7 @@ impl ReplacedContents {
let block_stretch_size = containing_block
.size
.block
.non_auto()
.to_definite()
.map(|block_size| Au::zero().max(block_size - pbm_sums.block));
// 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)
.map_inline_and_block_sizes(
|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)
}

View file

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

View file

@ -5,7 +5,6 @@
use app_units::Au;
use atomic_refcell::{AtomicRef, AtomicRefCell};
use style::properties::ComputedValues;
use style::values::generics::length::{GenericLengthPercentageOrAuto, LengthPercentageOrAuto};
use style::values::specified::align::AlignFlags;
use style::values::specified::box_::DisplayInside;
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 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> {
match input {
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 {
size: ContainingBlockSize {
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,
};
@ -361,7 +354,7 @@ impl ComputeInlineContentSizes for TaffyContainer {
let containing_block = &ContainingBlock {
size: ContainingBlockSize {
inline: Au::zero(),
block: GenericLengthPercentageOrAuto::Auto,
block: SizeConstraint::default(),
},
style,
};
@ -432,13 +425,6 @@ impl TaffyContainer {
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 align_items = container_style.clone_align_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)
.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)
.maybe_add(pbm.padding_border_sums.block.to_f32_px()),
};
let taffy_containing_block = taffy::Size {
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 {