layout: Refactor FlexItemLayoutResult (#38515)

This performs various refactorings:

- Turns `content_size` into `content_block_size`, losing the inline
component, since it was the same as `containing_block_inline_size`.
- Merges `containing_block_inline_size` and
`containing_block_block_size` into `containing_block_size`.
- Removes `has_child_which_depends_on_block_constraints` since this
information should already be in `depends_on_block_constraints`.
- `FlexItem::layout()` is no longer responsible for trying to reuse the
previous result. Therefore it no longer returns an `Option`, and no
longer accepts the previous result as a parameter.
- `FlexItemLayoutResult::compatible_with_containing_block_size()` is
removed, and a simplified version is inlined into the relevant caller of
`FlexItem::layout()`.

Testing: Not needed (no change in behavior)

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
Oriol Brufau 2025-08-07 11:18:46 -07:00 committed by GitHub
parent e40be635bd
commit cf99d437fb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -128,51 +128,20 @@ struct FlexItemLayoutResult {
// Either the first or the last baseline, depending on align-self. // Either the first or the last baseline, depending on align-self.
baseline_relative_to_margin_box: Option<Au>, baseline_relative_to_margin_box: Option<Au>,
// The content size of this layout. For replaced elements this is known before layout, // The content size of this layout in the block axis. This is known before layout
// but for non-replaced it's only known after layout. // for replaced elements, but for non-replaced it's only known after layout.
content_size: LogicalVec2<Au>, content_block_size: Au,
// The containing block inline size used to generate this layout. // The containing block size used to generate this layout.
containing_block_inline_size: Au, containing_block_size: ContainingBlockSize,
// The containing block block size used to generate this layout.
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,
// Whether or not this layout had a child that dependeded on block constraints.
has_child_which_depends_on_block_constraints: bool,
// The specific layout info that this flex item had. // The specific layout info that this flex item had.
specific_layout_info: Option<SpecificLayoutInfo>, specific_layout_info: Option<SpecificLayoutInfo>,
} }
impl FlexItemLayoutResult {
fn compatible_with_containing_block_size(&self, containing_block: &ContainingBlock) -> bool {
if containing_block.size.inline == self.containing_block_inline_size &&
(containing_block.size.block == self.containing_block_block_size ||
(!self.depends_on_block_constraints &&
!self.has_child_which_depends_on_block_constraints))
{
return true;
}
#[cfg(feature = "tracing")]
tracing::warn!(
name: "NonReplaced stretch cache miss",
cached_inline = ?self.containing_block_inline_size,
cached_block = ?self.containing_block_block_size,
required_inline = ?containing_block.size.inline,
required_block = ?containing_block.size.block,
depends_on_block_constraints = self.depends_on_block_constraints,
has_child_which_depends_on_block_constraints = self.has_child_which_depends_on_block_constraints,
);
false
}
}
/// A data structure to hold all of the information about a flex item that has been placed /// A data structure to hold all of the information about a flex item that has been placed
/// into a flex line. This happens once the item is laid out and its line has been determined. /// into a flex line. This happens once the item is laid out and its line has been determined.
struct FlexLineItem<'a> { struct FlexLineItem<'a> {
@ -1233,19 +1202,13 @@ impl InitialFlexLineLayout<'_> {
items items
.par_iter() .par_iter()
.zip(&item_used_main_sizes) .zip(&item_used_main_sizes)
.map(|(item, used_main_size)| { .map(|(item, used_main_size)| item.layout(*used_main_size, flex_context, None))
item.layout(*used_main_size, flex_context, None, None)
.unwrap()
})
.collect() .collect()
} else { } else {
items items
.iter() .iter()
.zip(&item_used_main_sizes) .zip(&item_used_main_sizes)
.map(|(item, used_main_size)| { .map(|(item, used_main_size)| item.layout(*used_main_size, flex_context, None))
item.layout(*used_main_size, flex_context, None, None)
.unwrap()
})
.collect() .collect()
}; };
@ -1575,13 +1538,18 @@ impl InitialFlexLineLayout<'_> {
let mut item_used_cross_sizes = Vec::with_capacity(item_count); let mut item_used_cross_sizes = Vec::with_capacity(item_count);
let mut item_margins = Vec::with_capacity(item_count); let mut item_margins = Vec::with_capacity(item_count);
for item in self.items.iter_mut() { for item in self.items.iter_mut() {
let cross_axis = match flex_context.config.flex_axis {
FlexAxis::Row => Direction::Block,
FlexAxis::Column => Direction::Inline,
};
let layout = &mut item.layout_result;
let used_cross_size = if item.item.cross_size_stretches_to_line { let used_cross_size = if item.item.cross_size_stretches_to_line {
let (axis, content_size) = match flex_context.config.flex_axis { let content_size = match cross_axis {
FlexAxis::Row => (Direction::Block, item.layout_result.content_size.block), Direction::Block => layout.content_block_size,
FlexAxis::Column => (Direction::Inline, item.layout_result.content_size.inline), Direction::Inline => layout.containing_block_size.inline,
}; };
item.item.content_cross_sizes.resolve( item.item.content_cross_sizes.resolve(
axis, cross_axis,
Size::Stretch, Size::Stretch,
Au::zero, Au::zero,
Some(final_line_cross_size - item.item.pbm_auto_is_zero.cross), Some(final_line_cross_size - item.item.pbm_auto_is_zero.cross),
@ -1591,26 +1559,38 @@ impl InitialFlexLineLayout<'_> {
// The interaction of collapsed table tracks and the flexbox algorithms is unclear, // The interaction of collapsed table tracks and the flexbox algorithms is unclear,
// see https://github.com/w3c/csswg-drafts/issues/11408. // see https://github.com/w3c/csswg-drafts/issues/11408.
item.item.box_.independent_formatting_context.is_table() && item.item.box_.independent_formatting_context.is_table() &&
axis == Direction::Inline, cross_axis == Direction::Inline,
) )
} else { } else {
item.layout_result.hypothetical_cross_size layout.hypothetical_cross_size
}; };
item_used_cross_sizes.push(used_cross_size); item_used_cross_sizes.push(used_cross_size);
// “If the flex item has `align-self: stretch`, redo layout for its contents, // “If the flex item has `align-self: stretch`, redo layout for its contents,
// treating this used size as its definite cross size so that percentage-sized // treating this used size as its definite cross size so that percentage-sized
// children can be resolved.” // children can be resolved.”
if item.item.cross_size_stretches_to_line { let needs_new_layout = item.item.cross_size_stretches_to_line &&
let new_layout = item.item.layout( match cross_axis {
item.used_main_size, Direction::Block => {
flex_context, SizeConstraint::Definite(used_cross_size) !=
Some(used_cross_size), layout.containing_block_size.block &&
Some(&mut item.layout_result), layout.depends_on_block_constraints
},
Direction::Inline => used_cross_size != layout.containing_block_size.inline,
};
if needs_new_layout {
#[cfg(feature = "tracing")]
tracing::warn!(
name: "Flex item stretch cache miss",
cached_inline = ?layout.containing_block_size.inline,
cached_block = ?layout.containing_block_size.block,
required_cross_size = ?used_cross_size,
cross_axis = ?cross_axis,
depends_on_block_constraints = layout.depends_on_block_constraints,
); );
if let Some(layout) = new_layout { *layout =
item.layout_result = layout; item.item
} .layout(item.used_main_size, flex_context, Some(used_cross_size));
} }
let baseline = item.get_or_synthesize_baseline_with_cross_size(used_cross_size); let baseline = item.get_or_synthesize_baseline_with_cross_size(used_cross_size);
@ -1753,7 +1733,6 @@ impl FlexItem<'_> {
fields( fields(
self_address = self as *const _ as usize, self_address = self as *const _ as usize,
box_address = self.box_ as *const _ as usize, box_address = self.box_ as *const _ as usize,
for_stretch = non_stretch_layout_result.is_some()
) )
)] )]
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
@ -1762,8 +1741,7 @@ impl FlexItem<'_> {
used_main_size: Au, used_main_size: Au,
flex_context: &FlexContext, flex_context: &FlexContext,
used_cross_size_override: Option<Au>, used_cross_size_override: Option<Au>,
non_stretch_layout_result: Option<&mut FlexItemLayoutResult>, ) -> FlexItemLayoutResult {
) -> Option<FlexItemLayoutResult> {
let containing_block = flex_context.containing_block; let containing_block = flex_context.containing_block;
let independent_formatting_context = &self.box_.independent_formatting_context; let independent_formatting_context = &self.box_.independent_formatting_context;
let is_table = independent_formatting_context.is_table(); let is_table = independent_formatting_context.is_table();
@ -1858,12 +1836,6 @@ impl FlexItem<'_> {
style: item_style, style: item_style,
}; };
if non_stretch_layout_result.is_some_and(|old_result| {
old_result.compatible_with_containing_block_size(&item_as_containing_block)
}) {
return None;
}
let lazy_block_size = if !cross_axis_is_item_block_axis { let lazy_block_size = if !cross_axis_is_item_block_axis {
used_main_size.into() used_main_size.into()
} else if let Some(cross_size) = used_cross_size_override { } else if let Some(cross_size) = used_cross_size_override {
@ -1904,14 +1876,6 @@ impl FlexItem<'_> {
.. ..
} = layout; } = layout;
let has_child_which_depends_on_block_constraints = fragments.iter().any(|fragment| {
fragment.base().is_some_and(|base| {
base.flags.contains(
FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
)
})
});
let hypothetical_cross_size = if cross_axis_is_item_block_axis { let hypothetical_cross_size = if cross_axis_is_item_block_axis {
lazy_block_size.resolve(|| content_block_size) lazy_block_size.resolve(|| content_block_size)
} else { } else {
@ -1943,21 +1907,16 @@ impl FlexItem<'_> {
_ => None, _ => None,
}; };
Some(FlexItemLayoutResult { FlexItemLayoutResult {
hypothetical_cross_size, hypothetical_cross_size,
fragments, fragments,
positioning_context, positioning_context,
baseline_relative_to_margin_box, baseline_relative_to_margin_box,
content_size: LogicalVec2 { content_block_size,
inline: item_as_containing_block.size.inline, containing_block_size: item_as_containing_block.size,
block: content_block_size,
},
containing_block_inline_size: item_as_containing_block.size.inline,
containing_block_block_size: item_as_containing_block.size.block,
depends_on_block_constraints, depends_on_block_constraints,
has_child_which_depends_on_block_constraints,
specific_layout_info, specific_layout_info,
}) }
} }
fn synthesized_baseline_relative_to_margin_box(&self, content_size: Au) -> Au { fn synthesized_baseline_relative_to_margin_box(&self, content_size: Au) -> Au {