layout: Add a first pass at incremental box tree construction (#37751)

This change:

- Adds a new type of LayoutDamage that signifies that a box needs its
  children recollected, because one or more of them need to be rebuilt.
- During restyle damage propagation, propagate this new damage upward in
  the tree. Then box tree construction should be able to preserve any
  still-valid box tree nodes from box slots.
- During BlockLevelBox job finalization, if a box slot is valid and
  there is not LayoutDamage to the element, use the old box slot,
  ensuring that its fragment cache is invalidated.

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

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Oriol Brufau <obrufau@igalia.com>
Co-authored-by: coding-joedow <ibluegalaxy_taoj@163.com>
This commit is contained in:
Martin Robinson 2025-07-03 10:13:20 +02:00 committed by GitHub
parent 9aa06b2c17
commit 6dafeb7a59
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 156 additions and 78 deletions

View file

@ -936,7 +936,7 @@ impl Document {
// FIXME(emilio): This is very inefficient, ideally the flag above would
// be enough and incremental layout could figure out from there.
node.dirty(NodeDamage::Other);
node.dirty(NodeDamage::ContentOrHeritage);
}
/// Remove any existing association between the provided id and any elements in this document.

View file

@ -23,6 +23,7 @@ use html5ever::{LocalName, Namespace, Prefix, QualName, local_name, namespace_pr
use js::jsapi::Heap;
use js::jsval::JSVal;
use js::rust::HandleObject;
use layout_api::LayoutDamage;
use net_traits::ReferrerPolicy;
use net_traits::request::CorsSettings;
use selectors::Element as SelectorsElement;
@ -358,9 +359,18 @@ impl Element {
// NodeStyleDamaged, but I'm preserving existing behavior.
restyle.hint.insert(RestyleHint::RESTYLE_SELF);
if damage == NodeDamage::Other {
doc.note_node_with_dirty_descendants(self.upcast());
restyle.damage = RestyleDamage::reconstruct();
match damage {
NodeDamage::Style => {},
NodeDamage::ContentOrHeritage => {
doc.note_node_with_dirty_descendants(self.upcast());
restyle
.damage
.insert(LayoutDamage::recollect_box_tree_children());
},
NodeDamage::Other => {
doc.note_node_with_dirty_descendants(self.upcast());
restyle.damage.insert(RestyleDamage::reconstruct());
},
}
}

View file

@ -3927,6 +3927,9 @@ impl VirtualMethods for Node {
pub(crate) enum NodeDamage {
/// The node's `style` attribute changed.
Style,
/// The node's content or heritage changed, such as the addition or removal of
/// children.
ContentOrHeritage,
/// Other parts of a node changed; attributes, text content, etc.
Other,
}