mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-03-28 07:33:16 +00:00
Merge pull request #1373 from lightpanda-io/explicit_globals
Some checks failed
e2e-test / zig build release (push) Has been cancelled
e2e-test / demo-scripts (push) Has been cancelled
e2e-test / cdp-and-hyperfine-bench (push) Has been cancelled
e2e-test / perf-fmt (push) Has been cancelled
e2e-test / browser fetch (push) Has been cancelled
zig-test / zig test (push) Has been cancelled
zig-test / perf-fmt (push) Has been cancelled
nightly build / build-linux-x86_64 (push) Has been cancelled
nightly build / build-linux-aarch64 (push) Has been cancelled
nightly build / build-macos-aarch64 (push) Has been cancelled
nightly build / build-macos-x86_64 (push) Has been cancelled
wpt / web platform tests json output (push) Has been cancelled
wpt / perf-fmt (push) Has been cancelled
e2e-integration-test / zig build release (push) Has been cancelled
e2e-integration-test / demo-integration-scripts (push) Has been cancelled
Some checks failed
e2e-test / zig build release (push) Has been cancelled
e2e-test / demo-scripts (push) Has been cancelled
e2e-test / cdp-and-hyperfine-bench (push) Has been cancelled
e2e-test / perf-fmt (push) Has been cancelled
e2e-test / browser fetch (push) Has been cancelled
zig-test / zig test (push) Has been cancelled
zig-test / perf-fmt (push) Has been cancelled
nightly build / build-linux-x86_64 (push) Has been cancelled
nightly build / build-linux-aarch64 (push) Has been cancelled
nightly build / build-macos-aarch64 (push) Has been cancelled
nightly build / build-macos-x86_64 (push) Has been cancelled
wpt / web platform tests json output (push) Has been cancelled
wpt / perf-fmt (push) Has been cancelled
e2e-integration-test / zig build release (push) Has been cancelled
e2e-integration-test / demo-integration-scripts (push) Has been cancelled
Explicit globals
This commit is contained in:
2
.github/actions/install/action.yml
vendored
2
.github/actions/install/action.yml
vendored
@@ -13,7 +13,7 @@ inputs:
|
||||
zig-v8:
|
||||
description: 'zig v8 version to install'
|
||||
required: false
|
||||
default: 'v0.2.3'
|
||||
default: 'v0.2.4'
|
||||
v8:
|
||||
description: 'v8 version to install'
|
||||
required: false
|
||||
|
||||
@@ -3,7 +3,7 @@ FROM debian:stable-slim
|
||||
ARG MINISIG=0.12
|
||||
ARG ZIG_MINISIG=RWSGOq2NVecA2UPNdBUZykf1CCb147pkmdtYxgb3Ti+JO/wCYvhbAb/U
|
||||
ARG V8=14.0.365.4
|
||||
ARG ZIG_V8=v0.2.3
|
||||
ARG ZIG_V8=v0.2.4
|
||||
ARG TARGETPLATFORM
|
||||
|
||||
RUN apt-get update -yq && \
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
.minimum_zig_version = "0.15.2",
|
||||
.dependencies = .{
|
||||
.v8 = .{
|
||||
.url = "https://github.com/lightpanda-io/zig-v8-fork/archive/5b0555e6b6154f957f9d7002ecb8005cc5a41b7a.tar.gz",
|
||||
.hash = "v8-0.0.0-xddH6xUqBABofwwIBsof3cD3c2FstBvm7_VzoughX1Km",
|
||||
.url = "https://github.com/lightpanda-io/zig-v8-fork/archive/v0.2.4.tar.gz",
|
||||
.hash = "v8-0.0.0-xddH66YvBAD0YI9xr6F0Xgnw9wN30FdZ10FLyuoV3e66",
|
||||
},
|
||||
//.v8 = .{ .path = "../zig-v8-fork" },
|
||||
// .v8 = .{ .path = "../zig-v8-fork" },
|
||||
.@"boringssl-zig" = .{
|
||||
.url = "git+https://github.com/Syndica/boringssl-zig.git#c53df00d06b02b755ad88bbf4d1202ed9687b096",
|
||||
.hash = "boringssl-0.1.0-VtJeWehMAAA4RNnwRnzEvKcS9rjsR1QVRw1uJrwXxmVK",
|
||||
|
||||
@@ -102,8 +102,8 @@ pub fn register(self: *EventManager, target: *EventTarget, typ: []const u8, call
|
||||
}
|
||||
|
||||
const func = switch (callback) {
|
||||
.function => |f| Function{ .value = f },
|
||||
.object => |o| Function{ .object = o },
|
||||
.function => |f| Function{ .value = try f.persist() },
|
||||
.object => |o| Function{ .object = try o.persist() },
|
||||
};
|
||||
|
||||
const listener = try self.listener_pool.create();
|
||||
@@ -368,12 +368,13 @@ fn dispatchPhase(self: *EventManager, list: *std.DoublyLinkedList, current_targe
|
||||
}
|
||||
|
||||
switch (listener.function) {
|
||||
.value => |value| try value.callWithThis(void, current_target, .{event}),
|
||||
.value => |value| try value.local().callWithThis(void, current_target, .{event}),
|
||||
.string => |string| {
|
||||
const str = try page.call_arena.dupeZ(u8, string.str());
|
||||
try self.page.js.eval(str, null);
|
||||
},
|
||||
.object => |obj| {
|
||||
.object => |*obj_global| {
|
||||
const obj = obj_global.local();
|
||||
if (try obj.getFunction("handleEvent")) |handleEvent| {
|
||||
try handleEvent.callWithThis(void, obj, .{event});
|
||||
}
|
||||
@@ -443,20 +444,20 @@ const Listener = struct {
|
||||
};
|
||||
|
||||
const Function = union(enum) {
|
||||
value: js.Function,
|
||||
value: js.Function.Global,
|
||||
string: String,
|
||||
object: js.Object,
|
||||
object: js.Object.Global,
|
||||
|
||||
fn eqlFunction(self: Function, func: js.Function) bool {
|
||||
return switch (self) {
|
||||
.value => |v| return v.id() == func.id(),
|
||||
.value => |v| v.isEqual(func),
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
|
||||
fn eqlObject(self: Function, obj: js.Object) bool {
|
||||
return switch (self) {
|
||||
.object => |o| return o.getId() == obj.getId(),
|
||||
.object => |o| return o.isEqual(obj),
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -562,18 +562,20 @@ fn _documentIsComplete(self: *Page) !void {
|
||||
// this event is weird, it's dispatched directly on the window, but
|
||||
// with the document as the target
|
||||
event._target = self.document.asEventTarget();
|
||||
const on_load = if (self.window._on_load) |*g| g.local() else null;
|
||||
try self._event_manager.dispatchWithFunction(
|
||||
self.window.asEventTarget(),
|
||||
event,
|
||||
self.window._on_load,
|
||||
on_load,
|
||||
.{ .inject_target = false, .context = "page load" },
|
||||
);
|
||||
|
||||
const pageshow_event = try PageTransitionEvent.initTrusted("pageshow", .{}, self);
|
||||
const on_pageshow = if (self.window._on_pageshow) |*g| g.local() else null;
|
||||
try self._event_manager.dispatchWithFunction(
|
||||
self.window.asEventTarget(),
|
||||
pageshow_event.asEvent(),
|
||||
self.window._on_pageshow,
|
||||
on_pageshow,
|
||||
.{ .context = "page show" },
|
||||
);
|
||||
}
|
||||
@@ -1997,7 +1999,7 @@ pub fn createElementNS(self: *Page, namespace: Element.Namespace, name: []const
|
||||
defer self._upgrading_element = prev_upgrading;
|
||||
|
||||
var caught: JS.TryCatch.Caught = undefined;
|
||||
_ = def.constructor.newInstance(&caught) catch |err| {
|
||||
_ = def.constructor.local().newInstance(&caught) catch |err| {
|
||||
log.warn(.js, "custom element constructor", .{ .name = name, .err = err, .caught = caught });
|
||||
return node;
|
||||
};
|
||||
|
||||
@@ -844,8 +844,9 @@ pub const Script = struct {
|
||||
self.executeCallback("error", script_element._on_error, page);
|
||||
}
|
||||
|
||||
fn executeCallback(self: *const Script, comptime typ: []const u8, cb_: ?js.Function, page: *Page) void {
|
||||
const cb = cb_ orelse return;
|
||||
fn executeCallback(self: *const Script, comptime typ: []const u8, cb_: ?js.Function.Global, page: *Page) void {
|
||||
const cb_global = cb_ orelse return;
|
||||
const cb = cb_global.local();
|
||||
|
||||
const Event = @import("webapi/Event.zig");
|
||||
const event = Event.initTrusted(typ, .{}, page) catch |err| {
|
||||
|
||||
@@ -77,12 +77,12 @@ identity_map: std.AutoHashMapUnmanaged(usize, js.Global(js.Object)) = .empty,
|
||||
// the @intFromPtr(js_obj.handle). But v8 can re-use address. Without
|
||||
// a reliable way to know if an object has already been persisted,
|
||||
// we now simply persist every time persist() is called.
|
||||
global_values: std.ArrayList(js.Global(js.Value)) = .empty,
|
||||
global_objects: std.ArrayList(js.Global(js.Object)) = .empty,
|
||||
global_modules: std.ArrayList(js.Global(js.Module)) = .empty,
|
||||
global_promises: std.ArrayList(js.Global(js.Promise)) = .empty,
|
||||
global_functions: std.ArrayList(js.Global(js.Function)) = .empty,
|
||||
global_promise_resolvers: std.ArrayList(js.Global(js.PromiseResolver)) = .empty,
|
||||
global_values: std.ArrayList(v8.Global) = .empty,
|
||||
global_objects: std.ArrayList(v8.Global) = .empty,
|
||||
global_modules: std.ArrayList(v8.Global) = .empty,
|
||||
global_promises: std.ArrayList(v8.Global) = .empty,
|
||||
global_functions: std.ArrayList(v8.Global) = .empty,
|
||||
global_promise_resolvers: std.ArrayList(v8.Global) = .empty,
|
||||
|
||||
// Our module cache: normalized module specifier => module.
|
||||
module_cache: std.StringHashMapUnmanaged(ModuleEntry) = .empty,
|
||||
@@ -100,19 +100,19 @@ script_manager: ?*ScriptManager,
|
||||
const ModuleEntry = struct {
|
||||
// Can be null if we're asynchrously loading the module, in
|
||||
// which case resolver_promise cannot be null.
|
||||
module: ?js.Module = null,
|
||||
module: ?js.Module.Global = null,
|
||||
|
||||
// The promise of the evaluating module. The resolved value is
|
||||
// meaningless to us, but the resolver promise needs to chain
|
||||
// to this, since we need to know when it's complete.
|
||||
module_promise: ?js.Promise = null,
|
||||
module_promise: ?js.Promise.Global = null,
|
||||
|
||||
// The promise for the resolver which is loading the module.
|
||||
// (AKA, the first time we try to load it). This resolver will
|
||||
// chain to the module_promise and, when it's done evaluating
|
||||
// will resolve its namespace. Any other attempt to load the
|
||||
// module willchain to this.
|
||||
resolver_promise: ?js.Promise = null,
|
||||
resolver_promise: ?js.Promise.Global = null,
|
||||
};
|
||||
|
||||
pub fn fromC(c_context: *const v8.Context) *Context {
|
||||
@@ -142,27 +142,27 @@ pub fn deinit(self: *Context) void {
|
||||
}
|
||||
|
||||
for (self.global_values.items) |*global| {
|
||||
global.deinit();
|
||||
v8.v8__Global__Reset(global);
|
||||
}
|
||||
|
||||
for (self.global_objects.items) |*global| {
|
||||
global.deinit();
|
||||
v8.v8__Global__Reset(global);
|
||||
}
|
||||
|
||||
for (self.global_modules.items) |*global| {
|
||||
global.deinit();
|
||||
v8.v8__Global__Reset(global);
|
||||
}
|
||||
|
||||
for (self.global_functions.items) |*global| {
|
||||
global.deinit();
|
||||
v8.v8__Global__Reset(global);
|
||||
}
|
||||
|
||||
for (self.global_promises.items) |*global| {
|
||||
global.deinit();
|
||||
v8.v8__Global__Reset(global);
|
||||
}
|
||||
|
||||
for (self.global_promise_resolvers.items) |*global| {
|
||||
global.deinit();
|
||||
v8.v8__Global__Reset(global);
|
||||
}
|
||||
|
||||
if (self.handle_scope) |*scope| {
|
||||
@@ -452,11 +452,41 @@ pub fn zigValueToJs(self: *Context, value: anytype, comptime opts: Caller.CallOp
|
||||
return .{ .ctx = self, .handle = @ptrCast(value.handle) };
|
||||
}
|
||||
|
||||
if (T == js.Function.Global) {
|
||||
// Auto-convert Global to local for bridge
|
||||
return .{ .ctx = self, .handle = @ptrCast(value.local().handle) };
|
||||
}
|
||||
|
||||
if (T == js.Object) {
|
||||
// we're returning a v8.Object
|
||||
return .{ .ctx = self, .handle = @ptrCast(value.handle) };
|
||||
}
|
||||
|
||||
if (T == js.Object.Global) {
|
||||
// Auto-convert Global to local for bridge
|
||||
return .{ .ctx = self, .handle = @ptrCast(value.local().handle) };
|
||||
}
|
||||
|
||||
if (T == js.Value.Global) {
|
||||
// Auto-convert Global to local for bridge
|
||||
return .{ .ctx = self, .handle = @ptrCast(value.local().handle) };
|
||||
}
|
||||
|
||||
if (T == js.Promise.Global) {
|
||||
// Auto-convert Global to local for bridge
|
||||
return .{ .ctx = self, .handle = @ptrCast(value.local().handle) };
|
||||
}
|
||||
|
||||
if (T == js.PromiseResolver.Global) {
|
||||
// Auto-convert Global to local for bridge
|
||||
return .{ .ctx = self, .handle = @ptrCast(value.local().handle) };
|
||||
}
|
||||
|
||||
if (T == js.Module.Global) {
|
||||
// Auto-convert Global to local for bridge
|
||||
return .{ .ctx = self, .handle = @ptrCast(value.local().handle) };
|
||||
}
|
||||
|
||||
if (T == js.Value) {
|
||||
return value;
|
||||
}
|
||||
@@ -778,6 +808,13 @@ fn jsValueToStruct(self: *Context, comptime T: type, js_value: js.Value) !?T {
|
||||
}
|
||||
return try self.newFunction(js_value);
|
||||
},
|
||||
js.Function.Global => {
|
||||
if (!js_value.isFunction()) {
|
||||
return null;
|
||||
}
|
||||
const func = try self.newFunction(js_value);
|
||||
return try func.persist();
|
||||
},
|
||||
// zig fmt: off
|
||||
js.TypedArray(u8), js.TypedArray(u16), js.TypedArray(u32), js.TypedArray(u64),
|
||||
js.TypedArray(i8), js.TypedArray(i16), js.TypedArray(i32), js.TypedArray(i64),
|
||||
@@ -806,6 +843,29 @@ fn jsValueToStruct(self: *Context, comptime T: type, js_value: js.Value) !?T {
|
||||
.handle = @ptrCast(js_value.handle),
|
||||
};
|
||||
},
|
||||
js.Object.Global => {
|
||||
if (!js_value.isObject()) {
|
||||
return null;
|
||||
}
|
||||
const obj = js.Object{
|
||||
.ctx = self,
|
||||
.handle = @ptrCast(js_value.handle),
|
||||
};
|
||||
return try obj.persist();
|
||||
},
|
||||
js.Value.Global => {
|
||||
return try js_value.persist();
|
||||
},
|
||||
js.Promise.Global => {
|
||||
if (!js_value.isPromise()) {
|
||||
return null;
|
||||
}
|
||||
const promise = js.Promise{
|
||||
.ctx = self,
|
||||
.handle = @ptrCast(js_value.handle),
|
||||
};
|
||||
return try promise.persist();
|
||||
},
|
||||
else => {
|
||||
if (!js_value.isObject()) {
|
||||
return null;
|
||||
@@ -1251,7 +1311,7 @@ fn _resolveModuleCallback(self: *Context, referrer: js.Module, specifier: [:0]co
|
||||
|
||||
const entry = self.module_cache.getPtr(normalized_specifier).?;
|
||||
if (entry.module) |m| {
|
||||
return m.handle;
|
||||
return m.local().handle;
|
||||
}
|
||||
|
||||
var source = try self.script_manager.?.waitForImport(normalized_specifier);
|
||||
@@ -1264,7 +1324,7 @@ fn _resolveModuleCallback(self: *Context, referrer: js.Module, specifier: [:0]co
|
||||
const mod = try self.compileModule(source.src(), normalized_specifier);
|
||||
try self.postCompileModule(mod, normalized_specifier);
|
||||
entry.module = try mod.persist();
|
||||
return entry.module.?.handle;
|
||||
return entry.module.?.local().handle;
|
||||
}
|
||||
|
||||
// Will get passed to ScriptManager and then passed back to us when
|
||||
@@ -1272,11 +1332,11 @@ fn _resolveModuleCallback(self: *Context, referrer: js.Module, specifier: [:0]co
|
||||
const DynamicModuleResolveState = struct {
|
||||
// The module that we're resolving (we'll actually resolve its
|
||||
// namespace)
|
||||
module: ?js.Module,
|
||||
module: ?js.Module.Global,
|
||||
context_id: usize,
|
||||
context: *Context,
|
||||
specifier: [:0]const u8,
|
||||
resolver: js.PromiseResolver,
|
||||
resolver: js.PromiseResolver.Global,
|
||||
};
|
||||
|
||||
fn _dynamicModuleCallback(self: *Context, specifier: [:0]const u8, referrer: []const u8) !js.Promise {
|
||||
@@ -1285,7 +1345,7 @@ fn _dynamicModuleCallback(self: *Context, specifier: [:0]const u8, referrer: []c
|
||||
// This is easy, there's already something responsible
|
||||
// for loading the module. Maybe it's still loading, maybe
|
||||
// it's complete. Whatever, we can just return that promise.
|
||||
return gop.value_ptr.resolver_promise.?;
|
||||
return gop.value_ptr.resolver_promise.?.local();
|
||||
}
|
||||
|
||||
const resolver = try self.createPromiseResolver().persist();
|
||||
@@ -1299,7 +1359,7 @@ fn _dynamicModuleCallback(self: *Context, specifier: [:0]const u8, referrer: []c
|
||||
.resolver = resolver,
|
||||
};
|
||||
|
||||
const promise = try resolver.promise().persist();
|
||||
const promise = try resolver.local().promise().persist();
|
||||
|
||||
if (!gop.found_existing) {
|
||||
// this module hasn't been seen before. This is the most
|
||||
@@ -1317,13 +1377,13 @@ fn _dynamicModuleCallback(self: *Context, specifier: [:0]const u8, referrer: []c
|
||||
// Next, we need to actually load it.
|
||||
self.script_manager.?.getAsyncImport(specifier, dynamicModuleSourceCallback, state, referrer) catch |err| {
|
||||
const error_msg = self.newString(@errorName(err));
|
||||
_ = resolver.reject("dynamic module get async", error_msg);
|
||||
_ = resolver.local().reject("dynamic module get async", error_msg);
|
||||
};
|
||||
|
||||
// For now, we're done. but this will be continued in
|
||||
// `dynamicModuleSourceCallback`, once the source for the
|
||||
// moduel is loaded.
|
||||
return promise;
|
||||
return promise.local();
|
||||
}
|
||||
|
||||
// So we have a module, but no async resolver. This can only
|
||||
@@ -1339,20 +1399,21 @@ fn _dynamicModuleCallback(self: *Context, specifier: [:0]const u8, referrer: []c
|
||||
// If the module hasn't been evaluated yet (it was only instantiated
|
||||
// as a static import dependency), we need to evaluate it now.
|
||||
if (gop.value_ptr.module_promise == null) {
|
||||
const mod = gop.value_ptr.module.?;
|
||||
const mod_global = gop.value_ptr.module.?;
|
||||
const mod = mod_global.local();
|
||||
const status = mod.getStatus();
|
||||
if (status == .kEvaluated or status == .kEvaluating) {
|
||||
// Module was already evaluated (shouldn't normally happen, but handle it).
|
||||
// Create a pre-resolved promise with the module namespace.
|
||||
const module_resolver = try self.createPromiseResolver().persist();
|
||||
_ = module_resolver.resolve("resolve module", mod.getModuleNamespace());
|
||||
gop.value_ptr.module_promise = try module_resolver.promise().persist();
|
||||
_ = module_resolver.local().resolve("resolve module", mod.getModuleNamespace());
|
||||
gop.value_ptr.module_promise = try module_resolver.local().promise().persist();
|
||||
} else {
|
||||
// the module was loaded, but not evaluated, we _have_ to evaluate it now
|
||||
const evaluated = mod.evaluate() catch {
|
||||
std.debug.assert(status == .kErrored);
|
||||
_ = resolver.reject("module evaluation", self.newString("Module evaluation failed"));
|
||||
return promise;
|
||||
_ = resolver.local().reject("module evaluation", self.newString("Module evaluation failed"));
|
||||
return promise.local();
|
||||
};
|
||||
std.debug.assert(evaluated.isPromise());
|
||||
gop.value_ptr.module_promise = try evaluated.toPromise().persist();
|
||||
@@ -1367,7 +1428,7 @@ fn _dynamicModuleCallback(self: *Context, specifier: [:0]const u8, referrer: []c
|
||||
// But we can skip direclty to `resolveDynamicModule` which is
|
||||
// what the above callback will eventually do.
|
||||
self.resolveDynamicModule(state, gop.value_ptr.*);
|
||||
return promise;
|
||||
return promise.local();
|
||||
}
|
||||
|
||||
fn dynamicModuleSourceCallback(ctx: *anyopaque, module_source_: anyerror!ScriptManager.ModuleSource) void {
|
||||
@@ -1375,7 +1436,7 @@ fn dynamicModuleSourceCallback(ctx: *anyopaque, module_source_: anyerror!ScriptM
|
||||
var self = state.context;
|
||||
|
||||
var ms = module_source_ catch |err| {
|
||||
_ = state.resolver.reject("dynamic module source", self.newString(@errorName(err)));
|
||||
_ = state.resolver.local().reject("dynamic module source", self.newString(@errorName(err)));
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -1392,7 +1453,7 @@ fn dynamicModuleSourceCallback(ctx: *anyopaque, module_source_: anyerror!ScriptM
|
||||
.caught = caught,
|
||||
.specifier = state.specifier,
|
||||
});
|
||||
_ = state.resolver.reject("dynamic compilation failure", self.newString(caught.exception orelse ""));
|
||||
_ = state.resolver.local().reject("dynamic compilation failure", self.newString(caught.exception orelse ""));
|
||||
return;
|
||||
};
|
||||
};
|
||||
@@ -1436,8 +1497,8 @@ fn resolveDynamicModule(self: *Context, state: *DynamicModuleResolveState, modul
|
||||
}
|
||||
|
||||
defer caller.context.runMicrotasks();
|
||||
const namespace = s.module.?.getModuleNamespace();
|
||||
_ = s.resolver.resolve("resolve namespace", namespace);
|
||||
const namespace = s.module.?.local().getModuleNamespace();
|
||||
_ = s.resolver.local().resolve("resolve namespace", namespace);
|
||||
}
|
||||
}.callback, @ptrCast(state));
|
||||
|
||||
@@ -1456,19 +1517,19 @@ fn resolveDynamicModule(self: *Context, state: *DynamicModuleResolveState, modul
|
||||
}
|
||||
|
||||
defer ctx.runMicrotasks();
|
||||
_ = s.resolver.reject("catch callback", js.Value{
|
||||
_ = s.resolver.local().reject("catch callback", js.Value{
|
||||
.ctx = ctx,
|
||||
.handle = v8.v8__FunctionCallbackInfo__Data(callback_handle).?,
|
||||
});
|
||||
}
|
||||
}.callback, @ptrCast(state));
|
||||
|
||||
_ = module_entry.module_promise.?.thenAndCatch(then_callback, catch_callback) catch |err| {
|
||||
_ = module_entry.module_promise.?.local().thenAndCatch(then_callback, catch_callback) catch |err| {
|
||||
log.err(.js, "module evaluation is promise", .{
|
||||
.err = err,
|
||||
.specifier = state.specifier,
|
||||
});
|
||||
_ = state.resolver.reject("module promise", self.newString("Failed to evaluate promise"));
|
||||
_ = state.resolver.local().reject("module promise", self.newString("Failed to evaluate promise"));
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -33,10 +33,6 @@ pub const Result = struct {
|
||||
exception: []const u8,
|
||||
};
|
||||
|
||||
pub fn id(self: *const Function) u32 {
|
||||
return @as(u32, @bitCast(v8.v8__Object__GetIdentityHash(@ptrCast(self.handle))));
|
||||
}
|
||||
|
||||
pub fn withThis(self: *const Function, value: anytype) !Function {
|
||||
const this_obj = if (@TypeOf(value) == js.Object)
|
||||
value.handle
|
||||
@@ -172,20 +168,41 @@ pub fn getPropertyValue(self: *const Function, name: []const u8) !?js.Value {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn persist(self: *const Function) !Function {
|
||||
pub fn persist(self: *const Function) !Global {
|
||||
var ctx = self.ctx;
|
||||
|
||||
const global = js.Global(Function).init(ctx.isolate.handle, self.handle);
|
||||
var global: v8.Global = undefined;
|
||||
v8.v8__Global__New(ctx.isolate.handle, self.handle, &global);
|
||||
|
||||
try ctx.global_functions.append(ctx.arena, global);
|
||||
|
||||
return .{
|
||||
.handle = global,
|
||||
.ctx = ctx,
|
||||
.this = self.this,
|
||||
.handle = global.local(),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn persistWithThis(self: *const Function, value: anytype) !Function {
|
||||
var persisted = try self.persist();
|
||||
return persisted.withThis(value);
|
||||
pub fn persistWithThis(self: *const Function, value: anytype) !Global {
|
||||
const with_this = try self.withThis(value);
|
||||
return with_this.persist();
|
||||
}
|
||||
|
||||
pub const Global = struct {
|
||||
handle: v8.Global,
|
||||
ctx: *js.Context,
|
||||
|
||||
pub fn deinit(self: *Global) void {
|
||||
v8.v8__Global__Reset(&self.handle);
|
||||
}
|
||||
|
||||
pub fn local(self: *const Global) Function {
|
||||
return .{
|
||||
.ctx = self.ctx,
|
||||
.handle = @ptrCast(v8.v8__Global__Get(&self.handle, self.ctx.isolate.handle)),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn isEqual(self: *const Global, other: Function) bool {
|
||||
return v8.v8__Global__IsEqual(&self.handle, other.handle);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -89,18 +89,37 @@ pub fn getScriptId(self: Module) u32 {
|
||||
return @intCast(v8.v8__Module__ScriptId(self.handle));
|
||||
}
|
||||
|
||||
pub fn persist(self: Module) !Module {
|
||||
pub fn persist(self: Module) !Global {
|
||||
var ctx = self.ctx;
|
||||
|
||||
const global = js.Global(Module).init(ctx.isolate.handle, self.handle);
|
||||
var global: v8.Global = undefined;
|
||||
v8.v8__Global__New(ctx.isolate.handle, self.handle, &global);
|
||||
try ctx.global_modules.append(ctx.arena, global);
|
||||
|
||||
return .{
|
||||
.handle = global,
|
||||
.ctx = ctx,
|
||||
.handle = global.local(),
|
||||
};
|
||||
}
|
||||
|
||||
pub const Global = struct {
|
||||
handle: v8.Global,
|
||||
ctx: *js.Context,
|
||||
|
||||
pub fn deinit(self: *Global) void {
|
||||
v8.v8__Global__Reset(&self.handle);
|
||||
}
|
||||
|
||||
pub fn local(self: *const Global) Module {
|
||||
return .{
|
||||
.ctx = self.ctx,
|
||||
.handle = @ptrCast(v8.v8__Global__Get(&self.handle, self.ctx.isolate.handle)),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn isEqual(self: *const Global, other: Module) bool {
|
||||
return v8.v8__Global__IsEqual(&self.handle, other.handle);
|
||||
}
|
||||
};
|
||||
|
||||
const Requests = struct {
|
||||
ctx: *const v8.Context,
|
||||
handle: *const v8.FixedArray,
|
||||
|
||||
@@ -103,15 +103,17 @@ pub fn format(self: Object, writer: *std.Io.Writer) !void {
|
||||
return writer.writeAll(str);
|
||||
}
|
||||
|
||||
pub fn persist(self: Object) !Object {
|
||||
pub fn persist(self: Object) !Global {
|
||||
var ctx = self.ctx;
|
||||
|
||||
const global = js.Global(Object).init(ctx.isolate.handle, self.handle);
|
||||
var global: v8.Global = undefined;
|
||||
v8.v8__Global__New(ctx.isolate.handle, self.handle, &global);
|
||||
|
||||
try ctx.global_objects.append(ctx.arena, global);
|
||||
|
||||
return .{
|
||||
.handle = global,
|
||||
.ctx = ctx,
|
||||
.handle = global.local(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -176,6 +178,26 @@ pub fn toZig(self: Object, comptime T: type) !T {
|
||||
return self.ctx.jsValueToZig(T, js_value);
|
||||
}
|
||||
|
||||
pub const Global = struct {
|
||||
handle: v8.Global,
|
||||
ctx: *js.Context,
|
||||
|
||||
pub fn deinit(self: *Global) void {
|
||||
v8.v8__Global__Reset(&self.handle);
|
||||
}
|
||||
|
||||
pub fn local(self: *const Global) Object {
|
||||
return .{
|
||||
.ctx = self.ctx,
|
||||
.handle = @ptrCast(v8.v8__Global__Get(&self.handle, self.ctx.isolate.handle)),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn isEqual(self: *const Global, other: Object) bool {
|
||||
return v8.v8__Global__IsEqual(&self.handle, other.handle);
|
||||
}
|
||||
};
|
||||
|
||||
pub const NameIterator = struct {
|
||||
count: u32,
|
||||
idx: u32 = 0,
|
||||
|
||||
@@ -47,14 +47,37 @@ pub fn thenAndCatch(self: Promise, on_fulfilled: js.Function, on_rejected: js.Fu
|
||||
}
|
||||
return error.PromiseChainFailed;
|
||||
}
|
||||
pub fn persist(self: Promise) !Promise {
|
||||
pub fn persist(self: Promise) !Global {
|
||||
var ctx = self.ctx;
|
||||
|
||||
const global = js.Global(Promise).init(ctx.isolate.handle, self.handle);
|
||||
var global: v8.Global = undefined;
|
||||
v8.v8__Global__New(ctx.isolate.handle, self.handle, &global);
|
||||
try ctx.global_promises.append(ctx.arena, global);
|
||||
|
||||
return .{
|
||||
.handle = global,
|
||||
.ctx = ctx,
|
||||
.handle = global.local(),
|
||||
};
|
||||
}
|
||||
|
||||
pub const Global = struct {
|
||||
handle: v8.Global,
|
||||
ctx: *js.Context,
|
||||
|
||||
pub fn deinit(self: *Global) void {
|
||||
v8.v8__Global__Reset(&self.handle);
|
||||
}
|
||||
|
||||
pub fn local(self: *const Global) Promise {
|
||||
return .{
|
||||
.ctx = self.ctx,
|
||||
.handle = @ptrCast(v8.v8__Global__Get(&self.handle, self.ctx.isolate.handle)),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn isEqual(self: *const Global, other: Promise) bool {
|
||||
return v8.v8__Global__IsEqual(&self.handle, other.handle);
|
||||
}
|
||||
|
||||
pub fn promise(self: *const Global) Promise {
|
||||
return self.local();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -75,14 +75,33 @@ fn _reject(self: PromiseResolver, value: anytype) !void {
|
||||
ctx.runMicrotasks();
|
||||
}
|
||||
|
||||
pub fn persist(self: PromiseResolver) !PromiseResolver {
|
||||
pub fn persist(self: PromiseResolver) !Global {
|
||||
var ctx = self.ctx;
|
||||
|
||||
const global = js.Global(PromiseResolver).init(ctx.isolate.handle, self.handle);
|
||||
var global: v8.Global = undefined;
|
||||
v8.v8__Global__New(ctx.isolate.handle, self.handle, &global);
|
||||
try ctx.global_promise_resolvers.append(ctx.arena, global);
|
||||
|
||||
return .{
|
||||
.handle = global,
|
||||
.ctx = ctx,
|
||||
.handle = global.local(),
|
||||
};
|
||||
}
|
||||
|
||||
pub const Global = struct {
|
||||
handle: v8.Global,
|
||||
ctx: *js.Context,
|
||||
|
||||
pub fn deinit(self: *Global) void {
|
||||
v8.v8__Global__Reset(&self.handle);
|
||||
}
|
||||
|
||||
pub fn local(self: *const Global) PromiseResolver {
|
||||
return .{
|
||||
.ctx = self.ctx,
|
||||
.handle = @ptrCast(v8.v8__Global__Get(&self.handle, self.ctx.isolate.handle)),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn isEqual(self: *const Global, other: PromiseResolver) bool {
|
||||
return v8.v8__Global__IsEqual(&self.handle, other.handle);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -243,15 +243,17 @@ pub fn fromJson(ctx: *js.Context, json: []const u8) !Value {
|
||||
return .{ .ctx = ctx, .handle = value.handle };
|
||||
}
|
||||
|
||||
pub fn persist(self: Value) !Value {
|
||||
pub fn persist(self: Value) !Global {
|
||||
var ctx = self.ctx;
|
||||
|
||||
const global = js.Global(Value).init(ctx.isolate.handle, self.handle);
|
||||
var global: v8.Global = undefined;
|
||||
v8.v8__Global__New(ctx.isolate.handle, self.handle, &global);
|
||||
|
||||
try ctx.global_values.append(ctx.arena, global);
|
||||
|
||||
return .{
|
||||
.handle = global,
|
||||
.ctx = ctx,
|
||||
.handle = global.local(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -298,3 +300,23 @@ pub fn format(self: Value, writer: *std.Io.Writer) !void {
|
||||
const str = self.toString(.{}) catch return error.WriteFailed;
|
||||
return writer.writeAll(str);
|
||||
}
|
||||
|
||||
pub const Global = struct {
|
||||
handle: v8.Global,
|
||||
ctx: *js.Context,
|
||||
|
||||
pub fn deinit(self: *Global) void {
|
||||
v8.v8__Global__Reset(&self.handle);
|
||||
}
|
||||
|
||||
pub fn local(self: *const Global) Value {
|
||||
return .{
|
||||
.ctx = self.ctx,
|
||||
.handle = @ptrCast(v8.v8__Global__Get(&self.handle, self.ctx.isolate.handle)),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn isEqual(self: *const Global, other: Value) bool {
|
||||
return v8.v8__Global__IsEqual(&self.handle, other.handle);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -37,8 +37,8 @@ pub fn getSignal(self: *const AbortController) *AbortSignal {
|
||||
return self._signal;
|
||||
}
|
||||
|
||||
pub fn abort(self: *AbortController, reason_: ?js.Object, page: *Page) !void {
|
||||
try self._signal.abort(if (reason_) |r| .{ .js_obj = r } else null, page);
|
||||
pub fn abort(self: *AbortController, reason_: ?js.Value.Global, page: *Page) !void {
|
||||
try self._signal.abort(if (reason_) |r| .{ .js_val = r } else null, page);
|
||||
}
|
||||
|
||||
pub const JsApi = struct {
|
||||
|
||||
@@ -29,7 +29,7 @@ const AbortSignal = @This();
|
||||
_proto: *EventTarget,
|
||||
_aborted: bool = false,
|
||||
_reason: Reason = .undefined,
|
||||
_on_abort: ?js.Function = null,
|
||||
_on_abort: ?js.Function.Global = null,
|
||||
|
||||
pub fn init(page: *Page) !*AbortSignal {
|
||||
return page._factory.eventTarget(AbortSignal{
|
||||
@@ -45,16 +45,12 @@ pub fn getReason(self: *const AbortSignal) Reason {
|
||||
return self._reason;
|
||||
}
|
||||
|
||||
pub fn getOnAbort(self: *const AbortSignal) ?js.Function {
|
||||
pub fn getOnAbort(self: *const AbortSignal) ?js.Function.Global {
|
||||
return self._on_abort;
|
||||
}
|
||||
|
||||
pub fn setOnAbort(self: *AbortSignal, cb_: ?js.Function) !void {
|
||||
if (cb_) |cb| {
|
||||
self._on_abort = try cb.persistWithThis(self);
|
||||
} else {
|
||||
self._on_abort = null;
|
||||
}
|
||||
pub fn setOnAbort(self: *AbortSignal, cb: ?js.Function.Global) !void {
|
||||
self._on_abort = cb;
|
||||
}
|
||||
|
||||
pub fn asEventTarget(self: *AbortSignal) *EventTarget {
|
||||
@@ -71,7 +67,7 @@ pub fn abort(self: *AbortSignal, reason_: ?Reason, page: *Page) !void {
|
||||
// Store the abort reason (default to a simple string if none provided)
|
||||
if (reason_) |reason| {
|
||||
switch (reason) {
|
||||
.js_obj => |js_obj| self._reason = .{ .js_obj = try js_obj.persist() },
|
||||
.js_val => |js_val| self._reason = .{ .js_val = js_val },
|
||||
.string => |str| self._reason = .{ .string = try page.dupeString(str) },
|
||||
.undefined => self._reason = reason,
|
||||
}
|
||||
@@ -81,18 +77,19 @@ pub fn abort(self: *AbortSignal, reason_: ?Reason, page: *Page) !void {
|
||||
|
||||
// Dispatch abort event
|
||||
const event = try Event.initTrusted("abort", .{}, page);
|
||||
const func = if (self._on_abort) |*g| g.local() else null;
|
||||
try page._event_manager.dispatchWithFunction(
|
||||
self.asEventTarget(),
|
||||
event,
|
||||
self._on_abort,
|
||||
func,
|
||||
.{ .context = "abort signal" },
|
||||
);
|
||||
}
|
||||
|
||||
// Static method to create an already-aborted signal
|
||||
pub fn createAborted(reason_: ?js.Object, page: *Page) !*AbortSignal {
|
||||
pub fn createAborted(reason_: ?js.Value.Global, page: *Page) !*AbortSignal {
|
||||
const signal = try init(page);
|
||||
try signal.abort(if (reason_) |r| .{ .js_obj = r } else null, page);
|
||||
try signal.abort(if (reason_) |r| .{ .js_val = r } else null, page);
|
||||
return signal;
|
||||
}
|
||||
|
||||
@@ -118,7 +115,7 @@ pub fn throwIfAborted(self: *const AbortSignal, page: *Page) !ThrowIfAborted {
|
||||
if (self._aborted) {
|
||||
const exception = switch (self._reason) {
|
||||
.string => |str| page.js.throw(str),
|
||||
.js_obj => |js_obj| page.js.throw(try js_obj.toString()),
|
||||
.js_val => |js_val| page.js.throw(try js_val.local().toString(.{ .allocator = page.call_arena })),
|
||||
.undefined => page.js.throw("AbortError"),
|
||||
};
|
||||
return .{ .exception = exception };
|
||||
@@ -127,7 +124,7 @@ pub fn throwIfAborted(self: *const AbortSignal, page: *Page) !ThrowIfAborted {
|
||||
}
|
||||
|
||||
const Reason = union(enum) {
|
||||
js_obj: js.Object,
|
||||
js_val: js.Value.Global,
|
||||
string: []const u8,
|
||||
undefined: void,
|
||||
};
|
||||
|
||||
@@ -24,7 +24,7 @@ const Element = @import("Element.zig");
|
||||
const CustomElementDefinition = @This();
|
||||
|
||||
name: []const u8,
|
||||
constructor: js.Function,
|
||||
constructor: js.Function.Global,
|
||||
observed_attributes: std.StringHashMapUnmanaged(void) = .{},
|
||||
// For customized built-in elements, this is the element tag they extend (e.g., .button)
|
||||
// For autonomous custom elements, this is null
|
||||
|
||||
@@ -30,7 +30,7 @@ const CustomElementDefinition = @import("CustomElementDefinition.zig");
|
||||
const CustomElementRegistry = @This();
|
||||
|
||||
_definitions: std.StringHashMapUnmanaged(*CustomElementDefinition) = .{},
|
||||
_when_defined: std.StringHashMapUnmanaged(js.PromiseResolver) = .{},
|
||||
_when_defined: std.StringHashMapUnmanaged(js.PromiseResolver.Global) = .{},
|
||||
|
||||
const DefineOptions = struct {
|
||||
extends: ?[]const u8 = null,
|
||||
@@ -106,11 +106,11 @@ pub fn define(self: *CustomElementRegistry, name: []const u8, constructor: js.Fu
|
||||
}
|
||||
|
||||
if (self._when_defined.fetchRemove(name)) |entry| {
|
||||
entry.value.resolve("whenDefined", constructor);
|
||||
entry.value.local().resolve("whenDefined", constructor);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(self: *CustomElementRegistry, name: []const u8) ?js.Function {
|
||||
pub fn get(self: *CustomElementRegistry, name: []const u8) ?js.Function.Global {
|
||||
const definition = self._definitions.get(name) orelse return null;
|
||||
return definition.constructor;
|
||||
}
|
||||
@@ -126,7 +126,7 @@ pub fn whenDefined(self: *CustomElementRegistry, name: []const u8, page: *Page)
|
||||
|
||||
const gop = try self._when_defined.getOrPut(page.arena, name);
|
||||
if (gop.found_existing) {
|
||||
return gop.value_ptr.promise();
|
||||
return gop.value_ptr.local().promise();
|
||||
}
|
||||
errdefer _ = self._when_defined.remove(name);
|
||||
const owned_name = try page.dupeString(name);
|
||||
@@ -135,7 +135,7 @@ pub fn whenDefined(self: *CustomElementRegistry, name: []const u8, page: *Page)
|
||||
gop.key_ptr.* = owned_name;
|
||||
gop.value_ptr.* = resolver;
|
||||
|
||||
return resolver.promise();
|
||||
return resolver.local().promise();
|
||||
}
|
||||
|
||||
fn upgradeNode(self: *CustomElementRegistry, node: *Node, page: *Page) !void {
|
||||
@@ -175,7 +175,7 @@ pub fn upgradeCustomElement(custom: *Custom, definition: *CustomElementDefinitio
|
||||
defer page._upgrading_element = prev_upgrading;
|
||||
|
||||
var caught: js.TryCatch.Caught = undefined;
|
||||
_ = definition.constructor.newInstance(&caught) catch |err| {
|
||||
_ = definition.constructor.local().newInstance(&caught) catch |err| {
|
||||
log.warn(.js, "custom element upgrade", .{ .name = definition.name, .err = err, .caught = caught });
|
||||
return error.CustomElementUpgradeFailed;
|
||||
};
|
||||
|
||||
@@ -54,7 +54,7 @@ _active_element: ?*Element = null,
|
||||
_style_sheets: ?*StyleSheetList = null,
|
||||
_write_insertion_point: ?*Node = null,
|
||||
_script_created_parser: ?Parser.Streaming = null,
|
||||
_adopted_style_sheets: ?js.Object = null,
|
||||
_adopted_style_sheets: ?js.Object.Global = null,
|
||||
|
||||
pub const Type = union(enum) {
|
||||
generic,
|
||||
@@ -766,7 +766,7 @@ pub fn getChildElementCount(self: *Document) u32 {
|
||||
return i;
|
||||
}
|
||||
|
||||
pub fn getAdoptedStyleSheets(self: *Document, page: *Page) !js.Object {
|
||||
pub fn getAdoptedStyleSheets(self: *Document, page: *Page) !js.Object.Global {
|
||||
if (self._adopted_style_sheets) |ass| {
|
||||
return ass;
|
||||
}
|
||||
|
||||
@@ -72,8 +72,8 @@ pub fn addEventListener(self: *EventTarget, typ: []const u8, callback_: ?EventLi
|
||||
const callback = callback_ orelse return;
|
||||
|
||||
const em_callback = switch (callback) {
|
||||
.object => |obj| EventManager.Callback{ .object = try obj.persist() },
|
||||
.function => |func| EventManager.Callback{ .function = try func.persist() },
|
||||
.object => |obj| EventManager.Callback{ .object = obj },
|
||||
.function => |func| EventManager.Callback{ .function = func },
|
||||
};
|
||||
|
||||
const options = blk: {
|
||||
@@ -106,7 +106,7 @@ pub fn removeEventListener(self: *EventTarget, typ: []const u8, callback_: ?Even
|
||||
|
||||
const em_callback = switch (callback) {
|
||||
.function => |func| EventManager.Callback{ .function = func },
|
||||
.object => |obj| EventManager.Callback{ .object = try obj.persist() },
|
||||
.object => |obj| EventManager.Callback{ .object = obj },
|
||||
};
|
||||
|
||||
const use_capture = blk: {
|
||||
|
||||
@@ -81,10 +81,11 @@ fn goInner(delta: i32, page: *Page) !void {
|
||||
if (try page.isSameOrigin(url)) {
|
||||
const event = try PopStateEvent.initTrusted("popstate", .{ .state = entry._state.value }, page);
|
||||
|
||||
const func = if (page.window._on_popstate) |*g| g.local() else null;
|
||||
try page._event_manager.dispatchWithFunction(
|
||||
page.window.asEventTarget(),
|
||||
event.asEvent(),
|
||||
page.window._on_popstate,
|
||||
func,
|
||||
.{ .context = "Pop State" },
|
||||
);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ pub fn registerTypes() []const type {
|
||||
|
||||
const IntersectionObserver = @This();
|
||||
|
||||
_callback: js.Function,
|
||||
_callback: js.Function.Global,
|
||||
_observing: std.ArrayList(*Element) = .{},
|
||||
_root: ?*Element = null,
|
||||
_root_margin: []const u8 = "0px",
|
||||
@@ -59,7 +59,7 @@ pub const ObserverInit = struct {
|
||||
};
|
||||
};
|
||||
|
||||
pub fn init(callback: js.Function, options: ?ObserverInit, page: *Page) !*IntersectionObserver {
|
||||
pub fn init(callback: js.Function.Global, options: ?ObserverInit, page: *Page) !*IntersectionObserver {
|
||||
const opts = options orelse ObserverInit{};
|
||||
const root_margin = if (opts.rootMargin) |rm| try page.arena.dupe(u8, rm) else "0px";
|
||||
|
||||
@@ -73,7 +73,7 @@ pub fn init(callback: js.Function, options: ?ObserverInit, page: *Page) !*Inters
|
||||
};
|
||||
|
||||
return page._factory.create(IntersectionObserver{
|
||||
._callback = try callback.persist(),
|
||||
._callback = callback,
|
||||
._root = opts.root,
|
||||
._root_margin = root_margin,
|
||||
._threshold = threshold,
|
||||
@@ -246,7 +246,7 @@ pub fn deliverEntries(self: *IntersectionObserver, page: *Page) !void {
|
||||
|
||||
const entries = try self.takeRecords(page);
|
||||
var caught: js.TryCatch.Caught = undefined;
|
||||
self._callback.tryCall(void, .{ entries, self }, &caught) catch |err| {
|
||||
self._callback.local().tryCall(void, .{ entries, self }, &caught) catch |err| {
|
||||
log.err(.page, "IntsctObserver.deliverEntries", .{ .err = err, .caught = caught });
|
||||
return err;
|
||||
};
|
||||
|
||||
@@ -29,8 +29,8 @@ const MessagePort = @This();
|
||||
_proto: *EventTarget,
|
||||
_enabled: bool = false,
|
||||
_closed: bool = false,
|
||||
_on_message: ?js.Function = null,
|
||||
_on_message_error: ?js.Function = null,
|
||||
_on_message: ?js.Function.Global = null,
|
||||
_on_message_error: ?js.Function.Global = null,
|
||||
_entangled_port: ?*MessagePort = null,
|
||||
|
||||
pub fn init(page: *Page) !*MessagePort {
|
||||
@@ -48,7 +48,7 @@ pub fn entangle(port1: *MessagePort, port2: *MessagePort) void {
|
||||
port2._entangled_port = port1;
|
||||
}
|
||||
|
||||
pub fn postMessage(self: *MessagePort, message: js.Value, page: *Page) !void {
|
||||
pub fn postMessage(self: *MessagePort, message: js.Value.Global, page: *Page) !void {
|
||||
if (self._closed) {
|
||||
return;
|
||||
}
|
||||
@@ -62,7 +62,7 @@ pub fn postMessage(self: *MessagePort, message: js.Value, page: *Page) !void {
|
||||
const callback = try page._factory.create(PostMessageCallback{
|
||||
.page = page,
|
||||
.port = other,
|
||||
.message = try message.persist(),
|
||||
.message = message,
|
||||
});
|
||||
|
||||
try page.scheduler.add(callback, PostMessageCallback.run, 0, .{
|
||||
@@ -88,33 +88,25 @@ pub fn close(self: *MessagePort) void {
|
||||
self._entangled_port = null;
|
||||
}
|
||||
|
||||
pub fn getOnMessage(self: *const MessagePort) ?js.Function {
|
||||
pub fn getOnMessage(self: *const MessagePort) ?js.Function.Global {
|
||||
return self._on_message;
|
||||
}
|
||||
|
||||
pub fn setOnMessage(self: *MessagePort, cb_: ?js.Function) !void {
|
||||
if (cb_) |cb| {
|
||||
self._on_message = try cb.persist();
|
||||
} else {
|
||||
self._on_message = null;
|
||||
}
|
||||
pub fn setOnMessage(self: *MessagePort, cb: ?js.Function.Global) !void {
|
||||
self._on_message = cb;
|
||||
}
|
||||
|
||||
pub fn getOnMessageError(self: *const MessagePort) ?js.Function {
|
||||
pub fn getOnMessageError(self: *const MessagePort) ?js.Function.Global {
|
||||
return self._on_message_error;
|
||||
}
|
||||
|
||||
pub fn setOnMessageError(self: *MessagePort, cb_: ?js.Function) !void {
|
||||
if (cb_) |cb| {
|
||||
self._on_message_error = try cb.persist();
|
||||
} else {
|
||||
self._on_message_error = null;
|
||||
}
|
||||
pub fn setOnMessageError(self: *MessagePort, cb: ?js.Function.Global) !void {
|
||||
self._on_message_error = cb;
|
||||
}
|
||||
|
||||
const PostMessageCallback = struct {
|
||||
port: *MessagePort,
|
||||
message: js.Value,
|
||||
message: js.Value.Global,
|
||||
page: *Page,
|
||||
|
||||
fn deinit(self: *PostMessageCallback) void {
|
||||
@@ -138,10 +130,11 @@ const PostMessageCallback = struct {
|
||||
return null;
|
||||
};
|
||||
|
||||
const func = if (self.port._on_message) |*g| g.local() else null;
|
||||
self.page._event_manager.dispatchWithFunction(
|
||||
self.port.asEventTarget(),
|
||||
event.asEvent(),
|
||||
self.port._on_message,
|
||||
func,
|
||||
.{ .context = "MessagePort message" },
|
||||
) catch |err| {
|
||||
log.err(.dom, "MessagePort.postMessage", .{ .err = err });
|
||||
|
||||
@@ -32,7 +32,7 @@ pub fn registerTypes() []const type {
|
||||
|
||||
const MutationObserver = @This();
|
||||
|
||||
_callback: js.Function,
|
||||
_callback: js.Function.Global,
|
||||
_observing: std.ArrayList(Observing) = .{},
|
||||
_pending_records: std.ArrayList(*MutationRecord) = .{},
|
||||
/// Intrusively linked to next element (see Page.zig).
|
||||
@@ -53,9 +53,9 @@ pub const ObserveOptions = struct {
|
||||
attributeFilter: ?[]const []const u8 = null,
|
||||
};
|
||||
|
||||
pub fn init(callback: js.Function, page: *Page) !*MutationObserver {
|
||||
pub fn init(callback: js.Function.Global, page: *Page) !*MutationObserver {
|
||||
return page._factory.create(MutationObserver{
|
||||
._callback = try callback.persist(),
|
||||
._callback = callback,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -249,7 +249,7 @@ pub fn deliverRecords(self: *MutationObserver, page: *Page) !void {
|
||||
// This ensures mutations triggered during the callback go into a fresh list
|
||||
const records = try self.takeRecords(page);
|
||||
var caught: js.TryCatch.Caught = undefined;
|
||||
self._callback.tryCall(void, .{ records, self }, &caught) catch |err| {
|
||||
self._callback.local().tryCall(void, .{ records, self }, &caught) catch |err| {
|
||||
log.err(.page, "MutObserver.deliverRecords", .{ .err = err, .caught = caught });
|
||||
return err;
|
||||
};
|
||||
|
||||
@@ -22,22 +22,22 @@ const Node = @import("Node.zig");
|
||||
|
||||
const NodeFilter = @This();
|
||||
|
||||
_func: ?js.Function,
|
||||
_func: ?js.Function.Global,
|
||||
_original_filter: ?FilterOpts,
|
||||
|
||||
pub const FilterOpts = union(enum) {
|
||||
function: js.Function,
|
||||
function: js.Function.Global,
|
||||
object: struct {
|
||||
pub const js_as_object = true;
|
||||
acceptNode: js.Function,
|
||||
acceptNode: js.Function.Global,
|
||||
},
|
||||
};
|
||||
|
||||
pub fn init(opts_: ?FilterOpts) !NodeFilter {
|
||||
const opts = opts_ orelse return .{ ._func = null, ._original_filter = null };
|
||||
const func = switch (opts) {
|
||||
.function => |func| try func.persist(),
|
||||
.object => |obj| try obj.acceptNode.persist(),
|
||||
.function => |func| func,
|
||||
.object => |obj| obj.acceptNode,
|
||||
};
|
||||
return .{
|
||||
._func = func,
|
||||
@@ -67,7 +67,7 @@ pub const SHOW_NOTATION: u32 = 0x800;
|
||||
|
||||
pub fn acceptNode(self: *const NodeFilter, node: *Node) !i32 {
|
||||
const func = self._func orelse return FILTER_ACCEPT;
|
||||
return func.call(i32, .{node});
|
||||
return func.local().call(i32, .{node});
|
||||
}
|
||||
|
||||
pub fn shouldShow(node: *const Node, what_to_show: u32) bool {
|
||||
|
||||
@@ -314,7 +314,7 @@ pub const Entry = struct {
|
||||
|
||||
pub const Mark = struct {
|
||||
_proto: *Entry,
|
||||
_detail: ?js.Value,
|
||||
_detail: ?js.Value.Global,
|
||||
|
||||
const Options = struct {
|
||||
detail: ?js.Value = null,
|
||||
@@ -344,7 +344,7 @@ pub const Mark = struct {
|
||||
return m;
|
||||
}
|
||||
|
||||
pub fn getDetail(self: *const Mark) ?js.Value {
|
||||
pub fn getDetail(self: *const Mark) ?js.Value.Global {
|
||||
return self._detail;
|
||||
}
|
||||
|
||||
@@ -362,7 +362,7 @@ pub const Mark = struct {
|
||||
|
||||
pub const Measure = struct {
|
||||
_proto: *Entry,
|
||||
_detail: ?js.Object,
|
||||
_detail: ?js.Object.Global,
|
||||
|
||||
const Options = struct {
|
||||
detail: ?js.Object = null,
|
||||
@@ -405,7 +405,7 @@ pub const Measure = struct {
|
||||
return m;
|
||||
}
|
||||
|
||||
pub fn getDetail(self: *const Measure) ?js.Object {
|
||||
pub fn getDetail(self: *const Measure) ?js.Object.Global {
|
||||
return self._detail;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ pub fn registerTypes() []const type {
|
||||
const PerformanceObserver = @This();
|
||||
|
||||
/// Emitted when there are events with same interests.
|
||||
_callback: js.Function,
|
||||
_callback: js.Function.Global,
|
||||
/// The threshold to deliver `PerformanceEventTiming` entries.
|
||||
_duration_threshold: f64,
|
||||
/// Entry types we're looking for are encoded as bit flags.
|
||||
@@ -44,9 +44,9 @@ _entries: std.ArrayList(*Performance.Entry),
|
||||
const DefaultDurationThreshold: f64 = 104;
|
||||
|
||||
/// Creates a new PerformanceObserver object with the given observer callback.
|
||||
pub fn init(callback: js.Function, page: *Page) !*PerformanceObserver {
|
||||
pub fn init(callback: js.Function.Global, page: *Page) !*PerformanceObserver {
|
||||
return page._factory.create(PerformanceObserver{
|
||||
._callback = try callback.persist(),
|
||||
._callback = callback,
|
||||
._duration_threshold = DefaultDurationThreshold,
|
||||
._interests = 0,
|
||||
._entries = .{},
|
||||
@@ -154,7 +154,7 @@ pub inline fn hasRecords(self: *const PerformanceObserver) bool {
|
||||
pub fn dispatch(self: *PerformanceObserver, page: *Page) !void {
|
||||
const records = try self.takeRecords(page);
|
||||
var caught: js.TryCatch.Caught = undefined;
|
||||
self._callback.tryCall(void, .{ EntryList{ ._entries = records }, self }, &caught) catch |err| {
|
||||
self._callback.local().tryCall(void, .{ EntryList{ ._entries = records }, self }, &caught) catch |err| {
|
||||
log.err(.page, "PerfObserver.dispatch", .{ .err = err, .caught = caught });
|
||||
return err;
|
||||
};
|
||||
|
||||
@@ -54,11 +54,11 @@ _navigator: Navigator = .init,
|
||||
_screen: *Screen,
|
||||
_performance: Performance,
|
||||
_storage_bucket: *storage.Bucket,
|
||||
_on_load: ?js.Function = null,
|
||||
_on_pageshow: ?js.Function = null,
|
||||
_on_popstate: ?js.Function = null,
|
||||
_on_error: ?js.Function = null, // TODO: invoke on error?
|
||||
_on_unhandled_rejection: ?js.Function = null, // TODO: invoke on error
|
||||
_on_load: ?js.Function.Global = null,
|
||||
_on_pageshow: ?js.Function.Global = null,
|
||||
_on_popstate: ?js.Function.Global = null,
|
||||
_on_error: ?js.Function.Global = null, // TODO: invoke on error?
|
||||
_on_unhandled_rejection: ?js.Function.Global = null, // TODO: invoke on error
|
||||
_location: *Location,
|
||||
_timer_id: u30 = 0,
|
||||
_timers: std.AutoHashMapUnmanaged(u32, *ScheduleCallback) = .{},
|
||||
@@ -145,51 +145,51 @@ pub fn getCustomElements(self: *Window) *CustomElementRegistry {
|
||||
return &self._custom_elements;
|
||||
}
|
||||
|
||||
pub fn getOnLoad(self: *const Window) ?js.Function {
|
||||
pub fn getOnLoad(self: *const Window) ?js.Function.Global {
|
||||
return self._on_load;
|
||||
}
|
||||
|
||||
pub fn setOnLoad(self: *Window, setter: ?FunctionSetter) !void {
|
||||
self._on_load = try getFunctionFromSetter(setter);
|
||||
pub fn setOnLoad(self: *Window, setter: ?FunctionSetter) void {
|
||||
self._on_load = getFunctionFromSetter(setter);
|
||||
}
|
||||
|
||||
pub fn getOnPageShow(self: *const Window) ?js.Function {
|
||||
pub fn getOnPageShow(self: *const Window) ?js.Function.Global {
|
||||
return self._on_pageshow;
|
||||
}
|
||||
|
||||
pub fn setOnPageShow(self: *Window, setter: ?FunctionSetter) !void {
|
||||
self._on_pageshow = try getFunctionFromSetter(setter);
|
||||
pub fn setOnPageShow(self: *Window, setter: ?FunctionSetter) void {
|
||||
self._on_pageshow = getFunctionFromSetter(setter);
|
||||
}
|
||||
|
||||
pub fn getOnPopState(self: *const Window) ?js.Function {
|
||||
pub fn getOnPopState(self: *const Window) ?js.Function.Global {
|
||||
return self._on_popstate;
|
||||
}
|
||||
|
||||
pub fn setOnPopState(self: *Window, setter: ?FunctionSetter) !void {
|
||||
self._on_popstate = try getFunctionFromSetter(setter);
|
||||
pub fn setOnPopState(self: *Window, setter: ?FunctionSetter) void {
|
||||
self._on_popstate = getFunctionFromSetter(setter);
|
||||
}
|
||||
|
||||
pub fn getOnError(self: *const Window) ?js.Function {
|
||||
pub fn getOnError(self: *const Window) ?js.Function.Global {
|
||||
return self._on_error;
|
||||
}
|
||||
|
||||
pub fn setOnError(self: *Window, setter: ?FunctionSetter) !void {
|
||||
self._on_error = try getFunctionFromSetter(setter);
|
||||
pub fn setOnError(self: *Window, setter: ?FunctionSetter) void {
|
||||
self._on_error = getFunctionFromSetter(setter);
|
||||
}
|
||||
|
||||
pub fn getOnUnhandledRejection(self: *const Window) ?js.Function {
|
||||
pub fn getOnUnhandledRejection(self: *const Window) ?js.Function.Global {
|
||||
return self._on_unhandled_rejection;
|
||||
}
|
||||
|
||||
pub fn setOnUnhandledRejection(self: *Window, setter: ?FunctionSetter) !void {
|
||||
self._on_unhandled_rejection = try getFunctionFromSetter(setter);
|
||||
pub fn setOnUnhandledRejection(self: *Window, setter: ?FunctionSetter) void {
|
||||
self._on_unhandled_rejection = getFunctionFromSetter(setter);
|
||||
}
|
||||
|
||||
pub fn fetch(_: *const Window, input: Fetch.Input, options: ?Fetch.InitOpts, page: *Page) !js.Promise {
|
||||
return Fetch.init(input, options, page);
|
||||
}
|
||||
|
||||
pub fn setTimeout(self: *Window, cb: js.Function, delay_ms: ?u32, params: []js.Value, page: *Page) !u32 {
|
||||
pub fn setTimeout(self: *Window, cb: js.Function.Global, delay_ms: ?u32, params: []js.Value.Global, page: *Page) !u32 {
|
||||
return self.scheduleCallback(cb, delay_ms orelse 0, .{
|
||||
.repeat = false,
|
||||
.params = params,
|
||||
@@ -198,7 +198,7 @@ pub fn setTimeout(self: *Window, cb: js.Function, delay_ms: ?u32, params: []js.V
|
||||
}, page);
|
||||
}
|
||||
|
||||
pub fn setInterval(self: *Window, cb: js.Function, delay_ms: ?u32, params: []js.Value, page: *Page) !u32 {
|
||||
pub fn setInterval(self: *Window, cb: js.Function.Global, delay_ms: ?u32, params: []js.Value.Global, page: *Page) !u32 {
|
||||
return self.scheduleCallback(cb, delay_ms orelse 0, .{
|
||||
.repeat = true,
|
||||
.params = params,
|
||||
@@ -207,7 +207,7 @@ pub fn setInterval(self: *Window, cb: js.Function, delay_ms: ?u32, params: []js.
|
||||
}, page);
|
||||
}
|
||||
|
||||
pub fn setImmediate(self: *Window, cb: js.Function, params: []js.Value, page: *Page) !u32 {
|
||||
pub fn setImmediate(self: *Window, cb: js.Function.Global, params: []js.Value.Global, page: *Page) !u32 {
|
||||
return self.scheduleCallback(cb, 0, .{
|
||||
.repeat = false,
|
||||
.params = params,
|
||||
@@ -216,7 +216,7 @@ pub fn setImmediate(self: *Window, cb: js.Function, params: []js.Value, page: *P
|
||||
}, page);
|
||||
}
|
||||
|
||||
pub fn requestAnimationFrame(self: *Window, cb: js.Function, page: *Page) !u32 {
|
||||
pub fn requestAnimationFrame(self: *Window, cb: js.Function.Global, page: *Page) !u32 {
|
||||
return self.scheduleCallback(cb, 5, .{
|
||||
.repeat = false,
|
||||
.params = &.{},
|
||||
@@ -253,7 +253,7 @@ pub fn cancelAnimationFrame(self: *Window, id: u32) void {
|
||||
const RequestIdleCallbackOpts = struct {
|
||||
timeout: ?u32 = null,
|
||||
};
|
||||
pub fn requestIdleCallback(self: *Window, cb: js.Function, opts_: ?RequestIdleCallbackOpts, page: *Page) !u32 {
|
||||
pub fn requestIdleCallback(self: *Window, cb: js.Function.Global, opts_: ?RequestIdleCallbackOpts, page: *Page) !u32 {
|
||||
const opts = opts_ orelse RequestIdleCallbackOpts{};
|
||||
return self.scheduleCallback(cb, opts.timeout orelse 50, .{
|
||||
.mode = .idle,
|
||||
@@ -269,10 +269,10 @@ pub fn cancelIdleCallback(self: *Window, id: u32) void {
|
||||
sc.removed = true;
|
||||
}
|
||||
|
||||
pub fn reportError(self: *Window, err: js.Value, page: *Page) !void {
|
||||
pub fn reportError(self: *Window, err: js.Value.Global, page: *Page) !void {
|
||||
const error_event = try ErrorEvent.initTrusted("error", .{
|
||||
.@"error" = err,
|
||||
.message = err.toString(.{}) catch "Unknown error",
|
||||
.message = err.local().toString(.{}) catch "Unknown error",
|
||||
.bubbles = false,
|
||||
.cancelable = true,
|
||||
}, page);
|
||||
@@ -316,7 +316,7 @@ pub fn getIsSecureContext(_: *const Window) bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn postMessage(self: *Window, message: js.Value, target_origin: ?[]const u8, page: *Page) !void {
|
||||
pub fn postMessage(self: *Window, message: js.Value.Global, target_origin: ?[]const u8, page: *Page) !void {
|
||||
// For now, we ignore targetOrigin checking and just dispatch the message
|
||||
// In a full implementation, we would validate the origin
|
||||
_ = target_origin;
|
||||
@@ -325,7 +325,7 @@ pub fn postMessage(self: *Window, message: js.Value, target_origin: ?[]const u8,
|
||||
const origin = try self._location.getOrigin(page);
|
||||
const callback = try page._factory.create(PostMessageCallback{
|
||||
.window = self,
|
||||
.message = try message.persist(),
|
||||
.message = message,
|
||||
.origin = try page.arena.dupe(u8, origin),
|
||||
.page = page,
|
||||
});
|
||||
@@ -465,13 +465,13 @@ pub fn scrollTo(self: *Window, opts: ScrollToOpts, y: ?i32, page: *Page) !void {
|
||||
|
||||
const ScheduleOpts = struct {
|
||||
repeat: bool,
|
||||
params: []js.Value,
|
||||
params: []js.Value.Global,
|
||||
name: []const u8,
|
||||
low_priority: bool = false,
|
||||
animation_frame: bool = false,
|
||||
mode: ScheduleCallback.Mode = .normal,
|
||||
};
|
||||
fn scheduleCallback(self: *Window, cb: js.Function, delay_ms: u32, opts: ScheduleOpts, page: *Page) !u32 {
|
||||
fn scheduleCallback(self: *Window, cb: js.Function.Global, delay_ms: u32, opts: ScheduleOpts, page: *Page) !u32 {
|
||||
if (self._timers.count() > 512) {
|
||||
// these are active
|
||||
return error.TooManyTimeout;
|
||||
@@ -481,12 +481,9 @@ fn scheduleCallback(self: *Window, cb: js.Function, delay_ms: u32, opts: Schedul
|
||||
self._timer_id = timer_id;
|
||||
|
||||
const params = opts.params;
|
||||
var persisted_params: []js.Value = &.{};
|
||||
var persisted_params: []js.Value.Global = &.{};
|
||||
if (params.len > 0) {
|
||||
persisted_params = try page.arena.alloc(js.Value, params.len);
|
||||
for (params, persisted_params) |a, *ca| {
|
||||
ca.* = try a.persist();
|
||||
}
|
||||
persisted_params = try page.arena.dupe(js.Value.Global, params);
|
||||
}
|
||||
|
||||
const gop = try self._timers.getOrPut(page.arena, timer_id);
|
||||
@@ -497,7 +494,7 @@ fn scheduleCallback(self: *Window, cb: js.Function, delay_ms: u32, opts: Schedul
|
||||
errdefer _ = self._timers.remove(timer_id);
|
||||
|
||||
const callback = try page._factory.create(ScheduleCallback{
|
||||
.cb = try cb.persist(),
|
||||
.cb = cb,
|
||||
.page = page,
|
||||
.mode = opts.mode,
|
||||
.name = opts.name,
|
||||
@@ -526,11 +523,11 @@ const ScheduleCallback = struct {
|
||||
// delay, in ms, to repeat. When null, will be removed after the first time
|
||||
repeat_ms: ?u32,
|
||||
|
||||
cb: js.Function,
|
||||
cb: js.Function.Global,
|
||||
|
||||
page: *Page,
|
||||
|
||||
params: []const js.Value,
|
||||
params: []const js.Value.Global,
|
||||
|
||||
removed: bool = false,
|
||||
|
||||
@@ -558,17 +555,17 @@ const ScheduleCallback = struct {
|
||||
switch (self.mode) {
|
||||
.idle => {
|
||||
const IdleDeadline = @import("IdleDeadline.zig");
|
||||
self.cb.call(void, .{IdleDeadline{}}) catch |err| {
|
||||
self.cb.local().call(void, .{IdleDeadline{}}) catch |err| {
|
||||
log.warn(.js, "window.idleCallback", .{ .name = self.name, .err = err });
|
||||
};
|
||||
},
|
||||
.animation_frame => {
|
||||
self.cb.call(void, .{page.window._performance.now()}) catch |err| {
|
||||
self.cb.local().call(void, .{page.window._performance.now()}) catch |err| {
|
||||
log.warn(.js, "window.RAF", .{ .name = self.name, .err = err });
|
||||
};
|
||||
},
|
||||
.normal => {
|
||||
self.cb.call(void, self.params) catch |err| {
|
||||
self.cb.local().call(void, self.params) catch |err| {
|
||||
log.warn(.js, "window.timer", .{ .name = self.name, .err = err });
|
||||
};
|
||||
},
|
||||
@@ -587,7 +584,7 @@ const ScheduleCallback = struct {
|
||||
|
||||
const PostMessageCallback = struct {
|
||||
window: *Window,
|
||||
message: js.Value,
|
||||
message: js.Value.Global,
|
||||
origin: []const u8,
|
||||
page: *Page,
|
||||
|
||||
@@ -615,17 +612,17 @@ const PostMessageCallback = struct {
|
||||
};
|
||||
|
||||
const FunctionSetter = union(enum) {
|
||||
func: js.Function,
|
||||
func: js.Function.Global,
|
||||
anything: js.Value,
|
||||
};
|
||||
|
||||
// window.onload = {}; doesn't fail, but it doesn't do anything.
|
||||
// seems like setting to null is ok (though, at least on Firefix, it preserves
|
||||
// the original value, which we could do, but why?)
|
||||
fn getFunctionFromSetter(setter_: ?FunctionSetter) !?js.Function {
|
||||
fn getFunctionFromSetter(setter_: ?FunctionSetter) ?js.Function.Global {
|
||||
const setter = setter_ orelse return null;
|
||||
return switch (setter) {
|
||||
.func => |func| try func.persist(),
|
||||
.func => |func| func, // Already a Global from bridge auto-conversion
|
||||
.anything => null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -21,10 +21,10 @@ const Page = @import("../../Page.zig");
|
||||
|
||||
const Animation = @This();
|
||||
|
||||
_effect: ?js.Object = null,
|
||||
_timeline: ?js.Object = null,
|
||||
_ready_resolver: ?js.PromiseResolver = null,
|
||||
_finished_resolver: ?js.PromiseResolver = null,
|
||||
_effect: ?js.Object.Global = null,
|
||||
_timeline: ?js.Object.Global = null,
|
||||
_ready_resolver: ?js.PromiseResolver.Global = null,
|
||||
_finished_resolver: ?js.PromiseResolver.Global = null,
|
||||
|
||||
pub fn init(page: *Page) !*Animation {
|
||||
return page._factory.create(Animation{});
|
||||
@@ -47,10 +47,10 @@ pub fn getPending(_: *const Animation) bool {
|
||||
pub fn getFinished(self: *Animation, page: *Page) !js.Promise {
|
||||
if (self._finished_resolver == null) {
|
||||
const resolver = try page.js.createPromiseResolver().persist();
|
||||
resolver.resolve("Animation.getFinished", self);
|
||||
resolver.local().resolve("Animation.getFinished", self);
|
||||
self._finished_resolver = resolver;
|
||||
}
|
||||
return self._finished_resolver.?.promise();
|
||||
return self._finished_resolver.?.local().promise();
|
||||
}
|
||||
|
||||
pub fn getReady(self: *Animation, page: *Page) !js.Promise {
|
||||
@@ -59,31 +59,23 @@ pub fn getReady(self: *Animation, page: *Page) !js.Promise {
|
||||
const resolver = try page.js.createPromiseResolver().persist();
|
||||
self._ready_resolver = resolver;
|
||||
}
|
||||
return self._ready_resolver.?.promise();
|
||||
return self._ready_resolver.?.local().promise();
|
||||
}
|
||||
|
||||
pub fn getEffect(self: *const Animation) ?js.Object {
|
||||
pub fn getEffect(self: *const Animation) ?js.Object.Global {
|
||||
return self._effect;
|
||||
}
|
||||
|
||||
pub fn setEffect(self: *Animation, effect: ?js.Object) !void {
|
||||
if (effect) |e| {
|
||||
self._effect = try e.persist();
|
||||
} else {
|
||||
self._effect = null;
|
||||
}
|
||||
pub fn setEffect(self: *Animation, effect: ?js.Object.Global) !void {
|
||||
self._effect = effect;
|
||||
}
|
||||
|
||||
pub fn getTimeline(self: *const Animation) ?js.Object {
|
||||
pub fn getTimeline(self: *const Animation) ?js.Object.Global {
|
||||
return self._timeline;
|
||||
}
|
||||
|
||||
pub fn setTimeline(self: *Animation, timeline: ?js.Object) !void {
|
||||
if (timeline) |t| {
|
||||
self._timeline = try t.persist();
|
||||
} else {
|
||||
self._timeline = null;
|
||||
}
|
||||
pub fn setTimeline(self: *Animation, timeline: ?js.Object.Global) !void {
|
||||
self._timeline = timeline;
|
||||
}
|
||||
|
||||
pub const JsApi = struct {
|
||||
|
||||
@@ -50,9 +50,10 @@ pub const Build = struct {
|
||||
pub fn complete(node: *Node, page: *Page) !void {
|
||||
const el = node.as(Element);
|
||||
const on_load = el.getAttributeSafe("onload") orelse return;
|
||||
page.window._on_load = page.js.stringToFunction(on_load) catch |err| blk: {
|
||||
if (page.js.stringToFunction(on_load)) |func| {
|
||||
page.window._on_load = try func.persist();
|
||||
} else |err| {
|
||||
log.err(.js, "body.onload", .{ .err = err, .str = on_load });
|
||||
break :blk null;
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -196,7 +196,7 @@ pub fn checkAndAttachBuiltIn(element: *Element, page: *Page) !void {
|
||||
defer page._upgrading_element = prev_upgrading;
|
||||
|
||||
var caught: js.TryCatch.Caught = undefined;
|
||||
_ = definition.constructor.newInstance(&caught) catch |err| {
|
||||
_ = definition.constructor.local().newInstance(&caught) catch |err| {
|
||||
log.warn(.js, "custom builtin ctor", .{ .name = is_value, .err = err, .caught = caught });
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -29,8 +29,8 @@ const Script = @This();
|
||||
|
||||
_proto: *HtmlElement,
|
||||
_src: []const u8 = "",
|
||||
_on_load: ?js.Function = null,
|
||||
_on_error: ?js.Function = null,
|
||||
_on_load: ?js.Function.Global = null,
|
||||
_on_error: ?js.Function.Global = null,
|
||||
_executed: bool = false,
|
||||
|
||||
pub fn asElement(self: *Script) *Element {
|
||||
@@ -74,28 +74,20 @@ pub fn setNonce(self: *Script, value: []const u8, page: *Page) !void {
|
||||
return self.asElement().setAttributeSafe("nonce", value, page);
|
||||
}
|
||||
|
||||
pub fn getOnLoad(self: *const Script) ?js.Function {
|
||||
pub fn getOnLoad(self: *const Script) ?js.Function.Global {
|
||||
return self._on_load;
|
||||
}
|
||||
|
||||
pub fn setOnLoad(self: *Script, cb_: ?js.Function) !void {
|
||||
if (cb_) |cb| {
|
||||
self._on_load = try cb.persist();
|
||||
} else {
|
||||
self._on_load = null;
|
||||
}
|
||||
pub fn setOnLoad(self: *Script, cb: ?js.Function.Global) void {
|
||||
self._on_load = cb;
|
||||
}
|
||||
|
||||
pub fn getOnError(self: *const Script) ?js.Function {
|
||||
pub fn getOnError(self: *const Script) ?js.Function.Global {
|
||||
return self._on_error;
|
||||
}
|
||||
|
||||
pub fn setOnError(self: *Script, cb_: ?js.Function) !void {
|
||||
if (cb_) |cb| {
|
||||
self._on_error = try cb.persist();
|
||||
} else {
|
||||
self._on_error = null;
|
||||
}
|
||||
pub fn setOnError(self: *Script, cb: ?js.Function.Global) void {
|
||||
self._on_error = cb;
|
||||
}
|
||||
|
||||
pub fn getNoModule(self: *const Script) bool {
|
||||
@@ -136,23 +128,19 @@ pub const Build = struct {
|
||||
self._src = element.getAttributeSafe("src") orelse "";
|
||||
|
||||
if (element.getAttributeSafe("onload")) |on_load| {
|
||||
self._on_load = blk: {
|
||||
const func = page.js.stringToFunction(on_load) catch |err| {
|
||||
log.err(.js, "script.onload", .{ .err = err, .str = on_load });
|
||||
break :blk null;
|
||||
};
|
||||
break :blk try func.persist();
|
||||
};
|
||||
if (page.js.stringToFunction(on_load)) |func| {
|
||||
self._on_load = try func.persist();
|
||||
} else |err| {
|
||||
log.err(.js, "script.onload", .{ .err = err, .str = on_load });
|
||||
}
|
||||
}
|
||||
|
||||
if (element.getAttributeSafe("onerror")) |on_error| {
|
||||
self._on_error = blk: {
|
||||
const func = page.js.stringToFunction(on_error) catch |err| {
|
||||
log.err(.js, "script.onerror", .{ .err = err, .str = on_error });
|
||||
break :blk null;
|
||||
};
|
||||
break :blk try func.persist();
|
||||
};
|
||||
if (page.js.stringToFunction(on_error)) |func| {
|
||||
self._on_error = try func.persist();
|
||||
} else |err| {
|
||||
log.err(.js, "script.onerror", .{ .err = err, .str = on_error });
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -27,11 +27,11 @@ const Allocator = std.mem.Allocator;
|
||||
const CustomEvent = @This();
|
||||
|
||||
_proto: *Event,
|
||||
_detail: ?js.Value = null,
|
||||
_arena: Allocator,
|
||||
_detail: ?js.Value.Global = null,
|
||||
|
||||
const CustomEventOptions = struct {
|
||||
detail: ?js.Value = null,
|
||||
detail: ?js.Value.Global = null,
|
||||
};
|
||||
|
||||
const Options = Event.inheritOptions(CustomEvent, CustomEventOptions);
|
||||
@@ -45,7 +45,7 @@ pub fn init(typ: []const u8, opts_: ?Options, page: *Page) !*CustomEvent {
|
||||
CustomEvent{
|
||||
._arena = arena,
|
||||
._proto = undefined,
|
||||
._detail = if (opts.detail) |detail| try detail.persist() else null,
|
||||
._detail = opts.detail,
|
||||
},
|
||||
);
|
||||
|
||||
@@ -58,7 +58,7 @@ pub fn initCustomEvent(
|
||||
event_string: []const u8,
|
||||
bubbles: ?bool,
|
||||
cancelable: ?bool,
|
||||
detail_: ?js.Value,
|
||||
detail_: ?js.Value.Global,
|
||||
page: *Page,
|
||||
) !void {
|
||||
// This function can only be called after the constructor has called.
|
||||
@@ -67,16 +67,14 @@ pub fn initCustomEvent(
|
||||
self._proto._bubbles = bubbles orelse false;
|
||||
self._proto._cancelable = cancelable orelse false;
|
||||
// Detail is stored separately.
|
||||
if (detail_) |detail| {
|
||||
self._detail = try detail.persist();
|
||||
}
|
||||
self._detail = detail_;
|
||||
}
|
||||
|
||||
pub fn asEvent(self: *CustomEvent) *Event {
|
||||
return self._proto;
|
||||
}
|
||||
|
||||
pub fn getDetail(self: *const CustomEvent) ?js.Value {
|
||||
pub fn getDetail(self: *const CustomEvent) ?js.Value.Global {
|
||||
return self._detail;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ _message: []const u8 = "",
|
||||
_filename: []const u8 = "",
|
||||
_line_number: u32 = 0,
|
||||
_column_number: u32 = 0,
|
||||
_error: ?js.Value = null,
|
||||
_error: ?js.Value.Global = null,
|
||||
_arena: Allocator,
|
||||
|
||||
pub const ErrorEventOptions = struct {
|
||||
@@ -38,7 +38,7 @@ pub const ErrorEventOptions = struct {
|
||||
filename: ?[]const u8 = null,
|
||||
lineno: u32 = 0,
|
||||
colno: u32 = 0,
|
||||
@"error": ?js.Value = null,
|
||||
@"error": ?js.Value.Global = null,
|
||||
};
|
||||
|
||||
const Options = Event.inheritOptions(ErrorEvent, ErrorEventOptions);
|
||||
@@ -64,7 +64,7 @@ fn initWithTrusted(typ: []const u8, opts_: ?Options, trusted: bool, page: *Page)
|
||||
._filename = if (opts.filename) |str| try arena.dupe(u8, str) else "",
|
||||
._line_number = opts.lineno,
|
||||
._column_number = opts.colno,
|
||||
._error = if (opts.@"error") |err| try err.persist() else null,
|
||||
._error = opts.@"error",
|
||||
},
|
||||
);
|
||||
|
||||
@@ -92,7 +92,7 @@ pub fn getColumnNumber(self: *const ErrorEvent) u32 {
|
||||
return self._column_number;
|
||||
}
|
||||
|
||||
pub fn getError(self: *const ErrorEvent) ?js.Value {
|
||||
pub fn getError(self: *const ErrorEvent) ?js.Value.Global {
|
||||
return self._error;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,12 +25,12 @@ const Window = @import("../Window.zig");
|
||||
const MessageEvent = @This();
|
||||
|
||||
_proto: *Event,
|
||||
_data: ?js.Value = null,
|
||||
_data: ?js.Value.Global = null,
|
||||
_origin: []const u8 = "",
|
||||
_source: ?*Window = null,
|
||||
|
||||
const MessageEventOptions = struct {
|
||||
data: ?js.Value = null,
|
||||
data: ?js.Value.Global = null,
|
||||
origin: ?[]const u8 = null,
|
||||
source: ?*Window = null,
|
||||
};
|
||||
@@ -52,7 +52,7 @@ fn initWithTrusted(typ: []const u8, opts_: ?Options, trusted: bool, page: *Page)
|
||||
typ,
|
||||
MessageEvent{
|
||||
._proto = undefined,
|
||||
._data = if (opts.data) |d| try d.persist() else null,
|
||||
._data = opts.data,
|
||||
._origin = if (opts.origin) |str| try page.arena.dupe(u8, str) else "",
|
||||
._source = opts.source,
|
||||
},
|
||||
@@ -66,7 +66,7 @@ pub fn asEvent(self: *MessageEvent) *Event {
|
||||
return self._proto;
|
||||
}
|
||||
|
||||
pub fn getData(self: *const MessageEvent) ?js.Value {
|
||||
pub fn getData(self: *const MessageEvent) ?js.Value.Global {
|
||||
return self._data;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,8 +30,8 @@ _id: []const u8 = "",
|
||||
_start_time: f64 = 0,
|
||||
_end_time: f64 = 0,
|
||||
_pause_on_exit: bool = false,
|
||||
_on_enter: ?js.Function = null,
|
||||
_on_exit: ?js.Function = null,
|
||||
_on_enter: ?js.Function.Global = null,
|
||||
_on_exit: ?js.Function.Global = null,
|
||||
|
||||
pub const Type = union(enum) {
|
||||
vtt: *@import("VTTCue.zig"),
|
||||
@@ -73,28 +73,20 @@ pub fn setPauseOnExit(self: *TextTrackCue, value: bool) void {
|
||||
self._pause_on_exit = value;
|
||||
}
|
||||
|
||||
pub fn getOnEnter(self: *const TextTrackCue) ?js.Function {
|
||||
pub fn getOnEnter(self: *const TextTrackCue) ?js.Function.Global {
|
||||
return self._on_enter;
|
||||
}
|
||||
|
||||
pub fn setOnEnter(self: *TextTrackCue, cb_: ?js.Function) !void {
|
||||
if (cb_) |cb| {
|
||||
self._on_enter = try cb.persistWithThis(self);
|
||||
} else {
|
||||
self._on_enter = null;
|
||||
}
|
||||
pub fn setOnEnter(self: *TextTrackCue, cb: ?js.Function.Global) !void {
|
||||
self._on_enter = cb;
|
||||
}
|
||||
|
||||
pub fn getOnExit(self: *const TextTrackCue) ?js.Function {
|
||||
pub fn getOnExit(self: *const TextTrackCue) ?js.Function.Global {
|
||||
return self._on_exit;
|
||||
}
|
||||
|
||||
pub fn setOnExit(self: *TextTrackCue, cb_: ?js.Function) !void {
|
||||
if (cb_) |cb| {
|
||||
self._on_exit = try cb.persistWithThis(self);
|
||||
} else {
|
||||
self._on_exit = null;
|
||||
}
|
||||
pub fn setOnExit(self: *TextTrackCue, cb: ?js.Function.Global) !void {
|
||||
self._on_exit = cb;
|
||||
}
|
||||
|
||||
pub const JsApi = struct {
|
||||
|
||||
@@ -26,7 +26,7 @@ const VTTCue = @This();
|
||||
|
||||
_proto: *TextTrackCue,
|
||||
_text: []const u8 = "",
|
||||
_region: ?js.Object = null,
|
||||
_region: ?js.Object.Global = null,
|
||||
_vertical: []const u8 = "",
|
||||
_snap_to_lines: bool = true,
|
||||
_line: ?f64 = null, // null represents "auto"
|
||||
@@ -65,16 +65,12 @@ pub fn setText(self: *VTTCue, value: []const u8, page: *Page) !void {
|
||||
self._text = try page.dupeString(value);
|
||||
}
|
||||
|
||||
pub fn getRegion(self: *const VTTCue) ?js.Object {
|
||||
pub fn getRegion(self: *const VTTCue) ?js.Object.Global {
|
||||
return self._region;
|
||||
}
|
||||
|
||||
pub fn setRegion(self: *VTTCue, value: ?js.Object) !void {
|
||||
if (value) |v| {
|
||||
self._region = try v.persist();
|
||||
} else {
|
||||
self._region = null;
|
||||
}
|
||||
pub fn setRegion(self: *VTTCue, value: ?js.Object.Global) !void {
|
||||
self._region = value;
|
||||
}
|
||||
|
||||
pub fn getVertical(self: *const VTTCue) []const u8 {
|
||||
|
||||
@@ -92,8 +92,8 @@ pub fn getTransition(_: *const Navigation) ?NavigationTransition {
|
||||
}
|
||||
|
||||
const NavigationReturn = struct {
|
||||
committed: js.Promise,
|
||||
finished: js.Promise,
|
||||
committed: js.Promise.Global,
|
||||
finished: js.Promise.Global,
|
||||
};
|
||||
|
||||
pub fn back(self: *Navigation, page: *Page) !NavigationReturn {
|
||||
@@ -278,9 +278,9 @@ pub fn navigateInner(
|
||||
if (is_same_document) {
|
||||
page.url = new_url;
|
||||
|
||||
committed.resolve("navigation push", {});
|
||||
committed.local().resolve("navigation push", {});
|
||||
// todo: Fire navigate event
|
||||
finished.resolve("navigation push", {});
|
||||
finished.local().resolve("navigation push", {});
|
||||
|
||||
_ = try self.pushEntry(url, .{ .source = .navigation, .value = state }, page, true);
|
||||
} else {
|
||||
@@ -291,9 +291,9 @@ pub fn navigateInner(
|
||||
if (is_same_document) {
|
||||
page.url = new_url;
|
||||
|
||||
committed.resolve("navigation replace", {});
|
||||
committed.local().resolve("navigation replace", {});
|
||||
// todo: Fire navigate event
|
||||
finished.resolve("navigation replace", {});
|
||||
finished.local().resolve("navigation replace", {});
|
||||
|
||||
_ = try self.replaceEntry(url, .{ .source = .navigation, .value = state }, page, true);
|
||||
} else {
|
||||
@@ -306,9 +306,9 @@ pub fn navigateInner(
|
||||
if (is_same_document) {
|
||||
page.url = new_url;
|
||||
|
||||
committed.resolve("navigation traverse", {});
|
||||
committed.local().resolve("navigation traverse", {});
|
||||
// todo: Fire navigate event
|
||||
finished.resolve("navigation traverse", {});
|
||||
finished.local().resolve("navigation traverse", {});
|
||||
} else {
|
||||
try page.scheduleNavigation(url, .{ .reason = .navigation, .kind = kind }, .script);
|
||||
}
|
||||
@@ -327,8 +327,8 @@ pub fn navigateInner(
|
||||
try self._proto.dispatch(.{ .currententrychange = event }, page);
|
||||
|
||||
return .{
|
||||
.committed = committed.promise(),
|
||||
.finished = finished.promise(),
|
||||
.committed = try committed.local().promise().persist(),
|
||||
.finished = try finished.local().promise().persist(),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ const NavigationCurrentEntryChangeEvent = @import("../event/NavigationCurrentEnt
|
||||
pub const NavigationEventTarget = @This();
|
||||
|
||||
_proto: *EventTarget,
|
||||
_on_currententrychange: ?js.Function = null,
|
||||
_on_currententrychange: ?js.Function.Global = null,
|
||||
|
||||
pub fn asEventTarget(self: *NavigationEventTarget) *EventTarget {
|
||||
return self._proto;
|
||||
@@ -43,15 +43,16 @@ pub fn dispatch(self: *NavigationEventTarget, event_type: DispatchType, page: *P
|
||||
};
|
||||
};
|
||||
|
||||
const func = if (@field(self, field)) |*g| g.local() else null;
|
||||
return page._event_manager.dispatchWithFunction(
|
||||
self.asEventTarget(),
|
||||
event,
|
||||
@field(self, field),
|
||||
func,
|
||||
.{ .context = "Navigation" },
|
||||
);
|
||||
}
|
||||
|
||||
pub fn getOnCurrentEntryChange(self: *NavigationEventTarget) ?js.Function {
|
||||
pub fn getOnCurrentEntryChange(self: *NavigationEventTarget) ?js.Function.Global {
|
||||
return self._on_currententrychange;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ pub const NavigationState = struct {
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/NavigationTransition
|
||||
pub const NavigationTransition = struct {
|
||||
finished: js.Promise,
|
||||
finished: js.Promise.Global,
|
||||
from: NavigationHistoryEntry,
|
||||
navigation_type: NavigationType,
|
||||
};
|
||||
|
||||
@@ -36,7 +36,7 @@ _page: *Page,
|
||||
_url: []const u8,
|
||||
_buf: std.ArrayList(u8),
|
||||
_response: *Response,
|
||||
_resolver: js.PromiseResolver,
|
||||
_resolver: js.PromiseResolver.Global,
|
||||
|
||||
pub const Input = Request.Input;
|
||||
pub const InitOpts = Request.InitOpts;
|
||||
@@ -77,7 +77,7 @@ pub fn init(input: Input, options: ?InitOpts, page: *Page) !js.Promise {
|
||||
.done_callback = httpDoneCallback,
|
||||
.error_callback = httpErrorCallback,
|
||||
});
|
||||
return fetch._resolver.promise();
|
||||
return fetch._resolver.local().promise();
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Fetch) void {
|
||||
@@ -149,13 +149,13 @@ fn httpDoneCallback(ctx: *anyopaque) !void {
|
||||
.len = self._buf.items.len,
|
||||
});
|
||||
|
||||
return self._resolver.resolve("fetch done", self._response);
|
||||
return self._resolver.local().resolve("fetch done", self._response);
|
||||
}
|
||||
|
||||
fn httpErrorCallback(ctx: *anyopaque, err: anyerror) void {
|
||||
const self: *Fetch = @ptrCast(@alignCast(ctx));
|
||||
self._response._type = .@"error"; // Set type to error for network failures
|
||||
self._resolver.reject("fetch error", @errorName(err));
|
||||
self._resolver.local().reject("fetch error", @errorName(err));
|
||||
}
|
||||
|
||||
const testing = @import("../../../testing.zig");
|
||||
|
||||
@@ -55,7 +55,7 @@ _response_headers: std.ArrayList([]const u8) = .empty,
|
||||
_response_type: ResponseType = .text,
|
||||
|
||||
_ready_state: ReadyState = .unsent,
|
||||
_on_ready_state_change: ?js.Function = null,
|
||||
_on_ready_state_change: ?js.Function.Global = null,
|
||||
|
||||
const ReadyState = enum(u8) {
|
||||
unsent = 0,
|
||||
@@ -67,7 +67,7 @@ const ReadyState = enum(u8) {
|
||||
|
||||
const Response = union(ResponseType) {
|
||||
text: []const u8,
|
||||
json: js.Value,
|
||||
json: js.Value.Global,
|
||||
document: *Node.Document,
|
||||
};
|
||||
|
||||
@@ -98,7 +98,7 @@ fn asEventTarget(self: *XMLHttpRequest) *EventTarget {
|
||||
return self._proto._proto;
|
||||
}
|
||||
|
||||
pub fn getOnReadyStateChange(self: *const XMLHttpRequest) ?js.Function {
|
||||
pub fn getOnReadyStateChange(self: *const XMLHttpRequest) ?js.Function.Global {
|
||||
return self._on_ready_state_change;
|
||||
}
|
||||
|
||||
@@ -416,10 +416,11 @@ fn stateChanged(self: *XMLHttpRequest, state: ReadyState, page: *Page) !void {
|
||||
self._ready_state = state;
|
||||
|
||||
const event = try Event.initTrusted("readystatechange", .{}, page);
|
||||
const func = if (self._on_ready_state_change) |*g| g.local() else null;
|
||||
try page._event_manager.dispatchWithFunction(
|
||||
self.asEventTarget(),
|
||||
event,
|
||||
self._on_ready_state_change,
|
||||
func,
|
||||
.{ .context = "XHR state change" },
|
||||
);
|
||||
}
|
||||
|
||||
@@ -26,13 +26,13 @@ const XMLHttpRequestEventTarget = @This();
|
||||
|
||||
_type: Type,
|
||||
_proto: *EventTarget,
|
||||
_on_abort: ?js.Function = null,
|
||||
_on_error: ?js.Function = null,
|
||||
_on_load: ?js.Function = null,
|
||||
_on_load_end: ?js.Function = null,
|
||||
_on_load_start: ?js.Function = null,
|
||||
_on_progress: ?js.Function = null,
|
||||
_on_timeout: ?js.Function = null,
|
||||
_on_abort: ?js.Function.Global = null,
|
||||
_on_error: ?js.Function.Global = null,
|
||||
_on_load: ?js.Function.Global = null,
|
||||
_on_load_end: ?js.Function.Global = null,
|
||||
_on_load_start: ?js.Function.Global = null,
|
||||
_on_progress: ?js.Function.Global = null,
|
||||
_on_timeout: ?js.Function.Global = null,
|
||||
|
||||
pub const Type = union(enum) {
|
||||
request: *@import("XMLHttpRequest.zig"),
|
||||
@@ -63,15 +63,16 @@ pub fn dispatch(self: *XMLHttpRequestEventTarget, comptime event_type: DispatchT
|
||||
page,
|
||||
);
|
||||
|
||||
const func = if (@field(self, field)) |*g| g.local() else null;
|
||||
return page._event_manager.dispatchWithFunction(
|
||||
self.asEventTarget(),
|
||||
event.asEvent(),
|
||||
@field(self, field),
|
||||
func,
|
||||
.{ .context = "XHR " ++ typ },
|
||||
);
|
||||
}
|
||||
|
||||
pub fn getOnAbort(self: *const XMLHttpRequestEventTarget) ?js.Function {
|
||||
pub fn getOnAbort(self: *const XMLHttpRequestEventTarget) ?js.Function.Global {
|
||||
return self._on_abort;
|
||||
}
|
||||
|
||||
@@ -83,7 +84,7 @@ pub fn setOnAbort(self: *XMLHttpRequestEventTarget, cb_: ?js.Function) !void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getOnError(self: *const XMLHttpRequestEventTarget) ?js.Function {
|
||||
pub fn getOnError(self: *const XMLHttpRequestEventTarget) ?js.Function.Global {
|
||||
return self._on_error;
|
||||
}
|
||||
|
||||
@@ -95,7 +96,7 @@ pub fn setOnError(self: *XMLHttpRequestEventTarget, cb_: ?js.Function) !void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getOnLoad(self: *const XMLHttpRequestEventTarget) ?js.Function {
|
||||
pub fn getOnLoad(self: *const XMLHttpRequestEventTarget) ?js.Function.Global {
|
||||
return self._on_load;
|
||||
}
|
||||
|
||||
@@ -107,7 +108,7 @@ pub fn setOnLoad(self: *XMLHttpRequestEventTarget, cb_: ?js.Function) !void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getOnLoadEnd(self: *const XMLHttpRequestEventTarget) ?js.Function {
|
||||
pub fn getOnLoadEnd(self: *const XMLHttpRequestEventTarget) ?js.Function.Global {
|
||||
return self._on_load_end;
|
||||
}
|
||||
|
||||
@@ -119,7 +120,7 @@ pub fn setOnLoadEnd(self: *XMLHttpRequestEventTarget, cb_: ?js.Function) !void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getOnLoadStart(self: *const XMLHttpRequestEventTarget) ?js.Function {
|
||||
pub fn getOnLoadStart(self: *const XMLHttpRequestEventTarget) ?js.Function.Global {
|
||||
return self._on_load_start;
|
||||
}
|
||||
|
||||
@@ -131,7 +132,7 @@ pub fn setOnLoadStart(self: *XMLHttpRequestEventTarget, cb_: ?js.Function) !void
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getOnProgress(self: *const XMLHttpRequestEventTarget) ?js.Function {
|
||||
pub fn getOnProgress(self: *const XMLHttpRequestEventTarget) ?js.Function.Global {
|
||||
return self._on_progress;
|
||||
}
|
||||
|
||||
@@ -143,7 +144,7 @@ pub fn setOnProgress(self: *XMLHttpRequestEventTarget, cb_: ?js.Function) !void
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getOnTimeout(self: *const XMLHttpRequestEventTarget) ?js.Function {
|
||||
pub fn getOnTimeout(self: *const XMLHttpRequestEventTarget) ?js.Function.Global {
|
||||
return self._on_timeout;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,15 +43,15 @@ _state: State,
|
||||
_reader: ?*ReadableStreamDefaultReader,
|
||||
_controller: *ReadableStreamDefaultController,
|
||||
_stored_error: ?[]const u8,
|
||||
_pull_fn: ?js.Function = null,
|
||||
_pull_fn: ?js.Function.Global = null,
|
||||
_pulling: bool = false,
|
||||
_pull_again: bool = false,
|
||||
_cancel: ?Cancel = null,
|
||||
|
||||
const UnderlyingSource = struct {
|
||||
start: ?js.Function = null,
|
||||
pull: ?js.Function = null,
|
||||
cancel: ?js.Function = null,
|
||||
pull: ?js.Function.Global = null,
|
||||
cancel: ?js.Function.Global = null,
|
||||
type: ?[]const u8 = null,
|
||||
};
|
||||
|
||||
@@ -80,12 +80,12 @@ pub fn init(src_: ?UnderlyingSource, strategy_: ?QueueingStrategy, page: *Page)
|
||||
|
||||
if (src.cancel) |callback| {
|
||||
self._cancel = .{
|
||||
.callback = try callback.persist(),
|
||||
.callback = callback,
|
||||
};
|
||||
}
|
||||
|
||||
if (src.pull) |pull| {
|
||||
self._pull_fn = try pull.persist();
|
||||
self._pull_fn = pull;
|
||||
try self.callPullIfNeeded();
|
||||
}
|
||||
}
|
||||
@@ -137,12 +137,12 @@ pub fn callPullIfNeeded(self: *ReadableStream) !void {
|
||||
|
||||
self._pulling = true;
|
||||
|
||||
const pull_fn = self._pull_fn orelse return;
|
||||
const pull_fn = &(self._pull_fn orelse return);
|
||||
|
||||
// Call the pull function
|
||||
// Note: In a complete implementation, we'd handle the promise returned by pull
|
||||
// and set _pulling = false when it resolves
|
||||
try pull_fn.call(void, .{self._controller});
|
||||
try pull_fn.local().call(void, .{self._controller});
|
||||
|
||||
self._pulling = false;
|
||||
|
||||
@@ -170,7 +170,7 @@ pub fn cancel(self: *ReadableStream, reason: ?[]const u8, page: *Page) !js.Promi
|
||||
if (self._state != .readable) {
|
||||
if (self._cancel) |c| {
|
||||
if (c.resolver) |r| {
|
||||
return r.promise();
|
||||
return r.local().promise();
|
||||
}
|
||||
}
|
||||
return page.js.resolvePromise(.{});
|
||||
@@ -186,11 +186,11 @@ pub fn cancel(self: *ReadableStream, reason: ?[]const u8, page: *Page) !js.Promi
|
||||
}
|
||||
|
||||
// Execute the cancel callback if provided
|
||||
if (c.callback) |cb| {
|
||||
if (c.callback) |*cb| {
|
||||
if (reason) |r| {
|
||||
try cb.call(void, .{r});
|
||||
try cb.local().call(void, .{r});
|
||||
} else {
|
||||
try cb.call(void, .{});
|
||||
try cb.local().call(void, .{});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,19 +201,19 @@ pub fn cancel(self: *ReadableStream, reason: ?[]const u8, page: *Page) !js.Promi
|
||||
.done = true,
|
||||
.value = .empty,
|
||||
};
|
||||
for (self._controller._pending_reads.items) |resolver| {
|
||||
resolver.resolve("stream cancelled", result);
|
||||
for (self._controller._pending_reads.items) |*resolver| {
|
||||
resolver.local().resolve("stream cancelled", result);
|
||||
}
|
||||
self._controller._pending_reads.clearRetainingCapacity();
|
||||
|
||||
c.resolver.?.resolve("ReadableStream.cancel", {});
|
||||
return c.resolver.?.promise();
|
||||
c.resolver.?.local().resolve("ReadableStream.cancel", {});
|
||||
return c.resolver.?.local().promise();
|
||||
}
|
||||
|
||||
const Cancel = struct {
|
||||
callback: ?js.Function = null,
|
||||
callback: ?js.Function.Global = null,
|
||||
reason: ?[]const u8 = null,
|
||||
resolver: ?js.PromiseResolver = null,
|
||||
resolver: ?js.PromiseResolver.Global = null,
|
||||
};
|
||||
|
||||
pub const JsApi = struct {
|
||||
|
||||
@@ -42,7 +42,7 @@ _page: *Page,
|
||||
_stream: *ReadableStream,
|
||||
_arena: std.mem.Allocator,
|
||||
_queue: std.ArrayList(Chunk),
|
||||
_pending_reads: std.ArrayList(js.PromiseResolver),
|
||||
_pending_reads: std.ArrayList(js.PromiseResolver.Global),
|
||||
_high_water_mark: u32,
|
||||
|
||||
pub fn init(stream: *ReadableStream, high_water_mark: u32, page: *Page) !*ReadableStreamDefaultController {
|
||||
@@ -59,7 +59,7 @@ pub fn init(stream: *ReadableStream, high_water_mark: u32, page: *Page) !*Readab
|
||||
pub fn addPendingRead(self: *ReadableStreamDefaultController, page: *Page) !js.Promise {
|
||||
const resolver = try page.js.createPromiseResolver().persist();
|
||||
try self._pending_reads.append(self._arena, resolver);
|
||||
return resolver.promise();
|
||||
return resolver.local().promise();
|
||||
}
|
||||
|
||||
pub fn enqueue(self: *ReadableStreamDefaultController, chunk: Chunk) !void {
|
||||
@@ -79,7 +79,7 @@ pub fn enqueue(self: *ReadableStreamDefaultController, chunk: Chunk) !void {
|
||||
.done = false,
|
||||
.value = .fromChunk(chunk),
|
||||
};
|
||||
resolver.resolve("stream enqueue", result);
|
||||
resolver.local().resolve("stream enqueue", result);
|
||||
}
|
||||
|
||||
pub fn close(self: *ReadableStreamDefaultController) !void {
|
||||
@@ -94,8 +94,8 @@ pub fn close(self: *ReadableStreamDefaultController) !void {
|
||||
.done = true,
|
||||
.value = .empty,
|
||||
};
|
||||
for (self._pending_reads.items) |resolver| {
|
||||
resolver.resolve("stream close", result);
|
||||
for (self._pending_reads.items) |*resolver| {
|
||||
resolver.local().resolve("stream close", result);
|
||||
}
|
||||
self._pending_reads.clearRetainingCapacity();
|
||||
}
|
||||
@@ -109,8 +109,8 @@ pub fn doError(self: *ReadableStreamDefaultController, err: []const u8) !void {
|
||||
self._stream._stored_error = try self._page.arena.dupe(u8, err);
|
||||
|
||||
// Reject all pending reads
|
||||
for (self._pending_reads.items) |resolver| {
|
||||
resolver.reject("stream errror", err);
|
||||
for (self._pending_reads.items) |*resolver| {
|
||||
resolver.local().reject("stream errror", err);
|
||||
}
|
||||
self._pending_reads.clearRetainingCapacity();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user