mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-03-22 04:34:44 +00:00
Merge pull request #1634 from lightpanda-io/event_rc
Add [basic] reference counting to events
This commit is contained in:
@@ -204,7 +204,8 @@ pub fn dispatch(self: *EventManager, target: *EventTarget, event: *Event) Dispat
|
||||
}
|
||||
|
||||
pub fn dispatchOpts(self: *EventManager, target: *EventTarget, event: *Event, comptime opts: DispatchOpts) DispatchError!void {
|
||||
defer if (!event._v8_handoff) event.deinit(false, self.page);
|
||||
event.acquireRef();
|
||||
defer event.deinit(false, self.page);
|
||||
|
||||
if (comptime IS_DEBUG) {
|
||||
log.debug(.event, "eventManager.dispatch", .{ .type = event._type_string.str(), .bubbles = event._bubbles });
|
||||
@@ -254,7 +255,8 @@ const DispatchWithFunctionOptions = struct {
|
||||
inject_target: bool = true,
|
||||
};
|
||||
pub fn dispatchWithFunction(self: *EventManager, target: *EventTarget, event: *Event, function_: ?js.Function, comptime opts: DispatchWithFunctionOptions) !void {
|
||||
defer if (!event._v8_handoff) event.deinit(false, self.page);
|
||||
event.acquireRef();
|
||||
defer event.deinit(false, self.page);
|
||||
|
||||
if (comptime IS_DEBUG) {
|
||||
log.debug(.event, "dispatchWithFunction", .{ .type = event._type_string.str(), .context = opts.context, .has_function = function_ != null });
|
||||
|
||||
@@ -237,6 +237,7 @@ fn eventInit(arena: Allocator, typ: String, value: anytype) !Event {
|
||||
const time_stamp = (raw_timestamp / 2) * 2;
|
||||
|
||||
return .{
|
||||
._rc = 0,
|
||||
._arena = arena,
|
||||
._type = unionInit(Event.Type, value),
|
||||
._type_string = typ,
|
||||
|
||||
@@ -217,7 +217,7 @@ pub fn mapZigInstanceToJs(self: *const Local, js_obj_handle: ?*const v8.Object,
|
||||
try ctx.finalizer_callbacks.put(ctx.arena, @intFromPtr(resolved.ptr), fc);
|
||||
}
|
||||
|
||||
conditionallyFlagHandoff(value);
|
||||
conditionallyReference(value);
|
||||
if (@hasDecl(JsApi.Meta, "weak")) {
|
||||
if (comptime IS_DEBUG) {
|
||||
std.debug.assert(JsApi.Meta.weak == true);
|
||||
@@ -1101,14 +1101,14 @@ fn resolveT(comptime T: type, value: *anyopaque) Resolved {
|
||||
};
|
||||
}
|
||||
|
||||
fn conditionallyFlagHandoff(value: anytype) void {
|
||||
fn conditionallyReference(value: anytype) void {
|
||||
const T = bridge.Struct(@TypeOf(value));
|
||||
if (@hasField(T, "_v8_handoff")) {
|
||||
value._v8_handoff = true;
|
||||
if (@hasDecl(T, "acquireRef")) {
|
||||
value.acquireRef();
|
||||
return;
|
||||
}
|
||||
if (@hasField(T, "_proto")) {
|
||||
conditionallyFlagHandoff(value._proto);
|
||||
conditionallyReference(value._proto);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ const Node = @import("Node.zig");
|
||||
const String = @import("../../string.zig").String;
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
const IS_DEBUG = @import("builtin").mode == .Debug;
|
||||
|
||||
pub const Event = @This();
|
||||
|
||||
@@ -44,13 +45,16 @@ _stop_immediate_propagation: bool = false,
|
||||
_event_phase: EventPhase = .none,
|
||||
_time_stamp: u64,
|
||||
_needs_retargeting: bool = false,
|
||||
_isTrusted: bool = false,
|
||||
_is_trusted: bool = false,
|
||||
|
||||
// There's a period of time between creating an event and handing it off to v8
|
||||
// where things can fail. If it does fail, we need to deinit the event. This flag
|
||||
// when true, tells us the event is registered in the js.Contxt and thus, at
|
||||
// the very least, will be finalized on context shutdown.
|
||||
_v8_handoff: bool = false,
|
||||
// where things can fail. If it does fail, we need to deinit the event. The timing
|
||||
// window can be difficult to capture, so we use a reference count.
|
||||
// should be 0, 1, or 2. 0
|
||||
// - 0: no reference, always a transient state going to either 1 or about to be deinit'd
|
||||
// - 1: either zig or v8 have a reference
|
||||
// - 2: both zig and v8 have a reference
|
||||
_rc: u8 = 0,
|
||||
|
||||
pub const EventPhase = enum(u8) {
|
||||
none = 0,
|
||||
@@ -92,7 +96,7 @@ pub fn initTrusted(typ: String, opts_: ?Options, page: *Page) !*Event {
|
||||
return initWithTrusted(arena, typ, opts_, true);
|
||||
}
|
||||
|
||||
fn initWithTrusted(arena: Allocator, typ: String, opts_: ?Options, trusted: bool) !*Event {
|
||||
fn initWithTrusted(arena: Allocator, typ: String, opts_: ?Options, comptime trusted: bool) !*Event {
|
||||
const opts = opts_ orelse Options{};
|
||||
|
||||
// Round to 2ms for privacy (browsers do this)
|
||||
@@ -108,7 +112,7 @@ fn initWithTrusted(arena: Allocator, typ: String, opts_: ?Options, trusted: bool
|
||||
._cancelable = opts.cancelable,
|
||||
._composed = opts.composed,
|
||||
._type_string = typ,
|
||||
._isTrusted = trusted,
|
||||
._is_trusted = trusted,
|
||||
};
|
||||
return event;
|
||||
}
|
||||
@@ -131,9 +135,26 @@ pub fn initEvent(
|
||||
self._prevent_default = false;
|
||||
}
|
||||
|
||||
pub fn acquireRef(self: *Event) void {
|
||||
self._rc += 1;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Event, shutdown: bool, page: *Page) void {
|
||||
_ = shutdown;
|
||||
if (shutdown) {
|
||||
page.releaseArena(self._arena);
|
||||
return;
|
||||
}
|
||||
|
||||
const rc = self._rc;
|
||||
if (comptime IS_DEBUG) {
|
||||
std.debug.assert(rc != 0);
|
||||
}
|
||||
|
||||
if (rc == 1) {
|
||||
page.releaseArena(self._arena);
|
||||
} else {
|
||||
self._rc = rc - 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as(self: *Event, comptime T: type) *T {
|
||||
@@ -235,15 +256,15 @@ pub fn getTimeStamp(self: *const Event) u64 {
|
||||
}
|
||||
|
||||
pub fn setTrusted(self: *Event) void {
|
||||
self._isTrusted = true;
|
||||
self._is_trusted = true;
|
||||
}
|
||||
|
||||
pub fn setUntrusted(self: *Event) void {
|
||||
self._isTrusted = false;
|
||||
self._is_trusted = false;
|
||||
}
|
||||
|
||||
pub fn getIsTrusted(self: *const Event) bool {
|
||||
return self._isTrusted;
|
||||
return self._is_trusted;
|
||||
}
|
||||
|
||||
pub fn composedPath(self: *Event, page: *Page) ![]const *EventTarget {
|
||||
@@ -401,8 +422,8 @@ pub fn populatePrototypes(self: anytype, opts: anytype, trusted: bool) void {
|
||||
}
|
||||
|
||||
// Set isTrusted at the Event level (base of prototype chain)
|
||||
if (T == Event or @hasField(T, "_isTrusted")) {
|
||||
self._isTrusted = trusted;
|
||||
if (T == Event or @hasField(T, "is_trusted")) {
|
||||
self._is_trusted = trusted;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,8 @@ pub fn dispatchEvent(self: *EventTarget, event: *Event, page: *Page) !bool {
|
||||
if (event._event_phase != .none) {
|
||||
return error.InvalidStateError;
|
||||
}
|
||||
event._isTrusted = false;
|
||||
event._is_trusted = false;
|
||||
event.acquireRef();
|
||||
try page._event_manager.dispatch(self, event);
|
||||
return !event._cancelable or !event._prevent_default;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user