Make IndependentFormattingContext a struct that owns styles

… 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.
This commit is contained in:
Simon Sapin 2019-11-26 11:22:23 +01:00
parent 799057f1e6
commit b2b3ea992c
9 changed files with 149 additions and 123 deletions

View file

@ -30,7 +30,7 @@ pub(super) enum Contents<Node> {
/// <https://drafts.csswg.org/css2/conform.html#replaced-element> /// <https://drafts.csswg.org/css2/conform.html#replaced-element>
Replaced(ReplacedContent), 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.
/// <https://drafts.csswg.org/css2/generate.html#content> /// <https://drafts.csswg.org/css2/generate.html#content>
OfPseudoElement(Vec<PseudoElementContentItem>), OfPseudoElement(Vec<PseudoElementContentItem>),
} }

View file

@ -7,9 +7,10 @@ use crate::element_data::LayoutBox;
use crate::flow::float::FloatBox; use crate::flow::float::FloatBox;
use crate::flow::inline::{InlineBox, InlineFormattingContext, InlineLevelBox, TextRun}; use crate::flow::inline::{InlineBox, InlineFormattingContext, InlineLevelBox, TextRun};
use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox}; use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox};
use crate::formatting_contexts::IndependentFormattingContext;
use crate::positioned::AbsolutelyPositionedBox; use crate::positioned::AbsolutelyPositionedBox;
use crate::style_ext::{DisplayGeneratingBox, DisplayInside, DisplayOutside}; use crate::style_ext::{DisplayGeneratingBox, DisplayInside, DisplayOutside};
use crate::{take, IndependentFormattingContext}; use crate::take;
use rayon::iter::{IntoParallelIterator, ParallelIterator}; use rayon::iter::{IntoParallelIterator, ParallelIterator};
use rayon_croissant::ParallelIteratorExt; use rayon_croissant::ParallelIteratorExt;
use servo_arc::Arc; use servo_arc::Arc;
@ -450,11 +451,10 @@ where
AbsolutelyPositionedBox { AbsolutelyPositionedBox {
contents: IndependentFormattingContext::construct( contents: IndependentFormattingContext::construct(
unimplemented!(), unimplemented!(),
&style, style,
display_inside, display_inside,
contents, contents,
), ),
style,
}, },
)); ));
self.current_inline_level_boxes().push(box_.clone()); self.current_inline_level_boxes().push(box_.clone());
@ -482,11 +482,10 @@ where
let box_ = Arc::new(InlineLevelBox::OutOfFlowFloatBox(FloatBox { let box_ = Arc::new(InlineLevelBox::OutOfFlowFloatBox(FloatBox {
contents: IndependentFormattingContext::construct( contents: IndependentFormattingContext::construct(
self.context, self.context,
&style, style,
display_inside, display_inside,
contents, contents,
), ),
style,
})); }));
self.current_inline_level_boxes().push(box_.clone()); self.current_inline_level_boxes().push(box_.clone());
box_slot.set(LayoutBox::InlineLevel(box_)) box_slot.set(LayoutBox::InlineLevel(box_))
@ -562,12 +561,12 @@ where
} => { } => {
let contents = IndependentFormattingContext::construct( let contents = IndependentFormattingContext::construct(
context, context,
&style, style,
display_inside, display_inside,
contents, contents,
); );
( (
Arc::new(BlockLevelBox::Independent { style, contents }), Arc::new(BlockLevelBox::Independent(contents)),
ContainsFloats::No, ContainsFloats::No,
) )
}, },
@ -580,11 +579,10 @@ where
AbsolutelyPositionedBox { AbsolutelyPositionedBox {
contents: IndependentFormattingContext::construct( contents: IndependentFormattingContext::construct(
context, context,
&style, style,
display_inside, display_inside,
contents, contents,
), ),
style: style,
}, },
)); ));
(block_level_box, ContainsFloats::No) (block_level_box, ContainsFloats::No)
@ -596,14 +594,12 @@ where
} => { } => {
let contents = IndependentFormattingContext::construct( let contents = IndependentFormattingContext::construct(
context, context,
&style, style,
display_inside, display_inside,
contents, contents,
); );
let block_level_box = Arc::new(BlockLevelBox::OutOfFlowFloatBox(FloatBox { let block_level_box =
contents, Arc::new(BlockLevelBox::OutOfFlowFloatBox(FloatBox { contents }));
style,
}));
(block_level_box, ContainsFloats::Yes) (block_level_box, ContainsFloats::Yes)
}, },
} }

View file

@ -2,13 +2,12 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * 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 servo_arc::Arc;
use style::properties::ComputedValues; use style::properties::ComputedValues;
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct FloatBox { pub(crate) struct FloatBox {
pub style: Arc<ComputedValues>,
pub contents: IndependentFormattingContext, pub contents: IndependentFormattingContext,
} }

