mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-03-30 17:18:57 +00:00
The introduction of frames means that data is no longer tied to a specific Page
or Context. 255b9a91cc introduced Origins for
v8 values shared across frames of the same origin. The commit highlighted the
lifetime mismatched that we now have with data that can outlive 1 frame. A
specific issue with that commit was the finalizers were still Context-owned.
But like any other piece of data, that isn't right; aside from modules, nothing
should be context-owned.
This commit continues where the last left off and moves finalizers from Context
to Origin. This is done in a separate commit because it introduces significant
changes. Currently, finalizers take a *Page, but that's no longer correct. A
value created in one Page, can outlive the Page. We need another container. I
original thought to use Origin, but that isn't know to CDP/MCP. Instead, I
decide to enhance the Session.
Session is now the owner of the page.arena, the page.factory and the
page.arena_pool. Finalizers are given a *Session which they can use to release
their arena.
117 lines
3.4 KiB
Zig
117 lines
3.4 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 String = @import("../../../string.zig").String;
|
|
const Page = @import("../../Page.zig");
|
|
const Session = @import("../../Session.zig");
|
|
const js = @import("../../js/js.zig");
|
|
|
|
const Event = @import("../Event.zig");
|
|
const UIEvent = @import("UIEvent.zig");
|
|
|
|
const TextEvent = @This();
|
|
|
|
_proto: *UIEvent,
|
|
_data: []const u8 = "",
|
|
|
|
pub const TextEventOptions = struct {
|
|
data: ?[]const u8 = null,
|
|
};
|
|
|
|
pub const Options = Event.inheritOptions(
|
|
TextEvent,
|
|
TextEventOptions,
|
|
);
|
|
|
|
pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*TextEvent {
|
|
const arena = try page.getArena(.{ .debug = "TextEvent" });
|
|
errdefer page.releaseArena(arena);
|
|
const type_string = try String.init(arena, typ, .{});
|
|
|
|
const opts = _opts orelse Options{};
|
|
|
|
const event = try page._factory.uiEvent(
|
|
arena,
|
|
type_string,
|
|
TextEvent{
|
|
._proto = undefined,
|
|
._data = if (opts.data) |str| try arena.dupe(u8, str) else "",
|
|
},
|
|
);
|
|
|
|
Event.populatePrototypes(event, opts, false);
|
|
return event;
|
|
}
|
|
|
|
pub fn deinit(self: *TextEvent, shutdown: bool, session: *Session) void {
|
|
self._proto.deinit(shutdown, session);
|
|
}
|
|
|
|
pub fn asEvent(self: *TextEvent) *Event {
|
|
return self._proto.asEvent();
|
|
}
|
|
|
|
pub fn getData(self: *const TextEvent) []const u8 {
|
|
return self._data;
|
|
}
|
|
|
|
pub fn initTextEvent(
|
|
self: *TextEvent,
|
|
typ: []const u8,
|
|
bubbles: bool,
|
|
cancelable: bool,
|
|
view: ?*@import("../Window.zig"),
|
|
data: []const u8,
|
|
) !void {
|
|
_ = view; // view parameter is ignored in modern implementations
|
|
|
|
const event = self._proto._proto;
|
|
if (event._event_phase != .none) {
|
|
// Only allow initialization if event hasn't been dispatched
|
|
return;
|
|
}
|
|
|
|
const arena = event._arena;
|
|
event._type_string = try String.init(arena, typ, .{});
|
|
event._bubbles = bubbles;
|
|
event._cancelable = cancelable;
|
|
self._data = try arena.dupe(u8, data);
|
|
}
|
|
|
|
pub const JsApi = struct {
|
|
pub const bridge = js.Bridge(TextEvent);
|
|
|
|
pub const Meta = struct {
|
|
pub const name = "TextEvent";
|
|
pub const prototype_chain = bridge.prototypeChain();
|
|
pub var class_id: bridge.ClassId = undefined;
|
|
pub const weak = true;
|
|
pub const finalizer = bridge.finalizer(TextEvent.deinit);
|
|
};
|
|
|
|
// No constructor - TextEvent is created via document.createEvent('TextEvent')
|
|
pub const data = bridge.accessor(TextEvent.getData, null, .{});
|
|
pub const initTextEvent = bridge.function(TextEvent.initTextEvent, .{});
|
|
};
|
|
|
|
const testing = @import("../../../testing.zig");
|
|
test "WebApi: TextEvent" {
|
|
try testing.htmlRunner("event/text.html", .{});
|
|
}
|