LibWeb: Reduce allocations in IntersectionObserver hot path

Pre-compute per-observer values (root node, root paintable, root
bounds, is_implicit_root, root_is_element) once before the per-target
loop instead of recomputing them for each target.

Add intersection_root_node() which returns GC::Ref<DOM::Node> without
creating GC::Root wrappers. Previously, intersection_root() was called
multiple times per target (in the skip condition check, in
compute_intersection, and again in root_intersection_rectangle inside
compute_intersection), each call creating GC::Root objects that require
heap allocation via new RootImpl.

Pass the pre-computed root bounds and root paintable into
compute_intersection instead of having it call
root_intersection_rectangle() and intersection_root() internally.

For an observer watching N targets, this eliminates roughly 4N heap
allocations per frame.
This commit is contained in:
Andreas Kling
2026-03-22 09:11:37 -05:00
committed by Andreas Kling
parent 9abb7e4517
commit e2d5d72f55
Notes: github-actions[bot] 2026-03-22 19:10:45 +00:00
3 changed files with 26 additions and 30 deletions

View File

@@ -51,6 +51,8 @@ public:
bool track_visibility() const { return m_track_visibility; }
Variant<GC::Root<DOM::Element>, GC::Root<DOM::Document>> intersection_root() const;
GC::Ref<DOM::Node> intersection_root_node() const;
bool is_implicit_root() const { return !m_root; }
CSSPixelRect root_intersection_rectangle() const;
void queue_entry(Badge<DOM::Document>, GC::Ref<IntersectionObserverEntry>);