From b2b3ea992c2f045a49d7264df18f5f85b2c913fb Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 26 Nov 2019 11:22:23 +0100 Subject: [PATCH] Make IndependentFormattingContext a struct that owns styles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … and has a private enum for its contents. Privacy forces the rest of the code to go through methods rather than matching on the enum, reducing accidental layout-mode-specific behavior. --- components/layout_2020/dom_traversal.rs | 2 +- components/layout_2020/flow/construct.rs | 24 ++-- components/layout_2020/flow/float.rs | 3 +- components/layout_2020/flow/inline.rs | 2 +- components/layout_2020/flow/mod.rs | 21 ++-- components/layout_2020/flow/root.rs | 16 +-- components/layout_2020/formatting_contexts.rs | 107 ++++++++++++++++++ components/layout_2020/lib.rs | 89 +-------------- components/layout_2020/positioned.rs | 8 +- 9 files changed, 149 insertions(+), 123 deletions(-) create mode 100644 components/layout_2020/formatting_contexts.rs diff --git a/components/layout_2020/dom_traversal.rs b/components/layout_2020/dom_traversal.rs index ce57f4c8100f..236e69b3d19f 100644 --- a/components/layout_2020/dom_traversal.rs +++ b/components/layout_2020/dom_traversal.rs @@ -30,7 +30,7 @@ pub(super) enum Contents { /// Replaced(ReplacedContent), - /// Content of a `::before` or `::after` pseudo-element this is being generated. + /// Content of a `::before` or `::after` pseudo-element that is being generated. /// OfPseudoElement(Vec), } diff --git a/components/layout_2020/flow/construct.rs b/components/layout_2020/flow/construct.rs index f3afabf15fc5..52724eb121fd 100644 --- a/components/layout_2020/flow/construct.rs +++ b/components/layout_2020/flow/construct.rs @@ -7,9 +7,10 @@ use crate::element_data::LayoutBox; use crate::flow::float::FloatBox; use crate::flow::inline::{InlineBox, InlineFormattingContext, InlineLevelBox, TextRun}; use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox}; +use crate::formatting_contexts::IndependentFormattingContext; use crate::positioned::AbsolutelyPositionedBox; use crate::style_ext::{DisplayGeneratingBox, DisplayInside, DisplayOutside}; -use crate::{take, IndependentFormattingContext}; +use crate::take; use rayon::iter::{IntoParallelIterator, ParallelIterator}; use rayon_croissant::ParallelIteratorExt; use servo_arc::Arc; @@ -450,11 +451,10 @@ where AbsolutelyPositionedBox { contents: IndependentFormattingContext::construct( unimplemented!(), - &style, + style, display_inside, contents, ), - style, }, )); self.current_inline_level_boxes().push(box_.clone()); @@ -482,11 +482,10 @@ where let box_ = Arc::new(InlineLevelBox::OutOfFlowFloatBox(FloatBox { contents: IndependentFormattingContext::construct( self.context, - &style, + style, display_inside, contents, ), - style, })); self.current_inline_level_boxes().push(box_.clone()); box_slot.set(LayoutBox::InlineLevel(box_)) @@ -562,12 +561,12 @@ where } => { let contents = IndependentFormattingContext::construct( context, - &style, + style, display_inside, contents, ); ( - Arc::new(BlockLevelBox::Independent { style, contents }), + Arc::new(BlockLevelBox::Independent(contents)), ContainsFloats::No, ) }, @@ -580,11 +579,10 @@ where AbsolutelyPositionedBox { contents: IndependentFormattingContext::construct( context, - &style, + style, display_inside, contents, ), - style: style, }, )); (block_level_box, ContainsFloats::No) @@ -596,14 +594,12 @@ where } => { let contents = IndependentFormattingContext::construct( context, - &style, + style, display_inside, contents, ); - let block_level_box = Arc::new(BlockLevelBox::OutOfFlowFloatBox(FloatBox { - contents, - style, - })); + let block_level_box = + Arc::new(BlockLevelBox::OutOfFlowFloatBox(FloatBox { contents })); (block_level_box, ContainsFloats::Yes) }, } diff --git a/components/layout_2020/flow/float.rs b/components/layout_2020/flow/float.rs index 31fec0b79c05..4698e9d2f1cc 100644 --- a/components/layout_2020/flow/float.rs +++ b/components/layout_2020/flow/float.rs @@ -2,13 +2,12 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use crate::IndependentFormattingContext; +use crate::formatting_contexts::IndependentFormattingContext; use servo_arc::Arc; use style::properties::ComputedValues; #[derive(Debug)] pub(crate) struct FloatBox { - pub style: Arc, pub contents: IndependentFormattingContext, } diff --git a/components/layout_2020/flow/inline.rs b/components/layout_2020/flow/inline.rs index e410fa269ece..8ff68f582f52 100644 --- a/components/layout_2020/flow/inline.rs +++ b/components/layout_2020/flow/inline.rs @@ -118,7 +118,7 @@ impl InlineFormattingContext { }, InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => { let initial_start_corner = - match Display::from(box_.style.get_box().original_display) { + match Display::from(box_.contents.style.get_box().original_display) { Display::GeneratingBox(DisplayGeneratingBox::OutsideInside { outside, inside: _, diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index b690e447cd73..f8ea3e54722b 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -7,6 +7,7 @@ use crate::context::LayoutContext; use crate::flow::float::{FloatBox, FloatContext}; use crate::flow::inline::InlineFormattingContext; +use crate::formatting_contexts::IndependentFormattingContext; use crate::fragments::{ AnonymousFragment, BoxFragment, CollapsedBlockMargins, CollapsedMargin, Fragment, }; @@ -15,7 +16,7 @@ use crate::positioned::{ adjust_static_positions, AbsolutelyPositionedBox, AbsolutelyPositionedFragment, }; use crate::style_ext::{ComputedValuesExt, Position}; -use crate::{relative_adjustement, ContainingBlock, IndependentFormattingContext}; +use crate::{relative_adjustement, ContainingBlock}; use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; use rayon_croissant::ParallelIteratorExt; use servo_arc::Arc; @@ -50,10 +51,7 @@ pub(crate) enum BlockLevelBox { }, OutOfFlowAbsolutelyPositionedBox(AbsolutelyPositionedBox), OutOfFlowFloatBox(FloatBox), - Independent { - style: Arc, - contents: IndependentFormattingContext, - }, + Independent(IndependentFormattingContext), } pub(super) struct FlowChildren { @@ -292,19 +290,24 @@ impl BlockLevelBox { }, )) }, - BlockLevelBox::Independent { style, contents } => match contents.as_replaced() { + BlockLevelBox::Independent(contents) => match contents.as_replaced() { Ok(replaced) => { // FIXME match *replaced {} }, - Err(contents) => Fragment::Box(layout_in_flow_non_replaced_block_level( + Err(non_replaced) => Fragment::Box(layout_in_flow_non_replaced_block_level( layout_context, containing_block, absolutely_positioned_fragments, - style, + &contents.style, BlockLevelKind::EstablishesAnIndependentFormattingContext, |containing_block, nested_abspos, _| { - contents.layout(layout_context, containing_block, tree_rank, nested_abspos) + non_replaced.layout( + layout_context, + containing_block, + tree_rank, + nested_abspos, + ) }, )), }, diff --git a/components/layout_2020/flow/root.rs b/components/layout_2020/flow/root.rs index a1831c6433ae..bbefa5a81df7 100644 --- a/components/layout_2020/flow/root.rs +++ b/components/layout_2020/flow/root.rs @@ -8,6 +8,7 @@ use crate::dom_traversal::{Contents, NodeExt}; use crate::flow::construct::ContainsFloats; use crate::flow::float::FloatBox; use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox}; +use crate::formatting_contexts::IndependentFormattingContext; use crate::fragments::Fragment; use crate::geom; use crate::geom::flow_relative::Vec2; @@ -16,7 +17,7 @@ use crate::replaced::ReplacedContent; use crate::style_ext::{ Direction, Display, DisplayGeneratingBox, DisplayInside, DisplayOutside, WritingMode, }; -use crate::{ContainingBlock, DefiniteContainingBlock, IndependentFormattingContext}; +use crate::{ContainingBlock, DefiniteContainingBlock}; use rayon::iter::{IntoParallelRefIterator, ParallelExtend, ParallelIterator}; use servo_arc::Arc; use style::context::SharedStyleContext; @@ -69,31 +70,32 @@ fn construct_for_root_element<'dom>( } } + let position = box_style.position; + let float = box_style.float; let contents = IndependentFormattingContext::construct( context, - &style, + style, display_inside, Contents::OfElement(root_element), ); - if box_style.position.is_absolutely_positioned() { + if position.is_absolutely_positioned() { ( ContainsFloats::No, vec![Arc::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox( - AbsolutelyPositionedBox { style, contents }, + AbsolutelyPositionedBox { contents }, ))], ) - } else if box_style.float.is_floating() { + } else if float.is_floating() { ( ContainsFloats::Yes, vec![Arc::new(BlockLevelBox::OutOfFlowFloatBox(FloatBox { contents, - style, }))], ) } else { ( ContainsFloats::No, - vec![Arc::new(BlockLevelBox::Independent { style, contents })], + vec![Arc::new(BlockLevelBox::Independent(contents))], ) } } diff --git a/components/layout_2020/formatting_contexts.rs b/components/layout_2020/formatting_contexts.rs new file mode 100644 index 000000000000..b4f9552dff0c --- /dev/null +++ b/components/layout_2020/formatting_contexts.rs @@ -0,0 +1,107 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use crate::context::LayoutContext; +use crate::dom_traversal::{Contents, NodeExt}; +use crate::flow::{BlockFormattingContext, FlowChildren}; +use crate::geom::flow_relative::Vec2; +use crate::positioned::AbsolutelyPositionedFragment; +use crate::replaced::ReplacedContent; +use crate::style_ext::{ComputedValuesExt, Direction, DisplayInside, Position, WritingMode}; +use crate::ContainingBlock; +use servo_arc::Arc; +use std::convert::TryInto; +use style::context::SharedStyleContext; +use style::properties::ComputedValues; + +/// https://drafts.csswg.org/css-display/#independent-formatting-context +#[derive(Debug)] +pub(crate) struct IndependentFormattingContext { + pub style: Arc, + contents: IndependentFormattingContextContents, +} + +// Private so that code outside of this module cannot match variants. +// It should got through methods instead. +#[derive(Debug)] +enum IndependentFormattingContextContents { + Flow(BlockFormattingContext), + + // Not called FC in specs, but behaves close enough + Replaced(ReplacedContent), + // Other layout modes go here +} + +pub(crate) struct NonReplacedIFC<'a>(NonReplacedIFCKind<'a>); + +enum NonReplacedIFCKind<'a> { + Flow(&'a BlockFormattingContext), +} + +impl IndependentFormattingContext { + pub fn construct<'dom, 'style>( + context: &SharedStyleContext<'style>, + style: Arc, + display_inside: DisplayInside, + contents: Contents>, + ) -> Self { + use self::IndependentFormattingContextContents as Contents; + let contents = match contents.try_into() { + Ok(non_replaced) => match display_inside { + DisplayInside::Flow | DisplayInside::FlowRoot => Contents::Flow( + BlockFormattingContext::construct(context, &style, non_replaced), + ), + }, + Err(replaced) => Contents::Replaced(replaced), + }; + Self { style, contents } + } + + pub fn as_replaced(&self) -> Result<&ReplacedContent, NonReplacedIFC> { + use self::IndependentFormattingContextContents as Contents; + use self::NonReplacedIFC as NR; + use self::NonReplacedIFCKind as Kind; + match &self.contents { + Contents::Replaced(r) => Ok(r), + Contents::Flow(f) => Err(NR(Kind::Flow(f))), + } + } + + pub fn layout<'a>( + &'a self, + layout_context: &LayoutContext, + containing_block: &ContainingBlock, + tree_rank: usize, + absolutely_positioned_fragments: &mut Vec>, + ) -> FlowChildren { + match self.as_replaced() { + Ok(replaced) => match *replaced {}, + Err(ifc) => ifc.layout( + layout_context, + containing_block, + tree_rank, + absolutely_positioned_fragments, + ), + } + } +} + +impl<'a> NonReplacedIFC<'a> { + pub fn layout( + &self, + layout_context: &LayoutContext, + containing_block: &ContainingBlock, + tree_rank: usize, + absolutely_positioned_fragments: &mut Vec>, + ) -> FlowChildren { + match &self.0 { + NonReplacedIFCKind::Flow(bfc) => bfc.layout( + layout_context, + containing_block, + tree_rank, + absolutely_positioned_fragments, + ), + } + } +} diff --git a/components/layout_2020/lib.rs b/components/layout_2020/lib.rs index c0892553f350..06db3b65acbe 100644 --- a/components/layout_2020/lib.rs +++ b/components/layout_2020/lib.rs @@ -12,16 +12,13 @@ #[macro_use] extern crate serde; -use style::properties::ComputedValues; -use style::values::computed::{Length, LengthOrAuto}; -use style::Zero; - pub mod context; pub mod data; pub mod display_list; mod dom_traversal; mod element_data; mod flow; +mod formatting_contexts; mod fragments; mod geom; mod opaque_node; @@ -43,87 +40,9 @@ use crate::replaced::ReplacedContent; use crate::style_ext::{ComputedValuesExt, Direction, DisplayInside, Position, WritingMode}; use servo_arc::Arc; use std::convert::TryInto; -use style::context::SharedStyleContext; - -/// https://drafts.csswg.org/css-display/#independent-formatting-context -#[derive(Debug)] -enum IndependentFormattingContext { - Flow(BlockFormattingContext), - - // Not called FC in specs, but behaves close enough - Replaced(ReplacedContent), - // Other layout modes go here -} - -enum NonReplacedIFC<'a> { - Flow(&'a BlockFormattingContext), -} - -impl IndependentFormattingContext { - fn construct<'dom, 'style>( - context: &SharedStyleContext<'style>, - style: &Arc, - display_inside: DisplayInside, - contents: Contents>, - ) -> Self { - match contents.try_into() { - Ok(non_replaced) => match display_inside { - DisplayInside::Flow | DisplayInside::FlowRoot => { - IndependentFormattingContext::Flow(BlockFormattingContext::construct( - context, - style, - non_replaced, - )) - }, - }, - Err(replaced) => IndependentFormattingContext::Replaced(replaced), - } - } - - fn as_replaced(&self) -> Result<&ReplacedContent, NonReplacedIFC> { - match self { - IndependentFormattingContext::Replaced(r) => Ok(r), - IndependentFormattingContext::Flow(f) => Err(NonReplacedIFC::Flow(f)), - } - } - - fn layout<'a>( - &'a self, - layout_context: &LayoutContext, - containing_block: &ContainingBlock, - tree_rank: usize, - absolutely_positioned_fragments: &mut Vec>, - ) -> FlowChildren { - match self.as_replaced() { - Ok(replaced) => match *replaced {}, - Err(ifc) => ifc.layout( - layout_context, - containing_block, - tree_rank, - absolutely_positioned_fragments, - ), - } - } -} - -impl<'a> NonReplacedIFC<'a> { - fn layout( - &self, - layout_context: &LayoutContext, - containing_block: &ContainingBlock, - tree_rank: usize, - absolutely_positioned_fragments: &mut Vec>, - ) -> FlowChildren { - match self { - NonReplacedIFC::Flow(bfc) => bfc.layout( - layout_context, - containing_block, - tree_rank, - absolutely_positioned_fragments, - ), - } - } -} +use style::properties::ComputedValues; +use style::values::computed::{Length, LengthOrAuto}; +use style::Zero; struct ContainingBlock { inline_size: Length, diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs index b37a5ed4a704..1f98512a6487 100644 --- a/components/layout_2020/positioned.rs +++ b/components/layout_2020/positioned.rs @@ -3,10 +3,11 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use crate::context::LayoutContext; +use crate::formatting_contexts::IndependentFormattingContext; use crate::fragments::{AnonymousFragment, BoxFragment, CollapsedBlockMargins, Fragment}; use crate::geom::flow_relative::{Rect, Sides, Vec2}; use crate::style_ext::{ComputedValuesExt, Direction, WritingMode}; -use crate::{ContainingBlock, DefiniteContainingBlock, IndependentFormattingContext}; +use crate::{ContainingBlock, DefiniteContainingBlock}; use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; use servo_arc::Arc; use style::properties::ComputedValues; @@ -15,7 +16,6 @@ use style::Zero; #[derive(Debug)] pub(crate) struct AbsolutelyPositionedBox { - pub style: Arc, pub contents: IndependentFormattingContext, } @@ -49,7 +49,7 @@ impl AbsolutelyPositionedBox { initial_start_corner: Vec2, tree_rank: usize, ) -> AbsolutelyPositionedFragment { - let style = &self.style; + let style = &self.contents.style; let box_offsets = style.box_offsets(); let box_size = style.box_size(); @@ -130,7 +130,7 @@ impl<'a> AbsolutelyPositionedFragment<'a> { layout_context: &LayoutContext, containing_block: &DefiniteContainingBlock, ) -> Fragment { - let style = &self.absolutely_positioned_box.style; + let style = &self.absolutely_positioned_box.contents.style; let cbis = containing_block.size.inline; let cbbs = containing_block.size.block;