diff --git a/components/layout_2020/flexbox/construct.rs b/components/layout_2020/flexbox/construct.rs index 876dbfe052b..8d9dfbf75ce 100644 --- a/components/layout_2020/flexbox/construct.rs +++ b/components/layout_2020/flexbox/construct.rs @@ -171,7 +171,7 @@ where let non_replaced = NonReplacedFormattingContext { base_fragment_info: info.into(), style: info.style.clone(), - content_sizes: None, + content_sizes_result: None, contents: NonReplacedFormattingContextContents::Flow( block_formatting_context, ), diff --git a/components/layout_2020/flexbox/layout.rs b/components/layout_2020/flexbox/layout.rs index 866c7e4a879..4338e6e93e1 100644 --- a/components/layout_2020/flexbox/layout.rs +++ b/components/layout_2020/flexbox/layout.rs @@ -31,7 +31,7 @@ use crate::geom::{AuOrAuto, LogicalRect, LogicalSides, LogicalVec2}; use crate::positioned::{ relative_adjustement, AbsolutelyPositionedBox, PositioningContext, PositioningContextLength, }; -use crate::sizing::{ContentSizes, IntrinsicSizingMode}; +use crate::sizing::{ContentSizes, InlineContentSizesResult, IntrinsicSizingMode}; use crate::style_ext::{Clamp, ComputedValuesExt, PaddingBorderMargin}; use crate::{ContainingBlock, IndefiniteContainingBlock}; @@ -336,6 +336,7 @@ struct FlexItemBoxInlineContentSizesInfo { min_flex_factors: DesiredFlexFractionAndGrowOrShrinkFactor, max_flex_factors: DesiredFlexFractionAndGrowOrShrinkFactor, min_content_main_size_for_multiline_container: Au, + depends_on_block_constraints: bool, } impl FlexContainer { @@ -348,7 +349,7 @@ impl FlexContainer { &mut self, layout_context: &LayoutContext, containing_block_for_children: &IndefiniteContainingBlock, - ) -> ContentSizes { + ) -> InlineContentSizesResult { match self.config.flex_axis { FlexAxis::Row => { self.main_content_sizes(layout_context, containing_block_for_children, || { @@ -367,14 +368,15 @@ impl FlexContainer { &mut self, layout_context: &LayoutContext, containing_block_for_children: &IndefiniteContainingBlock, - ) -> ContentSizes { + ) -> InlineContentSizesResult { // assert_eq!( self.config.flex_axis, FlexAxis::Column, "The cross axis should be the inline one" ); - let mut content_sizes = ContentSizes::zero(); + let mut sizes = ContentSizes::zero(); + let mut depends_on_block_constraints = false; for kid in self.children.iter() { let kid = &mut *kid.borrow_mut(); match kid { @@ -383,17 +385,22 @@ impl FlexContainer { // columns, and sum the column sizes and gaps. // TODO: Use the proper automatic minimum size. let ifc = &mut item.independent_formatting_context; - content_sizes.max_assign(ifc.outer_inline_content_sizes( + let result = ifc.outer_inline_content_sizes( layout_context, containing_block_for_children, &LogicalVec2::zero(), false, /* auto_block_size_stretches_to_containing_block */ - )); + ); + sizes.max_assign(result.sizes); + depends_on_block_constraints |= result.depends_on_block_constraints; }, FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(_) => {}, } } - content_sizes + InlineContentSizesResult { + sizes, + depends_on_block_constraints, + } } fn main_content_sizes<'a>( @@ -401,7 +408,7 @@ impl FlexContainer { layout_context: &LayoutContext, containing_block_for_children: &IndefiniteContainingBlock, flex_context_getter: impl Fn() -> &'a FlexContext<'a>, - ) -> ContentSizes { + ) -> InlineContentSizesResult { // - TODO: calculate intrinsic cross sizes when container is a column // (and check for ‘writing-mode’?) // - TODO: Collapsed flex items need to be skipped for intrinsic size calculation. @@ -483,6 +490,7 @@ impl FlexContainer { } else { Au::zero() }; + let mut container_depends_on_block_constraints = false; for FlexItemBoxInlineContentSizesInfo { outer_flex_base_size, @@ -492,6 +500,7 @@ impl FlexContainer { min_flex_factors, max_flex_factors, min_content_main_size_for_multiline_container, + depends_on_block_constraints, } in item_infos.iter() { // > 4. Add each item’s flex base size to the product of its flex grow factor (scaled flex shrink @@ -528,11 +537,16 @@ impl FlexContainer { container_min_content_size .max_assign(*min_content_main_size_for_multiline_container); } + + container_depends_on_block_constraints |= depends_on_block_constraints; } - ContentSizes { - min_content: container_min_content_size, - max_content: container_max_content_size, + InlineContentSizesResult { + sizes: ContentSizes { + min_content: container_min_content_size, + max_content: container_max_content_size, + }, + depends_on_block_constraints: container_depends_on_block_constraints, } } @@ -573,6 +587,7 @@ impl FlexContainer { FlexAxis::Row => containing_block.inline_size, FlexAxis::Column => containing_block.block_size.auto_is(|| { self.main_content_sizes(layout_context, &containing_block.into(), || &flex_context) + .sizes .max_content }), }; @@ -1023,7 +1038,7 @@ impl<'a> FlexItem<'a> { flex_context.config.flex_axis, ); - let (content_box_size, min_size, max_size, pbm) = box_ + let (content_box_size, min_size, max_size, pbm, _) = box_ .style() .content_box_sizes_and_padding_border_margin_deprecated(&containing_block.into()); @@ -1735,6 +1750,7 @@ impl FlexItem<'_> { &containing_block_for_children, &containing_block.into(), ) + .sizes .map(|size| { size.clamp_between_extremums( self.content_min_size.cross, @@ -2008,7 +2024,7 @@ impl FlexItemBox { let cross_axis_is_item_block_axis = cross_axis_is_item_block_axis(container_is_horizontal, item_is_horizontal, flex_axis); - let (content_box_size, content_min_size, content_max_size, pbm) = + let (content_box_size, content_min_size, content_max_size, pbm, _) = style.content_box_sizes_and_padding_border_margin_deprecated(containing_block); let padding = main_start_cross_start.sides_to_flex_relative(pbm.padding); let border = main_start_cross_start.sides_to_flex_relative(pbm.border); @@ -2069,17 +2085,23 @@ impl FlexItemBox { // Compute the min-content and max-content contributions of the item. // - let content_contribution_sizes = match flex_axis { - FlexAxis::Row => self - .independent_formatting_context - .outer_inline_content_sizes( - layout_context, - containing_block, - &content_min_size_no_auto, - item_with_auto_cross_size_stretches_to_container_size, - ), - FlexAxis::Column => self - .layout_for_block_content_size( + let (content_contribution_sizes, depends_on_block_constraints) = match flex_axis { + FlexAxis::Row => { + let InlineContentSizesResult { + sizes, + depends_on_block_constraints, + } = self + .independent_formatting_context + .outer_inline_content_sizes( + layout_context, + containing_block, + &content_min_size_no_auto, + item_with_auto_cross_size_stretches_to_container_size, + ); + (sizes, depends_on_block_constraints) + }, + FlexAxis::Column => { + let size = self.layout_for_block_content_size( flex_context_getter(), &pbm, content_box_size, @@ -2087,8 +2109,9 @@ impl FlexItemBox { content_max_size, item_with_auto_cross_size_stretches_to_container_size, IntrinsicSizingMode::Contribution, - ) - .into(), + ); + (size.into(), true) + }, }; let content_box_size = flex_axis.vec2_to_flex_relative(content_box_size); @@ -2155,6 +2178,7 @@ impl FlexItemBox { min_flex_factors, max_flex_factors, min_content_main_size_for_multiline_container, + depends_on_block_constraints, } } @@ -2282,6 +2306,7 @@ impl FlexItemBox { &containing_block_for_children, containing_block, ) + .sizes .min_content } else { block_content_size_callback(self) @@ -2444,6 +2469,7 @@ impl FlexItemBox { &containing_block_for_children, containing_block, ) + .sizes .max_content; if let Some(ratio) = ratio { max_content.clamp_between_extremums( @@ -2522,11 +2548,12 @@ impl FlexItemBox { let style = non_replaced.style.clone(); let containing_block_for_children = IndefiniteContainingBlock::new_for_style(&style); - let inline_content_sizes = non_replaced.inline_content_sizes( - flex_context.layout_context, - &containing_block_for_children, - ); - inline_content_sizes + non_replaced + .inline_content_sizes( + flex_context.layout_context, + &containing_block_for_children, + ) + .sizes .shrink_to_fit(containing_block_inline_size_minus_pbm) } }) diff --git a/components/layout_2020/flow/inline/mod.rs b/components/layout_2020/flow/inline/mod.rs index 1d5627e1d6c..21be242f35b 100644 --- a/components/layout_2020/flow/inline/mod.rs +++ b/components/layout_2020/flow/inline/mod.rs @@ -126,7 +126,7 @@ use crate::fragment_tree::{ }; use crate::geom::{LogicalRect, LogicalVec2, ToLogical}; use crate::positioned::{AbsolutelyPositionedBox, PositioningContext}; -use crate::sizing::ContentSizes; +use crate::sizing::{ContentSizes, InlineContentSizesResult}; use crate::style_ext::{ComputedValuesExt, PaddingBorderMargin}; use crate::{ContainingBlock, IndefiniteContainingBlock}; @@ -1565,7 +1565,7 @@ impl InlineFormattingContext { &self, layout_context: &LayoutContext, containing_block_for_children: &IndefiniteContainingBlock, - ) -> ContentSizes { + ) -> InlineContentSizesResult { ContentSizesComputation::compute(self, layout_context, containing_block_for_children) } @@ -2184,16 +2184,23 @@ struct ContentSizesComputation<'layout_data> { /// Stack of ending padding, margin, and border to add to the length /// when an inline box finishes. ending_inline_pbm_stack: Vec, + depends_on_block_constraints: bool, } impl<'layout_data> ContentSizesComputation<'layout_data> { - fn traverse(mut self, inline_formatting_context: &InlineFormattingContext) -> ContentSizes { + fn traverse( + mut self, + inline_formatting_context: &InlineFormattingContext, + ) -> InlineContentSizesResult { for inline_item in inline_formatting_context.inline_items.iter() { self.process_item(&mut inline_item.borrow_mut(), inline_formatting_context); } self.forced_line_break(); - self.paragraph + InlineContentSizesResult { + sizes: self.paragraph, + depends_on_block_constraints: self.depends_on_block_constraints, + } } fn process_item( @@ -2299,12 +2306,16 @@ impl<'layout_data> ContentSizesComputation<'layout_data> { self.line_break_opportunity(); } - let outer = atomic.outer_inline_content_sizes( + let InlineContentSizesResult { + sizes: outer, + depends_on_block_constraints, + } = atomic.outer_inline_content_sizes( self.layout_context, self.containing_block, &LogicalVec2::zero(), false, /* auto_block_size_stretches_to_containing_block */ ); + self.depends_on_block_constraints |= depends_on_block_constraints; if !inline_formatting_context .next_character_prevents_soft_wrap_opportunity(*offset_in_text) @@ -2356,7 +2367,7 @@ impl<'layout_data> ContentSizesComputation<'layout_data> { inline_formatting_context: &InlineFormattingContext, layout_context: &'layout_data LayoutContext, containing_block: &'layout_data IndefiniteContainingBlock, - ) -> ContentSizes { + ) -> InlineContentSizesResult { Self { layout_context, containing_block, @@ -2366,6 +2377,7 @@ impl<'layout_data> ContentSizesComputation<'layout_data> { had_content_yet_for_min_content: false, had_content_yet_for_max_content: false, ending_inline_pbm_stack: Vec::new(), + depends_on_block_constraints: false, } .traverse(inline_formatting_context) } diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index 5e9693b63fd..445972e64ab 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -37,7 +37,7 @@ use crate::geom::{ }; use crate::positioned::{AbsolutelyPositionedBox, PositioningContext, PositioningContextLength}; use crate::replaced::ReplacedContent; -use crate::sizing::{self, ContentSizes}; +use crate::sizing::{self, ContentSizes, InlineContentSizesResult}; use crate::style_ext::{Clamp, ComputedValuesExt, PaddingBorderMargin}; use crate::{ContainingBlock, IndefiniteContainingBlock}; @@ -234,7 +234,7 @@ impl OutsideMarker { &IndefiniteContainingBlock::new_for_style(&self.marker_style), ); let containing_block_for_children = ContainingBlock { - inline_size: content_sizes.max_content, + inline_size: content_sizes.sizes.max_content, block_size: AuOrAuto::auto(), style: &self.marker_style, }; @@ -361,28 +361,29 @@ fn calculate_inline_content_size_for_block_level_boxes( boxes: &[ArcRefCell], layout_context: &LayoutContext, containing_block: &IndefiniteContainingBlock, -) -> ContentSizes { +) -> InlineContentSizesResult { let get_box_info = |box_: &ArcRefCell| { match &mut *box_.borrow_mut() { BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(_) | BlockLevelBox::OutsideMarker { .. } => None, BlockLevelBox::OutOfFlowFloatBox(ref mut float_box) => { - let size = float_box - .contents - .outer_inline_content_sizes( - layout_context, - containing_block, - &LogicalVec2::zero(), - false, /* auto_block_size_stretches_to_containing_block */ - ) - .max(ContentSizes::zero()); + let inline_content_sizes_result = float_box.contents.outer_inline_content_sizes( + layout_context, + containing_block, + &LogicalVec2::zero(), + false, /* auto_block_size_stretches_to_containing_block */ + ); let style_box = &float_box.contents.style().get_box(); - Some((size, style_box.float, style_box.clear)) + Some(( + inline_content_sizes_result, + style_box.float, + style_box.clear, + )) }, BlockLevelBox::SameFormattingContextBlock { style, contents, .. } => { - let size = sizing::outer_inline( + let inline_content_sizes_result = sizing::outer_inline( style, containing_block, &LogicalVec2::zero(), @@ -390,30 +391,34 @@ fn calculate_inline_content_size_for_block_level_boxes( |containing_block_for_children| { contents.inline_content_sizes(layout_context, containing_block_for_children) }, - ) - .max(ContentSizes::zero()); + ); // A block in the same BFC can overlap floats, it's not moved next to them, // so we shouldn't add its size to the size of the floats. // Instead, we treat it like an independent block with 'clear: both'. - Some((size, Float::None, Clear::Both)) + Some((inline_content_sizes_result, Float::None, Clear::Both)) }, BlockLevelBox::Independent(ref mut independent) => { - let size = independent - .outer_inline_content_sizes( - layout_context, - containing_block, - &LogicalVec2::zero(), - false, /* auto_block_size_stretches_to_containing_block */ - ) - .max(ContentSizes::zero()); - Some((size, Float::None, independent.style().get_box().clear)) + let inline_content_sizes_result = independent.outer_inline_content_sizes( + layout_context, + containing_block, + &LogicalVec2::zero(), + false, /* auto_block_size_stretches_to_containing_block */ + ); + Some(( + inline_content_sizes_result, + Float::None, + independent.style().get_box().clear, + )) }, } }; /// When iterating the block-level boxes to compute the inline content sizes, /// this struct contains the data accumulated up to the current box. + #[derive(Default)] struct AccumulatedData { + /// Whether the inline size depends on the block one. + depends_on_block_constraints: bool, /// The maximum size seen so far, not including trailing uncleared floats. max_size: ContentSizes, /// The size of the trailing uncleared floats with 'float: left'. @@ -447,37 +452,44 @@ fn calculate_inline_content_size_for_block_level_boxes( } } - let accumulate = |mut data: AccumulatedData, (size, float, clear)| { - data.clear_floats(clear); - match float { - Float::Left => data.left_floats = data.left_floats.union(&size), - Float::Right => data.right_floats = data.right_floats.union(&size), - Float::None => { - data.max_size = data - .max_size - .max(data.left_floats.union(&data.right_floats).union(&size)); - data.left_floats = ContentSizes::zero(); - data.right_floats = ContentSizes::zero(); - }, - } - data - }; - let zero = AccumulatedData { - max_size: ContentSizes::zero(), - left_floats: ContentSizes::zero(), - right_floats: ContentSizes::zero(), - }; + let accumulate = + |mut data: AccumulatedData, + (inline_content_sizes_result, float, clear): (InlineContentSizesResult, _, _)| { + let size = inline_content_sizes_result.sizes.max(ContentSizes::zero()); + let depends_on_block_constraints = + inline_content_sizes_result.depends_on_block_constraints; + data.depends_on_block_constraints |= depends_on_block_constraints; + data.clear_floats(clear); + match float { + Float::Left => data.left_floats = data.left_floats.union(&size), + Float::Right => data.right_floats = data.right_floats.union(&size), + Float::None => { + data.max_size = data + .max_size + .max(data.left_floats.union(&data.right_floats).union(&size)); + data.left_floats = ContentSizes::zero(); + data.right_floats = ContentSizes::zero(); + }, + } + data + }; let data = if layout_context.use_rayon { boxes .par_iter() .filter_map(get_box_info) .collect::>() .into_iter() - .fold(zero, accumulate) + .fold(AccumulatedData::default(), accumulate) } else { - boxes.iter().filter_map(get_box_info).fold(zero, accumulate) + boxes + .iter() + .filter_map(get_box_info) + .fold(AccumulatedData::default(), accumulate) }; - data.max_size_including_uncleared_floats() + InlineContentSizesResult { + depends_on_block_constraints: data.depends_on_block_constraints, + sizes: data.max_size_including_uncleared_floats(), + } } impl BlockContainer { @@ -512,7 +524,7 @@ impl BlockContainer { &self, layout_context: &LayoutContext, containing_block_for_children: &IndefiniteContainingBlock, - ) -> ContentSizes { + ) -> InlineContentSizesResult { match &self { Self::BlockLevelBoxes(boxes) => calculate_inline_content_size_for_block_level_boxes( boxes, @@ -1984,6 +1996,7 @@ impl IndependentFormattingContext { ); non_replaced .inline_content_sizes(layout_context, &containing_block_for_children) + .sizes }; // https://drafts.csswg.org/css2/visudet.html#float-width diff --git a/components/layout_2020/formatting_contexts.rs b/components/layout_2020/formatting_contexts.rs index 7064eb72372..dc75e150654 100644 --- a/components/layout_2020/formatting_contexts.rs +++ b/components/layout_2020/formatting_contexts.rs @@ -18,7 +18,7 @@ use crate::fragment_tree::{BaseFragmentInfo, BoxFragment, Fragment, FragmentFlag use crate::geom::LogicalSides; use crate::positioned::PositioningContext; use crate::replaced::ReplacedContent; -use crate::sizing::{self, ContentSizes}; +use crate::sizing::{self, InlineContentSizesResult}; use crate::style_ext::{AspectRatio, DisplayInside}; use crate::table::Table; use crate::{AuOrAuto, ContainingBlock, IndefiniteContainingBlock, LogicalVec2}; @@ -36,7 +36,7 @@ pub(crate) struct NonReplacedFormattingContext { #[serde(skip_serializing)] pub style: Arc, /// If it was requested during construction - pub content_sizes: Option<(AuOrAuto, ContentSizes)>, + pub content_sizes_result: Option<(AuOrAuto, InlineContentSizesResult)>, pub contents: NonReplacedFormattingContextContents, } @@ -152,7 +152,7 @@ impl IndependentFormattingContext { Self::NonReplaced(NonReplacedFormattingContext { style: Arc::clone(&node_and_style_info.style), base_fragment_info, - content_sizes: None, + content_sizes_result: None, contents, }) }, @@ -187,7 +187,7 @@ impl IndependentFormattingContext { layout_context: &LayoutContext, containing_block_for_children: &IndefiniteContainingBlock, containing_block: &IndefiniteContainingBlock, - ) -> ContentSizes { + ) -> InlineContentSizesResult { match self { Self::NonReplaced(inner) => { inner.inline_content_sizes(layout_context, containing_block_for_children) @@ -206,7 +206,7 @@ impl IndependentFormattingContext { containing_block: &IndefiniteContainingBlock, auto_minimum: &LogicalVec2, auto_block_size_stretches_to_containing_block: bool, - ) -> ContentSizes { + ) -> InlineContentSizesResult { match self { Self::NonReplaced(non_replaced) => non_replaced.outer_inline_content_sizes( layout_context, @@ -274,20 +274,22 @@ impl NonReplacedFormattingContext { &mut self, layout_context: &LayoutContext, containing_block_for_children: &IndefiniteContainingBlock, - ) -> ContentSizes { + ) -> InlineContentSizesResult { assert_eq!( containing_block_for_children.size.inline, AuOrAuto::Auto, "inline_content_sizes() got non-auto containing block inline-size", ); - if let Some((previous_cb_block_size, result)) = self.content_sizes { - if previous_cb_block_size == containing_block_for_children.size.block { + if let Some((previous_cb_block_size, result)) = self.content_sizes_result { + if !result.depends_on_block_constraints || + previous_cb_block_size == containing_block_for_children.size.block + { return result; } // TODO: Should we keep multiple caches for various block sizes? } - self.content_sizes + self.content_sizes_result .insert(( containing_block_for_children.size.block, self.contents @@ -302,7 +304,7 @@ impl NonReplacedFormattingContext { containing_block: &IndefiniteContainingBlock, auto_minimum: &LogicalVec2, auto_block_size_stretches_to_containing_block: bool, - ) -> ContentSizes { + ) -> InlineContentSizesResult { sizing::outer_inline( &self.style.clone(), containing_block, @@ -320,7 +322,7 @@ impl NonReplacedFormattingContextContents { &mut self, layout_context: &LayoutContext, containing_block_for_children: &IndefiniteContainingBlock, - ) -> ContentSizes { + ) -> InlineContentSizesResult { match self { Self::Flow(inner) => inner .contents diff --git a/components/layout_2020/lib.rs b/components/layout_2020/lib.rs index d7fe1851bd6..51241b3baa9 100644 --- a/components/layout_2020/lib.rs +++ b/components/layout_2020/lib.rs @@ -65,7 +65,7 @@ impl<'a> IndefiniteContainingBlock<'a> { style: &'a ComputedValues, auto_minimum: &LogicalVec2, ) -> Self { - let (content_box_size, content_min_size, content_max_size, _) = + let (content_box_size, content_min_size, content_max_size, _, _) = style.content_box_sizes_and_padding_border_margin_deprecated(self); let block_size = content_box_size.block.map(|v| { v.clamp_between_extremums( diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs index 8f29162f549..ef42b983531 100644 --- a/components/layout_2020/positioned.rs +++ b/components/layout_2020/positioned.rs @@ -587,6 +587,7 @@ impl HoistedAbsolutelyPositionedBox { ); non_replaced .inline_content_sizes(layout_context, &containing_block_for_children) + .sizes .shrink_to_fit(available_size) }); diff --git a/components/layout_2020/replaced.rs b/components/layout_2020/replaced.rs index b54682a287d..a240c10ba03 100644 --- a/components/layout_2020/replaced.rs +++ b/components/layout_2020/replaced.rs @@ -29,7 +29,7 @@ use crate::context::LayoutContext; use crate::dom::NodeExt; use crate::fragment_tree::{BaseFragmentInfo, Fragment, IFrameFragment, ImageFragment}; use crate::geom::{LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSize}; -use crate::sizing::ContentSizes; +use crate::sizing::InlineContentSizesResult; use crate::style_ext::{AspectRatio, Clamp, ComputedValuesExt, PaddingBorderMargin}; use crate::{AuOrAuto, ContainingBlock, IndefiniteContainingBlock}; @@ -263,21 +263,27 @@ impl ReplacedContent { _: &LayoutContext, containing_block_for_children: &IndefiniteContainingBlock, preferred_aspect_ratio: Option, - ) -> ContentSizes { + ) -> InlineContentSizesResult { // FIXME: min/max-content of replaced elements is not defined in // https://dbaron.org/css/intrinsic/ // This seems sensible? let block_size = containing_block_for_children.size.block; - let inline_size = match (block_size, preferred_aspect_ratio) { - (AuOrAuto::LengthPercentage(block_size), Some(ratio)) => { - ratio.compute_dependent_size(Direction::Inline, block_size) + match (block_size, preferred_aspect_ratio) { + (AuOrAuto::LengthPercentage(block_size), Some(ratio)) => InlineContentSizesResult { + sizes: ratio + .compute_dependent_size(Direction::Inline, block_size) + .into(), + depends_on_block_constraints: true, }, - _ => self - .flow_relative_intrinsic_size(containing_block_for_children.style) - .inline - .unwrap_or_else(Au::zero), - }; - inline_size.into() + _ => InlineContentSizesResult { + sizes: self + .flow_relative_intrinsic_size(containing_block_for_children.style) + .inline + .unwrap_or_else(Au::zero) + .into(), + depends_on_block_constraints: false, + }, + } } pub fn make_fragments( diff --git a/components/layout_2020/sizing.rs b/components/layout_2020/sizing.rs index 521779120ff..774ff1ffc57 100644 --- a/components/layout_2020/sizing.rs +++ b/components/layout_2020/sizing.rs @@ -118,10 +118,15 @@ pub(crate) fn outer_inline( containing_block: &IndefiniteContainingBlock, auto_minimum: &LogicalVec2, auto_block_size_stretches_to_containing_block: bool, - get_content_size: impl FnOnce(&IndefiniteContainingBlock) -> ContentSizes, -) -> ContentSizes { - let (content_box_size, content_min_size, content_max_size, pbm) = - style.content_box_sizes_and_padding_border_margin_deprecated(containing_block); + get_content_size: impl FnOnce(&IndefiniteContainingBlock) -> InlineContentSizesResult, +) -> InlineContentSizesResult { + let ( + content_box_size, + content_min_size, + content_max_size, + pbm, + mut depends_on_block_constraints, + ) = style.content_box_sizes_and_padding_border_margin_deprecated(containing_block); let content_min_size = LogicalVec2 { inline: content_min_size.inline.auto_is(|| auto_minimum.inline), block: content_min_size.block.auto_is(|| auto_minimum.block), @@ -132,11 +137,15 @@ pub(crate) fn outer_inline( v.clamp_between_extremums(content_min_size.inline, content_max_size.inline) + pbm_inline_sum }; match content_box_size.inline { - AuOrAuto::LengthPercentage(inline_size) => adjust(inline_size).into(), + AuOrAuto::LengthPercentage(inline_size) => InlineContentSizesResult { + sizes: adjust(inline_size).into(), + depends_on_block_constraints: false, + }, AuOrAuto::Auto => { let block_size = if content_box_size.block.is_auto() && auto_block_size_stretches_to_containing_block { + depends_on_block_constraints = true; let outer_block_size = containing_block.size.block; outer_block_size.map(|v| v - pbm.padding_border_sums.block - margin.block_sum()) } else { @@ -145,7 +154,18 @@ pub(crate) fn outer_inline( .map(|v| v.clamp_between_extremums(content_min_size.block, content_max_size.block)); let containing_block_for_children = IndefiniteContainingBlock::new_for_style_and_block_size(style, block_size); - get_content_size(&containing_block_for_children).map(adjust) + let content_result = get_content_size(&containing_block_for_children); + InlineContentSizesResult { + sizes: content_result.sizes.map(adjust), + depends_on_block_constraints: content_result.depends_on_block_constraints && + depends_on_block_constraints, + } }, } } + +#[derive(Clone, Copy, Debug, Serialize)] +pub(crate) struct InlineContentSizesResult { + pub sizes: ContentSizes, + pub depends_on_block_constraints: bool, +} diff --git a/components/layout_2020/style_ext.rs b/components/layout_2020/style_ext.rs index c263bb14697..8fbe2bd68d9 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, SizeKeyword, }; use crate::{ContainingBlock, IndefiniteContainingBlock}; @@ -249,6 +249,7 @@ pub(crate) trait ComputedValuesExt { LogicalVec2>, LogicalVec2>, PaddingBorderMargin, + bool, /* depends_on_block_constraints */ ); fn content_box_sizes_and_padding_border_margin_deprecated( &self, @@ -258,6 +259,7 @@ pub(crate) trait ComputedValuesExt { LogicalVec2, LogicalVec2>, PaddingBorderMargin, + bool, /* depends_on_block_constraints */ ); fn padding_border_margin(&self, containing_block: &ContainingBlock) -> PaddingBorderMargin; fn padding_border_margin_for_intrinsic_size( @@ -499,6 +501,7 @@ impl ComputedValuesExt for ComputedValues { LogicalVec2>, LogicalVec2>, PaddingBorderMargin, + bool, /* depends_on_block_constraints */ ) { // // If max size properties or preferred size properties are set to a value containing @@ -513,25 +516,45 @@ impl ComputedValuesExt for ComputedValues { writing_mode, containing_block.size.inline.auto_is(Au::zero), ); - let box_size = self - .box_size(writing_mode) - .maybe_percentages_relative_to_basis(&containing_block_size); + let box_size = self.box_size(writing_mode); + let min_size = self.min_box_size(writing_mode); + let max_size = self.max_box_size(writing_mode); + let depends_on_block_constraints = |size: &Size| { + match size { + // fit-content is like clamp(min-content, stretch, max-content), but currently + // min-content and max-content have the same behavior in the block axis, + // so there is no dependency on block constraints. + // TODO: for flex and grid layout, min-content and max-content should be different. + // TODO: We are assuming that Size::Initial doesn't stretch. However, it may actually + // stretch flex and grid items depending on the CSS Align properties, in that case + // the caller needs to take care of it. + Size::Keyword(SizeKeyword::Stretch) => true, + Size::Numeric(length_percentage) => length_percentage.has_percentage(), + _ => false, + } + }; + let depends_on_block_constraints = depends_on_block_constraints(&box_size.block) || + depends_on_block_constraints(&min_size.block) || + depends_on_block_constraints(&max_size.block); + let box_size = box_size.maybe_percentages_relative_to_basis(&containing_block_size); let content_box_size = self .content_box_size_for_box_size(box_size, &pbm) .map(|v| v.map(Au::from)); - let min_size = self - .min_box_size(writing_mode) - .percentages_relative_to_basis(&containing_block_size_auto_is_zero); + let min_size = min_size.percentages_relative_to_basis(&containing_block_size_auto_is_zero); let content_min_size = self .content_min_box_size_for_min_size(min_size, &pbm) .map(|v| v.map(Au::from)); - let max_size = self - .max_box_size(writing_mode) - .maybe_percentages_relative_to_basis(&containing_block_size); + let max_size = max_size.maybe_percentages_relative_to_basis(&containing_block_size); let content_max_size = self .content_max_box_size_for_max_size(max_size, &pbm) .map(|v| v.map(Au::from)); - (content_box_size, content_min_size, content_max_size, pbm) + ( + content_box_size, + content_min_size, + content_max_size, + pbm, + depends_on_block_constraints, + ) } fn content_box_sizes_and_padding_border_margin_deprecated( @@ -542,14 +565,21 @@ impl ComputedValuesExt for ComputedValues { LogicalVec2, LogicalVec2>, PaddingBorderMargin, + bool, /* depends_on_block_constraints */ ) { - let (content_box_size, content_min_size, content_max_size, pbm) = - self.content_box_sizes_and_padding_border_margin(containing_block); + let ( + content_box_size, + content_min_size, + content_max_size, + pbm, + depends_on_block_constraints, + ) = self.content_box_sizes_and_padding_border_margin(containing_block); ( content_box_size.map(Size::to_auto_or), content_min_size.map(Size::to_auto_or), content_max_size.map(Size::to_numeric), pbm, + depends_on_block_constraints, ) } diff --git a/components/layout_2020/table/construct.rs b/components/layout_2020/table/construct.rs index 461267bdad0..089c8843f1e 100644 --- a/components/layout_2020/table/construct.rs +++ b/components/layout_2020/table/construct.rs @@ -137,7 +137,7 @@ impl Table { IndependentFormattingContext::NonReplaced(NonReplacedFormattingContext { base_fragment_info: (&anonymous_info).into(), style: grid_and_wrapper_style, - content_sizes: None, + content_sizes_result: None, contents: NonReplacedFormattingContextContents::Table(table), }) } @@ -858,7 +858,7 @@ where context: ArcRefCell::new(NonReplacedFormattingContext { style: info.style.clone(), base_fragment_info: info.into(), - content_sizes: None, + content_sizes_result: None, contents, }), }; diff --git a/components/layout_2020/table/layout.rs b/components/layout_2020/table/layout.rs index 6e746b607e8..24d5058b9ad 100644 --- a/components/layout_2020/table/layout.rs +++ b/components/layout_2020/table/layout.rs @@ -38,7 +38,7 @@ use crate::geom::{ Size, SizeKeyword, ToLogical, ToLogicalWithContainingBlock, }; use crate::positioned::{relative_adjustement, PositioningContext, PositioningContextLength}; -use crate::sizing::ContentSizes; +use crate::sizing::{ContentSizes, InlineContentSizesResult}; use crate::style_ext::{Clamp, ComputedValuesExt, PaddingBorderMargin}; use crate::table::TableSlotCoordinates; use crate::{ContainingBlock, IndefiniteContainingBlock}; @@ -298,10 +298,13 @@ impl<'a> TableLayout<'a> { let mut inline_content_sizes = if is_in_fixed_mode { ContentSizes::zero() } else { - cell.contents.contents.inline_content_sizes( - layout_context, - &IndefiniteContainingBlock::new_for_style(&cell.style), - ) + cell.contents + .contents + .inline_content_sizes( + layout_context, + &IndefiniteContainingBlock::new_for_style(&cell.style), + ) + .sizes }; inline_content_sizes.min_content += padding_border_sums.inline; inline_content_sizes.max_content += padding_border_sums.inline; @@ -784,6 +787,7 @@ impl<'a> TableLayout<'a> { &LogicalVec2::zero(), false, /* auto_block_size_stretches_to_containing_block */ ) + .sizes .min_content }) .max() @@ -2611,7 +2615,7 @@ impl Table { &mut self, layout_context: &LayoutContext, containing_block_for_children: &IndefiniteContainingBlock, - ) -> ContentSizes { + ) -> InlineContentSizesResult { let writing_mode = containing_block_for_children.style.writing_mode; let mut layout = TableLayout::new(self); let mut table_content_sizes = layout.compute_grid_min_max(layout_context, writing_mode); @@ -2638,7 +2642,10 @@ impl Table { .max_assign(caption_minimum_inline_size); } - table_content_sizes + InlineContentSizesResult { + sizes: table_content_sizes, + depends_on_block_constraints: false, + } } fn get_column_measure_for_column_at_index(