View file

@ -118,7 +118,7 @@ impl InlineFormattingContext {
}, },
InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => { InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => {
let initial_start_corner = 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 { Display::GeneratingBox(DisplayGeneratingBox::OutsideInside {
outside, outside,
inside: _, inside: _,

View file

@ -7,6 +7,7 @@
use crate::context::LayoutContext; use crate::context::LayoutContext;
use crate::flow::float::{FloatBox, FloatContext}; use crate::flow::float::{FloatBox, FloatContext};
use crate::flow::inline::InlineFormattingContext; use crate::flow::inline::InlineFormattingContext;
use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragments::{ use crate::fragments::{
AnonymousFragment, BoxFragment, CollapsedBlockMargins, CollapsedMargin, Fragment, AnonymousFragment, BoxFragment, CollapsedBlockMargins, CollapsedMargin, Fragment,
}; };
@ -15,7 +16,7 @@ use crate::positioned::{
adjust_static_positions, AbsolutelyPositionedBox, AbsolutelyPositionedFragment, adjust_static_positions, AbsolutelyPositionedBox, AbsolutelyPositionedFragment,
}; };
use crate::style_ext::{ComputedValuesExt, Position}; 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::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
use rayon_croissant::ParallelIteratorExt; use rayon_croissant::ParallelIteratorExt;
use servo_arc::Arc; use servo_arc::Arc;
@ -50,10 +51,7 @@ pub(crate) enum BlockLevelBox {
}, },
OutOfFlowAbsolutelyPositionedBox(AbsolutelyPositionedBox), OutOfFlowAbsolutelyPositionedBox(AbsolutelyPositionedBox),
OutOfFlowFloatBox(FloatBox), OutOfFlowFloatBox(FloatBox),
Independent { Independent(IndependentFormattingContext),
style: Arc<ComputedValues>,
contents: IndependentFormattingContext,
},
} }
pub(super) struct FlowChildren { 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) => { Ok(replaced) => {
// FIXME // FIXME
match *replaced {} 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, layout_context,
containing_block, containing_block,
absolutely_positioned_fragments, absolutely_positioned_fragments,
style, &contents.style,
BlockLevelKind::EstablishesAnIndependentFormattingContext, BlockLevelKind::EstablishesAnIndependentFormattingContext,
|containing_block, nested_abspos, _| { |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,
)
}, },
)), )),
}, },

View file

@ -8,6 +8,7 @@ use crate::dom_traversal::{Contents, NodeExt};
use crate::flow::construct::ContainsFloats; use crate::flow::construct::ContainsFloats;
use crate::flow::float::FloatBox; use crate::flow::float::FloatBox;
use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox}; use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox};
use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragments::Fragment; use crate::fragments::Fragment;
use crate::geom; use crate::geom;
use crate::geom::flow_relative::Vec2; use crate::geom::flow_relative::Vec2;
@ -16,7 +17,7 @@ use crate::replaced::ReplacedContent;
use crate::style_ext::{ use crate::style_ext::{
Direction, Display, DisplayGeneratingBox, DisplayInside, DisplayOutside, WritingMode, Direction, Display, DisplayGeneratingBox, DisplayInside, DisplayOutside, WritingMode,
}; };
use crate::{ContainingBlock, DefiniteContainingBlock, IndependentFormattingContext}; use crate::{ContainingBlock, DefiniteContainingBlock};
use rayon::iter::{IntoParallelRefIterator, ParallelExtend, ParallelIterator}; use rayon::iter::{IntoParallelRefIterator, ParallelExtend, ParallelIterator};
use servo_arc::Arc; use servo_arc::Arc;
use style::context::SharedStyleContext; 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( let contents = IndependentFormattingContext::construct(
context, context,
&style, style,
display_inside, display_inside,
Contents::OfElement(root_element), Contents::OfElement(root_element),
); );
if box_style.position.is_absolutely_positioned() { if position.is_absolutely_positioned() {
( (
ContainsFloats::No, ContainsFloats::No,
vec![Arc::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox( vec![Arc::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(
AbsolutelyPositionedBox { style, contents }, AbsolutelyPositionedBox { contents },
))], ))],
) )
} else if box_style.float.is_floating() { } else if float.is_floating() {
( (
ContainsFloats::Yes, ContainsFloats::Yes,
vec![Arc::new(BlockLevelBox::OutOfFlowFloatBox(FloatBox { vec![Arc::new(BlockLevelBox::OutOfFlowFloatBox(FloatBox {
contents, contents,
style,
}))], }))],
) )
} else { } else {
( (
ContainsFloats::No, ContainsFloats::No,
vec![Arc::new(BlockLevelBox::Independent { style, contents })], vec![Arc::new(BlockLevelBox::Independent(contents))],
) )
} }
} }

