From b43a3de51dec6019e5edd261b6327d0cdfdf89b3 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 12 Dec 2019 15:37:01 +0100 Subject: [PATCH] Introduce PositioningContext --- components/layout_2020/flow/inline.rs | 21 +++--- components/layout_2020/flow/mod.rs | 65 ++++++++++--------- components/layout_2020/flow/root.rs | 16 +++-- components/layout_2020/formatting_contexts.rs | 6 +- components/layout_2020/positioned.rs | 51 ++++++++++----- 5 files changed, 90 insertions(+), 69 deletions(-) diff --git a/components/layout_2020/flow/inline.rs b/components/layout_2020/flow/inline.rs index c4b760275d9..0a6fc8d87d6 100644 --- a/components/layout_2020/flow/inline.rs +++ b/components/layout_2020/flow/inline.rs @@ -9,7 +9,7 @@ use crate::formatting_contexts::IndependentFormattingContext; use crate::fragments::CollapsedBlockMargins; use crate::fragments::{AnonymousFragment, BoxFragment, Fragment, TextFragment}; use crate::geom::flow_relative::{Rect, Sides, Vec2}; -use crate::positioned::{AbsolutelyPositionedBox, AbsolutelyPositionedFragment}; +use crate::positioned::{AbsolutelyPositionedBox, PositioningContext}; use crate::sizing::ContentSizes; use crate::style_ext::{ComputedValuesExt, Display, DisplayGeneratingBox, DisplayOutside}; use crate::{relative_adjustement, ContainingBlock}; @@ -68,9 +68,9 @@ struct PartialInlineBoxFragment<'box_tree> { parent_nesting_level: InlineNestingLevelState<'box_tree>, } -struct InlineFormattingContextState<'box_tree, 'a> { - absolutely_positioned_fragments: &'a mut Vec>, - containing_block: &'a ContainingBlock<'a>, +struct InlineFormattingContextState<'box_tree, 'a, 'b> { + positioning_context: &'a mut PositioningContext<'box_tree>, + containing_block: &'b ContainingBlock<'b>, lines: Lines, inline_position: Length, partial_inline_boxes_stack: Vec>, @@ -195,12 +195,12 @@ impl InlineFormattingContext { pub(super) fn layout<'a>( &'a self, layout_context: &LayoutContext, + positioning_context: &mut PositioningContext<'a>, containing_block: &ContainingBlock, tree_rank: usize, - absolutely_positioned_fragments: &mut Vec>, ) -> FlowLayout { let mut ifc = InlineFormattingContextState { - absolutely_positioned_fragments, + positioning_context, containing_block, partial_inline_boxes_stack: Vec::new(), lines: Lines { @@ -244,7 +244,8 @@ impl InlineFormattingContext { panic!("display:none does not generate an abspos box") }, }; - ifc.absolutely_positioned_fragments + ifc.positioning_context + .abspos .push(box_.layout(initial_start_corner, tree_rank)); }, InlineLevelBox::OutOfFlowFloatBox(_box_) => { @@ -346,7 +347,7 @@ impl Lines { impl InlineBox { fn start_layout<'box_tree>( &'box_tree self, - ifc: &mut InlineFormattingContextState<'box_tree, '_>, + ifc: &mut InlineFormattingContextState<'box_tree, '_, '_>, ) -> PartialInlineBoxFragment<'box_tree> { let style = self.style.clone(); let cbis = ifc.containing_block.inline_size; @@ -440,7 +441,7 @@ impl<'box_tree> PartialInlineBoxFragment<'box_tree> { fn layout_atomic<'box_tree>( layout_context: &LayoutContext, - ifc: &mut InlineFormattingContextState<'box_tree, '_>, + ifc: &mut InlineFormattingContextState<'box_tree, '_, '_>, atomic: &'box_tree IndependentFormattingContext, ) { let cbis = ifc.containing_block.inline_size; @@ -521,9 +522,9 @@ fn layout_atomic<'box_tree>( // FIXME: Do we need to call `adjust_static_positions` somewhere near here? let independent_layout = non_replaced.layout( layout_context, + ifc.positioning_context, &containing_block_for_children, dummy_tree_rank, - ifc.absolutely_positioned_fragments, ); // https://drafts.csswg.org/css2/visudet.html#block-root-margin diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index 3e45defb365..d79d8eb7253 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -12,7 +12,7 @@ use crate::fragments::{AnonymousFragment, BoxFragment, Fragment}; use crate::fragments::{CollapsedBlockMargins, CollapsedMargin}; use crate::geom::flow_relative::{Rect, Sides, Vec2}; use crate::positioned::adjust_static_positions; -use crate::positioned::{AbsolutelyPositionedBox, AbsolutelyPositionedFragment}; +use crate::positioned::{AbsolutelyPositionedBox, PositioningContext}; use crate::replaced::ReplacedContent; use crate::style_ext::ComputedValuesExt; use crate::{relative_adjustement, ContainingBlock}; @@ -67,9 +67,9 @@ impl BlockFormattingContext { pub(super) fn layout<'a>( &'a self, layout_context: &LayoutContext, + positioning_context: &mut PositioningContext<'a>, containing_block: &ContainingBlock, tree_rank: usize, - absolutely_positioned_fragments: &mut Vec>, ) -> IndependentLayout { let mut float_context; let float_context = if self.contains_floats { @@ -80,9 +80,9 @@ impl BlockFormattingContext { }; let flow_layout = self.contents.layout( layout_context, + positioning_context, containing_block, tree_rank, - absolutely_positioned_fragments, float_context, CollapsibleWithParentStartMargin(false), ); @@ -103,27 +103,27 @@ impl BlockContainer { fn layout<'a>( &'a self, layout_context: &LayoutContext, + positioning_context: &mut PositioningContext<'a>, containing_block: &ContainingBlock, tree_rank: usize, - absolutely_positioned_fragments: &mut Vec>, float_context: Option<&mut FloatContext>, collapsible_with_parent_start_margin: CollapsibleWithParentStartMargin, ) -> FlowLayout { match self { BlockContainer::BlockLevelBoxes(child_boxes) => layout_block_level_children( layout_context, + positioning_context, child_boxes, containing_block, tree_rank, - absolutely_positioned_fragments, float_context, collapsible_with_parent_start_margin, ), BlockContainer::InlineFormattingContext(ifc) => ifc.layout( layout_context, + positioning_context, containing_block, tree_rank, - absolutely_positioned_fragments, ), } } @@ -131,10 +131,10 @@ impl BlockContainer { fn layout_block_level_children<'a>( layout_context: &LayoutContext, + positioning_context: &mut PositioningContext<'a>, child_boxes: &'a [Arc], containing_block: &ContainingBlock, tree_rank: usize, - absolutely_positioned_fragments: &mut Vec>, mut float_context: Option<&mut FloatContext>, collapsible_with_parent_start_margin: CollapsibleWithParentStartMargin, ) -> FlowLayout { @@ -194,7 +194,7 @@ fn layout_block_level_children<'a>( current_block_direction_position: Length, } - let abspos_so_far = absolutely_positioned_fragments.len(); + let abspos_so_far = positioning_context.abspos.len(); let mut placement_state = PlacementState { next_in_flow_margin_collapses_with_parent_start_margin: collapsible_with_parent_start_margin.0, @@ -213,9 +213,9 @@ fn layout_block_level_children<'a>( .map(|(tree_rank, box_)| { let mut fragment = box_.layout( layout_context, + positioning_context, containing_block, tree_rank, - absolutely_positioned_fragments, float_context.as_mut().map(|c| &mut **c), ); place_block_level_fragment(&mut fragment, &mut placement_state); @@ -227,19 +227,17 @@ fn layout_block_level_children<'a>( .par_iter() .enumerate() .mapfold_reduce_into( - absolutely_positioned_fragments, - |abspos_fragments, (tree_rank, box_)| { + positioning_context, + |positioning_context, (tree_rank, box_)| { box_.layout( layout_context, + positioning_context, containing_block, tree_rank, - abspos_fragments, /* float_context = */ None, ) }, - |left_abspos_fragments, mut right_abspos_fragments| { - left_abspos_fragments.append(&mut right_abspos_fragments); - }, + |left, right| left.append(right), ) .collect(); for fragment in &mut fragments { @@ -248,7 +246,7 @@ fn layout_block_level_children<'a>( } adjust_static_positions( - &mut absolutely_positioned_fragments[abspos_so_far..], + &mut positioning_context.abspos[abspos_so_far..], &mut fragments, tree_rank, ); @@ -269,25 +267,27 @@ impl BlockLevelBox { fn layout<'a>( &'a self, layout_context: &LayoutContext, + positioning_context: &mut PositioningContext<'a>, containing_block: &ContainingBlock, tree_rank: usize, - absolutely_positioned_fragments: &mut Vec>, float_context: Option<&mut FloatContext>, ) -> Fragment { match self { BlockLevelBox::SameFormattingContextBlock { style, contents } => { Fragment::Box(layout_in_flow_non_replaced_block_level( layout_context, + positioning_context, containing_block, - absolutely_positioned_fragments, style, BlockLevelKind::SameFormattingContextBlock, - |containing_block, nested_abspos, collapsible_with_parent_start_margin| { + |positioning_context, + containing_block, + collapsible_with_parent_start_margin| { contents.layout( layout_context, + positioning_context, containing_block, tree_rank, - nested_abspos, float_context, collapsible_with_parent_start_margin, ) @@ -302,16 +302,16 @@ impl BlockLevelBox { )), Err(non_replaced) => Fragment::Box(layout_in_flow_non_replaced_block_level( layout_context, + positioning_context, containing_block, - absolutely_positioned_fragments, &contents.style, BlockLevelKind::EstablishesAnIndependentFormattingContext, - |containing_block, nested_abspos, _| { + |positioning_context, containing_block, _| { let independent_layout = non_replaced.layout( layout_context, + positioning_context, containing_block, tree_rank, - nested_abspos, ); FlowLayout { fragments: independent_layout.fragments, @@ -322,7 +322,9 @@ impl BlockLevelBox { )), }, BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => { - absolutely_positioned_fragments.push(box_.layout(Vec2::zero(), tree_rank)); + positioning_context + .abspos + .push(box_.layout(Vec2::zero(), tree_rank)); Fragment::Anonymous(AnonymousFragment::no_op( containing_block.style.writing_mode, )) @@ -347,13 +349,13 @@ enum BlockLevelKind { /// https://drafts.csswg.org/css2/visudet.html#normal-block fn layout_in_flow_non_replaced_block_level<'a>( layout_context: &LayoutContext, + positioning_context: &mut PositioningContext<'a>, containing_block: &ContainingBlock, - absolutely_positioned_fragments: &mut Vec>, style: &Arc, block_level_kind: BlockLevelKind, layout_contents: impl FnOnce( + &mut PositioningContext<'a>, &ContainingBlock, - &mut Vec>, CollapsibleWithParentStartMargin, ) -> FlowLayout, ) -> BoxFragment { @@ -436,14 +438,14 @@ fn layout_in_flow_non_replaced_block_level<'a>( min_box_size.block == Length::zero() && pb.block_end == Length::zero() && block_level_kind == BlockLevelKind::SameFormattingContextBlock; - let mut nested_abspos = vec![]; + let mut nested_positioning_context = PositioningContext { abspos: Vec::new() }; let mut flow_layout = layout_contents( - &containing_block_for_children, if style.get_box().position == Position::Relative { - &mut nested_abspos + &mut nested_positioning_context } else { - absolutely_positioned_fragments + positioning_context }, + &containing_block_for_children, this_start_margin_can_collapse_with_children, ); let mut block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin); @@ -493,9 +495,8 @@ fn layout_in_flow_non_replaced_block_level<'a>( }, }; if style.get_box().position == Position::Relative { - AbsolutelyPositionedFragment::in_positioned_containing_block( + nested_positioning_context.layout_abspos( layout_context, - &nested_abspos, &mut flow_layout.fragments, &content_rect.size, &padding, diff --git a/components/layout_2020/flow/root.rs b/components/layout_2020/flow/root.rs index 15dc6d404b6..71d42643853 100644 --- a/components/layout_2020/flow/root.rs +++ b/components/layout_2020/flow/root.rs @@ -12,7 +12,8 @@ use crate::formatting_contexts::IndependentFormattingContext; use crate::fragments::Fragment; use crate::geom; use crate::geom::flow_relative::Vec2; -use crate::positioned::{AbsolutelyPositionedBox, AbsolutelyPositionedFragment}; +use crate::positioned::PositioningContext; +use crate::positioned::{AbsolutelyPositionedBox, CollectedAbsolutelyPositionedBox}; use crate::replaced::ReplacedContent; use crate::sizing::ContentSizesRequest; use crate::style_ext::{Display, DisplayGeneratingBox, DisplayInside}; @@ -110,24 +111,25 @@ impl BoxTreeRoot { }; let dummy_tree_rank = 0; - let mut absolutely_positioned_fragments = vec![]; + let mut positioning_context = PositioningContext { abspos: Vec::new() }; let mut independent_layout = self.0.layout( layout_context, + &mut positioning_context, &(&initial_containing_block).into(), dummy_tree_rank, - &mut absolutely_positioned_fragments, ); - let map = - |a: &AbsolutelyPositionedFragment| a.layout(layout_context, &initial_containing_block); + let map = |a: &CollectedAbsolutelyPositionedBox| { + a.layout(layout_context, &initial_containing_block) + }; if layout_context.use_rayon { independent_layout .fragments - .par_extend(absolutely_positioned_fragments.par_iter().map(map)) + .par_extend(positioning_context.abspos.par_iter().map(map)) } else { independent_layout .fragments - .extend(absolutely_positioned_fragments.iter().map(map)) + .extend(positioning_context.abspos.iter().map(map)) } FragmentTreeRoot(independent_layout.fragments) diff --git a/components/layout_2020/formatting_contexts.rs b/components/layout_2020/formatting_contexts.rs index eb90d62c926..dcbbfa370a6 100644 --- a/components/layout_2020/formatting_contexts.rs +++ b/components/layout_2020/formatting_contexts.rs @@ -6,7 +6,7 @@ use crate::context::LayoutContext; use crate::dom_traversal::{Contents, NodeExt}; use crate::flow::BlockFormattingContext; use crate::fragments::Fragment; -use crate::positioned::AbsolutelyPositionedFragment; +use crate::positioned::PositioningContext; use crate::replaced::ReplacedContent; use crate::sizing::{BoxContentSizes, ContentSizesRequest}; use crate::style_ext::DisplayInside; @@ -101,16 +101,16 @@ impl<'a> NonReplacedIFC<'a> { pub fn layout( &self, layout_context: &LayoutContext, + positioning_context: &mut PositioningContext<'a>, containing_block: &ContainingBlock, tree_rank: usize, - absolutely_positioned_fragments: &mut Vec>, ) -> IndependentLayout { match &self.0 { NonReplacedIFCKind::Flow(bfc) => bfc.layout( layout_context, + positioning_context, containing_block, tree_rank, - absolutely_positioned_fragments, ), } } diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs index b9c64ea54d3..a8500e59d73 100644 --- a/components/layout_2020/positioned.rs +++ b/components/layout_2020/positioned.rs @@ -21,9 +21,15 @@ pub(crate) struct AbsolutelyPositionedBox { pub contents: IndependentFormattingContext, } +#[derive(Default)] +pub(crate) struct PositioningContext<'box_tree> { + /// With `position: absolute` + pub abspos: Vec>, +} + #[derive(Debug)] -pub(crate) struct AbsolutelyPositionedFragment<'box_> { - absolutely_positioned_box: &'box_ AbsolutelyPositionedBox, +pub(crate) struct CollectedAbsolutelyPositionedBox<'box_tree> { + absolutely_positioned_box: &'box_tree AbsolutelyPositionedBox, /// The rank of the child from which this absolutely positioned fragment /// came from, when doing the layout of a block container. Used to compute @@ -81,7 +87,7 @@ impl AbsolutelyPositionedBox { &'a self, initial_start_corner: Vec2, tree_rank: usize, - ) -> AbsolutelyPositionedFragment { + ) -> CollectedAbsolutelyPositionedBox { fn absolute_box_offsets( initial_static_start: Length, start: LengthPercentageOrAuto, @@ -98,7 +104,7 @@ impl AbsolutelyPositionedBox { } let box_offsets = self.contents.style.box_offsets(); - AbsolutelyPositionedFragment { + CollectedAbsolutelyPositionedBox { absolutely_positioned_box: self, tree_rank, box_offsets: Vec2 { @@ -117,16 +123,25 @@ impl AbsolutelyPositionedBox { } } -impl<'a> AbsolutelyPositionedFragment<'a> { - pub(crate) fn in_positioned_containing_block( +impl PositioningContext<'_> { + /// Unlike `Vec::append`, this takes ownership of the other value. + pub(crate) fn append(&mut self, mut other: Self) { + if self.abspos.is_empty() { + self.abspos = other.abspos + } else { + self.abspos.append(&mut other.abspos) + } + } + + pub(crate) fn layout_abspos( + self, layout_context: &LayoutContext, - absolute: &[Self], fragments: &mut Vec, content_rect_size: &Vec2, padding: &Sides, style: &ComputedValues, ) { - if absolute.is_empty() { + if self.abspos.is_empty() { return; } let padding_rect = Rect { @@ -139,11 +154,12 @@ impl<'a> AbsolutelyPositionedFragment<'a> { size: padding_rect.size.clone(), style, }; - let map = |a: &AbsolutelyPositionedFragment| a.layout(layout_context, &containing_block); + let map = + |a: &CollectedAbsolutelyPositionedBox| a.layout(layout_context, &containing_block); let children = if layout_context.use_rayon { - absolute.par_iter().map(map).collect() + self.abspos.par_iter().map(map).collect() } else { - absolute.iter().map(map).collect() + self.abspos.iter().map(map).collect() }; fragments.push(Fragment::Anonymous(AnonymousFragment { children, @@ -151,7 +167,9 @@ impl<'a> AbsolutelyPositionedFragment<'a> { mode: style.writing_mode, })) } +} +impl CollectedAbsolutelyPositionedBox<'_> { pub(crate) fn layout( &self, layout_context: &LayoutContext, @@ -216,7 +234,7 @@ impl<'a> AbsolutelyPositionedFragment<'a> { block_end: block_axis.margin_end, }; - let mut absolutely_positioned_fragments = Vec::new(); + let mut positioning_context = PositioningContext { abspos: Vec::new() }; let (size, mut fragments) = match self.absolutely_positioned_box.contents.as_replaced() { Ok(replaced) => { // https://drafts.csswg.org/css2/visudet.html#abs-replaced-width @@ -256,9 +274,9 @@ impl<'a> AbsolutelyPositionedFragment<'a> { let dummy_tree_rank = 0; let independent_layout = non_replaced.layout( layout_context, + &mut positioning_context, &containing_block_for_children, dummy_tree_rank, - &mut absolutely_positioned_fragments, ); let size = Vec2 { @@ -288,9 +306,8 @@ impl<'a> AbsolutelyPositionedFragment<'a> { size, }; - AbsolutelyPositionedFragment::in_positioned_containing_block( + positioning_context.layout_abspos( layout_context, - &absolutely_positioned_fragments, &mut fragments, &content_rect.size, &padding, @@ -414,8 +431,8 @@ fn solve_axis( } pub(crate) fn adjust_static_positions( - absolutely_positioned_fragments: &mut [AbsolutelyPositionedFragment], - child_fragments: &mut [Fragment], + absolutely_positioned_fragments: &mut [CollectedAbsolutelyPositionedBox], + child_fragments: &[Fragment], tree_rank_in_parent: usize, ) { for abspos_fragment in absolutely_positioned_fragments {