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

@ -2076,11 +2076,8 @@ impl IndependentFormattingContext {
.content_rect .content_rect
.translate(pbm_physical_offset.to_vector()); .translate(pbm_physical_offset.to_vector());
// Apply baselines if necessary. // Apply baselines.
let mut fragment = match baselines { fragment = fragment.with_baselines(baselines);
Some(baselines) => fragment.with_baselines(baselines),
None => fragment,
};
// Lay out absolutely positioned children if this new atomic establishes a containing block // Lay out absolutely positioned children if this new atomic establishes a containing block
// for absolutes. // for absolutes.

View file

@ -2226,7 +2226,7 @@ fn block_size_is_zero_or_intrinsic(size: &StyleSize, containing_block: &Containi
pub(crate) struct IndependentFloatOrAtomicLayoutResult { pub(crate) struct IndependentFloatOrAtomicLayoutResult {
pub fragment: BoxFragment, pub fragment: BoxFragment,
pub baselines: Option<Baselines>, pub baselines: Baselines,
pub pbm_sums: LogicalSides<Au>, pub pbm_sums: LogicalSides<Au>,
} }
@ -2238,6 +2238,7 @@ impl IndependentFormattingContext {
containing_block: &ContainingBlock, containing_block: &ContainingBlock,
) -> IndependentFloatOrAtomicLayoutResult { ) -> IndependentFloatOrAtomicLayoutResult {
let style = self.style(); let style = self.style();
let writing_mode = style.writing_mode;
let container_writing_mode = containing_block.style.writing_mode; let container_writing_mode = containing_block.style.writing_mode;
let layout_style = self.layout_style(); let layout_style = self.layout_style();
let content_box_sizes_and_pbm = let content_box_sizes_and_pbm =
@ -2245,115 +2246,97 @@ impl IndependentFormattingContext {
let pbm = &content_box_sizes_and_pbm.pbm; let pbm = &content_box_sizes_and_pbm.pbm;
let margin = pbm.margin.auto_is(Au::zero); let margin = pbm.margin.auto_is(Au::zero);
let pbm_sums = pbm.padding + pbm.border + margin; 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 { let available_inline_size =
IndependentFormattingContextContents::Replaced(replaced) => { Au::zero().max(containing_block.size.inline - pbm_sums.inline_sum());
// Floats and atomic inlines can't collapse margins with their parent, let available_block_size = containing_block
// so don't ignore block margins when resolving a stretch block size. .size
// https://drafts.csswg.org/css-sizing-4/#stretch-fit-sizing .block
let ignore_block_margins_for_stretch = LogicalSides1D::new(false, false); .to_definite()
.map(|block_size| Au::zero().max(block_size - pbm_sums.block_sum()));
// https://drafts.csswg.org/css2/visudet.html#float-replaced-width let tentative_block_content_size =
// https://drafts.csswg.org/css2/visudet.html#inline-replaced-height self.tentative_block_content_size(preferred_aspect_ratio);
let content_size = replaced let tentative_block_size = if let Some(block_content_size) = tentative_block_content_size {
.used_size_as_if_inline_element( SizeConstraint::Definite(content_box_sizes_and_pbm.content_box_sizes.block.resolve(
containing_block, Direction::Block,
style, Size::FitContent,
&content_box_sizes_and_pbm, Au::zero,
ignore_block_margins_for_stretch, available_block_size,
) || block_content_size,
.to_physical_size(container_writing_mode); is_table,
let fragments = replaced.make_fragments(layout_context, style, content_size); ))
} else {
let content_rect = PhysicalRect::new(PhysicalPoint::zero(), content_size); content_box_sizes_and_pbm
(fragments, content_rect, None, None) .content_box_sizes
}, .block
IndependentFormattingContextContents::NonReplaced(non_replaced) => { .resolve_extrinsic(Size::FitContent, Au::zero(), available_block_size)
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 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(); let mut base_fragment_info = self.base_fragment_info();
if content_box_sizes_and_pbm.depends_on_block_constraints { if content_box_sizes_and_pbm.depends_on_block_constraints {
base_fragment_info.flags.insert( base_fragment_info.flags.insert(
@ -2366,7 +2349,7 @@ impl IndependentFormattingContext {
// And atomic inlines don't have clearance. // And atomic inlines don't have clearance.
let fragment = BoxFragment::new( let fragment = BoxFragment::new(
base_fragment_info, base_fragment_info,
self.style().clone(), style.clone(),
fragments, fragments,
content_rect, content_rect,
pbm.padding.to_physical(container_writing_mode), pbm.padding.to_physical(container_writing_mode),

View file

@ -85,13 +85,6 @@ impl<T: Copy> From<T> for LogicalVec2<T> {
} }
impl<T> LogicalVec2<T> { impl<T> LogicalVec2<T> {
pub(crate) fn as_ref(&self) -> LogicalVec2<&T> {
LogicalVec2 {
inline: &self.inline,
block: &self.block,
}
}
pub fn map_inline_and_block_axes<U>( pub fn map_inline_and_block_axes<U>(
&self, &self,
inline_f: impl FnOnce(&T) -> U, inline_f: impl FnOnce(&T) -> U,

View file

@ -29,12 +29,10 @@ use crate::dom::NodeExt;
use crate::fragment_tree::{ use crate::fragment_tree::{
BaseFragmentInfo, CollapsedBlockMargins, Fragment, IFrameFragment, ImageFragment, BaseFragmentInfo, CollapsedBlockMargins, Fragment, IFrameFragment, ImageFragment,
}; };
use crate::geom::{ use crate::geom::{LazySize, LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSize, Size, Sizes};
LazySize, LogicalSides1D, LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSize, Size, Sizes,
};
use crate::layout_box_base::{CacheableLayoutResult, LayoutBoxBase}; use crate::layout_box_base::{CacheableLayoutResult, LayoutBoxBase};
use crate::sizing::{ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult}; use crate::sizing::{ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult};
use crate::style_ext::{AspectRatio, Clamp, ComputedValuesExt, ContentBoxSizesAndPBM, LayoutStyle}; use crate::style_ext::{AspectRatio, Clamp, ComputedValuesExt, LayoutStyle};
use crate::{ConstraintSpace, ContainingBlock, SizeConstraint}; use crate::{ConstraintSpace, ContainingBlock, SizeConstraint};
#[derive(Debug, MallocSizeOf)] #[derive(Debug, MallocSizeOf)]
@ -410,29 +408,6 @@ impl ReplacedContents {
}) })
} }
/// <https://drafts.csswg.org/css2/visudet.html#inline-replaced-width>
/// <https://drafts.csswg.org/css2/visudet.html#inline-replaced-height>
///
/// Also used in other cases, for example
/// <https://drafts.csswg.org/css2/visudet.html#block-replaced-width>
pub(crate) fn used_size_as_if_inline_element(
&self,
containing_block: &ContainingBlock,
style: &ComputedValues,
content_box_sizes_and_pbm: &ContentBoxSizesAndPBM,
ignore_block_margins_for_stretch: LogicalSides1D<bool>,
) -> LogicalVec2<Au> {
let pbm = &content_box_sizes_and_pbm.pbm;
self.used_size_as_if_inline_element_from_content_box_sizes(
containing_block,
style,
self.preferred_aspect_ratio(style, &pbm.padding_border_sums),
content_box_sizes_and_pbm.content_box_sizes.as_ref(),
Size::FitContent.into(),
pbm.sums_auto_is_zero(ignore_block_margins_for_stretch),
)
}
/// The aspect ratio of the default object sizes. /// The aspect ratio of the default object sizes.
/// <https://drafts.csswg.org/css-images-3/#default-object-size> /// <https://drafts.csswg.org/css-images-3/#default-object-size>
pub(crate) fn default_aspect_ratio() -> AspectRatio { pub(crate) fn default_aspect_ratio() -> AspectRatio {