layout: Add incremental box tree construction for table caption (#37849)

This change extends incremental box tree updates to table captions. In
addition, calls to `LayoutBox::invalidate_cached_fragment()` are moved
to the damage calculation traversal.

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

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
Martin Robinson 2025-07-03 12:32:05 +02:00 committed by GitHub
parent 00472dec8e
commit 82f7f761d9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 37 additions and 14 deletions

View file

@ -180,6 +180,10 @@ impl BoxSlot<'_> {
*slot.borrow_mut() = Some(box_);
}
}
pub(crate) fn take_layout_box(&self) -> Option<LayoutBox> {
self.slot.as_ref().and_then(|slot| slot.borrow_mut().take())
}
}
impl Drop for BoxSlot<'_> {

View file

@ -700,7 +700,6 @@ impl BlockLevelJob<'_> {
},
None => None,
} {
block_level_box.borrow().invalidate_cached_fragment();
return block_level_box;
}
}

View file

@ -854,21 +854,37 @@ impl<'dom> TraversalHandler<'dom> for TableBuilderTraversal<'_, 'dom> {
let Contents::NonReplaced(non_replaced_contents) = contents else {
unreachable!("Replaced should not have a LayoutInternal display type.");
};
let contents =
IndependentNonReplacedContents::Flow(BlockFormattingContext::construct(
self.context,
info,
non_replaced_contents,
self.current_propagated_data,
false, /* is_list_item */
));
let caption = ArcRefCell::new(TableCaption {
context: IndependentFormattingContext {
base: LayoutBoxBase::new(info.into(), info.style.clone()),
contents: IndependentFormattingContextContents::NonReplaced(contents),
},
let old_caption = (!info.damage.has_box_damage())
.then(|| match box_slot.take_layout_box() {
Some(LayoutBox::TableLevelBox(TableLevelBox::Caption(caption))) => {
Some(caption)
},
_ => None,
})
.flatten();
let caption = old_caption.unwrap_or_else(|| {
let contents = IndependentNonReplacedContents::Flow(
BlockFormattingContext::construct(
self.context,
info,
non_replaced_contents,
self.current_propagated_data,
false, /* is_list_item */
),
);
ArcRefCell::new(TableCaption {
context: IndependentFormattingContext {
base: LayoutBoxBase::new(info.into(), info.style.clone()),
contents: IndependentFormattingContextContents::NonReplaced(
contents,
),
},
})
});
self.builder.table.captions.push(caption.clone());
box_slot.set(LayoutBox::TableLevelBox(TableLevelBox::Caption(caption)));
},

View file

@ -145,6 +145,10 @@ pub(crate) fn compute_damage_and_repair_style_inner(
element_data.borrow_mut().damage.insert(element_damage);
}
if element_damage.contains(LayoutDamage::recollect_box_tree_children()) {
node.invalidate_cached_fragment();
}
// Only propagate up layout phases from children, as other types of damage are
// incorporated into `element_damage` above.
element_damage | (damage_from_children & RestyleDamage::RELAYOUT)