From 82f7f761d93f451d69493f45b656eaa908b1a642 Mon Sep 17 00:00:00 2001 From: Martin Robinson Date: Thu, 3 Jul 2025 12:32:05 +0200 Subject: [PATCH] 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 Co-authored-by: Oriol Brufau --- components/layout/dom.rs | 4 +++ components/layout/flow/construct.rs | 1 - components/layout/table/construct.rs | 42 +++++++++++++++++++--------- components/layout/traversal.rs | 4 +++ 4 files changed, 37 insertions(+), 14 deletions(-) diff --git a/components/layout/dom.rs b/components/layout/dom.rs index 56daa77dc21..6a1aab4e7a6 100644 --- a/components/layout/dom.rs +++ b/components/layout/dom.rs @@ -180,6 +180,10 @@ impl BoxSlot<'_> { *slot.borrow_mut() = Some(box_); } } + + pub(crate) fn take_layout_box(&self) -> Option { + self.slot.as_ref().and_then(|slot| slot.borrow_mut().take()) + } } impl Drop for BoxSlot<'_> { diff --git a/components/layout/flow/construct.rs b/components/layout/flow/construct.rs index 71dbdcbc19b..68e7f1178d0 100644 --- a/components/layout/flow/construct.rs +++ b/components/layout/flow/construct.rs @@ -700,7 +700,6 @@ impl BlockLevelJob<'_> { }, None => None, } { - block_level_box.borrow().invalidate_cached_fragment(); return block_level_box; } } diff --git a/components/layout/table/construct.rs b/components/layout/table/construct.rs index 0ef39537e35..aa5c97c8107 100644 --- a/components/layout/table/construct.rs +++ b/components/layout/table/construct.rs @@ -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))); }, diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs index ff2a3c155d5..9a2e97f3162 100644 --- a/components/layout/traversal.rs +++ b/components/layout/traversal.rs @@ -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)