diff options
author | Martin Robinson <mrobinson@igalia.com> | 2023-08-03 10:51:27 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-08-03 08:51:27 +0000 |
commit | 1296ddf2736e55e813f26aeebfdd231e761dfb3e (patch) | |
tree | 2e21ece4fdfa27f4fe1f9503113ba9b18d278051 /components/layout_2020 | |
parent | 4c8db6af8730ff0213fc08b79a2dbc78b310394b (diff) | |
download | servo-1296ddf2736e55e813f26aeebfdd231e761dfb3e.tar.gz servo-1296ddf2736e55e813f26aeebfdd231e761dfb3e.zip |
Make fewer PositioningContexts when descending (#30061)
When descending and we have the option, don't create new
PositioningContexts just to update the static position of laid out
abspos descendants. Instead, use the new PositioningContextLength to
only update the newly added hoisted abspos boxes.
Diffstat (limited to 'components/layout_2020')
-rw-r--r-- | components/layout_2020/flexbox/layout.rs | 8 | ||||
-rw-r--r-- | components/layout_2020/flow/inline.rs | 21 | ||||
-rw-r--r-- | components/layout_2020/flow/mod.rs | 21 | ||||
-rw-r--r-- | components/layout_2020/positioned.rs | 58 |
4 files changed, 75 insertions, 33 deletions
diff --git a/components/layout_2020/flexbox/layout.rs b/components/layout_2020/flexbox/layout.rs index 19619375b99..f4cc3e2cf4c 100644 --- a/components/layout_2020/flexbox/layout.rs +++ b/components/layout_2020/flexbox/layout.rs @@ -11,7 +11,7 @@ use crate::formatting_contexts::{IndependentFormattingContext, IndependentLayout use crate::fragment_tree::{BoxFragment, CollapsedBlockMargins, Fragment}; use crate::geom::flow_relative::{Rect, Sides, Vec2}; use crate::geom::LengthOrAuto; -use crate::positioned::{AbsolutelyPositionedBox, PositioningContext}; +use crate::positioned::{AbsolutelyPositionedBox, PositioningContext, PositioningContextLength}; use crate::sizing::ContentSizes; use crate::style_ext::ComputedValuesExt; use crate::ContainingBlock; @@ -194,8 +194,10 @@ impl FlexContainer { let (fragment, mut child_positioning_context) = flex_item_fragments.next().unwrap(); let fragment = Fragment::Box(fragment); - child_positioning_context - .adjust_static_position_of_hoisted_fragments(&fragment); + child_positioning_context.adjust_static_position_of_hoisted_fragments( + &fragment, + PositioningContextLength::zero(), + ); positioning_context.append(child_positioning_context); fragment }, diff --git a/components/layout_2020/flow/inline.rs b/components/layout_2020/flow/inline.rs index 4eae022cbd3..7dcb04b53f3 100644 --- a/components/layout_2020/flow/inline.rs +++ b/components/layout_2020/flow/inline.rs @@ -786,8 +786,7 @@ fn layout_atomic( let margin = pbm.margin.auto_is(Length::zero); let pbm_sums = &(&pbm.padding + &pbm.border) + &margin; let position = style.clone_position(); - - let mut child_positioning_context = None; + let positioning_context_length_before_layout = ifc.positioning_context.len(); // We need to know the inline size of the atomic before deciding whether to do the line break. let mut fragment = match atomic { @@ -854,15 +853,9 @@ fn layout_atomic( "Mixed writing modes are not supported yet" ); - let collects_for_nearest_positioned_ancestor = ifc - .positioning_context - .collects_for_nearest_positioned_ancestor(); - child_positioning_context = Some(PositioningContext::new_for_subtree( - collects_for_nearest_positioned_ancestor, - )); let independent_layout = non_replaced.layout( layout_context, - child_positioning_context.as_mut().unwrap(), + &mut ifc.positioning_context, &containing_block_for_children, ); @@ -916,11 +909,11 @@ fn layout_atomic( start_corner += &relative_adjustement(atomic.style(), ifc.containing_block) } - if let Some(mut child_positioning_context) = child_positioning_context.take() { - child_positioning_context - .adjust_static_position_of_hoisted_fragments_with_offset(&start_corner); - ifc.positioning_context.append(child_positioning_context); - } + ifc.positioning_context + .adjust_static_position_of_hoisted_fragments_with_offset( + &start_corner, + positioning_context_length_before_layout, + ); fragment.content_rect.start_corner = start_corner; diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index 10449d50274..e5695655296 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -15,7 +15,7 @@ use crate::fragment_tree::{ BaseFragmentInfo, BoxFragment, CollapsedBlockMargins, CollapsedMargin, Fragment, }; use crate::geom::flow_relative::{Rect, Sides, Vec2}; -use crate::positioned::{AbsolutelyPositionedBox, PositioningContext}; +use crate::positioned::{AbsolutelyPositionedBox, PositioningContext, PositioningContextLength}; use crate::replaced::ReplacedContent; use crate::sizing::{self, ContentSizes}; use crate::style_ext::{ComputedValuesExt, PaddingBorderMargin}; @@ -449,7 +449,10 @@ fn layout_block_level_children_in_parallel( .into_iter() .map(|(mut fragment, mut child_positioning_context)| { placement_state.place_fragment(&mut fragment, None); - child_positioning_context.adjust_static_position_of_hoisted_fragments(&fragment); + child_positioning_context.adjust_static_position_of_hoisted_fragments( + &fragment, + PositioningContextLength::zero(), + ); positioning_context.append(child_positioning_context); fragment }) @@ -472,8 +475,6 @@ fn layout_block_level_children_sequentially( collapsible_with_parent_start_margin: CollapsibleWithParentStartMargin, ) -> FlowLayout { let mut placement_state = PlacementState::new(collapsible_with_parent_start_margin); - let collects_for_nearest_positioned_ancestor = - positioning_context.collects_for_nearest_positioned_ancestor(); // Because floats are involved, we do layout for this block formatting context in tree // order without parallelism. This enables mutable access to a `SequentialLayoutState` that @@ -481,11 +482,10 @@ fn layout_block_level_children_sequentially( let fragments = child_boxes .iter() .map(|child_box| { - let mut child_positioning_context = - PositioningContext::new_for_subtree(collects_for_nearest_positioned_ancestor); + let positioning_context_length_before_layout = positioning_context.len(); let mut fragment = child_box.borrow_mut().layout( layout_context, - &mut child_positioning_context, + positioning_context, containing_block, Some(&mut *sequential_layout_state), Some(CollapsibleWithParentStartMargin( @@ -494,9 +494,10 @@ fn layout_block_level_children_sequentially( ); placement_state.place_fragment(&mut fragment, Some(sequential_layout_state)); - - child_positioning_context.adjust_static_position_of_hoisted_fragments(&fragment); - positioning_context.append(child_positioning_context); + positioning_context.adjust_static_position_of_hoisted_fragments( + &fragment, + positioning_context_length_before_layout, + ); fragment }) diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs index fa94773965b..85c4731686d 100644 --- a/components/layout_2020/positioned.rs +++ b/components/layout_2020/positioned.rs @@ -158,13 +158,16 @@ impl PositioningContext { /// with the hoisted fragment so that it can be laid out properly at the containing /// block. /// - /// This function is used to update that static position at every level of the - /// fragment tree as the hoisted fragments move back up to their containing blocks. - /// Once an ancestor fragment is laid out, this function can be used to aggregate its - /// offset on the way back up. + /// This function is used to update the static position of hoisted boxes added after + /// the given index at every level of the fragment tree as the hoisted fragments move + /// up to their containing blocks. Once an ancestor fragment is laid out, this + /// function can be used to aggregate its offset to any descendent boxes that are + /// being hoisted. In this case, the appropriate index to use is the result of + /// [`PositioningContext::len()`] cached before laying out the [`Fragment`]. pub(crate) fn adjust_static_position_of_hoisted_fragments( &mut self, parent_fragment: &Fragment, + index: PositioningContextLength, ) { let start_offset = match &parent_fragment { Fragment::Box(b) | Fragment::Float(b) => &b.content_rect.start_corner, @@ -172,13 +175,14 @@ impl PositioningContext { Fragment::Anonymous(a) => &a.rect.start_corner, _ => unreachable!(), }; - self.adjust_static_position_of_hoisted_fragments_with_offset(start_offset); + self.adjust_static_position_of_hoisted_fragments_with_offset(start_offset, index); } /// See documentation for [adjust_static_position_of_hoisted_fragments]. pub(crate) fn adjust_static_position_of_hoisted_fragments_with_offset( &mut self, start_offset: &Vec2<CSSPixelLength>, + index: PositioningContextLength, ) { let update_fragment_if_needed = |hoisted_fragment: &mut HoistedAbsolutelyPositionedBox| { let mut fragment = hoisted_fragment.fragment.borrow_mut(); @@ -193,10 +197,14 @@ impl PositioningContext { self.for_nearest_positioned_ancestor .as_mut() .map(|hoisted_boxes| { - hoisted_boxes.iter_mut().for_each(update_fragment_if_needed); + hoisted_boxes + .iter_mut() + .skip(index.for_nearest_positioned_ancestor) + .for_each(update_fragment_if_needed); }); self.for_nearest_containing_block_for_all_descendants .iter_mut() + .skip(index.for_nearest_containing_block_for_all_descendants) .for_each(update_fragment_if_needed); } @@ -343,6 +351,43 @@ impl PositioningContext { .as_mut() .map(|v| v.clear()); } + + /// Get the length of this [PositioningContext]. + pub(crate) fn len(&self) -> PositioningContextLength { + PositioningContextLength { + for_nearest_positioned_ancestor: self + .for_nearest_positioned_ancestor + .as_ref() + .map_or(0, |vec| vec.len()), + for_nearest_containing_block_for_all_descendants: self + .for_nearest_containing_block_for_all_descendants + .len(), + } + } +} + +/// A data structure which stores the size of a positioning context. +pub(crate) struct PositioningContextLength { + /// The number of boxes that will be hoisted the the nearest positioned ancestor for + /// layout. + for_nearest_positioned_ancestor: usize, + /// The number of boxes that will be hoisted the the nearest ancestor which + /// establishes a containing block for all descendants for layout. + for_nearest_containing_block_for_all_descendants: usize, +} + +impl Zero for PositioningContextLength { + fn zero() -> Self { + PositioningContextLength { + for_nearest_positioned_ancestor: 0, + for_nearest_containing_block_for_all_descendants: 0, + } + } + + fn is_zero(&self) -> bool { + self.for_nearest_positioned_ancestor == 0 && + self.for_nearest_containing_block_for_all_descendants == 0 + } } impl HoistedAbsolutelyPositionedBox { @@ -640,6 +685,7 @@ impl HoistedAbsolutelyPositionedBox { // adjust it to account for the start corner of this absolute. positioning_context.adjust_static_position_of_hoisted_fragments_with_offset( &new_fragment.content_rect.start_corner, + PositioningContextLength::zero(), ); for_nearest_containing_block_for_all_descendants |