mirror of
https://github.com/servo/servo.git
synced 2025-07-23 07:13:52 +01:00
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.
This commit is contained in:
parent
4c8db6af87
commit
1296ddf273
4 changed files with 75 additions and 33 deletions
|
@ -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
|
||||
},
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
})
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue