From 264c0f972fd1a732ee1d1490d78a1d26a65c6f5f Mon Sep 17 00:00:00 2001 From: Martin Robinson Date: Sat, 7 Dec 2024 20:12:25 +0100 Subject: [PATCH] layout: Add `LayoutBoxBase` and use it for `IndependentFormattingContext` (#34507) Add a new struct `LayoutBoxBase`, that will be used throughout the box tree. The idea of this struct is that we have a place to consistently store common layout information (style and node information) and also to cache layout results such as content sizes (inline and maybe later box sizes) and eventually layout results. In addition to the addition of this struct, `IndependentFormattingContext` is flattened slightly so that it directly holds the contents of both replaced and non-replaced elements. This is only added to independent formatting contexts, but will later be added to all block containers as well. Signed-off-by: Martin Robinson --- components/layout_2020/construct_modern.rs | 17 +- components/layout_2020/dom_traversal.rs | 10 +- components/layout_2020/flexbox/layout.rs | 75 ++-- components/layout_2020/flow/inline/mod.rs | 15 +- components/layout_2020/flow/mod.rs | 339 +++++++++--------- components/layout_2020/flow/root.rs | 6 +- components/layout_2020/formatting_contexts.rs | 215 ++++------- components/layout_2020/layout_box_base.rs | 61 ++++ components/layout_2020/lib.rs | 1 + components/layout_2020/lists.rs | 4 +- components/layout_2020/positioned.rs | 34 +- components/layout_2020/replaced.rs | 4 +- components/layout_2020/table/construct.rs | 41 +-- components/layout_2020/table/layout.rs | 6 +- components/layout_2020/table/mod.rs | 4 +- components/layout_2020/taffy/layout.rs | 34 +- 16 files changed, 425 insertions(+), 441 deletions(-) create mode 100644 components/layout_2020/layout_box_base.rs diff --git a/components/layout_2020/construct_modern.rs b/components/layout_2020/construct_modern.rs index 5ff9aa08216..713954a39c8 100644 --- a/components/layout_2020/construct_modern.rs +++ b/components/layout_2020/construct_modern.rs @@ -15,9 +15,10 @@ use crate::dom_traversal::{Contents, NodeAndStyleInfo, TraversalHandler}; use crate::flow::inline::construct::InlineFormattingContextBuilder; use crate::flow::{BlockContainer, BlockFormattingContext}; use crate::formatting_contexts::{ - IndependentFormattingContext, NonReplacedFormattingContext, - NonReplacedFormattingContextContents, + IndependentFormattingContext, IndependentFormattingContextContents, + IndependentNonReplacedContents, }; +use crate::layout_box_base::LayoutBoxBase; use crate::style_ext::DisplayGeneratingBox; /// @@ -173,16 +174,12 @@ where BlockContainer::InlineFormattingContext(inline_formatting_context), ); let info = &self.info.new_anonymous(anonymous_style.clone().unwrap()); - let non_replaced = NonReplacedFormattingContext { - base_fragment_info: info.into(), - style: info.style.clone(), - content_sizes_result: Default::default(), - contents: NonReplacedFormattingContextContents::Flow( - block_formatting_context, + let formatting_context = IndependentFormattingContext { + base: LayoutBoxBase::new(info.into(), info.style.clone()), + contents: IndependentFormattingContextContents::NonReplaced( + IndependentNonReplacedContents::Flow(block_formatting_context), ), }; - let formatting_context = - IndependentFormattingContext::NonReplaced(non_replaced); Some(ModernItem { kind: ModernItemKind::InFlow, diff --git a/components/layout_2020/dom_traversal.rs b/components/layout_2020/dom_traversal.rs index c6a920aa060..2c532e2ebc4 100644 --- a/components/layout_2020/dom_traversal.rs +++ b/components/layout_2020/dom_traversal.rs @@ -16,7 +16,7 @@ use style::values::generics::counters::{Content, ContentItem}; use crate::context::LayoutContext; use crate::dom::{BoxSlot, LayoutBox, NodeExt}; use crate::fragment_tree::{BaseFragmentInfo, FragmentFlags, Tag}; -use crate::replaced::ReplacedContent; +use crate::replaced::ReplacedContents; use crate::style_ext::{Display, DisplayGeneratingBox, DisplayInside, DisplayOutside}; #[derive(Clone, Copy, Debug)] @@ -126,7 +126,7 @@ pub(super) enum Contents { NonReplaced(NonReplacedContents), /// Example: an `` element. /// - Replaced(ReplacedContent), + Replaced(ReplacedContents), } #[derive(Debug)] @@ -141,7 +141,7 @@ pub(super) enum NonReplacedContents { #[derive(Debug)] pub(super) enum PseudoElementContentItem { Text(String), - Replaced(ReplacedContent), + Replaced(ReplacedContents), } pub(super) trait TraversalHandler<'dom, Node> @@ -216,7 +216,7 @@ fn traverse_element<'dom, Node>( ) where Node: NodeExt<'dom>, { - let replaced = ReplacedContent::for_element(element, context); + let replaced = ReplacedContents::for_element(element, context); let style = element.style(context); match Display::from(style.get_box().display) { Display::None => element.unset_all_boxes(), @@ -421,7 +421,7 @@ where }, ContentItem::Image(image) => { if let Some(replaced_content) = - ReplacedContent::from_image(element, context, image) + ReplacedContents::from_image(element, context, image) { vec.push(PseudoElementContentItem::Replaced(replaced_content)); } diff --git a/components/layout_2020/flexbox/layout.rs b/components/layout_2020/flexbox/layout.rs index 0848c3ab2f0..2acdc862de4 100644 --- a/components/layout_2020/flexbox/layout.rs +++ b/components/layout_2020/flexbox/layout.rs @@ -30,7 +30,9 @@ use super::{ }; use crate::cell::ArcRefCell; use crate::context::LayoutContext; -use crate::formatting_contexts::{Baselines, IndependentFormattingContext, IndependentLayout}; +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::positioned::{ @@ -1893,8 +1895,8 @@ impl FlexItem<'_> { }), }; - let context = &self.box_.independent_formatting_context; - let item_writing_mode = context.style().writing_mode; + let independent_formatting_context = &self.box_.independent_formatting_context; + let item_writing_mode = independent_formatting_context.style().writing_mode; let item_is_horizontal = item_writing_mode.is_horizontal(); let flex_axis = flex_context.config.flex_axis; let cross_axis_is_item_block_axis = cross_axis_is_item_block_axis( @@ -1922,7 +1924,7 @@ impl FlexItem<'_> { item_writing_mode, self.preferred_aspect_ratio, ); - context + independent_formatting_context .inline_content_sizes(flex_context.layout_context, &constraint_space) .sizes .shrink_to_fit(stretch_size) @@ -1945,26 +1947,25 @@ impl FlexItem<'_> { }; let container_writing_mode = containing_block.style.writing_mode; - match context { - IndependentFormattingContext::Replaced(replaced) => { - let size = replaced - .contents - .used_size_as_if_inline_element_from_content_box_sizes( - containing_block, - &replaced.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)), - flex_axis.vec2_to_flow_relative(self.pbm_auto_is_zero), - ); + let item_style = independent_formatting_context.style(); + match &independent_formatting_context.contents { + IndependentFormattingContextContents::Replaced(replaced) => { + 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)), + flex_axis.vec2_to_flow_relative(self.pbm_auto_is_zero), + ); let hypothetical_cross_size = flex_axis.vec2_to_flex_relative(size).cross; if let Some(non_stretch_layout_result) = non_stretch_layout_result { @@ -1979,10 +1980,8 @@ impl FlexItem<'_> { } } - let fragments = replaced.contents.make_fragments( - &replaced.style, - size.to_physical_size(container_writing_mode), - ); + let fragments = replaced + .make_fragments(item_style, size.to_physical_size(container_writing_mode)); Some(FlexItemLayoutResult { hypothetical_cross_size, @@ -2000,7 +1999,7 @@ impl FlexItem<'_> { baseline_relative_to_margin_box: None, }) }, - IndependentFormattingContext::NonReplaced(non_replaced) => { + IndependentFormattingContextContents::NonReplaced(non_replaced) => { let calculate_hypothetical_cross_size = |content_block_size| { self.content_box_size .cross @@ -2020,7 +2019,7 @@ impl FlexItem<'_> { let item_as_containing_block = ContainingBlock { inline_size, block_size, - style: &non_replaced.style, + style: item_style, }; if let Some(non_stretch_layout_result) = non_stretch_layout_result { @@ -2067,7 +2066,7 @@ impl FlexItem<'_> { let item_writing_mode_is_orthogonal_to_container_writing_mode = flex_context.config.writing_mode.is_horizontal() != - non_replaced.style.writing_mode.is_horizontal(); + item_style.writing_mode.is_horizontal(); let has_compatible_baseline = match flex_axis { FlexAxis::Row => !item_writing_mode_is_orthogonal_to_container_writing_mode, FlexAxis::Column => item_writing_mode_is_orthogonal_to_container_writing_mode, @@ -2752,8 +2751,9 @@ impl FlexItemBox { .collects_for_nearest_positioned_ancestor(), ); - match &self.independent_formatting_context { - IndependentFormattingContext::Replaced(replaced) => { + let style = self.independent_formatting_context.style(); + match &self.independent_formatting_context.contents { + IndependentFormattingContextContents::Replaced(replaced) => { content_box_size.inline = content_box_size.inline.map(|v| v.max(Au::zero())); if intrinsic_sizing_mode == IntrinsicSizingMode::Size { content_box_size.block = AuOrAuto::Auto; @@ -2761,10 +2761,9 @@ impl FlexItemBox { max_size.block = None; } replaced - .contents .used_size_as_if_inline_element_from_content_box_sizes( flex_context.containing_block, - &replaced.style, + style, preferred_aspect_ratio, content_box_size .map(|size| size.non_auto().map_or(Size::Initial, Size::Numeric)), @@ -2775,7 +2774,7 @@ impl FlexItemBox { ) .block }, - IndependentFormattingContext::NonReplaced(non_replaced) => { + IndependentFormattingContextContents::NonReplaced(non_replaced) => { // TODO: This is wrong if the item writing mode is different from the flex // container's writing mode. let inline_size = content_box_size @@ -2792,7 +2791,7 @@ impl FlexItemBox { } else { let constraint_space = ConstraintSpace::new( SizeConstraint::default(), - non_replaced.style.writing_mode, + style.writing_mode, non_replaced.preferred_aspect_ratio(), ); non_replaced @@ -2808,7 +2807,7 @@ impl FlexItemBox { let item_as_containing_block = ContainingBlock { inline_size, block_size: AuOrAuto::Auto, - style: &non_replaced.style, + style, }; let content_block_size = || { if let Some(cache) = &*self.block_content_size_cache.borrow() { diff --git a/components/layout_2020/flow/inline/mod.rs b/components/layout_2020/flow/inline/mod.rs index d48f765a55c..a23abcd5d89 100644 --- a/components/layout_2020/flow/inline/mod.rs +++ b/components/layout_2020/flow/inline/mod.rs @@ -111,13 +111,14 @@ use webrender_api::FontInstanceKey; use xi_unicode::linebreak_property; use super::float::{Clear, PlacementAmongFloats}; +use super::IndependentFormattingContextContents; use crate::cell::ArcRefCell; use crate::context::LayoutContext; use crate::flow::float::{FloatBox, SequentialLayoutState}; use crate::flow::{CollapsibleWithParentStartMargin, FlowLayout}; use crate::formatting_contexts::{ Baselines, IndependentFormattingContext, IndependentLayoutResult, - NonReplacedFormattingContextContents, + IndependentNonReplacedContents, }; use crate::fragment_tree::{ BoxFragment, CollapsedBlockMargins, CollapsedMargin, Fragment, FragmentFlags, @@ -2034,13 +2035,11 @@ impl IndependentFormattingContext { match self.style().clone_baseline_source() { BaselineSource::First => baselines.first, BaselineSource::Last => baselines.last, - BaselineSource::Auto => { - if let Self::NonReplaced(non_replaced) = self { - if let NonReplacedFormattingContextContents::Flow(_) = non_replaced.contents { - return baselines.last; - } - } - baselines.first + BaselineSource::Auto => match &self.contents { + IndependentFormattingContextContents::NonReplaced( + IndependentNonReplacedContents::Flow(_), + ) => baselines.last, + _ => baselines.first, }, } } diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index 46ccf221b41..4f76a39b6eb 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -27,8 +27,8 @@ use crate::flow::float::{ SequentialLayoutState, }; use crate::formatting_contexts::{ - Baselines, IndependentFormattingContext, IndependentLayout, IndependentLayoutResult, - NonReplacedFormattingContext, + Baselines, IndependentFormattingContext, IndependentFormattingContextContents, + IndependentLayout, IndependentLayoutResult, IndependentNonReplacedContents, }; use crate::fragment_tree::{ BaseFragmentInfo, BoxFragment, CollapsedBlockMargins, CollapsedMargin, Fragment, FragmentFlags, @@ -37,8 +37,9 @@ use crate::geom::{ AuOrAuto, LogicalRect, LogicalSides, LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSides, Size, ToLogical, ToLogicalWithContainingBlock, }; +use crate::layout_box_base::LayoutBoxBase; use crate::positioned::{AbsolutelyPositionedBox, PositioningContext, PositioningContextLength}; -use crate::replaced::ReplacedContent; +use crate::replaced::ReplacedContents; use crate::sizing::{self, ContentSizes, InlineContentSizesResult}; use crate::style_ext::{ Clamp, ComputedValuesExt, ContentBoxSizesAndPBMDeprecated, PaddingBorderMargin, @@ -714,38 +715,20 @@ impl BlockLevelBox { ) }, )), - BlockLevelBox::Independent(independent) => match independent { - IndependentFormattingContext::Replaced(replaced) => { - Fragment::Box(positioning_context.layout_maybe_position_relative_fragment( - layout_context, - containing_block, - &replaced.style, - |_positioning_context| { - layout_in_flow_replaced_block_level( - containing_block, - replaced.base_fragment_info, - &replaced.style, - &replaced.contents, - sequential_layout_state, - ) - }, - )) - }, - IndependentFormattingContext::NonReplaced(non_replaced) => { - Fragment::Box(positioning_context.layout_maybe_position_relative_fragment( - layout_context, - containing_block, - &non_replaced.style, - |positioning_context| { - non_replaced.layout_in_flow_block_level( - layout_context, - positioning_context, - containing_block, - sequential_layout_state, - ) - }, - )) - }, + BlockLevelBox::Independent(independent) => { + Fragment::Box(positioning_context.layout_maybe_position_relative_fragment( + layout_context, + containing_block, + independent.style(), + |positioning_context| { + independent.layout_in_flow_block_level( + layout_context, + positioning_context, + containing_block, + sequential_layout_state, + ) + }, + )) }, BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => { // The static position of zero here is incorrect, however we do not know @@ -1006,7 +989,7 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context( .with_baselines(flow_layout.baselines) } -impl NonReplacedFormattingContext { +impl IndependentNonReplacedContents { /// Lay out a normal in flow non-replaced block that establishes an independent /// formatting context in its containing formatting context. /// @@ -1014,6 +997,7 @@ impl NonReplacedFormattingContext { /// - pub(crate) fn layout_in_flow_block_level( &self, + base: &LayoutBoxBase, layout_context: &LayoutContext, positioning_context: &mut PositioningContext, containing_block: &ContainingBlock, @@ -1021,6 +1005,7 @@ impl NonReplacedFormattingContext { ) -> BoxFragment { if let Some(sequential_layout_state) = sequential_layout_state { return self.layout_in_flow_block_level_sequentially( + base, layout_context, positioning_context, containing_block, @@ -1037,7 +1022,7 @@ impl NonReplacedFormattingContext { depends_on_block_constraints, } = solve_containing_block_padding_and_border_for_in_flow_box( containing_block, - &self.style, + &base.style, ); let layout = self.layout( @@ -1079,7 +1064,7 @@ 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; + let mut base_fragment_info = base.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, @@ -1087,7 +1072,7 @@ impl NonReplacedFormattingContext { } BoxFragment::new( base_fragment_info, - self.style.clone(), + base.style.clone(), layout.fragments, content_rect.to_physical(Some(containing_block)), pbm.padding.to_physical(containing_block_writing_mode), @@ -1104,6 +1089,7 @@ impl NonReplacedFormattingContext { /// layout concerns, such clearing and placing the content next to floats. fn layout_in_flow_block_level_sequentially( &self, + base: &LayoutBoxBase, layout_context: &LayoutContext<'_>, positioning_context: &mut PositioningContext, containing_block: &ContainingBlock<'_>, @@ -1116,7 +1102,7 @@ impl NonReplacedFormattingContext { content_max_box_size, pbm, depends_on_block_constraints, - } = self + } = base .style .content_box_sizes_and_padding_border_margin(&containing_block.into()) .into(); @@ -1147,6 +1133,7 @@ impl NonReplacedFormattingContext { let clearance; let mut content_size; let mut layout; + let style = &base.style; 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); @@ -1156,7 +1143,7 @@ impl NonReplacedFormattingContext { &ContainingBlock { inline_size, block_size, - style: &self.style, + style, }, containing_block, ); @@ -1188,17 +1175,14 @@ impl NonReplacedFormattingContext { containing_block, &pbm, content_size + pbm.padding_border_sums, - &self.style, + style, ); } else { // First compute the clear position required by the 'clear' property. // The code below may then add extra clearance when the element can't fit // next to floats not covered by 'clear'. let clear_position = sequential_layout_state.calculate_clear_position( - Clear::from_style_and_container_writing_mode( - &self.style, - containing_block_writing_mode, - ), + Clear::from_style_and_container_writing_mode(style, containing_block_writing_mode), &collapsed_margin_block_start, ); let ceiling = clear_position.unwrap_or_else(|| { @@ -1238,7 +1222,7 @@ impl NonReplacedFormattingContext { &ContainingBlock { inline_size: proposed_inline_size, block_size, - style: &self.style, + style, }, containing_block, ); @@ -1347,7 +1331,7 @@ impl NonReplacedFormattingContext { size: content_size, }; - let mut base_fragment_info = self.base_fragment_info; + let mut base_fragment_info = base.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, @@ -1356,7 +1340,7 @@ impl NonReplacedFormattingContext { BoxFragment::new( base_fragment_info, - self.style.clone(), + style.clone(), layout.fragments, content_rect.to_physical(Some(containing_block)), pbm.padding.to_physical(containing_block_writing_mode), @@ -1369,121 +1353,127 @@ impl NonReplacedFormattingContext { } } -/// -/// -/// -fn layout_in_flow_replaced_block_level( - containing_block: &ContainingBlock, - mut base_fragment_info: BaseFragmentInfo, - style: &Arc, - replaced: &ReplacedContent, - mut sequential_layout_state: Option<&mut SequentialLayoutState>, -) -> BoxFragment { - 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 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 containing_block_writing_mode = containing_block.style.writing_mode; - let physical_content_size = content_size.to_physical_size(containing_block_writing_mode); - let fragments = replaced.make_fragments(style, physical_content_size); - - let clearance; - if let Some(ref mut sequential_layout_state) = sequential_layout_state { - // From https://drafts.csswg.org/css2/#floats: - // "The border box of a table, a block-level replaced element, or an element in - // the normal flow that establishes a new block formatting context (such as an - // element with overflow other than visible) must not overlap the margin box of - // any floats in the same block formatting context as the element itself. If - // necessary, implementations should clear the said element by placing it below - // any preceding floats, but may place it adjacent to such floats if there is - // sufficient space. They may even make the border box of said element narrower - // than defined by section 10.3.3. CSS 2 does not define when a UA may put said - // element next to the float or by how much said element may become narrower." - let collapsed_margin_block_start = CollapsedMargin::new(margin_block_start); - let size = content_size + pbm.padding_border_sums; - ( - clearance, - (margin_inline_start, margin_inline_end), - effective_margin_inline_start, - ) = solve_clearance_and_inline_margins_avoiding_floats( - sequential_layout_state, - &collapsed_margin_block_start, +impl ReplacedContents { + /// + /// + /// + fn layout_in_flow_block_level( + &self, + base: &LayoutBoxBase, + containing_block: &ContainingBlock, + mut sequential_layout_state: Option<&mut SequentialLayoutState>, + ) -> BoxFragment { + let content_box_sizes_and_pbm = base + .style + .content_box_sizes_and_padding_border_margin(&containing_block.into()); + let pbm = &content_box_sizes_and_pbm.pbm; + let content_size = self.used_size_as_if_inline_element( containing_block, - pbm, - size, - style, + &base.style, + &content_box_sizes_and_pbm, ); - // Clearance prevents margin collapse between this block and previous ones, - // so in that case collapse margins before adjoining them below. - if clearance.is_some() { + 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 containing_block_writing_mode = containing_block.style.writing_mode; + let physical_content_size = content_size.to_physical_size(containing_block_writing_mode); + let fragments = self.make_fragments(&base.style, physical_content_size); + + let clearance; + if let Some(ref mut sequential_layout_state) = sequential_layout_state { + // From https://drafts.csswg.org/css2/#floats: + // "The border box of a table, a block-level replaced element, or an element in + // the normal flow that establishes a new block formatting context (such as an + // element with overflow other than visible) must not overlap the margin box of + // any floats in the same block formatting context as the element itself. If + // necessary, implementations should clear the said element by placing it below + // any preceding floats, but may place it adjacent to such floats if there is + // sufficient space. They may even make the border box of said element narrower + // than defined by section 10.3.3. CSS 2 does not define when a UA may put said + // element next to the float or by how much said element may become narrower." + let collapsed_margin_block_start = CollapsedMargin::new(margin_block_start); + let size = content_size + pbm.padding_border_sums; + ( + clearance, + (margin_inline_start, margin_inline_end), + effective_margin_inline_start, + ) = solve_clearance_and_inline_margins_avoiding_floats( + sequential_layout_state, + &collapsed_margin_block_start, + containing_block, + pbm, + size, + &base.style, + ); + + // Clearance prevents margin collapse between this block and previous ones, + // so in that case collapse margins before adjoining them below. + if clearance.is_some() { + sequential_layout_state.collapse_margins(); + } + sequential_layout_state.adjoin_assign(&collapsed_margin_block_start); + + // Margins can never collapse into replaced elements. sequential_layout_state.collapse_margins(); + sequential_layout_state + .advance_block_position(size.block + clearance.unwrap_or_else(Au::zero)); + sequential_layout_state.adjoin_assign(&CollapsedMargin::new(margin_block_end)); + } else { + clearance = None; + ( + (margin_inline_start, margin_inline_end), + effective_margin_inline_start, + ) = solve_inline_margins_for_in_flow_block_level( + containing_block, + pbm, + content_size.inline, + ); + }; + + let margin = LogicalSides { + inline_start: margin_inline_start, + inline_end: margin_inline_end, + block_start: margin_block_start, + block_end: margin_block_end, + }; + + let start_corner = LogicalVec2 { + block: pbm.padding.block_start + + pbm.border.block_start + + clearance.unwrap_or_else(Au::zero), + inline: pbm.padding.inline_start + + pbm.border.inline_start + + effective_margin_inline_start, + }; + let content_rect = LogicalRect { + start_corner, + size: content_size, } - sequential_layout_state.adjoin_assign(&collapsed_margin_block_start); + .to_physical(Some(containing_block)); - // Margins can never collapse into replaced elements. - sequential_layout_state.collapse_margins(); - sequential_layout_state - .advance_block_position(size.block + clearance.unwrap_or_else(Au::zero)); - sequential_layout_state.adjoin_assign(&CollapsedMargin::new(margin_block_end)); - } else { - clearance = None; - ( - (margin_inline_start, margin_inline_end), - effective_margin_inline_start, - ) = solve_inline_margins_for_in_flow_block_level( - containing_block, - pbm, - content_size.inline, - ); - }; + let mut base_fragment_info = base.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 margin = LogicalSides { - inline_start: margin_inline_start, - inline_end: margin_inline_end, - block_start: margin_block_start, - block_end: margin_block_end, - }; - - let start_corner = LogicalVec2 { - block: pbm.padding.block_start + - pbm.border.block_start + - clearance.unwrap_or_else(Au::zero), - inline: pbm.padding.inline_start + pbm.border.inline_start + effective_margin_inline_start, - }; - let content_rect = LogicalRect { - start_corner, - size: content_size, + BoxFragment::new( + base_fragment_info, + base.style.clone(), + fragments, + content_rect, + pbm.padding.to_physical(containing_block_writing_mode), + pbm.border.to_physical(containing_block_writing_mode), + margin.to_physical(containing_block_writing_mode), + clearance, + CollapsedBlockMargins::from_margin(&margin), + ) } - .to_physical(Some(containing_block)); - - 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, - style.clone(), - fragments, - content_rect, - pbm.padding.to_physical(containing_block_writing_mode), - pbm.border.to_physical(containing_block_writing_mode), - margin.to_physical(containing_block_writing_mode), - clearance, - CollapsedBlockMargins::from_margin(&margin), - ) } struct ContainingBlockPaddingAndBorder<'a> { @@ -2017,6 +2007,26 @@ fn block_size_is_zero_or_intrinsic(size: &StyleSize, containing_block: &Containi } impl IndependentFormattingContext { + pub(crate) fn layout_in_flow_block_level( + &self, + layout_context: &LayoutContext, + positioning_context: &mut PositioningContext, + containing_block: &ContainingBlock, + sequential_layout_state: Option<&mut SequentialLayoutState>, + ) -> BoxFragment { + match &self.contents { + IndependentFormattingContextContents::NonReplaced(contents) => contents + .layout_in_flow_block_level( + &self.base, + layout_context, + positioning_context, + containing_block, + sequential_layout_state, + ), + IndependentFormattingContextContents::Replaced(contents) => contents + .layout_in_flow_block_level(&self.base, containing_block, sequential_layout_state), + } + } pub(crate) fn layout_float_or_atomic_inline( &self, layout_context: &LayoutContext, @@ -2031,27 +2041,24 @@ impl IndependentFormattingContext { let margin = pbm.margin.auto_is(Au::zero); let pbm_sums = pbm.padding + pbm.border + margin; - let (fragments, content_rect, baselines) = match self { - IndependentFormattingContext::Replaced(replaced) => { + let (fragments, content_rect, baselines) = match &self.contents { + IndependentFormattingContextContents::Replaced(replaced) => { // https://drafts.csswg.org/css2/visudet.html#float-replaced-width // 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, + style, &content_box_sizes_and_pbm, ) .to_physical_size(container_writing_mode); - let fragments = replaced - .contents - .make_fragments(&replaced.style, content_size); + let fragments = replaced.make_fragments(style, content_size); let content_rect = PhysicalRect::new(PhysicalPoint::zero(), content_size); (fragments, content_rect, None) }, - IndependentFormattingContext::NonReplaced(non_replaced) => { - let writing_mode = non_replaced.style.writing_mode; + IndependentFormattingContextContents::NonReplaced(non_replaced) => { + let writing_mode = self.style().writing_mode; let available_inline_size = (containing_block.inline_size - pbm_sums.inline_sum()).max(Au::zero()); let available_block_size = containing_block @@ -2110,7 +2117,7 @@ impl IndependentFormattingContext { let containing_block_for_children = ContainingBlock { inline_size, block_size: tentative_block_size.to_auto_or(), - style: &non_replaced.style, + style: self.style(), }; assert_eq!( container_writing_mode.is_horizontal(), diff --git a/components/layout_2020/flow/root.rs b/components/layout_2020/flow/root.rs index b1c62416ecc..f9828e2308a 100644 --- a/components/layout_2020/flow/root.rs +++ b/components/layout_2020/flow/root.rs @@ -28,7 +28,7 @@ use crate::formatting_contexts::IndependentFormattingContext; use crate::fragment_tree::FragmentTree; use crate::geom::{LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSize}; use crate::positioned::{AbsolutelyPositionedBox, PositioningContext}; -use crate::replaced::ReplacedContent; +use crate::replaced::ReplacedContents; use crate::style_ext::{ComputedValuesExt, Display, DisplayGeneratingBox, DisplayInside}; use crate::taffy::{TaffyItemBox, TaffyItemBoxInner}; use crate::DefiniteContainingBlock; @@ -222,7 +222,7 @@ impl BoxTree { loop { if let Some((primary_style, display_inside, update_point)) = update_point(dirty_node) { - let contents = ReplacedContent::for_element(dirty_node, context) + let contents = ReplacedContents::for_element(dirty_node, context) .map_or_else(|| NonReplacedContents::OfElement.into(), Contents::Replaced); let info = NodeAndStyleInfo::new(dirty_node, Arc::clone(&primary_style)); let out_of_flow_absolutely_positioned_box = ArcRefCell::new( @@ -290,7 +290,7 @@ fn construct_for_root_element<'dom>( Display::GeneratingBox(display_generating_box) => display_generating_box.display_inside(), }; - let contents = ReplacedContent::for_element(root_element, context) + let contents = ReplacedContents::for_element(root_element, context) .map_or_else(|| NonReplacedContents::OfElement.into(), Contents::Replaced); let root_box = if box_style.position.is_absolutely_positioned() { BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(ArcRefCell::new( diff --git a/components/layout_2020/formatting_contexts.rs b/components/layout_2020/formatting_contexts.rs index 8e22ef33122..d1bc21448a1 100644 --- a/components/layout_2020/formatting_contexts.rs +++ b/components/layout_2020/formatting_contexts.rs @@ -3,7 +3,6 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use app_units::Au; -use atomic_refcell::AtomicRefCell; use serde::Serialize; use servo_arc::Arc; use style::properties::ComputedValues; @@ -17,46 +16,32 @@ use crate::flexbox::FlexContainer; use crate::flow::BlockFormattingContext; use crate::fragment_tree::{BaseFragmentInfo, BoxFragment, Fragment, FragmentFlags}; use crate::geom::LogicalSides; +use crate::layout_box_base::LayoutBoxBase; use crate::positioned::PositioningContext; -use crate::replaced::ReplacedContent; +use crate::replaced::ReplacedContents; use crate::sizing::{self, InlineContentSizesResult}; use crate::style_ext::{AspectRatio, DisplayInside}; use crate::table::Table; use crate::taffy::TaffyContainer; -use crate::{ - ConstraintSpace, ContainingBlock, IndefiniteContainingBlock, LogicalVec2, SizeConstraint, -}; +use crate::{ConstraintSpace, ContainingBlock, IndefiniteContainingBlock, LogicalVec2}; /// #[derive(Debug, Serialize)] -pub(crate) enum IndependentFormattingContext { - NonReplaced(NonReplacedFormattingContext), - Replaced(ReplacedFormattingContext), +pub(crate) struct IndependentFormattingContext { + pub base: LayoutBoxBase, + pub contents: IndependentFormattingContextContents, } #[derive(Debug, Serialize)] -pub(crate) struct NonReplacedFormattingContext { - pub base_fragment_info: BaseFragmentInfo, - #[serde(skip_serializing)] - pub style: Arc, - /// If it was requested during construction - #[serde(skip_serializing)] - pub content_sizes_result: AtomicRefCell>, - pub contents: NonReplacedFormattingContextContents, -} - -#[derive(Debug, Serialize)] -pub(crate) struct ReplacedFormattingContext { - pub base_fragment_info: BaseFragmentInfo, - #[serde(skip_serializing)] - pub style: Arc, - pub contents: ReplacedContent, +pub(crate) enum IndependentFormattingContextContents { + NonReplaced(IndependentNonReplacedContents), + Replaced(ReplacedContents), } // Private so that code outside of this module cannot match variants. // It should got through methods instead. #[derive(Debug, Serialize)] -pub(crate) enum NonReplacedFormattingContextContents { +pub(crate) enum IndependentNonReplacedContents { Flow(BlockFormattingContext), Flex(FlexContainer), Grid(TaffyContainer), @@ -115,24 +100,23 @@ impl IndependentFormattingContext { contents: Contents, propagated_text_decoration_line: TextDecorationLine, ) -> Self { + let mut base_fragment_info: BaseFragmentInfo = node_and_style_info.into(); + match contents { Contents::NonReplaced(non_replaced_contents) => { - let mut base_fragment_info: BaseFragmentInfo = node_and_style_info.into(); let contents = match display_inside { DisplayInside::Flow { is_list_item } | DisplayInside::FlowRoot { is_list_item } => { - NonReplacedFormattingContextContents::Flow( - BlockFormattingContext::construct( - context, - node_and_style_info, - non_replaced_contents, - propagated_text_decoration_line, - is_list_item, - ), - ) + IndependentNonReplacedContents::Flow(BlockFormattingContext::construct( + context, + node_and_style_info, + non_replaced_contents, + propagated_text_decoration_line, + is_list_item, + )) }, DisplayInside::Grid => { - NonReplacedFormattingContextContents::Grid(TaffyContainer::construct( + IndependentNonReplacedContents::Grid(TaffyContainer::construct( context, node_and_style_info, non_replaced_contents, @@ -140,7 +124,7 @@ impl IndependentFormattingContext { )) }, DisplayInside::Flex => { - NonReplacedFormattingContextContents::Flex(FlexContainer::construct( + IndependentNonReplacedContents::Flex(FlexContainer::construct( context, node_and_style_info, non_replaced_contents, @@ -157,7 +141,7 @@ impl IndependentFormattingContext { &node_and_style_info.style, ); base_fragment_info.flags.insert(FragmentFlags::DO_NOT_PAINT); - NonReplacedFormattingContextContents::Table(Table::construct( + IndependentNonReplacedContents::Table(Table::construct( context, node_and_style_info, table_grid_style, @@ -166,41 +150,36 @@ impl IndependentFormattingContext { )) }, }; - Self::NonReplaced(NonReplacedFormattingContext { - style: Arc::clone(&node_and_style_info.style), - base_fragment_info, - content_sizes_result: AtomicRefCell::default(), - contents, - }) + Self { + base: LayoutBoxBase::new(base_fragment_info, node_and_style_info.style.clone()), + contents: IndependentFormattingContextContents::NonReplaced(contents), + } }, Contents::Replaced(contents) => { - let mut base_fragment_info: BaseFragmentInfo = node_and_style_info.into(); base_fragment_info.flags.insert(FragmentFlags::IS_REPLACED); - Self::Replaced(ReplacedFormattingContext { - base_fragment_info, - style: Arc::clone(&node_and_style_info.style), - contents, - }) + Self { + base: LayoutBoxBase::new(base_fragment_info, node_and_style_info.style.clone()), + contents: IndependentFormattingContextContents::Replaced(contents), + } }, } } pub fn is_replaced(&self) -> bool { - matches!(self, Self::Replaced(_)) + matches!( + self.contents, + IndependentFormattingContextContents::Replaced(_) + ) } + #[inline] pub fn style(&self) -> &Arc { - match self { - Self::NonReplaced(inner) => &inner.style, - Self::Replaced(inner) => &inner.style, - } + &self.base.style } + #[inline] pub fn base_fragment_info(&self) -> BaseFragmentInfo { - match self { - Self::NonReplaced(inner) => inner.base_fragment_info, - Self::Replaced(inner) => inner.base_fragment_info, - } + self.base.base_fragment_info } pub(crate) fn inline_content_sizes( @@ -208,14 +187,15 @@ impl IndependentFormattingContext { layout_context: &LayoutContext, constraint_space: &ConstraintSpace, ) -> InlineContentSizesResult { - match self { - Self::NonReplaced(inner) => { - inner.inline_content_sizes(layout_context, constraint_space) - }, - Self::Replaced(inner) => inner - .contents - .inline_content_sizes(layout_context, constraint_space), - } + self.base + .inline_content_sizes(constraint_space, || match &self.contents { + IndependentFormattingContextContents::NonReplaced(contents) => { + contents.inline_content_sizes(layout_context, constraint_space) + }, + IndependentFormattingContextContents::Replaced(contents) => { + contents.inline_content_sizes(layout_context, constraint_space) + }, + }) } pub(crate) fn outer_inline_content_sizes( @@ -225,40 +205,32 @@ impl IndependentFormattingContext { auto_minimum: &LogicalVec2, auto_block_size_stretches_to_containing_block: bool, ) -> InlineContentSizesResult { - match self { - Self::NonReplaced(non_replaced) => non_replaced.outer_inline_content_sizes( - layout_context, - containing_block, - auto_minimum, - auto_block_size_stretches_to_containing_block, - ), - Self::Replaced(replaced) => sizing::outer_inline( - &replaced.style, - containing_block, - auto_minimum, - auto_block_size_stretches_to_containing_block, - |padding_border_sums| replaced.preferred_aspect_ratio(padding_border_sums), - |constraint_space| { - replaced - .contents - .inline_content_sizes(layout_context, constraint_space) - }, - ), - } + sizing::outer_inline( + self.style(), + containing_block, + auto_minimum, + auto_block_size_stretches_to_containing_block, + |padding_border_sums| self.preferred_aspect_ratio(padding_border_sums), + |constraint_space| self.inline_content_sizes(layout_context, constraint_space), + ) } pub(crate) fn preferred_aspect_ratio( &self, padding_border_sums: &LogicalVec2, ) -> Option { - match self { - Self::NonReplaced(non_replaced) => non_replaced.preferred_aspect_ratio(), - Self::Replaced(replaced) => replaced.preferred_aspect_ratio(padding_border_sums), + match &self.contents { + IndependentFormattingContextContents::NonReplaced(content) => { + content.preferred_aspect_ratio() + }, + IndependentFormattingContextContents::Replaced(content) => { + content.preferred_aspect_ratio(self.style(), padding_border_sums) + }, } } } -impl NonReplacedFormattingContext { +impl IndependentNonReplacedContents { pub fn layout( &self, layout_context: &LayoutContext, @@ -266,25 +238,25 @@ impl NonReplacedFormattingContext { containing_block_for_children: &ContainingBlock, containing_block: &ContainingBlock, ) -> IndependentLayout { - match &self.contents { - NonReplacedFormattingContextContents::Flow(bfc) => bfc.layout( + match self { + IndependentNonReplacedContents::Flow(bfc) => bfc.layout( layout_context, positioning_context, containing_block_for_children, ), - NonReplacedFormattingContextContents::Flex(fc) => fc.layout( + IndependentNonReplacedContents::Flex(fc) => fc.layout( layout_context, positioning_context, containing_block_for_children, containing_block, ), - NonReplacedFormattingContextContents::Grid(fc) => fc.layout( + IndependentNonReplacedContents::Grid(fc) => fc.layout( layout_context, positioning_context, containing_block_for_children, containing_block, ), - NonReplacedFormattingContextContents::Table(table) => table.layout( + IndependentNonReplacedContents::Table(table) => table.layout( layout_context, positioning_context, containing_block_for_children, @@ -299,47 +271,6 @@ impl NonReplacedFormattingContext { None } - pub(crate) fn inline_content_sizes( - &self, - layout_context: &LayoutContext, - constraint_space: &ConstraintSpace, - ) -> InlineContentSizesResult { - let mut cache = self.content_sizes_result.borrow_mut(); - if let Some((previous_cb_block_size, result)) = *cache { - if !result.depends_on_block_constraints || - previous_cb_block_size == constraint_space.block_size - { - return result; - } - // TODO: Should we keep multiple caches for various block sizes? - } - - let result = self - .contents - .inline_content_sizes(layout_context, constraint_space); - *cache = Some((constraint_space.block_size, result)); - result - } - - pub(crate) fn outer_inline_content_sizes( - &self, - layout_context: &LayoutContext, - containing_block: &IndefiniteContainingBlock, - auto_minimum: &LogicalVec2, - auto_block_size_stretches_to_containing_block: bool, - ) -> InlineContentSizesResult { - sizing::outer_inline( - &self.style, - containing_block, - auto_minimum, - auto_block_size_stretches_to_containing_block, - |_| self.preferred_aspect_ratio(), - |constraint_space| self.inline_content_sizes(layout_context, constraint_space), - ) - } -} - -impl NonReplacedFormattingContextContents { pub(crate) fn inline_content_sizes( &self, layout_context: &LayoutContext, @@ -355,13 +286,3 @@ impl NonReplacedFormattingContextContents { } } } - -impl ReplacedFormattingContext { - pub(crate) fn preferred_aspect_ratio( - &self, - padding_border_sums: &LogicalVec2, - ) -> Option { - self.contents - .preferred_aspect_ratio(&self.style, padding_border_sums) - } -} diff --git a/components/layout_2020/layout_box_base.rs b/components/layout_2020/layout_box_base.rs new file mode 100644 index 00000000000..10a2d98d149 --- /dev/null +++ b/components/layout_2020/layout_box_base.rs @@ -0,0 +1,61 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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 atomic_refcell::AtomicRefCell; +use serde::Serialize; +use servo_arc::Arc; +use style::properties::ComputedValues; + +use crate::fragment_tree::BaseFragmentInfo; +use crate::geom::SizeConstraint; +use crate::sizing::InlineContentSizesResult; +use crate::ConstraintSpace; + +/// A box tree node that handles containing information about style and the original DOM +/// node or pseudo-element that it is based on. This also handles caching of layout values +/// such as the inline content sizes to avoid recalculating these values during layout +/// passes. +/// +/// In the future, this will hold layout results to support incremental layout. +#[derive(Debug, Serialize)] +pub(crate) struct LayoutBoxBase { + pub base_fragment_info: BaseFragmentInfo, + #[serde(skip_serializing)] + pub style: Arc, + #[serde(skip_serializing)] + pub cached_inline_content_size: + AtomicRefCell>, +} + +impl LayoutBoxBase { + pub(crate) fn new(base_fragment_info: BaseFragmentInfo, style: Arc) -> Self { + Self { + base_fragment_info, + style, + cached_inline_content_size: AtomicRefCell::default(), + } + } + + /// Get the inline content sizes of a box tree node that extends this [`LayoutBoxBase`], fetch + /// the result from a cache when possible. + pub(crate) fn inline_content_sizes( + &self, + constraint_space: &ConstraintSpace, + inline_content_sizes_fn: impl FnOnce() -> InlineContentSizesResult, + ) -> InlineContentSizesResult { + let mut cache = self.cached_inline_content_size.borrow_mut(); + if let Some((previous_cb_block_size, result)) = *cache { + if !result.depends_on_block_constraints || + previous_cb_block_size == constraint_space.block_size + { + return result; + } + // TODO: Should we keep multiple caches for various block sizes? + } + + let result = inline_content_sizes_fn(); + *cache = Some((constraint_space.block_size, result)); + result + } +} diff --git a/components/layout_2020/lib.rs b/components/layout_2020/lib.rs index 64e5e102887..3232a1aac44 100644 --- a/components/layout_2020/lib.rs +++ b/components/layout_2020/lib.rs @@ -14,6 +14,7 @@ pub mod flow; mod formatting_contexts; mod fragment_tree; pub mod geom; +mod layout_box_base; mod taffy; #[macro_use] pub mod layout_debug; diff --git a/components/layout_2020/lists.rs b/components/layout_2020/lists.rs index b0e97ab02e3..ee8db260c8c 100644 --- a/components/layout_2020/lists.rs +++ b/components/layout_2020/lists.rs @@ -10,7 +10,7 @@ use style::values::computed::Image; use crate::context::LayoutContext; use crate::dom::NodeExt; use crate::dom_traversal::{NodeAndStyleInfo, PseudoElementContentItem}; -use crate::replaced::ReplacedContent; +use crate::replaced::ReplacedContents; /// pub(crate) fn make_marker<'dom, Node>( @@ -32,7 +32,7 @@ where // https://drafts.csswg.org/css-lists/#marker-image let marker_image = || match &style.list_style_image { Image::Url(url) => Some(vec![ - PseudoElementContentItem::Replaced(ReplacedContent::from_image_url( + PseudoElementContentItem::Replaced(ReplacedContents::from_image_url( node, context, url, )?), PseudoElementContentItem::Text(" ".into()), diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs index 1cf53ee8768..6fc0ddf66b5 100644 --- a/components/layout_2020/positioned.rs +++ b/components/layout_2020/positioned.rs @@ -20,7 +20,9 @@ use crate::cell::ArcRefCell; use crate::context::LayoutContext; use crate::dom::NodeExt; use crate::dom_traversal::{Contents, NodeAndStyleInfo}; -use crate::formatting_contexts::IndependentFormattingContext; +use crate::formatting_contexts::{ + IndependentFormattingContext, IndependentFormattingContextContents, +}; use crate::fragment_tree::{ BoxFragment, CollapsedBlockMargins, Fragment, FragmentFlags, HoistedSharedFragment, }; @@ -521,24 +523,22 @@ impl HoistedAbsolutelyPositionedBox { flip_anchor: false, }; - if let IndependentFormattingContext::Replaced(replaced) = context { + if let IndependentFormattingContextContents::Replaced(replaced) = &context.contents { // https://drafts.csswg.org/css2/visudet.html#abs-replaced-width // https://drafts.csswg.org/css2/visudet.html#abs-replaced-height let inset_sums = LogicalVec2 { inline: inline_axis_solver.inset_sum(), block: block_axis_solver.inset_sum(), }; - let used_size = replaced - .contents - .used_size_as_if_inline_element_from_content_box_sizes( - containing_block, - &style, - replaced.preferred_aspect_ratio(&pbm.padding_border_sums), - computed_size, - computed_min_size, - computed_max_size, - pbm.padding_border_sums + pbm.margin.auto_is(Au::zero).sum() + inset_sums, - ); + let used_size = replaced.used_size_as_if_inline_element_from_content_box_sizes( + containing_block, + &style, + context.preferred_aspect_ratio(&pbm.padding_border_sums), + computed_size, + computed_min_size, + computed_max_size, + pbm.padding_border_sums + pbm.margin.auto_is(Au::zero).sum() + inset_sums, + ); inline_axis_solver.override_size(used_size.inline); block_axis_solver.override_size(used_size.block); } @@ -561,20 +561,20 @@ impl HoistedAbsolutelyPositionedBox { let mut new_fragment = { let content_size: LogicalVec2; let fragments; - match context { - IndependentFormattingContext::Replaced(replaced) => { + match &context.contents { + IndependentFormattingContextContents::Replaced(replaced) => { // https://drafts.csswg.org/css2/visudet.html#abs-replaced-width // https://drafts.csswg.org/css2/visudet.html#abs-replaced-height content_size = LogicalVec2 { inline: inline_axis.size.to_definite().unwrap(), block: block_axis.size.to_definite().unwrap(), }; - fragments = replaced.contents.make_fragments( + fragments = replaced.make_fragments( &style, content_size.to_physical_size(containing_block_writing_mode), ); }, - IndependentFormattingContext::NonReplaced(non_replaced) => { + IndependentFormattingContextContents::NonReplaced(non_replaced) => { // https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width // https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-height let inline_size = inline_axis.size.to_definite().unwrap(); diff --git a/components/layout_2020/replaced.rs b/components/layout_2020/replaced.rs index c1e4236d052..bedfbf54ffe 100644 --- a/components/layout_2020/replaced.rs +++ b/components/layout_2020/replaced.rs @@ -34,7 +34,7 @@ use crate::style_ext::{AspectRatio, Clamp, ComputedValuesExt, ContentBoxSizesAnd use crate::{ConstraintSpace, ContainingBlock, SizeConstraint}; #[derive(Debug, Serialize)] -pub(crate) struct ReplacedContent { +pub(crate) struct ReplacedContents { pub kind: ReplacedContentKind, natural_size: NaturalSizes, base_fragment_info: BaseFragmentInfo, @@ -140,7 +140,7 @@ pub(crate) enum ReplacedContentKind { Video(Option), } -impl ReplacedContent { +impl ReplacedContents { pub fn for_element<'dom>(element: impl NodeExt<'dom>, context: &LayoutContext) -> Option { if let Some(ref data_attribute_string) = element.as_typeless_object_with_data_attribute() { if let Some(url) = try_to_parse_image_data_url(data_attribute_string) { diff --git a/components/layout_2020/table/construct.rs b/components/layout_2020/table/construct.rs index d57e315d3d8..8eb754d8df5 100644 --- a/components/layout_2020/table/construct.rs +++ b/components/layout_2020/table/construct.rs @@ -25,10 +25,11 @@ use crate::dom::{BoxSlot, NodeExt}; use crate::dom_traversal::{Contents, NodeAndStyleInfo, NonReplacedContents, TraversalHandler}; use crate::flow::{BlockContainerBuilder, BlockFormattingContext}; use crate::formatting_contexts::{ - IndependentFormattingContext, NonReplacedFormattingContext, - NonReplacedFormattingContextContents, + IndependentFormattingContext, IndependentFormattingContextContents, + IndependentNonReplacedContents, }; use crate::fragment_tree::BaseFragmentInfo; +use crate::layout_box_base::LayoutBoxBase; use crate::style_ext::{DisplayGeneratingBox, DisplayLayoutInternal}; /// A reference to a slot and its coordinates in the table @@ -134,12 +135,12 @@ impl Table { let mut table = table_builder.finish(); table.anonymous = true; - IndependentFormattingContext::NonReplaced(NonReplacedFormattingContext { - base_fragment_info: (&anonymous_info).into(), - style: grid_and_wrapper_style, - content_sizes_result: Default::default(), - contents: NonReplacedFormattingContextContents::Table(table), - }) + IndependentFormattingContext { + base: LayoutBoxBase::new((&anonymous_info).into(), grid_and_wrapper_style), + contents: IndependentFormattingContextContents::NonReplaced( + IndependentNonReplacedContents::Table(table), + ), + } } /// Push a new slot into the last row of this table. @@ -853,15 +854,13 @@ where DisplayLayoutInternal::TableCaption => { let contents = match contents.try_into() { Ok(non_replaced_contents) => { - NonReplacedFormattingContextContents::Flow( - BlockFormattingContext::construct( - self.context, - info, - non_replaced_contents, - self.current_text_decoration_line, - false, /* is_list_item */ - ), - ) + IndependentNonReplacedContents::Flow(BlockFormattingContext::construct( + self.context, + info, + non_replaced_contents, + self.current_text_decoration_line, + false, /* is_list_item */ + )) }, Err(_replaced) => { unreachable!("Replaced should not have a LayoutInternal display type."); @@ -869,11 +868,9 @@ where }; let caption = TableCaption { - context: ArcRefCell::new(NonReplacedFormattingContext { - style: info.style.clone(), - base_fragment_info: info.into(), - content_sizes_result: Default::default(), - contents, + context: ArcRefCell::new(IndependentFormattingContext { + base: LayoutBoxBase::new(info.into(), info.style.clone()), + contents: IndependentFormattingContextContents::NonReplaced(contents), }), }; diff --git a/components/layout_2020/table/layout.rs b/components/layout_2020/table/layout.rs index 673beb604ae..ea7714207dd 100644 --- a/components/layout_2020/table/layout.rs +++ b/components/layout_2020/table/layout.rs @@ -1613,7 +1613,7 @@ impl<'a> TableLayout<'a> { parent_positioning_context: &mut PositioningContext, ) -> BoxFragment { let context = caption.context.borrow(); - let mut positioning_context = PositioningContext::new_for_style(&context.style); + let mut positioning_context = PositioningContext::new_for_style(context.style()); let containing_block = &ContainingBlock { inline_size: self.table_width + table_pbm.padding_border_sums.inline, block_size: AuOrAuto::Auto, @@ -1711,7 +1711,7 @@ impl<'a> TableLayout<'a> { table_layout .fragments .extend(self.table.captions.iter().filter_map(|caption| { - if caption.context.borrow().style.clone_caption_side() != CaptionSide::Top { + if caption.context.borrow().style().clone_caption_side() != CaptionSide::Top { return None; } @@ -1811,7 +1811,7 @@ impl<'a> TableLayout<'a> { table_layout .fragments .extend(self.table.captions.iter().filter_map(|caption| { - if caption.context.borrow().style.clone_caption_side() != CaptionSide::Bottom { + if caption.context.borrow().style().clone_caption_side() != CaptionSide::Bottom { return None; } diff --git a/components/layout_2020/table/mod.rs b/components/layout_2020/table/mod.rs index 1e29e605605..5a2c335875d 100644 --- a/components/layout_2020/table/mod.rs +++ b/components/layout_2020/table/mod.rs @@ -82,7 +82,7 @@ use style_traits::dom::OpaqueNode; use super::flow::BlockFormattingContext; use crate::cell::ArcRefCell; use crate::flow::BlockContainer; -use crate::formatting_contexts::NonReplacedFormattingContext; +use crate::formatting_contexts::IndependentFormattingContext; use crate::fragment_tree::BaseFragmentInfo; pub type TableSize = Size2D; @@ -320,5 +320,5 @@ impl TableTrackGroup { #[derive(Debug, Serialize)] pub struct TableCaption { /// The contents of this cell, with its own layout. - context: ArcRefCell, + context: ArcRefCell, } diff --git a/components/layout_2020/taffy/layout.rs b/components/layout_2020/taffy/layout.rs index 33b1ce8a1ab..02c8568c091 100644 --- a/components/layout_2020/taffy/layout.rs +++ b/components/layout_2020/taffy/layout.rs @@ -15,7 +15,10 @@ use taffy::{AvailableSpace, MaybeMath, RequestedAxis, RunMode}; use super::{TaffyContainer, TaffyItemBox, TaffyItemBoxInner, TaffyStyloStyle}; use crate::cell::ArcRefCell; use crate::context::LayoutContext; -use crate::formatting_contexts::{Baselines, IndependentFormattingContext, IndependentLayout}; +use crate::formatting_contexts::{ + Baselines, IndependentFormattingContext, IndependentFormattingContextContents, + IndependentLayout, +}; use crate::fragment_tree::{BoxFragment, CollapsedBlockMargins, Fragment}; use crate::geom::{ LogicalSides, LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSides, PhysicalSize, Size, @@ -43,13 +46,12 @@ fn resolve_content_size(constraint: AvailableSpace, content_sizes: ContentSizes) #[inline(always)] fn with_independant_formatting_context( item: &mut TaffyItemBoxInner, - cb: impl FnOnce(&mut IndependentFormattingContext) -> T, + cb: impl FnOnce(&IndependentFormattingContext) -> T, ) -> T { match item { TaffyItemBoxInner::InFlowBox(ref mut context) => cb(context), TaffyItemBoxInner::OutOfFlowAbsolutelyPositionedBox(ref abspos_box) => { - let mut abspos_box = AtomicRefCell::borrow_mut(abspos_box); - cb(&mut abspos_box.context) + cb(&AtomicRefCell::borrow(abspos_box).context) }, } } @@ -132,13 +134,14 @@ impl taffy::LayoutPartialTree for TaffyContainerContext<'_> { with_independant_formatting_context( &mut child.taffy_level_box, |independent_context| -> taffy::LayoutOutput { - match independent_context { - IndependentFormattingContext::Replaced(replaced) => { + let style = independent_context.style(); + match &independent_context.contents { + IndependentFormattingContextContents::Replaced(replaced) => { // TODO: re-evaluate sizing constraint conversions in light of recent layout_2020 changes let containing_block = &self.content_box_size_override; // Adjust known_dimensions from border box to content box - let pbm = replaced.style.padding_border_margin(containing_block); + let pbm = style.padding_border_margin(containing_block); let pb_sum = pbm.padding_border_sums.map(|v| v.to_f32_px()); let content_box_known_dimensions = taffy::Size { width: inputs @@ -152,11 +155,11 @@ impl taffy::LayoutPartialTree for TaffyContainerContext<'_> { }; let content_box_size = replaced - .contents .used_size_as_if_inline_element_from_content_box_sizes( containing_block, - &replaced.style, - replaced.preferred_aspect_ratio(&pbm.padding_border_sums), + 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), @@ -176,9 +179,8 @@ impl taffy::LayoutPartialTree for TaffyContainerContext<'_> { // Create fragments if the RunMode if PerformLayout // If the RunMode is ComputeSize then only the returned size will be used if inputs.run_mode == RunMode::PerformLayout { - child.child_fragments = replaced - .contents - .make_fragments(&replaced.style, content_box_size); + child.child_fragments = + replaced.make_fragments(style, content_box_size); } let computed_size = taffy::Size { @@ -198,12 +200,12 @@ impl taffy::LayoutPartialTree for TaffyContainerContext<'_> { } }, - IndependentFormattingContext::NonReplaced(non_replaced) => { + IndependentFormattingContextContents::NonReplaced(non_replaced) => { // TODO: re-evaluate sizing constraint conversions in light of recent layout_2020 changes let containing_block = &self.content_box_size_override; // Adjust known_dimensions from border box to content box - let pbm = non_replaced.style.padding_border_margin(containing_block); + let pbm = style.padding_border_margin(containing_block); let margin_sum = pbm.margin.auto_is(Au::zero).sum(); let content_box_inset = (pbm.padding_border_sums + margin_sum).map(|v| v.to_f32_px()); @@ -256,7 +258,7 @@ impl taffy::LayoutPartialTree for TaffyContainerContext<'_> { let content_box_size_override = ContainingBlock { inline_size: Au::from_f32_px(inline_size), block_size: maybe_block_size, - style: &non_replaced.style, + style, }; let layout = {