Split FlowChildren in IndependentLayout and FlowLayout

The result of doing the layout of an independent formatting context
should be unconcerned with margin collapsing.
This commit is contained in:
Anthony Ramine 2019-11-26 16:21:11 +01:00 committed by Simon Sapin
parent 24b7eadfff
commit 858bc5aca6
6 changed files with 61 additions and 48 deletions

View file

@ -4,7 +4,7 @@
use crate::context::LayoutContext; use crate::context::LayoutContext;
use crate::flow::float::FloatBox; use crate::flow::float::FloatBox;
use crate::flow::FlowChildren; use crate::flow::FlowLayout;
use crate::fragments::{ use crate::fragments::{
AnonymousFragment, BoxFragment, CollapsedBlockMargins, Fragment, TextFragment, AnonymousFragment, BoxFragment, CollapsedBlockMargins, Fragment, TextFragment,
}; };
@ -88,7 +88,7 @@ impl InlineFormattingContext {
containing_block: &ContainingBlock, containing_block: &ContainingBlock,
tree_rank: usize, tree_rank: usize,
absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>, absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>,
) -> FlowChildren { ) -> FlowLayout {
let mut ifc = InlineFormattingContextState { let mut ifc = InlineFormattingContextState {
containing_block, containing_block,
partial_inline_boxes_stack: Vec::new(), partial_inline_boxes_stack: Vec::new(),
@ -156,9 +156,9 @@ impl InlineFormattingContext {
} else { } else {
ifc.line_boxes ifc.line_boxes
.finish_line(&mut ifc.current_nesting_level, containing_block); .finish_line(&mut ifc.current_nesting_level, containing_block);
return FlowChildren { return FlowLayout {
fragments: ifc.line_boxes.boxes, fragments: ifc.line_boxes.boxes,
block_size: ifc.line_boxes.next_line_block_position, content_block_size: ifc.line_boxes.next_line_block_position,
collapsible_margins_in_children: CollapsedBlockMargins::zero(), collapsible_margins_in_children: CollapsedBlockMargins::zero(),
}; };
} }

View file

@ -7,11 +7,11 @@
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::formatting_contexts::{IndependentFormattingContext, IndependentLayout};
use crate::fragments::{ use crate::fragments::{
AnonymousFragment, BoxFragment, CollapsedBlockMargins, CollapsedMargin, Fragment, AnonymousFragment, BoxFragment, CollapsedBlockMargins, CollapsedMargin, Fragment,
}; };
use crate::geom::flow_relative::{Rect, Vec2}; use crate::geom::flow_relative::{Rect, Sides, Vec2};
use crate::positioned::{ use crate::positioned::{
adjust_static_positions, AbsolutelyPositionedBox, AbsolutelyPositionedFragment, adjust_static_positions, AbsolutelyPositionedBox, AbsolutelyPositionedFragment,
}; };
@ -54,9 +54,9 @@ pub(crate) enum BlockLevelBox {
Independent(IndependentFormattingContext), Independent(IndependentFormattingContext),
} }
pub(super) struct FlowChildren { struct FlowLayout {
pub fragments: Vec<Fragment>, pub fragments: Vec<Fragment>,
pub block_size: Length, pub content_block_size: Length,
pub collapsible_margins_in_children: CollapsedBlockMargins, pub collapsible_margins_in_children: CollapsedBlockMargins,
} }
@ -70,7 +70,7 @@ impl BlockFormattingContext {
containing_block: &ContainingBlock, containing_block: &ContainingBlock,
tree_rank: usize, tree_rank: usize,
absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>, absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>,
) -> FlowChildren { ) -> IndependentLayout {
let mut float_context; let mut float_context;
let float_context = if self.contains_floats { let float_context = if self.contains_floats {
float_context = FloatContext::new(); float_context = FloatContext::new();
@ -78,7 +78,7 @@ impl BlockFormattingContext {
} else { } else {
None None
}; };
let mut flow_children = self.contents.layout( let flow_layout = self.contents.layout(
layout_context, layout_context,
containing_block, containing_block,
tree_rank, tree_rank,
@ -86,12 +86,16 @@ impl BlockFormattingContext {
float_context, float_context,
CollapsibleWithParentStartMargin(false), CollapsibleWithParentStartMargin(false),
); );
flow_children.block_size += flow_children.collapsible_margins_in_children.end.solve(); assert!(
flow_children !flow_layout
.collapsible_margins_in_children .collapsible_margins_in_children
.collapsed_through = false; .collapsed_through
flow_children.collapsible_margins_in_children.end = CollapsedMargin::zero(); );
flow_children IndependentLayout {
fragments: flow_layout.fragments,
content_block_size: flow_layout.content_block_size +
flow_layout.collapsible_margins_in_children.end.solve(),
}
} }
} }
@ -104,7 +108,7 @@ impl BlockContainer {
absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>, absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>,
float_context: Option<&mut FloatContext>, float_context: Option<&mut FloatContext>,
collapsible_with_parent_start_margin: CollapsibleWithParentStartMargin, collapsible_with_parent_start_margin: CollapsibleWithParentStartMargin,
) -> FlowChildren { ) -> FlowLayout {
match self { match self {
BlockContainer::BlockLevelBoxes(child_boxes) => layout_block_level_children( BlockContainer::BlockLevelBoxes(child_boxes) => layout_block_level_children(
layout_context, layout_context,
@ -133,7 +137,7 @@ fn layout_block_level_children<'a>(
absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>, absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>,
float_context: Option<&mut FloatContext>, float_context: Option<&mut FloatContext>,
collapsible_with_parent_start_margin: CollapsibleWithParentStartMargin, collapsible_with_parent_start_margin: CollapsibleWithParentStartMargin,
) -> FlowChildren { ) -> FlowLayout {
fn place_block_level_fragment(fragment: &mut Fragment, placement_state: &mut PlacementState) { fn place_block_level_fragment(fragment: &mut Fragment, placement_state: &mut PlacementState) {
match fragment { match fragment {
Fragment::Box(fragment) => { Fragment::Box(fragment) => {
@ -249,9 +253,9 @@ fn layout_block_level_children<'a>(
tree_rank, tree_rank,
); );
FlowChildren { FlowLayout {
fragments, fragments,
block_size: placement_state.current_block_direction_position, content_block_size: placement_state.current_block_direction_position,
collapsible_margins_in_children: CollapsedBlockMargins { collapsible_margins_in_children: CollapsedBlockMargins {
collapsed_through: placement_state collapsed_through: placement_state
.next_in_flow_margin_collapses_with_parent_start_margin, .next_in_flow_margin_collapses_with_parent_start_margin,
@ -302,12 +306,17 @@ impl BlockLevelBox {
&contents.style, &contents.style,
BlockLevelKind::EstablishesAnIndependentFormattingContext, BlockLevelKind::EstablishesAnIndependentFormattingContext,
|containing_block, nested_abspos, _| { |containing_block, nested_abspos, _| {
non_replaced.layout( let independent_layout = non_replaced.layout(
layout_context, layout_context,
containing_block, containing_block,
tree_rank, tree_rank,
nested_abspos, nested_abspos,
) );
FlowLayout {
fragments: independent_layout.fragments,
content_block_size: independent_layout.content_block_size,
collapsible_margins_in_children: CollapsedBlockMargins::zero(),
}
}, },
)), )),
}, },
@ -341,7 +350,7 @@ fn layout_in_flow_non_replaced_block_level<'a>(
&ContainingBlock, &ContainingBlock,
&mut Vec<AbsolutelyPositionedFragment<'a>>, &mut Vec<AbsolutelyPositionedFragment<'a>>,
CollapsibleWithParentStartMargin, CollapsibleWithParentStartMargin,
) -> FlowChildren, ) -> FlowLayout,
) -> BoxFragment { ) -> BoxFragment {
let cbis = containing_block.inline_size; let cbis = containing_block.inline_size;
let padding = style.padding().percentages_relative_to(cbis); let padding = style.padding().percentages_relative_to(cbis);
@ -400,7 +409,7 @@ fn layout_in_flow_non_replaced_block_level<'a>(
LengthOrAuto::Auto, LengthOrAuto::Auto,
); );
let mut nested_abspos = vec![]; let mut nested_abspos = vec![];
let mut flow_children = layout_contents( let mut flow_layout = layout_contents(
&containing_block_for_children, &containing_block_for_children,
if style.get_box().position == Position::Relative { if style.get_box().position == Position::Relative {
&mut nested_abspos &mut nested_abspos
@ -412,15 +421,15 @@ fn layout_in_flow_non_replaced_block_level<'a>(
if this_start_margin_can_collapse_with_children.0 { if this_start_margin_can_collapse_with_children.0 {
block_margins_collapsed_with_children block_margins_collapsed_with_children
.start .start
.adjoin_assign(&flow_children.collapsible_margins_in_children.start); .adjoin_assign(&flow_layout.collapsible_margins_in_children.start);
if flow_children if flow_layout
.collapsible_margins_in_children .collapsible_margins_in_children
.collapsed_through .collapsed_through
{ {
block_margins_collapsed_with_children block_margins_collapsed_with_children
.start .start
.adjoin_assign(&std::mem::replace( .adjoin_assign(&std::mem::replace(
&mut flow_children.collapsible_margins_in_children.end, &mut flow_layout.collapsible_margins_in_children.end,
CollapsedMargin::zero(), CollapsedMargin::zero(),
)); ));
} }
@ -428,18 +437,18 @@ fn layout_in_flow_non_replaced_block_level<'a>(
if this_end_margin_can_collapse_with_children { if this_end_margin_can_collapse_with_children {
block_margins_collapsed_with_children block_margins_collapsed_with_children
.end .end
.adjoin_assign(&flow_children.collapsible_margins_in_children.end); .adjoin_assign(&flow_layout.collapsible_margins_in_children.end);
} else { } else {
flow_children.block_size += flow_children.collapsible_margins_in_children.end.solve(); flow_layout.content_block_size += flow_layout.collapsible_margins_in_children.end.solve();
} }
block_margins_collapsed_with_children.collapsed_through = block_margins_collapsed_with_children.collapsed_through =
this_start_margin_can_collapse_with_children.0 && this_start_margin_can_collapse_with_children.0 &&
this_end_margin_can_collapse_with_children && this_end_margin_can_collapse_with_children &&
flow_children flow_layout
.collapsible_margins_in_children .collapsible_margins_in_children
.collapsed_through; .collapsed_through;
let relative_adjustement = relative_adjustement(style, inline_size, block_size); let relative_adjustement = relative_adjustement(style, inline_size, block_size);
let block_size = block_size.auto_is(|| flow_children.block_size); let block_size = block_size.auto_is(|| flow_layout.content_block_size);
let content_rect = Rect { let content_rect = Rect {
start_corner: Vec2 { start_corner: Vec2 {
block: pb.block_start + relative_adjustement.block, block: pb.block_start + relative_adjustement.block,
@ -454,7 +463,7 @@ fn layout_in_flow_non_replaced_block_level<'a>(
AbsolutelyPositionedFragment::in_positioned_containing_block( AbsolutelyPositionedFragment::in_positioned_containing_block(
layout_context, layout_context,
&nested_abspos, &nested_abspos,
&mut flow_children.fragments, &mut flow_layout.fragments,
&content_rect.size, &content_rect.size,
&padding, &padding,
containing_block_for_children.mode, containing_block_for_children.mode,
@ -462,7 +471,7 @@ fn layout_in_flow_non_replaced_block_level<'a>(
} }
BoxFragment { BoxFragment {
style: style.clone(), style: style.clone(),
children: flow_children.fragments, children: flow_layout.fragments,
content_rect, content_rect,
padding, padding,
border, border,

View file

@ -31,10 +31,7 @@ pub struct BoxTreeRoot(BlockFormattingContext);
pub struct FragmentTreeRoot(Vec<Fragment>); pub struct FragmentTreeRoot(Vec<Fragment>);
impl BoxTreeRoot { impl BoxTreeRoot {
pub fn construct<'dom, Node>( pub fn construct<'dom, Node>(context: &SharedStyleContext<'_>, root_element: Node) -> Self
context: &SharedStyleContext<'_>,
root_element: Node,
) -> Self
where where
Node: 'dom + Copy + LayoutNode + Send + Sync, Node: 'dom + Copy + LayoutNode + Send + Sync,
{ {
@ -124,7 +121,7 @@ impl BoxTreeRoot {
}; };
let dummy_tree_rank = 0; let dummy_tree_rank = 0;
let mut absolutely_positioned_fragments = vec![]; let mut absolutely_positioned_fragments = vec![];
let mut flow_children = self.0.layout( let mut independent_layout = self.0.layout(
layout_context, layout_context,
&initial_containing_block, &initial_containing_block,
dummy_tree_rank, dummy_tree_rank,
@ -135,12 +132,12 @@ impl BoxTreeRoot {
size: initial_containing_block_size, size: initial_containing_block_size,
mode: initial_containing_block.mode, mode: initial_containing_block.mode,
}; };
flow_children.fragments.par_extend( independent_layout.fragments.par_extend(
absolutely_positioned_fragments absolutely_positioned_fragments
.par_iter() .par_iter()
.map(|a| a.layout(layout_context, &initial_containing_block)), .map(|a| a.layout(layout_context, &initial_containing_block)),
); );
FragmentTreeRoot(flow_children.fragments) FragmentTreeRoot(independent_layout.fragments)
} }
} }

View file

@ -4,7 +4,8 @@
use crate::context::LayoutContext; use crate::context::LayoutContext;
use crate::dom_traversal::{Contents, NodeExt}; use crate::dom_traversal::{Contents, NodeExt};
use crate::flow::{BlockFormattingContext, FlowChildren}; use crate::flow::BlockFormattingContext;
use crate::fragments::Fragment;
use crate::geom::flow_relative::Vec2; use crate::geom::flow_relative::Vec2;
use crate::positioned::AbsolutelyPositionedFragment; use crate::positioned::AbsolutelyPositionedFragment;
use crate::replaced::ReplacedContent; use crate::replaced::ReplacedContent;
@ -14,6 +15,7 @@ use servo_arc::Arc;
use std::convert::TryInto; use std::convert::TryInto;
use style::context::SharedStyleContext; use style::context::SharedStyleContext;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::values::computed::Length;
/// https://drafts.csswg.org/css-display/#independent-formatting-context /// https://drafts.csswg.org/css-display/#independent-formatting-context
#[derive(Debug)] #[derive(Debug)]
@ -22,6 +24,11 @@ pub(crate) struct IndependentFormattingContext {
contents: IndependentFormattingContextContents, contents: IndependentFormattingContextContents,
} }
pub(crate) struct IndependentLayout {
pub fragments: Vec<Fragment>,
pub content_block_size: Length,
}
// Private so that code outside of this module cannot match variants. // Private so that code outside of this module cannot match variants.
// It should got through methods instead. // It should got through methods instead.
#[derive(Debug)] #[derive(Debug)]
@ -74,7 +81,7 @@ impl IndependentFormattingContext {
containing_block: &ContainingBlock, containing_block: &ContainingBlock,
tree_rank: usize, tree_rank: usize,
absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>, absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>,
) -> FlowChildren { ) -> IndependentLayout {
match self.as_replaced() { match self.as_replaced() {
Ok(replaced) => match *replaced {}, Ok(replaced) => match *replaced {},
Err(ifc) => ifc.layout( Err(ifc) => ifc.layout(
@ -94,7 +101,7 @@ impl<'a> NonReplacedIFC<'a> {
containing_block: &ContainingBlock, containing_block: &ContainingBlock,
tree_rank: usize, tree_rank: usize,
absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>, absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>,
) -> FlowChildren { ) -> IndependentLayout {
match &self.0 { match &self.0 {
NonReplacedIFCKind::Flow(bfc) => bfc.layout( NonReplacedIFCKind::Flow(bfc) => bfc.layout(
layout_context, layout_context,

View file

@ -33,7 +33,7 @@ pub use flow::{BoxTreeRoot, FragmentTreeRoot};
use crate::context::LayoutContext; use crate::context::LayoutContext;
use crate::dom_traversal::{Contents, NodeExt}; use crate::dom_traversal::{Contents, NodeExt};
use crate::flow::{BlockFormattingContext, FlowChildren}; use crate::flow::BlockFormattingContext;
use crate::geom::flow_relative::Vec2; use crate::geom::flow_relative::Vec2;
use crate::positioned::AbsolutelyPositionedFragment; use crate::positioned::AbsolutelyPositionedFragment;
use crate::replaced::ReplacedContent; use crate::replaced::ReplacedContent;

View file

@ -274,7 +274,7 @@ impl<'a> AbsolutelyPositionedFragment<'a> {
); );
let dummy_tree_rank = 0; let dummy_tree_rank = 0;
let mut absolutely_positioned_fragments = vec![]; let mut absolutely_positioned_fragments = vec![];
let mut flow_children = self.absolutely_positioned_box.contents.layout( let mut independent_layout = self.absolutely_positioned_box.contents.layout(
layout_context, layout_context,
&containing_block_for_children, &containing_block_for_children,
dummy_tree_rank, dummy_tree_rank,
@ -286,7 +286,7 @@ impl<'a> AbsolutelyPositionedFragment<'a> {
Anchor::End(end) => cbbs - end - pb.inline_end - margin.inline_end - inline_size, Anchor::End(end) => cbbs - end - pb.inline_end - margin.inline_end - inline_size,
}; };
let block_size = block_size.auto_is(|| flow_children.block_size); let block_size = block_size.auto_is(|| independent_layout.content_block_size);
let block_start = match block_anchor { let block_start = match block_anchor {
Anchor::Start(start) => start + pb.block_start + margin.block_start, Anchor::Start(start) => start + pb.block_start + margin.block_start,
Anchor::End(end) => cbbs - end - pb.block_end - margin.block_end - block_size, Anchor::End(end) => cbbs - end - pb.block_end - margin.block_end - block_size,
@ -306,7 +306,7 @@ impl<'a> AbsolutelyPositionedFragment<'a> {
AbsolutelyPositionedFragment::in_positioned_containing_block( AbsolutelyPositionedFragment::in_positioned_containing_block(
layout_context, layout_context,
&absolutely_positioned_fragments, &absolutely_positioned_fragments,
&mut flow_children.fragments, &mut independent_layout.fragments,
&content_rect.size, &content_rect.size,
&padding, &padding,
containing_block_for_children.mode, containing_block_for_children.mode,
@ -314,7 +314,7 @@ impl<'a> AbsolutelyPositionedFragment<'a> {
Fragment::Box(BoxFragment { Fragment::Box(BoxFragment {
style: style.clone(), style: style.clone(),
children: flow_children.fragments, children: independent_layout.fragments,
content_rect, content_rect,
padding, padding,
border, border,