layout: Implement node geometry queries against BoxTree's Fragment (#36663)

This is a followup to #36629, continuing to implement script-based
layout queries  using the `Fragment`s attached to the `BoxTree`. In this
change, geometry queris (apart from parent offset) are calculated using
`Fragment`s hanging of the `BoxTree`.

In order to make this work, all `Fragment`s for inlines split by blocks,
need to be accessible in the `BoxTree`. This required some changes to
the way that box tree items were stored in DOM `BoxSlot`s. Now every
inline level item can have more than a single `BoxTree` item. These are
carefully collected by the `InlineFormattingContextBuilder` -- currently
a bit fragile, but with more documentation.

Testing: There are tests for these changes.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
Martin Robinson 2025-04-25 15:38:05 +02:00 committed by GitHub
parent cc91395397
commit b63a1818c4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 197 additions and 170 deletions

View file

@ -458,15 +458,14 @@ where
self.propagated_data.without_text_decorations(),
),
);
box_slot.set(LayoutBox::InlineLevel(atomic));
box_slot.set(LayoutBox::InlineLevel(vec![atomic]));
return;
};
// Otherwise, this is just a normal inline box. Whatever happened before, all we need to do
// before recurring is to remember this ongoing inline level box.
let inline_item = self
.inline_formatting_context_builder
.start_inline_box(InlineBox::new(info));
self.inline_formatting_context_builder
.start_inline_box(InlineBox::new(info), None);
if is_list_item {
if let Some((marker_info, marker_contents)) =
@ -486,8 +485,14 @@ where
self.finish_anonymous_table_if_needed();
self.inline_formatting_context_builder.end_inline_box();
box_slot.set(LayoutBox::InlineLevel(inline_item));
// As we are ending this inline box, during the course of the `traverse()` above, the ongoing
// inline formatting context may have been split around block-level elements. In that case,
// more than a single inline box tree item may have been produced for this inline-level box.
// `InlineFormattingContextBuilder::end_inline_box()` is returning all of those box tree
// items.
box_slot.set(LayoutBox::InlineLevel(
self.inline_formatting_context_builder.end_inline_box(),
));
}
fn handle_block_level_element(
@ -574,7 +579,7 @@ where
display_inside,
contents,
));
box_slot.set(LayoutBox::InlineLevel(inline_level_box));
box_slot.set(LayoutBox::InlineLevel(vec![inline_level_box]));
return;
}
@ -607,7 +612,7 @@ where
contents,
self.propagated_data,
));
box_slot.set(LayoutBox::InlineLevel(inline_level_box));
box_slot.set(LayoutBox::InlineLevel(vec![inline_level_box]));
return;
}