layout: Unify layout logic for replaced and non-replaced floats&atomics (#37897)

Laying out a float or atomic inline will now use the same logic
regardless of whether it's replaced or not.
This reduces the amount of code, and should have no observable effect.

Testing: Unneeded (no behavior change)
This part of #37942

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
Oriol Brufau 2025-07-09 21:46:22 +02:00 committed by GitHub
parent 70c57c6136
commit 47c56d8d74
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 94 additions and 146 deletions

View file

@ -2226,7 +2226,7 @@ fn block_size_is_zero_or_intrinsic(size: &StyleSize, containing_block: &Containi
pub(crate) struct IndependentFloatOrAtomicLayoutResult {
pub fragment: BoxFragment,
pub baselines: Option<Baselines>,
pub baselines: Baselines,
pub pbm_sums: LogicalSides<Au>,
}
@ -2238,6 +2238,7 @@ impl IndependentFormattingContext {
containing_block: &ContainingBlock,
) -> IndependentFloatOrAtomicLayoutResult {
let style = self.style();
let writing_mode = style.writing_mode;
let container_writing_mode = containing_block.style.writing_mode;
let layout_style = self.layout_style();
let content_box_sizes_and_pbm =
@ -2245,115 +2246,97 @@ impl IndependentFormattingContext {
let pbm = &content_box_sizes_and_pbm.pbm;
let margin = pbm.margin.auto_is(Au::zero);
let pbm_sums = pbm.padding + pbm.border + margin;
let preferred_aspect_ratio = self.preferred_aspect_ratio(&pbm.padding_border_sums);
let is_table = self.is_table();
let (fragments, content_rect, baselines, specific_layout_info) = match &self.contents {
IndependentFormattingContextContents::Replaced(replaced) => {
// Floats and atomic inlines can't collapse margins with their parent,
// so don't ignore block margins when resolving a stretch block size.
// https://drafts.csswg.org/css-sizing-4/#stretch-fit-sizing
let ignore_block_margins_for_stretch = LogicalSides1D::new(false, false);
let available_inline_size =
Au::zero().max(containing_block.size.inline - pbm_sums.inline_sum());
let available_block_size = containing_block
.size
.block
.to_definite()
.map(|block_size| Au::zero().max(block_size - pbm_sums.block_sum()));
// https://drafts.csswg.org/css2/visudet.html#float-replaced-width
// https://drafts.csswg.org/css2/visudet.html#inline-replaced-height
let content_size = replaced
.used_size_as_if_inline_element(
containing_block,
style,
&content_box_sizes_and_pbm,
ignore_block_margins_for_stretch,
)
.to_physical_size(container_writing_mode);
let fragments = replaced.make_fragments(layout_context, style, content_size);
let content_rect = PhysicalRect::new(PhysicalPoint::zero(), content_size);
(fragments, content_rect, None, None)
},
IndependentFormattingContextContents::NonReplaced(non_replaced) => {
let writing_mode = self.style().writing_mode;
let available_inline_size =
Au::zero().max(containing_block.size.inline - pbm_sums.inline_sum());
let available_block_size = containing_block
.size
.block
.to_definite()
.map(|block_size| Au::zero().max(block_size - pbm_sums.block_sum()));
let tentative_block_size = content_box_sizes_and_pbm
.content_box_sizes
.block
.resolve_extrinsic(Size::FitContent, Au::zero(), available_block_size);
let get_content_size = || {
let constraint_space = ConstraintSpace::new(
tentative_block_size,
writing_mode,
non_replaced.preferred_aspect_ratio(),
);
self.inline_content_sizes(layout_context, &constraint_space)
.sizes
};
let is_table = layout_style.is_table();
let inline_size = content_box_sizes_and_pbm.content_box_sizes.inline.resolve(
Direction::Inline,
Size::FitContent,
Au::zero,
Some(available_inline_size),
get_content_size,
is_table,
);
let containing_block_for_children = ContainingBlock {
size: ContainingBlockSize {
inline: inline_size,
block: tentative_block_size,
},
style: self.style(),
};
assert_eq!(
container_writing_mode.is_horizontal(),
writing_mode.is_horizontal(),
"Mixed horizontal and vertical writing modes are not supported yet"
);
let lazy_block_size = LazySize::new(
&content_box_sizes_and_pbm.content_box_sizes.block,
Direction::Block,
Size::FitContent,
Au::zero,
available_block_size,
is_table,
);
let independent_layout = non_replaced.layout(
layout_context,
child_positioning_context,
&containing_block_for_children,
containing_block,
&self.base,
false, /* depends_on_block_constraints */
&lazy_block_size,
);
let inline_size = independent_layout
.content_inline_size_for_table
.unwrap_or(inline_size);
let block_size = lazy_block_size.resolve(|| independent_layout.content_block_size);
let content_size = LogicalVec2 {
block: block_size,
inline: inline_size,
}
.to_physical_size(container_writing_mode);
let content_rect = PhysicalRect::new(PhysicalPoint::zero(), content_size);
(
independent_layout.fragments,
content_rect,
Some(independent_layout.baselines),
independent_layout.specific_layout_info,
)
},
let tentative_block_content_size =
self.tentative_block_content_size(preferred_aspect_ratio);
let tentative_block_size = if let Some(block_content_size) = tentative_block_content_size {
SizeConstraint::Definite(content_box_sizes_and_pbm.content_box_sizes.block.resolve(
Direction::Block,
Size::FitContent,
Au::zero,
available_block_size,
|| block_content_size,
is_table,
))
} else {
content_box_sizes_and_pbm
.content_box_sizes
.block
.resolve_extrinsic(Size::FitContent, Au::zero(), available_block_size)
};
let get_content_size = || {
let constraint_space =
ConstraintSpace::new(tentative_block_size, writing_mode, preferred_aspect_ratio);
self.inline_content_sizes(layout_context, &constraint_space)
.sizes
};
let inline_size = content_box_sizes_and_pbm.content_box_sizes.inline.resolve(
Direction::Inline,
Size::FitContent,
Au::zero,
Some(available_inline_size),
get_content_size,
is_table,
);
let containing_block_for_children = ContainingBlock {
size: ContainingBlockSize {
inline: inline_size,
block: tentative_block_size,
},
style,
};
assert_eq!(
container_writing_mode.is_horizontal(),
writing_mode.is_horizontal(),
"Mixed horizontal and vertical writing modes are not supported yet"
);
let lazy_block_size = LazySize::new(
&content_box_sizes_and_pbm.content_box_sizes.block,
Direction::Block,
Size::FitContent,
Au::zero,
available_block_size,
is_table,
);
let CacheableLayoutResult {
content_inline_size_for_table,
content_block_size,
fragments,
baselines,
specific_layout_info,
..
} = self.layout(
layout_context,
child_positioning_context,
&containing_block_for_children,
containing_block,
preferred_aspect_ratio,
false, /* depends_on_block_constraints */
&lazy_block_size,
);
let content_size = LogicalVec2 {
inline: content_inline_size_for_table.unwrap_or(inline_size),
block: lazy_block_size.resolve(|| content_block_size),
}
.to_physical_size(container_writing_mode);
let content_rect = PhysicalRect::new(PhysicalPoint::zero(), content_size);
let mut base_fragment_info = self.base_fragment_info();
if content_box_sizes_and_pbm.depends_on_block_constraints {
base_fragment_info.flags.insert(
@ -2366,7 +2349,7 @@ impl IndependentFormattingContext {
// And atomic inlines don't have clearance.
let fragment = BoxFragment::new(
base_fragment_info,
self.style().clone(),
style.clone(),
fragments,
content_rect,
pbm.padding.to_physical(container_writing_mode),