mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-02-04 14:33:47 +00:00
Add finalizers and arenas to events
Events will now be finalized when no longer needed, and allocate using arenas from the ArenaPool rather than the page.arena.
This commit is contained in:
@@ -136,12 +136,16 @@ pub fn dispatch(self: *EventManager, target: *EventTarget, event: *Event) !void
|
||||
event._dispatch_target = target; // Store original target for composedPath()
|
||||
var was_handled = false;
|
||||
|
||||
defer if (was_handled) {
|
||||
defer {
|
||||
if (was_handled) {
|
||||
var ls: js.Local.Scope = undefined;
|
||||
self.page.js.localScope(&ls);
|
||||
defer ls.deinit();
|
||||
ls.local.runMicrotasks();
|
||||
};
|
||||
} else {
|
||||
event.deinit(false);
|
||||
}
|
||||
}
|
||||
|
||||
switch (target._type) {
|
||||
.node => |node| try self.dispatchNode(node, event, &was_handled),
|
||||
@@ -181,26 +185,30 @@ pub fn dispatchWithFunction(self: *EventManager, target: *EventTarget, event: *E
|
||||
event._dispatch_target = target; // Store original target for composedPath()
|
||||
}
|
||||
|
||||
var was_dispatched = false;
|
||||
defer if (was_dispatched) {
|
||||
var was_handled = false;
|
||||
defer {
|
||||
if (was_handled) {
|
||||
var ls: js.Local.Scope = undefined;
|
||||
self.page.js.localScope(&ls);
|
||||
defer ls.deinit();
|
||||
ls.local.runMicrotasks();
|
||||
};
|
||||
} else {
|
||||
event.deinit(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (function_) |func| {
|
||||
const js_val = try func.local.zigValueToJs(event, .{});
|
||||
was_handled = true;
|
||||
|
||||
event._current_target = target;
|
||||
if (func.callWithThis(void, target, .{event})) {
|
||||
was_dispatched = true;
|
||||
} else |err| {
|
||||
// a non-JS error
|
||||
func.callWithThis(void, target, .{js_val}) catch |err| {
|
||||
log.warn(.event, opts.context, .{ .err = err });
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const list = self.lookup.get(@intFromPtr(target)) orelse return;
|
||||
try self.dispatchAll(list, target, event, &was_dispatched);
|
||||
try self.dispatchAll(list, target, event, &was_handled);
|
||||
}
|
||||
|
||||
fn dispatchNode(self: *EventManager, target: *Node, event: *Event, was_handled: *bool) !void {
|
||||
@@ -364,7 +372,6 @@ fn dispatchPhase(self: *EventManager, list: *std.DoublyLinkedList, current_targe
|
||||
self.removeListener(list, listener);
|
||||
}
|
||||
|
||||
was_handled.* = true;
|
||||
event._current_target = current_target;
|
||||
|
||||
// Compute adjusted target for shadow DOM retargeting (only if needed)
|
||||
@@ -377,8 +384,11 @@ fn dispatchPhase(self: *EventManager, list: *std.DoublyLinkedList, current_targe
|
||||
page.js.localScope(&ls);
|
||||
defer ls.deinit();
|
||||
|
||||
const js_val = try ls.local.zigValueToJs(event, .{});
|
||||
was_handled.* = true;
|
||||
|
||||
switch (listener.function) {
|
||||
.value => |value| try ls.toLocal(value).callWithThis(void, current_target, .{event}),
|
||||
.value => |value| try ls.toLocal(value).callWithThis(void, current_target, .{js_val}),
|
||||
.string => |string| {
|
||||
const str = try page.call_arena.dupeZ(u8, string.str());
|
||||
try ls.local.eval(str, null);
|
||||
@@ -386,7 +396,7 @@ fn dispatchPhase(self: *EventManager, list: *std.DoublyLinkedList, current_targe
|
||||
.object => |obj_global| {
|
||||
const obj = ls.toLocal(obj_global);
|
||||
if (try obj.getFunction("handleEvent")) |handleEvent| {
|
||||
try handleEvent.callWithThis(void, obj, .{event});
|
||||
try handleEvent.callWithThis(void, obj, .{js_val});
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@@ -172,60 +172,56 @@ pub fn eventTarget(self: *Factory, child: anytype) !*@TypeOf(child) {
|
||||
return chain.get(1);
|
||||
}
|
||||
|
||||
fn eventInit(typ: []const u8, value: anytype, page: *Page) !Event {
|
||||
fn eventInit(arena: Allocator, typ: []const u8, value: anytype, page: *Page) !Event {
|
||||
// Round to 2ms for privacy (browsers do this)
|
||||
const raw_timestamp = @import("../datetime.zig").milliTimestamp(.monotonic);
|
||||
const time_stamp = (raw_timestamp / 2) * 2;
|
||||
|
||||
return .{
|
||||
._page = page,
|
||||
._arena = arena,
|
||||
._type = unionInit(Event.Type, value),
|
||||
._type_string = try String.init(page.arena, typ, .{}),
|
||||
._type_string = try String.init(arena, typ, .{}),
|
||||
._time_stamp = time_stamp,
|
||||
};
|
||||
}
|
||||
|
||||
// this is a root object
|
||||
pub fn event(self: *Factory, typ: []const u8, child: anytype) !*@TypeOf(child) {
|
||||
const allocator = self._slab.allocator();
|
||||
|
||||
pub fn event(self: *Factory, arena: Allocator, typ: []const u8, child: anytype) !*@TypeOf(child) {
|
||||
const chain = try PrototypeChain(
|
||||
&.{ Event, @TypeOf(child) },
|
||||
).allocate(allocator);
|
||||
).allocate(arena);
|
||||
|
||||
// Special case: Event has a _type_string field, so we need manual setup
|
||||
const event_ptr = chain.get(0);
|
||||
event_ptr.* = try eventInit(typ, chain.get(1), self._page);
|
||||
event_ptr.* = try eventInit(arena, typ, chain.get(1), self._page);
|
||||
chain.setLeaf(1, child);
|
||||
|
||||
return chain.get(1);
|
||||
}
|
||||
|
||||
pub fn uiEvent(self: *Factory, typ: []const u8, child: anytype) !*@TypeOf(child) {
|
||||
const allocator = self._slab.allocator();
|
||||
|
||||
pub fn uiEvent(self: *Factory, arena: Allocator, typ: []const u8, child: anytype) !*@TypeOf(child) {
|
||||
const chain = try PrototypeChain(
|
||||
&.{ Event, UIEvent, @TypeOf(child) },
|
||||
).allocate(allocator);
|
||||
).allocate(arena);
|
||||
|
||||
// Special case: Event has a _type_string field, so we need manual setup
|
||||
const event_ptr = chain.get(0);
|
||||
event_ptr.* = try eventInit(typ, chain.get(1), self._page);
|
||||
event_ptr.* = try eventInit(arena, typ, chain.get(1), self._page);
|
||||
chain.setMiddle(1, UIEvent.Type);
|
||||
chain.setLeaf(2, child);
|
||||
|
||||
return chain.get(2);
|
||||
}
|
||||
|
||||
pub fn mouseEvent(self: *Factory, typ: []const u8, mouse: MouseEvent, child: anytype) !*@TypeOf(child) {
|
||||
const allocator = self._slab.allocator();
|
||||
|
||||
pub fn mouseEvent(self: *Factory, arena: Allocator, typ: []const u8, mouse: MouseEvent, child: anytype) !*@TypeOf(child) {
|
||||
const chain = try PrototypeChain(
|
||||
&.{ Event, UIEvent, MouseEvent, @TypeOf(child) },
|
||||
).allocate(allocator);
|
||||
).allocate(arena);
|
||||
|
||||
// Special case: Event has a _type_string field, so we need manual setup
|
||||
const event_ptr = chain.get(0);
|
||||
event_ptr.* = try eventInit(typ, chain.get(1), self._page);
|
||||
event_ptr.* = try eventInit(arena, typ, chain.get(1), self._page);
|
||||
chain.setMiddle(1, UIEvent.Type);
|
||||
|
||||
// Set MouseEvent with all its fields
|
||||
|
||||
@@ -333,6 +333,10 @@ fn reset(self: *Page, comptime initializing: bool) !void {
|
||||
self._customized_builtin_disconnected_callback_invoked = .{};
|
||||
self._undefined_custom_elements = .{};
|
||||
|
||||
if (comptime IS_DEBUG) {
|
||||
self._arena_pool_leak_track = .{};
|
||||
}
|
||||
|
||||
try self.registerBackgroundTasks();
|
||||
}
|
||||
|
||||
|
||||
@@ -197,22 +197,21 @@ pub fn mapZigInstanceToJs(self: *const Local, js_obj_handle: ?*const v8.Object,
|
||||
// dont' use js_obj.persist(), because we don't want to track this in
|
||||
// context.global_objects, we want to track it in context.identity_map.
|
||||
v8.v8__Global__New(isolate.handle, js_obj.handle, gop.value_ptr);
|
||||
if (@hasDecl(JsApi.Meta, "finalizer")) {
|
||||
if (comptime IS_DEBUG) {
|
||||
// You can normally return a "*Node" and we'll correctly
|
||||
// handle it as what it really is, e.g. an HTMLScriptElement.
|
||||
// But for finalizers, we can't do that. I think this
|
||||
// limitation will be OK - this auto-resolution is largely
|
||||
// limited to Node -> HtmlElement, none of which has finalizers
|
||||
std.debug.assert(resolved.class_id == JsApi.Meta.class_id);
|
||||
}
|
||||
|
||||
if (@hasDecl(JsApi.Meta, "finalizer")) {
|
||||
// It would be great if resolved knew the resolved type, but I
|
||||
// can't figure out how to make that work, since it depends on
|
||||
// the [runtime] `value.
|
||||
// We need the resolved finalizer, which we have in resolved.
|
||||
// The above if statement would be more clear as:
|
||||
// if (resolved.finalizer) |finalizer| {
|
||||
// But that's a runtime check.
|
||||
// Instead, we check if the base has finalizer. The assumption
|
||||
// here is that if a resolve type has a finalizer, than the base
|
||||
// should have a finalizer too.
|
||||
try ctx.finalizer_callbacks.put(ctx.arena, @intFromPtr(resolved.ptr), .init(value));
|
||||
if (@hasDecl(JsApi.Meta, "weak")) {
|
||||
if (comptime IS_DEBUG) {
|
||||
std.debug.assert(JsApi.Meta.weak == true);
|
||||
}
|
||||
v8.v8__Global__SetWeakFinalizer(gop.value_ptr, resolved.ptr, JsApi.Meta.finalizer.from_v8, v8.kParameter);
|
||||
if (resolved.weak) {
|
||||
v8.v8__Global__SetWeakFinalizer(gop.value_ptr, resolved.ptr, resolved.finalizer.?, v8.kParameter);
|
||||
}
|
||||
}
|
||||
return js_obj;
|
||||
@@ -1032,9 +1031,11 @@ fn jsUnsignedIntToZig(comptime T: type, max: comptime_int, maybe: u32) !T {
|
||||
// This function recursively walks the _type union field (if there is one) to
|
||||
// get the most specific class_id possible.
|
||||
const Resolved = struct {
|
||||
weak: bool,
|
||||
ptr: *anyopaque,
|
||||
class_id: u16,
|
||||
prototype_chain: []const @import("TaggedOpaque.zig").PrototypeChainEntry,
|
||||
finalizer: ?*const fn (handle: ?*const v8.WeakCallbackInfo) callconv(.c) void = null,
|
||||
};
|
||||
pub fn resolveValue(value: anytype) Resolved {
|
||||
const T = bridge.Struct(@TypeOf(value));
|
||||
@@ -1062,10 +1063,13 @@ pub fn resolveValue(value: anytype) Resolved {
|
||||
}
|
||||
|
||||
fn resolveT(comptime T: type, value: *anyopaque) Resolved {
|
||||
const Meta = T.JsApi.Meta;
|
||||
return .{
|
||||
.ptr = value,
|
||||
.class_id = T.JsApi.Meta.class_id,
|
||||
.prototype_chain = &T.JsApi.Meta.prototype_chain,
|
||||
.class_id = Meta.class_id,
|
||||
.prototype_chain = &Meta.prototype_chain,
|
||||
.weak = if (@hasDecl(Meta, "weak")) Meta.weak else false,
|
||||
.finalizer = if (@hasDecl(Meta, "finalizer")) Meta.finalizer.from_v8 else null,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -111,7 +111,8 @@ pub fn Builder(comptime T: type) type {
|
||||
// to be possible between finalization and context shutdown,
|
||||
// we need to be defensive).
|
||||
// There _ARE_ alternatives to this. But this is simple.
|
||||
const ctx = self._page.js;
|
||||
const page = findPageField(T, self);
|
||||
const ctx = page.js;
|
||||
if (!ctx.identity_map.contains(@intFromPtr(ptr))) {
|
||||
return;
|
||||
}
|
||||
@@ -515,6 +516,17 @@ fn countFlattenedTypes(comptime Types: []const type) usize {
|
||||
return c;
|
||||
}
|
||||
|
||||
fn findPageField(comptime OriginalT: type, value: anytype) *Page {
|
||||
const T = Struct(@TypeOf(value));
|
||||
if (@hasField(T, "_page")) {
|
||||
return value._page;
|
||||
}
|
||||
if (@hasField(T, "_proto") == false) {
|
||||
@compileError("Expected to find a _page: *Page field on " ++ @typeName(OriginalT) ++ " or it's _proto chain");
|
||||
}
|
||||
return findPageField(OriginalT, value._proto);
|
||||
}
|
||||
|
||||
// T => T
|
||||
// *T => T
|
||||
pub fn Struct(comptime T: type) type {
|
||||
|
||||
@@ -24,11 +24,14 @@ const EventTarget = @import("EventTarget.zig");
|
||||
const Node = @import("Node.zig");
|
||||
const String = @import("../../string.zig").String;
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
pub const Event = @This();
|
||||
|
||||
pub const _prototype_root = true;
|
||||
_type: Type,
|
||||
|
||||
_page: *Page,
|
||||
_arena: Allocator,
|
||||
_bubbles: bool = false,
|
||||
_cancelable: bool = false,
|
||||
_composed: bool = false,
|
||||
@@ -79,23 +82,32 @@ pub fn init(typ: []const u8, opts_: ?Options, page: *Page) !*Event {
|
||||
}
|
||||
|
||||
fn initWithTrusted(typ: []const u8, opts_: ?Options, trusted: bool, page: *Page) !*Event {
|
||||
const arena = try page.getArena(.{ .debug = "Event" });
|
||||
errdefer page.releaseArena(arena);
|
||||
|
||||
const opts = opts_ orelse Options{};
|
||||
|
||||
// Round to 2ms for privacy (browsers do this)
|
||||
const raw_timestamp = @import("../../datetime.zig").milliTimestamp(.monotonic);
|
||||
const time_stamp = (raw_timestamp / 2) * 2;
|
||||
|
||||
const event = try page._factory.create(Event{
|
||||
const self = try arena.create(Event);
|
||||
self.* = .{
|
||||
._page = page,
|
||||
._arena = arena,
|
||||
._type = .generic,
|
||||
._bubbles = opts.bubbles,
|
||||
._time_stamp = time_stamp,
|
||||
._cancelable = opts.cancelable,
|
||||
._composed = opts.composed,
|
||||
._type_string = try String.init(page.arena, typ, .{}),
|
||||
});
|
||||
._isTrusted = trusted,
|
||||
._type_string = try String.init(arena, typ, .{}),
|
||||
};
|
||||
return self;
|
||||
}
|
||||
|
||||
event._isTrusted = trusted;
|
||||
return event;
|
||||
pub fn deinit(self: *Event, _: bool) void {
|
||||
self._page.releaseArena(self._arena);
|
||||
}
|
||||
|
||||
pub fn initEvent(
|
||||
@@ -103,13 +115,12 @@ pub fn initEvent(
|
||||
event_string: []const u8,
|
||||
bubbles: ?bool,
|
||||
cancelable: ?bool,
|
||||
page: *Page,
|
||||
) !void {
|
||||
if (self._event_phase != .none) {
|
||||
return;
|
||||
}
|
||||
|
||||
self._type_string = try String.init(page.arena, event_string, .{});
|
||||
self._type_string = try String.init(self._arena, event_string, .{});
|
||||
self._bubbles = bubbles orelse false;
|
||||
self._cancelable = cancelable orelse false;
|
||||
self._stop_propagation = false;
|
||||
@@ -385,6 +396,8 @@ pub const JsApi = struct {
|
||||
|
||||
pub const prototype_chain = bridge.prototypeChain();
|
||||
pub var class_id: bridge.ClassId = undefined;
|
||||
pub const weak = true;
|
||||
pub const finalizer = bridge.finalizer(Event.deinit);
|
||||
};
|
||||
|
||||
pub const constructor = bridge.constructor(Event.init, .{});
|
||||
|
||||
@@ -33,17 +33,24 @@ const CompositionEventOptions = struct {
|
||||
const Options = Event.inheritOptions(CompositionEvent, CompositionEventOptions);
|
||||
|
||||
pub fn init(typ: []const u8, opts_: ?Options, page: *Page) !*CompositionEvent {
|
||||
const arena = try page.getArena(.{ .debug = "CompositionEvent" });
|
||||
errdefer page.releaseArena(arena);
|
||||
|
||||
const opts = opts_ orelse Options{};
|
||||
|
||||
const event = try page._factory.event(typ, CompositionEvent{
|
||||
const event = try page._factory.event(arena, typ, CompositionEvent{
|
||||
._proto = undefined,
|
||||
._data = if (opts.data) |str| try page.dupeString(str) else "",
|
||||
._data = if (opts.data) |str| try arena.dupe(u8, str) else "",
|
||||
});
|
||||
|
||||
Event.populatePrototypes(event, opts, false);
|
||||
return event;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *CompositionEvent, shutdown: bool) void {
|
||||
self._proto.deinit(shutdown);
|
||||
}
|
||||
|
||||
pub fn asEvent(self: *CompositionEvent) *Event {
|
||||
return self._proto;
|
||||
}
|
||||
@@ -59,6 +66,8 @@ pub const JsApi = struct {
|
||||
pub const name = "CompositionEvent";
|
||||
pub const prototype_chain = bridge.prototypeChain();
|
||||
pub var class_id: bridge.ClassId = undefined;
|
||||
pub const weak = true;
|
||||
pub const finalizer = bridge.finalizer(CompositionEvent.deinit);
|
||||
};
|
||||
|
||||
pub const constructor = bridge.constructor(CompositionEvent.init, .{});
|
||||
|
||||
@@ -37,10 +37,13 @@ const CustomEventOptions = struct {
|
||||
const Options = Event.inheritOptions(CustomEvent, CustomEventOptions);
|
||||
|
||||
pub fn init(typ: []const u8, opts_: ?Options, page: *Page) !*CustomEvent {
|
||||
const arena = page.arena;
|
||||
const arena = try page.getArena(.{ .debug = "CustomEvent" });
|
||||
errdefer page.releaseArena(arena);
|
||||
|
||||
const opts = opts_ orelse Options{};
|
||||
|
||||
const event = try page._factory.event(
|
||||
arena,
|
||||
typ,
|
||||
CustomEvent{
|
||||
._arena = arena,
|
||||
@@ -53,21 +56,23 @@ pub fn init(typ: []const u8, opts_: ?Options, page: *Page) !*CustomEvent {
|
||||
return event;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *CustomEvent, shutdown: bool) void {
|
||||
self._proto.deinit(shutdown);
|
||||
}
|
||||
|
||||
pub fn initCustomEvent(
|
||||
self: *CustomEvent,
|
||||
event_string: []const u8,
|
||||
bubbles: ?bool,
|
||||
cancelable: ?bool,
|
||||
detail_: ?js.Value.Global,
|
||||
page: *Page,
|
||||
detail: ?js.Value.Global,
|
||||
) !void {
|
||||
// This function can only be called after the constructor has called.
|
||||
// So we assume proto is initialized already by constructor.
|
||||
self._proto._type_string = try String.init(page.arena, event_string, .{});
|
||||
self._proto._type_string = try String.init(self._proto._arena, event_string, .{});
|
||||
self._proto._bubbles = bubbles orelse false;
|
||||
self._proto._cancelable = cancelable orelse false;
|
||||
// Detail is stored separately.
|
||||
self._detail = detail_;
|
||||
self._detail = detail;
|
||||
}
|
||||
|
||||
pub fn asEvent(self: *CustomEvent) *Event {
|
||||
@@ -85,6 +90,8 @@ pub const JsApi = struct {
|
||||
pub const name = "CustomEvent";
|
||||
pub const prototype_chain = bridge.prototypeChain();
|
||||
pub var class_id: bridge.ClassId = undefined;
|
||||
pub const weak = true;
|
||||
pub const finalizer = bridge.finalizer(CustomEvent.deinit);
|
||||
};
|
||||
|
||||
pub const constructor = bridge.constructor(CustomEvent.init, .{});
|
||||
|
||||
@@ -31,7 +31,6 @@ _filename: []const u8 = "",
|
||||
_line_number: u32 = 0,
|
||||
_column_number: u32 = 0,
|
||||
_error: ?js.Value.Global = null,
|
||||
_arena: Allocator,
|
||||
|
||||
pub const ErrorEventOptions = struct {
|
||||
message: ?[]const u8 = null,
|
||||
@@ -52,13 +51,15 @@ pub fn initTrusted(typ: []const u8, opts_: ?Options, page: *Page) !*ErrorEvent {
|
||||
}
|
||||
|
||||
fn initWithTrusted(typ: []const u8, opts_: ?Options, trusted: bool, page: *Page) !*ErrorEvent {
|
||||
const arena = page.arena;
|
||||
const arena = try page.getArena(.{ .debug = "ErrorEvent" });
|
||||
errdefer page.releaseArena(arena);
|
||||
|
||||
const opts = opts_ orelse Options{};
|
||||
|
||||
const event = try page._factory.event(
|
||||
arena,
|
||||
typ,
|
||||
ErrorEvent{
|
||||
._arena = arena,
|
||||
._proto = undefined,
|
||||
._message = if (opts.message) |str| try arena.dupe(u8, str) else "",
|
||||
._filename = if (opts.filename) |str| try arena.dupe(u8, str) else "",
|
||||
@@ -72,6 +73,10 @@ fn initWithTrusted(typ: []const u8, opts_: ?Options, trusted: bool, page: *Page)
|
||||
return event;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *ErrorEvent, shutdown: bool) void {
|
||||
self._proto.deinit(shutdown);
|
||||
}
|
||||
|
||||
pub fn asEvent(self: *ErrorEvent) *Event {
|
||||
return self._proto;
|
||||
}
|
||||
@@ -103,6 +108,8 @@ pub const JsApi = struct {
|
||||
pub const name = "ErrorEvent";
|
||||
pub const prototype_chain = bridge.prototypeChain();
|
||||
pub var class_id: bridge.ClassId = undefined;
|
||||
pub const weak = true;
|
||||
pub const finalizer = bridge.finalizer(ErrorEvent.deinit);
|
||||
};
|
||||
|
||||
// Start API
|
||||
|
||||
@@ -189,15 +189,19 @@ pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*KeyboardEvent {
|
||||
}
|
||||
|
||||
fn initWithTrusted(typ: []const u8, _opts: ?Options, trusted: bool, page: *Page) !*KeyboardEvent {
|
||||
const arena = try page.getArena(.{ .debug = "KeyboardEvent" });
|
||||
errdefer page.releaseArena(arena);
|
||||
|
||||
const opts = _opts orelse Options{};
|
||||
|
||||
const event = try page._factory.uiEvent(
|
||||
arena,
|
||||
typ,
|
||||
KeyboardEvent{
|
||||
._proto = undefined,
|
||||
._key = try Key.fromString(page.arena, opts.key),
|
||||
._key = try Key.fromString(arena, opts.key),
|
||||
._location = std.meta.intToEnum(Location, opts.location) catch return error.TypeError,
|
||||
._code = if (opts.code) |c| try page.dupeString(c) else "",
|
||||
._code = if (opts.code) |c| try arena.dupe(u8, c) else "",
|
||||
._repeat = opts.repeat,
|
||||
._is_composing = opts.isComposing,
|
||||
._ctrl_key = opts.ctrlKey,
|
||||
@@ -211,6 +215,10 @@ fn initWithTrusted(typ: []const u8, _opts: ?Options, trusted: bool, page: *Page)
|
||||
return event;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *KeyboardEvent, shutdown: bool) void {
|
||||
self._proto.deinit(shutdown);
|
||||
}
|
||||
|
||||
pub fn asEvent(self: *KeyboardEvent) *Event {
|
||||
return self._proto.asEvent();
|
||||
}
|
||||
@@ -251,8 +259,8 @@ pub fn getShiftKey(self: *const KeyboardEvent) bool {
|
||||
return self._shift_key;
|
||||
}
|
||||
|
||||
pub fn getModifierState(self: *const KeyboardEvent, str: []const u8, page: *Page) !bool {
|
||||
const key = try Key.fromString(page.arena, str);
|
||||
pub fn getModifierState(self: *KeyboardEvent, str: []const u8) !bool {
|
||||
const key = try Key.fromString(self.asEvent()._arena, str);
|
||||
|
||||
switch (key) {
|
||||
.Alt, .AltGraph => return self._alt_key,
|
||||
@@ -274,6 +282,8 @@ pub const JsApi = struct {
|
||||
pub const name = "KeyboardEvent";
|
||||
pub const prototype_chain = bridge.prototypeChain();
|
||||
pub var class_id: bridge.ClassId = undefined;
|
||||
pub const weak = true;
|
||||
pub const finalizer = bridge.finalizer(KeyboardEvent.deinit);
|
||||
};
|
||||
|
||||
pub const constructor = bridge.constructor(KeyboardEvent.init, .{});
|
||||
|
||||
@@ -46,14 +46,18 @@ pub fn initTrusted(typ: []const u8, opts_: ?Options, page: *Page) !*MessageEvent
|
||||
}
|
||||
|
||||
fn initWithTrusted(typ: []const u8, opts_: ?Options, trusted: bool, page: *Page) !*MessageEvent {
|
||||
const arena = try page.getArena(.{ .debug = "MessageEvent" });
|
||||
errdefer page.releaseArena(arena);
|
||||
|
||||
const opts = opts_ orelse Options{};
|
||||
|
||||
const event = try page._factory.event(
|
||||
arena,
|
||||
typ,
|
||||
MessageEvent{
|
||||
._proto = undefined,
|
||||
._data = opts.data,
|
||||
._origin = if (opts.origin) |str| try page.arena.dupe(u8, str) else "",
|
||||
._origin = if (opts.origin) |str| try arena.dupe(u8, str) else "",
|
||||
._source = opts.source,
|
||||
},
|
||||
);
|
||||
@@ -62,6 +66,10 @@ fn initWithTrusted(typ: []const u8, opts_: ?Options, trusted: bool, page: *Page)
|
||||
return event;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *MessageEvent, shutdown: bool) void {
|
||||
self._proto.deinit(shutdown);
|
||||
}
|
||||
|
||||
pub fn asEvent(self: *MessageEvent) *Event {
|
||||
return self._proto;
|
||||
}
|
||||
@@ -85,6 +93,8 @@ pub const JsApi = struct {
|
||||
pub const name = "MessageEvent";
|
||||
pub const prototype_chain = bridge.prototypeChain();
|
||||
pub var class_id: bridge.ClassId = undefined;
|
||||
pub const weak = true;
|
||||
pub const finalizer = bridge.finalizer(MessageEvent.deinit);
|
||||
};
|
||||
|
||||
pub const constructor = bridge.constructor(MessageEvent.init, .{});
|
||||
|
||||
@@ -75,9 +75,13 @@ pub const Options = Event.inheritOptions(
|
||||
);
|
||||
|
||||
pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*MouseEvent {
|
||||
const arena = try page.getArena(.{ .debug = "MouseEvent" });
|
||||
errdefer page.releaseArena(arena);
|
||||
|
||||
const opts = _opts orelse Options{};
|
||||
|
||||
const event = try page._factory.uiEvent(
|
||||
arena,
|
||||
typ,
|
||||
MouseEvent{
|
||||
._type = .generic,
|
||||
@@ -99,6 +103,10 @@ pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*MouseEvent {
|
||||
return event;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *MouseEvent, shutdown: bool) void {
|
||||
self._proto.deinit(shutdown);
|
||||
}
|
||||
|
||||
pub fn asEvent(self: *MouseEvent) *Event {
|
||||
return self._proto.asEvent();
|
||||
}
|
||||
@@ -180,6 +188,8 @@ pub const JsApi = struct {
|
||||
pub const name = "MouseEvent";
|
||||
pub const prototype_chain = bridge.prototypeChain();
|
||||
pub var class_id: bridge.ClassId = undefined;
|
||||
pub const weak = true;
|
||||
pub const finalizer = bridge.finalizer(MouseEvent.deinit);
|
||||
};
|
||||
|
||||
pub const constructor = bridge.constructor(MouseEvent.init, .{});
|
||||
|
||||
@@ -53,12 +53,16 @@ fn initWithTrusted(
|
||||
trusted: bool,
|
||||
page: *Page,
|
||||
) !*NavigationCurrentEntryChangeEvent {
|
||||
const arena = try page.getArena(.{ .debug = "NavigationCurrentEntryChangeEvent" });
|
||||
errdefer page.releaseArena(arena);
|
||||
|
||||
const navigation_type = if (opts.navigationType) |nav_type_str|
|
||||
std.meta.stringToEnum(NavigationType, nav_type_str)
|
||||
else
|
||||
null;
|
||||
|
||||
const event = try page._factory.event(
|
||||
arena,
|
||||
typ,
|
||||
NavigationCurrentEntryChangeEvent{
|
||||
._proto = undefined,
|
||||
@@ -71,6 +75,10 @@ fn initWithTrusted(
|
||||
return event;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *NavigationCurrentEntryChangeEvent, shutdown: bool) void {
|
||||
self._proto.deinit(shutdown);
|
||||
}
|
||||
|
||||
pub fn asEvent(self: *NavigationCurrentEntryChangeEvent) *Event {
|
||||
return self._proto;
|
||||
}
|
||||
@@ -90,6 +98,8 @@ pub const JsApi = struct {
|
||||
pub const name = "NavigationCurrentEntryChangeEvent";
|
||||
pub const prototype_chain = bridge.prototypeChain();
|
||||
pub var class_id: bridge.ClassId = undefined;
|
||||
pub const weak = true;
|
||||
pub const finalizer = bridge.finalizer(NavigationCurrentEntryChangeEvent.deinit);
|
||||
};
|
||||
|
||||
pub const constructor = bridge.constructor(NavigationCurrentEntryChangeEvent.init, .{});
|
||||
|
||||
@@ -41,9 +41,13 @@ pub fn initTrusted(typ: []const u8, _opts: ?Options, page: *Page) !*PageTransiti
|
||||
}
|
||||
|
||||
fn initWithTrusted(typ: []const u8, _opts: ?Options, trusted: bool, page: *Page) !*PageTransitionEvent {
|
||||
const arena = try page.getArena(.{ .debug = "PageTransitionEvent" });
|
||||
errdefer page.releaseArena(arena);
|
||||
|
||||
const opts = _opts orelse Options{};
|
||||
|
||||
const event = try page._factory.event(
|
||||
arena,
|
||||
typ,
|
||||
PageTransitionEvent{
|
||||
._proto = undefined,
|
||||
@@ -55,6 +59,10 @@ fn initWithTrusted(typ: []const u8, _opts: ?Options, trusted: bool, page: *Page)
|
||||
return event;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *PageTransitionEvent, shutdown: bool) void {
|
||||
self._proto.deinit(shutdown);
|
||||
}
|
||||
|
||||
pub fn asEvent(self: *PageTransitionEvent) *Event {
|
||||
return self._proto;
|
||||
}
|
||||
@@ -70,6 +78,8 @@ pub const JsApi = struct {
|
||||
pub const name = "PageTransitionEvent";
|
||||
pub const prototype_chain = bridge.prototypeChain();
|
||||
pub var class_id: bridge.ClassId = undefined;
|
||||
pub const weak = true;
|
||||
pub const finalizer = bridge.finalizer(PageTransitionEvent.deinit);
|
||||
};
|
||||
|
||||
pub const constructor = bridge.constructor(PageTransitionEvent.init, .{});
|
||||
|
||||
@@ -81,9 +81,13 @@ const Options = Event.inheritOptions(
|
||||
);
|
||||
|
||||
pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*PointerEvent {
|
||||
const arena = try page.getArena(.{ .debug = "PointerEvent" });
|
||||
errdefer page.releaseArena(arena);
|
||||
|
||||
const opts = _opts orelse Options{};
|
||||
|
||||
const event = try page._factory.mouseEvent(
|
||||
arena,
|
||||
typ,
|
||||
MouseEvent{
|
||||
._type = .{ .pointer_event = undefined },
|
||||
@@ -120,6 +124,10 @@ pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*PointerEvent {
|
||||
return event;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *PointerEvent, shutdown: bool) void {
|
||||
self._proto.deinit(shutdown);
|
||||
}
|
||||
|
||||
pub fn asEvent(self: *PointerEvent) *Event {
|
||||
return self._proto.asEvent();
|
||||
}
|
||||
@@ -179,6 +187,8 @@ pub const JsApi = struct {
|
||||
pub const name = "PointerEvent";
|
||||
pub const prototype_chain = bridge.prototypeChain();
|
||||
pub var class_id: bridge.ClassId = undefined;
|
||||
pub const weak = true;
|
||||
pub const finalizer = bridge.finalizer(PointerEvent.deinit);
|
||||
};
|
||||
|
||||
pub const constructor = bridge.constructor(PointerEvent.init, .{});
|
||||
|
||||
@@ -41,9 +41,13 @@ pub fn initTrusted(typ: []const u8, _opts: ?Options, page: *Page) !*PopStateEven
|
||||
}
|
||||
|
||||
fn initWithTrusted(typ: []const u8, _opts: ?Options, trusted: bool, page: *Page) !*PopStateEvent {
|
||||
const arena = try page.getArena(.{ .debug = "CustomEvPopStateEventent" });
|
||||
errdefer page.releaseArena(arena);
|
||||
|
||||
const opts = _opts orelse Options{};
|
||||
|
||||
const event = try page._factory.event(
|
||||
arena,
|
||||
typ,
|
||||
PopStateEvent{
|
||||
._proto = undefined,
|
||||
@@ -55,6 +59,10 @@ fn initWithTrusted(typ: []const u8, _opts: ?Options, trusted: bool, page: *Page)
|
||||
return event;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *PopStateEvent, shutdown: bool) void {
|
||||
self._proto.deinit(shutdown);
|
||||
}
|
||||
|
||||
pub fn asEvent(self: *PopStateEvent) *Event {
|
||||
return self._proto;
|
||||
}
|
||||
@@ -76,6 +84,8 @@ pub const JsApi = struct {
|
||||
pub const name = "PopStateEvent";
|
||||
pub const prototype_chain = bridge.prototypeChain();
|
||||
pub var class_id: bridge.ClassId = undefined;
|
||||
pub const weak = true;
|
||||
pub const finalizer = bridge.finalizer(PopStateEvent.deinit);
|
||||
};
|
||||
|
||||
pub const constructor = bridge.constructor(PopStateEvent.init, .{});
|
||||
|
||||
@@ -42,9 +42,13 @@ pub fn initTrusted(typ: []const u8, _opts: ?Options, page: *Page) !*ProgressEven
|
||||
}
|
||||
|
||||
fn initWithTrusted(typ: []const u8, _opts: ?Options, trusted: bool, page: *Page) !*ProgressEvent {
|
||||
const arena = try page.getArena(.{ .debug = "ProgressEvent" });
|
||||
errdefer page.releaseArena(arena);
|
||||
|
||||
const opts = _opts orelse Options{};
|
||||
|
||||
const event = try page._factory.event(
|
||||
arena,
|
||||
typ,
|
||||
ProgressEvent{
|
||||
._proto = undefined,
|
||||
@@ -57,6 +61,10 @@ fn initWithTrusted(typ: []const u8, _opts: ?Options, trusted: bool, page: *Page)
|
||||
return event;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *ProgressEvent, shutdown: bool) void {
|
||||
self._proto.deinit(shutdown);
|
||||
}
|
||||
|
||||
pub fn asEvent(self: *ProgressEvent) *Event {
|
||||
return self._proto;
|
||||
}
|
||||
@@ -81,6 +89,8 @@ pub const JsApi = struct {
|
||||
pub const name = "ProgressEvent";
|
||||
pub const prototype_chain = bridge.prototypeChain();
|
||||
pub var class_id: bridge.ClassId = undefined;
|
||||
pub const weak = true;
|
||||
pub const finalizer = bridge.finalizer(ProgressEvent.deinit);
|
||||
};
|
||||
|
||||
pub const constructor = bridge.constructor(ProgressEvent.init, .{});
|
||||
|
||||
@@ -45,9 +45,13 @@ pub const Options = Event.inheritOptions(
|
||||
);
|
||||
|
||||
pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*UIEvent {
|
||||
const arena = try page.getArena(.{ .debug = "UIEvent" });
|
||||
errdefer page.releaseArena(arena);
|
||||
|
||||
const opts = _opts orelse Options{};
|
||||
|
||||
const event = try page._factory.event(
|
||||
arena,
|
||||
typ,
|
||||
UIEvent{
|
||||
._type = .generic,
|
||||
@@ -61,6 +65,10 @@ pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*UIEvent {
|
||||
return event;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *UIEvent, shutdown: bool) void {
|
||||
self._proto.deinit(shutdown);
|
||||
}
|
||||
|
||||
pub fn as(self: *UIEvent, comptime T: type) *T {
|
||||
return self.is(T).?;
|
||||
}
|
||||
@@ -105,6 +113,8 @@ pub const JsApi = struct {
|
||||
pub const name = "UIEvent";
|
||||
pub const prototype_chain = bridge.prototypeChain();
|
||||
pub var class_id: bridge.ClassId = undefined;
|
||||
pub const weak = true;
|
||||
pub const finalizer = bridge.finalizer(UIEvent.deinit);
|
||||
};
|
||||
|
||||
pub const constructor = bridge.constructor(UIEvent.init, .{});
|
||||
|
||||
Reference in New Issue
Block a user