aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authorOriol Brufau <obrufau@igalia.com>2024-12-18 16:52:18 -0800
committerGitHub <noreply@github.com>2024-12-19 00:52:18 +0000
commite2a0ac07ff2aeece5485f491210e77ebc2af127c (patch)
treec25df0f0f89a7ef23920017d508cb970e7a2aec7 /components
parent28e330c9b6bf4edfdb42172968268fba85ceecf5 (diff)
downloadservo-e2a0ac07ff2aeece5485f491210e77ebc2af127c.tar.gz
servo-e2a0ac07ff2aeece5485f491210e77ebc2af127c.zip
Refactor box size computation (#34671)
in each layout logic, in order to correctly resolve sizing keywords. This patch adds a new `Sizes` struct which holds the preferred, min and max sizing values for one axis, and unifies the logic to resolve the final size into there. Signed-off-by: Oriol Brufau <obrufau@igalia.com>
Diffstat (limited to 'components')
-rw-r--r--components/layout_2020/flexbox/layout.rs44
-rw-r--r--components/layout_2020/flow/mod.rs259
-rw-r--r--components/layout_2020/geom.rs119
-rw-r--r--components/layout_2020/positioned.rs76
-rw-r--r--components/layout_2020/replaced.rs70
-rw-r--r--components/layout_2020/sizing.rs33
-rw-r--r--components/layout_2020/style_ext.rs29
-rw-r--r--components/layout_2020/taffy/layout.rs24
8 files changed, 311 insertions, 343 deletions
diff --git a/components/layout_2020/flexbox/layout.rs b/components/layout_2020/flexbox/layout.rs
index 668477cbd32..84cc08232fc 100644
--- a/components/layout_2020/flexbox/layout.rs
+++ b/components/layout_2020/flexbox/layout.rs
@@ -34,7 +34,7 @@ use crate::formatting_contexts::{
Baselines, IndependentFormattingContextContents, IndependentLayout,
};
use crate::fragment_tree::{BoxFragment, CollapsedBlockMargins, Fragment, FragmentFlags};
-use crate::geom::{AuOrAuto, LogicalRect, LogicalSides, LogicalVec2, Size};
+use crate::geom::{AuOrAuto, LogicalRect, LogicalSides, LogicalVec2, Size, Sizes};
use crate::positioned::{
relative_adjustement, AbsolutelyPositionedBox, PositioningContext, PositioningContextLength,
};
@@ -1957,20 +1957,22 @@ impl FlexItem<'_> {
let item_style = independent_formatting_context.style();
match &independent_formatting_context.contents {
IndependentFormattingContextContents::Replaced(replaced) => {
+ let min_size = flex_axis.vec2_to_flow_relative(self.content_min_size);
+ let max_size = flex_axis.vec2_to_flow_relative(self.content_max_size);
let size = replaced.used_size_as_if_inline_element_from_content_box_sizes(
containing_block,
item_style,
self.preferred_aspect_ratio,
- LogicalVec2 {
- inline: Size::Numeric(inline_size),
- block: block_size.non_auto().map_or(Size::Initial, Size::Numeric),
- },
- flex_axis
- .vec2_to_flow_relative(self.content_min_size)
- .map(|size| Size::Numeric(*size)),
- flex_axis
- .vec2_to_flow_relative(self.content_max_size)
- .map(|size| size.map_or(Size::Initial, Size::Numeric)),
+ &Sizes::new(
+ block_size.non_auto().map_or(Size::Initial, Size::Numeric),
+ Size::Numeric(min_size.block),
+ max_size.block.map_or(Size::Initial, Size::Numeric),
+ ),
+ &Sizes::new(
+ Size::Numeric(inline_size),
+ Size::Numeric(min_size.inline),
+ max_size.inline.map_or(Size::Initial, Size::Numeric),
+ ),
flex_axis.vec2_to_flow_relative(self.pbm_auto_is_zero),
);
let hypothetical_cross_size = flex_axis.vec2_to_flex_relative(size).cross;
@@ -2777,10 +2779,22 @@ impl FlexItemBox {
flex_context.containing_block,
style,
preferred_aspect_ratio,
- content_box_size
- .map(|size| size.non_auto().map_or(Size::Initial, Size::Numeric)),
- min_size.map(|size| Size::Numeric(*size)),
- max_size.map(|size| size.map_or(Size::Initial, Size::Numeric)),
+ &Sizes::new(
+ content_box_size
+ .block
+ .non_auto()
+ .map_or(Size::Initial, Size::Numeric),
+ Size::Numeric(min_size.block),
+ max_size.block.map_or(Size::Initial, Size::Numeric),
+ ),
+ &Sizes::new(
+ content_box_size
+ .inline
+ .non_auto()
+ .map_or(Size::Initial, Size::Numeric),
+ Size::Numeric(min_size.inline),
+ max_size.inline.map_or(Size::Initial, Size::Numeric),
+ ),
padding_border_margin.padding_border_sums +
padding_border_margin.margin.auto_is(Au::zero).sum(),
)
diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs
index d66ab0332a5..e94301391e2 100644
--- a/components/layout_2020/flow/mod.rs
+++ b/components/layout_2020/flow/mod.rs
@@ -5,8 +5,6 @@
//! Flow layout, also known as block-and-inline layout.
-use std::cell::LazyCell;
-
use app_units::Au;
use inline::InlineFormattingContext;
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
@@ -35,7 +33,7 @@ use crate::fragment_tree::{
};
use crate::geom::{
AuOrAuto, LogicalRect, LogicalSides, LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSides,
- Size, ToLogical, ToLogicalWithContainingBlock,
+ Size, Sizes, ToLogical, ToLogicalWithContainingBlock,
};
use crate::layout_box_base::LayoutBoxBase;
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext, PositioningContextLength};
@@ -796,9 +794,7 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context(
let ContainingBlockPaddingAndBorder {
containing_block: containing_block_for_children,
pbm,
- preferred_block_size,
- min_block_size,
- max_block_size,
+ block_sizes,
depends_on_block_constraints,
available_block_size,
} = solve_containing_block_padding_and_border_for_in_flow_box(
@@ -939,16 +935,12 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context(
content_block_size += collapsible_margins_in_children.end.solve();
}
- let available_block_size = available_block_size.unwrap_or(content_block_size);
- let block_content_sizes = LazyCell::new(|| content_block_size.into());
- let preferred_block_size =
- preferred_block_size.resolve(Size::FitContent, available_block_size, &block_content_sizes);
- let min_block_size = min_block_size
- .resolve_non_initial(available_block_size, &block_content_sizes)
- .unwrap_or_default();
- let max_block_size =
- max_block_size.resolve_non_initial(available_block_size, &block_content_sizes);
- let block_size = preferred_block_size.clamp_between_extremums(min_block_size, max_block_size);
+ let block_size = block_sizes.resolve(
+ Size::FitContent,
+ Au::zero(),
+ available_block_size.unwrap_or(content_block_size),
+ || content_block_size.into(),
+ );
if let Some(ref mut sequential_layout_state) = sequential_layout_state {
// Now that we're done laying out our children, we can restore the
@@ -1042,9 +1034,7 @@ impl IndependentNonReplacedContents {
let ContainingBlockPaddingAndBorder {
containing_block: containing_block_for_children,
pbm,
- preferred_block_size,
- min_block_size,
- max_block_size,
+ block_sizes,
depends_on_block_constraints,
available_block_size,
} = solve_containing_block_padding_and_border_for_in_flow_box(
@@ -1063,21 +1053,12 @@ impl IndependentNonReplacedContents {
let (block_size, inline_size) = match layout.content_inline_size_for_table {
Some(inline_size) => (layout.content_block_size, inline_size),
None => {
- let available_block_size =
- available_block_size.unwrap_or(layout.content_block_size);
- let block_content_sizes = LazyCell::new(|| layout.content_block_size.into());
- let preferred_block_size = preferred_block_size.resolve(
+ let block_size = block_sizes.resolve(
Size::FitContent,
- available_block_size,
- &block_content_sizes,
+ Au::zero(),
+ available_block_size.unwrap_or(layout.content_block_size),
+ || layout.content_block_size.into(),
);
- let min_block_size = min_block_size
- .resolve_non_initial(available_block_size, &block_content_sizes)
- .unwrap_or_default();
- let max_block_size =
- max_block_size.resolve_non_initial(available_block_size, &block_content_sizes);
- let block_size =
- preferred_block_size.clamp_between_extremums(min_block_size, max_block_size);
(block_size, containing_block_for_children.size.inline)
},
};
@@ -1137,9 +1118,7 @@ impl IndependentNonReplacedContents {
let style = &base.style;
let containing_block_writing_mode = containing_block.style.writing_mode;
let ContentBoxSizesAndPBM {
- content_box_size,
- content_min_box_size,
- content_max_box_size,
+ content_box_sizes,
pbm,
depends_on_block_constraints,
} = style.content_box_sizes_and_padding_border_margin(&containing_block.into());
@@ -1181,21 +1160,14 @@ impl IndependentNonReplacedContents {
.block
.non_auto()
.map(|block_size| Au::zero().max(block_size - pbm_sums.block_sum()));
- let preferred_block_size = content_box_size
- .block
- .maybe_resolve_extrinsic(available_block_size);
- let min_block_size = content_min_box_size
- .block
- .maybe_resolve_extrinsic(available_block_size)
- .unwrap_or_default();
- let max_block_size = content_max_box_size
+ let (preferred_block_size, min_block_size, max_block_size) = content_box_sizes
.block
- .maybe_resolve_extrinsic(available_block_size);
+ .resolve_each_extrinsic(Size::FitContent, Au::zero(), available_block_size);
let tentative_block_size =
SizeConstraint::new(preferred_block_size, min_block_size, max_block_size);
// With the tentative block size we can compute the inline min/max-content sizes.
- let inline_content_sizes = LazyCell::new(|| {
+ let get_inline_content_sizes = || {
let constraint_space = ConstraintSpace::new(
tentative_block_size,
style.writing_mode,
@@ -1203,55 +1175,29 @@ impl IndependentNonReplacedContents {
);
base.inline_content_sizes(layout_context, &constraint_space, self)
.sizes
- });
+ };
- // The final inline size can depend on the available space, which depends on where
- // we are placing the box, since floats reduce the available space.
- // TODO: this logic could be refined further, since even if some of the 3 sizes
- // depends on the available space, the resulting size might not. For example,
- // `min-width: 200px; width: 100px; max-width: stretch`.
- let inline_size_depends_on_available_space = matches!(
- content_box_size.inline,
- Size::Initial | Size::Stretch | Size::FitContent
- ) || matches!(
- content_min_box_size.inline,
- Size::Stretch | Size::FitContent
- ) || matches!(
- content_max_box_size.inline,
- Size::Stretch | Size::FitContent
- );
let compute_inline_size = |stretch_size| {
- let preferred_inline_size =
- content_box_size
- .inline
- .resolve(Size::Stretch, stretch_size, &inline_content_sizes);
- let min_inline_size = content_min_box_size
- .inline
- .resolve_non_initial(stretch_size, &inline_content_sizes)
- .unwrap_or_default();
- let max_inline_size = content_max_box_size
- .inline
- .resolve_non_initial(stretch_size, &inline_content_sizes);
- preferred_inline_size.clamp_between_extremums(min_inline_size, max_inline_size)
+ content_box_sizes.inline.resolve(
+ Size::Stretch,
+ Au::zero(),
+ stretch_size,
+ get_inline_content_sizes,
+ )
};
let compute_block_size = |layout: &IndependentLayout| {
- let stretch_size = available_block_size.unwrap_or(layout.content_block_size);
- let block_contents_size = LazyCell::new(|| layout.content_block_size.into());
- let min_block_size = content_min_box_size
- .block
- .resolve_non_initial(stretch_size, &block_contents_size)
- .unwrap_or_default();
- let max_block_size = content_max_box_size
- .block
- .resolve_non_initial(stretch_size, &block_contents_size);
- tentative_block_size
- .to_definite()
- .unwrap_or(layout.content_block_size)
- .clamp_between_extremums(min_block_size, max_block_size)
+ content_box_sizes.block.resolve(
+ Size::FitContent,
+ Au::zero(),
+ available_block_size.unwrap_or(layout.content_block_size),
+ || layout.content_block_size.into(),
+ )
};
- if !inline_size_depends_on_available_space {
+ // The final inline size can depend on the available space, which depends on where
+ // we are placing the box, since floats reduce the available space.
+ if !content_box_sizes.inline.depends_on_available_space() {
// If the inline size doesn't depend on the available inline space, we can just
// compute it with an available inline space of zero. Then, after layout we can
// compute the block size, and finally place among floats.
@@ -1591,9 +1537,7 @@ impl ReplacedContents {
struct ContainingBlockPaddingAndBorder<'a> {
containing_block: ContainingBlock<'a>,
pbm: PaddingBorderMargin,
- preferred_block_size: Size<Au>,
- min_block_size: Size<Au>,
- max_block_size: Size<Au>,
+ block_sizes: Sizes,
depends_on_block_constraints: bool,
available_block_size: Option<Au>,
}
@@ -1637,9 +1581,7 @@ fn solve_containing_block_padding_and_border_for_in_flow_box<'a>(
return ContainingBlockPaddingAndBorder {
containing_block: containing_block_for_children,
pbm: PaddingBorderMargin::zero(),
- preferred_block_size: Size::default(),
- min_block_size: Size::default(),
- max_block_size: Size::default(),
+ block_sizes: Sizes::default(),
depends_on_block_constraints: false,
// The available block size may actually be definite, but it should be irrelevant
// since the sizing properties are set to their initial value.
@@ -1648,9 +1590,7 @@ fn solve_containing_block_padding_and_border_for_in_flow_box<'a>(
}
let ContentBoxSizesAndPBM {
- content_box_size,
- content_min_box_size,
- content_max_box_size,
+ content_box_sizes,
pbm,
depends_on_block_constraints,
} = style.content_box_sizes_and_padding_border_margin(&containing_block.into());
@@ -1668,42 +1608,27 @@ fn solve_containing_block_padding_and_border_for_in_flow_box<'a>(
// https://drafts.csswg.org/css2/#the-height-property
// https://drafts.csswg.org/css2/visudet.html#min-max-heights
- let preferred_block_size = content_box_size
- .block
- .maybe_resolve_extrinsic(available_block_size);
- let min_block_size = content_min_box_size
- .block
- .maybe_resolve_extrinsic(available_block_size)
- .unwrap_or_default();
- let max_block_size = content_max_box_size
- .block
- .maybe_resolve_extrinsic(available_block_size);
- let tentative_block_size =
- SizeConstraint::new(preferred_block_size, min_block_size, max_block_size);
+ let tentative_block_size = content_box_sizes.block.resolve_extrinsic(
+ Size::FitContent,
+ Au::zero(),
+ available_block_size,
+ );
// https://drafts.csswg.org/css2/#the-width-property
// https://drafts.csswg.org/css2/visudet.html#min-max-widths
- let inline_content_sizes = LazyCell::new(|| {
+ let get_inline_content_sizes = || {
get_inline_content_sizes(&ConstraintSpace::new(
tentative_block_size,
writing_mode,
None, /* TODO: support preferred aspect ratios on non-replaced boxes */
))
- });
- let preferred_inline_size = content_box_size.inline.resolve(
+ };
+ let inline_size = content_box_sizes.inline.resolve(
Size::Stretch,
+ Au::zero(),
available_inline_size,
- &inline_content_sizes,
+ get_inline_content_sizes,
);
- let min_inline_size = content_min_box_size
- .inline
- .resolve_non_initial(available_inline_size, &inline_content_sizes)
- .unwrap_or_default();
- let max_inline_size = content_max_box_size
- .inline
- .resolve_non_initial(available_inline_size, &inline_content_sizes);
- let inline_size =
- preferred_inline_size.clamp_between_extremums(min_inline_size, max_inline_size);
let containing_block_for_children = ContainingBlock {
size: ContainingBlockSize {
@@ -1724,9 +1649,7 @@ fn solve_containing_block_padding_and_border_for_in_flow_box<'a>(
ContainingBlockPaddingAndBorder {
containing_block: containing_block_for_children,
pbm,
- preferred_block_size: content_box_size.block,
- min_block_size: content_min_box_size.block,
- max_block_size: content_max_box_size.block,
+ block_sizes: content_box_sizes.block,
depends_on_block_constraints,
available_block_size,
}
@@ -2182,23 +2105,12 @@ impl IndependentFormattingContext {
.block
.non_auto()
.map(|block_size| (block_size - pbm_sums.block_sum()).max(Au::zero()));
- let preferred_block_size = content_box_sizes_and_pbm
- .content_box_size
- .block
- .maybe_resolve_extrinsic(available_block_size);
- let min_block_size = content_box_sizes_and_pbm
- .content_min_box_size
+ let tentative_block_size = content_box_sizes_and_pbm
+ .content_box_sizes
.block
- .maybe_resolve_extrinsic(available_block_size)
- .unwrap_or_default();
- let max_block_size = content_box_sizes_and_pbm
- .content_max_box_size
- .block
- .maybe_resolve_extrinsic(available_block_size);
- let tentative_block_size =
- SizeConstraint::new(preferred_block_size, min_block_size, max_block_size);
+ .resolve_extrinsic(Size::FitContent, Au::zero(), available_block_size);
- let content_size = LazyCell::new(|| {
+ let get_content_size = || {
let constraint_space = ConstraintSpace::new(
tentative_block_size,
writing_mode,
@@ -2206,29 +2118,14 @@ impl IndependentFormattingContext {
);
self.inline_content_sizes(layout_context, &constraint_space)
.sizes
- });
+ };
- // https://drafts.csswg.org/css2/visudet.html#float-width
- // https://drafts.csswg.org/css2/visudet.html#inlineblock-width
- let tentative_inline_size = content_box_sizes_and_pbm
- .content_box_size
- .inline
- .resolve(Size::FitContent, available_inline_size, &content_size);
-
- // https://drafts.csswg.org/css2/visudet.html#min-max-widths
- // In this case “applying the rules above again” with a non-auto inline-size
- // always results in that size.
- let min_inline_size = content_box_sizes_and_pbm
- .content_min_box_size
- .inline
- .resolve_non_initial(available_inline_size, &content_size)
- .unwrap_or_default();
- let max_inline_size = content_box_sizes_and_pbm
- .content_max_box_size
- .inline
- .resolve_non_initial(available_inline_size, &content_size);
- let inline_size =
- tentative_inline_size.clamp_between_extremums(min_inline_size, max_inline_size);
+ let inline_size = content_box_sizes_and_pbm.content_box_sizes.inline.resolve(
+ Size::FitContent,
+ Au::zero(),
+ available_inline_size,
+ get_content_size,
+ );
let containing_block_for_children = ContainingBlock {
size: ContainingBlockSize {
@@ -2249,31 +2146,21 @@ impl IndependentFormattingContext {
&containing_block_for_children,
containing_block,
);
- let (inline_size, block_size) =
- match independent_layout.content_inline_size_for_table {
- Some(inline) => (inline, independent_layout.content_block_size),
- None => {
- // https://drafts.csswg.org/css2/visudet.html#block-root-margin
- let stretch_size = available_block_size
- .unwrap_or(independent_layout.content_block_size);
- let content_size =
- LazyCell::new(|| independent_layout.content_block_size.into());
- let min_block_size = content_box_sizes_and_pbm
- .content_min_box_size
- .block
- .resolve_non_initial(stretch_size, &content_size)
- .unwrap_or_default();
- let max_block_size = content_box_sizes_and_pbm
- .content_max_box_size
- .block
- .resolve_non_initial(stretch_size, &content_size);
- let block_size = tentative_block_size
- .to_definite()
- .unwrap_or(independent_layout.content_block_size)
- .clamp_between_extremums(min_block_size, max_block_size);
- (inline_size, block_size)
- },
- };
+ let (inline_size, block_size) = match independent_layout
+ .content_inline_size_for_table
+ {
+ Some(inline) => (inline, independent_layout.content_block_size),
+ None => {
+ // https://drafts.csswg.org/css2/visudet.html#block-root-margin
+ let block_size = content_box_sizes_and_pbm.content_box_sizes.block.resolve(
+ Size::FitContent,
+ Au::zero(),
+ available_block_size.unwrap_or(independent_layout.content_block_size),
+ || independent_layout.content_block_size.into(),
+ );
+ (inline_size, block_size)
+ },
+ };
let content_size = LogicalVec2 {
block: block_size,
diff --git a/components/layout_2020/geom.rs b/components/layout_2020/geom.rs
index 1684e0304a3..4df12676c50 100644
--- a/components/layout_2020/geom.rs
+++ b/components/layout_2020/geom.rs
@@ -870,3 +870,122 @@ impl SizeConstraint {
.map_or(AutoOr::Auto, AutoOr::LengthPercentage)
}
}
+
+#[derive(Clone, Default)]
+pub(crate) struct Sizes {
+ /// <https://drafts.csswg.org/css-sizing-3/#preferred-size-properties>
+ pub preferred: Size<Au>,
+ /// <https://drafts.csswg.org/css-sizing-3/#min-size-properties>
+ pub min: Size<Au>,
+ /// <https://drafts.csswg.org/css-sizing-3/#max-size-properties>
+ pub max: Size<Au>,
+}
+
+impl Sizes {
+ #[inline]
+ pub(crate) fn new(preferred: Size<Au>, min: Size<Au>, max: Size<Au>) -> Self {
+ Self {
+ preferred,
+ min,
+ max,
+ }
+ }
+
+ #[inline]
+ pub(crate) fn depends_on_available_space(&self) -> bool {
+ // TODO: this logic could be refined further, since even if some of the 3 sizes
+ // depends on the available space, the resulting size might not. For example,
+ // `min-width: 200px; width: 100px; max-width: stretch`.
+ matches!(
+ self.preferred,
+ Size::Initial | Size::Stretch | Size::FitContent
+ ) || matches!(self.min, Size::Stretch | Size::FitContent) ||
+ matches!(self.max, Size::Stretch | Size::FitContent)
+ }
+
+ /// Resolves the three sizes into a single numerical value.
+ #[inline]
+ pub(crate) fn resolve(
+ &self,
+ automatic_size: Size<Au>,
+ automatic_minimum_size: Au,
+ stretch_size: Au,
+ get_content_size: impl FnOnce() -> ContentSizes,
+ ) -> Au {
+ let (preferred, min, max) = self.resolve_each(
+ automatic_size,
+ automatic_minimum_size,
+ stretch_size,
+ get_content_size,
+ );
+ preferred.clamp_between_extremums(min, max)
+ }
+
+ /// Resolves each of the three sizes into a numerical value, separately.
+ #[inline]
+ pub(crate) fn resolve_each(
+ &self,
+ automatic_size: Size<Au>,
+ automatic_minimum_size: Au,
+ stretch_size: Au,
+ get_content_size: impl FnOnce() -> ContentSizes,
+ ) -> (Au, Au, Option<Au>) {
+ // The provided `get_content_size` is a FnOnce but we may need its result multiple times.
+ // A LazyCell will only invoke it once if needed, and then reuse the result.
+ let content_size = LazyCell::new(get_content_size);
+ (
+ self.preferred
+ .resolve(automatic_size, stretch_size, &content_size),
+ self.min
+ .resolve_non_initial(stretch_size, &content_size)
+ .unwrap_or(automatic_minimum_size),
+ self.max.resolve_non_initial(stretch_size, &content_size),
+ )
+ }
+
+ /// Tries to extrinsically resolve the three sizes into a single [`SizeConstraint`].
+ /// Values that are intrinsic or need `stretch_size` when it's `None` are handled as such:
+ /// - On the preferred size, they make the returned value be an indefinite [`SizeConstraint::MinMax`].
+ /// - On the min size, they are treated as `auto`, enforcing the automatic minimum size.
+ /// - On the max size, they are treated as `none`, enforcing no maximum.
+ #[inline]
+ pub(crate) fn resolve_extrinsic(
+ &self,
+ automatic_size: Size<Au>,
+ automatic_minimum_size: Au,
+ stretch_size: Option<Au>,
+ ) -> SizeConstraint {
+ let (preferred, min, max) =
+ self.resolve_each_extrinsic(automatic_size, automatic_minimum_size, stretch_size);
+ SizeConstraint::new(preferred, min, max)
+ }
+
+ /// Tries to extrinsically resolve each of the three sizes into a numerical value, separately.
+ /// This can't resolve values that are intrinsic or need `stretch_size` but it's `None`.
+ /// - The 1st returned value is the resolved preferred size. If it can't be resolved then
+ /// the returned value is `None`. Note that this is different than treating it as `auto`.
+ /// TODO: This needs to be discussed in <https://github.com/w3c/csswg-drafts/issues/11387>.
+ /// - The 2nd returned value is the resolved minimum size. If it can't be resolved then we
+ /// treat it as the initial `auto`, returning the automatic minimum size.
+ /// - The 3rd returned value is the resolved maximum size. If it can't be resolved then we
+ /// treat it as the initial `none`, returning `None`.
+ #[inline]
+ pub(crate) fn resolve_each_extrinsic(
+ &self,
+ automatic_size: Size<Au>,
+ automatic_minimum_size: Au,
+ stretch_size: Option<Au>,
+ ) -> (Option<Au>, Au, Option<Au>) {
+ (
+ if self.preferred.is_initial() {
+ automatic_size.maybe_resolve_extrinsic(stretch_size)
+ } else {
+ self.preferred.maybe_resolve_extrinsic(stretch_size)
+ },
+ self.min
+ .maybe_resolve_extrinsic(stretch_size)
+ .unwrap_or(automatic_minimum_size),
+ self.max.maybe_resolve_extrinsic(stretch_size),
+ )
+ }
+}
diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs
index 9841f9b6c86..0b1ba1e02e6 100644
--- a/components/layout_2020/positioned.rs
+++ b/components/layout_2020/positioned.rs
@@ -2,7 +2,6 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
-use std::cell::LazyCell;
use std::mem;
use app_units::Au;
@@ -28,10 +27,10 @@ use crate::fragment_tree::{
};
use crate::geom::{
AuOrAuto, LengthPercentageOrAuto, LogicalRect, LogicalSides, LogicalVec2, PhysicalPoint,
- PhysicalRect, PhysicalVec, Size, ToLogical, ToLogicalWithContainingBlock,
+ PhysicalRect, PhysicalVec, Size, Sizes, ToLogical, ToLogicalWithContainingBlock,
};
use crate::sizing::ContentSizes;
-use crate::style_ext::{ComputedValuesExt, DisplayInside};
+use crate::style_ext::{ComputedValuesExt, ContentBoxSizesAndPBM, DisplayInside};
use crate::{
ConstraintSpace, ContainingBlock, ContainingBlockSize, DefiniteContainingBlock, SizeConstraint,
};
@@ -460,11 +459,12 @@ impl HoistedAbsolutelyPositionedBox {
let absolutely_positioned_box = self.absolutely_positioned_box.borrow();
let context = &absolutely_positioned_box.context;
let style = context.style().clone();
+ let ContentBoxSizesAndPBM {
+ content_box_sizes,
+ pbm,
+ ..
+ } = style.content_box_sizes_and_padding_border_margin(&containing_block.into());
let containing_block = &containing_block.into();
- let pbm = style.padding_border_margin(containing_block);
- let computed_size = style.content_box_size(containing_block, &pbm);
- let computed_min_size = style.content_min_box_size(containing_block, &pbm);
- let computed_max_size = style.content_max_box_size(containing_block, &pbm);
let shared_fragment = self.fragment.borrow();
let static_position_rect = shared_fragment
@@ -489,9 +489,7 @@ impl HoistedAbsolutelyPositionedBox {
padding_border_sum: pbm.padding_border_sums.inline,
computed_margin_start: pbm.margin.inline_start,
computed_margin_end: pbm.margin.inline_end,
- computed_size: computed_size.inline,
- computed_min_size: computed_min_size.inline,
- computed_max_size: computed_max_size.inline,
+ computed_sizes: content_box_sizes.inline,
avoid_negative_margin_start: true,
box_offsets: inline_box_offsets,
static_position_rect_axis: static_position_rect.get_axis(AxisDirection::Inline),
@@ -515,9 +513,7 @@ impl HoistedAbsolutelyPositionedBox {
padding_border_sum: pbm.padding_border_sums.block,
computed_margin_start: pbm.margin.block_start,
computed_margin_end: pbm.margin.block_end,
- computed_size: computed_size.block,
- computed_min_size: computed_min_size.block,
- computed_max_size: computed_max_size.block,
+ computed_sizes: content_box_sizes.block,
avoid_negative_margin_start: false,
box_offsets: block_box_offsets,
static_position_rect_axis: static_position_rect.get_axis(AxisDirection::Block),
@@ -536,9 +532,8 @@ impl HoistedAbsolutelyPositionedBox {
containing_block,
&style,
context.preferred_aspect_ratio(&pbm.padding_border_sums),
- computed_size,
- computed_min_size,
- computed_max_size,
+ &block_axis_solver.computed_sizes,
+ &inline_axis_solver.computed_sizes,
pbm.padding_border_sums + pbm.margin.auto_is(Au::zero).sum() + inset_sums,
);
inline_axis_solver.override_size(used_size.inline);
@@ -746,9 +741,7 @@ struct AbsoluteAxisSolver<'a> {
padding_border_sum: Au,
computed_margin_start: AuOrAuto,
computed_margin_end: AuOrAuto,
- computed_size: Size<Au>,
- computed_min_size: Size<Au>,
- computed_max_size: Size<Au>,
+ computed_sizes: Sizes,
avoid_negative_margin_start: bool,
box_offsets: AbsoluteBoxOffsets<'a>,
static_position_rect_axis: RectAxis,
@@ -795,40 +788,21 @@ impl<'a> AbsoluteAxisSolver<'a> {
///
/// In the replaced case, `size` is never `Auto`.
fn solve(&self, get_content_size: Option<impl FnOnce() -> ContentSizes>) -> AxisResult {
- // The provided `get_content_size` is a FnOnce but we may need its result multiple times.
- // A LazyCell will only invoke it once if needed, and then reuse the result.
- let content_size = get_content_size.map(LazyCell::new);
let solve_size = |initial_behavior, stretch_size: Au| -> SizeConstraint {
let stretch_size = stretch_size.max(Au::zero());
- if let Some(ref content_size) = content_size {
- let preferred_size = Some(self.computed_size.resolve(
+ if let Some(get_content_size) = get_content_size {
+ SizeConstraint::Definite(self.computed_sizes.resolve(
initial_behavior,
+ Au::zero(),
stretch_size,
- content_size,
- ));
- let min_size = self
- .computed_min_size
- .resolve_non_initial(stretch_size, content_size)
- .unwrap_or_default();
- let max_size = self
- .computed_max_size
- .resolve_non_initial(stretch_size, content_size);
- SizeConstraint::new(preferred_size, min_size, max_size)
+ get_content_size,
+ ))
} else {
- let preferred_size = if self.computed_size.is_initial() {
- initial_behavior
- } else {
- self.computed_size
- }
- .maybe_resolve_extrinsic(Some(stretch_size));
- let min_size = self
- .computed_min_size
- .maybe_resolve_extrinsic(Some(stretch_size))
- .unwrap_or_default();
- let max_size = self
- .computed_max_size
- .maybe_resolve_extrinsic(Some(stretch_size));
- SizeConstraint::new(preferred_size, min_size, max_size)
+ self.computed_sizes.resolve_extrinsic(
+ initial_behavior,
+ Au::zero(),
+ Some(stretch_size),
+ )
}
};
if self.box_offsets.either_auto() {
@@ -891,9 +865,9 @@ impl<'a> AbsoluteAxisSolver<'a> {
}
fn override_size(&mut self, size: Au) {
- self.computed_size = Size::Numeric(size);
- self.computed_min_size = Size::default();
- self.computed_max_size = Size::default();
+ self.computed_sizes.preferred = Size::Numeric(size);
+ self.computed_sizes.min = Size::default();
+ self.computed_sizes.max = Size::default();
}
fn origin_for_margin_box(
diff --git a/components/layout_2020/replaced.rs b/components/layout_2020/replaced.rs
index 86345e0b8f5..df845841438 100644
--- a/components/layout_2020/replaced.rs
+++ b/components/layout_2020/replaced.rs
@@ -30,7 +30,7 @@ use webrender_api::ImageKey;
use crate::context::LayoutContext;
use crate::dom::NodeExt;
use crate::fragment_tree::{BaseFragmentInfo, Fragment, IFrameFragment, ImageFragment};
-use crate::geom::{LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSize, Size};
+use crate::geom::{LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSize, Size, Sizes};
use crate::sizing::{ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult};
use crate::style_ext::{AspectRatio, Clamp, ComputedValuesExt, ContentBoxSizesAndPBM};
use crate::{ConstraintSpace, ContainingBlock, SizeConstraint};
@@ -439,9 +439,8 @@ impl ReplacedContents {
containing_block,
style,
self.preferred_aspect_ratio(style, &pbm.padding_border_sums),
- content_box_sizes_and_pbm.content_box_size,
- content_box_sizes_and_pbm.content_min_box_size,
- content_box_sizes_and_pbm.content_max_box_size,
+ &content_box_sizes_and_pbm.content_box_sizes.block,
+ &content_box_sizes_and_pbm.content_box_sizes.inline,
pbm.padding_border_sums + pbm.margin.auto_is(Au::zero).sum(),
)
}
@@ -481,15 +480,13 @@ impl ReplacedContents {
///
/// <https://drafts.csswg.org/css-sizing-4/#aspect-ratio-size-transfers>
/// <https://github.com/w3c/csswg-drafts/issues/6071#issuecomment-2243986313>
- #[allow(clippy::too_many_arguments)]
pub(crate) fn used_size_as_if_inline_element_from_content_box_sizes(
&self,
containing_block: &ContainingBlock,
style: &ComputedValues,
preferred_aspect_ratio: Option<AspectRatio>,
- box_size: LogicalVec2<Size<Au>>,
- min_box_size: LogicalVec2<Size<Au>>,
- max_box_size: LogicalVec2<Size<Au>>,
+ block_sizes: &Sizes,
+ inline_sizes: &Sizes,
pbm_sums: LogicalVec2<Au>,
) -> LogicalVec2<Au> {
// <https://drafts.csswg.org/css-images-3/#natural-dimensions>
@@ -520,19 +517,9 @@ impl ReplacedContents {
// First, compute the inline size. Intrinsic values depend on the block sizing properties
// through the aspect ratio, but these can also be intrinsic and depend on the inline size.
// Therefore, we tentatively treat intrinsic block sizing properties as their initial value.
- let inline_content_size = LazyCell::new(|| {
- let get_block_size = || {
- SizeConstraint::new(
- box_size.block.maybe_resolve_extrinsic(block_stretch_size),
- min_box_size
- .block
- .maybe_resolve_extrinsic(block_stretch_size)
- .unwrap_or_default(),
- max_box_size
- .block
- .maybe_resolve_extrinsic(block_stretch_size),
- )
- };
+ let get_inline_content_size = || {
+ let get_block_size =
+ || block_sizes.resolve_extrinsic(Size::FitContent, Au::zero(), block_stretch_size);
self.content_size(
Direction::Inline,
preferred_aspect_ratio,
@@ -540,24 +527,19 @@ impl ReplacedContents {
&get_inline_fallback_size,
)
.into()
- });
- let preferred_inline =
- box_size
- .inline
- .resolve(Size::FitContent, inline_stretch_size, &inline_content_size);
- let min_inline = min_box_size
- .inline
- .resolve_non_initial(inline_stretch_size, &inline_content_size)
- .unwrap_or_default();
- let max_inline = max_box_size
- .inline
- .resolve_non_initial(inline_stretch_size, &inline_content_size);
+ };
+ let (preferred_inline, min_inline, max_inline) = inline_sizes.resolve_each(
+ Size::FitContent,
+ Au::zero(),
+ inline_stretch_size,
+ get_inline_content_size,
+ );
let inline_size = preferred_inline.clamp_between_extremums(min_inline, max_inline);
// Now we can compute the block size, using the inline size from above.
let block_content_size = LazyCell::new(|| -> ContentSizes {
let get_inline_size = || {
- if box_size.inline.is_initial() {
+ if inline_sizes.preferred.is_initial() {
// TODO: do we really need to special-case `auto`?
// https://github.com/w3c/csswg-drafts/issues/11236
SizeConstraint::MinMax(min_inline, max_inline)
@@ -573,20 +555,12 @@ impl ReplacedContents {
)
.into()
});
- let block_stretch_size =
- block_stretch_size.unwrap_or_else(|| block_content_size.max_content);
- let preferred_block =
- box_size
- .block
- .resolve(Size::FitContent, block_stretch_size, &block_content_size);
- let min_block = min_box_size
- .block
- .resolve_non_initial(block_stretch_size, &block_content_size)
- .unwrap_or_default();
- let max_block = max_box_size
- .block
- .resolve_non_initial(block_stretch_size, &block_content_size);
- let block_size = preferred_block.clamp_between_extremums(min_block, max_block);
+ let block_size = block_sizes.resolve(
+ Size::FitContent,
+ Au::zero(),
+ block_stretch_size.unwrap_or_else(|| block_content_size.max_content),
+ || *block_content_size,
+ );
LogicalVec2 {
inline: inline_size,
diff --git a/components/layout_2020/sizing.rs b/components/layout_2020/sizing.rs
index 7715e5627da..1e8fe74d6e6 100644
--- a/components/layout_2020/sizing.rs
+++ b/components/layout_2020/sizing.rs
@@ -15,7 +15,7 @@ use style::Zero;
use crate::context::LayoutContext;
use crate::geom::Size;
use crate::style_ext::{AspectRatio, Clamp, ComputedValuesExt, ContentBoxSizesAndPBM};
-use crate::{ConstraintSpace, IndefiniteContainingBlock, LogicalVec2, SizeConstraint};
+use crate::{ConstraintSpace, IndefiniteContainingBlock, LogicalVec2};
#[derive(PartialEq)]
pub(crate) enum IntrinsicSizingMode {
@@ -118,9 +118,7 @@ pub(crate) fn outer_inline(
get_content_size: impl FnOnce(&ConstraintSpace) -> InlineContentSizesResult,
) -> InlineContentSizesResult {
let ContentBoxSizesAndPBM {
- content_box_size,
- content_min_box_size,
- content_max_box_size,
+ content_box_sizes,
pbm,
mut depends_on_block_constraints,
} = style.content_box_sizes_and_padding_border_margin(containing_block);
@@ -135,25 +133,20 @@ pub(crate) fn outer_inline(
.block
.non_auto()
.map(|v| Au::zero().max(v - pbm_sums.block));
- let preferred_block_size = if content_box_size.block.is_initial() &&
+ let automatic_size = if content_box_sizes.block.preferred.is_initial() &&
auto_block_size_stretches_to_containing_block
{
depends_on_block_constraints = true;
- available_block_size
+ Size::Stretch
} else {
- content_box_size
- .block
- .maybe_resolve_extrinsic(available_block_size)
+ Size::FitContent
};
- let min_block_size = content_min_box_size
- .block
- .maybe_resolve_extrinsic(available_block_size)
- .unwrap_or(auto_minimum.block);
- let max_block_size = content_max_box_size
- .block
- .maybe_resolve_extrinsic(available_block_size);
get_content_size(&ConstraintSpace::new(
- SizeConstraint::new(preferred_block_size, min_block_size, max_block_size),
+ content_box_sizes.block.resolve_extrinsic(
+ automatic_size,
+ auto_minimum.block,
+ available_block_size,
+ ),
style.writing_mode,
get_preferred_aspect_ratio(&pbm.padding_border_sums),
))
@@ -180,14 +173,14 @@ pub(crate) fn outer_inline(
})
};
let (preferred_min_content, preferred_max_content, preferred_depends_on_block_constraints) =
- resolve_non_initial(content_box_size.inline)
+ resolve_non_initial(content_box_sizes.inline.preferred)
.unwrap_or_else(|| resolve_non_initial(Size::FitContent).unwrap());
let (min_min_content, min_max_content, min_depends_on_block_constraints) = resolve_non_initial(
- content_min_box_size.inline,
+ content_box_sizes.inline.min,
)
.unwrap_or((auto_minimum.inline, auto_minimum.inline, false));
let (max_min_content, max_max_content, max_depends_on_block_constraints) =
- resolve_non_initial(content_max_box_size.inline)
+ resolve_non_initial(content_box_sizes.inline.max)
.map(|(min_content, max_content, depends_on_block_constraints)| {
(
Some(min_content),
diff --git a/components/layout_2020/style_ext.rs b/components/layout_2020/style_ext.rs
index 34f95bef7cf..e6733ac998e 100644
--- a/components/layout_2020/style_ext.rs
+++ b/components/layout_2020/style_ext.rs
@@ -29,7 +29,7 @@ use crate::dom_traversal::Contents;
use crate::fragment_tree::FragmentFlags;
use crate::geom::{
AuOrAuto, LengthPercentageOrAuto, LogicalSides, LogicalVec2, PhysicalSides, PhysicalSize,
- PhysicalVec, Size,
+ PhysicalVec, Size, Sizes,
};
use crate::{ContainingBlock, IndefiniteContainingBlock};
@@ -189,9 +189,7 @@ impl AspectRatio {
#[derive(Clone)]
pub(crate) struct ContentBoxSizesAndPBM {
- pub content_box_size: LogicalVec2<Size<Au>>,
- pub content_min_box_size: LogicalVec2<Size<Au>>,
- pub content_max_box_size: LogicalVec2<Size<Au>>,
+ pub content_box_sizes: LogicalVec2<Sizes>,
pub pbm: PaddingBorderMargin,
pub depends_on_block_constraints: bool,
}
@@ -199,9 +197,11 @@ pub(crate) struct ContentBoxSizesAndPBM {
impl From<ContentBoxSizesAndPBM> for ContentBoxSizesAndPBMDeprecated {
fn from(sizes: ContentBoxSizesAndPBM) -> Self {
Self {
- content_box_size: sizes.content_box_size.map(Size::to_auto_or),
- content_min_box_size: sizes.content_min_box_size.map(Size::to_auto_or),
- content_max_box_size: sizes.content_max_box_size.map(Size::to_numeric),
+ content_box_size: sizes
+ .content_box_sizes
+ .map(|size| size.preferred.to_auto_or()),
+ content_min_box_size: sizes.content_box_sizes.map(|size| size.min.to_auto_or()),
+ content_max_box_size: sizes.content_box_sizes.map(|size| size.max.to_numeric()),
pbm: sizes.pbm.clone(),
depends_on_block_constraints: sizes.depends_on_block_constraints,
}
@@ -560,9 +560,18 @@ impl ComputedValuesExt for ComputedValues {
.content_max_box_size_for_max_size(max_size, &pbm)
.map(|v| v.map(Au::from));
ContentBoxSizesAndPBM {
- content_box_size,
- content_min_box_size,
- content_max_box_size,
+ content_box_sizes: LogicalVec2 {
+ block: Sizes::new(
+ content_box_size.block,
+ content_min_box_size.block,
+ content_max_box_size.block,
+ ),
+ inline: Sizes::new(
+ content_box_size.inline,
+ content_min_box_size.inline,
+ content_max_box_size.inline,
+ ),
+ },
pbm,
depends_on_block_constraints,
}
diff --git a/components/layout_2020/taffy/layout.rs b/components/layout_2020/taffy/layout.rs
index 4ed13aa008b..3cdf162899e 100644
--- a/components/layout_2020/taffy/layout.rs
+++ b/components/layout_2020/taffy/layout.rs
@@ -22,7 +22,7 @@ use crate::formatting_contexts::{
use crate::fragment_tree::{BoxFragment, CollapsedBlockMargins, Fragment};
use crate::geom::{
LogicalSides, LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSides, PhysicalSize, Size,
- SizeConstraint,
+ SizeConstraint, Sizes,
};
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext, PositioningContextLength};
use crate::sizing::{ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult};
@@ -155,18 +155,16 @@ impl taffy::LayoutPartialTree for TaffyContainerContext<'_> {
style,
independent_context
.preferred_aspect_ratio(&pbm.padding_border_sums),
- LogicalVec2 {
- inline: option_f32_to_size(content_box_known_dimensions.width),
- block: option_f32_to_size(content_box_known_dimensions.height),
- },
- LogicalVec2 {
- inline: Size::Numeric(Au::zero()),
- block: Size::Numeric(Au::zero()),
- },
- LogicalVec2 {
- inline: Size::Initial,
- block: Size::Initial,
- },
+ &Sizes::new(
+ option_f32_to_size(content_box_known_dimensions.height),
+ Size::Initial,
+ Size::Initial,
+ ),
+ &Sizes::new(
+ option_f32_to_size(content_box_known_dimensions.width),
+ Size::Initial,
+ Size::Initial,
+ ),
pbm.padding_border_sums + pbm.margin.auto_is(Au::zero).sum(),
)
.to_physical_size(self.style.writing_mode);