diff --git a/src/browser/EventManager.zig b/src/browser/EventManager.zig index cfe5966e..ffc8de9c 100644 --- a/src/browser/EventManager.zig +++ b/src/browser/EventManager.zig @@ -170,6 +170,8 @@ const DispatchError = error{ JsException, }; pub fn dispatch(self: *EventManager, target: *EventTarget, event: *Event) DispatchError!void { + defer if (!event._v8_handoff) event.deinit(false, self.page); + if (comptime IS_DEBUG) { log.debug(.event, "eventManager.dispatch", .{ .type = event._type_string.str(), .bubbles = event._bubbles }); } @@ -218,6 +220,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); + if (comptime IS_DEBUG) { log.debug(.event, "dispatchWithFunction", .{ .type = event._type_string.str(), .context = opts.context, .has_function = function_ != null }); } @@ -757,7 +761,6 @@ const ActivationState = struct { .bubbles = true, .cancelable = false, }, page); - defer if (!event._v8_handoff) event.deinit(false); const target = input.asElement().asEventTarget(); try page._event_manager.dispatch(target, event); diff --git a/src/browser/Factory.zig b/src/browser/Factory.zig index a46c3dc2..44bfcb1e 100644 --- a/src/browser/Factory.zig +++ b/src/browser/Factory.zig @@ -183,41 +183,41 @@ pub fn standaloneEventTarget(self: *Factory, child: anytype) !*EventTarget { } // this is a root object -pub fn event(self: *Factory, arena: Allocator, typ: String, child: anytype) !*@TypeOf(child) { +pub fn event(_: *const Factory, arena: Allocator, typ: String, child: anytype) !*@TypeOf(child) { const chain = try PrototypeChain( &.{ Event, @TypeOf(child) }, ).allocate(arena); // Special case: Event has a _type_string field, so we need manual setup const event_ptr = chain.get(0); - event_ptr.* = try self.eventInit(arena, typ, chain.get(1)); + event_ptr.* = try eventInit(arena, typ, chain.get(1)); chain.setLeaf(1, child); return chain.get(1); } -pub fn uiEvent(self: *Factory, arena: Allocator, typ: String, child: anytype) !*@TypeOf(child) { +pub fn uiEvent(_: *const Factory, arena: Allocator, typ: String, child: anytype) !*@TypeOf(child) { const chain = try PrototypeChain( &.{ Event, UIEvent, @TypeOf(child) }, ).allocate(arena); // Special case: Event has a _type_string field, so we need manual setup const event_ptr = chain.get(0); - event_ptr.* = try self.eventInit(arena, typ, chain.get(1)); + event_ptr.* = try eventInit(arena, typ, chain.get(1)); chain.setMiddle(1, UIEvent.Type); chain.setLeaf(2, child); return chain.get(2); } -pub fn mouseEvent(self: *Factory, arena: Allocator, typ: String, mouse: MouseEvent, child: anytype) !*@TypeOf(child) { +pub fn mouseEvent(_: *const Factory, arena: Allocator, typ: String, mouse: MouseEvent, child: anytype) !*@TypeOf(child) { const chain = try PrototypeChain( &.{ Event, UIEvent, MouseEvent, @TypeOf(child) }, ).allocate(arena); // Special case: Event has a _type_string field, so we need manual setup const event_ptr = chain.get(0); - event_ptr.* = try self.eventInit(arena, typ, chain.get(1)); + event_ptr.* = try eventInit(arena, typ, chain.get(1)); chain.setMiddle(1, UIEvent.Type); // Set MouseEvent with all its fields @@ -231,14 +231,13 @@ pub fn mouseEvent(self: *Factory, arena: Allocator, typ: String, mouse: MouseEve return chain.get(3); } -fn eventInit(self: *const Factory, arena: Allocator, typ: String, value: anytype) !Event { +fn eventInit(arena: Allocator, typ: String, value: anytype) !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 .{ ._arena = arena, - ._page = self._page, ._type = unionInit(Event.Type, value), ._type_string = typ, ._time_stamp = time_stamp, diff --git a/src/browser/Page.zig b/src/browser/Page.zig index bf87fad7..c58d8086 100644 --- a/src/browser/Page.zig +++ b/src/browser/Page.zig @@ -643,7 +643,6 @@ pub fn documentIsLoaded(self: *Page) void { pub fn _documentIsLoaded(self: *Page) !void { const event = try Event.initTrusted(.wrap("DOMContentLoaded"), .{ .bubbles = true }, self); - defer if (!event._v8_handoff) event.deinit(false); try self._event_manager.dispatch( self.document.asEventTarget(), event, @@ -664,7 +663,6 @@ pub fn iframeCompletedLoading(self: *Page, iframe: *Element.Html.IFrame) void { log.err(.page, "iframe event init", .{ .err = err }); break :blk; }; - defer if (!event._v8_handoff) event.deinit(false); self._event_manager.dispatch(iframe.asNode().asEventTarget(), event) catch |err| { log.warn(.js, "iframe onload", .{ .err = err, .url = iframe._src }); }; @@ -727,7 +725,6 @@ fn _documentIsComplete(self: *Page) !void { // Dispatch `_to_load` events before window.load. for (self._to_load.items) |element| { const event = try Event.initTrusted(comptime .wrap("load"), .{}, self); - defer if (!event._v8_handoff) event.deinit(false); try self._event_manager.dispatch(element.asEventTarget(), event); } @@ -736,7 +733,6 @@ fn _documentIsComplete(self: *Page) !void { // Dispatch window.load event. const event = try Event.initTrusted(comptime .wrap("load"), .{}, self); - defer if (!event._v8_handoff) event.deinit(false); // This event is weird, it's dispatched directly on the window, but // with the document as the target. event._target = self.document.asEventTarget(); @@ -748,7 +744,6 @@ fn _documentIsComplete(self: *Page) !void { ); const pageshow_event = (try PageTransitionEvent.initTrusted(comptime .wrap("pageshow"), .{}, self)).asEvent(); - defer if (!pageshow_event._v8_handoff) pageshow_event.deinit(false); try self._event_manager.dispatchWithFunction( self.window.asEventTarget(), pageshow_event, @@ -1565,8 +1560,6 @@ pub fn deliverSlotchangeEvents(self: *Page) void { log.err(.page, "deliverSlotchange.init", .{ .err = err, .type = self._type }); continue; }; - defer if (!event._v8_handoff) event.deinit(false); - const target = slot.asNode().asEventTarget(); _ = target.dispatchEvent(event, self) catch |err| { log.err(.page, "deliverSlotchange.dispatch", .{ .err = err, .type = self._type }); @@ -3182,8 +3175,6 @@ pub fn triggerMouseClick(self: *Page, x: f64, y: f64) !void { .clientX = x, .clientY = y, }, self)).asEvent(); - - defer if (!event._v8_handoff) event.deinit(false); try self._event_manager.dispatch(target.asEventTarget(), event); } @@ -3241,8 +3232,6 @@ pub fn handleClick(self: *Page, target: *Node) !void { pub fn triggerKeyboard(self: *Page, keyboard_event: *KeyboardEvent) !void { const event = keyboard_event.asEvent(); - defer if (!event._v8_handoff) event.deinit(false); - const element = self.window._document._active_element orelse return; if (comptime IS_DEBUG) { log.debug(.page, "page keydown", .{ @@ -3312,10 +3301,8 @@ pub fn submitForm(self: *Page, submitter_: ?*Element, form_: ?*Element.Html.Form const form_element = form.asElement(); if (submit_opts.fire_event) { - const submit_event = try Event.initTrusted(comptime .wrap("submit"), .{ .bubbles = true, .cancelable = true }, self); - defer if (!submit_event._v8_handoff) submit_event.deinit(false); - const onsubmit_handler = try form.asHtmlElement().getOnSubmit(self); + const submit_event = try Event.initTrusted(comptime .wrap("submit"), .{ .bubbles = true, .cancelable = true }, self); var ls: JS.Local.Scope = undefined; self.js.localScope(&ls); diff --git a/src/browser/ScriptManager.zig b/src/browser/ScriptManager.zig index 19e20825..f4d95230 100644 --- a/src/browser/ScriptManager.zig +++ b/src/browser/ScriptManager.zig @@ -893,7 +893,7 @@ pub const Script = struct { }); return; }; - defer if (!event._v8_handoff) event.deinit(false); + defer if (!event._v8_handoff) event.deinit(false, self.manager.page); var caught: js.TryCatch.Caught = undefined; cb.tryCall(void, .{event}, &caught) catch { diff --git a/src/browser/js/Context.zig b/src/browser/js/Context.zig index 115b6156..24981c08 100644 --- a/src/browser/js/Context.zig +++ b/src/browser/js/Context.zig @@ -1011,7 +1011,7 @@ pub fn queueMicrotaskFunc(self: *Context, cb: js.Function) void { self.isolate.enqueueMicrotaskFunc(cb); } -pub fn createFinalizerCallback(self: *Context, global: v8.Global, ptr: *anyopaque, finalizerFn: *const fn (ptr: *anyopaque) void) !*FinalizerCallback { +pub fn createFinalizerCallback(self: *Context, global: v8.Global, ptr: *anyopaque, finalizerFn: *const fn (ptr: *anyopaque, page: *Page) void) !*FinalizerCallback { const fc = try self.finalizer_callback_pool.create(); fc.* = .{ .ctx = self, @@ -1031,10 +1031,10 @@ pub const FinalizerCallback = struct { ctx: *Context, ptr: *anyopaque, global: v8.Global, - finalizerFn: *const fn (ptr: *anyopaque) void, + finalizerFn: *const fn (ptr: *anyopaque, page: *Page) void, pub fn deinit(self: *FinalizerCallback) void { - self.finalizerFn(self.ptr); + self.finalizerFn(self.ptr, self.ctx.page); self.ctx.finalizer_callback_pool.destroy(self); } }; diff --git a/src/browser/js/Local.zig b/src/browser/js/Local.zig index b51453b5..c4362d4b 100644 --- a/src/browser/js/Local.zig +++ b/src/browser/js/Local.zig @@ -17,6 +17,7 @@ // along with this program. If not, see . const std = @import("std"); +const Page = @import("../Page.zig"); const log = @import("../../log.zig"); const string = @import("../../string.zig"); @@ -1061,7 +1062,7 @@ const Resolved = struct { class_id: u16, prototype_chain: []const @import("TaggedOpaque.zig").PrototypeChainEntry, finalizer_from_v8: ?*const fn (handle: ?*const v8.WeakCallbackInfo) callconv(.c) void = null, - finalizer_from_zig: ?*const fn (ptr: *anyopaque) void = null, + finalizer_from_zig: ?*const fn (ptr: *anyopaque, page: *Page) void = null, }; pub fn resolveValue(value: anytype) Resolved { const T = bridge.Struct(@TypeOf(value)); diff --git a/src/browser/js/bridge.zig b/src/browser/js/bridge.zig index 3a991313..a8558161 100644 --- a/src/browser/js/bridge.zig +++ b/src/browser/js/bridge.zig @@ -104,11 +104,11 @@ pub fn Builder(comptime T: type) type { return entries; } - pub fn finalizer(comptime func: *const fn (self: *T, shutdown: bool) void) Finalizer { + pub fn finalizer(comptime func: *const fn (self: *T, shutdown: bool, page: *Page) void) Finalizer { return .{ .from_zig = struct { - fn wrap(ptr: *anyopaque) void { - func(@ptrCast(@alignCast(ptr)), true); + fn wrap(ptr: *anyopaque, page: *Page) void { + func(@ptrCast(@alignCast(ptr)), true, page); } }.wrap, @@ -120,7 +120,7 @@ pub fn Builder(comptime T: type) type { const ctx = fc.ctx; const value_ptr = fc.ptr; if (ctx.finalizer_callbacks.contains(@intFromPtr(value_ptr))) { - func(@ptrCast(@alignCast(value_ptr)), false); + func(@ptrCast(@alignCast(value_ptr)), false, ctx.page); ctx.release(value_ptr); } else { // A bit weird, but v8 _requires_ that we release it @@ -398,7 +398,7 @@ pub const Property = struct { const Finalizer = struct { // The finalizer wrapper when called fro Zig. This is only called on // Context.deinit - from_zig: *const fn (ctx: *anyopaque) void, + from_zig: *const fn (ctx: *anyopaque, page: *Page) void, // The finalizer wrapper when called from V8. This may never be called // (hence why we fallback to calling in Context.denit). If it is called, diff --git a/src/browser/webapi/AbortSignal.zig b/src/browser/webapi/AbortSignal.zig index 8eb61062..186a6cad 100644 --- a/src/browser/webapi/AbortSignal.zig +++ b/src/browser/webapi/AbortSignal.zig @@ -77,8 +77,6 @@ pub fn abort(self: *AbortSignal, reason_: ?Reason, local: *const js.Local, page: // Dispatch abort event const event = try Event.initTrusted(comptime .wrap("abort"), .{}, page); - defer if (!event._v8_handoff) event.deinit(false); - try page._event_manager.dispatchWithFunction( self.asEventTarget(), event, diff --git a/src/browser/webapi/Element.zig b/src/browser/webapi/Element.zig index 753d50a7..3a47be9b 100644 --- a/src/browser/webapi/Element.zig +++ b/src/browser/webapi/Element.zig @@ -868,12 +868,10 @@ pub fn focus(self: *Element, page: *Page) !void { // Dispatch blur on old element (no bubble, composed) const blur_event = try FocusEvent.initTrusted(comptime .wrap("blur"), .{ .composed = true, .relatedTarget = new_target }, page); - defer if (!blur_event.asEvent()._v8_handoff) blur_event.deinit(false); try page._event_manager.dispatch(old_target, blur_event.asEvent()); // Dispatch focusout on old element (bubbles, composed) const focusout_event = try FocusEvent.initTrusted(comptime .wrap("focusout"), .{ .bubbles = true, .composed = true, .relatedTarget = new_target }, page); - defer if (!focusout_event.asEvent()._v8_handoff) focusout_event.deinit(false); try page._event_manager.dispatch(old_target, focusout_event.asEvent()); } @@ -881,12 +879,10 @@ pub fn focus(self: *Element, page: *Page) !void { // Dispatch focus on new element (no bubble, composed) const focus_event = try FocusEvent.initTrusted(comptime .wrap("focus"), .{ .composed = true, .relatedTarget = old_related }, page); - defer if (!focus_event.asEvent()._v8_handoff) focus_event.deinit(false); try page._event_manager.dispatch(new_target, focus_event.asEvent()); // Dispatch focusin on new element (bubbles, composed) const focusin_event = try FocusEvent.initTrusted(comptime .wrap("focusin"), .{ .bubbles = true, .composed = true, .relatedTarget = old_related }, page); - defer if (!focusin_event.asEvent()._v8_handoff) focusin_event.deinit(false); try page._event_manager.dispatch(new_target, focusin_event.asEvent()); } @@ -900,12 +896,10 @@ pub fn blur(self: *Element, page: *Page) !void { // Dispatch blur (no bubble, composed) const blur_event = try FocusEvent.initTrusted(comptime .wrap("blur"), .{ .composed = true }, page); - defer if (!blur_event.asEvent()._v8_handoff) blur_event.deinit(false); try page._event_manager.dispatch(old_target, blur_event.asEvent()); // Dispatch focusout (bubbles, composed) const focusout_event = try FocusEvent.initTrusted(comptime .wrap("focusout"), .{ .bubbles = true, .composed = true }, page); - defer if (!focusout_event.asEvent()._v8_handoff) focusout_event.deinit(false); try page._event_manager.dispatch(old_target, focusout_event.asEvent()); } diff --git a/src/browser/webapi/Event.zig b/src/browser/webapi/Event.zig index b8568e79..0082682f 100644 --- a/src/browser/webapi/Event.zig +++ b/src/browser/webapi/Event.zig @@ -30,7 +30,6 @@ pub const Event = @This(); pub const _prototype_root = true; _type: Type, -_page: *Page, _arena: Allocator, _bubbles: bool = false, _cancelable: bool = false, @@ -84,16 +83,16 @@ pub fn init(typ: []const u8, opts_: ?Options, page: *Page) !*Event { const arena = try page.getArena(.{ .debug = "Event" }); errdefer page.releaseArena(arena); const str = try String.init(arena, typ, .{}); - return initWithTrusted(arena, str, opts_, false, page); + return initWithTrusted(arena, str, opts_, false); } pub fn initTrusted(typ: String, opts_: ?Options, page: *Page) !*Event { const arena = try page.getArena(.{ .debug = "Event.trusted" }); errdefer page.releaseArena(arena); - return initWithTrusted(arena, typ, opts_, true, page); + return initWithTrusted(arena, typ, opts_, true); } -fn initWithTrusted(arena: Allocator, typ: String, opts_: ?Options, trusted: bool, page: *Page) !*Event { +fn initWithTrusted(arena: Allocator, typ: String, opts_: ?Options, trusted: bool) !*Event { const opts = opts_ orelse Options{}; // Round to 2ms for privacy (browsers do this) @@ -102,7 +101,6 @@ fn initWithTrusted(arena: Allocator, typ: String, opts_: ?Options, trusted: bool const event = try arena.create(Event); event.* = .{ - ._page = page, ._arena = arena, ._type = .generic, ._bubbles = opts.bubbles, @@ -133,9 +131,9 @@ pub fn initEvent( self._prevent_default = false; } -pub fn deinit(self: *Event, shutdown: bool) void { +pub fn deinit(self: *Event, shutdown: bool, page: *Page) void { _ = shutdown; - self._page.releaseArena(self._arena); + page.releaseArena(self._arena); } pub fn as(self: *Event, comptime T: type) *T { diff --git a/src/browser/webapi/History.zig b/src/browser/webapi/History.zig index cf665e05..4e6bb348 100644 --- a/src/browser/webapi/History.zig +++ b/src/browser/webapi/History.zig @@ -80,8 +80,6 @@ fn goInner(delta: i32, page: *Page) !void { if (entry._url) |url| { if (try page.isSameOrigin(url)) { const event = (try PopStateEvent.initTrusted(comptime .wrap("popstate"), .{ .state = entry._state.value }, page)).asEvent(); - defer if (!event._v8_handoff) event.deinit(false); - try page._event_manager.dispatchWithFunction( page.window.asEventTarget(), event, diff --git a/src/browser/webapi/IntersectionObserver.zig b/src/browser/webapi/IntersectionObserver.zig index 4431d224..9d64de3c 100644 --- a/src/browser/webapi/IntersectionObserver.zig +++ b/src/browser/webapi/IntersectionObserver.zig @@ -36,7 +36,6 @@ pub fn registerTypes() []const type { const IntersectionObserver = @This(); -_page: *Page, _arena: Allocator, _callback: js.Function.Temp, _observing: std.ArrayList(*Element) = .{}, @@ -83,7 +82,6 @@ pub fn init(callback: js.Function.Temp, options: ?ObserverInit, page: *Page) !*I const self = try arena.create(IntersectionObserver); self.* = .{ - ._page = page, ._arena = arena, ._callback = callback, ._root = opts.root, @@ -93,8 +91,7 @@ pub fn init(callback: js.Function.Temp, options: ?ObserverInit, page: *Page) !*I return self; } -pub fn deinit(self: *IntersectionObserver, shutdown: bool) void { - const page = self._page; +pub fn deinit(self: *IntersectionObserver, shutdown: bool, page: *Page) void { page.js.release(self._callback); if ((comptime IS_DEBUG) and !shutdown) { std.debug.assert(self._observing.items.len == 0); @@ -140,7 +137,7 @@ pub fn unobserve(self: *IntersectionObserver, target: *Element, page: *Page) voi while (j < self._pending_entries.items.len) { if (self._pending_entries.items[j]._target == target) { const entry = self._pending_entries.swapRemove(j); - entry.deinit(false); + entry.deinit(false, page); } else { j += 1; } @@ -160,7 +157,7 @@ pub fn disconnect(self: *IntersectionObserver, page: *Page) void { self._previous_states.clearRetainingCapacity(); for (self._pending_entries.items) |entry| { - entry.deinit(false); + entry.deinit(false, page); } self._pending_entries.clearRetainingCapacity(); page.js.safeWeakRef(self); @@ -245,7 +242,6 @@ fn checkIntersection(self: *IntersectionObserver, target: *Element, page: *Page) const entry = try arena.create(IntersectionObserverEntry); entry.* = .{ - ._page = page, ._arena = arena, ._target = target, ._time = page.window._performance.now(), @@ -297,7 +293,6 @@ pub fn deliverEntries(self: *IntersectionObserver, page: *Page) !void { } pub const IntersectionObserverEntry = struct { - _page: *Page, _arena: Allocator, _time: f64, _target: *Element, @@ -307,8 +302,8 @@ pub const IntersectionObserverEntry = struct { _intersection_ratio: f64, _is_intersecting: bool, - pub fn deinit(self: *const IntersectionObserverEntry, _: bool) void { - self._page.releaseArena(self._arena); + pub fn deinit(self: *const IntersectionObserverEntry, _: bool, page: *Page) void { + page.releaseArena(self._arena); } pub fn getTarget(self: *const IntersectionObserverEntry) *Element { diff --git a/src/browser/webapi/MessagePort.zig b/src/browser/webapi/MessagePort.zig index def38da0..ffddf30c 100644 --- a/src/browser/webapi/MessagePort.zig +++ b/src/browser/webapi/MessagePort.zig @@ -130,7 +130,6 @@ const PostMessageCallback = struct { log.err(.dom, "MessagePort.postMessage", .{ .err = err }); return null; }).asEvent(); - defer if (!event._v8_handoff) event.deinit(false); var ls: js.Local.Scope = undefined; page.js.localScope(&ls); diff --git a/src/browser/webapi/MutationObserver.zig b/src/browser/webapi/MutationObserver.zig index c84e4db0..68d85fb4 100644 --- a/src/browser/webapi/MutationObserver.zig +++ b/src/browser/webapi/MutationObserver.zig @@ -38,7 +38,6 @@ pub fn registerTypes() []const type { const MutationObserver = @This(); -_page: *Page, _arena: Allocator, _callback: js.Function.Temp, _observing: std.ArrayList(Observing) = .{}, @@ -79,15 +78,13 @@ pub fn init(callback: js.Function.Temp, page: *Page) !*MutationObserver { const self = try arena.create(MutationObserver); self.* = .{ - ._page = page, ._arena = arena, ._callback = callback, }; return self; } -pub fn deinit(self: *MutationObserver, shutdown: bool) void { - const page = self._page; +pub fn deinit(self: *MutationObserver, shutdown: bool, page: *Page) void { page.js.release(self._callback); if ((comptime IS_DEBUG) and !shutdown) { std.debug.assert(self._observing.items.len == 0); @@ -174,7 +171,7 @@ pub fn disconnect(self: *MutationObserver, page: *Page) void { page.unregisterMutationObserver(self); self._observing.clearRetainingCapacity(); for (self._pending_records.items) |record| { - record.deinit(false); + record.deinit(false, page); } self._pending_records.clearRetainingCapacity(); page.js.safeWeakRef(self); @@ -218,10 +215,9 @@ pub fn notifyAttributeChange( } } - const arena = try self._page.getArena(.{ .debug = "MutationRecord" }); + const arena = try page.getArena(.{ .debug = "MutationRecord" }); const record = try arena.create(MutationRecord); record.* = .{ - ._page = page, ._arena = arena, ._type = .attributes, ._target = target_node, @@ -263,10 +259,9 @@ pub fn notifyCharacterDataChange( continue; } - const arena = try self._page.getArena(.{ .debug = "MutationRecord" }); + const arena = try page.getArena(.{ .debug = "MutationRecord" }); const record = try arena.create(MutationRecord); record.* = .{ - ._page = page, ._arena = arena, ._type = .characterData, ._target = target, @@ -311,10 +306,9 @@ pub fn notifyChildListChange( continue; } - const arena = try self._page.getArena(.{ .debug = "MutationRecord" }); + const arena = try page.getArena(.{ .debug = "MutationRecord" }); const record = try arena.create(MutationRecord); record.* = .{ - ._page = page, ._arena = arena, ._type = .childList, ._target = target, @@ -354,7 +348,6 @@ pub fn deliverRecords(self: *MutationObserver, page: *Page) !void { pub const MutationRecord = struct { _type: Type, - _page: *Page, _target: *Node, _arena: Allocator, _attribute_name: ?[]const u8, @@ -370,8 +363,8 @@ pub const MutationRecord = struct { characterData, }; - pub fn deinit(self: *const MutationRecord, _: bool) void { - self._page.releaseArena(self._arena); + pub fn deinit(self: *const MutationRecord, _: bool, page: *Page) void { + page.releaseArena(self._arena); } pub fn getType(self: *const MutationRecord) []const u8 { diff --git a/src/browser/webapi/Selection.zig b/src/browser/webapi/Selection.zig index 88da6d56..ed7bb4fd 100644 --- a/src/browser/webapi/Selection.zig +++ b/src/browser/webapi/Selection.zig @@ -39,7 +39,6 @@ pub const init: Selection = .{}; fn dispatchSelectionChangeEvent(page: *Page) !void { const event = try Event.init("selectionchange", .{}, page); - defer if (!event._v8_handoff) event.deinit(false); try page._event_manager.dispatch(page.document.asEventTarget(), event); } diff --git a/src/browser/webapi/Window.zig b/src/browser/webapi/Window.zig index 80694dfa..d33a9308 100644 --- a/src/browser/webapi/Window.zig +++ b/src/browser/webapi/Window.zig @@ -308,12 +308,10 @@ pub fn reportError(self: *Window, err: js.Value, page: *Page) !void { .cancelable = true, }, page); - const event = error_event.asEvent(); - defer if (!event._v8_handoff) event.deinit(false); - // Invoke window.onerror callback if set (per WHATWG spec, this is called // with 5 arguments: message, source, lineno, colno, error) // If it returns true, the event is cancelled. + var prevent_default = false; if (self._on_error) |on_error| { var ls: js.Local.Scope = undefined; page.js.localScope(&ls); @@ -330,12 +328,12 @@ pub fn reportError(self: *Window, err: js.Value, page: *Page) !void { // Per spec: returning true from onerror cancels the event if (result) |r| { - if (r.isTrue()) { - event._prevent_default = true; - } + prevent_default = r.isTrue(); } } + const event = error_event.asEvent(); + event._prevent_default = prevent_default; try page._event_manager.dispatch(self.asEventTarget(), event); if (comptime builtin.is_test == false) { @@ -478,7 +476,6 @@ pub fn scrollTo(self: *Window, opts: ScrollToOpts, y: ?i32, page: *Page) !void { } const event = try Event.initTrusted(comptime .wrap("scroll"), .{ .bubbles = true }, p); - defer if (!event._v8_handoff) event.deinit(false); try p._event_manager.dispatch(p.document.asEventTarget(), event); pos.state = .end; @@ -506,7 +503,6 @@ pub fn scrollTo(self: *Window, opts: ScrollToOpts, y: ?i32, page: *Page) !void { .done => return null, } const event = try Event.initTrusted(comptime .wrap("scrollend"), .{ .bubbles = true }, p); - defer if (!event._v8_handoff) event.deinit(false); try p._event_manager.dispatch(p.document.asEventTarget(), event); pos.state = .done; @@ -527,11 +523,10 @@ pub fn unhandledPromiseRejection(self: *Window, rejection: js.PromiseRejection, }); } - var event = (try @import("event/PromiseRejectionEvent.zig").init("unhandledrejection", .{ + const event = (try @import("event/PromiseRejectionEvent.zig").init("unhandledrejection", .{ .reason = if (rejection.reason()) |r| try r.temp() else null, .promise = try rejection.promise().temp(), }, page)).asEvent(); - defer if (!event._v8_handoff) event.deinit(false); try page._event_manager.dispatchWithFunction( self.asEventTarget(), @@ -705,7 +700,6 @@ const PostMessageCallback = struct { .bubbles = false, .cancelable = false, }, page)).asEvent(); - defer if (!event._v8_handoff) event.deinit(false); try page._event_manager.dispatch(window.asEventTarget(), event); return null; diff --git a/src/browser/webapi/animation/Animation.zig b/src/browser/webapi/animation/Animation.zig index f69ca118..96143952 100644 --- a/src/browser/webapi/animation/Animation.zig +++ b/src/browser/webapi/animation/Animation.zig @@ -61,8 +61,8 @@ pub fn init(page: *Page) !*Animation { return self; } -pub fn deinit(self: *Animation, _: bool) void { - self._page.releaseArena(self._arena); +pub fn deinit(self: *Animation, _: bool, page: *Page) void { + page.releaseArena(self._arena); } pub fn play(self: *Animation, page: *Page) !void { diff --git a/src/browser/webapi/element/Html.zig b/src/browser/webapi/element/Html.zig index cba1306b..0e5fa3ad 100644 --- a/src/browser/webapi/element/Html.zig +++ b/src/browser/webapi/element/Html.zig @@ -338,7 +338,6 @@ pub fn click(self: *HtmlElement, page: *Page) !void { .clientX = 0, .clientY = 0, }, page)).asEvent(); - defer if (!event._v8_handoff) event.deinit(false); try page._event_manager.dispatch(self.asEventTarget(), event); } diff --git a/src/browser/webapi/element/html/Input.zig b/src/browser/webapi/element/html/Input.zig index 0928a9c9..c16af069 100644 --- a/src/browser/webapi/element/html/Input.zig +++ b/src/browser/webapi/element/html/Input.zig @@ -100,7 +100,6 @@ pub fn setOnSelectionChange(self: *Input, listener: ?js.Function) !void { fn dispatchSelectionChangeEvent(self: *Input, page: *Page) !void { const event = try Event.init("selectionchange", .{ .bubbles = true }, page); - defer if (!event._v8_handoff) event.deinit(false); try page._event_manager.dispatch(self.asElement().asEventTarget(), event); } @@ -344,7 +343,6 @@ pub fn select(self: *Input, page: *Page) !void { const len = if (self._value) |v| @as(u32, @intCast(v.len)) else 0; try self.setSelectionRange(0, len, null, page); const event = try Event.init("select", .{ .bubbles = true }, page); - defer if (!event._v8_handoff) event.deinit(false); try page._event_manager.dispatch(self.asElement().asEventTarget(), event); } diff --git a/src/browser/webapi/element/html/Media.zig b/src/browser/webapi/element/html/Media.zig index ca9f6088..f258ee74 100644 --- a/src/browser/webapi/element/html/Media.zig +++ b/src/browser/webapi/element/html/Media.zig @@ -166,7 +166,6 @@ pub fn load(self: *Media, page: *Page) !void { fn dispatchEvent(self: *Media, name: []const u8, page: *Page) !void { const event = try Event.init(name, .{ .bubbles = false, .cancelable = false }, page); - defer if (!event._v8_handoff) event.deinit(false); try page._event_manager.dispatch(self.asElement().asEventTarget(), event); } diff --git a/src/browser/webapi/element/html/TextArea.zig b/src/browser/webapi/element/html/TextArea.zig index 41ccce76..916f67d8 100644 --- a/src/browser/webapi/element/html/TextArea.zig +++ b/src/browser/webapi/element/html/TextArea.zig @@ -52,7 +52,6 @@ pub fn setOnSelectionChange(self: *TextArea, listener: ?js.Function) !void { fn dispatchSelectionChangeEvent(self: *TextArea, page: *Page) !void { const event = try Event.init("selectionchange", .{ .bubbles = true }, page); - defer if (!event._v8_handoff) event.deinit(false); try page._event_manager.dispatch(self.asElement().asEventTarget(), event); } @@ -140,7 +139,6 @@ pub fn select(self: *TextArea, page: *Page) !void { const len = if (self._value) |v| @as(u32, @intCast(v.len)) else 0; try self.setSelectionRange(0, len, null, page); const event = try Event.init("select", .{ .bubbles = true }, page); - defer if (!event._v8_handoff) event.deinit(false); try page._event_manager.dispatch(self.asElement().asEventTarget(), event); } diff --git a/src/browser/webapi/encoding/TextDecoder.zig b/src/browser/webapi/encoding/TextDecoder.zig index be719279..4f23cfcc 100644 --- a/src/browser/webapi/encoding/TextDecoder.zig +++ b/src/browser/webapi/encoding/TextDecoder.zig @@ -25,7 +25,6 @@ const Allocator = std.mem.Allocator; const TextDecoder = @This(); _fatal: bool, -_page: *Page, _arena: Allocator, _ignore_bom: bool, _stream: std.ArrayList(u8), @@ -52,7 +51,6 @@ pub fn init(label_: ?[]const u8, opts_: ?InitOpts, page: *Page) !*TextDecoder { const opts = opts_ orelse InitOpts{}; const self = try arena.create(TextDecoder); self.* = .{ - ._page = page, ._arena = arena, ._stream = .empty, ._fatal = opts.fatal, @@ -61,8 +59,8 @@ pub fn init(label_: ?[]const u8, opts_: ?InitOpts, page: *Page) !*TextDecoder { return self; } -pub fn deinit(self: *TextDecoder, _: bool) void { - self._page.releaseArena(self._arena); +pub fn deinit(self: *TextDecoder, _: bool, page: *Page) void { + page.releaseArena(self._arena); } pub fn getIgnoreBOM(self: *const TextDecoder) bool { diff --git a/src/browser/webapi/event/CompositionEvent.zig b/src/browser/webapi/event/CompositionEvent.zig index 0362cb83..b98fdd6f 100644 --- a/src/browser/webapi/event/CompositionEvent.zig +++ b/src/browser/webapi/event/CompositionEvent.zig @@ -53,8 +53,8 @@ pub fn init(typ: []const u8, opts_: ?Options, page: *Page) !*CompositionEvent { return event; } -pub fn deinit(self: *CompositionEvent, shutdown: bool) void { - self._proto.deinit(shutdown); +pub fn deinit(self: *CompositionEvent, shutdown: bool, page: *Page) void { + self._proto.deinit(shutdown, page); } pub fn asEvent(self: *CompositionEvent) *Event { diff --git a/src/browser/webapi/event/CustomEvent.zig b/src/browser/webapi/event/CustomEvent.zig index 808e6ed2..e303d901 100644 --- a/src/browser/webapi/event/CustomEvent.zig +++ b/src/browser/webapi/event/CustomEvent.zig @@ -72,12 +72,11 @@ pub fn initCustomEvent( self._detail = detail_; } -pub fn deinit(self: *CustomEvent, shutdown: bool) void { - const proto = self._proto; +pub fn deinit(self: *CustomEvent, shutdown: bool, page: *Page) void { if (self._detail) |d| { - proto._page.js.release(d); + page.js.release(d); } - proto.deinit(shutdown); + self._proto.deinit(shutdown, page); } pub fn asEvent(self: *CustomEvent) *Event { diff --git a/src/browser/webapi/event/ErrorEvent.zig b/src/browser/webapi/event/ErrorEvent.zig index 4983fe90..5dd12a26 100644 --- a/src/browser/webapi/event/ErrorEvent.zig +++ b/src/browser/webapi/event/ErrorEvent.zig @@ -79,12 +79,11 @@ fn initWithTrusted(arena: Allocator, typ: String, opts_: ?Options, trusted: bool return event; } -pub fn deinit(self: *ErrorEvent, shutdown: bool) void { - const proto = self._proto; +pub fn deinit(self: *ErrorEvent, shutdown: bool, page: *Page) void { if (self._error) |e| { - proto._page.js.release(e); + page.js.release(e); } - proto.deinit(shutdown); + self._proto.deinit(shutdown, page); } pub fn asEvent(self: *ErrorEvent) *Event { diff --git a/src/browser/webapi/event/FocusEvent.zig b/src/browser/webapi/event/FocusEvent.zig index 2da56b04..37065936 100644 --- a/src/browser/webapi/event/FocusEvent.zig +++ b/src/browser/webapi/event/FocusEvent.zig @@ -69,8 +69,8 @@ fn initWithTrusted(arena: Allocator, typ: String, _opts: ?Options, trusted: bool return event; } -pub fn deinit(self: *FocusEvent, shutdown: bool) void { - self._proto.deinit(shutdown); +pub fn deinit(self: *FocusEvent, shutdown: bool, page: *Page) void { + self._proto.deinit(shutdown, page); } pub fn asEvent(self: *FocusEvent) *Event { diff --git a/src/browser/webapi/event/KeyboardEvent.zig b/src/browser/webapi/event/KeyboardEvent.zig index 7f062840..6e391812 100644 --- a/src/browser/webapi/event/KeyboardEvent.zig +++ b/src/browser/webapi/event/KeyboardEvent.zig @@ -221,8 +221,8 @@ fn initWithTrusted(arena: Allocator, typ: String, _opts: ?Options, trusted: bool return event; } -pub fn deinit(self: *KeyboardEvent, shutdown: bool) void { - self._proto.deinit(shutdown); +pub fn deinit(self: *KeyboardEvent, shutdown: bool, page: *Page) void { + self._proto.deinit(shutdown, page); } pub fn asEvent(self: *KeyboardEvent) *Event { diff --git a/src/browser/webapi/event/MessageEvent.zig b/src/browser/webapi/event/MessageEvent.zig index d285e0e7..34e04518 100644 --- a/src/browser/webapi/event/MessageEvent.zig +++ b/src/browser/webapi/event/MessageEvent.zig @@ -72,12 +72,11 @@ fn initWithTrusted(arena: Allocator, typ: String, opts_: ?Options, trusted: bool return event; } -pub fn deinit(self: *MessageEvent, shutdown: bool) void { - const proto = self._proto; +pub fn deinit(self: *MessageEvent, shutdown: bool, page: *Page) void { if (self._data) |d| { - proto._page.js.release(d); + page.js.release(d); } - proto.deinit(shutdown); + self._proto.deinit(shutdown, page); } pub fn asEvent(self: *MessageEvent) *Event { diff --git a/src/browser/webapi/event/MouseEvent.zig b/src/browser/webapi/event/MouseEvent.zig index 3997140d..c94a37d1 100644 --- a/src/browser/webapi/event/MouseEvent.zig +++ b/src/browser/webapi/event/MouseEvent.zig @@ -109,8 +109,8 @@ 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 deinit(self: *MouseEvent, shutdown: bool, page: *Page) void { + self._proto.deinit(shutdown, page); } pub fn asEvent(self: *MouseEvent) *Event { diff --git a/src/browser/webapi/event/NavigationCurrentEntryChangeEvent.zig b/src/browser/webapi/event/NavigationCurrentEntryChangeEvent.zig index 47101f2a..59e32b06 100644 --- a/src/browser/webapi/event/NavigationCurrentEntryChangeEvent.zig +++ b/src/browser/webapi/event/NavigationCurrentEntryChangeEvent.zig @@ -82,8 +82,8 @@ fn initWithTrusted( return event; } -pub fn deinit(self: *NavigationCurrentEntryChangeEvent, shutdown: bool) void { - self._proto.deinit(shutdown); +pub fn deinit(self: *NavigationCurrentEntryChangeEvent, shutdown: bool, page: *Page) void { + self._proto.deinit(shutdown, page); } pub fn asEvent(self: *NavigationCurrentEntryChangeEvent) *Event { diff --git a/src/browser/webapi/event/PageTransitionEvent.zig b/src/browser/webapi/event/PageTransitionEvent.zig index 259c68db..eceab4f2 100644 --- a/src/browser/webapi/event/PageTransitionEvent.zig +++ b/src/browser/webapi/event/PageTransitionEvent.zig @@ -65,8 +65,8 @@ fn initWithTrusted(arena: Allocator, typ: String, _opts: ?Options, trusted: bool return event; } -pub fn deinit(self: *PageTransitionEvent, shutdown: bool) void { - self._proto.deinit(shutdown); +pub fn deinit(self: *PageTransitionEvent, shutdown: bool, page: *Page) void { + self._proto.deinit(shutdown, page); } pub fn asEvent(self: *PageTransitionEvent) *Event { diff --git a/src/browser/webapi/event/PointerEvent.zig b/src/browser/webapi/event/PointerEvent.zig index df388186..82f4874f 100644 --- a/src/browser/webapi/event/PointerEvent.zig +++ b/src/browser/webapi/event/PointerEvent.zig @@ -127,8 +127,8 @@ 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 deinit(self: *PointerEvent, shutdown: bool, page: *Page) void { + self._proto.deinit(shutdown, page); } pub fn asEvent(self: *PointerEvent) *Event { diff --git a/src/browser/webapi/event/PopStateEvent.zig b/src/browser/webapi/event/PopStateEvent.zig index d346d9cc..45774998 100644 --- a/src/browser/webapi/event/PopStateEvent.zig +++ b/src/browser/webapi/event/PopStateEvent.zig @@ -66,8 +66,8 @@ fn initWithTrusted(arena: Allocator, typ: String, _opts: ?Options, trusted: bool return event; } -pub fn deinit(self: *PopStateEvent, shutdown: bool) void { - self._proto.deinit(shutdown); +pub fn deinit(self: *PopStateEvent, shutdown: bool, page: *Page) void { + self._proto.deinit(shutdown, page); } pub fn asEvent(self: *PopStateEvent) *Event { diff --git a/src/browser/webapi/event/ProgressEvent.zig b/src/browser/webapi/event/ProgressEvent.zig index 8e061c71..a78982a1 100644 --- a/src/browser/webapi/event/ProgressEvent.zig +++ b/src/browser/webapi/event/ProgressEvent.zig @@ -67,8 +67,8 @@ fn initWithTrusted(arena: Allocator, typ: String, _opts: ?Options, trusted: bool return event; } -pub fn deinit(self: *ProgressEvent, shutdown: bool) void { - self._proto.deinit(shutdown); +pub fn deinit(self: *ProgressEvent, shutdown: bool, page: *Page) void { + self._proto.deinit(shutdown, page); } pub fn asEvent(self: *ProgressEvent) *Event { diff --git a/src/browser/webapi/event/PromiseRejectionEvent.zig b/src/browser/webapi/event/PromiseRejectionEvent.zig index db498a24..957228df 100644 --- a/src/browser/webapi/event/PromiseRejectionEvent.zig +++ b/src/browser/webapi/event/PromiseRejectionEvent.zig @@ -56,16 +56,14 @@ pub fn init(typ: []const u8, opts_: ?Options, page: *Page) !*PromiseRejectionEve return event; } -pub fn deinit(self: *PromiseRejectionEvent, shutdown: bool) void { - const proto = self._proto; - const js_ctx = proto._page.js; +pub fn deinit(self: *PromiseRejectionEvent, shutdown: bool, page: *Page) void { if (self._reason) |r| { - js_ctx.release(r); + page.js.release(r); } if (self._promise) |p| { - js_ctx.release(p); + page.js.release(p); } - proto.deinit(shutdown); + self._proto.deinit(shutdown, page); } pub fn asEvent(self: *PromiseRejectionEvent) *Event { diff --git a/src/browser/webapi/event/TextEvent.zig b/src/browser/webapi/event/TextEvent.zig index 65b16db8..54789c13 100644 --- a/src/browser/webapi/event/TextEvent.zig +++ b/src/browser/webapi/event/TextEvent.zig @@ -58,8 +58,8 @@ pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*TextEvent { return event; } -pub fn deinit(self: *TextEvent, shutdown: bool) void { - self._proto.deinit(shutdown); +pub fn deinit(self: *TextEvent, shutdown: bool, page: *Page) void { + self._proto.deinit(shutdown, page); } pub fn asEvent(self: *TextEvent) *Event { diff --git a/src/browser/webapi/event/UIEvent.zig b/src/browser/webapi/event/UIEvent.zig index b708dbd9..6d329221 100644 --- a/src/browser/webapi/event/UIEvent.zig +++ b/src/browser/webapi/event/UIEvent.zig @@ -69,8 +69,8 @@ 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 deinit(self: *UIEvent, shutdown: bool, page: *Page) void { + self._proto.deinit(shutdown, page); } pub fn as(self: *UIEvent, comptime T: type) *T { diff --git a/src/browser/webapi/event/WheelEvent.zig b/src/browser/webapi/event/WheelEvent.zig index f1aadba7..ee725941 100644 --- a/src/browser/webapi/event/WheelEvent.zig +++ b/src/browser/webapi/event/WheelEvent.zig @@ -86,8 +86,8 @@ pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*WheelEvent { return event; } -pub fn deinit(self: *WheelEvent, shutdown: bool) void { - self._proto.deinit(shutdown); +pub fn deinit(self: *WheelEvent, shutdown: bool, page: *Page) void { + self._proto.deinit(shutdown, page); } pub fn asEvent(self: *WheelEvent) *Event { diff --git a/src/browser/webapi/navigation/Navigation.zig b/src/browser/webapi/navigation/Navigation.zig index fb856aef..6facfee9 100644 --- a/src/browser/webapi/navigation/Navigation.zig +++ b/src/browser/webapi/navigation/Navigation.zig @@ -24,10 +24,11 @@ const URL = @import("../URL.zig"); const js = @import("../../js/js.zig"); const Page = @import("../../Page.zig"); -const IS_DEBUG = @import("builtin").mode == .Debug; - +const Event = @import("../Event.zig"); const EventTarget = @import("../EventTarget.zig"); +const IS_DEBUG = @import("builtin").mode == .Debug; + // https://developer.mozilla.org/en-US/docs/Web/API/Navigation const Navigation = @This(); @@ -203,15 +204,17 @@ pub fn pushEntry( try self._entries.append(arena, entry); self._index = index; - if (previous) |prev| { - if (should_dispatch) { - const event = try NavigationCurrentEntryChangeEvent.initTrusted( - .wrap("currententrychange"), - .{ .from = prev, .navigationType = @tagName(.push) }, - page, - ); - try self.dispatch(.{ .currententrychange = event }, page); - } + if (previous == null or should_dispatch == false) { + return entry; + } + + if (self._on_currententrychange) |cec| { + const event = (try NavigationCurrentEntryChangeEvent.initTrusted( + .wrap("currententrychange"), + .{ .from = previous.?, .navigationType = @tagName(.push) }, + page, + )).asEvent(); + try self.dispatch(cec, event, page); } return entry; @@ -243,13 +246,17 @@ pub fn replaceEntry( self._entries.items[self._index] = entry; - if (should_dispatch) { - const event = try NavigationCurrentEntryChangeEvent.initTrusted( + if (should_dispatch == false) { + return entry; + } + + if (self._on_currententrychange) |cec| { + const event = (try NavigationCurrentEntryChangeEvent.initTrusted( .wrap("currententrychange"), .{ .from = previous, .navigationType = @tagName(.replace) }, page, - ); - try self.dispatch(.{ .currententrychange = event }, page); + )).asEvent(); + try self.dispatch(cec, event, page); } return entry; @@ -335,13 +342,15 @@ pub fn navigateInner( }, } - // If we haven't navigated off, let us fire off an a currententrychange. - const event = try NavigationCurrentEntryChangeEvent.initTrusted( - .wrap("currententrychange"), - .{ .from = previous, .navigationType = @tagName(kind) }, - page, - ); - try self.dispatch(.{ .currententrychange = event }, page); + if (self._on_currententrychange) |cec| { + // If we haven't navigated off, let us fire off an a currententrychange. + const event = (try NavigationCurrentEntryChangeEvent.initTrusted( + .wrap("currententrychange"), + .{ .from = previous, .navigationType = @tagName(kind) }, + page, + )).asEvent(); + try self.dispatch(cec, event, page); + } _ = try committed.persist(); _ = try finished.persist(); @@ -420,35 +429,17 @@ pub fn updateCurrentEntry(self: *Navigation, options: UpdateCurrentEntryOptions, .value = options.state.toJson(arena) catch return error.DataClone, }; - const event = try NavigationCurrentEntryChangeEvent.initTrusted( - .wrap("currententrychange"), - .{ .from = previous, .navigationType = null }, - page, - ); - try self.dispatch(.{ .currententrychange = event }, page); + if (self._on_currententrychange) |cec| { + const event = (try NavigationCurrentEntryChangeEvent.initTrusted( + .wrap("currententrychange"), + .{ .from = previous, .navigationType = null }, + page, + )).asEvent(); + try self.dispatch(cec, event, page); + } } -const DispatchType = union(enum) { - currententrychange: *NavigationCurrentEntryChangeEvent, -}; - -pub fn dispatch(self: *Navigation, event_type: DispatchType, page: *Page) !void { - const event, const field = blk: { - break :blk switch (event_type) { - .currententrychange => |cec| .{ cec.asEvent(), "_on_currententrychange" }, - }; - }; - defer if (!event._v8_handoff) event.deinit(false); - - if (comptime IS_DEBUG) { - if (page.js.local == null) { - log.fatal(.bug, "null context scope", .{ .src = "Navigation.dispatch", .url = page.url }); - std.debug.assert(page.js.local != null); - } - } - - const func = @field(self, field) orelse return; - +pub fn dispatch(self: *Navigation, func: js.Function.Global, event: *Event, page: *Page) !void { var ls: js.Local.Scope = undefined; page.js.localScope(&ls); defer ls.deinit(); diff --git a/src/browser/webapi/net/Fetch.zig b/src/browser/webapi/net/Fetch.zig index 47fa8bc5..161e88c2 100644 --- a/src/browser/webapi/net/Fetch.zig +++ b/src/browser/webapi/net/Fetch.zig @@ -45,7 +45,7 @@ pub const InitOpts = Request.InitOpts; pub fn init(input: Input, options: ?InitOpts, page: *Page) !js.Promise { const request = try Request.init(input, options, page); const response = try Response.init(null, .{ .status = 0 }, page); - errdefer response.deinit(true); + errdefer response.deinit(true, page); const resolver = page.js.local.?.createPromiseResolver(); @@ -184,7 +184,7 @@ fn httpErrorCallback(ctx: *anyopaque, err: anyerror) void { // clear this. (defer since `self is in the response's arena). defer if (self._owns_response) { - response.deinit(err == error.Abort); + response.deinit(err == error.Abort, self._page); self._owns_response = false; }; @@ -205,7 +205,7 @@ fn httpShutdownCallback(ctx: *anyopaque) void { if (self._owns_response) { var response = self._response; response._transfer = null; - response.deinit(true); + response.deinit(true, self._page); // Do not access `self` after this point: the Fetch struct was // allocated from response._arena which has been released. } diff --git a/src/browser/webapi/net/Response.zig b/src/browser/webapi/net/Response.zig index d8c67e53..2884c825 100644 --- a/src/browser/webapi/net/Response.zig +++ b/src/browser/webapi/net/Response.zig @@ -36,7 +36,6 @@ pub const Type = enum { opaqueredirect, }; -_page: *Page, _status: u16, _arena: Allocator, _headers: *Headers, @@ -65,7 +64,6 @@ pub fn init(body_: ?[]const u8, opts_: ?InitOpts, page: *Page) !*Response { const self = try arena.create(Response); self.* = .{ - ._page = page, ._arena = arena, ._status = opts.status, ._status_text = status_text, @@ -78,7 +76,7 @@ pub fn init(body_: ?[]const u8, opts_: ?InitOpts, page: *Page) !*Response { return self; } -pub fn deinit(self: *Response, shutdown: bool) void { +pub fn deinit(self: *Response, shutdown: bool, page: *Page) void { if (self._transfer) |transfer| { if (shutdown) { transfer.terminate(); @@ -87,7 +85,7 @@ pub fn deinit(self: *Response, shutdown: bool) void { } self._transfer = null; } - self._page.releaseArena(self._arena); + page.releaseArena(self._arena); } pub fn getStatus(self: *const Response) u16 { diff --git a/src/browser/webapi/net/XMLHttpRequest.zig b/src/browser/webapi/net/XMLHttpRequest.zig index e39e8ce4..fa37ff42 100644 --- a/src/browser/webapi/net/XMLHttpRequest.zig +++ b/src/browser/webapi/net/XMLHttpRequest.zig @@ -92,7 +92,7 @@ pub fn init(page: *Page) !*XMLHttpRequest { }); } -pub fn deinit(self: *XMLHttpRequest, shutdown: bool) void { +pub fn deinit(self: *XMLHttpRequest, shutdown: bool, page: *Page) void { if (self._transfer) |transfer| { if (shutdown) { transfer.terminate(); @@ -102,7 +102,6 @@ pub fn deinit(self: *XMLHttpRequest, shutdown: bool) void { self._transfer = null; } - const page = self._page; const js_ctx = page.js; if (self._on_ready_state_change) |func| { js_ctx.release(func); @@ -182,9 +181,10 @@ pub fn open(self: *XMLHttpRequest, method_: []const u8, url: [:0]const u8) !void self._response_headers.clearRetainingCapacity(); self._request_body = null; + const page = self._page; self._method = try parseMethod(method_); - self._url = try URL.resolve(self._arena, self._page.base(), url, .{ .always_dupe = true }); - try self.stateChanged(.opened, self._page.js.local.?, self._page); + self._url = try URL.resolve(self._arena, page.base(), url, .{ .always_dupe = true }); + try self.stateChanged(.opened, page.js.local.?, page); } pub fn setRequestHeader(self: *XMLHttpRequest, name: []const u8, value: []const u8, page: *Page) !void { @@ -524,8 +524,6 @@ fn stateChanged(self: *XMLHttpRequest, state: ReadyState, local: *const js.Local self._ready_state = state; const event = try Event.initTrusted(.wrap("readystatechange"), .{}, page); - defer if (!event._v8_handoff) event.deinit(false); - try page._event_manager.dispatchWithFunction( self.asEventTarget(), event, diff --git a/src/browser/webapi/net/XMLHttpRequestEventTarget.zig b/src/browser/webapi/net/XMLHttpRequestEventTarget.zig index 355eddda..cb7be000 100644 --- a/src/browser/webapi/net/XMLHttpRequestEventTarget.zig +++ b/src/browser/webapi/net/XMLHttpRequestEventTarget.zig @@ -62,7 +62,6 @@ pub fn dispatch(self: *XMLHttpRequestEventTarget, comptime event_type: DispatchT .{ .total = progress.total, .loaded = progress.loaded }, page, )).asEvent(); - defer if (!event._v8_handoff) event.deinit(false); return page._event_manager.dispatchWithFunction( self.asEventTarget(), diff --git a/src/browser/webapi/storage/Cookie.zig b/src/browser/webapi/storage/Cookie.zig index 5e352bd4..da499efb 100644 --- a/src/browser/webapi/storage/Cookie.zig +++ b/src/browser/webapi/storage/Cookie.zig @@ -435,7 +435,7 @@ pub const Jar = struct { pub fn removeExpired(self: *Jar, request_time: ?i64) void { if (self.cookies.items.len == 0) return; const time = request_time orelse std.time.timestamp(); - var i: usize = self.cookies.items.len ; + var i: usize = self.cookies.items.len; while (i > 0) { i -= 1; const cookie = &self.cookies.items[i];