diff --git a/components/layout_2020/flexbox/construct.rs b/components/layout_2020/flexbox/construct.rs index d1d3580aace..c4c5ff57d60 100644 --- a/components/layout_2020/flexbox/construct.rs +++ b/components/layout_2020/flexbox/construct.rs @@ -181,7 +181,7 @@ where independent_formatting_context: IndependentFormattingContext::NonReplaced( non_replaced, ), - cached_layout: Default::default(), + block_content_size_cache: Default::default(), }))) }, FlexLevelJob::Element { @@ -213,7 +213,7 @@ where contents, self.text_decoration_line, ), - cached_layout: Default::default(), + block_content_size_cache: Default::default(), })) }; box_slot.set(LayoutBox::FlexLevel(box_.clone())); diff --git a/components/layout_2020/flexbox/layout.rs b/components/layout_2020/flexbox/layout.rs index 8950e9a0ce1..bb580c23f8d 100644 --- a/components/layout_2020/flexbox/layout.rs +++ b/components/layout_2020/flexbox/layout.rs @@ -12,6 +12,7 @@ use style::computed_values::position::T as Position; use style::logical_geometry::Direction; use style::properties::longhands::align_items::computed_value::T as AlignItems; use style::properties::longhands::box_sizing::computed_value::T as BoxSizing; +use style::properties::longhands::flex_direction::computed_value::T as FlexDirection; use style::properties::longhands::flex_wrap::computed_value::T as FlexWrap; use style::properties::ComputedValues; use style::values::computed::length::Size; @@ -22,8 +23,7 @@ use style::Zero; use super::geom::{FlexAxis, FlexRelativeRect, FlexRelativeSides, FlexRelativeVec2}; use super::{ - FlexContainer, FlexContainerConfig, FlexItemBox, FlexItemLayoutCache, - FlexItemLayoutCacheDescriptor, FlexLevelBox, + CachedBlockSizeContribution, FlexContainer, FlexContainerConfig, FlexItemBox, FlexLevelBox, }; use crate::cell::ArcRefCell; use crate::context::LayoutContext; @@ -34,7 +34,9 @@ use crate::positioned::{ relative_adjustement, AbsolutelyPositionedBox, PositioningContext, PositioningContextLength, }; use crate::sizing::{ContentSizes, InlineContentSizesResult, IntrinsicSizingMode}; -use crate::style_ext::{Clamp, ComputedValuesExt, PaddingBorderMargin}; +use crate::style_ext::{ + Clamp, ComputedValuesExt, ContentBoxSizesAndPBMDeprecated, PaddingBorderMargin, +}; use crate::{ContainingBlock, IndefiniteContainingBlock}; // FIMXE: “Flex items […] `z-index` values other than `auto` create a stacking context @@ -78,8 +80,12 @@ struct FlexItem<'a> { /// hypothetical_main_size: Au, + /// This is `align-self`, defaulting to `align-items` if `auto` align_self: AlignItems, + + /// Whether or not the size of this [`FlexItem`] depends on its block constraints. + depends_on_block_constraints: bool, } /// Child of a FlexContainer. Can either be absolutely positioned, or not. If not, @@ -97,6 +103,22 @@ struct FlexItemLayoutResult { // Either the first or the last baseline, depending on ‘align-self’. baseline_relative_to_margin_box: Option, + + // The content size of this layout. For replaced elements this is known before layout, + // but for non-replaced it's only known after layout. + content_size: LogicalVec2, + + // The containing block inline size used to generate this layout. + containing_block_inline_size: Au, + + // The containing block block size used to generate this layout. + containing_block_block_size: AuOrAuto, + + // Whether or not this layout depended on block constraints. + depends_on_block_constraints: bool, + + // Whether or not this layout had a child that dependeded on block constraints. + has_child_which_depends_on_block_constraints: bool, } impl FlexItemLayoutResult { @@ -172,11 +194,17 @@ impl FlexItemLayoutResult { let mut fragment_info = item.box_.base_fragment_info(); fragment_info.flags.insert(FragmentFlags::IS_FLEX_ITEM); + if item.depends_on_block_constraints { + fragment_info.flags.insert( + FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM, + ); + } let flags = fragment_info.flags; let containing_block = flex_context.containing_block; let container_writing_mode = containing_block.style.writing_mode; let style = item.box_.style(); + let mut fragment = BoxFragment::new( fragment_info, style.clone(), @@ -208,6 +236,23 @@ impl FlexItemLayoutResult { (fragment, self.positioning_context) } + + fn compatible_with_containing_block_size(&self, containing_block: &ContainingBlock) -> bool { + if containing_block.inline_size != self.containing_block_inline_size { + return false; + } + containing_block.block_size == self.containing_block_block_size || + (!self.depends_on_block_constraints && + !self.has_child_which_depends_on_block_constraints) + } + + fn compatible_with_containing_block_size_and_content_size( + &self, + containing_block: &ContainingBlock, + size: LogicalVec2, + ) -> bool { + size == self.content_size && self.compatible_with_containing_block_size(containing_block) + } } struct InitialFlexLineLayout<'a> { @@ -571,8 +616,12 @@ impl FlexContainer { containing_block: &ContainingBlock, containing_block_for_container: &ContainingBlock, ) -> IndependentLayout { - let (container_min_cross_size, container_max_cross_size) = + let (container_min_cross_size, container_max_cross_size, depends_on_block_constraints) = self.available_cross_space_for_flex_items(containing_block_for_container); + + let depends_on_block_constraints = + depends_on_block_constraints || self.config.flex_direction == FlexDirection::Column; + let mut flex_context = FlexContext { config: self.config.clone(), layout_context, @@ -896,6 +945,7 @@ impl FlexContainer { content_block_size, content_inline_size_for_table: None, baselines, + depends_on_block_constraints, } } @@ -967,22 +1017,26 @@ impl FlexContainer { fn available_cross_space_for_flex_items( &self, containing_block_for_container: &ContainingBlock, - ) -> (Au, Option) { - let pbm = self + ) -> (Au, Option, bool) { + let sizes: ContentBoxSizesAndPBMDeprecated = self .style - .padding_border_margin(containing_block_for_container); + .content_box_sizes_and_padding_border_margin(&containing_block_for_container.into()) + .into(); + let max_box_size = self - .style - .content_max_box_size_deprecated(containing_block_for_container, &pbm); + .config + .flex_axis + .vec2_to_flex_relative(sizes.content_max_box_size); let min_box_size = self - .style - .content_min_box_size_deprecated(containing_block_for_container, &pbm) - .auto_is(Au::zero); + .config + .flex_axis + .vec2_to_flex_relative(sizes.content_min_box_size.auto_is(Au::zero)); - let max_box_size = self.config.flex_axis.vec2_to_flex_relative(max_box_size); - let min_box_size = self.config.flex_axis.vec2_to_flex_relative(min_box_size); - - (min_box_size.cross, max_box_size.cross) + ( + min_box_size.cross, + max_box_size.cross, + sizes.depends_on_block_constraints, + ) } } @@ -1046,9 +1100,16 @@ impl<'a> FlexItem<'a> { flex_context.config.flex_axis, ); - let (content_box_size, min_size, max_size, pbm, _) = box_ + let ContentBoxSizesAndPBMDeprecated { + content_box_size, + content_min_box_size, + content_max_box_size, + pbm, + depends_on_block_constraints, + } = box_ .style() - .content_box_sizes_and_padding_border_margin_deprecated(&containing_block.into()); + .content_box_sizes_and_padding_border_margin(&containing_block.into()) + .into(); let margin_auto_is_zero = flex_context.sides_to_flex_relative(pbm.margin.auto_is(Au::zero)); let padding = flex_context.sides_to_flex_relative(pbm.padding); @@ -1065,8 +1126,10 @@ impl<'a> FlexItem<'a> { .item_with_auto_cross_size_stretches_to_container_size(box_.style(), &margin); let flex_relative_content_box_size = flex_context.vec2_to_flex_relative(content_box_size); - let flex_relative_content_max_size = flex_context.vec2_to_flex_relative(max_size); - let flex_relative_content_min_size = flex_context.vec2_to_flex_relative(min_size); + let flex_relative_content_max_size = + flex_context.vec2_to_flex_relative(content_max_box_size); + let flex_relative_content_min_size = + flex_context.vec2_to_flex_relative(content_min_box_size); let flex_relative_content_min_size = FlexRelativeVec2 { main: flex_relative_content_min_size.main.auto_is(|| { box_.automatic_min_size( @@ -1079,14 +1142,14 @@ impl<'a> FlexItem<'a> { &pbm_auto_is_zero, item_with_auto_cross_size_stretches_to_container_size, |item| { - let min_size_auto_is_zero = min_size.auto_is(Au::zero); + let min_size_auto_is_zero = content_min_box_size.auto_is(Au::zero); item.layout_for_block_content_size( flex_context, &pbm, content_box_size, min_size_auto_is_zero, - max_size, + content_max_box_size, item_with_auto_cross_size_stretches_to_container_size, IntrinsicSizingMode::Size, ) @@ -1095,7 +1158,6 @@ impl<'a> FlexItem<'a> { }), cross: flex_relative_content_min_size.cross.auto_is(Au::zero), }; - let align_self = AlignItems( flex_context .config @@ -1122,7 +1184,7 @@ impl<'a> FlexItem<'a> { &pbm, content_box_size, min_size, - max_size, + content_max_box_size, item_with_auto_cross_size_stretches_to_container_size, IntrinsicSizingMode::Size, ) @@ -1148,6 +1210,7 @@ impl<'a> FlexItem<'a> { flex_base_size_is_definite, hypothetical_main_size, align_self, + depends_on_block_constraints, } } @@ -1263,7 +1326,10 @@ impl InitialFlexLineLayout<'_> { let item_layout_results = items .iter_mut() .zip(&item_used_main_sizes) - .map(|(item, &used_main_size)| item.layout(used_main_size, flex_context, None)) + .map(|(item, &used_main_size)| { + item.layout(used_main_size, flex_context, None, None) + .unwrap() + }) .collect::>(); // https://drafts.csswg.org/css-flexbox/#algo-cross-line @@ -1552,14 +1618,23 @@ impl InitialFlexLineLayout<'_> { }; item_used_cross_sizes.push(used_cross_size); + // “If the flex item has `align-self: stretch`, redo layout for its contents, + // treating this used size as its definite cross size so that percentage-sized + // children can be resolved.” if stretches { - // “If the flex item has `align-self: stretch`, redo layout for its contents, - // treating this used size as its definite cross size - // so that percentage-sized children can be resolved.” - *item_layout_result = - item.layout(*used_main_size, flex_context, Some(used_cross_size)); + let new_layout = item.layout( + *used_main_size, + flex_context, + Some(used_cross_size), + Some(item_layout_result), + ); + if let Some(layout) = new_layout { + *item_layout_result = layout; + } } + let _ = item.box_.block_content_size_cache.borrow_mut().take(); + let baseline = item_layout_result .get_or_synthesize_baseline_with_cross_size(used_cross_size, item); if matches!( @@ -1705,14 +1780,16 @@ impl FlexItem<'_> { /// From : /// > performing layout as if it were an in-flow block-level box with the used main /// > size and the given available space, treating `auto` as `fit-content`. + #[allow(clippy::too_many_arguments)] fn layout( &mut self, used_main_size: Au, flex_context: &FlexContext, used_cross_size_override: Option, - ) -> FlexItemLayoutResult { + non_stretch_layout_result: Option<&mut FlexItemLayoutResult>, + ) -> Option { // Clear any layout cache information so that it doesn't persist until the next layout. - self.box_.cached_layout.borrow_mut().take(); + self.box_.block_content_size_cache.borrow_mut().take(); let containing_block = flex_context.containing_block; let mut positioning_context = PositioningContext::new_for_style(self.box_.style()) @@ -1799,34 +1876,82 @@ impl FlexItem<'_> { flex_axis.vec2_to_flow_relative(self.content_min_size), flex_axis.vec2_to_flow_relative(self.content_max_size), ); - let cross_size = flex_axis.vec2_to_flex_relative(size).cross; + let hypothetical_cross_size = flex_axis.vec2_to_flex_relative(size).cross; + + if let Some(non_stretch_layout_result) = non_stretch_layout_result { + if non_stretch_layout_result + .compatible_with_containing_block_size_and_content_size( + containing_block, + size, + ) + { + non_stretch_layout_result.hypothetical_cross_size = hypothetical_cross_size; + return None; + } + } + let fragments = replaced.contents.make_fragments( &replaced.style, containing_block, size.to_physical_size(container_writing_mode), ); - FlexItemLayoutResult { - hypothetical_cross_size: cross_size, + Some(FlexItemLayoutResult { + hypothetical_cross_size, fragments, positioning_context, + content_size: size, + containing_block_inline_size: containing_block.inline_size, + containing_block_block_size: containing_block.block_size, + depends_on_block_constraints: false, + has_child_which_depends_on_block_constraints: false, // We will need to synthesize the baseline, but since the used cross // size can differ from the hypothetical cross size, we should defer // synthesizing until needed. baseline_relative_to_margin_box: None, - } + }) }, IndependentFormattingContext::NonReplaced(non_replaced) => { + let calculate_hypothetical_cross_size = |content_block_size| { + self.content_box_size + .cross + .auto_is(|| { + if cross_axis_is_item_block_axis { + content_block_size + } else { + inline_size + } + }) + .clamp_between_extremums( + self.content_min_size.cross, + self.content_max_size.cross, + ) + }; + let item_as_containing_block = ContainingBlock { inline_size, block_size, style: &non_replaced.style, }; + + if let Some(non_stretch_layout_result) = non_stretch_layout_result { + if non_stretch_layout_result + .compatible_with_containing_block_size(&item_as_containing_block) + { + non_stretch_layout_result.hypothetical_cross_size = + calculate_hypothetical_cross_size( + non_stretch_layout_result.content_size.inline, + ); + return None; + } + } + let IndependentLayout { fragments, content_block_size, baselines: content_box_baselines, + depends_on_block_constraints, .. } = non_replaced.layout( flex_context.layout_context, @@ -1835,6 +1960,12 @@ impl FlexItem<'_> { containing_block, ); + let has_child_which_depends_on_block_constraints = fragments.iter().any(|fragment| { + fragment.base().map_or(false,|base| + base.flags.contains( + FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM)) + }); + let item_writing_mode_is_orthogonal_to_container_writing_mode = flex_context.config.writing_mode.is_horizontal() != non_replaced.style.writing_mode.is_horizontal(); @@ -1860,27 +1991,20 @@ impl FlexItem<'_> { _ => None, }; - let hypothetical_cross_size = self - .content_box_size - .cross - .auto_is(|| { - if cross_axis_is_item_block_axis { - content_block_size - } else { - inline_size - } - }) - .clamp_between_extremums( - self.content_min_size.cross, - self.content_max_size.cross, - ); - - FlexItemLayoutResult { - hypothetical_cross_size, + Some(FlexItemLayoutResult { + hypothetical_cross_size: calculate_hypothetical_cross_size(content_block_size), fragments, positioning_context, baseline_relative_to_margin_box, - } + content_size: LogicalVec2 { + inline: item_as_containing_block.inline_size, + block: content_block_size, + }, + containing_block_inline_size: item_as_containing_block.inline_size, + containing_block_block_size: item_as_containing_block.block_size, + depends_on_block_constraints, + has_child_which_depends_on_block_constraints, + }) }, } } @@ -2035,8 +2159,15 @@ 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, _) = - style.content_box_sizes_and_padding_border_margin_deprecated(containing_block); + let ContentBoxSizesAndPBMDeprecated { + content_box_size, + content_min_box_size, + content_max_box_size, + pbm, + .. + } = style + .content_box_sizes_and_padding_border_margin(containing_block) + .into(); let padding = main_start_cross_start.sides_to_flex_relative(pbm.padding); let border = main_start_cross_start.sides_to_flex_relative(pbm.border); let margin = main_start_cross_start.sides_to_flex_relative(pbm.margin); @@ -2055,8 +2186,8 @@ impl FlexItemBox { containing_block, cross_axis_is_item_block_axis, flex_axis.vec2_to_flex_relative(content_box_size), - flex_axis.vec2_to_flex_relative(content_min_size), - flex_axis.vec2_to_flex_relative(content_max_size), + flex_axis.vec2_to_flex_relative(content_min_box_size), + flex_axis.vec2_to_flex_relative(content_max_box_size), &pbm_auto_is_zero, item_with_auto_cross_size_stretches_to_container_size, |item| { @@ -2064,8 +2195,8 @@ impl FlexItemBox { flex_context_getter(), &pbm, content_box_size, - content_min_size.map(|v| v.auto_is(Au::zero)), - content_max_size, + content_min_box_size.map(|v| v.auto_is(Au::zero)), + content_max_box_size, item_with_auto_cross_size_stretches_to_container_size, IntrinsicSizingMode::Size, ) @@ -2073,13 +2204,13 @@ impl FlexItemBox { ); let content_min_size_no_auto = if cross_axis_is_item_block_axis { LogicalVec2 { - inline: content_min_size.inline.auto_is(|| automatic_min_size), - block: content_min_size.block.auto_is(Au::zero), + inline: content_min_box_size.inline.auto_is(|| automatic_min_size), + block: content_min_box_size.block.auto_is(Au::zero), } } else { LogicalVec2 { - inline: content_min_size.inline.auto_is(Au::zero), - block: content_min_size.block.auto_is(|| automatic_min_size), + inline: content_min_box_size.inline.auto_is(Au::zero), + block: content_min_box_size.block.auto_is(|| automatic_min_size), } }; let block_content_size_callback = |item: &mut FlexItemBox| { @@ -2088,7 +2219,7 @@ impl FlexItemBox { &pbm, content_box_size, content_min_size_no_auto, - content_max_size, + content_max_box_size, item_with_auto_cross_size_stretches_to_container_size, IntrinsicSizingMode::Size, ) @@ -2117,7 +2248,7 @@ impl FlexItemBox { &pbm, content_box_size, content_min_size_no_auto, - content_max_size, + content_max_box_size, item_with_auto_cross_size_stretches_to_container_size, IntrinsicSizingMode::Contribution, ); @@ -2127,7 +2258,7 @@ impl FlexItemBox { let content_box_size = flex_axis.vec2_to_flex_relative(content_box_size); let content_min_size_no_auto = flex_axis.vec2_to_flex_relative(content_min_size_no_auto); - let content_max_size = flex_axis.vec2_to_flex_relative(content_max_size); + let content_max_size = flex_axis.vec2_to_flex_relative(content_max_box_size); // TODO: when laying out a column container with an indefinite main size, // we compute the base sizes of the items twice. We should consider caching. @@ -2578,9 +2709,9 @@ impl FlexItemBox { style: &non_replaced.style, }; let mut content_block_size = || { - if let Some(cache) = &*self.cached_layout.borrow() { - if cache.descriptor.compatible_with_size(inline_size) { - return cache.descriptor.content_block_size; + if let Some(cache) = &*self.block_content_size_cache.borrow() { + if inline_size == cache.containing_block_inline_size { + return cache.content_block_size; } } @@ -2590,14 +2721,12 @@ impl FlexItemBox { &item_as_containing_block, flex_context.containing_block, ); - let content_block_size = layout.content_block_size; - *self.cached_layout.borrow_mut() = Some(FlexItemLayoutCache { - descriptor: FlexItemLayoutCacheDescriptor { + *self.block_content_size_cache.borrow_mut() = + Some(CachedBlockSizeContribution { containing_block_inline_size: item_as_containing_block.inline_size, content_block_size: layout.content_block_size, - }, - }); + }); content_block_size }; match intrinsic_sizing_mode { diff --git a/components/layout_2020/flexbox/mod.rs b/components/layout_2020/flexbox/mod.rs index 4eeac734feb..0e6f7837425 100644 --- a/components/layout_2020/flexbox/mod.rs +++ b/components/layout_2020/flexbox/mod.rs @@ -117,7 +117,7 @@ pub(crate) enum FlexLevelBox { pub(crate) struct FlexItemBox { independent_formatting_context: IndependentFormattingContext, #[serde(skip)] - cached_layout: ArcRefCell>, + block_content_size_cache: ArcRefCell>, } impl std::fmt::Debug for FlexItemBox { @@ -136,19 +136,7 @@ impl FlexItemBox { } } -#[derive(Debug)] -struct FlexItemLayoutCacheDescriptor { +struct CachedBlockSizeContribution { containing_block_inline_size: Au, content_block_size: Au, } - -impl FlexItemLayoutCacheDescriptor { - fn compatible_with_size(&self, inline: Au) -> bool { - inline == self.containing_block_inline_size - } -} - -/// A cache to avoid multiple layouts during flexbox layout. -struct FlexItemLayoutCache { - descriptor: FlexItemLayoutCacheDescriptor, -} diff --git a/components/layout_2020/flow/inline/mod.rs b/components/layout_2020/flow/inline/mod.rs index 4bad4293e5a..73c678e0458 100644 --- a/components/layout_2020/flow/inline/mod.rs +++ b/components/layout_2020/flow/inline/mod.rs @@ -627,6 +627,10 @@ pub(super) struct InlineFormattingContextLayout<'layout_data> { /// Whether or not this InlineFormattingContext has processed any in flow content at all. had_inflow_content: bool, + /// Whether or not the layout of this InlineFormattingContext depends on the block size + /// of its container for the purposes of flexbox layout. + depends_on_block_constraints: bool, + /// The currently white-space-collapse setting of this line. This is stored on the /// [`InlineFormattingContextLayout`] because when a soft wrap opportunity is defined /// by the boundary between two characters, the white-space-collapse property of their @@ -701,6 +705,12 @@ impl<'layout_dta> InlineFormattingContextLayout<'layout_dta> { .map(|index| &self.ifc.font_metrics[index].metrics), ); + self.depends_on_block_constraints |= inline_box + .style + .depends_on_block_constraints_due_to_relative_positioning( + self.containing_block.style.writing_mode, + ); + // If we are starting a `
` element prepare to clear after its deferred linebreak has been // processed. Note that a `
` is composed of the element itself and the inner pseudo-element // with the actual linebreak. Both will have this `FragmentFlag`; that's why this code only @@ -1631,6 +1641,7 @@ impl InlineFormattingContext { deferred_br_clear: Clear::None, have_deferred_soft_wrap_opportunity: false, had_inflow_content: false, + depends_on_block_constraints: false, white_space_collapse: style_text.white_space_collapse, text_wrap_mode: style_text.text_wrap_mode, baselines: Baselines::default(), @@ -1692,6 +1703,7 @@ impl InlineFormattingContext { content_block_size, collapsible_margins_in_children, baselines: layout.baselines, + depends_on_block_constraints: layout.depends_on_block_constraints, } } @@ -1921,6 +1933,12 @@ impl IndependentFormattingContext { layout.containing_block, ); + // If this Fragment's layout depends on the block size of the containing block, + // then the entire layout of the inline formatting context does as well. + layout.depends_on_block_constraints |= fragment.base.flags.contains( + FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM, + ); + // Offset the content rectangle by the physical offset of the padding, border, and margin. let container_writing_mode = layout.containing_block.style.writing_mode; let pbm_physical_offset = pbm_sums diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index b174c68ff3a..834b16c304e 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -38,7 +38,9 @@ use crate::geom::{ use crate::positioned::{AbsolutelyPositionedBox, PositioningContext, PositioningContextLength}; use crate::replaced::ReplacedContent; use crate::sizing::{self, ContentSizes, InlineContentSizesResult}; -use crate::style_ext::{Clamp, ComputedValuesExt, PaddingBorderMargin}; +use crate::style_ext::{ + Clamp, ComputedValuesExt, ContentBoxSizesAndPBMDeprecated, PaddingBorderMargin, +}; use crate::{ContainingBlock, IndefiniteContainingBlock}; mod construct; @@ -204,6 +206,8 @@ pub(crate) struct FlowLayout { /// used to propagate inflow baselines to the ancestors of `display: inline-block` elements /// and table content. pub baselines: Baselines, + /// Whether or not this layout depends on the block size of its containing block. + pub depends_on_block_constraints: bool, } #[derive(Clone, Copy)] @@ -348,6 +352,7 @@ impl BlockFormattingContext { clearance.unwrap_or_default(), content_inline_size_for_table: None, baselines: flow_layout.baselines, + depends_on_block_constraints: flow_layout.depends_on_block_constraints, } } } @@ -567,12 +572,21 @@ fn layout_block_level_children( ), }; + let depends_on_block_constraints = fragments.iter().any(|fragment| { + fragment.base().is_some_and(|base| { + base.flags.contains( + FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM, + ) + }) + }); + let (content_block_size, collapsible_margins_in_children, baselines) = placement_state.finish(); FlowLayout { fragments, content_block_size, collapsible_margins_in_children, baselines, + depends_on_block_constraints, } } @@ -763,7 +777,7 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context( layout_context: &LayoutContext, positioning_context: &mut PositioningContext, containing_block: &ContainingBlock, - base_fragment_info: BaseFragmentInfo, + mut base_fragment_info: BaseFragmentInfo, style: &Arc, contents: &BlockContainer, mut sequential_layout_state: Option<&mut SequentialLayoutState>, @@ -775,6 +789,7 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context( box_size, min_box_size, max_box_size, + depends_on_block_constraints, } = solve_containing_block_padding_and_border_for_in_flow_box(containing_block, style); let ResolvedMargins { margin, @@ -954,6 +969,12 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context( }; let containing_block_writing_mode = containing_block.style.writing_mode; + if depends_on_block_constraints { + base_fragment_info + .flags + .insert(FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM); + } + BoxFragment::new( base_fragment_info, style.clone(), @@ -996,6 +1017,7 @@ impl NonReplacedFormattingContext { box_size, min_box_size, max_box_size, + depends_on_block_constraints, } = solve_containing_block_padding_and_border_for_in_flow_box( containing_block, &self.style, @@ -1039,8 +1061,15 @@ impl NonReplacedFormattingContext { let block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin); let containing_block_writing_mode = containing_block.style.writing_mode; + + let mut base_fragment_info = self.base_fragment_info; + if depends_on_block_constraints { + base_fragment_info.flags.insert( + FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM, + ); + } BoxFragment::new( - self.base_fragment_info, + base_fragment_info, self.style.clone(), layout.fragments, content_rect.to_physical(Some(containing_block)), @@ -1063,19 +1092,21 @@ impl NonReplacedFormattingContext { containing_block: &ContainingBlock<'_>, sequential_layout_state: &mut SequentialLayoutState, ) -> BoxFragment { - let pbm = self.style.padding_border_margin(containing_block); - let box_size = self + let ContentBoxSizesAndPBMDeprecated { + content_box_size, + content_min_box_size, + content_max_box_size, + pbm, + depends_on_block_constraints, + } = self .style - .content_box_size_deprecated(containing_block, &pbm); - let max_box_size = self - .style - .content_max_box_size_deprecated(containing_block, &pbm); - let min_box_size = self - .style - .content_min_box_size_deprecated(containing_block, &pbm) - .auto_is(Au::zero); - let block_size = box_size.block.map(|block_size| { - block_size.clamp_between_extremums(min_box_size.block, max_box_size.block) + .content_box_sizes_and_padding_border_margin(&containing_block.into()) + .into(); + let content_min_box_size = content_min_box_size.auto_is(Au::zero); + + let block_size = content_box_size.block.map(|block_size| { + block_size + .clamp_between_extremums(content_min_box_size.block, content_max_box_size.block) }); let margin_inline_start; @@ -1098,9 +1129,9 @@ impl NonReplacedFormattingContext { let clearance; let mut content_size; let mut layout; - if let AuOrAuto::LengthPercentage(ref inline_size) = box_size.inline { - let inline_size = - inline_size.clamp_between_extremums(min_box_size.inline, max_box_size.inline); + if let AuOrAuto::LengthPercentage(ref inline_size) = content_box_size.inline { + let inline_size = inline_size + .clamp_between_extremums(content_min_box_size.inline, content_max_box_size.inline); layout = self.layout( layout_context, positioning_context, @@ -1120,9 +1151,10 @@ impl NonReplacedFormattingContext { } else { content_size = LogicalVec2 { block: block_size.auto_is(|| { - layout - .content_block_size - .clamp_between_extremums(min_box_size.block, max_box_size.block) + layout.content_block_size.clamp_between_extremums( + content_min_box_size.block, + content_max_box_size.block, + ) }), inline: inline_size, }; @@ -1154,8 +1186,8 @@ impl NonReplacedFormattingContext { // Create a PlacementAmongFloats using the minimum size in all dimensions as the object size. let minimum_size_of_block = LogicalVec2 { - inline: min_box_size.inline, - block: block_size.auto_is(|| min_box_size.block), + inline: content_min_box_size.inline, + block: block_size.auto_is(|| content_min_box_size.block), } + pbm.padding_border_sums; let mut placement = PlacementAmongFloats::new( &sequential_layout_state.floats, @@ -1170,7 +1202,10 @@ impl NonReplacedFormattingContext { placement_rect = placement.place(); let proposed_inline_size = (placement_rect.size.inline - pbm.padding_border_sums.inline) - .clamp_between_extremums(min_box_size.inline, max_box_size.inline); + .clamp_between_extremums( + content_min_box_size.inline, + content_max_box_size.inline, + ); // Now lay out the block using the inline size we calculated from the placement. // Later we'll check to see if the resulting block size is compatible with the @@ -1208,9 +1243,10 @@ impl NonReplacedFormattingContext { } else { content_size = LogicalVec2 { block: block_size.auto_is(|| { - layout - .content_block_size - .clamp_between_extremums(min_box_size.block, max_box_size.block) + layout.content_block_size.clamp_between_extremums( + content_min_box_size.block, + content_max_box_size.block, + ) }), inline: proposed_inline_size, }; @@ -1289,11 +1325,17 @@ impl NonReplacedFormattingContext { }, size: content_size, }; - let block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin); + + let mut base_fragment_info = self.base_fragment_info; + if depends_on_block_constraints { + base_fragment_info.flags.insert( + FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM, + ); + } let containing_block_writing_mode = containing_block.style.writing_mode; BoxFragment::new( - self.base_fragment_info, + base_fragment_info, self.style.clone(), layout.fragments, content_rect.to_physical(Some(containing_block)), @@ -1301,7 +1343,7 @@ impl NonReplacedFormattingContext { pbm.border.to_physical(containing_block_writing_mode), margin.to_physical(containing_block_writing_mode), clearance, - block_margins_collapsed_with_children, + CollapsedBlockMargins::from_margin(&margin), ) .with_baselines(layout.baselines) } @@ -1312,18 +1354,25 @@ impl NonReplacedFormattingContext { /// fn layout_in_flow_replaced_block_level( containing_block: &ContainingBlock, - base_fragment_info: BaseFragmentInfo, + mut base_fragment_info: BaseFragmentInfo, style: &Arc, replaced: &ReplacedContent, mut sequential_layout_state: Option<&mut SequentialLayoutState>, ) -> BoxFragment { - let pbm = style.padding_border_margin(containing_block); - let content_size = replaced.used_size_as_if_inline_element(containing_block, style, &pbm); + let content_box_sizes_and_pbm: ContentBoxSizesAndPBMDeprecated = style + .content_box_sizes_and_padding_border_margin(&containing_block.into()) + .into(); + let pbm = &content_box_sizes_and_pbm.pbm; + let content_size = replaced.used_size_as_if_inline_element( + containing_block, + style, + &content_box_sizes_and_pbm, + ); let margin_inline_start; let margin_inline_end; let effective_margin_inline_start; - let (margin_block_start, margin_block_end) = solve_block_margins_for_in_flow_block_level(&pbm); + let (margin_block_start, margin_block_end) = solve_block_margins_for_in_flow_block_level(pbm); let containing_block_writing_mode = containing_block.style.writing_mode; let physical_content_size = content_size.to_physical_size(containing_block_writing_mode); @@ -1351,7 +1400,7 @@ fn layout_in_flow_replaced_block_level( sequential_layout_state, &collapsed_margin_block_start, containing_block, - &pbm, + pbm, size, style, ); @@ -1375,7 +1424,7 @@ fn layout_in_flow_replaced_block_level( effective_margin_inline_start, ) = solve_inline_margins_for_in_flow_block_level( containing_block, - &pbm, + pbm, content_size.inline, ); }; @@ -1399,7 +1448,11 @@ fn layout_in_flow_replaced_block_level( } .to_physical(Some(containing_block)); - let block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin); + if content_box_sizes_and_pbm.depends_on_block_constraints { + base_fragment_info + .flags + .insert(FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM); + } BoxFragment::new( base_fragment_info, @@ -1410,7 +1463,7 @@ fn layout_in_flow_replaced_block_level( pbm.border.to_physical(containing_block_writing_mode), margin.to_physical(containing_block_writing_mode), clearance, - block_margins_collapsed_with_children, + CollapsedBlockMargins::from_margin(&margin), ) } @@ -1420,6 +1473,7 @@ struct ContainingBlockPaddingAndBorder<'a> { box_size: LogicalVec2, min_box_size: LogicalVec2, max_box_size: LogicalVec2>, + depends_on_block_constraints: bool, } struct ResolvedMargins { @@ -1464,19 +1518,24 @@ fn solve_containing_block_padding_and_border_for_in_flow_box<'a>( }, min_box_size: LogicalVec2::default(), max_box_size: LogicalVec2::default(), + depends_on_block_constraints: false, }; } - let pbm = style.padding_border_margin(containing_block); - let box_size = style.content_box_size_deprecated(containing_block, &pbm); - let max_box_size = style.content_max_box_size_deprecated(containing_block, &pbm); - let min_box_size = style - .content_min_box_size_deprecated(containing_block, &pbm) - .auto_is(Au::zero); + let ContentBoxSizesAndPBMDeprecated { + content_box_size, + content_min_box_size, + content_max_box_size, + pbm, + depends_on_block_constraints, + } = style + .content_box_sizes_and_padding_border_margin(&containing_block.into()) + .into(); + let content_min_box_size = content_min_box_size.auto_is(Au::zero); // https://drafts.csswg.org/css2/#the-width-property // https://drafts.csswg.org/css2/visudet.html#min-max-widths - let inline_size = box_size + let inline_size = content_box_size .inline .auto_is(|| { let margin_inline_start = pbm.margin.inline_start.auto_is(Au::zero); @@ -1486,13 +1545,14 @@ fn solve_containing_block_padding_and_border_for_in_flow_box<'a>( margin_inline_start - margin_inline_end }) - .clamp_between_extremums(min_box_size.inline, max_box_size.inline); + .clamp_between_extremums(content_min_box_size.inline, content_max_box_size.inline); // https://drafts.csswg.org/css2/#the-height-property // https://drafts.csswg.org/css2/visudet.html#min-max-heights - let mut block_size = box_size.block; + let mut block_size = content_box_size.block; if let AuOrAuto::LengthPercentage(ref mut block_size) = block_size { - *block_size = block_size.clamp_between_extremums(min_box_size.block, max_box_size.block); + *block_size = block_size + .clamp_between_extremums(content_min_box_size.block, content_max_box_size.block); } let containing_block_for_children = ContainingBlock { @@ -1512,9 +1572,10 @@ fn solve_containing_block_padding_and_border_for_in_flow_box<'a>( ContainingBlockPaddingAndBorder { containing_block: containing_block_for_children, pbm, - box_size, - min_box_size, - max_box_size, + box_size: content_box_size, + min_box_size: content_min_box_size, + max_box_size: content_max_box_size, + depends_on_block_constraints, } } @@ -1942,7 +2003,9 @@ impl IndependentFormattingContext { ) -> IndependentLayoutResult { let style = self.style(); let container_writing_mode = containing_block.style.writing_mode; - let pbm = style.padding_border_margin(containing_block); + let content_box_sizes_and_pbm = + style.content_box_sizes_and_padding_border_margin(&containing_block.into()); + let pbm = &content_box_sizes_and_pbm.pbm; let margin = pbm.margin.auto_is(Au::zero); let pbm_sums = pbm.padding + pbm.border + margin; @@ -1952,7 +2015,11 @@ impl IndependentFormattingContext { // https://drafts.csswg.org/css2/visudet.html#inline-replaced-height let content_size = replaced .contents - .used_size_as_if_inline_element(containing_block, &replaced.style, &pbm) + .used_size_as_if_inline_element( + containing_block, + &replaced.style, + &content_box_sizes_and_pbm.clone().into(), + ) .to_physical_size(container_writing_mode); let fragments = replaced.contents.make_fragments( &replaced.style, @@ -1965,25 +2032,24 @@ impl IndependentFormattingContext { }, IndependentFormattingContext::NonReplaced(non_replaced) => { let style = non_replaced.style.clone(); - let box_size = style.content_box_size(containing_block, &pbm); - let max_box_size = style.content_max_box_size(containing_block, &pbm); - let min_box_size = style.content_min_box_size(containing_block, &pbm); - let available_inline_size = (containing_block.inline_size - pbm_sums.inline_sum()).max(Au::zero()); let available_block_size = containing_block .block_size .non_auto() .map(|block_size| (block_size - pbm_sums.block_sum()).max(Au::zero())); - let tentative_block_size = box_size + let tentative_block_size = content_box_sizes_and_pbm + .content_box_size .block .maybe_resolve_extrinsic(available_block_size) .map(|size| { - let min_block_size = min_box_size + let min_block_size = content_box_sizes_and_pbm + .content_min_box_size .block .maybe_resolve_extrinsic(available_block_size) .unwrap_or_default(); - let max_block_size = max_box_size + let max_block_size = content_box_sizes_and_pbm + .content_max_box_size .block .maybe_resolve_extrinsic(available_block_size); size.clamp_between_extremums(min_block_size, max_block_size) @@ -2003,20 +2069,23 @@ impl IndependentFormattingContext { // https://drafts.csswg.org/css2/visudet.html#float-width // https://drafts.csswg.org/css2/visudet.html#inlineblock-width - let tentative_inline_size = box_size.inline.resolve( - Size::FitContent, - available_inline_size, - &mut get_content_size, - ); + let tentative_inline_size = + content_box_sizes_and_pbm.content_box_size.inline.resolve( + Size::FitContent, + available_inline_size, + &mut get_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 = min_box_size + let min_inline_size = content_box_sizes_and_pbm + .content_min_box_size .inline .resolve_non_initial(available_inline_size, &mut get_content_size) .unwrap_or_default(); - let max_inline_size = max_box_size + let max_inline_size = content_box_sizes_and_pbm + .content_max_box_size .inline .resolve_non_initial(available_inline_size, &mut get_content_size); let inline_size = @@ -2048,11 +2117,13 @@ impl IndependentFormattingContext { let stretch_size = available_block_size.unwrap_or(independent_layout.content_block_size); let mut get_content_size = || independent_layout.content_block_size.into(); - let min_block_size = min_box_size + let min_block_size = content_box_sizes_and_pbm + .content_min_box_size .block .resolve_non_initial(stretch_size, &mut get_content_size) .unwrap_or_default(); - let max_block_size = max_box_size + let max_block_size = content_box_sizes_and_pbm + .content_max_box_size .block .resolve_non_initial(stretch_size, &mut get_content_size); let block_size = tentative_block_size @@ -2077,8 +2148,15 @@ impl IndependentFormattingContext { }, }; + let mut base_fragment_info = self.base_fragment_info(); + if content_box_sizes_and_pbm.depends_on_block_constraints { + base_fragment_info.flags.insert( + FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM, + ); + } + let fragment = BoxFragment::new( - self.base_fragment_info(), + base_fragment_info, self.style().clone(), fragments, content_rect, diff --git a/components/layout_2020/formatting_contexts.rs b/components/layout_2020/formatting_contexts.rs index dc75e150654..d843ca4d32c 100644 --- a/components/layout_2020/formatting_contexts.rs +++ b/components/layout_2020/formatting_contexts.rs @@ -90,6 +90,9 @@ pub(crate) struct IndependentLayout { /// there was one. This is used to propagate baselines to the ancestors of `display: /// inline-block`. pub baselines: Baselines, + + /// Whether or not this layout depends on the containing block size. + pub depends_on_block_constraints: bool, } pub(crate) struct IndependentLayoutResult { diff --git a/components/layout_2020/fragment_tree/base_fragment.rs b/components/layout_2020/fragment_tree/base_fragment.rs index 626b1e15e69..05fe784b01d 100644 --- a/components/layout_2020/fragment_tree/base_fragment.rs +++ b/components/layout_2020/fragment_tree/base_fragment.rs @@ -104,6 +104,10 @@ bitflags! { /// for empty table cells when 'empty-cells' is 'hide' and also table wrappers. This flag /// doesn't avoid hit-testing nor does it prevent the painting outlines. const DO_NOT_PAINT = 1 << 6; + /// Whether or not the size of this fragment depends on the block size of its container + /// and the fragment can be a flex item. This flag is used to cache items during flex + /// layout. + const SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM = 1 << 7; } } diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs index 7dc5ef1d472..e1286905549 100644 --- a/components/layout_2020/positioned.rs +++ b/components/layout_2020/positioned.rs @@ -459,9 +459,15 @@ impl HoistedAbsolutelyPositionedBox { IndependentFormattingContext::Replaced(replaced) => { // https://drafts.csswg.org/css2/visudet.html#abs-replaced-width // https://drafts.csswg.org/css2/visudet.html#abs-replaced-height + let content_box_sizes_and_pbm = + style.content_box_sizes_and_padding_border_margin(&containing_block.into()); let used_size = replaced .contents - .used_size_as_if_inline_element(containing_block, &style, &pbm) + .used_size_as_if_inline_element( + containing_block, + &style, + &content_box_sizes_and_pbm.into(), + ) .map(|size| Size::Numeric(*size)); (used_size, Default::default(), Default::default()) }, @@ -477,7 +483,7 @@ impl HoistedAbsolutelyPositionedBox { .static_position_rect .to_logical(containing_block); - let box_offset = style.box_offsets(containing_block); + let box_offset = style.box_offsets(containing_block.style.writing_mode); // When the "static-position rect" doesn't come into play, we do not do any alignment // in the inline axis. @@ -982,7 +988,7 @@ pub(crate) fn relative_adjustement( let cbis = containing_block.inline_size; let cbbs = containing_block.block_size; let box_offsets = style - .box_offsets(containing_block) + .box_offsets(containing_block.style.writing_mode) .map_inline_and_block_axes( |value| value.map(|value| value.to_used_value(cbis)), |value| match cbbs.non_auto() { diff --git a/components/layout_2020/replaced.rs b/components/layout_2020/replaced.rs index a240c10ba03..290d792c5c2 100644 --- a/components/layout_2020/replaced.rs +++ b/components/layout_2020/replaced.rs @@ -30,7 +30,7 @@ use crate::dom::NodeExt; use crate::fragment_tree::{BaseFragmentInfo, Fragment, IFrameFragment, ImageFragment}; use crate::geom::{LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSize}; use crate::sizing::InlineContentSizesResult; -use crate::style_ext::{AspectRatio, Clamp, ComputedValuesExt, PaddingBorderMargin}; +use crate::style_ext::{AspectRatio, Clamp, ComputedValuesExt, ContentBoxSizesAndPBMDeprecated}; use crate::{AuOrAuto, ContainingBlock, IndefiniteContainingBlock}; #[derive(Debug, Serialize)] @@ -430,24 +430,22 @@ impl ReplacedContent { &self, containing_block: &ContainingBlock, style: &ComputedValues, - pbm: &PaddingBorderMargin, + content_box_sizes_and_pbm: &ContentBoxSizesAndPBMDeprecated, ) -> LogicalVec2 { - let box_size = style - .content_box_size_deprecated(containing_block, pbm) - // We need to clamp to zero here to obtain the proper aspect - // ratio when box-sizing is border-box and the inner box size - // would otherwise be negative. + // We need to clamp to zero here to obtain the proper aspect ratio when box-sizing + // is border-box and the inner box size would otherwise be negative. + let content_box_size = content_box_sizes_and_pbm + .content_box_size .map(|value| value.map(|value| value.max(Au::zero()))); - let min_box_size = style - .content_min_box_size_deprecated(containing_block, pbm) + let content_min_box_size = content_box_sizes_and_pbm + .content_min_box_size .auto_is(Au::zero); - let max_box_size = style.content_max_box_size_deprecated(containing_block, pbm); self.used_size_as_if_inline_element_from_content_box_sizes( containing_block, style, - box_size, - min_box_size, - max_box_size, + content_box_size, + content_min_box_size, + content_box_sizes_and_pbm.content_max_box_size, ) } diff --git a/components/layout_2020/sizing.rs b/components/layout_2020/sizing.rs index 774ff1ffc57..48018236cc7 100644 --- a/components/layout_2020/sizing.rs +++ b/components/layout_2020/sizing.rs @@ -11,7 +11,7 @@ use serde::Serialize; use style::properties::ComputedValues; use style::Zero; -use crate::style_ext::{Clamp, ComputedValuesExt}; +use crate::style_ext::{Clamp, ComputedValuesExt, ContentBoxSizesAndPBMDeprecated}; use crate::{AuOrAuto, IndefiniteContainingBlock, LogicalVec2}; #[derive(PartialEq)] @@ -120,21 +120,24 @@ pub(crate) fn outer_inline( auto_block_size_stretches_to_containing_block: bool, get_content_size: impl FnOnce(&IndefiniteContainingBlock) -> InlineContentSizesResult, ) -> InlineContentSizesResult { - let ( + let ContentBoxSizesAndPBMDeprecated { content_box_size, - content_min_size, - content_max_size, + content_min_box_size, + content_max_box_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), + } = style + .content_box_sizes_and_padding_border_margin(containing_block) + .into(); + let content_box_min_size = LogicalVec2 { + inline: content_min_box_size.inline.auto_is(|| auto_minimum.inline), + block: content_min_box_size.block.auto_is(|| auto_minimum.block), }; let margin = pbm.margin.map(|v| v.auto_is(Au::zero)); let pbm_inline_sum = pbm.padding_border_sums.inline + margin.inline_sum(); let adjust = |v: Au| { - v.clamp_between_extremums(content_min_size.inline, content_max_size.inline) + pbm_inline_sum + v.clamp_between_extremums(content_box_min_size.inline, content_max_box_size.inline) + + pbm_inline_sum }; match content_box_size.inline { AuOrAuto::LengthPercentage(inline_size) => InlineContentSizesResult { @@ -151,7 +154,9 @@ pub(crate) fn outer_inline( } else { content_box_size.block } - .map(|v| v.clamp_between_extremums(content_min_size.block, content_max_size.block)); + .map(|v| { + v.clamp_between_extremums(content_box_min_size.block, content_max_box_size.block) + }); let containing_block_for_children = IndefiniteContainingBlock::new_for_style_and_block_size(style, block_size); let content_result = get_content_size(&containing_block_for_children); diff --git a/components/layout_2020/style_ext.rs b/components/layout_2020/style_ext.rs index 2dd5f37e7b3..e0a15d99933 100644 --- a/components/layout_2020/style_ext.rs +++ b/components/layout_2020/style_ext.rs @@ -179,12 +179,38 @@ impl AspectRatio { } } +#[derive(Clone)] +pub(crate) struct ContentBoxSizesAndPBM { + pub content_box_size: LogicalVec2>, + pub content_min_box_size: LogicalVec2>, + pub content_max_box_size: LogicalVec2>, + pub pbm: PaddingBorderMargin, + pub depends_on_block_constraints: bool, +} + +impl From 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), + pbm: sizes.pbm.clone(), + depends_on_block_constraints: sizes.depends_on_block_constraints, + } + } +} + +pub(crate) struct ContentBoxSizesAndPBMDeprecated { + pub content_box_size: LogicalVec2, + pub content_min_box_size: LogicalVec2, + pub content_max_box_size: LogicalVec2>, + pub pbm: PaddingBorderMargin, + pub depends_on_block_constraints: bool, +} + pub(crate) trait ComputedValuesExt { fn physical_box_offsets(&self) -> PhysicalSides>; - fn box_offsets( - &self, - containing_block: &ContainingBlock, - ) -> LogicalSides>; + fn box_offsets(&self, writing_mode: WritingMode) -> LogicalSides>; fn box_size( &self, containing_block_writing_mode: WritingMode, @@ -242,27 +268,10 @@ pub(crate) trait ComputedValuesExt { box_size: LogicalVec2>, pbm: &PaddingBorderMargin, ) -> LogicalVec2>; - #[allow(clippy::type_complexity)] fn content_box_sizes_and_padding_border_margin( &self, containing_block: &IndefiniteContainingBlock, - ) -> ( - LogicalVec2>, - LogicalVec2>, - LogicalVec2>, - PaddingBorderMargin, - bool, /* depends_on_block_constraints */ - ); - fn content_box_sizes_and_padding_border_margin_deprecated( - &self, - containing_block: &IndefiniteContainingBlock, - ) -> ( - LogicalVec2, - LogicalVec2, - LogicalVec2>, - PaddingBorderMargin, - bool, /* depends_on_block_constraints */ - ); + ) -> ContentBoxSizesAndPBM; fn padding_border_margin(&self, containing_block: &ContainingBlock) -> PaddingBorderMargin; fn padding_border_margin_for_intrinsic_size( &self, @@ -313,6 +322,10 @@ pub(crate) trait ComputedValuesExt { resolved_auto_value: AlignItems, resolved_normal_value: AlignItems, ) -> AlignItems; + fn depends_on_block_constraints_due_to_relative_positioning( + &self, + writing_mode: WritingMode, + ) -> bool; } impl ComputedValuesExt for ComputedValues { @@ -334,14 +347,8 @@ impl ComputedValuesExt for ComputedValues { ) } - fn box_offsets( - &self, - containing_block: &ContainingBlock, - ) -> LogicalSides> { - LogicalSides::from_physical( - &self.physical_box_offsets(), - containing_block.style.writing_mode, - ) + fn box_offsets(&self, writing_mode: WritingMode) -> LogicalSides> { + LogicalSides::from_physical(&self.physical_box_offsets(), writing_mode) } fn box_size( @@ -500,13 +507,7 @@ impl ComputedValuesExt for ComputedValues { fn content_box_sizes_and_padding_border_margin( &self, containing_block: &IndefiniteContainingBlock, - ) -> ( - LogicalVec2>, - LogicalVec2>, - LogicalVec2>, - PaddingBorderMargin, - bool, /* depends_on_block_constraints */ - ) { + ) -> ContentBoxSizesAndPBM { // // If max size properties or preferred size properties are set to a value containing // indefinite percentages, we treat the entire value as the initial value of the property. @@ -537,54 +538,31 @@ impl ComputedValuesExt for ComputedValues { _ => 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); + depends_on_block_constraints(&max_size.block) || + self.depends_on_block_constraints_due_to_relative_positioning(writing_mode); + 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 = min_size.percentages_relative_to_basis(&containing_block_size_auto_is_zero); - let content_min_size = self + let content_min_box_size = self .content_min_box_size_for_min_size(min_size, &pbm) .map(|v| v.map(Au::from)); let max_size = max_size.maybe_percentages_relative_to_basis(&containing_block_size); - let content_max_size = self + let content_max_box_size = self .content_max_box_size_for_max_size(max_size, &pbm) .map(|v| v.map(Au::from)); - ( + ContentBoxSizesAndPBM { content_box_size, - content_min_size, - content_max_size, + content_min_box_size, + content_max_box_size, pbm, depends_on_block_constraints, - ) - } - - fn content_box_sizes_and_padding_border_margin_deprecated( - &self, - containing_block: &IndefiniteContainingBlock, - ) -> ( - LogicalVec2, - LogicalVec2, - LogicalVec2>, - PaddingBorderMargin, - bool, /* depends_on_block_constraints */ - ) { - 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, - ) + } } fn padding_border_margin(&self, containing_block: &ContainingBlock) -> PaddingBorderMargin { @@ -1031,6 +1009,25 @@ impl ComputedValuesExt for ComputedValues { value => AlignItems(value), } } + + fn depends_on_block_constraints_due_to_relative_positioning( + &self, + writing_mode: WritingMode, + ) -> bool { + if !matches!( + self.get_box().position, + ComputedPosition::Relative | ComputedPosition::Sticky + ) { + return false; + } + let box_offsets = self.box_offsets(writing_mode); + let has_percentage = |offset: LengthPercentageOrAuto<'_>| { + offset + .non_auto() + .is_some_and(LengthPercentage::has_percentage) + }; + has_percentage(box_offsets.block_start) || has_percentage(box_offsets.block_end) + } } impl From for Display { diff --git a/components/layout_2020/table/layout.rs b/components/layout_2020/table/layout.rs index c0c0a92c051..359f6fe5132 100644 --- a/components/layout_2020/table/layout.rs +++ b/components/layout_2020/table/layout.rs @@ -1683,11 +1683,18 @@ impl<'a> TableLayout<'a> { let offset_from_wrapper = -table_pbm.padding - table_pbm.border; let mut current_block_offset = offset_from_wrapper.block_start; + let depends_on_block_constraints = self + .table + .style + .content_box_sizes_and_padding_border_margin(&containing_block_for_table.into()) + .depends_on_block_constraints; + let mut table_layout = IndependentLayout { fragments: Vec::new(), content_block_size: Zero::zero(), content_inline_size_for_table: None, baselines: Baselines::default(), + depends_on_block_constraints, }; table_layout