Merge pull request #1870 from lightpanda-io/mutation_observer_rc

Switch to reference counting for Mutation Observer and Intersection O…
This commit is contained in:
Karl Seguin
2026-03-17 06:43:45 +08:00
committed by GitHub
2 changed files with 54 additions and 17 deletions

View File

@@ -37,6 +37,7 @@ pub fn registerTypes() []const type {
const IntersectionObserver = @This();
_rc: u8 = 0,
_arena: Allocator,
_callback: js.Function.Temp,
_observing: std.ArrayList(*Element) = .{},
@@ -93,12 +94,24 @@ pub fn init(callback: js.Function.Temp, options: ?ObserverInit, page: *Page) !*I
}
pub fn deinit(self: *IntersectionObserver, shutdown: bool, session: *Session) void {
const rc = self._rc;
if (comptime IS_DEBUG) {
std.debug.assert(rc != 0);
}
if (rc == 1 or shutdown) {
self._callback.release();
if ((comptime IS_DEBUG) and !shutdown) {
std.debug.assert(self._observing.items.len == 0);
}
session.releaseArena(self._arena);
} else {
self._rc = rc - 1;
}
}
pub fn acquireRef(self: *IntersectionObserver) void {
self._rc += 1;
}
pub fn observe(self: *IntersectionObserver, target: *Element, page: *Page) !void {
@@ -111,7 +124,7 @@ pub fn observe(self: *IntersectionObserver, target: *Element, page: *Page) !void
// Register with page if this is our first observation
if (self._observing.items.len == 0) {
page.js.strongRef(self);
self._rc += 1;
try page.registerIntersectionObserver(self);
}
@@ -148,20 +161,26 @@ pub fn unobserve(self: *IntersectionObserver, target: *Element, page: *Page) voi
}
if (self._observing.items.len == 0) {
page.js.safeWeakRef(self);
self.deinit(false, page._session);
}
}
pub fn disconnect(self: *IntersectionObserver, page: *Page) void {
page.unregisterIntersectionObserver(self);
self._observing.clearRetainingCapacity();
self._previous_states.clearRetainingCapacity();
for (self._pending_entries.items) |entry| {
entry.deinit(false, page._session);
}
self._pending_entries.clearRetainingCapacity();
page.js.safeWeakRef(self);
const observing_count = self._observing.items.len;
self._observing.clearRetainingCapacity();
if (observing_count > 0) {
self.deinit(false, page._session);
}
page.unregisterIntersectionObserver(self);
}
pub fn takeRecords(self: *IntersectionObserver, page: *Page) ![]*IntersectionObserverEntry {

View File

@@ -39,6 +39,7 @@ pub fn registerTypes() []const type {
const MutationObserver = @This();
_rc: u8 = 0,
_arena: Allocator,
_callback: js.Function.Temp,
_observing: std.ArrayList(Observing) = .{},
@@ -86,12 +87,24 @@ pub fn init(callback: js.Function.Temp, page: *Page) !*MutationObserver {
}
pub fn deinit(self: *MutationObserver, shutdown: bool, session: *Session) void {
const rc = self._rc;
if (comptime IS_DEBUG) {
std.debug.assert(rc != 0);
}
if (rc == 1 or shutdown) {
self._callback.release();
if ((comptime IS_DEBUG) and !shutdown) {
std.debug.assert(self._observing.items.len == 0);
}
session.releaseArena(self._arena);
} else {
self._rc = rc - 1;
}
}
pub fn acquireRef(self: *MutationObserver) void {
self._rc += 1;
}
pub fn observe(self: *MutationObserver, target: *Node, options: ObserveOptions, page: *Page) !void {
@@ -158,7 +171,7 @@ pub fn observe(self: *MutationObserver, target: *Node, options: ObserveOptions,
// Register with page if this is our first observation
if (self._observing.items.len == 0) {
page.js.strongRef(self);
self._rc += 1;
try page.registerMutationObserver(self);
}
@@ -169,13 +182,18 @@ pub fn observe(self: *MutationObserver, target: *Node, options: ObserveOptions,
}
pub fn disconnect(self: *MutationObserver, page: *Page) void {
page.unregisterMutationObserver(self);
self._observing.clearRetainingCapacity();
for (self._pending_records.items) |record| {
record.deinit(false, page._session);
}
self._pending_records.clearRetainingCapacity();
page.js.safeWeakRef(self);
const observing_count = self._observing.items.len;
self._observing.clearRetainingCapacity();
if (observing_count > 0) {
self.deinit(false, page._session);
}
page.unregisterMutationObserver(self);
}
pub fn takeRecords(self: *MutationObserver, page: *Page) ![]*MutationRecord {