mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-07-31 09:46:05 -04:00
We typically persist a v8::Value by calling persist() or temp() on our v8 wrappers. Both persist() and temp() create a v8::Global, but persist() tracks it in the page's globals ArrayList while temp() tracks it in the page's temps HashMap. Globals are only freed when the page is torn down, hence a simple ArrayList is all we need. Temps can be freed at any point, hence HashMap is used. (Temps are also freed on teardown, but they can be freed before that too). This commit removes Temp (js.Value.Temp, js.Promise.Temp, js.Function.Temp) and all the mechinery around them (e.g. pseudo Global generic). There are now only Globals and any global can be freed at any time (while still being tracked in the page in order to be able to free any un-freed on page teardown). Many files were touched because .Temp -> .Global and .temp() -> .persist(). This commit is based off the indexeddb branch because indexeddb introduced "bare" globals (globals which aren't tracked by the Page). Building this new model to include "Bare" globals avoids a messy merge later.
160 lines
4.9 KiB
Zig
160 lines
4.9 KiB
Zig
// Copyright (C) 2023-2026 Lightpanda (Selecy SAS)
|
|
//
|
|
// Francis Bouvier <francis@lightpanda.io>
|
|
// Pierre Tachoire <pierre@lightpanda.io>
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as
|
|
// published by the Free Software Foundation, either version 3 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
const std = @import("std");
|
|
const lp = @import("lightpanda");
|
|
|
|
const js = @import("../../js/js.zig");
|
|
const Page = @import("../../Page.zig");
|
|
|
|
const Event = @import("../Event.zig");
|
|
const MessagePort = @import("../MessagePort.zig");
|
|
const Window = @import("../Window.zig");
|
|
|
|
const String = lp.String;
|
|
const Allocator = std.mem.Allocator;
|
|
const IS_DEBUG = @import("builtin").mode == .Debug;
|
|
|
|
const MessageEvent = @This();
|
|
|
|
_proto: *Event,
|
|
_data: ?Data = null,
|
|
_origin: []const u8 = "",
|
|
_source: ?*Window = null,
|
|
_ports: []const *MessagePort = &.{},
|
|
|
|
const MessageEventOptions = struct {
|
|
data: ?Data = null,
|
|
origin: ?[]const u8 = null,
|
|
source: ?*Window = null,
|
|
ports: []const *MessagePort = &.{},
|
|
};
|
|
|
|
pub const Data = union(enum) {
|
|
value: js.Value.Global,
|
|
string: []const u8,
|
|
arraybuffer: js.ArrayBuffer,
|
|
blob: *@import("../Blob.zig"),
|
|
};
|
|
|
|
const Options = Event.inheritOptions(MessageEvent, MessageEventOptions);
|
|
|
|
pub fn init(typ: []const u8, opts_: ?Options, page: *Page) !*MessageEvent {
|
|
const arena = try page.getArena(.small, "MessageEvent");
|
|
errdefer page.releaseArena(arena);
|
|
const type_string = try String.init(arena, typ, .{});
|
|
return initWithTrusted(arena, type_string, opts_, false, page);
|
|
}
|
|
|
|
pub fn initTrusted(typ: String, opts_: ?Options, page: *Page) !*MessageEvent {
|
|
const arena = try page.getArena(.small, "MessageEvent.trusted");
|
|
errdefer page.releaseArena(arena);
|
|
return initWithTrusted(arena, typ, opts_, true, page);
|
|
}
|
|
|
|
fn initWithTrusted(arena: Allocator, typ: String, opts_: ?Options, trusted: bool, page: *Page) !*MessageEvent {
|
|
const opts = opts_ orelse Options{};
|
|
|
|
const event = try page.factory.event(
|
|
arena,
|
|
typ,
|
|
MessageEvent{
|
|
._proto = undefined,
|
|
._data = opts.data,
|
|
._origin = if (opts.origin) |str| try arena.dupe(u8, str) else "",
|
|
._source = opts.source,
|
|
._ports = if (opts.ports.len == 0) &.{} else try arena.dupe(*MessagePort, opts.ports),
|
|
},
|
|
);
|
|
|
|
Event.populatePrototypes(event, opts, trusted);
|
|
return event;
|
|
}
|
|
|
|
pub fn deinit(self: *MessageEvent, page: *Page) void {
|
|
if (self._data) |d| {
|
|
switch (d) {
|
|
.value => |js_val| js_val.release(),
|
|
.blob => |blob| blob.releaseRef(page),
|
|
.string, .arraybuffer => {},
|
|
}
|
|
}
|
|
self._proto.deinit(page);
|
|
}
|
|
|
|
pub fn acquireRef(self: *MessageEvent) void {
|
|
self._proto.acquireRef();
|
|
}
|
|
|
|
pub fn releaseRef(self: *MessageEvent, page: *Page) void {
|
|
self._proto._rc.release(self, page);
|
|
}
|
|
|
|
pub fn asEvent(self: *MessageEvent) *Event {
|
|
return self._proto;
|
|
}
|
|
|
|
pub fn getData(self: *const MessageEvent) ?Data {
|
|
return self._data;
|
|
}
|
|
|
|
pub fn getOrigin(self: *const MessageEvent) []const u8 {
|
|
return self._origin;
|
|
}
|
|
|
|
pub fn getSource(self: *const MessageEvent, exec: *js.Execution) ?Window.Access {
|
|
switch (exec.js.global) {
|
|
.frame => |frame| {
|
|
const source = self._source orelse return null;
|
|
return Window.Access.init(frame.window, source);
|
|
},
|
|
.worker => {
|
|
// source for worker should always be null
|
|
if (comptime IS_DEBUG) {
|
|
std.debug.assert(self._source == null);
|
|
}
|
|
return null;
|
|
},
|
|
}
|
|
}
|
|
|
|
pub fn getPorts(self: *const MessageEvent) []const *MessagePort {
|
|
return self._ports;
|
|
}
|
|
|
|
pub const JsApi = struct {
|
|
pub const bridge = js.Bridge(MessageEvent);
|
|
|
|
pub const Meta = struct {
|
|
pub const name = "MessageEvent";
|
|
pub const prototype_chain = bridge.prototypeChain();
|
|
pub var class_id: bridge.ClassId = undefined;
|
|
};
|
|
|
|
pub const constructor = bridge.constructor(MessageEvent.init, .{});
|
|
pub const data = bridge.accessor(MessageEvent.getData, null, .{});
|
|
pub const origin = bridge.accessor(MessageEvent.getOrigin, null, .{});
|
|
pub const source = bridge.accessor(MessageEvent.getSource, null, .{});
|
|
pub const ports = bridge.accessor(MessageEvent.getPorts, null, .{});
|
|
};
|
|
|
|
const testing = @import("../../../testing.zig");
|
|
test "WebApi: MessageEvent" {
|
|
try testing.htmlRunner("event/message.html", .{});
|
|
}
|