From b43a3de51dec6019e5edd261b6327d0cdfdf89b3 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 12 Dec 2019 15:37:01 +0100 Subject: [PATCH 01/13] 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 { From 9edda952c9b2c19337e4096b989fcc047c59ea18 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 12 Dec 2019 15:42:40 +0100 Subject: [PATCH 02/13] Make adjust_static_positions a method of PositioningContext --- components/layout_2020/flow/mod.rs | 84 +++++++++++++--------------- components/layout_2020/positioned.rs | 17 +++++- 2 files changed, 55 insertions(+), 46 deletions(-) diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index d79d8eb7253..3c1df828d1f 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -11,7 +11,6 @@ use crate::formatting_contexts::{IndependentFormattingContext, IndependentLayout 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, PositioningContext}; use crate::replaced::ReplacedContent; use crate::style_ext::ComputedValuesExt; @@ -194,7 +193,6 @@ fn layout_block_level_children<'a>( current_block_direction_position: Length, } - 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, @@ -202,54 +200,50 @@ fn layout_block_level_children<'a>( current_margin: CollapsedMargin::zero(), current_block_direction_position: Length::zero(), }; - let mut fragments: Vec<_>; - if float_context.is_some() || !layout_context.use_rayon { - // Because floats are involved, we do layout for this block formatting context - // in tree order without parallelism. This enables mutable access - // to a `FloatContext` that tracks every float encountered so far (again in tree order). - fragments = child_boxes - .iter() - .enumerate() - .map(|(tree_rank, box_)| { - let mut fragment = box_.layout( - layout_context, - positioning_context, - containing_block, - tree_rank, - float_context.as_mut().map(|c| &mut **c), - ); - place_block_level_fragment(&mut fragment, &mut placement_state); - fragment - }) - .collect() - } else { - fragments = child_boxes - .par_iter() - .enumerate() - .mapfold_reduce_into( - positioning_context, - |positioning_context, (tree_rank, box_)| { - box_.layout( + let fragments = positioning_context.adjust_static_positions(tree_rank, |positioning_context| { + if float_context.is_some() || !layout_context.use_rayon { + // Because floats are involved, we do layout for this block formatting context + // in tree order without parallelism. This enables mutable access + // to a `FloatContext` that tracks every float encountered so far (again in tree order). + child_boxes + .iter() + .enumerate() + .map(|(tree_rank, box_)| { + let mut fragment = box_.layout( layout_context, positioning_context, containing_block, tree_rank, - /* float_context = */ None, - ) - }, - |left, right| left.append(right), - ) - .collect(); - for fragment in &mut fragments { - place_block_level_fragment(fragment, &mut placement_state) + float_context.as_mut().map(|c| &mut **c), + ); + place_block_level_fragment(&mut fragment, &mut placement_state); + fragment + }) + .collect() + } else { + let mut fragments = child_boxes + .par_iter() + .enumerate() + .mapfold_reduce_into( + positioning_context, + |positioning_context, (tree_rank, box_)| { + box_.layout( + layout_context, + positioning_context, + containing_block, + tree_rank, + /* float_context = */ None, + ) + }, + |left, right| left.append(right), + ) + .collect(); + for fragment in &mut fragments { + place_block_level_fragment(fragment, &mut placement_state) + } + fragments } - } - - adjust_static_positions( - &mut positioning_context.abspos[abspos_so_far..], - &mut fragments, - tree_rank, - ); + }); FlowLayout { fragments, diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs index a8500e59d73..0c2f0fe55f0 100644 --- a/components/layout_2020/positioned.rs +++ b/components/layout_2020/positioned.rs @@ -133,6 +133,21 @@ impl PositioningContext<'_> { } } + pub(crate) fn adjust_static_positions( + &mut self, + tree_rank_in_parent: usize, + f: impl FnOnce(&mut Self) -> Vec, + ) -> Vec { + let abspos_so_far = self.abspos.len(); + let fragments = f(self); + adjust_static_positions( + &mut self.abspos[abspos_so_far..], + &fragments, + tree_rank_in_parent, + ); + fragments + } + pub(crate) fn layout_abspos( self, layout_context: &LayoutContext, @@ -430,7 +445,7 @@ fn solve_axis( } } -pub(crate) fn adjust_static_positions( +fn adjust_static_positions( absolutely_positioned_fragments: &mut [CollectedAbsolutelyPositionedBox], child_fragments: &[Fragment], tree_rank_in_parent: usize, From 1c8d14ac0d586a69c1836ec5cd11541d98ae399d Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 12 Dec 2019 18:57:18 +0100 Subject: [PATCH 03/13] Upgrade rayon_croissant to 0.2.0 --- Cargo.lock | 4 ++-- components/layout_2020/Cargo.toml | 2 +- components/layout_2020/flow/construct.rs | 30 ++++++++++++------------ components/layout_2020/flow/mod.rs | 1 + 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 562456fece0..7a7c5f5debc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4221,9 +4221,9 @@ dependencies = [ [[package]] name = "rayon_croissant" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b725e815f3aa08718063883a75003336889debafe2f8fa67fbe91563ddc4efa" +checksum = "3e4aafda434bd10fec689858e2b1d713d0b784b1e60df3761ac8fa727d7e8e27" dependencies = [ "moite_moite", "rayon", diff --git a/components/layout_2020/Cargo.toml b/components/layout_2020/Cargo.toml index 5a28da8d9ee..1d76d00af79 100644 --- a/components/layout_2020/Cargo.toml +++ b/components/layout_2020/Cargo.toml @@ -25,7 +25,7 @@ msg = {path = "../msg"} net_traits = {path = "../net_traits"} range = {path = "../range"} rayon = "1" -rayon_croissant = "0.1.1" +rayon_croissant = "0.2.0" script_layout_interface = {path = "../script_layout_interface"} script_traits = {path = "../script_traits"} serde = "1.0" diff --git a/components/layout_2020/flow/construct.rs b/components/layout_2020/flow/construct.rs index 4a397add2c3..25b401e5592 100644 --- a/components/layout_2020/flow/construct.rs +++ b/components/layout_2020/flow/construct.rs @@ -172,14 +172,6 @@ impl BlockContainer { contains_floats: ContainsFloats, outer_content_sizes_of_children: ContentSizes, } - impl Default for Accumulator { - fn default() -> Self { - Self { - contains_floats: ContainsFloats::No, - outer_content_sizes_of_children: ContentSizes::zero(), - } - } - } let mut acc = Accumulator { contains_floats: builder.contains_floats, outer_content_sizes_of_children: ContentSizes::zero(), @@ -199,13 +191,21 @@ impl BlockContainer { builder .block_level_boxes .into_par_iter() - .mapfold_reduce_into(&mut acc, mapfold, |left, right| { - left.contains_floats |= right.contains_floats; - if content_sizes.requests_inline() { - left.outer_content_sizes_of_children - .max_assign(&right.outer_content_sizes_of_children) - } - }) + .mapfold_reduce_into( + &mut acc, + mapfold, + || Accumulator { + contains_floats: ContainsFloats::No, + outer_content_sizes_of_children: ContentSizes::zero(), + }, + |left, right| { + left.contains_floats |= right.contains_floats; + if content_sizes.requests_inline() { + left.outer_content_sizes_of_children + .max_assign(&right.outer_content_sizes_of_children) + } + }, + ) .collect() } else { builder diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index 3c1df828d1f..449789530e6 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -235,6 +235,7 @@ fn layout_block_level_children<'a>( /* float_context = */ None, ) }, + Default::default, |left, right| left.append(right), ) .collect(); From c44ee516a10fca4d4d715337cc5c61c10bca1a44 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 12 Dec 2019 21:44:24 +0100 Subject: [PATCH 04/13] Give `PositioningContext` more responsibilities Iits details are now private to the module. It has a couple methods that take closures to make sure that "before" and "after" steps are done together: * In an absolutely positioned box, take care of nested abspos (establish a new containing block, etc.) * For a box that *might* be `position: relative`, optionally take care of the same. --- components/layout_2020/flow/inline.rs | 1 - components/layout_2020/flow/mod.rs | 141 +++++------ components/layout_2020/flow/root.rs | 22 +- components/layout_2020/positioned.rs | 329 ++++++++++++++++---------- 4 files changed, 271 insertions(+), 222 deletions(-) diff --git a/components/layout_2020/flow/inline.rs b/components/layout_2020/flow/inline.rs index 0a6fc8d87d6..82d946b42dc 100644 --- a/components/layout_2020/flow/inline.rs +++ b/components/layout_2020/flow/inline.rs @@ -245,7 +245,6 @@ impl InlineFormattingContext { }, }; ifc.positioning_context - .abspos .push(box_.layout(initial_start_corner, tree_rank)); }, InlineLevelBox::OutOfFlowFloatBox(_box_) => { diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index 449789530e6..f524614f03d 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -18,7 +18,6 @@ use crate::{relative_adjustement, ContainingBlock}; use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; use rayon_croissant::ParallelIteratorExt; use servo_arc::Arc; -use style::computed_values::position::T as Position; use style::properties::ComputedValues; use style::values::computed::{Length, LengthOrAuto}; use style::Zero; @@ -235,8 +234,8 @@ fn layout_block_level_children<'a>( /* float_context = */ None, ) }, - Default::default, - |left, right| left.append(right), + PositioningContext::new, + PositioningContext::append, ) .collect(); for fragment in &mut fragments { @@ -317,9 +316,7 @@ impl BlockLevelBox { )), }, BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => { - positioning_context - .abspos - .push(box_.layout(Vec2::zero(), tree_rank)); + positioning_context.push(box_.layout(Vec2::zero(), tree_rank)); Fragment::Anonymous(AnonymousFragment::no_op( containing_block.style.writing_mode, )) @@ -433,80 +430,70 @@ 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_positioning_context = PositioningContext { abspos: Vec::new() }; - let mut flow_layout = layout_contents( - if style.get_box().position == Position::Relative { - &mut nested_positioning_context - } else { - positioning_context - }, - &containing_block_for_children, - this_start_margin_can_collapse_with_children, - ); - let mut block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin); - if this_start_margin_can_collapse_with_children.0 { - block_margins_collapsed_with_children - .start - .adjoin_assign(&flow_layout.collapsible_margins_in_children.start); - if flow_layout - .collapsible_margins_in_children - .collapsed_through - { + + positioning_context.for_maybe_position_relative(layout_context, style, |positioning_context| { + let mut flow_layout = layout_contents( + positioning_context, + &containing_block_for_children, + this_start_margin_can_collapse_with_children, + ); + let mut block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin); + if this_start_margin_can_collapse_with_children.0 { block_margins_collapsed_with_children .start - .adjoin_assign(&std::mem::replace( - &mut flow_layout.collapsible_margins_in_children.end, - CollapsedMargin::zero(), - )); - } - } - if this_end_margin_can_collapse_with_children { - block_margins_collapsed_with_children - .end - .adjoin_assign(&flow_layout.collapsible_margins_in_children.end); - } else { - flow_layout.content_block_size += flow_layout.collapsible_margins_in_children.end.solve(); - } - block_margins_collapsed_with_children.collapsed_through = - this_start_margin_can_collapse_with_children.0 && - this_end_margin_can_collapse_with_children && - flow_layout + .adjoin_assign(&flow_layout.collapsible_margins_in_children.start); + if flow_layout .collapsible_margins_in_children - .collapsed_through; - let relative_adjustement = relative_adjustement(style, inline_size, block_size); - let block_size = block_size.auto_is(|| { - flow_layout - .content_block_size - .clamp_between_extremums(min_box_size.block, max_box_size.block) - }); - let content_rect = Rect { - start_corner: Vec2 { - block: pb.block_start + relative_adjustement.block, - inline: pb.inline_start + relative_adjustement.inline + margin.inline_start, - }, - size: Vec2 { - block: block_size, - inline: inline_size, - }, - }; - if style.get_box().position == Position::Relative { - nested_positioning_context.layout_abspos( - layout_context, - &mut flow_layout.fragments, - &content_rect.size, - &padding, - style, - ) - } - BoxFragment { - style: style.clone(), - children: flow_layout.fragments, - content_rect, - padding, - border, - margin, - block_margins_collapsed_with_children, - } + .collapsed_through + { + block_margins_collapsed_with_children + .start + .adjoin_assign(&std::mem::replace( + &mut flow_layout.collapsible_margins_in_children.end, + CollapsedMargin::zero(), + )); + } + } + if this_end_margin_can_collapse_with_children { + block_margins_collapsed_with_children + .end + .adjoin_assign(&flow_layout.collapsible_margins_in_children.end); + } else { + flow_layout.content_block_size += + flow_layout.collapsible_margins_in_children.end.solve(); + } + block_margins_collapsed_with_children.collapsed_through = + this_start_margin_can_collapse_with_children.0 && + this_end_margin_can_collapse_with_children && + flow_layout + .collapsible_margins_in_children + .collapsed_through; + let relative_adjustement = relative_adjustement(style, inline_size, block_size); + let block_size = block_size.auto_is(|| { + flow_layout + .content_block_size + .clamp_between_extremums(min_box_size.block, max_box_size.block) + }); + let content_rect = Rect { + start_corner: Vec2 { + block: pb.block_start + relative_adjustement.block, + inline: pb.inline_start + relative_adjustement.inline + margin.inline_start, + }, + size: Vec2 { + block: block_size, + inline: inline_size, + }, + }; + BoxFragment { + style: style.clone(), + children: flow_layout.fragments, + content_rect, + padding, + border, + margin, + block_margins_collapsed_with_children, + } + }) } /// https://drafts.csswg.org/css2/visudet.html#block-replaced-width diff --git a/components/layout_2020/flow/root.rs b/components/layout_2020/flow/root.rs index 71d42643853..e668c882d0e 100644 --- a/components/layout_2020/flow/root.rs +++ b/components/layout_2020/flow/root.rs @@ -12,13 +12,12 @@ use crate::formatting_contexts::IndependentFormattingContext; use crate::fragments::Fragment; use crate::geom; use crate::geom::flow_relative::Vec2; +use crate::positioned::AbsolutelyPositionedBox; use crate::positioned::PositioningContext; -use crate::positioned::{AbsolutelyPositionedBox, CollectedAbsolutelyPositionedBox}; use crate::replaced::ReplacedContent; use crate::sizing::ContentSizesRequest; use crate::style_ext::{Display, DisplayGeneratingBox, DisplayInside}; use crate::DefiniteContainingBlock; -use rayon::iter::{IntoParallelRefIterator, ParallelExtend, ParallelIterator}; use script_layout_interface::wrapper_traits::LayoutNode; use servo_arc::Arc; use style::properties::ComputedValues; @@ -111,7 +110,7 @@ impl BoxTreeRoot { }; let dummy_tree_rank = 0; - let mut positioning_context = PositioningContext { abspos: Vec::new() }; + let mut positioning_context = PositioningContext::new(); let mut independent_layout = self.0.layout( layout_context, &mut positioning_context, @@ -119,18 +118,11 @@ impl BoxTreeRoot { dummy_tree_rank, ); - let map = |a: &CollectedAbsolutelyPositionedBox| { - a.layout(layout_context, &initial_containing_block) - }; - if layout_context.use_rayon { - independent_layout - .fragments - .par_extend(positioning_context.abspos.par_iter().map(map)) - } else { - independent_layout - .fragments - .extend(positioning_context.abspos.iter().map(map)) - } + positioning_context.layout_in_initial_containing_block( + layout_context, + &initial_containing_block, + &mut independent_layout.fragments, + ); FragmentTreeRoot(independent_layout.fragments) } diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs index 0c2f0fe55f0..881e395ca7d 100644 --- a/components/layout_2020/positioned.rs +++ b/components/layout_2020/positioned.rs @@ -10,8 +10,9 @@ use crate::geom::flow_relative::{Rect, Sides, Vec2}; use crate::sizing::ContentSizesRequest; use crate::style_ext::{ComputedValuesExt, DisplayInside}; use crate::{ContainingBlock, DefiniteContainingBlock}; -use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; +use rayon::iter::{IntoParallelRefIterator, ParallelExtend, ParallelIterator}; use servo_arc::Arc; +use style::computed_values::position::T as Position; use style::properties::ComputedValues; use style::values::computed::{Length, LengthOrAuto, LengthPercentage, LengthPercentageOrAuto}; use style::Zero; @@ -21,10 +22,8 @@ pub(crate) struct AbsolutelyPositionedBox { pub contents: IndependentFormattingContext, } -#[derive(Default)] pub(crate) struct PositioningContext<'box_tree> { - /// With `position: absolute` - pub abspos: Vec>, + boxes: Vec>, } #[derive(Debug)] @@ -83,8 +82,8 @@ impl AbsolutelyPositionedBox { } } - pub(crate) fn layout<'a>( - &'a self, + pub(crate) fn layout( + &self, initial_start_corner: Vec2, tree_rank: usize, ) -> CollectedAbsolutelyPositionedBox { @@ -123,73 +122,143 @@ impl AbsolutelyPositionedBox { } } -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) +impl<'box_tree> PositioningContext<'box_tree> { + pub(crate) fn new() -> Self { + Self { + boxes: Vec::new(), } } + pub(crate) fn for_maybe_position_relative( + &mut self, + layout_context: &LayoutContext, + style: &ComputedValues, + f: impl FnOnce(&mut Self) -> BoxFragment, + ) -> BoxFragment { + if style.clone_position() == Position::Relative { + Self::for_positioned(layout_context, f) + } else { + f(self) + } + } + + fn for_positioned( + layout_context: &LayoutContext, + f: impl FnOnce(&mut Self) -> BoxFragment, + ) -> BoxFragment { + let mut new = Self::new(); + let mut positioned_box_fragment = f(&mut new); + new.layout_in_positioned_ancestor(layout_context, &mut positioned_box_fragment); + positioned_box_fragment + } + + pub(crate) fn push(&mut self, box_: CollectedAbsolutelyPositionedBox<'box_tree>) { + self.boxes.push(box_) + } + + pub(crate) fn append(&mut self, other: Self) { + vec_append_owned( + &mut self.boxes, + other.boxes, + ); + } + pub(crate) fn adjust_static_positions( &mut self, tree_rank_in_parent: usize, f: impl FnOnce(&mut Self) -> Vec, ) -> Vec { - let abspos_so_far = self.abspos.len(); + let so_far = self.boxes.len(); + let fragments = f(self); + adjust_static_positions( - &mut self.abspos[abspos_so_far..], + &mut self.boxes[so_far..], &fragments, tree_rank_in_parent, ); fragments } - pub(crate) fn layout_abspos( - self, + pub(crate) fn layout_in_initial_containing_block( + &mut self, layout_context: &LayoutContext, + initial_containing_block: &DefiniteContainingBlock, fragments: &mut Vec, - content_rect_size: &Vec2, - padding: &Sides, - style: &ComputedValues, ) { - if self.abspos.is_empty() { - return; + CollectedAbsolutelyPositionedBox::layout_many( + layout_context, + &self.boxes, + fragments, + initial_containing_block, + ) + } + + fn layout_in_positioned_ancestor( + &mut self, + layout_context: &LayoutContext, + positioned_box_fragment: &mut BoxFragment, + ) { + if !self.boxes.is_empty() { + let padding_rect = Rect { + size: positioned_box_fragment.content_rect.size.clone(), + // Ignore the content rect’s position in its own containing block: + start_corner: Vec2::zero(), + } + .inflate(&positioned_box_fragment.padding); + let containing_block = DefiniteContainingBlock { + size: padding_rect.size.clone(), + style: &positioned_box_fragment.style, + }; + let mut children = Vec::new(); + CollectedAbsolutelyPositionedBox::layout_many( + layout_context, + &self.boxes, + &mut children, + &containing_block, + ); + positioned_box_fragment + .children + .push(Fragment::Anonymous(AnonymousFragment { + children, + rect: padding_rect, + mode: positioned_box_fragment.style.writing_mode, + })) } - let padding_rect = Rect { - size: content_rect_size.clone(), - // Ignore the content rect’s position in its own containing block: - start_corner: Vec2::zero(), - } - .inflate(&padding); - let containing_block = DefiniteContainingBlock { - size: padding_rect.size.clone(), - style, - }; - let map = - |a: &CollectedAbsolutelyPositionedBox| a.layout(layout_context, &containing_block); - let children = if layout_context.use_rayon { - self.abspos.par_iter().map(map).collect() - } else { - self.abspos.iter().map(map).collect() - }; - fragments.push(Fragment::Anonymous(AnonymousFragment { - children, - rect: padding_rect, - mode: style.writing_mode, - })) } } -impl CollectedAbsolutelyPositionedBox<'_> { +impl<'box_tree> CollectedAbsolutelyPositionedBox<'box_tree> { + pub(crate) fn layout_many( + layout_context: &LayoutContext, + boxes: &[Self], + fragments: &mut Vec, + containing_block: &DefiniteContainingBlock, + ) { + if layout_context.use_rayon { + fragments.par_extend(boxes.par_iter().map( + |box_| { + Fragment::Box(box_.layout( + layout_context, + containing_block, + )) + } + )) + } else { + fragments.extend(boxes.iter().map(|box_| { + Fragment::Box(box_.layout( + layout_context, + containing_block, + )) + })) + } + } + pub(crate) fn layout( &self, layout_context: &LayoutContext, containing_block: &DefiniteContainingBlock, - ) -> Fragment { + ) -> BoxFragment { let style = &self.absolutely_positioned_box.contents.style; let cbis = containing_block.size.inline; let cbbs = containing_block.size.block; @@ -249,94 +318,88 @@ impl CollectedAbsolutelyPositionedBox<'_> { block_end: block_axis.margin_end, }; - 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 - // https://drafts.csswg.org/css2/visudet.html#abs-replaced-height - let style = &self.absolutely_positioned_box.contents.style; - let size = replaced_used_size.unwrap(); - let fragments = replaced.make_fragments(style, size.clone()); - (size, fragments) - }, - Err(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.auto_is(|| { - let available_size = match inline_axis.anchor { - Anchor::Start(start) => { - cbis - start - pb.inline_sum() - margin.inline_sum() - }, - Anchor::End(end) => cbis - end - pb.inline_sum() - margin.inline_sum(), + PositioningContext::for_positioned(layout_context, |positioning_context| { + let size; + let fragments; + match self.absolutely_positioned_box.contents.as_replaced() { + Ok(replaced) => { + // https://drafts.csswg.org/css2/visudet.html#abs-replaced-width + // https://drafts.csswg.org/css2/visudet.html#abs-replaced-height + let style = &self.absolutely_positioned_box.contents.style; + size = replaced_used_size.unwrap(); + fragments = replaced.make_fragments(style, size.clone()); + }, + Err(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.auto_is(|| { + let available_size = match inline_axis.anchor { + Anchor::Start(start) => { + cbis - start - pb.inline_sum() - margin.inline_sum() + }, + Anchor::End(end) => cbis - end - pb.inline_sum() - margin.inline_sum(), + }; + self.absolutely_positioned_box + .contents + .content_sizes + .shrink_to_fit(available_size) + }); + + let containing_block_for_children = ContainingBlock { + inline_size, + block_size: block_axis.size, + style, }; - self.absolutely_positioned_box - .contents - .content_sizes - .shrink_to_fit(available_size) - }); + // https://drafts.csswg.org/css-writing-modes/#orthogonal-flows + assert_eq!( + containing_block.style.writing_mode, + containing_block_for_children.style.writing_mode, + "Mixed writing modes are not supported yet" + ); + let dummy_tree_rank = 0; + let independent_layout = non_replaced.layout( + layout_context, + positioning_context, + &containing_block_for_children, + dummy_tree_rank, + ); - let containing_block_for_children = ContainingBlock { - inline_size, - block_size: block_axis.size, - style, - }; - // https://drafts.csswg.org/css-writing-modes/#orthogonal-flows - assert_eq!( - containing_block.style.writing_mode, - containing_block_for_children.style.writing_mode, - "Mixed writing modes are not supported yet" - ); - let dummy_tree_rank = 0; - let independent_layout = non_replaced.layout( - layout_context, - &mut positioning_context, - &containing_block_for_children, - dummy_tree_rank, - ); + size = Vec2 { + inline: inline_size, + block: block_axis + .size + .auto_is(|| independent_layout.content_block_size), + }; + fragments = independent_layout.fragments + }, + }; - let size = Vec2 { - inline: inline_size, - block: block_axis - .size - .auto_is(|| independent_layout.content_block_size), - }; - (size, independent_layout.fragments) - }, - }; + let inline_start = match inline_axis.anchor { + Anchor::Start(start) => start + pb.inline_start + margin.inline_start, + Anchor::End(end) => cbbs - end - pb.inline_end - margin.inline_end - size.inline, + }; + let block_start = match block_axis.anchor { + Anchor::Start(start) => start + pb.block_start + margin.block_start, + Anchor::End(end) => cbbs - end - pb.block_end - margin.block_end - size.block, + }; - let inline_start = match inline_axis.anchor { - Anchor::Start(start) => start + pb.inline_start + margin.inline_start, - Anchor::End(end) => cbbs - end - pb.inline_end - margin.inline_end - size.inline, - }; - let block_start = match block_axis.anchor { - Anchor::Start(start) => start + pb.block_start + margin.block_start, - Anchor::End(end) => cbbs - end - pb.block_end - margin.block_end - size.block, - }; + let content_rect = Rect { + start_corner: Vec2 { + inline: inline_start, + block: block_start, + }, + size, + }; - let content_rect = Rect { - start_corner: Vec2 { - inline: inline_start, - block: block_start, - }, - size, - }; - - positioning_context.layout_abspos( - layout_context, - &mut fragments, - &content_rect.size, - &padding, - style, - ); - - Fragment::Box(BoxFragment { - style: style.clone(), - children: fragments, - content_rect, - padding, - border, - margin, - block_margins_collapsed_with_children: CollapsedBlockMargins::zero(), + BoxFragment { + style: style.clone(), + children: fragments, + content_rect, + padding, + border, + margin, + block_margins_collapsed_with_children: CollapsedBlockMargins::zero(), + } }) } } @@ -468,3 +531,11 @@ fn adjust_static_positions( } } } + +fn vec_append_owned(a: &mut Vec, mut b: Vec) { + if a.is_empty() { + *a = b + } else { + a.append(&mut b) + } +} From 5ebddf19e6249d7b39c092d7a439e38c3644f4c9 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 12 Dec 2019 22:21:33 +0100 Subject: [PATCH 05/13] Layout `position: fixed` in the initial containing block --- components/layout_2020/flow/mod.rs | 3 +- components/layout_2020/flow/root.rs | 2 +- components/layout_2020/positioned.rs | 117 +++++++++++++++++++++------ 3 files changed, 97 insertions(+), 25 deletions(-) diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index f524614f03d..800e7b211fc 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -220,6 +220,7 @@ fn layout_block_level_children<'a>( }) .collect() } else { + let has_positioned_ancestor = positioning_context.has_positioned_ancestor(); let mut fragments = child_boxes .par_iter() .enumerate() @@ -234,7 +235,7 @@ fn layout_block_level_children<'a>( /* float_context = */ None, ) }, - PositioningContext::new, + || PositioningContext::new_for_rayon(has_positioned_ancestor), PositioningContext::append, ) .collect(); diff --git a/components/layout_2020/flow/root.rs b/components/layout_2020/flow/root.rs index e668c882d0e..24dea984e62 100644 --- a/components/layout_2020/flow/root.rs +++ b/components/layout_2020/flow/root.rs @@ -110,7 +110,7 @@ impl BoxTreeRoot { }; let dummy_tree_rank = 0; - let mut positioning_context = PositioningContext::new(); + let mut positioning_context = PositioningContext::new_for_initial_containing_block(); let mut independent_layout = self.0.layout( layout_context, &mut positioning_context, diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs index 881e395ca7d..05cfb85e57a 100644 --- a/components/layout_2020/positioned.rs +++ b/components/layout_2020/positioned.rs @@ -10,7 +10,8 @@ use crate::geom::flow_relative::{Rect, Sides, Vec2}; use crate::sizing::ContentSizesRequest; use crate::style_ext::{ComputedValuesExt, DisplayInside}; use crate::{ContainingBlock, DefiniteContainingBlock}; -use rayon::iter::{IntoParallelRefIterator, ParallelExtend, ParallelIterator}; +use rayon::iter::{IntoParallelRefIterator, ParallelExtend}; +use rayon_croissant::ParallelIteratorExt; use servo_arc::Arc; use style::computed_values::position::T as Position; use style::properties::ComputedValues; @@ -23,7 +24,8 @@ pub(crate) struct AbsolutelyPositionedBox { } pub(crate) struct PositioningContext<'box_tree> { - boxes: Vec>, + for_nearest_positioned_ancestor: Option>>, + for_initial_containing_block: Vec>, } #[derive(Debug)] @@ -123,12 +125,28 @@ impl AbsolutelyPositionedBox { } impl<'box_tree> PositioningContext<'box_tree> { - pub(crate) fn new() -> Self { + pub(crate) fn new_for_initial_containing_block() -> Self { Self { - boxes: Vec::new(), + for_nearest_positioned_ancestor: None, + for_initial_containing_block: Vec::new(), } } + pub(crate) fn new_for_rayon(has_positioned_ancestor: bool) -> Self { + Self { + for_nearest_positioned_ancestor: if has_positioned_ancestor { + Some(Vec::new()) + } else { + None + }, + for_initial_containing_block: Vec::new(), + } + } + + pub(crate) fn has_positioned_ancestor(&self) -> bool { + self.for_nearest_positioned_ancestor.is_some() + } + pub(crate) fn for_maybe_position_relative( &mut self, layout_context: &LayoutContext, @@ -136,7 +154,7 @@ impl<'box_tree> PositioningContext<'box_tree> { f: impl FnOnce(&mut Self) -> BoxFragment, ) -> BoxFragment { if style.clone_position() == Position::Relative { - Self::for_positioned(layout_context, f) + Self::for_positioned(layout_context, &mut self.for_initial_containing_block, f) } else { f(self) } @@ -144,23 +162,48 @@ impl<'box_tree> PositioningContext<'box_tree> { fn for_positioned( layout_context: &LayoutContext, + for_initial_containing_block: &mut Vec>, f: impl FnOnce(&mut Self) -> BoxFragment, ) -> BoxFragment { - let mut new = Self::new(); + let mut new = Self { + for_nearest_positioned_ancestor: Some(Vec::new()), + for_initial_containing_block: std::mem::take(for_initial_containing_block), + }; let mut positioned_box_fragment = f(&mut new); new.layout_in_positioned_ancestor(layout_context, &mut positioned_box_fragment); + *for_initial_containing_block = new.for_initial_containing_block; positioned_box_fragment } pub(crate) fn push(&mut self, box_: CollectedAbsolutelyPositionedBox<'box_tree>) { - self.boxes.push(box_) + if let Some(nearest) = &mut self.for_nearest_positioned_ancestor { + match box_ + .absolutely_positioned_box + .contents + .style + .clone_position() + { + Position::Fixed => {}, // fall through + Position::Absolute => return nearest.push(box_), + Position::Static | Position::Relative => unreachable!(), + } + } + self.for_initial_containing_block.push(box_) } pub(crate) fn append(&mut self, other: Self) { vec_append_owned( - &mut self.boxes, - other.boxes, + &mut self.for_initial_containing_block, + other.for_initial_containing_block, ); + match ( + self.for_nearest_positioned_ancestor.as_mut(), + other.for_nearest_positioned_ancestor, + ) { + (Some(a), Some(b)) => vec_append_owned(a, b), + (None, None) => {}, + _ => unreachable!(), + } } pub(crate) fn adjust_static_positions( @@ -168,15 +211,26 @@ impl<'box_tree> PositioningContext<'box_tree> { tree_rank_in_parent: usize, f: impl FnOnce(&mut Self) -> Vec, ) -> Vec { - let so_far = self.boxes.len(); + let for_icb_so_far = self.for_initial_containing_block.len(); + let for_nearest_so_far = self + .for_nearest_positioned_ancestor + .as_ref() + .map(|v| v.len()); let fragments = f(self); adjust_static_positions( - &mut self.boxes[so_far..], + &mut self.for_initial_containing_block[for_icb_so_far..], &fragments, tree_rank_in_parent, ); + if let Some(nearest) = &mut self.for_nearest_positioned_ancestor { + adjust_static_positions( + &mut nearest[for_nearest_so_far.unwrap()..], + &fragments, + tree_rank_in_parent, + ); + } fragments } @@ -186,12 +240,19 @@ impl<'box_tree> PositioningContext<'box_tree> { initial_containing_block: &DefiniteContainingBlock, fragments: &mut Vec, ) { - CollectedAbsolutelyPositionedBox::layout_many( - layout_context, - &self.boxes, - fragments, - initial_containing_block, - ) + debug_assert!(self.for_nearest_positioned_ancestor.is_none()); + + // Loop because it’s possible that we discover (the static position of) + // more absolutely-positioned boxes while doing layout for others. + while !self.for_initial_containing_block.is_empty() { + CollectedAbsolutelyPositionedBox::layout_many( + layout_context, + &std::mem::take(&mut self.for_initial_containing_block), + fragments, + &mut self.for_initial_containing_block, + initial_containing_block, + ) + } } fn layout_in_positioned_ancestor( @@ -199,7 +260,8 @@ impl<'box_tree> PositioningContext<'box_tree> { layout_context: &LayoutContext, positioned_box_fragment: &mut BoxFragment, ) { - if !self.boxes.is_empty() { + let for_here = self.for_nearest_positioned_ancestor.take().unwrap(); + if !for_here.is_empty() { let padding_rect = Rect { size: positioned_box_fragment.content_rect.size.clone(), // Ignore the content rect’s position in its own containing block: @@ -213,8 +275,9 @@ impl<'box_tree> PositioningContext<'box_tree> { let mut children = Vec::new(); CollectedAbsolutelyPositionedBox::layout_many( layout_context, - &self.boxes, + &for_here, &mut children, + &mut self.for_initial_containing_block, &containing_block, ); positioned_box_fragment @@ -233,21 +296,27 @@ impl<'box_tree> CollectedAbsolutelyPositionedBox<'box_tree> { layout_context: &LayoutContext, boxes: &[Self], fragments: &mut Vec, + for_initial_containing_block: &mut Vec>, containing_block: &DefiniteContainingBlock, ) { if layout_context.use_rayon { - fragments.par_extend(boxes.par_iter().map( - |box_| { + fragments.par_extend(boxes.par_iter().mapfold_reduce_into( + for_initial_containing_block, + |for_initial_containing_block, box_| { Fragment::Box(box_.layout( layout_context, + for_initial_containing_block, containing_block, )) - } + }, + Vec::new, + vec_append_owned, )) } else { fragments.extend(boxes.iter().map(|box_| { Fragment::Box(box_.layout( layout_context, + for_initial_containing_block, containing_block, )) })) @@ -257,6 +326,7 @@ impl<'box_tree> CollectedAbsolutelyPositionedBox<'box_tree> { pub(crate) fn layout( &self, layout_context: &LayoutContext, + for_initial_containing_block: &mut Vec>, containing_block: &DefiniteContainingBlock, ) -> BoxFragment { let style = &self.absolutely_positioned_box.contents.style; @@ -318,7 +388,8 @@ impl<'box_tree> CollectedAbsolutelyPositionedBox<'box_tree> { block_end: block_axis.margin_end, }; - PositioningContext::for_positioned(layout_context, |positioning_context| { + let for_icb = for_initial_containing_block; + PositioningContext::for_positioned(layout_context, for_icb, |positioning_context| { let size; let fragments; match self.absolutely_positioned_box.contents.as_replaced() { From 53a8a609d22570c969b9dd6a1e760b6ee72c7381 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 13 Dec 2019 00:09:43 +0100 Subject: [PATCH 06/13] Fix a width v.s. height confusion bug in abspos layout --- components/layout_2020/positioned.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs index 05cfb85e57a..e92dafbbad0 100644 --- a/components/layout_2020/positioned.rs +++ b/components/layout_2020/positioned.rs @@ -447,7 +447,7 @@ impl<'box_tree> CollectedAbsolutelyPositionedBox<'box_tree> { let inline_start = match inline_axis.anchor { Anchor::Start(start) => start + pb.inline_start + margin.inline_start, - Anchor::End(end) => cbbs - end - pb.inline_end - margin.inline_end - size.inline, + Anchor::End(end) => cbis - end - pb.inline_end - margin.inline_end - size.inline, }; let block_start = match block_axis.anchor { Anchor::Start(start) => start + pb.block_start + margin.block_start, From 6fce97c65c2d1d8f59b098596aac45f64306893d Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 13 Dec 2019 00:42:18 +0100 Subject: [PATCH 07/13] Parse `background: ` --- .../properties/shorthands/background.mako.rs | 23 +++++++++++++++++++ .../box-display/block-in-inline-008.xht.ini | 2 -- .../box-display/containing-block-001.xht.ini | 2 -- .../box-display/containing-block-002.xht.ini | 2 -- .../box-display/containing-block-003.xht.ini | 2 -- .../box-display/containing-block-004.xht.ini | 2 -- .../box-display/containing-block-005.xht.ini | 2 -- .../box-display/containing-block-006.xht.ini | 2 -- .../box-display/containing-block-007.xht.ini | 2 -- .../box-display/containing-block-008.xht.ini | 2 -- .../box-display/containing-block-010.xht.ini | 2 -- .../box-display/containing-block-023.xht.ini | 2 ++ .../box-display/containing-block-026.xht.ini | 2 -- 13 files changed, 25 insertions(+), 22 deletions(-) delete mode 100644 tests/wpt/metadata-layout-2020/css/CSS2/box-display/block-in-inline-008.xht.ini delete mode 100644 tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-001.xht.ini delete mode 100644 tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-002.xht.ini delete mode 100644 tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-003.xht.ini delete mode 100644 tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-004.xht.ini delete mode 100644 tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-005.xht.ini delete mode 100644 tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-006.xht.ini delete mode 100644 tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-007.xht.ini delete mode 100644 tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-008.xht.ini delete mode 100644 tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-010.xht.ini create mode 100644 tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-023.xht.ini delete mode 100644 tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-026.xht.ini diff --git a/components/style/properties/shorthands/background.mako.rs b/components/style/properties/shorthands/background.mako.rs index 011ff5cb3d8..124d4fe406c 100644 --- a/components/style/properties/shorthands/background.mako.rs +++ b/components/style/properties/shorthands/background.mako.rs @@ -193,6 +193,29 @@ } +<%helpers:shorthand name="background" + engines="servo-2020" + sub_properties="background-color" + spec="https://drafts.csswg.org/css-backgrounds/#the-background"> + use crate::values::specified::Color; + use crate::parser::Parse; + + pub fn parse_value<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { + Ok(expanded! { + background_color: Color::parse(context, input)? + }) + } + + impl<'a> ToCss for LonghandsToSerialize<'a> { + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result where W: fmt::Write { + self.background_color.to_css(dest) + } + } + + <%helpers:shorthand name="background-position" engines="gecko servo-2013" flags="SHORTHAND_IN_GETCS" diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/block-in-inline-008.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/box-display/block-in-inline-008.xht.ini deleted file mode 100644 index 5089f96e696..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/block-in-inline-008.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[block-in-inline-008.xht] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-001.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-001.xht.ini deleted file mode 100644 index fe9734b830b..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-001.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[containing-block-001.xht] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-002.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-002.xht.ini deleted file mode 100644 index e2c7dd3545b..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-002.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[containing-block-002.xht] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-003.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-003.xht.ini deleted file mode 100644 index 245262f0b90..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-003.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[containing-block-003.xht] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-004.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-004.xht.ini deleted file mode 100644 index 199c0c4dd37..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-004.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[containing-block-004.xht] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-005.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-005.xht.ini deleted file mode 100644 index 612786df8b4..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-005.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[containing-block-005.xht] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-006.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-006.xht.ini deleted file mode 100644 index 0394efb0d59..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-006.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[containing-block-006.xht] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-007.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-007.xht.ini deleted file mode 100644 index 0c000bb2cd3..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-007.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[containing-block-007.xht] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-008.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-008.xht.ini deleted file mode 100644 index dd630be0f54..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-008.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[containing-block-008.xht] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-010.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-010.xht.ini deleted file mode 100644 index af40eef0a5d..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-010.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[containing-block-010.xht] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-023.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-023.xht.ini new file mode 100644 index 00000000000..906c33cc7ca --- /dev/null +++ b/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-023.xht.ini @@ -0,0 +1,2 @@ +[containing-block-023.xht] + expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-026.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-026.xht.ini deleted file mode 100644 index 46f865284ca..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/containing-block-026.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[containing-block-026.xht] - expected: FAIL From c0962aa3fcadce403df4e73c154b9a87fcb4d6c1 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 13 Dec 2019 12:09:51 +0100 Subject: [PATCH 08/13] Replace the closure in `layout_in_flow_non_replaced_block_level` with an enum --- components/layout_2020/flow/mod.rs | 83 ++++++++++++++---------------- 1 file changed, 38 insertions(+), 45 deletions(-) diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index 800e7b211fc..1450d2a6c1a 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -7,7 +7,7 @@ use crate::context::LayoutContext; use crate::flow::float::{FloatBox, FloatContext}; use crate::flow::inline::InlineFormattingContext; -use crate::formatting_contexts::{IndependentFormattingContext, IndependentLayout}; +use crate::formatting_contexts::{IndependentFormattingContext, IndependentLayout, NonReplacedIFC}; use crate::fragments::{AnonymousFragment, BoxFragment, Fragment}; use crate::fragments::{CollapsedBlockMargins, CollapsedMargin}; use crate::geom::flow_relative::{Rect, Sides, Vec2}; @@ -274,19 +274,9 @@ impl BlockLevelBox { positioning_context, containing_block, style, - BlockLevelKind::SameFormattingContextBlock, - |positioning_context, - containing_block, - collapsible_with_parent_start_margin| { - contents.layout( - layout_context, - positioning_context, - containing_block, - tree_rank, - float_context, - collapsible_with_parent_start_margin, - ) - }, + BlockLevelKind::SameFormattingContextBlock(contents), + tree_rank, + float_context )) }, BlockLevelBox::Independent(contents) => match contents.as_replaced() { @@ -300,20 +290,9 @@ impl BlockLevelBox { positioning_context, containing_block, &contents.style, - BlockLevelKind::EstablishesAnIndependentFormattingContext, - |positioning_context, containing_block, _| { - let independent_layout = non_replaced.layout( - layout_context, - positioning_context, - containing_block, - tree_rank, - ); - FlowLayout { - fragments: independent_layout.fragments, - content_block_size: independent_layout.content_block_size, - collapsible_margins_in_children: CollapsedBlockMargins::zero(), - } - }, + BlockLevelKind::EstablishesAnIndependentFormattingContext(non_replaced), + tree_rank, + float_context )), }, BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => { @@ -332,10 +311,9 @@ impl BlockLevelBox { } } -#[derive(PartialEq)] -enum BlockLevelKind { - SameFormattingContextBlock, - EstablishesAnIndependentFormattingContext, +enum BlockLevelKind<'a> { + SameFormattingContextBlock(&'a BlockContainer), + EstablishesAnIndependentFormattingContext(NonReplacedIFC<'a>), } /// https://drafts.csswg.org/css2/visudet.html#blockwidth @@ -345,12 +323,9 @@ fn layout_in_flow_non_replaced_block_level<'a>( positioning_context: &mut PositioningContext<'a>, containing_block: &ContainingBlock, style: &Arc, - block_level_kind: BlockLevelKind, - layout_contents: impl FnOnce( - &mut PositioningContext<'a>, - &ContainingBlock, - CollapsibleWithParentStartMargin, - ) -> FlowLayout, + block_level_kind: BlockLevelKind<'a>, + tree_rank: usize, + float_context: Option<&mut FloatContext>, ) -> BoxFragment { let cbis = containing_block.inline_size; let padding = style.padding().percentages_relative_to(cbis); @@ -424,20 +399,38 @@ fn layout_in_flow_non_replaced_block_level<'a>( ); let this_start_margin_can_collapse_with_children = CollapsibleWithParentStartMargin( - block_level_kind == BlockLevelKind::SameFormattingContextBlock && + matches!(block_level_kind, BlockLevelKind::SameFormattingContextBlock(_)) && pb.block_start == Length::zero(), ); let this_end_margin_can_collapse_with_children = block_size == LengthOrAuto::Auto && min_box_size.block == Length::zero() && pb.block_end == Length::zero() && - block_level_kind == BlockLevelKind::SameFormattingContextBlock; + matches!(block_level_kind, BlockLevelKind::SameFormattingContextBlock(_)); positioning_context.for_maybe_position_relative(layout_context, style, |positioning_context| { - let mut flow_layout = layout_contents( - positioning_context, - &containing_block_for_children, - this_start_margin_can_collapse_with_children, - ); + let mut flow_layout = match block_level_kind { + BlockLevelKind::SameFormattingContextBlock(contents) => contents.layout( + layout_context, + positioning_context, + &containing_block_for_children, + tree_rank, + float_context, + this_start_margin_can_collapse_with_children, + ), + BlockLevelKind::EstablishesAnIndependentFormattingContext(non_replaced) => { + let independent_layout = non_replaced.layout( + layout_context, + positioning_context, + &containing_block_for_children, + tree_rank, + ); + FlowLayout { + fragments: independent_layout.fragments, + content_block_size: independent_layout.content_block_size, + collapsible_margins_in_children: CollapsedBlockMargins::zero(), + } + } + }; let mut block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin); if this_start_margin_can_collapse_with_children.0 { block_margins_collapsed_with_children From 672d971d580fbde74586d2b8b8105b4cc2940ab0 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 13 Dec 2019 12:33:07 +0100 Subject: [PATCH 09/13] Regroup branches specific to `SameFormattingContextBlock` --- components/layout_2020/flow/mod.rs | 115 ++++++++++++++--------------- 1 file changed, 55 insertions(+), 60 deletions(-) diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index 1450d2a6c1a..9eabd6b29c4 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -276,7 +276,7 @@ impl BlockLevelBox { style, BlockLevelKind::SameFormattingContextBlock(contents), tree_rank, - float_context + float_context, )) }, BlockLevelBox::Independent(contents) => match contents.as_replaced() { @@ -292,7 +292,7 @@ impl BlockLevelBox { &contents.style, BlockLevelKind::EstablishesAnIndependentFormattingContext(non_replaced), tree_rank, - float_context + float_context, )), }, BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => { @@ -398,25 +398,56 @@ fn layout_in_flow_non_replaced_block_level<'a>( "Mixed writing modes are not supported yet" ); - let this_start_margin_can_collapse_with_children = CollapsibleWithParentStartMargin( - matches!(block_level_kind, BlockLevelKind::SameFormattingContextBlock(_)) && - pb.block_start == Length::zero(), - ); - let this_end_margin_can_collapse_with_children = block_size == LengthOrAuto::Auto && - min_box_size.block == Length::zero() && - pb.block_end == Length::zero() && - matches!(block_level_kind, BlockLevelKind::SameFormattingContextBlock(_)); + let mut block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin); positioning_context.for_maybe_position_relative(layout_context, style, |positioning_context| { - let mut flow_layout = match block_level_kind { - BlockLevelKind::SameFormattingContextBlock(contents) => contents.layout( - layout_context, - positioning_context, - &containing_block_for_children, - tree_rank, - float_context, - this_start_margin_can_collapse_with_children, - ), + let fragments; + let mut content_block_size; + match block_level_kind { + BlockLevelKind::SameFormattingContextBlock(contents) => { + let this_start_margin_can_collapse_with_children = pb.block_start == Length::zero(); + let this_end_margin_can_collapse_with_children = pb.block_end == Length::zero() && + block_size == LengthOrAuto::Auto && + min_box_size.block == Length::zero(); + + let flow_layout = contents.layout( + layout_context, + positioning_context, + &containing_block_for_children, + tree_rank, + float_context, + CollapsibleWithParentStartMargin(this_start_margin_can_collapse_with_children), + ); + fragments = flow_layout.fragments; + content_block_size = flow_layout.content_block_size; + let mut collapsible_margins_in_children = + flow_layout.collapsible_margins_in_children; + + if this_start_margin_can_collapse_with_children { + block_margins_collapsed_with_children + .start + .adjoin_assign(&collapsible_margins_in_children.start); + if collapsible_margins_in_children.collapsed_through { + block_margins_collapsed_with_children.start.adjoin_assign( + &std::mem::replace( + &mut collapsible_margins_in_children.end, + CollapsedMargin::zero(), + ), + ); + } + } + if this_end_margin_can_collapse_with_children { + block_margins_collapsed_with_children + .end + .adjoin_assign(&collapsible_margins_in_children.end); + } else { + content_block_size += collapsible_margins_in_children.end.solve(); + } + block_margins_collapsed_with_children.collapsed_through = + this_start_margin_can_collapse_with_children && + this_end_margin_can_collapse_with_children && + collapsible_margins_in_children.collapsed_through; + }, BlockLevelKind::EstablishesAnIndependentFormattingContext(non_replaced) => { let independent_layout = non_replaced.layout( layout_context, @@ -424,49 +455,13 @@ fn layout_in_flow_non_replaced_block_level<'a>( &containing_block_for_children, tree_rank, ); - FlowLayout { - fragments: independent_layout.fragments, - content_block_size: independent_layout.content_block_size, - collapsible_margins_in_children: CollapsedBlockMargins::zero(), - } - } + fragments = independent_layout.fragments; + content_block_size = independent_layout.content_block_size; + }, }; - let mut block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin); - if this_start_margin_can_collapse_with_children.0 { - block_margins_collapsed_with_children - .start - .adjoin_assign(&flow_layout.collapsible_margins_in_children.start); - if flow_layout - .collapsible_margins_in_children - .collapsed_through - { - block_margins_collapsed_with_children - .start - .adjoin_assign(&std::mem::replace( - &mut flow_layout.collapsible_margins_in_children.end, - CollapsedMargin::zero(), - )); - } - } - if this_end_margin_can_collapse_with_children { - block_margins_collapsed_with_children - .end - .adjoin_assign(&flow_layout.collapsible_margins_in_children.end); - } else { - flow_layout.content_block_size += - flow_layout.collapsible_margins_in_children.end.solve(); - } - block_margins_collapsed_with_children.collapsed_through = - this_start_margin_can_collapse_with_children.0 && - this_end_margin_can_collapse_with_children && - flow_layout - .collapsible_margins_in_children - .collapsed_through; let relative_adjustement = relative_adjustement(style, inline_size, block_size); let block_size = block_size.auto_is(|| { - flow_layout - .content_block_size - .clamp_between_extremums(min_box_size.block, max_box_size.block) + content_block_size.clamp_between_extremums(min_box_size.block, max_box_size.block) }); let content_rect = Rect { start_corner: Vec2 { @@ -480,7 +475,7 @@ fn layout_in_flow_non_replaced_block_level<'a>( }; BoxFragment { style: style.clone(), - children: flow_layout.fragments, + children: fragments, content_rect, padding, border, From 04b701b9e0820f1b10103dc336fa2981f726f578 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 13 Dec 2019 12:41:58 +0100 Subject: [PATCH 10/13] Move call to `for_maybe_position_relative` out of `layout_in_flow_non_replaced_block_level` --- components/layout_2020/flow/mod.rs | 204 +++++++++++++++-------------- 1 file changed, 107 insertions(+), 97 deletions(-) diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index 9eabd6b29c4..34cce3a31a6 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -269,31 +269,43 @@ impl BlockLevelBox { ) -> Fragment { match self { BlockLevelBox::SameFormattingContextBlock { style, contents } => { - Fragment::Box(layout_in_flow_non_replaced_block_level( + Fragment::Box(positioning_context.for_maybe_position_relative( layout_context, - positioning_context, - containing_block, style, - BlockLevelKind::SameFormattingContextBlock(contents), - tree_rank, - float_context, + |positioning_context| { + layout_in_flow_non_replaced_block_level( + layout_context, + positioning_context, + containing_block, + style, + BlockLevelKind::SameFormattingContextBlock(contents), + tree_rank, + float_context, + ) + }, )) }, - BlockLevelBox::Independent(contents) => match contents.as_replaced() { - Ok(replaced) => Fragment::Box(layout_in_flow_replaced_block_level( - containing_block, - &contents.style, - replaced, - )), - Err(non_replaced) => Fragment::Box(layout_in_flow_non_replaced_block_level( + BlockLevelBox::Independent(contents) => { + Fragment::Box(positioning_context.for_maybe_position_relative( layout_context, - positioning_context, - containing_block, &contents.style, - BlockLevelKind::EstablishesAnIndependentFormattingContext(non_replaced), - tree_rank, - float_context, - )), + |positioning_context| match contents.as_replaced() { + Ok(replaced) => layout_in_flow_replaced_block_level( + containing_block, + &contents.style, + replaced, + ), + Err(non_replaced) => layout_in_flow_non_replaced_block_level( + layout_context, + positioning_context, + containing_block, + &contents.style, + BlockLevelKind::EstablishesAnIndependentFormattingContext(non_replaced), + tree_rank, + float_context, + ), + }, + )) }, BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => { positioning_context.push(box_.layout(Vec2::zero(), tree_rank)); @@ -302,6 +314,7 @@ impl BlockLevelBox { )) }, BlockLevelBox::OutOfFlowFloatBox(_box_) => { + // FIXME: call for_maybe_position_relative here // TODO Fragment::Anonymous(AnonymousFragment::no_op( containing_block.style.writing_mode, @@ -400,89 +413,86 @@ fn layout_in_flow_non_replaced_block_level<'a>( let mut block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin); - positioning_context.for_maybe_position_relative(layout_context, style, |positioning_context| { - let fragments; - let mut content_block_size; - match block_level_kind { - BlockLevelKind::SameFormattingContextBlock(contents) => { - let this_start_margin_can_collapse_with_children = pb.block_start == Length::zero(); - let this_end_margin_can_collapse_with_children = pb.block_end == Length::zero() && - block_size == LengthOrAuto::Auto && - min_box_size.block == Length::zero(); + let fragments; + let mut content_block_size; + match block_level_kind { + BlockLevelKind::SameFormattingContextBlock(contents) => { + let this_start_margin_can_collapse_with_children = pb.block_start == Length::zero(); + let this_end_margin_can_collapse_with_children = pb.block_end == Length::zero() && + block_size == LengthOrAuto::Auto && + min_box_size.block == Length::zero(); - let flow_layout = contents.layout( - layout_context, - positioning_context, - &containing_block_for_children, - tree_rank, - float_context, - CollapsibleWithParentStartMargin(this_start_margin_can_collapse_with_children), - ); - fragments = flow_layout.fragments; - content_block_size = flow_layout.content_block_size; - let mut collapsible_margins_in_children = - flow_layout.collapsible_margins_in_children; + let flow_layout = contents.layout( + layout_context, + positioning_context, + &containing_block_for_children, + tree_rank, + float_context, + CollapsibleWithParentStartMargin(this_start_margin_can_collapse_with_children), + ); + fragments = flow_layout.fragments; + content_block_size = flow_layout.content_block_size; + let mut collapsible_margins_in_children = flow_layout.collapsible_margins_in_children; - if this_start_margin_can_collapse_with_children { + if this_start_margin_can_collapse_with_children { + block_margins_collapsed_with_children + .start + .adjoin_assign(&collapsible_margins_in_children.start); + if collapsible_margins_in_children.collapsed_through { block_margins_collapsed_with_children .start - .adjoin_assign(&collapsible_margins_in_children.start); - if collapsible_margins_in_children.collapsed_through { - block_margins_collapsed_with_children.start.adjoin_assign( - &std::mem::replace( - &mut collapsible_margins_in_children.end, - CollapsedMargin::zero(), - ), - ); - } + .adjoin_assign(&std::mem::replace( + &mut collapsible_margins_in_children.end, + CollapsedMargin::zero(), + )); } - if this_end_margin_can_collapse_with_children { - block_margins_collapsed_with_children - .end - .adjoin_assign(&collapsible_margins_in_children.end); - } else { - content_block_size += collapsible_margins_in_children.end.solve(); - } - block_margins_collapsed_with_children.collapsed_through = - this_start_margin_can_collapse_with_children && - this_end_margin_can_collapse_with_children && - collapsible_margins_in_children.collapsed_through; - }, - BlockLevelKind::EstablishesAnIndependentFormattingContext(non_replaced) => { - let independent_layout = non_replaced.layout( - layout_context, - positioning_context, - &containing_block_for_children, - tree_rank, - ); - fragments = independent_layout.fragments; - content_block_size = independent_layout.content_block_size; - }, - }; - let relative_adjustement = relative_adjustement(style, inline_size, block_size); - let block_size = block_size.auto_is(|| { - content_block_size.clamp_between_extremums(min_box_size.block, max_box_size.block) - }); - let content_rect = Rect { - start_corner: Vec2 { - block: pb.block_start + relative_adjustement.block, - inline: pb.inline_start + relative_adjustement.inline + margin.inline_start, - }, - size: Vec2 { - block: block_size, - inline: inline_size, - }, - }; - BoxFragment { - style: style.clone(), - children: fragments, - content_rect, - padding, - border, - margin, - block_margins_collapsed_with_children, - } - }) + } + if this_end_margin_can_collapse_with_children { + block_margins_collapsed_with_children + .end + .adjoin_assign(&collapsible_margins_in_children.end); + } else { + content_block_size += collapsible_margins_in_children.end.solve(); + } + block_margins_collapsed_with_children.collapsed_through = + this_start_margin_can_collapse_with_children && + this_end_margin_can_collapse_with_children && + collapsible_margins_in_children.collapsed_through; + }, + BlockLevelKind::EstablishesAnIndependentFormattingContext(non_replaced) => { + let independent_layout = non_replaced.layout( + layout_context, + positioning_context, + &containing_block_for_children, + tree_rank, + ); + fragments = independent_layout.fragments; + content_block_size = independent_layout.content_block_size; + }, + }; + let relative_adjustement = relative_adjustement(style, inline_size, block_size); + let block_size = block_size.auto_is(|| { + content_block_size.clamp_between_extremums(min_box_size.block, max_box_size.block) + }); + let content_rect = Rect { + start_corner: Vec2 { + block: pb.block_start + relative_adjustement.block, + inline: pb.inline_start + relative_adjustement.inline + margin.inline_start, + }, + size: Vec2 { + block: block_size, + inline: inline_size, + }, + }; + BoxFragment { + style: style.clone(), + children: fragments, + content_rect, + padding, + border, + margin, + block_margins_collapsed_with_children, + } } /// https://drafts.csswg.org/css2/visudet.html#block-replaced-width From b218957461263d885bc142383e05fe44c093c2fe Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 13 Dec 2019 12:44:05 +0100 Subject: [PATCH 11/13] Rename `CollectedAbsolutelyPositionedBox` to `HoistedAbsolutelyPositionedBox` --- components/layout_2020/positioned.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs index e92dafbbad0..bb7629da170 100644 --- a/components/layout_2020/positioned.rs +++ b/components/layout_2020/positioned.rs @@ -24,12 +24,12 @@ pub(crate) struct AbsolutelyPositionedBox { } pub(crate) struct PositioningContext<'box_tree> { - for_nearest_positioned_ancestor: Option>>, - for_initial_containing_block: Vec>, + for_nearest_positioned_ancestor: Option>>, + for_initial_containing_block: Vec>, } #[derive(Debug)] -pub(crate) struct CollectedAbsolutelyPositionedBox<'box_tree> { +pub(crate) struct HoistedAbsolutelyPositionedBox<'box_tree> { absolutely_positioned_box: &'box_tree AbsolutelyPositionedBox, /// The rank of the child from which this absolutely positioned fragment @@ -88,7 +88,7 @@ impl AbsolutelyPositionedBox { &self, initial_start_corner: Vec2, tree_rank: usize, - ) -> CollectedAbsolutelyPositionedBox { + ) -> HoistedAbsolutelyPositionedBox { fn absolute_box_offsets( initial_static_start: Length, start: LengthPercentageOrAuto, @@ -105,7 +105,7 @@ impl AbsolutelyPositionedBox { } let box_offsets = self.contents.style.box_offsets(); - CollectedAbsolutelyPositionedBox { + HoistedAbsolutelyPositionedBox { absolutely_positioned_box: self, tree_rank, box_offsets: Vec2 { @@ -162,7 +162,7 @@ impl<'box_tree> PositioningContext<'box_tree> { fn for_positioned( layout_context: &LayoutContext, - for_initial_containing_block: &mut Vec>, + for_initial_containing_block: &mut Vec>, f: impl FnOnce(&mut Self) -> BoxFragment, ) -> BoxFragment { let mut new = Self { @@ -175,7 +175,7 @@ impl<'box_tree> PositioningContext<'box_tree> { positioned_box_fragment } - pub(crate) fn push(&mut self, box_: CollectedAbsolutelyPositionedBox<'box_tree>) { + pub(crate) fn push(&mut self, box_: HoistedAbsolutelyPositionedBox<'box_tree>) { if let Some(nearest) = &mut self.for_nearest_positioned_ancestor { match box_ .absolutely_positioned_box @@ -245,7 +245,7 @@ impl<'box_tree> PositioningContext<'box_tree> { // Loop because it’s possible that we discover (the static position of) // more absolutely-positioned boxes while doing layout for others. while !self.for_initial_containing_block.is_empty() { - CollectedAbsolutelyPositionedBox::layout_many( + HoistedAbsolutelyPositionedBox::layout_many( layout_context, &std::mem::take(&mut self.for_initial_containing_block), fragments, @@ -273,7 +273,7 @@ impl<'box_tree> PositioningContext<'box_tree> { style: &positioned_box_fragment.style, }; let mut children = Vec::new(); - CollectedAbsolutelyPositionedBox::layout_many( + HoistedAbsolutelyPositionedBox::layout_many( layout_context, &for_here, &mut children, @@ -291,12 +291,12 @@ impl<'box_tree> PositioningContext<'box_tree> { } } -impl<'box_tree> CollectedAbsolutelyPositionedBox<'box_tree> { +impl<'box_tree> HoistedAbsolutelyPositionedBox<'box_tree> { pub(crate) fn layout_many( layout_context: &LayoutContext, boxes: &[Self], fragments: &mut Vec, - for_initial_containing_block: &mut Vec>, + for_initial_containing_block: &mut Vec>, containing_block: &DefiniteContainingBlock, ) { if layout_context.use_rayon { @@ -326,7 +326,7 @@ impl<'box_tree> CollectedAbsolutelyPositionedBox<'box_tree> { pub(crate) fn layout( &self, layout_context: &LayoutContext, - for_initial_containing_block: &mut Vec>, + for_initial_containing_block: &mut Vec>, containing_block: &DefiniteContainingBlock, ) -> BoxFragment { let style = &self.absolutely_positioned_box.contents.style; @@ -580,7 +580,7 @@ fn solve_axis( } fn adjust_static_positions( - absolutely_positioned_fragments: &mut [CollectedAbsolutelyPositionedBox], + absolutely_positioned_fragments: &mut [HoistedAbsolutelyPositionedBox], child_fragments: &[Fragment], tree_rank_in_parent: usize, ) { From 58b7005a9bb0e6c7a4c339bf82abec9b3b20eef2 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 13 Dec 2019 13:12:57 +0100 Subject: [PATCH 12/13] Make `for_maybe_position_relative` take care of relative adjustment. --- components/layout_2020/flow/inline.rs | 20 +++++------- components/layout_2020/flow/mod.rs | 18 ++++------- components/layout_2020/lib.rs | 30 ----------------- components/layout_2020/positioned.rs | 32 ++++++++++++++++++- .../style/properties/longhands/box.mako.rs | 3 ++ .../block-in-inline-relpos-001.xht.ini | 2 -- 6 files changed, 49 insertions(+), 56 deletions(-) delete mode 100644 tests/wpt/metadata-layout-2020/css/CSS2/box-display/block-in-inline-relpos-001.xht.ini diff --git a/components/layout_2020/flow/inline.rs b/components/layout_2020/flow/inline.rs index 82d946b42dc..93d7d6f8bdc 100644 --- a/components/layout_2020/flow/inline.rs +++ b/components/layout_2020/flow/inline.rs @@ -9,10 +9,10 @@ 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, PositioningContext}; +use crate::positioned::{relative_adjustement, AbsolutelyPositionedBox, PositioningContext}; use crate::sizing::ContentSizes; use crate::style_ext::{ComputedValuesExt, Display, DisplayGeneratingBox, DisplayOutside}; -use crate::{relative_adjustement, ContainingBlock}; +use crate::ContainingBlock; use app_units::Au; use gfx::text::text_run::GlyphRun; use servo_arc::Arc; @@ -367,11 +367,9 @@ impl InlineBox { block: padding.block_start + border.block_start + margin.block_start, inline: ifc.inline_position - ifc.current_nesting_level.inline_start, }; - start_corner += &relative_adjustement( - &style, - ifc.containing_block.inline_size, - ifc.containing_block.block_size, - ); + if style.clone_position().is_relative() { + start_corner += &relative_adjustement(&style, ifc.containing_block) + } PartialInlineBoxFragment { style, start_corner, @@ -457,11 +455,9 @@ fn layout_atomic<'box_tree>( block: pbm.block_start, inline: ifc.inline_position - ifc.current_nesting_level.inline_start, }; - start_corner += &relative_adjustement( - &atomic.style, - ifc.containing_block.inline_size, - ifc.containing_block.block_size, - ); + if atomic.style.clone_position().is_relative() { + start_corner += &relative_adjustement(&atomic.style, ifc.containing_block) + } let fragment = match atomic.as_replaced() { Ok(replaced) => { diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index 34cce3a31a6..031e7fab787 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -14,7 +14,7 @@ use crate::geom::flow_relative::{Rect, Sides, Vec2}; use crate::positioned::{AbsolutelyPositionedBox, PositioningContext}; use crate::replaced::ReplacedContent; use crate::style_ext::ComputedValuesExt; -use crate::{relative_adjustement, ContainingBlock}; +use crate::ContainingBlock; use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; use rayon_croissant::ParallelIteratorExt; use servo_arc::Arc; @@ -271,6 +271,7 @@ impl BlockLevelBox { BlockLevelBox::SameFormattingContextBlock { style, contents } => { Fragment::Box(positioning_context.for_maybe_position_relative( layout_context, + containing_block, style, |positioning_context| { layout_in_flow_non_replaced_block_level( @@ -288,6 +289,7 @@ impl BlockLevelBox { BlockLevelBox::Independent(contents) => { Fragment::Box(positioning_context.for_maybe_position_relative( layout_context, + containing_block, &contents.style, |positioning_context| match contents.as_replaced() { Ok(replaced) => layout_in_flow_replaced_block_level( @@ -470,14 +472,13 @@ fn layout_in_flow_non_replaced_block_level<'a>( content_block_size = independent_layout.content_block_size; }, }; - let relative_adjustement = relative_adjustement(style, inline_size, block_size); let block_size = block_size.auto_is(|| { content_block_size.clamp_between_extremums(min_box_size.block, max_box_size.block) }); let content_rect = Rect { start_corner: Vec2 { - block: pb.block_start + relative_adjustement.block, - inline: pb.inline_start + relative_adjustement.inline + margin.inline_start, + block: pb.block_start, + inline: pb.inline_start, }, size: Vec2 { block: block_size, @@ -525,15 +526,10 @@ fn layout_in_flow_replaced_block_level<'a>( block_end: computed_margin.block_end.auto_is(Length::zero), }; let fragments = replaced.make_fragments(style, size.clone()); - let relative_adjustement = relative_adjustement( - style, - size.inline, - LengthOrAuto::LengthPercentage(size.block), - ); let content_rect = Rect { start_corner: Vec2 { - block: pb.block_start + relative_adjustement.block, - inline: pb.inline_start + relative_adjustement.inline + margin.inline_start, + block: pb.block_start, + inline: pb.inline_start + margin.inline_start, }, size, }; diff --git a/components/layout_2020/lib.rs b/components/layout_2020/lib.rs index 8e923f870d7..b8cc003caf5 100644 --- a/components/layout_2020/lib.rs +++ b/components/layout_2020/lib.rs @@ -27,11 +27,8 @@ pub mod wrapper; pub use flow::{BoxTreeRoot, FragmentTreeRoot}; use crate::geom::flow_relative::Vec2; -use crate::style_ext::ComputedValuesExt; -use style::computed_values::position::T as Position; use style::properties::ComputedValues; use style::values::computed::{Length, LengthOrAuto}; -use style::Zero; struct ContainingBlock<'a> { inline_size: Length, @@ -53,30 +50,3 @@ impl<'a> From<&'_ DefiniteContainingBlock<'a>> for ContainingBlock<'a> { } } } - -/// https://drafts.csswg.org/css2/visuren.html#relative-positioning -fn relative_adjustement( - style: &ComputedValues, - inline_size: Length, - block_size: LengthOrAuto, -) -> Vec2 { - if style.get_box().position != Position::Relative { - return Vec2::zero(); - } - fn adjust(start: LengthOrAuto, end: LengthOrAuto) -> Length { - match (start, end) { - (LengthOrAuto::Auto, LengthOrAuto::Auto) => Length::zero(), - (LengthOrAuto::Auto, LengthOrAuto::LengthPercentage(end)) => -end, - (LengthOrAuto::LengthPercentage(start), _) => start, - } - } - let block_size = block_size.auto_is(Length::zero); - let box_offsets = style.box_offsets().map_inline_and_block_axes( - |v| v.percentage_relative_to(inline_size), - |v| v.percentage_relative_to(block_size), - ); - Vec2 { - inline: adjust(box_offsets.inline_start, box_offsets.inline_end), - block: adjust(box_offsets.block_start, box_offsets.block_end), - } -} diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs index bb7629da170..cfe615ae27d 100644 --- a/components/layout_2020/positioned.rs +++ b/components/layout_2020/positioned.rs @@ -150,11 +150,17 @@ impl<'box_tree> PositioningContext<'box_tree> { pub(crate) fn for_maybe_position_relative( &mut self, layout_context: &LayoutContext, + containing_block: &ContainingBlock, style: &ComputedValues, f: impl FnOnce(&mut Self) -> BoxFragment, ) -> BoxFragment { if style.clone_position() == Position::Relative { - Self::for_positioned(layout_context, &mut self.for_initial_containing_block, f) + let mut fragment = + // Establing a containing block for absolutely positioned descendants + Self::for_positioned(layout_context, &mut self.for_initial_containing_block, f); + + fragment.content_rect.start_corner += &relative_adjustement(style, containing_block); + fragment } else { f(self) } @@ -610,3 +616,27 @@ fn vec_append_owned(a: &mut Vec, mut b: Vec) { a.append(&mut b) } } + +/// https://drafts.csswg.org/css2/visuren.html#relative-positioning +pub(crate) fn relative_adjustement( + style: &ComputedValues, + containing_block: &ContainingBlock, +) -> Vec2 { + let cbis = containing_block.inline_size; + let cbbs = containing_block.block_size.auto_is(Length::zero); + let box_offsets = style.box_offsets().map_inline_and_block_axes( + |v| v.percentage_relative_to(cbis), + |v| v.percentage_relative_to(cbbs), + ); + fn adjust(start: LengthOrAuto, end: LengthOrAuto) -> Length { + match (start, end) { + (LengthOrAuto::Auto, LengthOrAuto::Auto) => Length::zero(), + (LengthOrAuto::Auto, LengthOrAuto::LengthPercentage(end)) => -end, + (LengthOrAuto::LengthPercentage(start), _) => start, + } + } + Vec2 { + inline: adjust(box_offsets.inline_start, box_offsets.inline_end), + block: adjust(box_offsets.block_start, box_offsets.block_end), + } +} diff --git a/components/style/properties/longhands/box.mako.rs b/components/style/properties/longhands/box.mako.rs index b8b6cbc8c34..aa6118b8a8a 100644 --- a/components/style/properties/longhands/box.mako.rs +++ b/components/style/properties/longhands/box.mako.rs @@ -55,6 +55,9 @@ impl computed_value::T { pub fn is_absolutely_positioned(self) -> bool { matches!(self, Self::Absolute | Self::Fixed) } + pub fn is_relative(self) -> bool { + self == Self::Relative + } } diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/block-in-inline-relpos-001.xht.ini b/tests/wpt/metadata-layout-2020/css/CSS2/box-display/block-in-inline-relpos-001.xht.ini deleted file mode 100644 index 36bc0e014bb..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/box-display/block-in-inline-relpos-001.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[block-in-inline-relpos-001.xht] - expected: FAIL From 6f3c5ce773b4170d8c27c958c0bbf3822bfe452f Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 13 Dec 2019 13:59:15 +0100 Subject: [PATCH 13/13] Rename `BlockLevelKind` to `NonReplacedContents` --- components/layout_2020/flow/mod.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index 031e7fab787..64f87ea09d0 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -279,7 +279,7 @@ impl BlockLevelBox { positioning_context, containing_block, style, - BlockLevelKind::SameFormattingContextBlock(contents), + NonReplacedContents::SameFormattingContextBlock(contents), tree_rank, float_context, ) @@ -302,7 +302,9 @@ impl BlockLevelBox { positioning_context, containing_block, &contents.style, - BlockLevelKind::EstablishesAnIndependentFormattingContext(non_replaced), + NonReplacedContents::EstablishesAnIndependentFormattingContext( + non_replaced, + ), tree_rank, float_context, ), @@ -326,7 +328,7 @@ impl BlockLevelBox { } } -enum BlockLevelKind<'a> { +enum NonReplacedContents<'a> { SameFormattingContextBlock(&'a BlockContainer), EstablishesAnIndependentFormattingContext(NonReplacedIFC<'a>), } @@ -338,7 +340,7 @@ fn layout_in_flow_non_replaced_block_level<'a>( positioning_context: &mut PositioningContext<'a>, containing_block: &ContainingBlock, style: &Arc, - block_level_kind: BlockLevelKind<'a>, + block_level_kind: NonReplacedContents<'a>, tree_rank: usize, float_context: Option<&mut FloatContext>, ) -> BoxFragment { @@ -418,7 +420,7 @@ fn layout_in_flow_non_replaced_block_level<'a>( let fragments; let mut content_block_size; match block_level_kind { - BlockLevelKind::SameFormattingContextBlock(contents) => { + NonReplacedContents::SameFormattingContextBlock(contents) => { let this_start_margin_can_collapse_with_children = pb.block_start == Length::zero(); let this_end_margin_can_collapse_with_children = pb.block_end == Length::zero() && block_size == LengthOrAuto::Auto && @@ -461,7 +463,7 @@ fn layout_in_flow_non_replaced_block_level<'a>( this_end_margin_can_collapse_with_children && collapsible_margins_in_children.collapsed_through; }, - BlockLevelKind::EstablishesAnIndependentFormattingContext(non_replaced) => { + NonReplacedContents::EstablishesAnIndependentFormattingContext(non_replaced) => { let independent_layout = non_replaced.layout( layout_context, positioning_context,