View file

@ -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<ComputedValues>,
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<ComputedValues>,
display_inside: DisplayInside,
contents: Contents<impl NodeExt<'dom>>,
) -> 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<AbsolutelyPositionedFragment<'a>>,
) -> 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<AbsolutelyPositionedFragment<'a>>,
) -> FlowChildren {
match &self.0 {
NonReplacedIFCKind::Flow(bfc) => bfc.layout(
layout_context,
containing_block,
tree_rank,
absolutely_positioned_fragments,
),
}
}
}

View file

@ -12,16 +12,13 @@
#[macro_use] #[macro_use]
extern crate serde; extern crate serde;
use style::properties::ComputedValues;
use style::values::computed::{Length, LengthOrAuto};
use style::Zero;
pub mod context; pub mod context;
pub mod data; pub mod data;
pub mod display_list; pub mod display_list;
mod dom_traversal; mod dom_traversal;
mod element_data; mod element_data;
mod flow; mod flow;
mod formatting_contexts;
mod fragments; mod fragments;
mod geom; mod geom;
mod opaque_node; mod opaque_node;
@ -43,87 +40,9 @@ use crate::replaced::ReplacedContent;
use crate::style_ext::{ComputedValuesExt, Direction, DisplayInside, Position, WritingMode}; use crate::style_ext::{ComputedValuesExt, Direction, DisplayInside, Position, WritingMode};
use servo_arc::Arc; use servo_arc::Arc;
use std::convert::TryInto; use std::convert::TryInto;
use style::context::SharedStyleContext; use style::properties::ComputedValues;
use style::values::computed::{Length, LengthOrAuto};
/// https://drafts.csswg.org/css-display/#independent-formatting-context use style::Zero;
#[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<ComputedValues>,
display_inside: DisplayInside,
contents: Contents<impl NodeExt<'dom>>,
) -> 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<AbsolutelyPositionedFragment<'a>>,
) -> 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<AbsolutelyPositionedFragment<'a>>,
) -> FlowChildren {
match self {
NonReplacedIFC::Flow(bfc) => bfc.layout(
layout_context,
containing_block,
tree_rank,
absolutely_positioned_fragments,
),
}
}
}
struct ContainingBlock { struct ContainingBlock {
inline_size: Length, inline_size: Length,

View file

@ -3,10 +3,11 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::context::LayoutContext; use crate::context::LayoutContext;
use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragments::{AnonymousFragment, BoxFragment, CollapsedBlockMargins, Fragment}; use crate::fragments::{AnonymousFragment, BoxFragment, CollapsedBlockMargins, Fragment};
use crate::geom::flow_relative::{Rect, Sides, Vec2}; use crate::geom::flow_relative::{Rect, Sides, Vec2};
use crate::style_ext::{ComputedValuesExt, Direction, WritingMode}; use crate::style_ext::{ComputedValuesExt, Direction, WritingMode};
use crate::{ContainingBlock, DefiniteContainingBlock, IndependentFormattingContext}; use crate::{ContainingBlock, DefiniteContainingBlock};
use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
use servo_arc::Arc; use servo_arc::Arc;
use style::properties::ComputedValues; use style::properties::ComputedValues;
@ -15,7 +16,6 @@ use style::Zero;
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct AbsolutelyPositionedBox { pub(crate) struct AbsolutelyPositionedBox {
pub style: Arc<ComputedValues>,
pub contents: IndependentFormattingContext, pub contents: IndependentFormattingContext,
} }
@ -49,7 +49,7 @@ impl AbsolutelyPositionedBox {
initial_start_corner: Vec2<Length>, initial_start_corner: Vec2<Length>,
tree_rank: usize, tree_rank: usize,
) -> AbsolutelyPositionedFragment { ) -> AbsolutelyPositionedFragment {
let style = &self.style; let style = &self.contents.style;
let box_offsets = style.box_offsets(); let box_offsets = style.box_offsets();
let box_size = style.box_size(); let box_size = style.box_size();
@ -130,7 +130,7 @@ impl<'a> AbsolutelyPositionedFragment<'a> {
layout_context: &LayoutContext, layout_context: &LayoutContext,
containing_block: &DefiniteContainingBlock, containing_block: &DefiniteContainingBlock,
) -> Fragment { ) -> Fragment {
let style = &self.absolutely_positioned_box.style; let style = &self.absolutely_positioned_box.contents.style;
let cbis = containing_block.size.inline; let cbis = containing_block.size.inline;
let cbbs = containing_block.size.block; let cbbs = containing_block.size.block;