layout: Add incremental box tree construction for table cell (#37850)

This change extends incremental box tree updates to table cells. In
addition, for simplicity this refactors `BoxSlot::take_layout_box()`
into `BoxSlot::take_layout_box_if_undamaged()`.

Testing: This should not change observable behavior and is thus covered
by existing WPT tests.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
Oriol Brufau 2025-07-03 14:06:31 +02:00 committed by GitHub
parent 06cc4bdae7
commit d33d057763
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 54 additions and 45 deletions

View file

@ -181,7 +181,10 @@ impl BoxSlot<'_> {
} }
} }
pub(crate) fn take_layout_box(&self) -> Option<LayoutBox> { pub(crate) fn take_layout_box_if_undamaged(&self, damage: LayoutDamage) -> Option<LayoutBox> {
if damage.has_box_damage() {
return None;
}
self.slot.as_ref().and_then(|slot| slot.borrow_mut().take()) self.slot.as_ref().and_then(|slot| slot.borrow_mut().take())
} }
} }

View file

@ -855,14 +855,11 @@ impl<'dom> TraversalHandler<'dom> for TableBuilderTraversal<'_, 'dom> {
unreachable!("Replaced should not have a LayoutInternal display type."); unreachable!("Replaced should not have a LayoutInternal display type.");
}; };
let old_caption = (!info.damage.has_box_damage()) let old_box = box_slot.take_layout_box_if_undamaged(info.damage);
.then(|| match box_slot.take_layout_box() { let old_caption = old_box.and_then(|layout_box| match layout_box {
Some(LayoutBox::TableLevelBox(TableLevelBox::Caption(caption))) => { LayoutBox::TableLevelBox(TableLevelBox::Caption(caption)) => Some(caption),
Some(caption)
},
_ => None, _ => None,
}) });
.flatten();
let caption = old_caption.unwrap_or_else(|| { let caption = old_caption.unwrap_or_else(|| {
let contents = IndependentNonReplacedContents::Flow( let contents = IndependentNonReplacedContents::Flow(
@ -1006,6 +1003,15 @@ impl<'dom> TraversalHandler<'dom> for TableRowBuilder<'_, '_, 'dom, '_> {
match display { match display {
DisplayGeneratingBox::LayoutInternal(internal) => match internal { DisplayGeneratingBox::LayoutInternal(internal) => match internal {
DisplayLayoutInternal::TableCell => { DisplayLayoutInternal::TableCell => {
self.finish_current_anonymous_cell_if_needed();
let old_box = box_slot.take_layout_box_if_undamaged(info.damage);
let old_cell = old_box.and_then(|layout_box| match layout_box {
LayoutBox::TableLevelBox(TableLevelBox::Cell(cell)) => Some(cell),
_ => None,
});
let cell = old_cell.unwrap_or_else(|| {
// This value will already have filtered out rowspan=0 // This value will already have filtered out rowspan=0
// in quirks mode, so we don't have to worry about that. // in quirks mode, so we don't have to worry about that.
let (rowspan, colspan) = if info.pseudo_element_type.is_none() { let (rowspan, colspan) = if info.pseudo_element_type.is_none() {
@ -1037,14 +1043,14 @@ impl<'dom> TraversalHandler<'dom> for TableRowBuilder<'_, '_, 'dom, '_> {
false, /* is_list_item */ false, /* is_list_item */
); );
self.finish_current_anonymous_cell_if_needed(); ArcRefCell::new(TableSlotCell {
let cell = ArcRefCell::new(TableSlotCell {
base: LayoutBoxBase::new(info.into(), info.style.clone()), base: LayoutBoxBase::new(info.into(), info.style.clone()),
contents, contents,
colspan, colspan,
rowspan, rowspan,
})
}); });
self.table_traversal.builder.add_cell(cell.clone()); self.table_traversal.builder.add_cell(cell.clone());
box_slot.set(LayoutBox::TableLevelBox(TableLevelBox::Cell(cell))); box_slot.set(LayoutBox::TableLevelBox(TableLevelBox::Cell(cell)));
}, },