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

@ -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,
),
}
}
}