layout: Simplify PositioningContext by having it hold a single Vec (#36795)

`PositioningContext` held two vectors, one inside an `Option`, to
differentiate between the version used for a containing block for all
descendants (including `position: absolute` and `position: fixed`) or
only for `position: absolute` descendants. This distinction was really
hard to reason about and required a lot of bookkeeping about what kind
of `PositioningContext` a layout box's parent expected. In addition, it
led to a lot of mistakes.

This change simplifies things so that `PositioningContext` only holds a
single vector. When it comes time to lay out hoisted absolutely
positioned
fragments, the code then:
 - lays out all of them (in the case of a `PositioningContext` for all
   descendants), or
 - only lays out the `position: absolute` descendants and preserves the
   `position: fixed` descendants (in the case the `PositioningContext`
   is only for `position: absolute`.), or
- lays out none of them if the `PositioningContext` was created for
  box that did not establish a containing block for absolutes.

It's possible that this way of dealing with hoisted absolutes is a bit
less efficient, but, the number of these descendants is typically quite
small, so it should not be significant. In addition, this decreases the
size in memory of all `PositioningContexts` which are created in more
situations as time goes on.

Testing: There is a new WPT test with this change.
Fixes: #36696.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
Martin Robinson 2025-05-02 14:20:11 +02:00 committed by GitHub
parent e25e63b587
commit 9bc16482a3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 203 additions and 323 deletions

View file

@ -689,16 +689,13 @@ fn layout_block_level_children_in_parallel(
placement_state: &mut PlacementState,
ignore_block_margins_for_stretch: LogicalSides1D<bool>,
) -> Vec<Fragment> {
let collects_for_nearest_positioned_ancestor =
positioning_context.collects_for_nearest_positioned_ancestor();
let mut layout_results: Vec<(Fragment, PositioningContext)> =
Vec::with_capacity(child_boxes.len());
child_boxes
.par_iter()
.map(|child_box| {
let mut child_positioning_context =
PositioningContext::new_for_subtree(collects_for_nearest_positioned_ancestor);
let mut child_positioning_context = PositioningContext::default();
let fragment = child_box.borrow().layout(
layout_context,
&mut child_positioning_context,