From 744f075181a39fe2684d83005f381cffbc941c4b Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 24 Jul 2020 10:39:15 -0700 Subject: [PATCH 1/4] Allow adjusting box offsets --- components/layout_2020/flow/mod.rs | 3 +++ components/layout_2020/positioned.rs | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index f042f814dd32..325133529800 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -352,6 +352,9 @@ impl BlockLevelBox { BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => { let hoisted_box = AbsolutelyPositionedBox::to_hoisted( box_.clone(), + // This is incorrect, however we do not know the + // correct positioning until later, in place_block_level_fragment, + // and this value will be adjusted there Vec2::zero(), tree_rank, containing_block, diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs index 853b22347e9e..eb455eb4990b 100644 --- a/components/layout_2020/positioned.rs +++ b/components/layout_2020/positioned.rs @@ -49,6 +49,16 @@ pub(crate) struct HoistedAbsolutelyPositionedBox { pub fragment: ArcRefCell>>, } +impl HoistedAbsolutelyPositionedBox { + /// In some cases `inset: auto`-positioned elements do not know their precise + /// position until after they're hoisted. This lets us adjust auto values + /// after the fact. + pub(crate) fn adjust_offsets(&mut self, offsets: Vec2) { + self.box_offsets.inline.adjust_offset(offsets.inline); + self.box_offsets.block.adjust_offset(offsets.block); + } +} + #[derive(Clone, Debug)] pub(crate) enum AbsoluteBoxOffsets { StaticStart { @@ -66,6 +76,15 @@ pub(crate) enum AbsoluteBoxOffsets { }, } +impl AbsoluteBoxOffsets { + fn adjust_offset(&mut self, new_offset: Length) { + match *self { + AbsoluteBoxOffsets::StaticStart {ref mut start} => *start = new_offset, + _ => () + } + } +} + impl AbsolutelyPositionedBox { pub fn construct<'dom>( context: &LayoutContext, From 76ae734811e21b9977292950cfaa07264b554a79 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 24 Jul 2020 11:50:11 -0700 Subject: [PATCH 2/4] Bubble out hoisted box --- components/layout_2020/flow/mod.rs | 114 ++++++++++++++++----------- components/layout_2020/positioned.rs | 4 +- 2 files changed, 69 insertions(+), 49 deletions(-) diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index 325133529800..c5e2f1ed73b8 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -16,7 +16,9 @@ use crate::fragments::{ CollapsedMargin, Fragment, Tag, }; use crate::geom::flow_relative::{Rect, Sides, Vec2}; -use crate::positioned::{AbsolutelyPositionedBox, PositioningContext}; +use crate::positioned::{ + AbsolutelyPositionedBox, HoistedAbsolutelyPositionedBox, PositioningContext, +}; use crate::replaced::ReplacedContent; use crate::sizing::{self, ContentSizes}; use crate::style_ext::{ComputedValuesExt, PaddingBorderMargin}; @@ -229,13 +231,16 @@ fn layout_block_level_children( .iter() .enumerate() .map(|(tree_rank, box_)| { - let mut fragment = box_.borrow_mut().layout( - layout_context, - positioning_context, - containing_block, - tree_rank, - float_context.as_mut().map(|c| &mut **c), - ); + let mut fragment = box_ + .borrow_mut() + .layout( + layout_context, + positioning_context, + containing_block, + tree_rank, + float_context.as_mut().map(|c| &mut **c), + ) + .0; place_block_level_fragment(&mut fragment, &mut placement_state); fragment }) @@ -249,13 +254,15 @@ fn layout_block_level_children( .mapfold_reduce_into( positioning_context, |positioning_context, (tree_rank, box_)| { - box_.borrow_mut().layout( - layout_context, - positioning_context, - containing_block, - tree_rank, - /* float_context = */ None, - ) + box_.borrow_mut() + .layout( + layout_context, + positioning_context, + containing_block, + tree_rank, + /* float_context = */ None, + ) + .0 }, || PositioningContext::new_for_rayon(collects_for_nearest_positioned_ancestor), PositioningContext::append, @@ -281,6 +288,9 @@ fn layout_block_level_children( } impl BlockLevelBox { + /// Lays out the box. In case it is absolutely positioned, + /// this also returns the HoistedAbsolutelyPositionedBox which will need + /// to be adjusted before being added to the positioning context fn layout( &mut self, layout_context: &LayoutContext, @@ -288,31 +298,34 @@ impl BlockLevelBox { containing_block: &ContainingBlock, tree_rank: usize, float_context: Option<&mut FloatContext>, - ) -> Fragment { + ) -> (Fragment, Option) { match self { BlockLevelBox::SameFormattingContextBlock { tag, style, contents, - } => Fragment::Box(positioning_context.layout_maybe_position_relative_fragment( - layout_context, - containing_block, - style, - |positioning_context| { - layout_in_flow_non_replaced_block_level( - layout_context, - positioning_context, - containing_block, - *tag, - style, - NonReplacedContents::SameFormattingContextBlock(contents), - tree_rank, - float_context, - ) - }, - )), + } => ( + Fragment::Box(positioning_context.layout_maybe_position_relative_fragment( + layout_context, + containing_block, + style, + |positioning_context| { + layout_in_flow_non_replaced_block_level( + layout_context, + positioning_context, + containing_block, + *tag, + style, + NonReplacedContents::SameFormattingContextBlock(contents), + tree_rank, + float_context, + ) + }, + )), + None, + ), BlockLevelBox::Independent(independent) => match independent { - IndependentFormattingContext::Replaced(replaced) => { + IndependentFormattingContext::Replaced(replaced) => ( Fragment::Box(positioning_context.layout_maybe_position_relative_fragment( layout_context, containing_block, @@ -325,9 +338,10 @@ impl BlockLevelBox { &replaced.contents, ) }, - )) - }, - IndependentFormattingContext::NonReplaced(non_replaced) => { + )), + None, + ), + IndependentFormattingContext::NonReplaced(non_replaced) => ( Fragment::Box(positioning_context.layout_maybe_position_relative_fragment( layout_context, containing_block, @@ -346,8 +360,9 @@ impl BlockLevelBox { float_context, ) }, - )) - }, + )), + None, + ), }, BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => { let hoisted_box = AbsolutelyPositionedBox::to_hoisted( @@ -360,17 +375,22 @@ impl BlockLevelBox { containing_block, ); let hoisted_fragment = hoisted_box.fragment.clone(); - positioning_context.push(hoisted_box); - Fragment::AbsoluteOrFixedPositioned(AbsoluteOrFixedPositionedFragment { - hoisted_fragment, - position: box_.borrow().context.style().clone_position(), - }) + ( + Fragment::AbsoluteOrFixedPositioned(AbsoluteOrFixedPositionedFragment { + hoisted_fragment, + position: box_.borrow().context.style().clone_position(), + }), + Some(hoisted_box), + ) }, BlockLevelBox::OutOfFlowFloatBox(_box_) => { // FIXME: call layout_maybe_position_relative_fragment here - Fragment::Anonymous(AnonymousFragment::no_op( - containing_block.style.writing_mode, - )) + ( + Fragment::Anonymous(AnonymousFragment::no_op( + containing_block.style.writing_mode, + )), + None, + ) }, } } diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs index eb455eb4990b..3773b53afccd 100644 --- a/components/layout_2020/positioned.rs +++ b/components/layout_2020/positioned.rs @@ -79,8 +79,8 @@ pub(crate) enum AbsoluteBoxOffsets { impl AbsoluteBoxOffsets { fn adjust_offset(&mut self, new_offset: Length) { match *self { - AbsoluteBoxOffsets::StaticStart {ref mut start} => *start = new_offset, - _ => () + AbsoluteBoxOffsets::StaticStart { ref mut start } => *start = new_offset, + _ => (), } } } From 916d1eeb74ed53a79e7e8ef07869cc822ca88e9d Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 24 Jul 2020 12:53:50 -0700 Subject: [PATCH 3/4] Apply abspos inset: auto adjustments in flow --- components/layout_2020/flow/mod.rs | 80 ++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 27 deletions(-) diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index c5e2f1ed73b8..090f5e854706 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -166,9 +166,14 @@ fn layout_block_level_children( mut float_context: Option<&mut FloatContext>, collapsible_with_parent_start_margin: CollapsibleWithParentStartMargin, ) -> 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, + positioning_context: &mut PositioningContext, + maybe_hoisted: Option, + ) { match fragment { - Fragment::Box(fragment) => { + Fragment::Box(ref mut fragment) => { let fragment_block_margins = &fragment.block_margins_collapsed_with_children; let fragment_block_size = fragment.padding.block_sum() + fragment.border.block_sum() + @@ -203,7 +208,21 @@ fn layout_block_level_children( placement_state.current_margin.solve() + fragment_block_size; placement_state.current_margin = fragment_block_margins.end; }, - Fragment::Anonymous(_) | Fragment::AbsoluteOrFixedPositioned(_) => {}, + Fragment::AbsoluteOrFixedPositioned(_) => { + // We didn't know where to apply `inset: auto` adjustments before + // but we do know, apply the offsets based on where the box is supposed + // to be + // + // https://drafts.csswg.org/css-position-3/#staticpos-rect + if let Some(mut hoisted) = maybe_hoisted { + hoisted.adjust_offsets(Vec2 { + block: placement_state.current_block_direction_position, + inline: Length::new(0.), + }); + positioning_context.push(hoisted) + } + }, + Fragment::Anonymous(_) => {}, _ => unreachable!(), } } @@ -231,47 +250,54 @@ fn layout_block_level_children( .iter() .enumerate() .map(|(tree_rank, box_)| { - let mut fragment = box_ - .borrow_mut() - .layout( - layout_context, - positioning_context, - containing_block, - tree_rank, - float_context.as_mut().map(|c| &mut **c), - ) - .0; - place_block_level_fragment(&mut fragment, &mut placement_state); + let (mut fragment, maybe_hoisted) = box_.borrow_mut().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, + positioning_context, + maybe_hoisted, + ); fragment }) .collect() } else { let collects_for_nearest_positioned_ancestor = positioning_context.collects_for_nearest_positioned_ancestor(); - let mut fragments = child_boxes + let fragments: Vec<_> = child_boxes .par_iter() .enumerate() .mapfold_reduce_into( positioning_context, |positioning_context, (tree_rank, box_)| { - box_.borrow_mut() - .layout( - layout_context, - positioning_context, - containing_block, - tree_rank, - /* float_context = */ None, - ) - .0 + box_.borrow_mut().layout( + layout_context, + positioning_context, + containing_block, + tree_rank, + /* float_context = */ None, + ) }, || PositioningContext::new_for_rayon(collects_for_nearest_positioned_ancestor), PositioningContext::append, ) .collect(); - for fragment in &mut fragments { - place_block_level_fragment(fragment, &mut placement_state) + let mut new_fragments = Vec::with_capacity(fragments.len()); + for (mut fragment, maybe_hoisted) in fragments.into_iter() { + place_block_level_fragment( + &mut fragment, + &mut placement_state, + positioning_context, + maybe_hoisted, + ); + new_fragments.push(fragment) } - fragments + new_fragments } }); From 4d57db33e0bee455a8ec39be5913905b1215942e Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 24 Jul 2020 13:18:02 -0700 Subject: [PATCH 4/4] Handle margins --- components/layout_2020/flow/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index 090f5e854706..6c9e987d2bcd 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -216,7 +216,8 @@ fn layout_block_level_children( // https://drafts.csswg.org/css-position-3/#staticpos-rect if let Some(mut hoisted) = maybe_hoisted { hoisted.adjust_offsets(Vec2 { - block: placement_state.current_block_direction_position, + block: placement_state.current_block_direction_position + + placement_state.current_margin.solve(), inline: Length::new(0.), }); positioning_context.push(hoisted)