refactor: Introduce Arena wrapper

Introduces a ArenaAllocator wrappre (lp.Arena). This is groundwork for better
memory tracking and reporting memory usage to v8. This is almost purely a
mechanical change to lay a foundation for a follow up PR that will address
https://github.com/lightpanda-io/browser/issues/3027

Some code became a bit leaner: a pooled arena can release itself (it has a
reference to the ArenaPool).

Some code became uglier: The Frame has a `_local_arena: *lp.Arena` and a
`local_arena: Allocator` (same with call_arena, and same with a few other types)
so that consumers aren't impacted (they continue to use `frame.local_arena`).
This commit is contained in:
Karl Seguin committed 2026-07-30 13:02:13 +08:00
1 parent 5aa1f0619c
commit bdce49a4b5
123 files changed
+971 -961

No files matched your search

+79
View File
@@ -0,0 +1,79 @@
// 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/>.
// An arena checked out of an ArenaPool. Owners hold the *Arena and release it
// when they're done with it; everything downstream takes the plain Allocator
// from allocator().
//
// Never copy an Arena by value: the Allocator it hands out points back into it.
const std = @import("std");
const builtin = @import("builtin");
const ArenaPool = @import("ArenaPool.zig");
const Allocator = std.mem.Allocator;
const ArenaAllocator = std.heap.ArenaAllocator;
const Arena = @This();
const IS_DEBUG = builtin.mode == .Debug;
// In Debug, don't pool and don't retain capacity. Both can mask UAF.
pub const SAFETY = IS_DEBUG == true and builtin.is_test == false;
_arena: ArenaAllocator,
pool: *ArenaPool,
bucket: *ArenaPool.Bucket,
// Only meaningful while this arena sits in its bucket's free list.
next: ?*Arena,
debug: if (IS_DEBUG) []const u8 else void = if (IS_DEBUG) "" else {},
pub fn allocator(self: *Arena) Allocator {
return self._arena.allocator();
}
pub fn release(self: *Arena) void {
self.pool.release(self);
}
pub fn reset(self: *Arena, retain: usize) void {
_ = self._arena.reset(if (comptime SAFETY) .free_all else .{ .retain_with_limit = retain });
}
pub fn resetRetain(self: *Arena) void {
_ = self._arena.reset(if (comptime SAFETY) .free_all else .retain_capacity);
}
pub fn alloc(self: *Arena, comptime T: type, n: usize) ![]T {
return self.allocator().alloc(T, n);
}
pub fn create(self: *Arena, comptime T: type) !*T {
return self.allocator().create(T);
}
pub fn dupe(self: *Arena, comptime T: type, m: []const T) ![]T {
return self.allocator().dupe(T, m);
}
pub fn dupeZ(self: *Arena, comptime T: type, m: []const T) ![:0]T {
return self.allocator().dupeZ(T, m);
}
+42 -61
View File
@@ -20,6 +20,8 @@ const std = @import("std");
const lp = @import("lightpanda");
const builtin = @import("builtin");
const Arena = @import("Arena.zig");
const log = lp.log;
const Allocator = std.mem.Allocator;
const ArenaAllocator = std.heap.ArenaAllocator;
@@ -27,26 +29,17 @@ const ArenaAllocator = std.heap.ArenaAllocator;
const ArenaPool = @This();
const IS_DEBUG = builtin.mode == .Debug;
// In Debug, disable pooling to better catch UAF.
const SAFETY = IS_DEBUG == true and builtin.is_test == false;
const SAFETY = Arena.SAFETY;
pub const BucketSize = enum { tiny, small, medium, large };
const Bucket = struct {
free_list: ?*Entry = null,
pub const Bucket = struct {
free_list: ?*Arena = null,
free_list_len: u16 = 0,
free_list_max: u16,
retain_bytes: usize,
};
const Entry = struct {
next: ?*Entry,
arena: ArenaAllocator,
bucket: *Bucket,
debug: if (IS_DEBUG) []const u8 else void = if (IS_DEBUG) "" else {},
};
pub const Config = struct {
tiny: Config.Bucket = .{ .max = 512, .retain = 1024 },
small: Config.Bucket = .{ .max = 128, .retain = 4 * 1024 },
@@ -65,7 +58,7 @@ medium: Bucket,
large: Bucket,
allocator: Allocator,
mutex: std.Io.Mutex = .init,
entry_pool: std.heap.MemoryPool(Entry),
entry_pool: std.heap.MemoryPool(Arena),
_leak_track: if (IS_DEBUG) std.StringHashMapUnmanaged(isize) else void = if (IS_DEBUG) .empty else {},
@@ -101,7 +94,7 @@ pub fn deinit(self: *ArenaPool) void {
var entry = bucket.free_list;
while (entry) |e| {
entry = e.next;
e.arena.deinit();
e._arena.deinit();
}
}
self.entry_pool.deinit(self.allocator);
@@ -110,7 +103,7 @@ pub fn deinit(self: *ArenaPool) void {
// Acquire an arena from the pool.
// - Pass a BucketSize (.tiny, .small, .medium, .large) for explicit bucket selection
// - Pass a usize for automatic bucket selection based on expected size
pub fn acquire(self: *ArenaPool, size_or_bucket: anytype, debug: []const u8) !Allocator {
pub fn acquire(self: *ArenaPool, size_or_bucket: anytype, debug: []const u8) !*Arena {
const bucket_size: BucketSize = blk: {
const T = @TypeOf(size_or_bucket);
if (T == BucketSize or T == @TypeOf(.enum_literal)) {
@@ -147,7 +140,7 @@ pub fn acquire(self: *ArenaPool, size_or_bucket: anytype, debug: []const u8) !Al
gop.value_ptr.* += 1;
}
lp.metrics.arena_hit.incr(bucket_size);
return entry.arena.allocator();
return entry;
}
lp.metrics.arena_miss.incr(bucket_size);
@@ -155,9 +148,10 @@ pub fn acquire(self: *ArenaPool, size_or_bucket: anytype, debug: []const u8) !Al
const entry = try self.entry_pool.create(self.allocator);
entry.* = .{
.next = null,
.pool = self,
.bucket = bucket,
.debug = if (IS_DEBUG) debug else {},
.arena = ArenaAllocator.init(self.allocator),
._arena = ArenaAllocator.init(self.allocator),
};
if (IS_DEBUG) {
@@ -167,13 +161,12 @@ pub fn acquire(self: *ArenaPool, size_or_bucket: anytype, debug: []const u8) !Al
}
gop.value_ptr.* += 1;
}
return entry.arena.allocator();
return entry;
}
// Universal release - determines bucket from the Entry automatically
pub fn release(self: *ArenaPool, allocator: Allocator) void {
const arena: *ArenaAllocator = @ptrCast(@alignCast(allocator.ptr));
const entry: *Entry = @fieldParentPtr("arena", arena);
// Prefer Arena.release(). Determines the bucket from the Arena automatically.
pub fn release(self: *ArenaPool, entry: *Arena) void {
const arena = &entry._arena;
const bucket = entry.bucket;
if (IS_DEBUG) {
@@ -208,18 +201,6 @@ pub fn release(self: *ArenaPool, allocator: Allocator) void {
bucket.free_list_len += 1;
}
pub fn reset(_: *const ArenaPool, allocator: Allocator, retain: usize) void {
const arena: *ArenaAllocator = @ptrCast(@alignCast(allocator.ptr));
// In Debug, free_all, it's less likely to hide things
_ = arena.reset(if (comptime SAFETY) .free_all else .{ .retain_with_limit = retain });
}
pub fn resetRetain(_: *const ArenaPool, allocator: Allocator) void {
const arena: *ArenaAllocator = @ptrCast(@alignCast(allocator.ptr));
// In Debug, free_all, it's less likely to hide things
_ = arena.reset(if (comptime SAFETY) .free_all else .retain_capacity);
}
const testing = std.testing;
test "ArenaPool: basic acquire and release" {
var pool = ArenaPool.init(testing.allocator, .{});
@@ -230,17 +211,17 @@ test "ArenaPool: basic acquire and release" {
const large = try pool.acquire(.large, "test-large");
// All three must be distinct arenas
try testing.expect(tiny.ptr != medium.ptr);
try testing.expect(medium.ptr != large.ptr);
try testing.expect(tiny != medium);
try testing.expect(medium != large);
_ = try tiny.alloc(u8, 64);
_ = try medium.alloc(u8, 1024);
_ = try large.alloc(u8, 4096);
// Universal release works for all buckets
pool.release(tiny);
pool.release(medium);
pool.release(large);
tiny.release();
medium.release();
large.release();
try testing.expectEqual(1, pool.tiny.free_list_len);
try testing.expectEqual(1, pool.medium.free_list_len);
@@ -252,20 +233,20 @@ test "ArenaPool: reuse from correct bucket" {
defer pool.deinit();
const tiny1 = try pool.acquire(.tiny, "test");
pool.release(tiny1);
tiny1.release();
try testing.expectEqual(1, pool.tiny.free_list_len);
// Next acquire with .tiny should reuse from tiny bucket
const tiny2 = try pool.acquire(.tiny, "test");
try testing.expectEqual(0, pool.tiny.free_list_len);
try testing.expectEqual(tiny1.ptr, tiny2.ptr);
try testing.expectEqual(tiny1, tiny2);
// acquire with .medium should NOT get the tiny arena
const medium = try pool.acquire(.medium, "test-medium");
try testing.expect(medium.ptr != tiny2.ptr);
try testing.expect(medium != tiny2);
pool.release(tiny2);
pool.release(medium);
tiny2.release();
medium.release();
}
test "ArenaPool: respects per-bucket max limits" {
@@ -282,11 +263,11 @@ test "ArenaPool: respects per-bucket max limits" {
const t3 = try pool.acquire(.tiny, "t3");
// Release all 3, but only 1 should be kept (tiny_max = 1)
pool.release(t1);
t1.release();
try testing.expectEqual(1, pool.tiny.free_list_len);
pool.release(t2);
t2.release();
try testing.expectEqual(1, pool.tiny.free_list_len); // still 1, t2 discarded
pool.release(t3);
t3.release();
try testing.expectEqual(1, pool.tiny.free_list_len); // still 1, t3 discarded
// Acquire 3 medium arenas
@@ -295,9 +276,9 @@ test "ArenaPool: respects per-bucket max limits" {
const m3 = try pool.acquire(.medium, "m3");
// Release all 3, but only 2 should be kept (medium_max = 2)
pool.release(m1);
pool.release(m2);
pool.release(m3);
m1.release();
m2.release();
m3.release();
try testing.expectEqual(2, pool.medium.free_list_len);
}
@@ -311,7 +292,7 @@ test "ArenaPool: reset clears memory without releasing" {
@memset(buf, 0xFF);
// reset() frees arena memory but keeps the allocator in-flight.
pool.reset(alloc, 0);
alloc.reset(0);
// The free list must stay empty; the allocator was not released.
try testing.expectEqual(0, pool.medium.free_list_len);
@@ -321,7 +302,7 @@ test "ArenaPool: reset clears memory without releasing" {
@memset(buf2, 0x00);
try testing.expectEqual(@as(u8, 0x00), buf2[0]);
pool.release(alloc);
alloc.release();
}
test "ArenaPool: deinit with entries in free list" {
@@ -333,8 +314,8 @@ test "ArenaPool: deinit with entries in free list" {
const a2 = try pool.acquire(.medium, "test2");
_ = try a1.alloc(u8, 256);
_ = try a2.alloc(u8, 512);
pool.release(a1);
pool.release(a2);
a1.release();
a2.release();
try testing.expectEqual(1, pool.tiny.free_list_len);
try testing.expectEqual(1, pool.medium.free_list_len);
@@ -351,9 +332,9 @@ test "ArenaPool: small bucket" {
const s2 = try pool.acquire(.small, "s2");
const s3 = try pool.acquire(.small, "s3");
pool.release(s1);
pool.release(s2);
pool.release(s3);
s1.release();
s2.release();
s3.release();
try testing.expectEqual(2, pool.small.free_list_len);
}
@@ -371,10 +352,10 @@ test "ArenaPool: size-based acquire" {
// > 16KB -> large
const d = try pool.acquire(20000, "fits-large");
pool.release(a);
pool.release(b);
pool.release(c);
pool.release(d);
a.release();
b.release();
c.release();
d.release();
try testing.expectEqual(1, pool.tiny.free_list_len);
try testing.expectEqual(1, pool.small.free_list_len);
+24 -27
View File
@@ -30,9 +30,6 @@ const lp = @import("lightpanda");
const CDP = @import("cdp/CDP.zig");
const ArenaPool = @import("ArenaPool.zig");
const Allocator = std.mem.Allocator;
const DoublyLinkedList = std.DoublyLinkedList;
const Inbox = @This();
@@ -47,16 +44,16 @@ queue: DoublyLinkedList = .{},
// a syncRequest and we want the following non-nested tick to pick it up again.
terminated: bool = false,
pub fn deinit(self: *Inbox, arena_pool: *ArenaPool) void {
pub fn deinit(self: *Inbox) void {
self.mutex.lockUncancelable(lp.io);
defer self.mutex.unlock(lp.io);
while (self.queue.popFirst()) |node| {
const msg: *Message = @fieldParentPtr("node", node);
msg.deinit(arena_pool);
msg.deinit();
}
}
pub fn push(self: *Inbox, arena: Allocator, payload: Message.Payload) void {
pub fn push(self: *Inbox, arena: *lp.Arena, payload: Message.Payload) void {
const msg = arena.create(Message) catch |err| switch (err) {
error.OutOfMemory => @panic("OOM"),
};
@@ -109,7 +106,7 @@ pub fn popIf(self: *Inbox, predicate: *const fn (*Message) bool) ?*Message {
}
pub const Message = struct {
arena: Allocator,
arena: *lp.Arena,
payload: Payload,
node: DoublyLinkedList.Node = .{},
@@ -145,8 +142,8 @@ pub const Message = struct {
input: CDP.InputMessage,
};
pub fn deinit(self: *const Message, pool: *ArenaPool) void {
pool.release(self.arena);
pub fn deinit(self: *const Message) void {
self.arena.release();
}
};
@@ -155,7 +152,7 @@ test "Inbox: push then pop returns FIFO order" {
const arena_pool = &testing.test_app.arena_pool;
var inbox = Inbox{};
defer inbox.deinit(&testing.test_app.arena_pool);
defer inbox.deinit();
{
const arena = try arena_pool.acquire(.tiny, "inbox test");
@@ -174,17 +171,17 @@ test "Inbox: push then pop returns FIFO order" {
{
const m = inbox.pop().?;
defer m.deinit(arena_pool);
defer m.deinit();
try testing.expectEqual("first", m.payload.ping);
}
{
const m = inbox.pop().?;
defer m.deinit(arena_pool);
defer m.deinit();
try testing.expectEqual("second", m.payload.ping);
}
{
const m = inbox.pop().?;
defer m.deinit(arena_pool);
defer m.deinit();
try testing.expectEqual(@as(?anyerror, null), m.payload.disconnect);
}
try testing.expect(inbox.pop() == null);
@@ -203,7 +200,7 @@ test "Inbox: deinit frees remaining items" {
inbox.push(arena, .{ .disconnect = error.PeerClosed });
}
inbox.deinit(&testing.test_app.arena_pool);
inbox.deinit();
// Memory leaks would be caught by the test runner.
}
@@ -221,14 +218,14 @@ fn testIsPing(msg: *Message) bool {
test "Inbox: popIf on empty queue returns null" {
var inbox = Inbox{};
defer inbox.deinit(&testing.test_app.arena_pool);
defer inbox.deinit();
try testing.expect(inbox.popIf(testAlwaysTrue) == null);
}
test "Inbox: popIf with no match leaves queue intact" {
const arena_pool = &testing.test_app.arena_pool;
var inbox = Inbox{};
defer inbox.deinit(arena_pool);
defer inbox.deinit();
{
const arena = try arena_pool.acquire(.tiny, "popif test");
@@ -244,12 +241,12 @@ test "Inbox: popIf with no match leaves queue intact" {
// Original FIFO order preserved.
{
const m = inbox.pop().?;
defer m.deinit(arena_pool);
defer m.deinit();
try testing.expectEqual("first", m.payload.ping);
}
{
const m = inbox.pop().?;
defer m.deinit(arena_pool);
defer m.deinit();
try testing.expectEqual("second", m.payload.ping);
}
try testing.expect(inbox.pop() == null);
@@ -258,7 +255,7 @@ test "Inbox: popIf with no match leaves queue intact" {
test "Inbox: popIf with always-true predicate behaves like pop" {
const arena_pool = &testing.test_app.arena_pool;
var inbox = Inbox{};
defer inbox.deinit(arena_pool);
defer inbox.deinit();
{
const arena = try arena_pool.acquire(.tiny, "popif test");
@@ -271,12 +268,12 @@ test "Inbox: popIf with always-true predicate behaves like pop" {
{
const m = inbox.popIf(testAlwaysTrue).?;
defer m.deinit(arena_pool);
defer m.deinit();
try testing.expectEqual("a", m.payload.ping);
}
{
const m = inbox.popIf(testAlwaysTrue).?;
defer m.deinit(arena_pool);
defer m.deinit();
try testing.expectEqual("b", m.payload.ping);
}
try testing.expect(inbox.popIf(testAlwaysTrue) == null);
@@ -285,7 +282,7 @@ test "Inbox: popIf with always-true predicate behaves like pop" {
test "Inbox: popIf cherry-picks middle, preserves order of remainder" {
const arena_pool = &testing.test_app.arena_pool;
var inbox = Inbox{};
defer inbox.deinit(arena_pool);
defer inbox.deinit();
{
const arena = try arena_pool.acquire(.tiny, "popif test");
@@ -303,19 +300,19 @@ test "Inbox: popIf cherry-picks middle, preserves order of remainder" {
// testIsPing skips the disconnect at the head and picks the middle.
{
const m = inbox.popIf(testIsPing).?;
defer m.deinit(arena_pool);
defer m.deinit();
try testing.expectEqual("middle", m.payload.ping);
}
// Remaining two disconnects pop in original order.
{
const m = inbox.pop().?;
defer m.deinit(arena_pool);
defer m.deinit();
try testing.expect(m.payload.disconnect == null);
}
{
const m = inbox.pop().?;
defer m.deinit(arena_pool);
defer m.deinit();
try testing.expect(m.payload.disconnect.? == error.PeerClosed);
}
try testing.expect(inbox.pop() == null);
@@ -324,7 +321,7 @@ test "Inbox: popIf cherry-picks middle, preserves order of remainder" {
test "Inbox: popIf picks first match in FIFO order" {
const arena_pool = &testing.test_app.arena_pool;
var inbox = Inbox{};
defer inbox.deinit(arena_pool);
defer inbox.deinit();
{
const arena = try arena_pool.acquire(.tiny, "popif test");
@@ -340,6 +337,6 @@ test "Inbox: popIf picks first match in FIFO order" {
}
const m = inbox.popIf(testIsPing).?;
defer m.deinit(arena_pool);
defer m.deinit();
try testing.expectEqual("first", m.payload.ping);
}
+10 -10
View File
@@ -77,10 +77,10 @@ pub fn eventTargetWithAllocator(_: *const Factory, allocator: Allocator, child:
}
// this is a root object
pub fn event(_: *const Factory, arena: Allocator, typ: String, child: anytype) !*@TypeOf(child) {
pub fn event(_: *const Factory, arena: *lp.Arena, typ: String, child: anytype) !*@TypeOf(child) {
const chain = try PrototypeChain(
&.{ Event, @TypeOf(child) },
).allocate(arena);
).allocate(arena.allocator());
// Special case: Event has a _type_string field, so we need manual setup
const event_ptr = chain.get(0);
@@ -90,10 +90,10 @@ pub fn event(_: *const Factory, arena: Allocator, typ: String, child: anytype) !
return chain.get(1);
}
pub fn uiEvent(_: *const Factory, arena: Allocator, typ: String, child: anytype) !*@TypeOf(child) {
pub fn uiEvent(_: *const Factory, arena: *lp.Arena, typ: String, child: anytype) !*@TypeOf(child) {
const chain = try PrototypeChain(
&.{ Event, UIEvent, @TypeOf(child) },
).allocate(arena);
).allocate(arena.allocator());
// Special case: Event has a _type_string field, so we need manual setup
const event_ptr = chain.get(0);
@@ -104,10 +104,10 @@ pub fn uiEvent(_: *const Factory, arena: Allocator, typ: String, child: anytype)
return chain.get(2);
}
pub fn mouseEvent(_: *const Factory, arena: Allocator, typ: String, mouse: MouseEvent, child: anytype) !*@TypeOf(child) {
pub fn mouseEvent(_: *const Factory, arena: *lp.Arena, typ: String, mouse: MouseEvent, child: anytype) !*@TypeOf(child) {
const chain = try PrototypeChain(
&.{ Event, UIEvent, MouseEvent, @TypeOf(child) },
).allocate(arena);
).allocate(arena.allocator());
// Special case: Event has a _type_string field, so we need manual setup
const event_ptr = chain.get(0);
@@ -236,7 +236,7 @@ fn AutoPrototypeChain(comptime types: []const type) type {
};
}
fn eventInit(arena: Allocator, typ: String, value: anytype) !Event {
fn eventInit(arena: *lp.Arena, typ: String, value: anytype) !Event {
// Round to 2ms for privacy (browsers do this)
// Same (already coarsened) clock as the performance time origin, so the
// timeStamp getter can report it relative to that origin.
@@ -255,7 +255,7 @@ pub fn blob(_: *const Factory, arena: Allocator, child: anytype) !*@TypeOf(child
// Special case: Blob has slice and mime fields, so we need manual setup
const chain = try PrototypeChain(
&.{ Blob, @TypeOf(child) },
).allocate(arena);
).allocate(arena.allocator());
const blob_ptr = chain.get(0);
blob_ptr.* = .{
@@ -270,8 +270,8 @@ pub fn blob(_: *const Factory, arena: Allocator, child: anytype) !*@TypeOf(child
return chain.get(1);
}
pub fn abstractRange(_: *const Factory, arena: Allocator, child: anytype, frame: *Frame) !*@TypeOf(child) {
const chain = try PrototypeChain(&.{ AbstractRange, @TypeOf(child) }).allocate(arena);
pub fn abstractRange(_: *const Factory, arena: *lp.Arena, child: anytype, frame: *Frame) !*@TypeOf(child) {
const chain = try PrototypeChain(&.{ AbstractRange, @TypeOf(child) }).allocate(arena.allocator());
const doc = frame.document.asNode();
const abstract_range = chain.get(0);
+41 -41
View File
@@ -298,10 +298,12 @@ arena: Allocator,
// An arena with a lifetime for at least the scope of one Zig invocation from
// JS. Prefer local_arena where possible. Use call_arena when allocations may
// need to call back into JS (event dispatch, forEach callback, ....)
_call_arena: *lp.Arena,
call_arena: Allocator,
// An arena with a lifetime guaranteed to be for exactly 1 invoking of a Zig
// function from JS. Best arena to use, when possible.
_local_arena: *lp.Arena,
local_arena: Allocator,
parent: ?*Frame,
@@ -358,10 +360,10 @@ pub fn init(self: *Frame, frame_id: u32, page: *Page, opts: InitOpts) !void {
const session = page.session;
const call_arena = try session.getArena(.medium, "call_arena");
errdefer session.releaseArena(call_arena);
errdefer call_arena.release();
const local_arena = try session.getArena(.medium, "local_arena");
errdefer session.releaseArena(local_arena);
errdefer local_arena.release();
const factory = &page.factory;
const document = (try factory.document(Node.Document.HTMLDocument{
@@ -376,8 +378,10 @@ pub fn init(self: *Frame, frame_id: u32, page: *Page, opts: InitOpts) !void {
.parent = parent,
.document = document,
.window = undefined,
.call_arena = call_arena,
.local_arena = local_arena,
._call_arena = call_arena,
._local_arena = local_arena,
.call_arena = call_arena.allocator(),
.local_arena = local_arena.allocator(),
._frame_id = frame_id,
._page = page,
._session = session,
@@ -491,7 +495,7 @@ pub fn deinit(self: *Frame) void {
const page = self._page;
if (self._queued_navigation) |qn| {
page.releaseArena(qn.arena);
qn.arena.release();
}
while (self._message_ports.first) |node| {
@@ -549,8 +553,8 @@ pub fn deinit(self: *Frame) void {
self._script_manager.deinit();
self._style_manager.deinit();
page.releaseArena(self.call_arena);
page.releaseArena(self.local_arena);
self._call_arena.release();
self._local_arena.release();
}
pub fn trackWorker(self: *Frame, worker: *Worker) !void {
@@ -614,14 +618,10 @@ pub fn headersForRequest(self: *Frame, headers: *HttpClient.Headers) !void {
}
}
pub fn getArena(self: *Frame, size_or_bucket: anytype, debug: []const u8) !Allocator {
pub fn getArena(self: *Frame, size_or_bucket: anytype, debug: []const u8) !*lp.Arena {
return self._session.getArena(size_or_bucket, debug);
}
pub fn releaseArena(self: *Frame, allocator: Allocator) void {
return self._session.releaseArena(allocator);
}
pub fn isSameOrigin(self: *const Frame, url: [:0]const u8) bool {
const current_origin = self.origin orelse return false;
@@ -705,11 +705,11 @@ pub fn navigate(self: *Frame, request_url: [:0]const u8, opts: NavigateOpts) !vo
return error.BlobNotFound;
};
const parse_arena = try self.getArena(.medium, "Frame.parseBlob");
defer self.releaseArena(parse_arena);
defer parse_arena.release();
// A script executed mid-parse can revoke the blob URL, letting GC
// free the buffer under the parser; parse a copy.
const html = try parse_arena.dupe(u8, blob._slice);
var parser = Parser.init(parse_arena, self.document.asNode(), self, .{ .allow_declarative_shadow = true });
var parser = Parser.init(parse_arena.allocator(), self.document.asNode(), self, .{ .allow_declarative_shadow = true });
parser.parse(html);
} else {
self.document.injectBlank(self) catch |err| {
@@ -805,7 +805,7 @@ pub fn navigate(self: *Frame, request_url: [:0]const u8, opts: NavigateOpts) !vo
try transfer.req.headers.add(hdr);
}
if (opts.referer) |ref| {
const ref_header = try std.mem.concatWithSentinel(transfer.arena, u8, &.{ "Referer: ", ref }, 0);
const ref_header = try std.mem.concatWithSentinel(transfer.arena.allocator(), u8, &.{ "Referer: ", ref }, 0);
try transfer.req.headers.add(ref_header);
}
}
@@ -865,14 +865,14 @@ pub fn scheduleNavigation(self: *Frame, request_url: []const u8, opts: NavigateO
return;
}
const arena = try self._session.getArena(.small, "scheduleNavigation");
errdefer self._session.releaseArena(arena);
errdefer arena.release();
return self.scheduleNavigationWithArena(arena, request_url, opts, nt);
}
// Don't name the first parameter "self", because the target of this navigation
// might change inside the function. So the code should be explicit about the
// frame that it's acting on.
fn scheduleNavigationWithArena(originator: *Frame, arena: Allocator, request_url: []const u8, opts: NavigateOpts, nt: Navigation) !void {
fn scheduleNavigationWithArena(originator: *Frame, arena: *lp.Arena, request_url: []const u8, opts: NavigateOpts, nt: Navigation) !void {
const resolved_url, const is_about_blank = blk: {
if (URL.isCompleteHTTPUrl(request_url)) {
break :blk .{ try arena.dupeZ(u8, request_url), false };
@@ -900,7 +900,7 @@ fn scheduleNavigationWithArena(originator: *Frame, arena: Allocator, request_url
};
const u = try URL.resolve(
arena,
arena.allocator(),
frame_base,
request_url,
.{ .encoding = originator.charset },
@@ -926,7 +926,7 @@ fn scheduleNavigationWithArena(originator: *Frame, arena: Allocator, request_url
std.mem.eql(u8, target.url, resolved_url) and
std.mem.indexOfScalar(u8, resolved_url, '#') != null)
{
session.releaseArena(arena);
arena.release();
return;
}
@@ -949,7 +949,7 @@ fn scheduleNavigationWithArena(originator: *Frame, arena: Allocator, request_url
try target.queueHashChange(old_url, target.url);
// don't defer this, the caller is responsible for freeing it on error
session.releaseArena(arena);
arena.release();
return;
}
@@ -997,7 +997,7 @@ fn scheduleNavigationWithArena(originator: *Frame, arena: Allocator, request_url
};
if (target._queued_navigation) |existing| {
session.releaseArena(existing.arena);
existing.arena.release();
}
target._queued_navigation = qn;
@@ -1535,7 +1535,7 @@ fn frameDataCallback(transfer: *HttpClient.Transfer, data: []const u8) !void {
}
switch (self._parse_state) {
.html => |*html| try html.buffer.appendSlice(html.arena, data),
.html => |*html| try html.buffer.appendSlice(html.arena.allocator(), data),
.text => |*buf| {
// we have to escape the data...
var v = data;
@@ -1596,15 +1596,15 @@ fn frameDoneCallback(ctx: *anyopaque) !void {
};
const parse_arena = try self.getArena(.medium, "Frame.parse");
defer self.releaseArena(parse_arena);
defer parse_arena.release();
var parser = Parser.init(parse_arena, self.document.asNode(), self, .{ .allow_declarative_shadow = true });
var parser = Parser.init(parse_arena.allocator(), self.document.asNode(), self, .{ .allow_declarative_shadow = true });
switch (self._parse_state) {
.html => |*html| {
{
defer {
self.releaseArena(html.arena);
html.arena.release();
self._parse_state = .complete;
}
@@ -1629,7 +1629,7 @@ fn frameDoneCallback(ctx: *anyopaque) !void {
self._parse_state = .{ .raw_done = buf.items };
// Use empty an HTML containing the image.
const html = try std.mem.concat(parse_arena, u8, &.{
const html = try std.mem.concat(parse_arena.allocator(), u8, &.{
"<html><head><meta charset=\"utf-8\"></head><body><img src=\"",
self.url,
"\"></body></html>",
@@ -1656,7 +1656,7 @@ fn frameDoneCallback(ctx: *anyopaque) !void {
},
.err => |err| {
// Generate a pseudo HTML page indicating the failure.
const html = try std.mem.concat(parse_arena, u8, &.{
const html = try std.mem.concat(parse_arena.allocator(), u8, &.{
"<html><head><meta charset=\"utf-8\"></head><body><h1>Navigation failed</h1><p>Reason: ",
@errorName(err),
"</p></body></html>",
@@ -2177,9 +2177,9 @@ pub fn loadExternalStylesheet(self: *Frame, link: *Element.Html.Link, href: []co
const element = link.asElement();
const arena = try session.getArena(.medium, "Frame.loadExternalStylesheet");
defer session.releaseArena(arena);
defer arena.release();
const resolved = URL.resolve(arena, self.base(), href, .{ .encoding = self.charset }) catch |err| {
const resolved = URL.resolve(arena.allocator(), self.base(), href, .{ .encoding = self.charset }) catch |err| {
log.warn(.http, "external stylesheet resolve", .{ .err = err, .href = href });
try self.fireElementEvent(element, comptime .wrap("error"));
return;
@@ -2208,7 +2208,7 @@ pub fn loadExternalStylesheet(self: *Frame, link: *Element.Html.Link, href: []co
sm.is_evaluating = true;
defer sm.endEvaluationWindow(was_evaluating);
var response = http_client.syncRequest(arena, .{
var response = http_client.syncRequest(arena.allocator(), .{
.url = resolved,
.method = .GET,
.frame_id = self._frame_id,
@@ -2223,7 +2223,7 @@ pub fn loadExternalStylesheet(self: *Frame, link: *Element.Html.Link, href: []co
log.warn(.http, "external stylesheet fetch", .{ .err = err, .url = resolved });
return self.fireElementEvent(element, comptime .wrap("error"));
};
defer response.deinit(arena);
defer response.deinit(arena.allocator());
if (response.status < 200 or response.status >= 300) {
log.info(.http, "external stylesheet status", .{ .status = response.status, .url = resolved });
@@ -2967,7 +2967,7 @@ const ParseState = union(enum) {
complete,
err: anyerror,
html: struct {
arena: Allocator,
arena: *lp.Arena,
buffer: std.ArrayList(u8),
},
text: std.ArrayList(u8),
@@ -2976,9 +2976,9 @@ const ParseState = union(enum) {
raw_done: []const u8,
download: Download,
fn deinit(self: *ParseState, frame: *Frame) void {
fn deinit(self: *ParseState, _: *Frame) void {
switch (self.*) {
.html => |html| frame.releaseArena(html.arena),
.html => |html| html.arena.release(),
// Only reached when a frame is torn down mid-download (the normal
// completion path in frameDoneCallback already closes the file and
// transitions to .complete).
@@ -3143,7 +3143,7 @@ const Navigation = union(NavigationType) {
};
pub const QueuedNavigation = struct {
arena: Allocator,
arena: *lp.Arena,
url: [:0]const u8,
opts: NavigateOpts,
is_about_blank: bool,
@@ -3365,7 +3365,7 @@ pub fn submitForm(self: *Frame, submitter_: ?*Element, form_: ?*Element.Html.For
const is_post = std.mem.eql(u8, method, "post");
const arena = try self._session.getArena(.medium, "submitForm");
errdefer self._session.releaseArena(arena);
errdefer arena.release();
// Get charset from accept-charset attribute or fall back to document charset
const charset: []const u8 = blk: {
@@ -3394,8 +3394,8 @@ pub fn submitForm(self: *Frame, submitter_: ?*Element, form_: ?*Element.Html.For
break :blk .urlencode;
};
var buf = std.Io.Writer.Allocating.init(arena);
try form_data.write(.{ .encoding = encoding, .charset = charset, .allocator = arena }, &buf.writer);
var buf = std.Io.Writer.Allocating.init(arena.allocator());
try form_data.write(.{ .encoding = encoding, .charset = charset, .allocator = arena.allocator() }, &buf.writer);
var action = blk: {
if (submit_button) |s| {
@@ -3413,13 +3413,13 @@ pub fn submitForm(self: *Frame, submitter_: ?*Element, form_: ?*Element.Html.For
opts.body = buf.written();
opts.header = switch (encoding) {
.urlencode => "Content-Type: application/x-www-form-urlencoded",
.formdata => |b| try std.fmt.allocPrintSentinel(arena, "Content-Type: multipart/form-data; boundary={s}", .{b}, 0),
.formdata => |b| try std.fmt.allocPrintSentinel(arena.allocator(), "Content-Type: multipart/form-data; boundary={s}", .{b}, 0),
// Per WHATWG HTML §4.10.21.6, text/plain submissions include the form's
// resolved encoding (accept-charset or document charset).
.plaintext => try std.fmt.allocPrintSentinel(arena, "Content-Type: text/plain; charset={s}", .{charset}, 0),
.plaintext => try std.fmt.allocPrintSentinel(arena.allocator(), "Content-Type: text/plain; charset={s}", .{charset}, 0),
};
} else {
action = try URL.concatQueryString(arena, action, buf.written());
action = try URL.concatQueryString(arena.allocator(), action, buf.written());
}
return self.scheduleNavigationWithArena(arena, action, opts, .{ .form = target_frame });
+9 -11
View File
@@ -72,6 +72,7 @@ factory: Factory,
// The arena for this Page's lifetime. Document / Frame / Factory / DOM
// objects allocate out of this.
_frame_arena: *lp.Arena,
frame_arena: Allocator,
// Origin map for same-origin context sharing. Entries live for the Page's
@@ -150,13 +151,14 @@ pub fn getViewport(self: *const Page) Viewport {
// Initialize a Page and its root Frame.
pub fn init(self: *Page, session: *Session, frame_id: u32) !void {
const frame_arena = try session.arena_pool.acquire(.large, "Page.frame_arena");
errdefer session.arena_pool.release(frame_arena);
errdefer frame_arena.release();
self.* = .{
.session = session,
.frame = undefined,
.frame_arena = frame_arena,
.factory = Factory.init(frame_arena),
._frame_arena = frame_arena,
.frame_arena = frame_arena.allocator(),
.factory = Factory.init(frame_arena.allocator()),
.globals = .init(session.browser.app.allocator),
};
self.queued_navigation = &self.queued_navigation_1;
@@ -228,7 +230,7 @@ pub fn deinit(self: *Page) void {
self.origins = .empty;
}
session.arena_pool.release(self.frame_arena);
self._frame_arena.release();
}
pub fn recordJsError(self: *Page, err: anyerror) void {
@@ -236,14 +238,10 @@ pub fn recordJsError(self: *Page, err: anyerror) void {
lp.metrics.js_errors.incr(if (err == error.JsException) .js_exception else .other);
}
pub fn getArena(self: *Page, size_or_bucket: anytype, debug: []const u8) !Allocator {
pub fn getArena(self: *Page, size_or_bucket: anytype, debug: []const u8) !*lp.Arena {
return self.session.getArena(size_or_bucket, debug);
}
pub fn releaseArena(self: *Page, allocator: Allocator) void {
return self.session.releaseArena(allocator);
}
pub fn getOrCreateOrigin(self: *Page, key_: ?[]const u8) !*js.Origin {
const session = self.session;
const key = key_ orelse {
@@ -255,7 +253,7 @@ pub fn getOrCreateOrigin(self: *Page, key_: ?[]const u8) !*js.Origin {
return js.Origin.init(session.browser.app, session.browser.env.isolate, &opaque_origin);
};
const gop = try self.origins.getOrPut(session.arena, key);
const gop = try self.origins.getOrPut(session.arena.allocator(), key);
if (gop.found_existing) {
const origin = gop.value_ptr.*;
origin.rc += 1;
@@ -320,7 +318,7 @@ pub fn scheduleNavigation(self: *Page, frame: *Frame) !void {
}
}
return list.append(self.session.arena, frame);
return list.append(self.session.arena.allocator(), frame);
}
pub fn findFrameByFrameId(self: *Page, frame_id: u32) ?*Frame {
+3 -3
View File
@@ -79,7 +79,7 @@ pub fn waitForFrameCDP(self: *Runner, frame_id: u32, timeout_ms: u32, until: lp.
pub fn waitForAll(self: *Runner, timeout_ms: u32, opts: WaitForFrameOpts) !void {
const session = self.session;
const arena = try session.getArena(.tiny, "Runner.waitForAll");
defer session.releaseArena(arena);
defer arena.release();
var pages_to_wait: usize = 0;
for (session.pages.items) |page| {
@@ -332,10 +332,10 @@ fn _tick(self: *Runner, comptime is_cdp: bool, timeout_ms: u32, conditions: []Wa
pub fn waitForSelector(self: *Runner, frame_id: u32, input: [:0]const u8, timeout_ms: u32) !*Node.Element {
const session = self.session;
const arena = try session.getArena(.small, "Runner.waitForSelector");
defer session.releaseArena(arena);
defer arena.release();
const timer: std.Io.Timestamp = .now(lp.io, .boot);
const selector = try Selector.parseLeaky(arena, input);
const selector = try Selector.parseLeaky(arena.allocator(), input);
while (true) {
if (session.isCancelled()) {
+7 -7
View File
@@ -113,7 +113,7 @@ pub fn preloadScript(self: *ScriptManager, element: ?*Element.Html, url: []const
const frame = self.frame;
const arena = try frame.getArena(.large, "SM.preloadScript");
errdefer frame.releaseArena(arena);
errdefer arena.release();
const owned_url = try arena.dupeZ(u8, url);
@@ -242,10 +242,10 @@ pub fn addFromElement(self: *ScriptManager, comptime from_parser: bool, script_e
const arena = try frame.getArena(.large, "SM.addFromElement");
errdefer if (handover == false) {
frame.releaseArena(arena);
arena.release();
};
const remote_url = try URL.resolve(arena, base_url, src, .{ .encoding = frame.charset });
const remote_url = try URL.resolve(arena.allocator(), base_url, src, .{ .encoding = frame.charset });
script_element._executed = true;
const mode: Script.Extra.FrameExtra.Mode = blk: {
@@ -304,7 +304,7 @@ pub fn addFromElement(self: *ScriptManager, comptime from_parser: bool, script_e
// The adopted Script has its own arena; ours held only the URL
// resolution, which nothing below needs.
handover = true;
frame.releaseArena(arena);
arena.release();
if (pre.complete and mode == .async) {
// The fetch already finished, so no doneCallback will move it
@@ -354,7 +354,7 @@ pub fn addFromElement(self: *ScriptManager, comptime from_parser: bool, script_e
script.status = pre.status;
script.complete = true;
} else {
const response = try self.base.client.syncRequest(arena, .{
const response = try self.base.client.syncRequest(arena.allocator(), .{
.url = remote_url,
.method = .GET,
.frame_id = frame._frame_id,
@@ -430,7 +430,7 @@ fn addInlineScript(self: *ScriptManager, script_element: *Element.Html.Script, k
const frame = self.frame;
const arena = try frame.getArena(source_len + @sizeOf(Script) + 1, "SM.addInlineScript");
errdefer frame.releaseArena(arena);
errdefer arena.release();
const source = blk: {
const buf = try arena.alloc(u8, source_len + 1);
@@ -627,7 +627,7 @@ test "ScriptManager: waitForPreload stops when teardown is pending" {
.raw = try message_arena.dupe(u8, "{}"),
.input = .{ .method = "Target.closeTarget" },
} });
defer client.inbox.pop().?.deinit(client.arena_pool);
defer client.inbox.pop().?.deinit();
try testing.expect(sm.waitForPreload(url) == null);
}
+8 -12
View File
@@ -185,14 +185,10 @@ pub fn getHeaders(self: *ScriptManagerBase) !http.Headers {
return headers;
}
fn acquireArena(self: *ScriptManagerBase, size_or_bucket: anytype, debug: []const u8) !Allocator {
fn acquireArena(self: *ScriptManagerBase, size_or_bucket: anytype, debug: []const u8) !*lp.Arena {
return self.owner.session().getArena(size_or_bucket, debug);
}
fn releaseArena(self: *ScriptManagerBase, arena: Allocator) void {
self.owner.session().releaseArena(arena);
}
pub fn scriptList(self: *ScriptManagerBase, script: *const Script) *std.DoublyLinkedList {
return switch (script.extra) {
.import, .import_async => &self.async_scripts,
@@ -239,7 +235,7 @@ pub fn preloadImport(self: *ScriptManagerBase, url: [:0]const u8, referrer: []co
errdefer _ = self.imported_modules.remove(url);
const arena = try self.acquireArena(.large, "SM.preloadImport");
errdefer self.releaseArena(arena);
errdefer arena.release();
const script = try arena.create(Script);
script.* = .{
@@ -431,7 +427,7 @@ pub fn getAsyncImport(self: *ScriptManagerBase, url: [:0]const u8, cb: ImportAsy
}
const arena = try self.acquireArena(.large, "SM.getAsyncImport");
errdefer self.releaseArena(arena);
errdefer arena.release();
const script = try arena.create(Script);
script.* = .{
@@ -614,7 +610,7 @@ pub const Script = struct {
status: u16 = 0,
source: Source,
url: []const u8,
arena: Allocator,
arena: *lp.Arena,
extra: Extra,
node: std.DoublyLinkedList.Node,
manager: *ScriptManagerBase,
@@ -691,7 +687,7 @@ pub const Script = struct {
};
pub fn deinit(self: *Script) void {
self.manager.releaseArena(self.arena);
self.arena.release();
}
pub fn startCallback(transfer: *HttpClient.Transfer) !void {
@@ -754,7 +750,7 @@ pub const Script = struct {
lp.assert(self.source.remote.capacity == 0, "ScriptManagerBase.Header buffer", .{ .capacity = self.source.remote.capacity });
var buffer: std.ArrayList(u8) = .empty;
if (transfer.getContentLength()) |cl| {
try buffer.ensureTotalCapacity(self.arena, cl);
try buffer.ensureTotalCapacity(self.arena.allocator(), cl);
}
self.source = .{ .remote = buffer };
return .proceed;
@@ -769,7 +765,7 @@ pub const Script = struct {
}
fn _dataCallback(self: *Script, _: *HttpClient.Transfer, data: []const u8) !void {
try self.source.remote.appendSlice(self.arena, data);
try self.source.remote.appendSlice(self.arena.allocator(), data);
}
pub fn doneCallback(ctx: *anyopaque) !void {
@@ -1148,7 +1144,7 @@ test "ScriptManagerBase: waitForImport stops when teardown is pending" {
.raw = try message_arena.dupe(u8, "{}"),
.input = .{ .method = "Target.disposeBrowserContext" },
} });
defer client.inbox.pop().?.deinit(client.arena_pool);
defer client.inbox.pop().?.deinit();
try testing.expectError(error.SyncWaitInterrupted, sm.waitForImport(url));
}
+12 -17
View File
@@ -39,7 +39,6 @@ const SharedWorkerGlobalScope = @import("webapi/SharedWorkerGlobalScope.zig");
const log = lp.log;
const ArenaPool = App.ArenaPool;
const Allocator = std.mem.Allocator;
const IS_DEBUG = builtin.mode == .Debug;
// A Session represents a browsing context group (cookie jar, session storage,
@@ -50,7 +49,7 @@ const IS_DEBUG = builtin.mode == .Debug;
const Session = @This();
browser: *Browser,
arena: Allocator,
arena: *lp.Arena,
history: History,
navigation: *Navigation,
storage_shed: storage.Shed,
@@ -161,9 +160,9 @@ pub fn init(self: *Session, browser: *Browser, notification: *Notification) !voi
const arena_pool = browser.arena_pool;
const arena = try arena_pool.acquire(.small, "Session");
errdefer arena_pool.release(arena);
errdefer arena.release();
const navigation = try Factory.chainedWithAllocator(arena, .{
const navigation = try Factory.chainedWithAllocator(arena.allocator(), .{
EventTarget{ ._type = undefined },
Navigation{ ._proto = undefined },
});
@@ -211,7 +210,7 @@ pub fn deinit(self: *Session) void {
self.bridge_store.deinit(allocator);
}
self._console_messages.deinit();
self.arena_pool.release(self.arena);
self.arena.release();
}
/// Register the console listener so `drainConsoleMessages` returns output. Idempotent.
@@ -285,7 +284,7 @@ fn allocatePage(self: *Session, frame_id: u32) !*Page {
// Tear down and free a Page allocated via allocatePage.
fn queuePageDestruction(self: *Session, page: *Page) void {
self._page_destruction_queue.append(self.arena, page) catch @panic("OOM");
self._page_destruction_queue.append(self.arena.allocator(), page) catch @panic("OOM");
}
fn retire(self: *Session, page: *Page) void {
@@ -348,7 +347,7 @@ fn installNewActivePage(self: *Session, frame_id: u32) !*Frame {
const page = try self.allocatePage(frame_id);
errdefer self.queuePageDestruction(page);
try self.pages.append(self.arena, page);
try self.pages.append(self.arena.allocator(), page);
errdefer _ = self.pages.pop();
const frame = &page.frame;
@@ -390,7 +389,7 @@ pub fn closePage(self: *Session, frame_id: u32) void {
// We queue then process so that there is a single place (processDestroyQueues)
// where pages get destroyed.
pub fn closeAllPages(self: *Session) void {
self._page_destruction_queue.ensureUnusedCapacity(self.arena, self.pages.items.len) catch @panic("OOM");
self._page_destruction_queue.ensureUnusedCapacity(self.arena.allocator(), self.pages.items.len) catch @panic("OOM");
for (self.pages.items) |page| {
page.frame.abortTransfers();
self._page_destruction_queue.appendAssumeCapacity(page);
@@ -399,14 +398,10 @@ pub fn closeAllPages(self: *Session) void {
self.processDestroyQueues();
}
pub fn getArena(self: *Session, size_or_bucket: anytype, debug: []const u8) !Allocator {
pub fn getArena(self: *Session, size_or_bucket: anytype, debug: []const u8) !*lp.Arena {
return self.arena_pool.acquire(size_or_bucket, debug);
}
pub fn releaseArena(self: *Session, allocator: Allocator) void {
self.arena_pool.release(allocator);
}
// The live page for a top-level browsing context, by its root frame id.
pub fn livePage(self: *Session, frame_id: u32) ?*Page {
for (self.pages.items) |page| {
@@ -594,7 +589,7 @@ fn processPageQueuedNavigation(self: *Session, page: *Page) !void {
if (qn.is_about_blank) {
// Defer about:blank to second pass
try about_blank_queue.append(self.arena, frame);
try about_blank_queue.append(self.arena.allocator(), frame);
continue;
}
@@ -643,7 +638,7 @@ fn processPageQueuedNavigation(self: *Session, page: *Page) !void {
fn processFrameNavigation(self: *Session, frame: *Frame, qn: *QueuedNavigation) !void {
frame._queued_navigation = null;
defer self.releaseArena(qn.arena);
defer qn.arena.release();
// A popup whose window was close()'d is parked in page.closed_frames and
// torn down at Page.deinit. It must never be navigated. This navigation
@@ -782,7 +777,7 @@ fn processRootQueuedNavigation(self: *Session, page: *Page) !void {
// The qn arena is consumed here regardless of success — frame.navigate
// dupes the URL into the page's own arena, so we can release the qn
// arena as soon as navigate returns.
defer self.arena_pool.release(qn.arena);
defer qn.arena.release();
if (is_synthetic) {
return self.replaceRootImmediate(current_frame._frame_id, qn.url, qn.opts);
@@ -844,7 +839,7 @@ pub fn initiateRootNavigation(self: *Session, frame_id: u32, url: [:0]const u8,
live.replacement = page;
errdefer live.replacement = null;
try self.pages.append(self.arena, page);
try self.pages.append(self.arena.allocator(), page);
errdefer _ = self.pages.pop();
if (comptime IS_DEBUG) {
+27 -27
View File
@@ -53,7 +53,7 @@ const RuleList = std.MultiArrayList(VisibilityRule);
frame: *Frame,
arena: Allocator,
arena: *lp.Arena,
// Bucketed rules for fast lookup - keyed by rightmost selector part
id_rules: std.StringHashMapUnmanaged(RuleList) = .empty,
@@ -89,7 +89,7 @@ pub fn init(frame: *Frame) !StyleManager {
}
pub fn deinit(self: *StyleManager) void {
self.frame.releaseArena(self.arena);
self.arena.release();
}
const IS_DEBUG = builtin.mode == .Debug;
@@ -118,7 +118,7 @@ fn parseSheet(self: *StyleManager, build_arena: Allocator, sheet: *CSSStyleSheet
const owner_node = sheet.getOwnerNode() orelse return;
if (owner_node.is(Element.Html.Style)) |style| {
const text = try style.asNode().getTextContentAlloc(self.arena);
const text = try style.asNode().getTextContentAlloc(self.arena.allocator());
var it = CssParser.parseStylesheet(text);
while (it.next()) |parsed_rule| {
switch (parsed_rule) {
@@ -475,7 +475,7 @@ fn addRawRule(self: *StyleManager, build_arena: Allocator, selector_text: []cons
if (!props.isRelevant()) return;
const selectors = SelectorParser.parseList(self.arena, selector_text) catch return;
const selectors = SelectorParser.parseList(self.arena.allocator(), selector_text) catch return;
for (selectors) |selector| {
const rightmost = if (selector.segments.len > 0) selector.segments[selector.segments.len - 1].compound else selector.first;
const bucket_key = getBucketKey(rightmost) orelse continue;
@@ -489,22 +489,22 @@ fn addRawRule(self: *StyleManager, build_arena: Allocator, selector_text: []cons
switch (bucket_key) {
.id => |id| {
const gop = try self.id_rules.getOrPut(self.arena, id);
const gop = try self.id_rules.getOrPut(self.arena.allocator(), id);
if (!gop.found_existing) gop.value_ptr.* = .{};
try gop.value_ptr.append(self.arena, rule);
try gop.value_ptr.append(self.arena.allocator(), rule);
},
.class => |class| {
const gop = try self.class_rules.getOrPut(self.arena, class);
const gop = try self.class_rules.getOrPut(self.arena.allocator(), class);
if (!gop.found_existing) gop.value_ptr.* = .{};
try gop.value_ptr.append(self.arena, rule);
try gop.value_ptr.append(self.arena.allocator(), rule);
},
.tag => |tag| {
const gop = try self.tag_rules.getOrPut(self.arena, tag);
const gop = try self.tag_rules.getOrPut(self.arena.allocator(), tag);
if (!gop.found_existing) gop.value_ptr.* = .{};
try gop.value_ptr.append(self.arena, rule);
try gop.value_ptr.append(self.arena.allocator(), rule);
},
.other => {
try self.other_rules.append(self.arena, rule);
try self.other_rules.append(self.arena.allocator(), rule);
},
}
}
@@ -536,7 +536,7 @@ fn rebuildIfDirty(self: *StyleManager) !void {
self.layer_ids = .empty;
self.next_anon_layer = 0;
self.rule_layers = .empty;
self.frame.releaseArena(build_arena);
build_arena.release();
}
self.dirty = false;
@@ -546,31 +546,31 @@ fn rebuildIfDirty(self: *StyleManager) !void {
const tag_rules_count = self.tag_rules.count();
const other_rules_count = self.other_rules.len;
self.frame._session.arena_pool.resetRetain(self.arena);
self.arena.resetRetain();
self.next_doc_order = 1;
self.id_rules = .empty;
try self.id_rules.ensureTotalCapacity(self.arena, id_rules_count);
try self.id_rules.ensureTotalCapacity(self.arena.allocator(), id_rules_count);
self.class_rules = .empty;
try self.class_rules.ensureTotalCapacity(self.arena, class_rules_count);
try self.class_rules.ensureTotalCapacity(self.arena.allocator(), class_rules_count);
self.tag_rules = .empty;
try self.tag_rules.ensureTotalCapacity(self.arena, tag_rules_count);
try self.tag_rules.ensureTotalCapacity(self.arena.allocator(), tag_rules_count);
self.other_rules = .{};
try self.other_rules.ensureTotalCapacity(self.arena, other_rules_count);
try self.other_rules.ensureTotalCapacity(self.arena.allocator(), other_rules_count);
const sheets = self.frame.document._style_sheets orelse return;
for (sheets._sheets.items) |sheet| {
self.parseSheet(build_arena, sheet) catch |err| {
self.parseSheet(build_arena.allocator(), sheet) catch |err| {
log.err(.browser, "StyleManager parseSheet", .{ .err = err });
return err;
};
}
try self.finalizeLayerRanks(build_arena);
try self.finalizeLayerRanks(build_arena.allocator());
}
// Check if an element is hidden based on options.
@@ -946,7 +946,7 @@ fn addRule(self: *StyleManager, build_arena: Allocator, style_rule: *CSSStyleRul
}
// Parse the selector list
const selectors = SelectorParser.parseList(self.arena, selector_text) catch return;
const selectors = SelectorParser.parseList(self.arena.allocator(), selector_text) catch return;
if (selectors.len == 0) {
return;
}
@@ -974,22 +974,22 @@ fn addRule(self: *StyleManager, build_arena: Allocator, style_rule: *CSSStyleRul
// Add to appropriate bucket
switch (bucket_key) {
.id => |id| {
const gop = try self.id_rules.getOrPut(self.arena, id);
const gop = try self.id_rules.getOrPut(self.arena.allocator(), id);
if (!gop.found_existing) gop.value_ptr.* = .{};
try gop.value_ptr.append(self.arena, rule);
try gop.value_ptr.append(self.arena.allocator(), rule);
},
.class => |class| {
const gop = try self.class_rules.getOrPut(self.arena, class);
const gop = try self.class_rules.getOrPut(self.arena.allocator(), class);
if (!gop.found_existing) gop.value_ptr.* = .{};
try gop.value_ptr.append(self.arena, rule);
try gop.value_ptr.append(self.arena.allocator(), rule);
},
.tag => |tag| {
const gop = try self.tag_rules.getOrPut(self.arena, tag);
const gop = try self.tag_rules.getOrPut(self.arena.allocator(), tag);
if (!gop.found_existing) gop.value_ptr.* = .{};
try gop.value_ptr.append(self.arena, rule);
try gop.value_ptr.append(self.arena.allocator(), rule);
},
.other => {
try self.other_rules.append(self.arena, rule);
try self.other_rules.append(self.arena.allocator(), rule);
},
}
}
+2 -2
View File
@@ -103,7 +103,7 @@ fn htmlAsChildrenInner(frame: *Frame, node: *Node, html: []const u8, opts: Fragm
// XML.
pub fn xmlDocument(frame: *Frame, xml: []const u8) !?*Document.XMLDocument {
const arena = try frame.getArena(.medium, "parse.xmlDocument");
defer frame.releaseArena(arena);
defer arena.release();
const previous_parse_mode = frame._parse_mode;
frame._parse_mode = .fragment;
@@ -111,7 +111,7 @@ pub fn xmlDocument(frame: *Frame, xml: []const u8) !?*Document.XMLDocument {
const doc = try frame._factory.document(Document.XMLDocument{ ._proto = undefined });
const doc_node = doc.asNode();
var parser = Parser.init(arena, doc_node, frame, .{});
var parser = Parser.init(arena.allocator(), doc_node, frame, .{});
parser.parseXML(xml);
if (parser.terminated) {
return error.ExecutionTerminated;
+4 -4
View File
@@ -38,9 +38,9 @@ pub fn scriptHint(frame: *Frame, element: ?*Element.Html, href: []const u8) bool
}
const arena = frame.getArena(.small, "preload.scriptHint") catch return false;
defer frame.releaseArena(arena);
defer arena.release();
const resolved = URL.resolve(arena, frame.base(), href, .{ .encoding = frame.charset }) catch return false;
const resolved = URL.resolve(arena.allocator(), frame.base(), href, .{ .encoding = frame.charset }) catch return false;
if (!isRemoteScheme(resolved)) {
return false;
}
@@ -79,9 +79,9 @@ pub fn prescan(frame: *Frame, html: []const u8) void {
return;
}
const arena = frame.getArena(.small, "preload.prescan") catch return;
defer frame.releaseArena(arena);
defer arena.release();
var scan = Prescan{ .frame = frame, .base = frame.base(), .arena = arena };
var scan = Prescan{ .frame = frame, .base = frame.base(), .arena = arena.allocator() };
Parser.prescan(html, frame.charset, &scan, Prescan.callback);
}
+3 -3
View File
@@ -274,7 +274,7 @@ pub fn findClickActivationTarget(target: *Node, bubbles: bool) ?*Node {
fn runJavascriptUrl(frame: *Frame, source: []const u8) !void {
const arena = try frame.getArena(.tiny, "javascript-url");
errdefer frame.releaseArena(arena);
errdefer arena.release();
const task = try arena.create(JavascriptUrlTask);
task.* = .{
@@ -292,7 +292,7 @@ fn runJavascriptUrl(frame: *Frame, source: []const u8) !void {
const JavascriptUrlTask = struct {
frame: *Frame,
arena: std.mem.Allocator,
arena: *lp.Arena,
source: []const u8,
fn run(ptr: *anyopaque) !?u32 {
@@ -320,7 +320,7 @@ const JavascriptUrlTask = struct {
}
fn deinit(self: *JavascriptUrlTask) void {
self.frame.releaseArena(self.arena);
self.arena.release();
}
};
+8 -8
View File
@@ -93,7 +93,7 @@ heap_profiler: ?*v8.HeapProfiler = null,
templates: []*const v8.FunctionTemplate,
// Arena for the lifetime of the context
arena: Allocator,
arena: *lp.Arena,
// The call_arena for this context. For main world contexts this is
// frame.call_arena. For isolated world contexts this is a separate arena
@@ -205,7 +205,7 @@ pub fn deinit(self: *Context) void {
}
const env = self.env;
defer env.app.arena_pool.release(self.arena);
defer self.arena.release();
// Unlink any IndexedDB gate participants first: the session-scoped engine
// must never wake a waiter into this scheduler once it's torn down.
@@ -353,7 +353,7 @@ pub fn module(self: *Context, comptime want_result: bool, local: *const js.Local
// gop will _always_ initiated if cacheable == true
var gop: std.StringHashMapUnmanaged(ModuleEntry).GetOrPutResult = undefined;
if (cacheable) {
gop = try self.module_cache.getOrPut(arena, url);
gop = try self.module_cache.getOrPut(arena.allocator(), url);
if (gop.found_existing) {
if (gop.value_ptr.module) |cache_mod| {
if (gop.value_ptr.module_promise == null) {
@@ -514,7 +514,7 @@ fn compileModule(local: *const js.Local, src: []const u8, name: []const u8) !js.
// we always want to track its identity (so that, if this module imports other
// modules, we can resolve the full URL), and preload any dependent modules.
fn postCompileModule(self: *Context, mod: js.Module, url: [:0]const u8, local: *const js.Local) !void {
try self.module_identifier.putNoClobber(self.arena, mod.getIdentityHash(), url);
try self.module_identifier.putNoClobber(self.arena.allocator(), mod.getIdentityHash(), url);
// Non-async modules are blocking. We can download them in parallel, but
// they need to be processed serially. So we want to get the list of
@@ -534,7 +534,7 @@ fn postCompileModule(self: *Context, mod: js.Module, url: [:0]const u8, local: *
return err;
},
};
const nested_gop = try self.module_cache.getOrPut(self.arena, normalized_specifier);
const nested_gop = try self.module_cache.getOrPut(self.arena.allocator(), normalized_specifier);
if (!nested_gop.found_existing) {
const owned_specifier = try self.arena.dupeZ(u8, normalized_specifier);
nested_gop.key_ptr.* = owned_specifier;
@@ -636,7 +636,7 @@ pub fn dynamicModuleCallback(
};
const normalized_specifier = self.script_manager.resolveSpecifier(
self.arena, // might need to survive until the module is loaded
self.arena.allocator(), // might need to survive until the module is loaded
resource,
specifier,
) catch |err| switch (err) {
@@ -749,7 +749,7 @@ fn _resolveModuleCallback(self: *Context, referrer: js.Module, specifier: [:0]co
};
const normalized_specifier = try self.script_manager.resolveSpecifier(
self.arena,
self.arena.allocator(),
referrer_path,
specifier,
);
@@ -804,7 +804,7 @@ const DynamicModuleResolveState = struct {
};
fn _dynamicModuleCallback(self: *Context, specifier: [:0]const u8, referrer: []const u8, local: *const js.Local) !js.Promise {
const gop = try self.module_cache.getOrPut(self.arena, specifier);
const gop = try self.module_cache.getOrPut(self.arena.allocator(), specifier);
if (gop.found_existing) {
if (gop.value_ptr.resolver_promise) |rp| {
return local.toLocal(rp);
+2 -2
View File
@@ -255,7 +255,7 @@ fn _createContext(self: *Env, global: anytype, params: ContextParams) !*Context
const is_frame = T == *Frame;
const context_arena = try self.app.arena_pool.acquire(.medium, params.debug_name);
errdefer self.app.arena_pool.release(context_arena);
errdefer context_arena.release();
const isolate = self.isolate;
var hs: js.HandleScope = undefined;
@@ -340,7 +340,7 @@ fn _createContext(self: *Env, global: anytype, params: ContextParams) !*Context
.local_arena = params.local_arena,
.microtask_queue = microtask_queue,
.script_manager = if (comptime is_frame) &global._script_manager.base else &global._script_manager,
.scheduler = .init(context_arena),
.scheduler = .init(context_arena.allocator()),
.identity = params.identity,
.identity_arena = params.identity_arena,
.execution = undefined,
+1 -5
View File
@@ -76,14 +76,10 @@ pub fn dupeString(self: *const Execution, value: []const u8) ![]const u8 {
return self.arena.dupe(u8, value);
}
pub fn getArena(self: *const Execution, size_or_bucket: anytype, debug: []const u8) !Allocator {
pub fn getArena(self: *const Execution, size_or_bucket: anytype, debug: []const u8) !*lp.Arena {
return self.page.getArena(size_or_bucket, debug);
}
pub fn releaseArena(self: *const Execution, allocator: Allocator) void {
self.page.releaseArena(allocator);
}
pub fn headersForRequest(self: *const Execution, headers: *HttpClient.Headers) !void {
return switch (self.js.global) {
inline else => |g| g.headersForRequest(headers),
+1 -1
View File
@@ -91,7 +91,7 @@ pub fn persist(self: Module) !Global {
var ctx = self.local.ctx;
var global: v8.Global = undefined;
v8.v8__Global__New(ctx.isolate.handle, self.handle, &global);
try ctx.global_modules.append(ctx.arena, global);
try ctx.global_modules.append(ctx.arena.allocator(), global);
return .{ .handle = global };
}
+5 -6
View File
@@ -24,18 +24,17 @@
// separately via js.Identity - Session has the main world Identity, and
// IsolatedWorlds have their own Identity instances.
const std = @import("std");
const lp = @import("lightpanda");
const js = @import("js.zig");
const App = @import("../../App.zig");
const v8 = js.v8;
const Allocator = std.mem.Allocator;
const Origin = @This();
rc: usize = 1,
arena: Allocator,
arena: *lp.Arena,
// The key, e.g. lightpanda.io:443
key: []const u8,
@@ -46,7 +45,7 @@ security_token: v8.Global,
pub fn init(app: *App, isolate: js.Isolate, key: []const u8) !*Origin {
const arena = try app.arena_pool.acquire(.tiny, "Origin");
errdefer app.arena_pool.release(arena);
errdefer arena.release();
var hs: js.HandleScope = undefined;
hs.init(isolate);
@@ -67,7 +66,7 @@ pub fn init(app: *App, isolate: js.Isolate, key: []const u8) !*Origin {
return self;
}
pub fn deinit(self: *Origin, app: *App) void {
pub fn deinit(self: *Origin, _: *App) void {
v8.v8__Global__Reset(&self.security_token);
app.arena_pool.release(self.arena);
self.arena.release();
}
+1 -1
View File
@@ -601,7 +601,7 @@ const CloneDelegate = struct {
const handle = message orelse break :blk null;
const str = js.String{ .local = local, .handle = handle };
// the exception can outlive this call; dupe onto the context arena
break :blk str.toSliceWithAlloc(local.ctx.arena) catch null;
break :blk str.toSliceWithAlloc(local.ctx.arena.allocator()) catch null;
};
throwDataCloneException(local, msg);
}
+1 -1
View File
@@ -782,7 +782,7 @@ pub fn unknownObjectPropertyCallback(comptime JsApi: type) *const fn (?*const v8
fn logUnknownProperty(local: *const js.Local, key: []const u8) !void {
const ctx = local.ctx;
const gop = try ctx.unknown_properties.getOrPut(ctx.arena, key);
const gop = try ctx.unknown_properties.getOrPut(ctx.arena.allocator(), key);
if (gop.found_existing) {
gop.value_ptr.count += 1;
} else {
+2 -4
View File
@@ -26,15 +26,13 @@ const Node = @import("Node.zig");
const Range = @import("Range.zig");
const StaticRange = @import("StaticRange.zig");
const Allocator = std.mem.Allocator;
const AbstractRange = @This();
pub const _prototype_root = true;
_rc: lp.RC = .{},
_type: Type,
_arena: Allocator,
_arena: *lp.Arena,
_end_offset: u32,
_start_offset: u32,
_frame_loader_id: u32,
@@ -55,7 +53,7 @@ pub fn deinit(self: *AbstractRange, page: *Page) void {
frame._live_ranges.remove(&self._range_link);
}
}
page.releaseArena(self._arena);
self._arena.release();
}
pub fn releaseRef(self: *AbstractRange, page: *Page) void {
+11 -12
View File
@@ -26,7 +26,6 @@ const Mime = @import("../Mime.zig");
const Writer = std.Io.Writer;
const Execution = js.Execution;
const Allocator = std.mem.Allocator;
/// https://w3c.github.io/FileAPI/#blob-section
/// https://developer.mozilla.org/en-US/docs/Web/API/Blob
@@ -37,7 +36,7 @@ pub const _prototype_root = true;
_type: Type,
_rc: lp.RC,
_arena: Allocator,
_arena: *lp.Arena,
/// Immutable slice of blob.
/// Note that another blob may hold a pointer/slice to this,
@@ -82,7 +81,7 @@ const InitOptions = struct {
pub fn init(parts_: ?[]const js.Value, opts_: ?InitOptions, page: *Page) !*Blob {
const session = page.session;
const arena = try session.getArena(.large, "Blob");
errdefer session.releaseArena(arena);
errdefer arena.release();
const self = try arena.create(Blob);
self.* = try buildValue(arena, parts_, opts_ orelse .{});
@@ -92,13 +91,13 @@ pub fn init(parts_: ?[]const js.Value, opts_: ?InitOptions, page: *Page) !*Blob
// The Blob value for `parts`, with everything it references copied to
// `arena`. Callers either arena.create it (init) or embed it as the root of
// a {Blob, File} chain.
pub fn buildValue(arena: Allocator, parts_: ?[]const js.Value, opts: InitOptions) !Blob {
const mime = try Mime.serialize(arena, opts.type);
pub fn buildValue(arena: *lp.Arena, parts_: ?[]const js.Value, opts: InitOptions) !Blob {
const mime = try Mime.serialize(arena.allocator(), opts.type);
const data = blk: {
if (parts_) |blob_parts| {
const use_native_endings = std.mem.eql(u8, opts.endings, "native");
var w: Writer.Allocating = .init(arena);
var w: Writer.Allocating = .init(arena.allocator());
for (blob_parts) |js_val| {
const part = try js_val.toStringSmart();
try writePartWithEndings(part, use_native_endings, &w.writer);
@@ -118,28 +117,28 @@ pub fn buildValue(arena: Allocator, parts_: ?[]const js.Value, opts: InitOptions
};
}
pub fn buildValueFromBytes(arena: Allocator, data: []const u8, content_type: []const u8) !Blob {
pub fn buildValueFromBytes(arena: *lp.Arena, data: []const u8, content_type: []const u8) !Blob {
return .{
._rc = .{},
._arena = arena,
._type = .generic,
._slice = try arena.dupe(u8, data),
._mime = try Mime.serialize(arena, content_type),
._mime = try Mime.serialize(arena.allocator(), content_type),
};
}
/// Creates a new Blob from raw byte slices (for internal Zig use).
pub fn initFromBytes(data: []const u8, content_type: []const u8, page: *Page) !*Blob {
const arena = try page.getArena(data.len + content_type.len + 256, "Blob");
errdefer page.releaseArena(arena);
errdefer arena.release();
const self = try arena.create(Blob);
self.* = try buildValueFromBytes(arena, data, content_type);
return self;
}
pub fn deinit(self: *Blob, page: *Page) void {
page.releaseArena(self._arena);
pub fn deinit(self: *Blob, _: *Page) void {
self._arena.release();
}
pub fn releaseRef(self: *Blob, page: *Page) void {
@@ -160,7 +159,7 @@ pub fn structuredDeserialize(reader: *js.StructuredReader, page: *Page) !*Blob {
const data = try reader.readBytes();
const arena = try page.getArena(data.len + mime.len + 256, "Blob.clone");
errdefer page.releaseArena(arena);
errdefer arena.release();
const self = try arena.create(Blob);
self.* = .{
+2 -2
View File
@@ -174,12 +174,12 @@ const PostMessageCallback = struct {
// (never realloc) and teardown is deferred to the next tick, so walking
// each channel list live during dispatch is safe.
const arena = try page.getArena(.tiny, "BroadcastChannel.postMessage");
defer page.releaseArena(arena);
defer arena.release();
// Opaque origins have no string form and are unique per execution, so
// the sender is the only same-origin context
const executions = if (origin) |o|
try page.executionsForOrigin(arena, o)
try page.executionsForOrigin(arena.allocator(), o)
else
(&self.exec)[0..1];
+4 -6
View File
@@ -16,7 +16,6 @@
// 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 crypto = @import("../../sys/libcrypto.zig");
@@ -24,14 +23,13 @@ const js = @import("../js/js.zig");
const Page = @import("../Page.zig");
const Execution = js.Execution;
const Allocator = std.mem.Allocator;
/// Represents a cryptographic key obtained from one of the SubtleCrypto methods
/// generateKey(), deriveKey(), importKey(), or unwrapKey().
const CryptoKey = @This();
_rc: lp.RC = .{},
_arena: Allocator = undefined,
_arena: *lp.Arena = undefined,
/// Algorithm being used.
_type: Type,
/// Whether this is a secret (symmetric), public, or private key. Surfaced as
@@ -105,7 +103,7 @@ pub const Usages = struct {
/// are expected to be static strings. Takes ownership of `_vary.pkey`.
pub fn init(exec: *const Execution, key: CryptoKey) !*CryptoKey {
const arena = try exec.getArena(.tiny, "CryptoKey");
errdefer exec.releaseArena(arena);
errdefer arena.release();
const self = try arena.create(CryptoKey);
self.* = key;
@@ -117,12 +115,12 @@ pub fn init(exec: *const Execution, key: CryptoKey) !*CryptoKey {
return self;
}
pub fn deinit(self: *CryptoKey, page: *Page) void {
pub fn deinit(self: *CryptoKey, _: *Page) void {
switch (self._vary) {
.pkey => |pkey| crypto.EVP_PKEY_free(pkey),
.none, .digest => {},
}
page.releaseArena(self._arena);
self._arena.release();
}
pub fn releaseRef(self: *CryptoKey, page: *Page) void {
+2 -2
View File
@@ -36,9 +36,9 @@ pub fn init(init_: ?js.Value, exec: *const js.Execution) !*DOMMatrix {
pub fn create(m: [16]f64, is_2d: bool, page: *Page) !*DOMMatrix {
const arena = try page.getArena(.tiny, "DOMMatrix");
errdefer page.releaseArena(arena);
errdefer arena.release();
const self = try Factory.chainedWithAllocator(arena, .{
const self = try Factory.chainedWithAllocator(arena.allocator(), .{
RO.buildValue(arena, m, is_2d),
DOMMatrix{ ._proto = undefined },
});
+5 -7
View File
@@ -23,15 +23,13 @@ const js = @import("../js/js.zig");
const Page = @import("../Page.zig");
const DOMMatrix = @import("DOMMatrix.zig");
const Allocator = std.mem.Allocator;
const DOMMatrixReadOnly = @This();
pub const _prototype_root = true;
_type: Type,
_rc: lp.RC,
_arena: Allocator,
_arena: *lp.Arena,
// Stored column-major, matching the spec's mAB naming where A is the column
// and B is the row:
@@ -68,8 +66,8 @@ pub fn init(init_: ?js.Value, exec: *const js.Execution) !*DOMMatrixReadOnly {
return createBare(parsed.m, parsed.is_2d, exec.page);
}
pub fn deinit(self: *DOMMatrixReadOnly, page: *Page) void {
page.releaseArena(self._arena);
pub fn deinit(self: *DOMMatrixReadOnly, _: *Page) void {
self._arena.release();
}
pub fn acquireRef(self: *DOMMatrixReadOnly) void {
@@ -82,14 +80,14 @@ pub fn releaseRef(self: *DOMMatrixReadOnly, page: *Page) void {
pub fn createBare(m: [16]f64, is_2d: bool, page: *Page) !*DOMMatrixReadOnly {
const arena = try page.getArena(.tiny, "DOMMatrix");
errdefer page.releaseArena(arena);
errdefer arena.release();
const self = try arena.create(DOMMatrixReadOnly);
self.* = buildValue(arena, m, is_2d);
return self;
}
pub fn buildValue(arena: std.mem.Allocator, m: [16]f64, is_2d: bool) DOMMatrixReadOnly {
pub fn buildValue(arena: *lp.Arena, m: [16]f64, is_2d: bool) DOMMatrixReadOnly {
return .{
._rc = .{},
._arena = arena,
+2 -2
View File
@@ -52,7 +52,7 @@ pub fn parseFromString(
return switch (target_mime) {
.@"text/html" => {
const arena = try frame.getArena(.medium, "DOMParser.parseFromString");
defer frame.releaseArena(arena);
defer arena.release();
// DOMParser builds a detached Document. Borrow the same fragment
// parse-mode that `Frame.parse` uses so frame-side hooks
@@ -76,7 +76,7 @@ pub fn parseFromString(
}
// Parse HTML into the document
var parser = Parser.init(arena, doc.asNode(), frame, .{});
var parser = Parser.init(arena.allocator(), doc.asNode(), frame, .{});
parser.parse(normalized);
if (parser.terminated) {
return error.ExecutionTerminated;
+2 -2
View File
@@ -33,9 +33,9 @@ pub fn init(x_: ?f64, y_: ?f64, z_: ?f64, w_: ?f64, exec: *const js.Execution) !
pub fn create(x: f64, y: f64, z: f64, w: f64, page: *Page) !*DOMPoint {
const arena = try page.getArena(.tiny, "DOMPoint");
errdefer page.releaseArena(arena);
errdefer arena.release();
const self = try Factory.chainedWithAllocator(arena, .{
const self = try Factory.chainedWithAllocator(arena.allocator(), .{
RO.buildValue(arena, x, y, z, w),
DOMPoint{ ._proto = undefined },
});
+5 -7
View File
@@ -24,15 +24,13 @@ const Page = @import("../Page.zig");
const DOMPoint = @import("DOMPoint.zig");
const Matrix = @import("DOMMatrixReadOnly.zig");
const Allocator = std.mem.Allocator;
const DOMPointReadOnly = @This();
pub const _prototype_root = true;
_type: Type,
_rc: lp.RC,
_arena: Allocator,
_arena: *lp.Arena,
_x: f64,
_y: f64,
@@ -72,8 +70,8 @@ pub fn init(x_: ?f64, y_: ?f64, z_: ?f64, w_: ?f64, exec: *const js.Execution) !
return createBare(x_ orelse 0, y_ orelse 0, z_ orelse 0, w_ orelse 1, exec.page);
}
pub fn deinit(self: *DOMPointReadOnly, page: *Page) void {
page.releaseArena(self._arena);
pub fn deinit(self: *DOMPointReadOnly, _: *Page) void {
self._arena.release();
}
pub fn acquireRef(self: *DOMPointReadOnly) void {
@@ -86,14 +84,14 @@ pub fn releaseRef(self: *DOMPointReadOnly, page: *Page) void {
pub fn createBare(x: f64, y: f64, z: f64, w: f64, page: *Page) !*DOMPointReadOnly {
const arena = try page.getArena(.tiny, "DOMPoint");
errdefer page.releaseArena(arena);
errdefer arena.release();
const self = try arena.create(DOMPointReadOnly);
self.* = buildValue(arena, x, y, z, w);
return self;
}
pub fn buildValue(arena: Allocator, x: f64, y: f64, z: f64, w: f64) DOMPointReadOnly {
pub fn buildValue(arena: *lp.Arena, x: f64, y: f64, z: f64, w: f64) DOMPointReadOnly {
return .{
._rc = .{},
._arena = arena,
+10 -10
View File
@@ -47,7 +47,7 @@ pub fn registerTypes() []const type {
};
}
_arena: Allocator,
_arena: *lp.Arena,
// Refcounted so the GC weak-finalizer (or page teardown) releases the pooled
// arena exactly once; mirrors Blob's lifecycle.
_rc: lp.RC = .{},
@@ -61,7 +61,7 @@ _effect_allowed: []const u8 = "uninitialized",
pub fn init(frame: *Frame) !*DataTransfer {
const arena = try frame.getArena(.medium, "DataTransfer");
errdefer frame.releaseArena(arena);
errdefer arena.release();
const fl = try frame._factory.create(FileList{});
try frame.trackFileList(fl);
@@ -77,8 +77,8 @@ pub fn init(frame: *Frame) !*DataTransfer {
return self;
}
pub fn deinit(self: *DataTransfer, page: *Page) void {
page.releaseArena(self._arena);
pub fn deinit(self: *DataTransfer, _: *Page) void {
self._arena.release();
}
pub fn acquireRef(self: *DataTransfer) void {
@@ -112,7 +112,7 @@ pub fn getData(self: *const DataTransfer, format: []const u8, frame: *Frame) ![]
}
pub fn setData(self: *DataTransfer, format: []const u8, data: []const u8) !void {
const norm = try normalizeFormat(self._arena, format);
const norm = try normalizeFormat(self._arena.allocator(), format);
const owned_data = try self._arena.dupe(u8, data);
for (self._items.items) |it| {
if (it._kind == .string and std.mem.eql(u8, it._type, norm)) {
@@ -122,7 +122,7 @@ pub fn setData(self: *DataTransfer, format: []const u8, data: []const u8) !void
}
const it = try self._arena.create(DataTransferItem);
it.* = .{ ._data_transfer = self, ._kind = .string, ._type = norm, ._payload = .{ .string = owned_data } };
try self._items.append(self._arena, it);
try self._items.append(self._arena.allocator(), it);
}
pub fn clearData(self: *DataTransfer, format_: ?[]const u8, frame: *Frame) !void {
@@ -158,11 +158,11 @@ pub fn addItem(self: *DataTransfer, data: js.Value, type_: ?[]const u8, frame: *
return try self.addFileItem(file, frame);
} else |_| {}
const owned_data = try data.toStringSliceWithAlloc(self._arena);
const norm = try normalizeFormat(self._arena, type_ orelse "");
const owned_data = try data.toStringSliceWithAlloc(self._arena.allocator());
const norm = try normalizeFormat(self._arena.allocator(), type_ orelse "");
const it = try self._arena.create(DataTransferItem);
it.* = .{ ._data_transfer = self, ._kind = .string, ._type = norm, ._payload = .{ .string = owned_data } };
try self._items.append(self._arena, it);
try self._items.append(self._arena.allocator(), it);
return it;
}
@@ -170,7 +170,7 @@ fn addFileItem(self: *DataTransfer, file: *File, frame: *Frame) !*DataTransferIt
file._proto.acquireRef();
const it = try self._arena.create(DataTransferItem);
it.* = .{ ._data_transfer = self, ._kind = .file, ._type = file._proto.getType(), ._payload = .{ .file = file } };
try self._items.append(self._arena, it);
try self._items.append(self._arena.allocator(), it);
try self.rebuildFiles(frame);
return it;
}
@@ -33,8 +33,6 @@ const WorkerGlobalScope = @import("WorkerGlobalScope.zig");
const MessageEvent = @import("event/MessageEvent.zig");
const Allocator = std.mem.Allocator;
const DedicatedWorkerGlobalScope = @This();
pub const Proto = WorkerGlobalScope;
@@ -54,7 +52,7 @@ _pending_messages: std.ArrayList(?js.Value.Global) = .empty,
pub fn init(worker: *Worker, url: [:0]const u8) !*DedicatedWorkerGlobalScope {
return WorkerGlobalScope.init(
worker._arena,
worker._arena.allocator(),
url,
.dedicated,
DedicatedWorkerGlobalScope{
@@ -152,7 +150,7 @@ fn scheduleMessage(self: *DedicatedWorkerGlobalScope, cloned_data: ?js.Value.Glo
const session = wgs._session;
const message_arena = try session.getArena(.tiny, "DedicatedWorkerGlobalScope.receiveMessage");
errdefer session.releaseArena(message_arena);
errdefer message_arena.release();
const callback = try message_arena.create(ReceiveMessageCallback);
callback.* = .{
@@ -184,7 +182,7 @@ pub fn drainPendingMessages(self: *DedicatedWorkerGlobalScope) void {
const ReceiveMessageCallback = struct {
data: ?js.Value.Global,
arena: Allocator,
arena: *lp.Arena,
worker_scope: *DedicatedWorkerGlobalScope,
fn cancelled(ctx: *anyopaque) void {
@@ -196,7 +194,7 @@ const ReceiveMessageCallback = struct {
}
fn deinit(self: *ReceiveMessageCallback) void {
self.worker_scope._proto._session.releaseArena(self.arena);
self.arena.release();
}
fn run(ctx: *anyopaque) !?u32 {
+3 -3
View File
@@ -1056,9 +1056,9 @@ fn writeInternal(self: *Document, text: []const []const u8, append_newline: bool
defer frame._parse_mode = previous_parse_mode;
const arena = try frame.getArena(.medium, "Document.write");
defer frame.releaseArena(arena);
defer arena.release();
var parser = Parser.init(arena, fragment_node, frame, .{ .allow_declarative_shadow = true });
var parser = Parser.init(arena.allocator(), fragment_node, frame, .{ .allow_declarative_shadow = true });
parser.parseFragment(html);
// Extract children from wrapper HTML element (html5ever wraps fragments)
@@ -1070,7 +1070,7 @@ fn writeInternal(self: *Document, text: []const []const u8, append_newline: bool
var it = if (first.is(Element.Html.Html) == null) fragment_node.childrenIterator() else first.childrenIterator();
while (it.next()) |child| {
try children_to_insert.append(arena, child);
try children_to_insert.append(arena.allocator(), child);
}
if (children_to_insert.items.len == 0) {
+8 -9
View File
@@ -27,13 +27,12 @@ const EventTarget = @import("EventTarget.zig");
const String = lp.String;
const Execution = js.Execution;
const Allocator = std.mem.Allocator;
pub const Event = @This();
pub const _prototype_root = true;
_type: Type,
_arena: Allocator,
_arena: *lp.Arena,
_bubbles: bool = false,
_cancelable: bool = false,
_composed: bool = false,
@@ -107,18 +106,18 @@ pub const Options = struct {
pub fn init(typ: []const u8, opts_: ?Options, page: *Page) !*Event {
const arena = try page.getArena(.tiny, "Event");
errdefer page.releaseArena(arena);
const str = try String.init(arena, typ, .{});
errdefer arena.release();
const str = try String.init(arena.allocator(), typ, .{});
return initWithTrusted(arena, str, opts_, false);
}
pub fn initTrusted(typ: String, opts_: ?Options, page: *Page) !*Event {
const arena = try page.getArena(.tiny, "Event.trusted");
errdefer page.releaseArena(arena);
errdefer arena.release();
return initWithTrusted(arena, typ, opts_, true);
}
fn initWithTrusted(arena: Allocator, typ: String, opts_: ?Options, comptime trusted: bool) !*Event {
fn initWithTrusted(arena: *lp.Arena, typ: String, opts_: ?Options, comptime trusted: bool) !*Event {
const opts = opts_ orelse Options{};
// Same (already coarsened) clock as the performance time origin, so the
@@ -150,7 +149,7 @@ pub fn initEvent(
}
self._initialized = true;
self._type_string = try String.init(self._arena, event_string, .{});
self._type_string = try String.init(self._arena.allocator(), event_string, .{});
self._bubbles = bubbles orelse false;
self._cancelable = cancelable orelse false;
self._stop_propagation = false;
@@ -162,8 +161,8 @@ pub fn acquireRef(self: *Event) void {
self._rc.acquire();
}
pub fn deinit(self: *Event, page: *Page) void {
page.releaseArena(self._arena);
pub fn deinit(self: *Event, _: *Page) void {
self._arena.release();
}
pub fn releaseRef(self: *Event, page: *Page) void {
+4 -4
View File
@@ -47,9 +47,9 @@ pub fn init(
const opts = opts_ orelse InitOptions{};
const session = page.session;
const arena = try session.getArena(.large, "Blob");
errdefer session.releaseArena(arena);
errdefer arena.release();
const file = try Factory.chainedWithAllocator(arena, .{
const file = try Factory.chainedWithAllocator(arena.allocator(), .{
try Blob.buildValue(arena, parts_, .{
.type = opts.type,
.endings = opts.endings,
@@ -90,9 +90,9 @@ pub fn structuredDeserialize(reader: *js.StructuredReader, page: *Page) !*File {
const last_modified = try reader.readUint64();
const arena = try page.getArena(data.len + mime.len + name.len + 256, "Blob.clone");
errdefer page.releaseArena(arena);
errdefer arena.release();
const file = try Factory.chainedWithAllocator(arena, .{
const file = try Factory.chainedWithAllocator(arena.allocator(), .{
Blob{
._rc = .{},
._arena = arena,
+6 -6
View File
@@ -38,7 +38,7 @@ pub const Proto = EventTarget;
_rc: lp.RC = .{},
_exec: *Execution,
_proto: *EventTarget,
_arena: Allocator,
_arena: *lp.Arena,
_ready_state: ReadyState = .empty,
_result: ?Result = null,
@@ -67,16 +67,16 @@ const Result = union(enum) {
pub fn init(exec: *Execution) !*FileReader {
const arena = try exec.getArena(.tiny, "FileReader");
errdefer exec.releaseArena(arena);
errdefer arena.release();
return exec._factory.eventTargetWithAllocator(arena, FileReader{
return exec._factory.eventTargetWithAllocator(arena.allocator(), FileReader{
._exec = exec,
._arena = arena,
._proto = undefined,
});
}
pub fn deinit(self: *FileReader, page: *Page) void {
pub fn deinit(self: *FileReader, _: *Page) void {
if (self._on_abort) |func| func.release();
if (self._on_error) |func| func.release();
if (self._on_load) |func| func.release();
@@ -84,7 +84,7 @@ pub fn deinit(self: *FileReader, page: *Page) void {
if (self._on_load_start) |func| func.release();
if (self._on_progress) |func| func.release();
page.releaseArena(self._arena);
self._arena.release();
}
pub fn releaseRef(self: *FileReader, page: *Page) void {
@@ -219,7 +219,7 @@ fn readInternal(self: *FileReader, blob: *Blob, read_type: ReadType) !void {
.data_url => blk: {
// Create data URL with base64 encoding
const mime = if (blob._mime.len > 0) blob._mime else "application/octet-stream";
const data_url = try encodeDataURL(self._arena, mime, data);
const data_url = try encodeDataURL(self._arena.allocator(), mime, data);
break :blk .{ .string = data_url };
},
};
+4 -4
View File
@@ -54,11 +54,11 @@ pub fn pushState(_: *History, state: js.Value, _: ?[]const u8, _url: ?[]const u8
const session = frame._session;
const arena = session.arena;
const url = if (_url) |u|
try @import("../URL.zig").resolve(arena, frame.url, u, .{})
try @import("../URL.zig").resolve(arena.allocator(), frame.url, u, .{})
else
try arena.dupeZ(u8, frame.url);
const json = state.toJson(arena) catch return error.DataClone;
const json = state.toJson(arena.allocator()) catch return error.DataClone;
_ = try session.navigation.pushEntry(url, .{ .source = .history, .value = json }, frame, true);
frame.url = url;
@@ -76,11 +76,11 @@ pub fn replaceState(_: *History, state: js.Value, _: ?[]const u8, _url: ?[]const
const session = frame._session;
const arena = session.arena;
const url = if (_url) |u|
try @import("../URL.zig").resolve(arena, frame.url, u, .{})
try @import("../URL.zig").resolve(arena.allocator(), frame.url, u, .{})
else
try arena.dupeZ(u8, frame.url);
const json = state.toJson(arena) catch return error.DataClone;
const json = state.toJson(arena.allocator()) catch return error.DataClone;
_ = try session.navigation.replaceEntry(url, .{ .source = .history, .value = json }, frame, true);
frame.url = url;
+10 -11
View File
@@ -28,7 +28,6 @@ const Element = @import("Element.zig");
const DOMRect = @import("DOMRect.zig");
const log = lp.log;
const Allocator = std.mem.Allocator;
pub fn registerTypes() []const type {
return &.{
@@ -40,7 +39,7 @@ pub fn registerTypes() []const type {
const IntersectionObserver = @This();
_rc: lp.RC = .{},
_arena: Allocator,
_arena: *lp.Arena,
_callback: js.Function.Global,
_observing: std.ArrayList(*Element) = .empty,
_root: ?*Element = null,
@@ -67,7 +66,7 @@ pub const ObserverInit = struct {
pub fn init(callback: js.Function.Global, options: ?ObserverInit, frame: *Frame) !*IntersectionObserver {
const arena = try frame.getArena(.small, "IntersectionObserver");
errdefer frame.releaseArena(arena);
errdefer arena.release();
const opts = options orelse ObserverInit{};
const root_margin = if (opts.rootMargin) |rm| try arena.dupe(u8, rm) else "0px";
@@ -113,7 +112,7 @@ pub fn deinit(self: *IntersectionObserver, page: *Page) void {
// FinalizerCallback. We 100% own them.
entry.deinit(page);
}
page.releaseArena(self._arena);
self._arena.release();
}
pub fn releaseRef(self: *IntersectionObserver, page: *Page) void {
@@ -132,12 +131,12 @@ pub fn observe(self: *IntersectionObserver, target: *Element, frame: *Frame) !vo
}
}
try self._observing.append(self._arena, target);
try self._observing.append(self._arena.allocator(), target);
if (self._observing.items.len == 1) {
try Frame.observers.registerIntersectionObserver(frame, self);
}
try self._tracked.put(self._arena, target, {});
try self._tracked.put(self._arena.allocator(), target, {});
// Check intersection for this new target and schedule delivery
try self.checkIntersection(target, frame);
@@ -266,7 +265,7 @@ fn checkIntersection(self: *IntersectionObserver, target: *Element, frame: *Fram
// document to fake a position (O(node count)) — so it only runs here.
const data = try self.calculateIntersection(target, has_parent, frame);
const arena = try frame.getArena(.tiny, "IntersectionObserverEntry");
errdefer frame.releaseArena(arena);
errdefer arena.release();
const entry = try arena.create(IntersectionObserverEntry);
entry.* = .{
@@ -279,7 +278,7 @@ fn checkIntersection(self: *IntersectionObserver, target: *Element, frame: *Fram
._bounding_client_rect = try DOMRect.create(data.bounding_client_rect, frame._factory),
._intersection_ratio = data.intersection_ratio,
};
try self._pending_entries.append(self._arena, entry);
try self._pending_entries.append(self._arena.allocator(), entry);
_ = self._tracked.removeByPtr(tracked.key_ptr);
}
@@ -317,7 +316,7 @@ pub fn deliverEntries(self: *IntersectionObserver, frame: *Frame) !void {
pub const IntersectionObserverEntry = struct {
_rc: lp.RC = .{},
_arena: Allocator,
_arena: *lp.Arena,
_time: f64,
_target: *Element,
_bounding_client_rect: *DOMRect,
@@ -326,8 +325,8 @@ pub const IntersectionObserverEntry = struct {
_intersection_ratio: f64,
_is_intersecting: bool,
pub fn deinit(self: *IntersectionObserverEntry, page: *Page) void {
page.releaseArena(self._arena);
pub fn deinit(self: *IntersectionObserverEntry, _: *Page) void {
self._arena.release();
}
pub fn releaseRef(self: *IntersectionObserverEntry, page: *Page) void {
+10 -11
View File
@@ -28,7 +28,6 @@ const Element = @import("Element.zig");
const log = lp.log;
const String = lp.String;
const Allocator = std.mem.Allocator;
pub fn registerTypes() []const type {
return &.{
@@ -40,7 +39,7 @@ pub fn registerTypes() []const type {
const MutationObserver = @This();
_rc: lp.RC = .{},
_arena: Allocator,
_arena: *lp.Arena,
_callback: js.Function.Global,
_observing: std.ArrayList(Observing) = .empty,
_pending_records: std.ArrayList(*MutationRecord) = .empty,
@@ -76,7 +75,7 @@ pub const ObserveOptions = struct {
pub fn init(callback: js.Function.Global, frame: *Frame) !*MutationObserver {
const arena = try frame.getArena(.small, "MutationObserver");
errdefer frame.releaseArena(arena);
errdefer arena.release();
const self = try arena.create(MutationObserver);
self.* = .{
._arena = arena,
@@ -92,7 +91,7 @@ pub fn deinit(self: *MutationObserver, page: *Page) void {
record.deinit(page);
}
self._callback.release();
page.releaseArena(self._arena);
self._arena.release();
}
pub fn releaseRef(self: *MutationObserver, page: *Page) void {
@@ -165,7 +164,7 @@ pub fn observe(self: *MutationObserver, target: *Node, options: ObserveOptions,
}
}
try self._observing.append(arena, .{
try self._observing.append(arena.allocator(), .{
.target = target,
.options = store_options,
});
@@ -242,7 +241,7 @@ pub fn notifyAttributeChange(
._next_sibling = null,
};
try self._pending_records.append(self._arena, record);
try self._pending_records.append(self._arena.allocator(), record);
try Frame.observers.scheduleMutationDelivery(frame);
break;
@@ -286,7 +285,7 @@ pub fn notifyCharacterDataChange(
._next_sibling = null,
};
try self._pending_records.append(self._arena, record);
try self._pending_records.append(self._arena.allocator(), record);
try Frame.observers.scheduleMutationDelivery(frame);
break;
@@ -330,7 +329,7 @@ pub fn notifyChildListChange(
._next_sibling = next_sibling,
};
try self._pending_records.append(self._arena, record);
try self._pending_records.append(self._arena.allocator(), record);
try Frame.observers.scheduleMutationDelivery(frame);
break;
@@ -360,7 +359,7 @@ pub const MutationRecord = struct {
_rc: lp.RC = .{},
_type: Type,
_target: *Node,
_arena: Allocator,
_arena: *lp.Arena,
_attribute_name: ?[]const u8,
_old_value: ?[]const u8,
_added_nodes: []const *Node,
@@ -374,8 +373,8 @@ pub const MutationRecord = struct {
characterData,
};
pub fn deinit(self: *MutationRecord, session: *Page) void {
session.releaseArena(self._arena);
pub fn deinit(self: *MutationRecord, _: *Page) void {
self._arena.release();
}
pub fn releaseRef(self: *MutationRecord, session: *Page) void {
+5 -7
View File
@@ -16,7 +16,6 @@
// 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");
@@ -25,14 +24,13 @@ const Page = @import("../Page.zig");
const EventTarget = @import("EventTarget.zig");
const Execution = js.Execution;
const Allocator = std.mem.Allocator;
const Notification = @This();
pub const Proto = EventTarget;
_rc: lp.RC = .{},
_arena: Allocator,
_arena: *lp.Arena,
_proto: *EventTarget,
_title: []const u8,
_body: []const u8 = "",
@@ -61,10 +59,10 @@ const Options = struct {
pub fn init(title: []const u8, options_: ?Options, exec: *const Execution) !*Notification {
const arena = try exec.getArena(.small, "Notification");
errdefer exec.releaseArena(arena);
errdefer arena.release();
const options = options_ orelse Options{};
return exec._factory.eventTargetWithAllocator(arena, Notification{
return exec._factory.eventTargetWithAllocator(arena.allocator(), Notification{
._arena = arena,
._proto = undefined,
._title = try arena.dupe(u8, title),
@@ -81,8 +79,8 @@ pub fn init(title: []const u8, options_: ?Options, exec: *const Execution) !*Not
});
}
pub fn deinit(self: *Notification, page: *Page) void {
page.releaseArena(self._arena);
pub fn deinit(self: *Notification, _: *Page) void {
self._arena.release();
}
pub fn releaseRef(self: *Notification, page: *Page) void {
+4 -7
View File
@@ -16,15 +16,12 @@
// 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 Execution = js.Execution;
const Allocator = std.mem.Allocator;
pub fn registerTypes() []const type {
return &.{ Permissions, PermissionStatus };
}
@@ -48,7 +45,7 @@ const QueryDescriptor = struct {
// 'prompt' (the default safe value — neither granted nor denied) when unset.
pub fn query(_: *const Permissions, qd: QueryDescriptor, exec: *const Execution) !js.Promise {
const arena = try exec.getArena(.tiny, "PermissionStatus");
errdefer exec.releaseArena(arena);
errdefer arena.release();
const state = exec.session.browser.permissions.get(qd.name) orelse .prompt;
const status = try arena.create(PermissionStatus);
@@ -62,12 +59,12 @@ pub fn query(_: *const Permissions, qd: QueryDescriptor, exec: *const Execution)
const PermissionStatus = struct {
_rc: lp.RC = .{},
_arena: Allocator,
_arena: *lp.Arena,
_name: []const u8,
_state: State,
pub fn deinit(self: *PermissionStatus, page: *Page) void {
page.releaseArena(self._arena);
pub fn deinit(self: *PermissionStatus, _: *Page) void {
self._arena.release();
}
pub fn releaseRef(self: *PermissionStatus, page: *Page) void {
+2 -2
View File
@@ -41,7 +41,7 @@ pub fn init(frame: *Frame) !*Range {
// frame's main document.
pub fn initIn(container: *Node, frame: *Frame) !*Range {
const arena = try frame.getArena(.medium, "Range");
errdefer frame.releaseArena(arena);
errdefer arena.release();
const range = try frame._factory.abstractRange(arena, Range{ ._proto = undefined }, frame);
range._proto._start_container = container;
range._proto._end_container = container;
@@ -328,7 +328,7 @@ pub fn intersectsNode(self: *const Range, node: *Node) bool {
pub fn cloneRange(self: *const Range, frame: *Frame) !*Range {
const arena = try frame.getArena(.medium, "Range.clone");
errdefer frame.releaseArena(arena);
errdefer arena.release();
const clone = try frame._factory.abstractRange(arena, Range{ ._proto = undefined }, frame);
clone._proto._end_offset = self._proto._end_offset;
+5 -6
View File
@@ -33,7 +33,6 @@ const DOMRect = @import("DOMRect.zig");
const Factory = @import("../Factory.zig");
const log = lp.log;
const Allocator = std.mem.Allocator;
pub fn registerTypes() []const type {
return &.{
@@ -46,7 +45,7 @@ pub fn registerTypes() []const type {
const ResizeObserver = @This();
_rc: lp.RC = .{},
_arena: Allocator,
_arena: *lp.Arena,
_callback: js.Function.Global,
_observations: std.ArrayList(Observation) = .empty,
@@ -63,7 +62,7 @@ const Options = struct {
pub fn init(callback: js.Function.Global, frame: *Frame) !*ResizeObserver {
const arena = try frame.getArena(.small, "ResizeObserver");
errdefer frame.releaseArena(arena);
errdefer arena.release();
const self = try arena.create(ResizeObserver);
self.* = .{
@@ -73,9 +72,9 @@ pub fn init(callback: js.Function.Global, frame: *Frame) !*ResizeObserver {
return self;
}
pub fn deinit(self: *ResizeObserver, page: *Page) void {
pub fn deinit(self: *ResizeObserver, _: *Page) void {
self._callback.release();
page.releaseArena(self._arena);
self._arena.release();
}
pub fn acquireRef(self: *ResizeObserver) void {
@@ -95,7 +94,7 @@ pub fn observe(self: *ResizeObserver, target: *Element, options_: ?Options, fram
}
}
try self._observations.append(self._arena, .{ .target = target });
try self._observations.append(self._arena.allocator(), .{ .target = target });
if (self._observations.items.len == 1) {
try Frame.observers.registerResizeObserver(frame, self);
}
+15 -16
View File
@@ -30,7 +30,6 @@ const WorkerGlobalScope = @import("WorkerGlobalScope.zig");
const MessageEvent = @import("event/MessageEvent.zig");
const log = lp.log;
const Allocator = std.mem.Allocator;
const IS_DEBUG = @import("builtin").mode == .Debug;
const SharedWorkerGlobalScope = @This();
@@ -38,7 +37,7 @@ const SharedWorkerGlobalScope = @This();
pub const Proto = WorkerGlobalScope;
_proto: *WorkerGlobalScope,
_arena: Allocator,
_arena: *lp.Arena,
_url: [:0]const u8,
_name: []const u8,
@@ -55,7 +54,7 @@ _loader_id: u32,
_closed: bool = false,
_script_loaded: bool = false,
_script_arena: ?Allocator = null,
_script_arena: ?*lp.Arena = null,
_script_buffer: std.ArrayList(u8) = .empty,
_http_transfer: ?*Transfer = null,
@@ -68,13 +67,13 @@ pub fn init(frame: *Frame, url: [:0]const u8, name: []const u8, worker_type: Wor
const session = frame._session;
const arena = try session.getArena(.small, "SharedWorker");
errdefer session.releaseArena(arena);
errdefer arena.release();
const owned_url = try arena.dupeZ(u8, url);
const frame_id = session.nextFrameId();
const loader_id = session.nextLoaderId();
const self = try WorkerGlobalScope.init(
arena,
arena.allocator(),
owned_url,
.shared,
SharedWorkerGlobalScope{
@@ -143,7 +142,7 @@ pub fn deinit(self: *SharedWorkerGlobalScope) void {
self.releaseScriptArena();
self.unregister();
self._proto.deinit();
self._proto._session.releaseArena(self._arena);
self._arena.release();
}
pub fn register(self: *SharedWorkerGlobalScope, lookup_key: []const u8) !void {
@@ -152,7 +151,7 @@ pub fn register(self: *SharedWorkerGlobalScope, lookup_key: []const u8) !void {
const key = try self._arena.dupe(u8, lookup_key);
const session = self._proto._session;
try session.shared_workers.put(session.arena, key, self);
try session.shared_workers.put(session.arena.allocator(), key, self);
self._registry_key = key;
}
@@ -172,7 +171,7 @@ pub fn connect(self: *SharedWorkerGlobalScope, client_exec: *js.Execution) !*Mes
MessagePort.entangle(client_port, worker_port);
if (self._script_loaded == false) {
try self._pending_connects.append(self._arena, worker_port);
try self._pending_connects.append(self._arena.allocator(), worker_port);
return client_port;
}
@@ -214,7 +213,7 @@ fn httpHeaderCallback(transfer: *Transfer) !Transfer.HeaderResult {
}
if (transfer.getContentLength()) |cl| {
try self._script_buffer.ensureTotalCapacity(self._script_arena.?, cl);
try self._script_buffer.ensureTotalCapacity(self._script_arena.?.allocator(), cl);
}
return .proceed;
@@ -222,7 +221,7 @@ fn httpHeaderCallback(transfer: *Transfer) !Transfer.HeaderResult {
fn httpDataCallback(transfer: *Transfer, data: []const u8) !void {
const self: *SharedWorkerGlobalScope = @ptrCast(@alignCast(transfer.req.ctx));
try self._script_buffer.appendSlice(self._script_arena.?, data);
try self._script_buffer.appendSlice(self._script_arena.?.allocator(), data);
}
fn httpDoneCallback(ctx: *anyopaque) !void {
@@ -297,7 +296,7 @@ fn loadInitialScript(self: *SharedWorkerGlobalScope, script: []const u8) !void {
}
js_context.page.recordJsError(err);
const caught = try_catch.caughtOrError(self._script_arena.?, err);
const caught = try_catch.caughtOrError(self._script_arena.?.allocator(), err);
log.err(.browser, "shared worker script error", .{ .url = self._url, .caught = caught });
return;
},
@@ -307,7 +306,7 @@ fn loadInitialScript(self: *SharedWorkerGlobalScope, script: []const u8) !void {
}
js_context.page.recordJsError(err);
const caught = try_catch.caughtOrError(self._script_arena.?, err);
const caught = try_catch.caughtOrError(self._script_arena.?.allocator(), err);
log.err(.browser, "shared worker module error", .{ .url = self._url, .caught = caught });
return;
},
@@ -322,7 +321,7 @@ fn releaseScriptArena(self: *SharedWorkerGlobalScope) void {
const arena = self._script_arena orelse return;
self._script_arena = null;
self._script_buffer = .empty;
self._proto._session.releaseArena(arena);
arena.release();
}
fn drainPendingConnects(self: *SharedWorkerGlobalScope) void {
@@ -339,7 +338,7 @@ fn scheduleConnect(self: *SharedWorkerGlobalScope, port: *MessagePort) !void {
const session = wgs._session;
const connect_arena = try session.getArena(.tiny, "SharedWorkerGlobalScope.connect");
errdefer session.releaseArena(connect_arena);
errdefer connect_arena.release();
const callback = try connect_arena.create(ConnectCallback);
callback.* = .{
@@ -357,7 +356,7 @@ fn scheduleConnect(self: *SharedWorkerGlobalScope, port: *MessagePort) !void {
const ConnectCallback = struct {
port: *MessagePort,
arena: Allocator,
arena: *lp.Arena,
worker_scope: *SharedWorkerGlobalScope,
fn cancelled(ctx: *anyopaque) void {
@@ -366,7 +365,7 @@ const ConnectCallback = struct {
}
fn deinit(self: *ConnectCallback) void {
self.worker_scope._proto._session.releaseArena(self.arena);
self.arena.release();
}
fn run(ctx: *anyopaque) !?u32 {
+1 -1
View File
@@ -50,7 +50,7 @@ pub fn init(opts: StaticRangeInit, frame: *Frame) !*StaticRange {
}
const arena = try frame.getArena(.medium, "StaticRange");
errdefer frame.releaseArena(arena);
errdefer arena.release();
const static_range = try frame._factory.abstractRange(arena, StaticRange{ ._proto = undefined }, frame);
const proto = static_range._proto;
+3 -4
View File
@@ -27,7 +27,6 @@ const lp = @import("lightpanda");
const js = @import("../js/js.zig");
const log = lp.log;
const Allocator = std.mem.Allocator;
const CLAMP_MS = 4;
const CLAMP_NESTING = 5;
@@ -97,7 +96,7 @@ pub fn schedule(
}
const arena = try exec.getArena(.tiny, "Timers.schedule");
errdefer exec.releaseArena(arena);
errdefer arena.release();
const timer_id = self._timer_id +% 1;
self._timer_id = timer_id;
@@ -191,7 +190,7 @@ const ScheduleCallback = struct {
mode: Mode,
exec: *js.Execution,
timers: *Timers,
arena: Allocator,
arena: *lp.Arena,
removed: bool = false,
params: []const js.Value.Global,
@@ -205,7 +204,7 @@ const ScheduleCallback = struct {
for (self.params) |param| {
param.release();
}
self.exec.releaseArena(self.arena);
self.arena.release();
}
fn run(ptr: *anyopaque) !?u32 {
+3 -4
View File
@@ -35,7 +35,6 @@ const TouchEvent = @import("event/TouchEvent.zig");
const EventManagerBase = @import("../EventManagerBase.zig");
const log = lp.log;
const Allocator = std.mem.Allocator;
// This type is only included when the binary is built with the -Dwpt_extensions flag
const WebDriver = @This();
@@ -135,7 +134,7 @@ pub fn actionSequence(_: *const WebDriver, sources: js.Value, frame: *Frame) !js
}
const arena = try frame.getArena(.tiny, "WebDriver.actionSequence");
errdefer frame.releaseArena(arena);
errdefer arena.release();
const persisted = try sources.persist();
errdefer persisted.release();
@@ -164,7 +163,7 @@ pub fn actionSequence(_: *const WebDriver, sources: js.Value, frame: *Frame) !js
const ActionSequence = struct {
frame: *Frame,
arena: Allocator,
arena: *lp.Arena,
sources: js.Value.Global,
resolver: js.PromiseResolver.Global,
@@ -211,7 +210,7 @@ const ActionSequence = struct {
fn deinit(self: *ActionSequence) void {
self.sources.release();
self.resolver.release();
self.frame.releaseArena(self.arena);
self.arena.release();
}
};
+3 -4
View File
@@ -55,7 +55,6 @@ const Notification = @import("../../Notification.zig");
const log = lp.log;
const IS_DEBUG = builtin.mode == .Debug;
const Allocator = std.mem.Allocator;
const Execution = js.Execution;
pub fn registerTypes() []const type {
@@ -816,7 +815,7 @@ pub fn postMessage(self: *Window, message: js.Value, target_origin: ?[]const u8,
const source_window = target_frame.js.getIncumbent().window;
const arena = try target_frame.getArena(.medium, "Window.postMessage");
errdefer target_frame.releaseArena(arena);
errdefer arena.release();
// StructuredSerialize runs synchronously (per spec): clone the message into
// the target window's realm now. The receiver gets a fresh, independent copy
@@ -1079,13 +1078,13 @@ pub const Access = union(enum) {
const PostMessageCallback = struct {
frame: *Frame,
source: *Window,
arena: Allocator,
arena: *lp.Arena,
origin: []const u8,
message: js.Value.Global,
ports: []const *MessagePort,
fn deinit(self: *PostMessageCallback) void {
self.frame.releaseArena(self.arena);
self.arena.release();
}
// Called by the scheduler if the task is dropped before it runs. `run` and
+14 -15
View File
@@ -31,7 +31,6 @@ const ErrorEvent = @import("event/ErrorEvent.zig");
const DedicatedWorkerGlobalScope = @import("DedicatedWorkerGlobalScope.zig");
const log = lp.log;
const Allocator = std.mem.Allocator;
const IS_DEBUG = @import("builtin").mode == .Debug;
const Worker = @This();
@@ -51,13 +50,13 @@ _loader_id: u32,
_proto: *EventTarget,
_frame: *Frame,
_arena: Allocator,
_arena: *lp.Arena,
_worker_scope: *DedicatedWorkerGlobalScope,
_url: [:0]const u8,
_type: WorkerType = .classic,
_script_loaded: bool = false,
_script_arena: ?Allocator = null,
_script_arena: ?*lp.Arena = null,
_script_buffer: std.ArrayList(u8) = .empty,
_http_transfer: ?*Transfer = null,
@@ -74,10 +73,10 @@ pub fn init(url: []const u8, options: ?WorkerOptions, frame: *Frame) !*Worker {
const session = frame._session;
const arena = try session.getArena(.small, "Worker");
errdefer session.releaseArena(arena);
errdefer arena.release();
const resolved_url = try URL.resolve(arena, frame.base(), url, .{ .encoding = frame.charset });
const self = try frame._page.factory.eventTargetWithAllocator(arena, Worker{
const resolved_url = try URL.resolve(arena.allocator(), frame.base(), url, .{ .encoding = frame.charset });
const self = try frame._page.factory.eventTargetWithAllocator(arena.allocator(), Worker{
._arena = arena,
._proto = undefined,
._frame = frame,
@@ -152,7 +151,7 @@ pub fn deinit(self: *Worker) void {
}
self.releaseScriptArena();
self._worker_scope.deinit();
self._frame._session.releaseArena(self._arena);
self._arena.release();
}
pub fn asEventTarget(self: *Worker) *EventTarget {
@@ -172,7 +171,7 @@ fn httpHeaderCallback(transfer: *Transfer) !Transfer.HeaderResult {
}
if (transfer.getContentLength()) |cl| {
try self._script_buffer.ensureTotalCapacity(self._script_arena.?, cl);
try self._script_buffer.ensureTotalCapacity(self._script_arena.?.allocator(), cl);
}
return .proceed;
@@ -180,7 +179,7 @@ fn httpHeaderCallback(transfer: *Transfer) !Transfer.HeaderResult {
fn httpDataCallback(transfer: *Transfer, data: []const u8) !void {
const self: *Worker = @ptrCast(@alignCast(transfer.req.ctx));
try self._script_buffer.appendSlice(self._script_arena.?, data);
try self._script_buffer.appendSlice(self._script_arena.?.allocator(), data);
}
fn httpDoneCallback(ctx: *anyopaque) !void {
@@ -244,7 +243,7 @@ fn loadInitialScript(self: *Worker, script: []const u8) !void {
}
js_context.page.recordJsError(err);
const caught = try_catch.caughtOrError(self._script_arena.?, err);
const caught = try_catch.caughtOrError(self._script_arena.?.allocator(), err);
log.err(.browser, "worker script error", .{ .url = self._url, .caught = caught });
self.fireErrorEvent(caught.exception orelse @errorName(err), null);
return;
@@ -255,7 +254,7 @@ fn loadInitialScript(self: *Worker, script: []const u8) !void {
}
js_context.page.recordJsError(err);
const caught = try_catch.caughtOrError(self._script_arena.?, err);
const caught = try_catch.caughtOrError(self._script_arena.?.allocator(), err);
log.err(.browser, "worker module error", .{ .url = self._url, .caught = caught });
self.fireErrorEvent(caught.exception orelse @errorName(err), null);
return;
@@ -295,7 +294,7 @@ fn releaseScriptArena(self: *Worker) void {
const arena = self._script_arena orelse return;
self._script_arena = null;
self._script_buffer = .empty;
self._frame._session.releaseArena(arena);
arena.release();
}
// Fire an error event on the Worker object (parent context)
@@ -356,7 +355,7 @@ pub fn receiveMessage(self: *Worker, data: js.Value) !void {
};
const message_arena = try frame.getArena(.tiny, "Worker.receiveMessage");
errdefer frame.releaseArena(message_arena);
errdefer message_arena.release();
const callback = try message_arena.create(ReceiveMessageCallback);
callback.* = .{
@@ -411,7 +410,7 @@ fn getFunctionFromSetter(setter_: ?FunctionSetter) ?js.Function.Global {
const ReceiveMessageCallback = struct {
data: anyerror!js.Value.Global,
arena: Allocator,
arena: *lp.Arena,
worker: *Worker,
fn cancelled(ctx: *anyopaque) void {
@@ -423,7 +422,7 @@ const ReceiveMessageCallback = struct {
}
fn deinit(self: *ReceiveMessageCallback) void {
self.worker._frame._session.releaseArena(self.arena);
self.arena.release();
}
fn run(ctx: *anyopaque) !?u32 {
+15 -11
View File
@@ -73,6 +73,8 @@ _identity: JS.Identity = .{},
_http_owner: HttpClient.Owner,
arena: Allocator,
_call_arena: *lp.Arena,
_local_arena: *lp.Arena,
call_arena: Allocator,
local_arena: Allocator,
url: [:0]const u8,
@@ -135,10 +137,10 @@ pub fn init(
const session = frame._session;
const call_arena = try session.getArena(.small, "WorkerGlobalScope.call_arena");
errdefer session.releaseArena(call_arena);
errdefer call_arena.release();
const local_arena = try session.getArena(.small, "WorkerGlobalScope.local_arena");
errdefer session.releaseArena(local_arena);
errdefer local_arena.release();
const factory = frame._factory;
const leaf = try Factory.chainedWithAllocator(arena, .{
@@ -148,8 +150,10 @@ pub fn init(
.arena = arena,
.origin = frame.origin,
.js = undefined,
.call_arena = call_arena,
.local_arena = local_arena,
._call_arena = call_arena,
._local_arena = local_arena,
.call_arena = call_arena.allocator(),
.local_arena = local_arena.allocator(),
._frame = frame,
._page = frame._page,
._session = session,
@@ -181,8 +185,8 @@ pub fn init(
);
self.js = try session.browser.env.createWorkerContext(self, .{
.call_arena = call_arena,
.local_arena = local_arena,
.call_arena = call_arena.allocator(),
.local_arena = local_arena.allocator(),
.identity_arena = arena,
.identity = &self._identity,
});
@@ -216,8 +220,8 @@ pub fn deinit(self: *WorkerGlobalScope) void {
page.revokeBlobUrlsFor(self._frame_id);
browser.env.destroyContext(self.js);
session.releaseArena(self.call_arena);
session.releaseArena(self.local_arena);
self._call_arena.release();
self._local_arena.release();
}
pub fn base(self: *const WorkerGlobalScope) [:0]const u8 {
@@ -393,11 +397,11 @@ pub fn importScripts(self: *WorkerGlobalScope, urls: []const [:0]const u8) !void
const session = self._session;
const arena = try session.getArena(.large, "importScript");
defer session.releaseArena(arena);
defer arena.release();
for (urls) |url| {
defer session.arena_pool.resetRetain(arena);
try self.importScript(arena, url);
defer arena.resetRetain();
try self.importScript(arena.allocator(), url);
}
}
+7 -10
View File
@@ -22,7 +22,6 @@
//! arena for its own result data so multiple evaluations don't grow
//! the AST arena.
const std = @import("std");
const lp = @import("lightpanda");
const js = @import("../js/js.zig");
@@ -38,24 +37,22 @@ const xpath = struct {
const Evaluator = @import("../xpath/Evaluator.zig");
};
const Allocator = std.mem.Allocator;
const XPathExpression = @This();
_rc: lp.RC = .{},
_arena: Allocator,
_arena: *lp.Arena,
_expr: *const xpath.Ast.Expr,
pub fn init(expression: []const u8, frame: *Frame) !*XPathExpression {
const arena = try frame.getArena(.tiny, "XPathExpression");
errdefer frame.releaseArena(arena);
errdefer arena.release();
// The AST borrows string slices from its input (literals, names,
// var refs, function names). `expression` is materialized in the JS
// call_arena and is reclaimed when the top-level call returns, so
// dupe into our long-lived arena before parsing.
const owned = try arena.dupe(u8, expression);
const expr = try xpath.Parser.parse(arena, owned);
const expr = try xpath.Parser.parse(arena.allocator(), owned);
const xe = try arena.create(XPathExpression);
xe.* = .{ ._arena = arena, ._expr = expr };
return xe;
@@ -74,14 +71,14 @@ pub fn evaluate(
_ = result;
const arena = try frame.getArena(.medium, "XPathResult");
errdefer frame.releaseArena(arena);
errdefer arena.release();
const eval_result = try xpath.Evaluator.evaluate(arena, self._expr, context_node, frame);
const eval_result = try xpath.Evaluator.evaluate(arena.allocator(), self._expr, context_node, frame);
return XPathResult.fromResult(arena, requested_type orelse XPathResult.ANY_TYPE, eval_result);
}
pub fn deinit(self: *XPathExpression, page: *Page) void {
page.releaseArena(self._arena);
pub fn deinit(self: *XPathExpression, _: *Page) void {
self._arena.release();
}
pub fn acquireRef(self: *XPathExpression) void {
+9 -12
View File
@@ -32,7 +32,6 @@
//! `InvalidStateError` is what decision #4 captures and what most
//! legacy XPath consumers expect.
const std = @import("std");
const lp = @import("lightpanda");
const js = @import("../js/js.zig");
@@ -49,8 +48,6 @@ const xpath = struct {
const Evaluator = @import("../xpath/Evaluator.zig");
};
const Allocator = std.mem.Allocator;
const XPathResult = @This();
// WHATWG type constants. ANY_TYPE is a request flag — at construction
@@ -76,7 +73,7 @@ const Value = union(enum) {
};
_rc: lp.RC = .{},
_arena: Allocator,
_arena: *lp.Arena,
_type: u16,
_value: Value,
_iter_pos: usize = 0,
@@ -93,15 +90,15 @@ pub fn fromExpression(
frame: *Frame,
) !*XPathResult {
const arena = try frame.getArena(.medium, "XPathResult");
errdefer frame.releaseArena(arena);
errdefer arena.release();
// The AST borrows string slices from its input (literals, names,
// var refs, function names). `expression` is materialized in the JS
// call_arena and is reclaimed when the top-level call returns, so
// dupe into our long-lived arena before parsing.
const owned = try arena.dupe(u8, expression);
const expr = try xpath.Parser.parse(arena, owned);
const result = try xpath.Evaluator.evaluate(arena, expr, context_node, frame);
const expr = try xpath.Parser.parse(arena.allocator(), owned);
const result = try xpath.Evaluator.evaluate(arena.allocator(), expr, context_node, frame);
return fromResult(arena, requested_type, result);
}
@@ -110,7 +107,7 @@ pub fn fromExpression(
/// it on deinit. Used by `XPathExpression.evaluate` (which has its own
/// AST cache and only allocates a fresh result arena).
pub fn fromResult(
arena: Allocator,
arena: *lp.Arena,
requested_type: u16,
result: xpath.result.Result,
) !*XPathResult {
@@ -121,8 +118,8 @@ pub fn fromResult(
.boolean => |b| .{ .boolean = b },
.node_set => |ns| .{ .nodes = ns },
},
NUMBER_TYPE => .{ .number = try xpath.result.toNumber(arena, result) },
STRING_TYPE => .{ .string = try xpath.result.toString(arena, result) },
NUMBER_TYPE => .{ .number = try xpath.result.toNumber(arena.allocator(), result) },
STRING_TYPE => .{ .string = try xpath.result.toString(arena.allocator(), result) },
BOOLEAN_TYPE => .{ .boolean = xpath.result.toBoolean(result) },
UNORDERED_NODE_ITERATOR_TYPE,
ORDERED_NODE_ITERATOR_TYPE,
@@ -159,8 +156,8 @@ pub fn fromResult(
// ----- lifecycle -----
pub fn deinit(self: *XPathResult, page: *Page) void {
page.releaseArena(self._arena);
pub fn deinit(self: *XPathResult, _: *Page) void {
self._arena.release();
}
pub fn acquireRef(self: *XPathResult) void {
+4 -6
View File
@@ -16,14 +16,12 @@
// 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 Frame = @import("../../Frame.zig");
const log = lp.log;
const Allocator = std.mem.Allocator;
const Animation = @This();
@@ -36,7 +34,7 @@ const PlayState = enum {
_rc: lp.RC = .{},
_frame: *Frame,
_arena: Allocator,
_arena: *lp.Arena,
_effect: ?js.Object.Global = null,
_timeline: ?js.Object.Global = null,
@@ -53,7 +51,7 @@ _playState: PlayState = .idle,
// TODO add support for effect and timeline
pub fn init(frame: *Frame) !*Animation {
const arena = try frame.getArena(.tiny, "Animation");
errdefer frame.releaseArena(arena);
errdefer arena.release();
const self = try arena.create(Animation);
self.* = .{
@@ -64,8 +62,8 @@ pub fn init(frame: *Frame) !*Animation {
return self;
}
pub fn deinit(self: *Animation, page: *Page) void {
page.releaseArena(self._arena);
pub fn deinit(self: *Animation, _: *Page) void {
self._arena.release();
}
pub fn releaseRef(self: *Animation, page: *Page) void {
@@ -16,7 +16,7 @@
// 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 Page = @import("../../Page.zig");
const Frame = @import("../../Frame.zig");
@@ -29,7 +29,7 @@ const GenericIterator = @import("iterator.zig").Entry;
// No need to go through a TreeWalker or add any filtering.
const ChildNodes = @This();
_arena: std.mem.Allocator,
_arena: *lp.Arena,
_last_index: usize,
_last_length: ?u32,
_last_node: ?*Node,
@@ -42,7 +42,7 @@ pub const EntryIterator = GenericIterator(Iterator, null);
pub fn init(node: *Node, frame: *Frame) !*ChildNodes {
const arena = try frame.getArena(.small, "ChildNodes");
errdefer frame.releaseArena(arena);
errdefer arena.release();
const self = try arena.create(ChildNodes);
self.* = .{
@@ -56,8 +56,8 @@ pub fn init(node: *Node, frame: *Frame) !*ChildNodes {
return self;
}
pub fn deinit(self: *const ChildNodes, page: *Page) void {
page.releaseArena(self._arena);
pub fn deinit(self: *const ChildNodes, _: *Page) void {
self._arena.release();
}
pub fn length(self: *ChildNodes, frame: *const Frame) !u32 {
@@ -28,7 +28,6 @@ pub const ValueIterator = GenericIterator(Iterator, "1");
pub const EntryIterator = GenericIterator(Iterator, null);
const Execution = js.Execution;
const Allocator = std.mem.Allocator;
// not registered in collections.zig, because this is one of the rare
// collections that's also available in Worker
@@ -44,15 +43,15 @@ pub fn registerTypes() []const type {
pub const DOMStringList = @This();
_rc: lp.RC = .{},
_arena: Allocator,
_arena: *lp.Arena,
_items: []const []const u8,
pub fn acquireRef(self: *DOMStringList) void {
self._rc.acquire();
}
pub fn deinit(self: *DOMStringList, page: *Page) void {
page.releaseArena(self._arena);
pub fn deinit(self: *DOMStringList, _: *Page) void {
self._arena.release();
}
pub fn releaseRef(self: *DOMStringList, page: *Page) void {
+4 -7
View File
@@ -16,26 +16,23 @@
// 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 Frame = @import("../../Frame.zig");
const Allocator = std.mem.Allocator;
const FontFace = @This();
_rc: lp.RC = .{},
_arena: Allocator,
_arena: *lp.Arena,
_family: []const u8,
pub fn init(family: []const u8, source: []const u8, frame: *Frame) !*FontFace {
_ = source;
const arena = try frame.getArena(.tiny, "FontFace");
errdefer frame.releaseArena(arena);
errdefer arena.release();
const self = try arena.create(FontFace);
self.* = .{
@@ -45,8 +42,8 @@ pub fn init(family: []const u8, source: []const u8, frame: *Frame) !*FontFace {
return self;
}
pub fn deinit(self: *FontFace, page: *Page) void {
page.releaseArena(self._arena);
pub fn deinit(self: *FontFace, _: *Page) void {
self._arena.release();
}
pub fn releaseRef(self: *FontFace, page: *Page) void {
+5 -8
View File
@@ -16,7 +16,6 @@
// 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");
@@ -28,28 +27,26 @@ const EventTarget = @import("../EventTarget.zig");
const FontFace = @import("FontFace.zig");
const Allocator = std.mem.Allocator;
const FontFaceSet = @This();
pub const Proto = EventTarget;
_rc: lp.RC = .{},
_proto: *EventTarget,
_arena: Allocator,
_arena: *lp.Arena,
pub fn init(frame: *Frame) !*FontFaceSet {
const arena = try frame.getArena(.tiny, "FontFaceSet");
errdefer frame.releaseArena(arena);
errdefer arena.release();
return frame._factory.eventTargetWithAllocator(arena, FontFaceSet{
return frame._factory.eventTargetWithAllocator(arena.allocator(), FontFaceSet{
._proto = undefined,
._arena = arena,
});
}
pub fn deinit(self: *FontFaceSet, page: *Page) void {
page.releaseArena(self._arena);
pub fn deinit(self: *FontFaceSet, _: *Page) void {
self._arena.release();
}
pub fn releaseRef(self: *FontFaceSet, page: *Page) void {
+5 -7
View File
@@ -24,13 +24,11 @@ const Page = @import("../../Page.zig");
const html5ever = @import("../../parser/html5ever.zig");
const Allocator = std.mem.Allocator;
const TextDecoder = @This();
_rc: lp.RC = .{},
_fatal: bool,
_arena: Allocator,
_arena: *lp.Arena,
_ignore_bom: bool,
_bom_seen: bool,
_decoder: ?*anyopaque, // Persistent streaming decoder
@@ -58,7 +56,7 @@ pub fn init(label_: ?[]const u8, opts_: ?InitOpts, page: *Page) !*TextDecoder {
}
const arena = try page.getArena(.large, "TextDecoder");
errdefer page.releaseArena(arena);
errdefer arena.release();
const opts = opts_ orelse InitOpts{};
const self = try arena.create(TextDecoder);
@@ -75,11 +73,11 @@ pub fn init(label_: ?[]const u8, opts_: ?InitOpts, page: *Page) !*TextDecoder {
return self;
}
pub fn deinit(self: *TextDecoder, page: *Page) void {
pub fn deinit(self: *TextDecoder, _: *Page) void {
if (self._decoder) |decoder| {
html5ever.encoding_decoder_free(decoder);
}
page.releaseArena(self._arena);
self._arena.release();
}
pub fn releaseRef(self: *TextDecoder, page: *Page) void {
@@ -104,7 +102,7 @@ pub fn getEncoding(self: *TextDecoder) ![]const u8 {
if (self._lowercase_name.len > 0) {
return self._lowercase_name;
}
self._lowercase_name = try std.ascii.allocLowerString(self._arena, self._encoding_name);
self._lowercase_name = try std.ascii.allocLowerString(self._arena.allocator(), self._encoding_name);
return self._lowercase_name;
}
@@ -16,7 +16,6 @@
// 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");
@@ -25,7 +24,6 @@ const Frame = @import("../../Frame.zig");
const Event = @import("../Event.zig");
const String = lp.String;
const Allocator = std.mem.Allocator;
// https://html.spec.whatwg.org/multipage/browsing-the-web.html#the-beforeunloadevent-interface
const BeforeUnloadEvent = @This();
@@ -39,18 +37,18 @@ const Options = Event.inheritOptions(BeforeUnloadEvent, struct {});
pub fn init(typ: []const u8, _opts: ?Options, frame: *Frame) !*BeforeUnloadEvent {
const arena = try frame.getArena(.tiny, "BeforeUnloadEvent");
errdefer frame.releaseArena(arena);
const type_string = try String.init(arena, typ, .{});
errdefer arena.release();
const type_string = try String.init(arena.allocator(), typ, .{});
return initWithTrusted(arena, type_string, _opts, false, frame);
}
pub fn initTrusted(typ: String, _opts: ?Options, frame: *Frame) !*BeforeUnloadEvent {
const arena = try frame.getArena(.tiny, "BeforeUnloadEvent.trusted");
errdefer frame.releaseArena(arena);
errdefer arena.release();
return initWithTrusted(arena, typ, _opts, true, frame);
}
fn initWithTrusted(arena: Allocator, typ: String, _opts: ?Options, trusted: bool, frame: *Frame) !*BeforeUnloadEvent {
fn initWithTrusted(arena: *lp.Arena, typ: String, _opts: ?Options, trusted: bool, frame: *Frame) !*BeforeUnloadEvent {
const opts = _opts orelse Options{};
const event = try frame._factory.event(
+4 -6
View File
@@ -16,14 +16,12 @@
// 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 Page = @import("../../Page.zig");
const Event = @import("../Event.zig");
const String = lp.String;
const Allocator = std.mem.Allocator;
const CloseEvent = @This();
@@ -43,18 +41,18 @@ const Options = Event.inheritOptions(CloseEvent, CloseEventOptions);
pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*CloseEvent {
const arena = try page.getArena(.tiny, "CloseEvent");
errdefer page.releaseArena(arena);
const type_string = try String.init(arena, typ, .{});
errdefer arena.release();
const type_string = try String.init(arena.allocator(), typ, .{});
return initWithTrusted(arena, type_string, _opts, false, page);
}
pub fn initTrusted(typ: String, _opts: ?Options, page: *Page) !*CloseEvent {
const arena = try page.getArena(.tiny, "CloseEvent.trusted");
errdefer page.releaseArena(arena);
errdefer arena.release();
return initWithTrusted(arena, typ, _opts, true, page);
}
fn initWithTrusted(arena: Allocator, typ: String, _opts: ?Options, trusted: bool, page: *Page) !*CloseEvent {
fn initWithTrusted(arena: *lp.Arena, typ: String, _opts: ?Options, trusted: bool, page: *Page) !*CloseEvent {
const opts = _opts orelse Options{};
const event = try page.factory.event(
@@ -41,8 +41,8 @@ const Options = Event.inheritOptions(CompositionEvent, CompositionEventOptions);
pub fn init(typ: []const u8, opts_: ?Options, frame: *Frame) !*CompositionEvent {
const arena = try frame.getArena(.tiny, "CompositionEvent");
errdefer frame.releaseArena(arena);
const type_string = try String.init(arena, typ, .{});
errdefer arena.release();
const type_string = try String.init(arena.allocator(), typ, .{});
const opts = opts_ orelse Options{};
const event = try frame._factory.uiEvent(
@@ -82,7 +82,7 @@ pub fn initCompositionEvent(
const arena = event._arena;
event._initialized = true;
event._type_string = try String.init(arena, typ, .{});
event._type_string = try String.init(arena.allocator(), typ, .{});
event._bubbles = bubbles orelse false;
event._cancelable = cancelable orelse false;
ui._view = view;
+10 -10
View File
@@ -47,8 +47,8 @@ const Options = Event.inheritOptions(CookieChangeEvent, CookieChangeEventOptions
pub fn init(typ: []const u8, _opts: ?Options, exec: *const Execution) !*CookieChangeEvent {
const arena = try exec.getArena(.tiny, "CookieChangeEvent");
errdefer exec.releaseArena(arena);
const type_string = try String.init(arena, typ, .{});
errdefer arena.release();
const type_string = try String.init(arena.allocator(), typ, .{});
const opts = _opts orelse Options{};
@@ -57,8 +57,8 @@ pub fn init(typ: []const u8, _opts: ?Options, exec: *const Execution) !*CookieCh
type_string,
CookieChangeEvent{
._proto = undefined,
._changed = try cloneListItems(arena, opts.changed),
._deleted = try cloneListItems(arena, opts.deleted),
._changed = try cloneListItems(arena.allocator(), opts.changed),
._deleted = try cloneListItems(arena.allocator(), opts.deleted),
},
);
@@ -75,20 +75,20 @@ pub fn initSingle(
exec: *const Execution,
) !*CookieChangeEvent {
const arena = try exec.getArena(.tiny, "CookieChangeEvent");
errdefer exec.releaseArena(arena);
const type_string = try String.init(arena, "change", .{});
errdefer arena.release();
const type_string = try String.init(arena.allocator(), "change", .{});
const item = try arena.create(CookieStore.CookieListItem);
item.* = .{
.name = try String.init(arena, snapshot.name, .{}),
.name = try String.init(arena.allocator(), snapshot.name, .{}),
// Deletions report no value (the `deleted` accessor serializes the
// resulting null as undefined); changes carry the new value.
.value = if (kind == .deleted) null else try String.init(arena, snapshot.value, .{}),
.value = if (kind == .deleted) null else try String.init(arena.allocator(), snapshot.value, .{}),
.domain = if (snapshot.domain.len > 0 and snapshot.domain[0] == '.')
try String.init(arena, snapshot.domain[1..], .{})
try String.init(arena.allocator(), snapshot.domain[1..], .{})
else
null,
.path = try String.init(arena, snapshot.path, .{}),
.path = try String.init(arena.allocator(), snapshot.path, .{}),
.expires = null,
.secure = snapshot.secure,
.sameSite = switch (snapshot.same_site) {
+4 -4
View File
@@ -43,15 +43,15 @@ const Options = Event.inheritOptions(CustomEvent, CustomEventOptions);
pub fn init(typ: []const u8, opts_: ?Options, page: *Page) !*CustomEvent {
const arena = try page.getArena(.tiny, "CustomEvent");
errdefer page.releaseArena(arena);
const type_string = try String.init(arena, typ, .{});
errdefer arena.release();
const type_string = try String.init(arena.allocator(), typ, .{});
const opts = opts_ orelse Options{};
const event = try page.factory.event(
arena,
type_string,
CustomEvent{
._arena = arena,
._arena = arena.allocator(),
._proto = undefined,
._detail = opts.detail,
},
@@ -76,7 +76,7 @@ pub fn initCustomEvent(
// This function can only be called after the constructor has called.
// So we assume proto is initialized already by constructor.
self._proto._initialized = true;
self._proto._type_string = try String.init(self._proto._arena, event_string, .{});
self._proto._type_string = try String.init(self._proto._arena.allocator(), event_string, .{});
self._proto._bubbles = bubbles orelse false;
self._proto._cancelable = cancelable orelse false;
// Detail is stored separately.
@@ -41,8 +41,8 @@ const Options = Event.inheritOptions(DeviceMotionEvent, DeviceMotionEventOptions
pub fn init(typ: []const u8, _opts: ?Options, frame: *Frame) !*DeviceMotionEvent {
const arena = try frame.getArena(.tiny, "DeviceMotionEvent");
errdefer frame.releaseArena(arena);
const type_string = try String.init(arena, typ, .{});
errdefer arena.release();
const type_string = try String.init(arena.allocator(), typ, .{});
const opts = _opts orelse Options{};
const event = try frame._factory.event(
@@ -47,8 +47,8 @@ const Options = Event.inheritOptions(DeviceOrientationEvent, DeviceOrientationEv
pub fn init(typ: []const u8, _opts: ?Options, frame: *Frame) !*DeviceOrientationEvent {
const arena = try frame.getArena(.tiny, "DeviceOrientationEvent");
errdefer frame.releaseArena(arena);
const type_string = try String.init(arena, typ, .{});
errdefer arena.release();
const type_string = try String.init(arena.allocator(), typ, .{});
const opts = _opts orelse Options{};
const event = try frame._factory.event(
+2 -2
View File
@@ -51,8 +51,8 @@ pub fn initTrusted(typ: []const u8, _opts: ?Options, frame: *Frame) !*DragEvent
fn initWithTrusted(typ: []const u8, _opts: ?Options, trusted: bool, frame: *Frame) !*DragEvent {
const arena = try frame.getArena(.medium, "DragEvent");
errdefer frame.releaseArena(arena);
const type_string = try String.init(arena, typ, .{});
errdefer arena.release();
const type_string = try String.init(arena.allocator(), typ, .{});
const opts = _opts orelse Options{};
+5 -5
View File
@@ -51,25 +51,25 @@ const Options = Event.inheritOptions(ErrorEvent, ErrorEventOptions);
pub fn init(typ: []const u8, opts_: ?Options, page: *Page) !*ErrorEvent {
const arena = try page.getArena(.small, "ErrorEvent");
errdefer page.releaseArena(arena);
const type_string = try String.init(arena, typ, .{});
errdefer arena.release();
const type_string = try String.init(arena.allocator(), typ, .{});
return initWithTrusted(arena, type_string, opts_, false, page);
}
pub fn initTrusted(typ: String, opts_: ?Options, page: *Page) !*ErrorEvent {
const arena = try page.getArena(.small, "ErrorEvent.trusted");
errdefer page.releaseArena(arena);
errdefer arena.release();
return initWithTrusted(arena, typ, opts_, true, page);
}
fn initWithTrusted(arena: Allocator, typ: String, opts_: ?Options, trusted: bool, page: *Page) !*ErrorEvent {
fn initWithTrusted(arena: *lp.Arena, typ: String, opts_: ?Options, trusted: bool, page: *Page) !*ErrorEvent {
const opts = opts_ orelse Options{};
const event = try page.factory.event(
arena,
typ,
ErrorEvent{
._arena = arena,
._arena = arena.allocator(),
._proto = undefined,
._message = if (opts.message) |str| try arena.dupe(u8, str) else "",
._filename = if (opts.filename) |str| try arena.dupe(u8, str) else "",
+4 -6
View File
@@ -16,7 +16,6 @@
// 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");
@@ -27,7 +26,6 @@ const EventTarget = @import("../EventTarget.zig");
const UIEvent = @import("UIEvent.zig");
const String = lp.String;
const Allocator = std.mem.Allocator;
const FocusEvent = @This();
@@ -47,18 +45,18 @@ pub const Options = Event.inheritOptions(
pub fn initTrusted(typ: String, _opts: ?Options, frame: *Frame) !*FocusEvent {
const arena = try frame.getArena(.tiny, "FocusEvent.trusted");
errdefer frame.releaseArena(arena);
errdefer arena.release();
return initWithTrusted(arena, typ, _opts, true, frame);
}
pub fn init(typ: []const u8, _opts: ?Options, frame: *Frame) !*FocusEvent {
const arena = try frame.getArena(.tiny, "FocusEvent");
errdefer frame.releaseArena(arena);
const type_string = try String.init(arena, typ, .{});
errdefer arena.release();
const type_string = try String.init(arena.allocator(), typ, .{});
return initWithTrusted(arena, type_string, _opts, false, frame);
}
fn initWithTrusted(arena: Allocator, typ: String, _opts: ?Options, trusted: bool, frame: *Frame) !*FocusEvent {
fn initWithTrusted(arena: *lp.Arena, typ: String, _opts: ?Options, trusted: bool, frame: *Frame) !*FocusEvent {
const opts = _opts orelse Options{};
const event = try frame._factory.uiEvent(
+4 -6
View File
@@ -16,7 +16,6 @@
// 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");
@@ -27,7 +26,6 @@ const Event = @import("../Event.zig");
const FormData = @import("../net/FormData.zig");
const String = lp.String;
const Allocator = std.mem.Allocator;
/// https://developer.mozilla.org/en-US/docs/Web/API/FormDataEvent
const FormDataEvent = @This();
@@ -43,18 +41,18 @@ const Options = Event.inheritOptions(FormDataEvent, struct {
pub fn init(typ: []const u8, maybe_options: Options, frame: *Frame) !*FormDataEvent {
const arena = try frame.getArena(.tiny, "FormDataEvent");
errdefer frame.releaseArena(arena);
const type_string = try String.init(arena, typ, .{});
errdefer arena.release();
const type_string = try String.init(arena.allocator(), typ, .{});
return initWithTrusted(arena, type_string, maybe_options, false, frame);
}
pub fn initTrusted(typ: String, _opts: ?Options, frame: *Frame) !*FormDataEvent {
const arena = try frame.getArena(.tiny, "FormDataEvent.trusted");
errdefer frame.releaseArena(arena);
errdefer arena.release();
return initWithTrusted(arena, typ, _opts, true, frame);
}
fn initWithTrusted(arena: Allocator, typ: String, maybe_options: ?Options, trusted: bool, frame: *Frame) !*FormDataEvent {
fn initWithTrusted(arena: *lp.Arena, typ: String, maybe_options: ?Options, trusted: bool, frame: *Frame) !*FormDataEvent {
const options = maybe_options orelse Options{};
const event = try frame._factory.event(
+2 -2
View File
@@ -38,8 +38,8 @@ const Options = Event.inheritOptions(GamepadEvent, GamepadEventOptions);
pub fn init(typ: []const u8, _opts: ?Options, frame: *Frame) !*GamepadEvent {
const arena = try frame.getArena(.tiny, "GamepadEvent");
errdefer frame.releaseArena(arena);
const type_string = try String.init(arena, typ, .{});
errdefer arena.release();
const type_string = try String.init(arena.allocator(), typ, .{});
const opts = _opts orelse Options{};
const event = try frame._factory.event(
+4 -6
View File
@@ -16,7 +16,6 @@
// 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");
@@ -25,7 +24,6 @@ const Frame = @import("../../Frame.zig");
const Event = @import("../Event.zig");
const String = lp.String;
const Allocator = std.mem.Allocator;
// https://developer.mozilla.org/en-US/docs/Web/API/HashChangeEvent
const HashChangeEvent = @This();
@@ -45,18 +43,18 @@ const Options = Event.inheritOptions(HashChangeEvent, HashChangeEventOptions);
pub fn init(typ: []const u8, _opts: ?Options, frame: *Frame) !*HashChangeEvent {
const arena = try frame.getArena(.tiny, "HashChangeEvent");
errdefer frame.releaseArena(arena);
const type_string = try String.init(arena, typ, .{});
errdefer arena.release();
const type_string = try String.init(arena.allocator(), typ, .{});
return initWithTrusted(arena, type_string, _opts, false, frame);
}
pub fn initTrusted(typ: String, _opts: ?Options, frame: *Frame) !*HashChangeEvent {
const arena = try frame.getArena(.tiny, "HashChangeEvent.trusted");
errdefer frame.releaseArena(arena);
errdefer arena.release();
return initWithTrusted(arena, typ, _opts, true, frame);
}
fn initWithTrusted(arena: Allocator, typ: String, _opts: ?Options, trusted: bool, frame: *Frame) !*HashChangeEvent {
fn initWithTrusted(arena: *lp.Arena, typ: String, _opts: ?Options, trusted: bool, frame: *Frame) !*HashChangeEvent {
const opts = _opts orelse Options{};
const event = try frame._factory.event(
+4 -6
View File
@@ -16,7 +16,6 @@
// 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");
@@ -28,7 +27,6 @@ const UIEvent = @import("UIEvent.zig");
const DataTransfer = @import("../DataTransfer.zig");
const String = lp.String;
const Allocator = std.mem.Allocator;
const InputEvent = @This();
@@ -54,18 +52,18 @@ const Options = Event.inheritOptions(
pub fn initTrusted(typ: String, _opts: ?Options, frame: *Frame) !*InputEvent {
const arena = try frame.getArena(.tiny, "InputEvent.trusted");
errdefer frame.releaseArena(arena);
errdefer arena.release();
return initWithTrusted(arena, typ, _opts, true, frame);
}
pub fn init(typ: []const u8, _opts: ?Options, frame: *Frame) !*InputEvent {
const arena = try frame.getArena(.tiny, "InputEvent");
errdefer frame.releaseArena(arena);
const type_string = try String.init(arena, typ, .{});
errdefer arena.release();
const type_string = try String.init(arena.allocator(), typ, .{});
return initWithTrusted(arena, type_string, _opts, false, frame);
}
fn initWithTrusted(arena: Allocator, typ: String, _opts: ?Options, trusted: bool, frame: *Frame) !*InputEvent {
fn initWithTrusted(arena: *lp.Arena, typ: String, _opts: ?Options, trusted: bool, frame: *Frame) !*InputEvent {
const opts = _opts orelse Options{};
const event = try frame._factory.uiEvent(
+8 -9
View File
@@ -26,7 +26,6 @@ const Event = @import("../Event.zig");
const UIEvent = @import("UIEvent.zig");
const String = lp.String;
const Allocator = std.mem.Allocator;
const KeyboardEvent = @This();
@@ -297,18 +296,18 @@ const Options = Event.inheritOptions(
pub fn initTrusted(typ: String, _opts: ?Options, frame: *Frame) !*KeyboardEvent {
const arena = try frame.getArena(.tiny, "KeyboardEvent.trusted");
errdefer frame.releaseArena(arena);
errdefer arena.release();
return initWithTrusted(arena, typ, _opts, true, frame);
}
pub fn init(typ: []const u8, _opts: ?Options, frame: *Frame) !*KeyboardEvent {
const arena = try frame.getArena(.tiny, "KeyboardEvent");
errdefer frame.releaseArena(arena);
const type_string = try String.init(arena, typ, .{});
errdefer arena.release();
const type_string = try String.init(arena.allocator(), typ, .{});
return initWithTrusted(arena, type_string, _opts, false, frame);
}
fn initWithTrusted(arena: Allocator, typ: String, _opts: ?Options, trusted: bool, frame: *Frame) !*KeyboardEvent {
fn initWithTrusted(arena: *lp.Arena, typ: String, _opts: ?Options, trusted: bool, frame: *Frame) !*KeyboardEvent {
const opts = _opts orelse Options{};
const event = try frame._factory.uiEvent(
@@ -316,7 +315,7 @@ fn initWithTrusted(arena: Allocator, typ: String, _opts: ?Options, trusted: bool
typ,
KeyboardEvent{
._proto = undefined,
._key = try Key.fromString(arena, opts.key),
._key = try Key.fromString(arena.allocator(), opts.key),
._location = opts.location,
._code = if (opts.code) |c| try arena.dupe(u8, c) else "",
._repeat = opts.repeat,
@@ -431,11 +430,11 @@ pub fn initKeyboardEvent(
const arena = event._arena;
event._initialized = true;
event._type_string = try String.init(arena, typ, .{});
event._type_string = try String.init(arena.allocator(), typ, .{});
event._bubbles = bubbles orelse false;
event._cancelable = cancelable orelse false;
ui._view = view;
self._key = try Key.fromString(arena, key orelse "");
self._key = try Key.fromString(arena.allocator(), key orelse "");
self._location = location orelse 0;
self._ctrl_key = ctrl_key orelse false;
self._alt_key = alt_key orelse false;
@@ -444,7 +443,7 @@ pub fn initKeyboardEvent(
}
pub fn getModifierState(self: *const KeyboardEvent, str: []const u8) !bool {
const key = try Key.fromString(self._proto._proto._arena, str);
const key = try Key.fromString(self._proto._proto._arena.allocator(), str);
switch (key) {
.Alt, .AltGraph => return self._alt_key,
+4 -5
View File
@@ -27,7 +27,6 @@ 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();
@@ -65,18 +64,18 @@ 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, .{});
errdefer arena.release();
const type_string = try String.init(arena.allocator(), 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);
errdefer arena.release();
return initWithTrusted(arena, typ, opts_, true, page);
}
fn initWithTrusted(arena: Allocator, typ: String, opts_: ?Options, trusted: bool, page: *Page) !*MessageEvent {
fn initWithTrusted(arena: *lp.Arena, typ: String, opts_: ?Options, trusted: bool, page: *Page) !*MessageEvent {
const opts = opts_ orelse Options{};
const event = try page.factory.event(
+5 -6
View File
@@ -29,7 +29,6 @@ const UIEvent = @import("UIEvent.zig");
const PointerEvent = @import("PointerEvent.zig");
const String = lp.String;
const Allocator = std.mem.Allocator;
const MouseEvent = @This();
@@ -89,18 +88,18 @@ pub const Options = Event.inheritOptions(
pub fn init(typ: []const u8, _opts: ?Options, frame: *Frame) !*MouseEvent {
const arena = try frame.getArena(.tiny, "MouseEvent");
errdefer frame.releaseArena(arena);
const type_string = try String.init(arena, typ, .{});
errdefer arena.release();
const type_string = try String.init(arena.allocator(), typ, .{});
return initWithTrusted(arena, type_string, _opts, false, frame);
}
pub fn initTrusted(typ: String, _opts: ?Options, frame: *Frame) !*MouseEvent {
const arena = try frame.getArena(.tiny, "MouseEvent.trusted");
errdefer frame.releaseArena(arena);
errdefer arena.release();
return initWithTrusted(arena, typ, _opts, true, frame);
}
fn initWithTrusted(arena: Allocator, typ: String, _opts: ?Options, trusted: bool, frame: *Frame) !*MouseEvent {
fn initWithTrusted(arena: *lp.Arena, typ: String, _opts: ?Options, trusted: bool, frame: *Frame) !*MouseEvent {
const opts = _opts orelse Options{};
const event = try frame._factory.uiEvent(
@@ -242,7 +241,7 @@ pub fn initMouseEvent(
}
event._initialized = true;
event._type_string = try String.init(event._arena, typ, .{});
event._type_string = try String.init(event._arena.allocator(), typ, .{});
event._bubbles = bubbles orelse false;
event._cancelable = cancelable orelse false;
ui._view = view;
@@ -27,7 +27,6 @@ const NavigationHistoryEntry = @import("../navigation/NavigationHistoryEntry.zig
const NavigationType = @import("../navigation/root.zig").NavigationType;
const String = lp.String;
const Allocator = std.mem.Allocator;
const NavigationCurrentEntryChangeEvent = @This();
@@ -49,19 +48,19 @@ const Options = Event.inheritOptions(
pub fn init(typ: []const u8, opts: Options, frame: *Frame) !*NavigationCurrentEntryChangeEvent {
const arena = try frame.getArena(.tiny, "NavigationCurrentEntryChangeEvent");
errdefer frame.releaseArena(arena);
const type_string = try String.init(arena, typ, .{});
errdefer arena.release();
const type_string = try String.init(arena.allocator(), typ, .{});
return initWithTrusted(arena, type_string, opts, false, frame);
}
pub fn initTrusted(typ: String, opts: Options, frame: *Frame) !*NavigationCurrentEntryChangeEvent {
const arena = try frame.getArena(.tiny, "NavigationCurrentEntryChangeEvent.trusted");
errdefer frame.releaseArena(arena);
errdefer arena.release();
return initWithTrusted(arena, typ, opts, true, frame);
}
fn initWithTrusted(
arena: Allocator,
arena: *lp.Arena,
typ: String,
opts: Options,
trusted: bool,
@@ -16,7 +16,6 @@
// 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");
@@ -25,7 +24,6 @@ const Frame = @import("../../Frame.zig");
const Event = @import("../Event.zig");
const String = lp.String;
const Allocator = std.mem.Allocator;
// https://developer.mozilla.org/en-US/docs/Web/API/PageTransitionEvent
const PageTransitionEvent = @This();
@@ -43,18 +41,18 @@ const Options = Event.inheritOptions(PageTransitionEvent, PageTransitionEventOpt
pub fn init(typ: []const u8, _opts: ?Options, frame: *Frame) !*PageTransitionEvent {
const arena = try frame.getArena(.tiny, "PageTransitionEvent");
errdefer frame.releaseArena(arena);
const type_string = try String.init(arena, typ, .{});
errdefer arena.release();
const type_string = try String.init(arena.allocator(), typ, .{});
return initWithTrusted(arena, type_string, _opts, false, frame);
}
pub fn initTrusted(typ: String, _opts: ?Options, frame: *Frame) !*PageTransitionEvent {
const arena = try frame.getArena(.tiny, "PageTransitionEvent.trusted");
errdefer frame.releaseArena(arena);
errdefer arena.release();
return initWithTrusted(arena, typ, _opts, true, frame);
}
fn initWithTrusted(arena: Allocator, typ: String, _opts: ?Options, trusted: bool, frame: *Frame) !*PageTransitionEvent {
fn initWithTrusted(arena: *lp.Arena, typ: String, _opts: ?Options, trusted: bool, frame: *Frame) !*PageTransitionEvent {
const opts = _opts orelse Options{};
const event = try frame._factory.event(
+2 -2
View File
@@ -97,8 +97,8 @@ pub fn initTrusted(typ: []const u8, _opts: ?Options, frame: *Frame) !*PointerEve
fn initWithTrusted(typ: []const u8, _opts: ?Options, trusted: bool, frame: *Frame) !*PointerEvent {
const arena = try frame.getArena(.tiny, "PointerEvent");
errdefer frame.releaseArena(arena);
const type_string = try String.init(arena, typ, .{});
errdefer arena.release();
const type_string = try String.init(arena.allocator(), typ, .{});
const opts = _opts orelse Options{};
const event = try frame._factory.mouseEvent(
+4 -6
View File
@@ -16,7 +16,6 @@
// 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");
@@ -25,7 +24,6 @@ const Frame = @import("../../Frame.zig");
const Event = @import("../Event.zig");
const String = lp.String;
const Allocator = std.mem.Allocator;
// https://developer.mozilla.org/en-US/docs/Web/API/PopStateEvent
const PopStateEvent = @This();
@@ -43,18 +41,18 @@ const Options = Event.inheritOptions(PopStateEvent, PopStateEventOptions);
pub fn init(typ: []const u8, _opts: ?Options, frame: *Frame) !*PopStateEvent {
const arena = try frame.getArena(.tiny, "PopStateEvent");
errdefer frame.releaseArena(arena);
const type_string = try String.init(arena, typ, .{});
errdefer arena.release();
const type_string = try String.init(arena.allocator(), typ, .{});
return initWithTrusted(arena, type_string, _opts, false, frame);
}
pub fn initTrusted(typ: String, _opts: ?Options, frame: *Frame) !*PopStateEvent {
const arena = try frame.getArena(.tiny, "PopStateEvent.trusted");
errdefer frame.releaseArena(arena);
errdefer arena.release();
return initWithTrusted(arena, typ, _opts, true, frame);
}
fn initWithTrusted(arena: Allocator, typ: String, _opts: ?Options, trusted: bool, frame: *Frame) !*PopStateEvent {
fn initWithTrusted(arena: *lp.Arena, typ: String, _opts: ?Options, trusted: bool, frame: *Frame) !*PopStateEvent {
const opts = _opts orelse Options{};
const event = try frame._factory.event(
+4 -6
View File
@@ -16,14 +16,12 @@
// 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 Page = @import("../../Page.zig");
const Event = @import("../Event.zig");
const String = lp.String;
const Allocator = std.mem.Allocator;
const ProgressEvent = @This();
@@ -43,18 +41,18 @@ const Options = Event.inheritOptions(ProgressEvent, ProgressEventOptions);
pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*ProgressEvent {
const arena = try page.getArena(.tiny, "ProgressEvent");
errdefer page.releaseArena(arena);
const type_string = try String.init(arena, typ, .{});
errdefer arena.release();
const type_string = try String.init(arena.allocator(), typ, .{});
return initWithTrusted(arena, type_string, _opts, false, page);
}
pub fn initTrusted(typ: String, _opts: ?Options, page: *Page) !*ProgressEvent {
const arena = try page.getArena(.tiny, "ProgressEvent.trusted");
errdefer page.releaseArena(arena);
errdefer arena.release();
return initWithTrusted(arena, typ, _opts, true, page);
}
fn initWithTrusted(arena: Allocator, typ: String, _opts: ?Options, trusted: bool, page: *Page) !*ProgressEvent {
fn initWithTrusted(arena: *lp.Arena, typ: String, _opts: ?Options, trusted: bool, page: *Page) !*ProgressEvent {
const opts = _opts orelse Options{};
const event = try page.factory.event(
@@ -41,8 +41,8 @@ const Options = Event.inheritOptions(PromiseRejectionEvent, PromiseRejectionEven
pub fn init(typ: []const u8, opts_: ?Options, page: *Page) !*PromiseRejectionEvent {
const arena = try page.getArena(.tiny, "PromiseRejectionEvent");
errdefer page.releaseArena(arena);
const type_string = try String.init(arena, typ, .{});
errdefer arena.release();
const type_string = try String.init(arena.allocator(), typ, .{});
const opts = opts_ orelse Options{};
const event = try page.factory.event(
+5 -7
View File
@@ -16,7 +16,6 @@
// 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");
@@ -25,7 +24,6 @@ const Frame = @import("../../Frame.zig");
const Event = @import("../Event.zig");
const String = lp.String;
const Allocator = std.mem.Allocator;
// https://html.spec.whatwg.org/multipage/webstorage.html#the-storageevent-interface
const StorageEvent = @This();
@@ -49,18 +47,18 @@ const Options = Event.inheritOptions(StorageEvent, StorageEventOptions);
pub fn init(typ: []const u8, _opts: ?Options, frame: *Frame) !*StorageEvent {
const arena = try frame.getArena(.tiny, "StorageEvent");
errdefer frame.releaseArena(arena);
const type_string = try String.init(arena, typ, .{});
errdefer arena.release();
const type_string = try String.init(arena.allocator(), typ, .{});
return initWithTrusted(arena, type_string, _opts, false, frame);
}
pub fn initTrusted(typ: String, _opts: ?Options, frame: *Frame) !*StorageEvent {
const arena = try frame.getArena(.tiny, "StorageEvent.trusted");
errdefer frame.releaseArena(arena);
errdefer arena.release();
return initWithTrusted(arena, typ, _opts, true, frame);
}
fn initWithTrusted(arena: Allocator, typ: String, _opts: ?Options, trusted: bool, frame: *Frame) !*StorageEvent {
fn initWithTrusted(arena: *lp.Arena, typ: String, _opts: ?Options, trusted: bool, frame: *Frame) !*StorageEvent {
const opts = _opts orelse Options{};
const event = try frame._factory.event(
@@ -121,7 +119,7 @@ pub fn initStorageEvent(
const arena = event._arena;
event._initialized = true;
event._type_string = try String.init(arena, typ, .{});
event._type_string = try String.init(arena.allocator(), typ, .{});
event._bubbles = bubbles orelse false;
event._cancelable = cancelable orelse false;
self._key = if (key) |k| try arena.dupe(u8, k) else null;
+4 -6
View File
@@ -16,7 +16,6 @@
// 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");
@@ -26,7 +25,6 @@ const Event = @import("../Event.zig");
const HtmlElement = @import("../element/Html.zig");
const String = lp.String;
const Allocator = std.mem.Allocator;
/// https://developer.mozilla.org/en-US/docs/Web/API/SubmitEvent
const SubmitEvent = @This();
@@ -44,18 +42,18 @@ const Options = Event.inheritOptions(SubmitEvent, SubmitEventOptions);
pub fn init(typ: []const u8, opts_: ?Options, frame: *Frame) !*SubmitEvent {
const arena = try frame.getArena(.tiny, "SubmitEvent");
errdefer frame.releaseArena(arena);
const type_string = try String.init(arena, typ, .{});
errdefer arena.release();
const type_string = try String.init(arena.allocator(), typ, .{});
return initWithTrusted(arena, type_string, opts_, false, frame);
}
pub fn initTrusted(typ: String, _opts: ?Options, frame: *Frame) !*SubmitEvent {
const arena = try frame.getArena(.tiny, "SubmitEvent.trusted");
errdefer frame.releaseArena(arena);
errdefer arena.release();
return initWithTrusted(arena, typ, _opts, true, frame);
}
fn initWithTrusted(arena: Allocator, typ: String, _opts: ?Options, trusted: bool, frame: *Frame) !*SubmitEvent {
fn initWithTrusted(arena: *lp.Arena, typ: String, _opts: ?Options, trusted: bool, frame: *Frame) !*SubmitEvent {
const opts = _opts orelse Options{};
const event = try frame._factory.event(
+3 -3
View File
@@ -44,8 +44,8 @@ pub const Options = Event.inheritOptions(
pub fn init(typ: []const u8, _opts: ?Options, frame: *Frame) !*TextEvent {
const arena = try frame.getArena(.tiny, "TextEvent");
errdefer frame.releaseArena(arena);
const type_string = try String.init(arena, typ, .{});
errdefer arena.release();
const type_string = try String.init(arena.allocator(), typ, .{});
const opts = _opts orelse Options{};
@@ -86,7 +86,7 @@ pub fn initTextEvent(
const arena = event._arena;
event._initialized = true;
event._type_string = try String.init(arena, typ, .{});
event._type_string = try String.init(arena.allocator(), typ, .{});
event._bubbles = bubbles orelse false;
event._cancelable = cancelable orelse false;
ui._view = view;
+4 -6
View File
@@ -16,7 +16,6 @@
// 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");
@@ -26,7 +25,6 @@ const Event = @import("../Event.zig");
const HtmlElement = @import("../element/Html.zig");
const String = lp.String;
const Allocator = std.mem.Allocator;
/// https://html.spec.whatwg.org/multipage/popover.html#toggleevent
const ToggleEvent = @This();
@@ -48,18 +46,18 @@ const Options = Event.inheritOptions(ToggleEvent, ToggleEventOptions);
pub fn init(typ: []const u8, opts_: ?Options, frame: *Frame) !*ToggleEvent {
const arena = try frame.getArena(.tiny, "ToggleEvent");
errdefer frame.releaseArena(arena);
const type_string = try String.init(arena, typ, .{});
errdefer arena.release();
const type_string = try String.init(arena.allocator(), typ, .{});
return initWithTrusted(arena, type_string, opts_, false, frame);
}
pub fn initTrusted(typ: String, _opts: ?Options, frame: *Frame) !*ToggleEvent {
const arena = try frame.getArena(.tiny, "ToggleEvent.trusted");
errdefer frame.releaseArena(arena);
errdefer arena.release();
return initWithTrusted(arena, typ, _opts, true, frame);
}
fn initWithTrusted(arena: Allocator, typ: String, _opts: ?Options, trusted: bool, frame: *Frame) !*ToggleEvent {
fn initWithTrusted(arena: *lp.Arena, typ: String, _opts: ?Options, trusted: bool, frame: *Frame) !*ToggleEvent {
const opts = _opts orelse Options{};
const event = try frame._factory.event(
+2 -2
View File
@@ -60,8 +60,8 @@ pub fn initTrusted(typ: []const u8, _opts: ?Options, frame: *Frame) !*TouchEvent
fn initWithTrusted(typ: []const u8, _opts: ?Options, trusted: bool, frame: *Frame) !*TouchEvent {
const arena = try frame.getArena(.tiny, "TouchEvent");
errdefer frame.releaseArena(arena);
const type_string = try String.init(arena, typ, .{});
errdefer arena.release();
const type_string = try String.init(arena.allocator(), typ, .{});
const opts = _opts orelse Options{};
const event = try frame._factory.uiEvent(
+3 -3
View File
@@ -58,8 +58,8 @@ pub const Options = Event.inheritOptions(
pub fn init(typ: []const u8, _opts: ?Options, frame: *Frame) !*UIEvent {
const arena = try frame.getArena(.tiny, "UIEvent");
errdefer frame.releaseArena(arena);
const type_string = try String.init(arena, typ, .{});
errdefer arena.release();
const type_string = try String.init(arena.allocator(), typ, .{});
const opts = _opts orelse Options{};
const event = try frame._factory.event(
@@ -151,7 +151,7 @@ pub fn initUIEvent(
}
event._initialized = true;
event._type_string = try String.init(event._arena, typ, .{});
event._type_string = try String.init(event._arena.allocator(), typ, .{});
event._bubbles = bubbles orelse false;
event._cancelable = cancelable orelse false;
self._view = view;
+2 -2
View File
@@ -62,8 +62,8 @@ pub fn initTrusted(typ: []const u8, _opts: ?Options, frame: *Frame) !*WheelEvent
fn initWithTrusted(typ: []const u8, _opts: ?Options, trusted: bool, frame: *Frame) !*WheelEvent {
const arena = try frame.getArena(.medium, "WheelEvent");
errdefer frame.releaseArena(arena);
const type_string = try String.init(arena, typ, .{});
errdefer arena.release();
const type_string = try String.init(arena.allocator(), typ, .{});
const opts = _opts orelse Options{};
+8 -8
View File
@@ -213,9 +213,9 @@ pub fn pushEntry(
const id = self._next_entry_id;
self._next_entry_id += 1;
const id_str = try std.fmt.allocPrint(arena, "{d}", .{id});
const id_str = try std.fmt.allocPrint(arena.allocator(), "{d}", .{id});
const entry = try Factory.chainedWithAllocator(arena, .{
const entry = try Factory.chainedWithAllocator(arena.allocator(), .{
EventTarget{ ._type = undefined },
NavigationHistoryEntry{
._proto = undefined,
@@ -229,7 +229,7 @@ pub fn pushEntry(
// we don't always have a current entry...
const previous = if (self._entries.items.len > 0) self.getCurrentEntry() else null;
try self._entries.append(arena, entry);
try self._entries.append(arena.allocator(), entry);
self._index = index;
if (previous != null and should_dispatch) {
@@ -260,9 +260,9 @@ pub fn replaceEntry(
const id = self._next_entry_id;
self._next_entry_id += 1;
const id_str = try std.fmt.allocPrint(arena, "{d}", .{id});
const id_str = try std.fmt.allocPrint(arena.allocator(), "{d}", .{id});
const entry = try Factory.chainedWithAllocator(arena, .{
const entry = try Factory.chainedWithAllocator(arena.allocator(), .{
EventTarget{ ._type = undefined },
NavigationHistoryEntry{
._proto = undefined,
@@ -320,7 +320,7 @@ pub fn navigateInner(
const committed = local.createPromiseResolver();
const finished = local.createPromiseResolver();
var new_url = try URL.resolve(arena, frame.url, url, .{});
var new_url = try URL.resolve(arena.allocator(), frame.url, url, .{});
const is_same_document = URL.eqlDocument(new_url, frame.url);
// In case of navigation to the same document, we force an url duplication.
@@ -406,7 +406,7 @@ pub fn navigateInner(
pub fn navigate(self: *Navigation, _url: [:0]const u8, _opts: ?NavigateOptions, frame: *Frame) !NavigationReturn {
const arena = frame._session.arena;
const opts = _opts orelse NavigateOptions{};
const json = if (opts.state) |state| state.toJson(arena) catch return error.DataClone else null;
const json = if (opts.state) |state| state.toJson(arena.allocator()) catch return error.DataClone else null;
const kind: NavigationKind = if (opts.history) |history|
if (std.mem.eql(u8, "replace", history)) .{ .replace = json } else .{ .push = json }
@@ -469,7 +469,7 @@ pub fn updateCurrentEntry(self: *Navigation, options: UpdateCurrentEntryOptions,
const previous = self.getCurrentEntry();
self.getCurrentEntry()._state = .{
.source = .navigation,
.value = options.state.toJson(arena) catch return error.DataClone,
.value = options.state.toJson(arena.allocator()) catch return error.DataClone,
};
if (self._on_currententrychange) |cec| {
+13 -14
View File
@@ -33,7 +33,6 @@ const MessageEvent = @import("../event/MessageEvent.zig");
const log = lp.log;
const String = lp.String;
const Execution = js.Execution;
const Allocator = std.mem.Allocator;
const IS_DEBUG = @import("builtin").mode == .Debug;
// https://html.spec.whatwg.org/multipage/server-sent-events.html
@@ -44,7 +43,7 @@ pub const Proto = EventTarget;
_rc: lp.RC = .{},
_exec: *const Execution,
_proto: *EventTarget,
_arena: Allocator,
_arena: *lp.Arena,
_url: [:0]const u8,
_with_credentials: bool = false,
@@ -96,13 +95,13 @@ const Opts = struct {
pub fn init(url: []const u8, opts_: ?Opts, exec: *const Execution) !*EventSource {
const arena = try exec.getArena(.medium, "EventSource");
errdefer exec.releaseArena(arena);
errdefer arena.release();
const resolved = URL.resolve(arena, exec.base(), url, .{ .encoding = exec.charset.* }) catch {
const resolved = URL.resolve(arena.allocator(), exec.base(), url, .{ .encoding = exec.charset.* }) catch {
return error.SyntaxError;
};
const self = try exec._factory.eventTargetWithAllocator(arena, EventSource{
const self = try exec._factory.eventTargetWithAllocator(arena.allocator(), EventSource{
._exec = exec,
._arena = arena,
._proto = undefined,
@@ -130,7 +129,7 @@ pub fn init(url: []const u8, opts_: ?Opts, exec: *const Execution) !*EventSource
return self;
}
pub fn deinit(self: *EventSource, page: *Page) void {
pub fn deinit(self: *EventSource, _: *Page) void {
self._ready_state = .closed;
if (self._transfer) |transfer| {
self._transfer = null;
@@ -147,7 +146,7 @@ pub fn deinit(self: *EventSource, page: *Page) void {
func.release();
}
page.releaseArena(self._arena);
self._arena.release();
}
pub fn releaseRef(self: *EventSource, page: *Page) void {
@@ -174,7 +173,7 @@ fn connect(self: *EventSource) !void {
self._event_type_buf.clearRetainingCapacity();
self._id_buf.clearRetainingCapacity();
try self._id_buf.appendSlice(self._arena, self._last_event_id.items);
try self._id_buf.appendSlice(self._arena.allocator(), self._last_event_id.items);
var headers = try http_client.newHeaders();
try headers.add("Accept: text/event-stream");
@@ -344,7 +343,7 @@ fn httpHeaderDoneCallback(transfer: *Transfer) !Transfer.HeaderResult {
defer ls.deinit();
const final_url = try self._arena.dupeZ(u8, transfer.req.url);
self._event_origin = (URL.getOrigin(self._arena, final_url) catch null) orelse "";
self._event_origin = (URL.getOrigin(self._arena.allocator(), final_url) catch null) orelse "";
// https://html.spec.whatwg.org/multipage/server-sent-events.html#announce-the-connection
self._ready_state = .open;
@@ -463,7 +462,7 @@ fn bufferLine(self: *EventSource, bytes: []const u8) !void {
if (self._line_buf.items.len + bytes.len > self._max_response_size) {
return error.ResponseTooLarge;
}
return self._line_buf.appendSlice(self._arena, bytes);
return self._line_buf.appendSlice(self._arena.allocator(), bytes);
}
fn processLine(self: *EventSource) !void {
@@ -501,20 +500,20 @@ fn processLine(self: *EventSource) !void {
if (self._data_buf.items.len + add_len > self._max_response_size) {
return error.ResponseTooLarge;
}
try self._data_buf.ensureUnusedCapacity(arena, add_len);
try self._data_buf.ensureUnusedCapacity(arena.allocator(), add_len);
self._data_buf.appendSliceAssumeCapacity(value);
self._data_buf.appendAssumeCapacity('\n');
}
if (std.mem.eql(u8, field, "event")) {
self._event_type_buf.clearRetainingCapacity();
try self._event_type_buf.appendSlice(arena, value);
try self._event_type_buf.appendSlice(arena.allocator(), value);
}
if (std.mem.eql(u8, field, "id")) {
if (std.mem.indexOfScalar(u8, value, 0) == null) {
self._id_buf.clearRetainingCapacity();
try self._id_buf.appendSlice(arena, value);
try self._id_buf.appendSlice(arena.allocator(), value);
}
}
@@ -529,7 +528,7 @@ fn processLine(self: *EventSource) !void {
// An empty line completed an event block.
fn dispatchPending(self: *EventSource) !void {
self._last_event_id.clearRetainingCapacity();
try self._last_event_id.appendSlice(self._arena, self._id_buf.items);
try self._last_event_id.appendSlice(self._arena.allocator(), self._id_buf.items);
const data = self._data_buf.items;
if (data.len == 0) {
+4 -4
View File
@@ -152,7 +152,7 @@ fn httpHeaderDoneCallback(transfer: *Transfer) !Transfer.HeaderResult {
const arena = self._response._arena;
if (transfer.getContentLength()) |cl| {
try self._buf.ensureTotalCapacity(arena, cl);
try self._buf.ensureTotalCapacity(arena.allocator(), cl);
}
const res = self._response;
@@ -183,8 +183,8 @@ fn httpHeaderDoneCallback(transfer: *Transfer) !Transfer.HeaderResult {
// Determine response type based on origin comparison
const exec = self._exec;
const requesting_origin = URL.getOrigin(arena, exec.url.*) catch null;
const response_origin = URL.getOrigin(arena, res._url) catch null;
const requesting_origin = URL.getOrigin(arena.allocator(), exec.url.*) catch null;
const response_origin = URL.getOrigin(arena.allocator(), res._url) catch null;
if (requesting_origin) |fo| {
if (response_origin) |ro| {
@@ -218,7 +218,7 @@ fn httpDataCallback(transfer: *Transfer, data: []const u8) !void {
}
}
try self._buf.appendSlice(self._response._arena, data);
try self._buf.appendSlice(self._response._arena.allocator(), data);
}
fn httpDoneCallback(ctx: *anyopaque) !void {
+74 -45
View File
@@ -40,7 +40,7 @@ const FormData = @This();
_rc: lp.RC,
_arena: Allocator,
_arena: *lp.Arena,
_entries: std.ArrayList(Entry),
pub const Entry = struct {
@@ -77,7 +77,7 @@ pub const Entry = struct {
pub fn init(form_: ?*Form, submitter: ?*Element, exec: *const Execution) !*FormData {
const arena = try exec.getArena(.small, "FormData");
errdefer exec.releaseArena(arena);
errdefer arena.release();
const form_data = try arena.create(FormData);
form_data.* = .{
@@ -101,7 +101,7 @@ pub fn init(form_: ?*Form, submitter: ?*Element, exec: *const Execution) !*FormD
form._constructing_entry_list = true;
defer form._constructing_entry_list = false;
form_data._entries = try collectForm(arena, form, submitter, frame);
form_data._entries = try collectForm(arena.allocator(), form, submitter, frame);
// Hold a reference on each entry's File for the FormData's lifetime; released
// in deinit.
@@ -126,7 +126,7 @@ pub fn init(form_: ?*Form, submitter: ?*Element, exec: *const Execution) !*FormD
// application/x-www-form-urlencoded body back into a FormData.
pub fn initFromUrlEncoded(bytes: []const u8, exec: *const Execution) !*FormData {
const arena = try exec.getArena(.small, "FormData");
errdefer exec.releaseArena(arena);
errdefer arena.release();
const form_data = try arena.create(FormData);
form_data.* = .{
@@ -142,7 +142,7 @@ pub fn initFromUrlEncoded(bytes: []const u8, exec: *const Execution) !*FormData
// body back into a FormData. `boundary` is the Content-Type boundary param.
pub fn initFromMultipart(bytes: []const u8, boundary: []const u8, exec: *const Execution) !*FormData {
const arena = try exec.getArena(.small, "FormData");
errdefer exec.releaseArena(arena);
errdefer arena.release();
const form_data = try arena.create(FormData);
form_data.* = .{
@@ -170,7 +170,7 @@ pub fn deinit(self: *FormData, page: *Page) void {
}
}
// Frees the entry list and this FormData itself; do not touch self afterwards.
page.releaseArena(self._arena);
self._arena.release();
}
pub fn releaseRef(self: *FormData, page: *Page) void {
@@ -238,11 +238,11 @@ pub fn append(self: *FormData, name: []const u8, value: EntryValue, filename: ?[
// A Blob that is not a File becomes a File named "blob".
break :blk .{ .file = try fileFrom(blob, "blob", exec.page) };
},
.bytes => |b| .{ .string = try String.init(self._arena, b, .{}) },
.bytes => |b| .{ .string = try String.init(self._arena.allocator(), b, .{}) },
};
try self._entries.append(self._arena, .{
.name = try String.init(self._arena, name, .{}),
try self._entries.append(self._arena.allocator(), .{
.name = try String.init(self._arena.allocator(), name, .{}),
.value = entry_value,
});
}
@@ -252,9 +252,9 @@ pub fn append(self: *FormData, name: []const u8, value: EntryValue, filename: ?[
// the entry owns that reference and deleteByName releases it.
fn fileFrom(source: *Blob, name: []const u8, page: *Page) !*File {
const arena = try page.getArena(source._slice.len + source._mime.len + 256, "Blob");
errdefer page.releaseArena(arena);
errdefer arena.release();
const file = try Factory.chainedWithAllocator(arena, .{
const file = try Factory.chainedWithAllocator(arena.allocator(), .{
try Blob.buildValueFromBytes(arena, source._slice, source._mime),
File{
._proto = undefined,
@@ -268,9 +268,9 @@ fn fileFrom(source: *Blob, name: []const u8, page: *Page) !*File {
}
pub fn appendText(self: *FormData, name: []const u8, value: []const u8) !void {
try self._entries.append(self._arena, .{
.name = try String.init(self._arena, name, .{}),
.value = .{ .string = try String.init(self._arena, value, .{}) },
try self._entries.append(self._arena.allocator(), .{
.name = try String.init(self._arena.allocator(), name, .{}),
.value = .{ .string = try String.init(self._arena.allocator(), value, .{}) },
});
}
@@ -444,11 +444,11 @@ pub fn parseUrlEncoded(self: *FormData, bytes: []const u8) !void {
}
if (std.mem.indexOfScalar(u8, pair, '=')) |idx| {
try self.appendText(
try urlDecode(self._arena, pair[0..idx]),
try urlDecode(self._arena, pair[idx + 1 ..]),
try urlDecode(self._arena.allocator(), pair[0..idx]),
try urlDecode(self._arena.allocator(), pair[idx + 1 ..]),
);
} else {
const key = try urlDecode(self._arena, pair);
const key = try urlDecode(self._arena.allocator(), pair);
// Insert with empty value.
try self.appendText(key, "");
}
@@ -605,7 +605,7 @@ fn parseMultipart(self: *FormData, page: *Page, bytes: []const u8, boundary: []c
}
const parsed = disposition orelse return error.InvalidFormData;
const name = try decodeMultipartName(self._arena, parsed.name orelse return error.InvalidFormData);
const name = try decodeMultipartName(self._arena.allocator(), parsed.name orelse return error.InvalidFormData);
const content_end = indexOfBoundary(cursor.remaining(), boundary) orelse return error.InvalidFormData;
const content = cursor.remaining()[0..content_end];
@@ -619,14 +619,14 @@ fn parseMultipart(self: *FormData, page: *Page, bytes: []const u8, boundary: []c
const file = try blob._arena.create(File);
file.* = .{
._proto = blob,
._name = try blob._arena.dupe(u8, try decodeMultipartName(self._arena, filename)),
._name = try blob._arena.dupe(u8, try decodeMultipartName(self._arena.allocator(), filename)),
._last_modified = @intCast(lp.datetime.milliTimestamp(.real)),
};
blob._type = .{ .file = file };
file.acquireRef();
try self._entries.append(self._arena, .{
.name = try String.init(self._arena, name, .{}),
try self._entries.append(self._arena.allocator(), .{
.name = try String.init(self._arena.allocator(), name, .{}),
.value = .{ .file = file },
});
} else {
@@ -875,10 +875,12 @@ test "WebApi: FormData" {
test "FormData: multipart write" {
const allocator = testing.arena_allocator;
const arena = try testing.test_app.arena_pool.acquire(.small, "FormData test");
defer arena.release();
var fd = FormData{
._rc = .{},
._arena = allocator,
._arena = arena,
._entries = .empty,
};
try fd.appendText("name", "John");
@@ -904,10 +906,12 @@ test "FormData: multipart write" {
test "FormData: multipart escapes name CR/LF/quote" {
const allocator = testing.arena_allocator;
const arena = try testing.test_app.arena_pool.acquire(.small, "FormData test");
defer arena.release();
var fd = FormData{
._rc = .{},
._arena = allocator,
._arena = arena,
._entries = .empty,
};
try fd.appendText("a\"b\r\nc", "v");
@@ -929,10 +933,12 @@ test "FormData: multipart escapes name CR/LF/quote" {
test "FormData: multipart empty body" {
const allocator = testing.arena_allocator;
const arena = try testing.test_app.arena_pool.acquire(.small, "FormData test");
defer arena.release();
var fd = FormData{
._rc = .{},
._arena = allocator,
._arena = arena,
._entries = .empty,
};
@@ -947,7 +953,7 @@ test "FormData: multipart empty body" {
fn buildTestFile(arena: Allocator, page: *@import("../../Page.zig"), name: []const u8, mime: []const u8, body: []const u8) !*File {
const blob_arena = try page.getArena(body.len + mime.len + 256, "Blob");
const file = try Factory.chainedWithAllocator(blob_arena, .{
const file = try Factory.chainedWithAllocator(blob_arena.allocator(), .{
try Blob.buildValueFromBytes(blob_arena, body, mime),
File{
._proto = undefined,
@@ -962,6 +968,8 @@ fn buildTestFile(arena: Allocator, page: *@import("../../Page.zig"), name: []con
test "FormData: multipart with file" {
const allocator = testing.arena_allocator;
const arena = try testing.test_app.arena_pool.acquire(.small, "FormData test");
defer arena.release();
const frame = try testing.createFrame();
defer testing.test_session.closeAllPages();
@@ -970,7 +978,7 @@ test "FormData: multipart with file" {
var fd = FormData{
._rc = .{},
._arena = allocator,
._arena = arena,
._entries = .empty,
};
try fd.appendText("field", "value");
@@ -1000,6 +1008,8 @@ test "FormData: multipart with file" {
test "FormData: multipart with empty file defaults to octet-stream" {
const allocator = testing.arena_allocator;
const arena = try testing.test_app.arena_pool.acquire(.small, "FormData test");
defer arena.release();
const frame = try testing.createFrame();
defer testing.test_session.closeAllPages();
@@ -1008,7 +1018,7 @@ test "FormData: multipart with empty file defaults to octet-stream" {
var fd = FormData{
._rc = .{},
._arena = allocator,
._arena = arena,
._entries = .empty,
};
try fd._entries.append(allocator, .{
@@ -1034,6 +1044,8 @@ test "FormData: multipart with empty file defaults to octet-stream" {
test "FormData: multipart escapes file name and filename" {
const allocator = testing.arena_allocator;
const arena = try testing.test_app.arena_pool.acquire(.small, "FormData test");
defer arena.release();
const frame = try testing.createFrame();
defer testing.test_session.closeAllPages();
@@ -1042,7 +1054,7 @@ test "FormData: multipart escapes file name and filename" {
var fd = FormData{
._rc = .{},
._arena = allocator,
._arena = arena,
._entries = .empty,
};
try fd._entries.append(allocator, .{
@@ -1068,6 +1080,8 @@ test "FormData: multipart escapes file name and filename" {
test "FormData: file entry collapses to filename in urlencode" {
const allocator = testing.arena_allocator;
const arena = try testing.test_app.arena_pool.acquire(.small, "FormData test");
defer arena.release();
const frame = try testing.createFrame();
defer testing.test_session.closeAllPages();
@@ -1076,7 +1090,7 @@ test "FormData: file entry collapses to filename in urlencode" {
var fd = FormData{
._rc = .{},
._arena = allocator,
._arena = arena,
._entries = .empty,
};
try fd._entries.append(allocator, .{
@@ -1091,10 +1105,12 @@ test "FormData: file entry collapses to filename in urlencode" {
test "FormData: multipart no_file (unselected file input)" {
const allocator = testing.arena_allocator;
const arena = try testing.test_app.arena_pool.acquire(.small, "FormData test");
defer arena.release();
var fd = FormData{
._rc = .{},
._arena = allocator,
._arena = arena,
._entries = .empty,
};
try fd._entries.append(allocator, .{
@@ -1120,10 +1136,12 @@ test "FormData: multipart no_file (unselected file input)" {
test "FormData: no_file entry collapses to empty in urlencode" {
const allocator = testing.arena_allocator;
const arena = try testing.test_app.arena_pool.acquire(.small, "FormData test");
defer arena.release();
var fd = FormData{
._rc = .{},
._arena = allocator,
._arena = arena,
._entries = .empty,
};
try fd._entries.append(allocator, .{
@@ -1138,10 +1156,12 @@ test "FormData: no_file entry collapses to empty in urlencode" {
test "FormData: plaintext write" {
const allocator = testing.arena_allocator;
const arena = try testing.test_app.arena_pool.acquire(.small, "FormData test");
defer arena.release();
var fd = FormData{
._rc = .{},
._arena = allocator,
._arena = arena,
._entries = .empty,
};
try fd.appendText("name", "John");
@@ -1164,10 +1184,12 @@ test "FormData: plaintext write" {
test "FormData: plaintext empty body" {
const allocator = testing.arena_allocator;
const arena = try testing.test_app.arena_pool.acquire(.small, "FormData test");
defer arena.release();
var fd = FormData{
._rc = .{},
._arena = allocator,
._arena = arena,
._entries = .empty,
};
@@ -1178,11 +1200,12 @@ test "FormData: plaintext empty body" {
}
test "FormData: urlencoded parse" {
const allocator = testing.arena_allocator;
const arena = try testing.test_app.arena_pool.acquire(.small, "FormData test");
defer arena.release();
var fd = FormData{
._rc = .{},
._arena = allocator,
._arena = arena,
._entries = .empty,
};
try fd.parseUrlEncoded("a=1&b=hello+world&c=%26%3D&no_value&&bad=100%zz");
@@ -1197,11 +1220,12 @@ test "FormData: urlencoded parse" {
}
test "FormData: urlencoded parse exercises the vectorized guard" {
const allocator = testing.arena_allocator;
const arena = try testing.test_app.arena_pool.acquire(.small, "FormData test");
defer arena.release();
var fd = FormData{
._rc = .{},
._arena = allocator,
._arena = arena,
._entries = .empty,
};
// Values longer than any SIMD vector length, with the lone special
@@ -1217,13 +1241,14 @@ test "FormData: urlencoded parse exercises the vectorized guard" {
}
test "FormData: multipart parse" {
const allocator = testing.arena_allocator;
const arena = try testing.test_app.arena_pool.acquire(.small, "FormData test");
defer arena.release();
const frame = try testing.createFrame();
defer testing.test_session.closeAllPages();
var fd = FormData{
._rc = .{},
._arena = allocator,
._arena = arena,
._entries = .empty,
};
try fd.parseMultipart(frame._page, "--BOUNDARY\r\n" ++
@@ -1247,13 +1272,14 @@ test "FormData: multipart parse" {
}
test "FormData: multipart parse with file" {
const allocator = testing.arena_allocator;
const arena = try testing.test_app.arena_pool.acquire(.small, "FormData test");
defer arena.release();
const frame = try testing.createFrame();
defer testing.test_session.closeAllPages();
var fd = FormData{
._rc = .{},
._arena = allocator,
._arena = arena,
._entries = .empty,
};
try fd.parseMultipart(frame._page, "--B\r\n" ++
@@ -1285,7 +1311,8 @@ test "FormData: multipart parse with file" {
}
test "FormData: multipart parse rejects malformed bodies" {
const allocator = testing.arena_allocator;
const arena = try testing.test_app.arena_pool.acquire(.small, "FormData test");
defer arena.release();
const frame = try testing.createFrame();
defer testing.test_session.closeAllPages();
@@ -1300,7 +1327,7 @@ test "FormData: multipart parse rejects malformed bodies" {
for (cases) |case| {
var fd = FormData{
._rc = .{},
._arena = allocator,
._arena = arena,
._entries = .empty,
};
try testing.expectError(error.InvalidFormData, fd.parseMultipart(frame._page, case, "B"));
@@ -1309,12 +1336,14 @@ test "FormData: multipart parse rejects malformed bodies" {
test "FormData: multipart round-trip" {
const allocator = testing.arena_allocator;
const arena = try testing.test_app.arena_pool.acquire(.small, "FormData test");
defer arena.release();
const frame = try testing.createFrame();
defer testing.test_session.closeAllPages();
var src = FormData{
._rc = .{},
._arena = allocator,
._arena = arena,
._entries = .empty,
};
try src.appendText("username", "alice");
@@ -1332,7 +1361,7 @@ test "FormData: multipart round-trip" {
var fd = FormData{
._rc = .{},
._arena = allocator,
._arena = arena,
._entries = .empty,
};
try fd.parseMultipart(frame._page, buf.written(), "BOUNDARY");
+7 -8
View File
@@ -34,7 +34,6 @@ const body_init = @import("body_init.zig");
const BodyInit = body_init.BodyInit;
const Execution = js.Execution;
const Allocator = std.mem.Allocator;
const Request = @This();
@@ -43,7 +42,7 @@ _url: [:0]const u8,
_method: http.Method,
_headers: ?*Headers,
_body: ?[]const u8,
_arena: Allocator,
_arena: *lp.Arena,
_cache: Cache,
_credentials: Credentials,
_redirect: Redirect,
@@ -94,10 +93,10 @@ const Cache = enum {
pub fn init(input: Input, opts_: ?InitOpts, exec: *const Execution) !*Request {
const arena = try exec.getArena(.medium, "Request");
errdefer exec.releaseArena(arena);
errdefer arena.release();
const url = switch (input) {
.url => |u| try URL.resolve(arena, exec.base(), u, .{ .encoding = exec.charset.* }),
.url => |u| try URL.resolve(arena.allocator(), exec.base(), u, .{ .encoding = exec.charset.* }),
.request => |r| try arena.dupeZ(u8, r._url),
};
@@ -124,7 +123,7 @@ pub fn init(input: Input, opts_: ?InitOpts, exec: *const Execution) !*Request {
};
const body = if (opts.body) |b| blk: {
const extracted = try b.extract(arena);
const extracted = try b.extract(arena.allocator());
// Per Fetch §6.5 step 11, the default Content-Type only applies if
// the user has not already set one via the headers init dict.
if (extracted.content_type) |ct| {
@@ -164,8 +163,8 @@ pub fn init(input: Input, opts_: ?InitOpts, exec: *const Execution) !*Request {
return self;
}
pub fn deinit(self: *Request, page: *Page) void {
page.releaseArena(self._arena);
pub fn deinit(self: *Request, _: *Page) void {
self._arena.release();
}
pub fn releaseRef(self: *Request, page: *Page) void {
@@ -345,7 +344,7 @@ pub fn formData(self: *Request, exec: *const Execution) !js.Promise {
pub fn clone(self: *const Request, exec: *const Execution) !*Request {
const arena = try exec.getArena(if (self._body) |b| b.len else 512, "Request.clone");
errdefer exec.releaseArena(arena);
errdefer arena.release();
const request = try arena.create(Request);
request.* = .{
+11 -11
View File
@@ -49,7 +49,7 @@ pub const Type = enum {
_rc: lp.RC = .{},
_status: u16,
_arena: Allocator,
_arena: *lp.Arena,
_headers: *Headers,
_body: Body = .empty,
_type: Type,
@@ -76,7 +76,7 @@ pub const BodyInit = body_init.BodyInit;
pub fn init(body_: ?BodyInit, opts_: ?InitOpts, exec: *const Execution) !*Response {
const session = exec.session;
const arena = try session.getArena(.large, "Response");
errdefer session.releaseArena(arena);
errdefer arena.release();
const opts = opts_ orelse InitOpts{};
const status_text = if (opts.statusText) |st| try arena.dupe(u8, st) else "";
@@ -87,7 +87,7 @@ pub fn init(body_: ?BodyInit, opts_: ?InitOpts, exec: *const Execution) !*Respon
switch (b) {
.stream => |stream| break :blk .{ .stream = stream },
else => {
const extracted = try b.extract(arena);
const extracted = try b.extract(arena.allocator());
content_type = extracted.content_type;
break :blk .{ .bytes = extracted.bytes };
},
@@ -118,7 +118,7 @@ pub fn init(body_: ?BodyInit, opts_: ?InitOpts, exec: *const Execution) !*Respon
pub fn createError(exec: *const Execution) !*Response {
const session = exec.session;
const arena = try session.getArena(.large, "Response.error");
errdefer session.releaseArena(arena);
errdefer arena.release();
const self = try arena.create(Response);
self.* = .{
@@ -143,9 +143,9 @@ pub fn createRedirect(url_: []const u8, status_: ?u16, exec: *const Execution) !
const session = exec.session;
const arena = try session.getArena(.large, "Response.redirect");
errdefer session.releaseArena(arena);
errdefer arena.release();
const location = try URL.resolve(arena, exec.base(), url_, .{ .encoding = exec.charset.* });
const location = try URL.resolve(arena.allocator(), exec.base(), url_, .{ .encoding = exec.charset.* });
const headers = try Headers.init(null, exec);
try headers.set("location", location, exec);
@@ -167,9 +167,9 @@ pub fn createRedirect(url_: []const u8, status_: ?u16, exec: *const Execution) !
pub fn createJson(data: js.Value, opts_: ?InitOpts, exec: *const Execution) !*Response {
const session = exec.session;
const arena = try session.getArena(.medium, "Response.json");
errdefer session.releaseArena(arena);
errdefer arena.release();
const json = data.toJson(arena) catch |err| switch (err) {
const json = data.toJson(arena.allocator()) catch |err| switch (err) {
error.JsException => return error.TryCatchRethrow,
else => return err,
};
@@ -199,12 +199,12 @@ pub fn createJson(data: js.Value, opts_: ?InitOpts, exec: *const Execution) !*Re
return self;
}
pub fn deinit(self: *Response, page: *Page) void {
pub fn deinit(self: *Response, _: *Page) void {
if (self._http_transfer) |resp| {
resp.abort(error.Abort);
self._http_transfer = null;
}
page.releaseArena(self._arena);
self._arena.release();
}
pub fn releaseRef(self: *Response, page: *Page) void {
@@ -509,7 +509,7 @@ pub fn clone(self: *const Response, exec: *const Execution) !*Response {
.stream => 0,
};
const arena = try session.getArena(body_len + self._url.len + 256, "Response.clone");
errdefer session.releaseArena(arena);
errdefer arena.release();
const body: Body = switch (self._body) {
.bytes => |b| .{ .bytes = try arena.dupe(u8, b) },
+13 -13
View File
@@ -42,7 +42,7 @@ pub fn registerTypes() []const type {
const URLSearchParams = @This();
_rc: lp.RC = .{},
_arena: Allocator,
_arena: *lp.Arena,
_params: KeyValueList,
const InitOpts = union(enum) {
@@ -53,17 +53,17 @@ const InitOpts = union(enum) {
pub fn init(opts_: ?InitOpts, exec: *const Execution) !*URLSearchParams {
const arena = try exec.getArena(.small, "URLSearchParams");
errdefer exec.releaseArena(arena);
errdefer arena.release();
const params: KeyValueList = blk: {
const opts = opts_ orelse break :blk .empty;
switch (opts) {
.query_string => |qs| break :blk try paramsFromString(arena, qs, exec.buf),
.form_data => |fd| break :blk try fd.toKeyValueList(arena),
.query_string => |qs| break :blk try paramsFromString(arena.allocator(), qs, exec.buf),
.form_data => |fd| break :blk try fd.toKeyValueList(arena.allocator()),
.value => |js_val| {
// Order matters here; Array is also an Object.
if (js_val.isArray()) {
break :blk try paramsFromArray(arena, js_val.toArray());
break :blk try paramsFromArray(arena.allocator(), js_val.toArray());
}
if (js_val.isObject()) {
// Per the URL spec, an iterable init (URLSearchParams,
@@ -73,13 +73,13 @@ pub fn init(opts_: ?InitOpts, exec: *const Execution) !*URLSearchParams {
// the prototype-method-leak doesn't just turn into a
// silent empty querystring.
if (js_val.toZig(*URLSearchParams)) |other| {
break :blk try KeyValueList.copy(arena, other._params);
break :blk try KeyValueList.copy(arena.allocator(), other._params);
} else |_| {}
// normalizer is null, so frame won't be used
break :blk try KeyValueList.fromJsObject(arena, js_val.toObject(), null, exec.buf);
break :blk try KeyValueList.fromJsObject(arena.allocator(), js_val.toObject(), null, exec.buf);
}
if (js_val.isString()) |js_str| {
break :blk try paramsFromString(arena, try js_str.toSliceWithAlloc(arena), exec.buf);
break :blk try paramsFromString(arena.allocator(), try js_str.toSliceWithAlloc(arena.allocator()), exec.buf);
}
return error.InvalidArgument;
},
@@ -94,8 +94,8 @@ pub fn init(opts_: ?InitOpts, exec: *const Execution) !*URLSearchParams {
return self;
}
pub fn deinit(self: *URLSearchParams, page: *Page) void {
page.releaseArena(self._arena);
pub fn deinit(self: *URLSearchParams, _: *Page) void {
self._arena.release();
}
pub fn releaseRef(self: *URLSearchParams, page: *Page) void {
@@ -107,7 +107,7 @@ pub fn acquireRef(self: *URLSearchParams) void {
}
pub fn updateFromString(self: *URLSearchParams, query_string: []const u8, exec: *const Execution) !void {
self._params = try paramsFromString(self._arena, query_string, exec.buf);
self._params = try paramsFromString(self._arena.allocator(), query_string, exec.buf);
}
pub fn getSize(self: *const URLSearchParams) usize {
@@ -127,11 +127,11 @@ pub fn has(self: *const URLSearchParams, name: []const u8) bool {
}
pub fn set(self: *URLSearchParams, name: []const u8, value: []const u8) !void {
return self._params.set(self._arena, name, value);
return self._params.set(self._arena.allocator(), name, value);
}
pub fn append(self: *URLSearchParams, name: []const u8, value: []const u8) !void {
return self._params.append(self._arena, name, value);
return self._params.append(self._arena.allocator(), name, value);
}
pub fn delete(self: *URLSearchParams, name: []const u8, value: ?[]const u8) void {
+26 -27
View File
@@ -35,7 +35,6 @@ const MessageEvent = @import("../event/MessageEvent.zig");
const log = lp.log;
const Execution = js.Execution;
const Allocator = std.mem.Allocator;
const IS_DEBUG = @import("builtin").mode == .Debug;
const WebSocket = @This();
@@ -45,7 +44,7 @@ pub const Proto = EventTarget;
_rc: lp.RC = .{},
_exec: *const Execution,
_proto: *EventTarget,
_arena: Allocator,
_arena: *lp.Arena,
// Connection state
_ready_state: ReadyState = .connecting,
@@ -74,7 +73,7 @@ _recv_buffer: std.ArrayList(u8) = .empty,
_events: std.ArrayList(RecvEvent) = .empty,
// data is dupe'd by the _batch_arena and re-used after every delivery
_batch_arena: ?Allocator = null,
_batch_arena: ?*lp.Arena = null,
_batch_bytes: usize = 0,
// Linked into the client's ws_dispatch_queue while events await delivery.
@@ -153,11 +152,11 @@ pub fn init(url: []const u8, protocols: [][]const u8, exec: *const Execution) !*
}
const arena = try exec.getArena(.medium, "WebSocket");
errdefer exec.releaseArena(arena);
errdefer arena.release();
const resolved_url = blk: {
// Always UTF-8, never the document's charse
const resolved = URL.resolve(arena, exec.base(), url, .{ .encoding = "UTF-8" }) catch |err| switch (err) {
const resolved = URL.resolve(arena.allocator(), exec.base(), url, .{ .encoding = "UTF-8" }) catch |err| switch (err) {
error.TypeError => return error.SyntaxError,
else => return err,
};
@@ -170,10 +169,10 @@ pub fn init(url: []const u8, protocols: [][]const u8, exec: *const Execution) !*
// yup, this is what we're supposed to do.
if (std.mem.eql(u8, scheme, "http:")) {
break :blk try std.fmt.allocPrintSentinel(arena, "ws{s}", .{resolved["http".len..]}, 0);
break :blk try std.fmt.allocPrintSentinel(arena.allocator(), "ws{s}", .{resolved["http".len..]}, 0);
}
if (std.mem.eql(u8, scheme, "https:")) {
break :blk try std.fmt.allocPrintSentinel(arena, "wss{s}", .{resolved["https".len..]}, 0);
break :blk try std.fmt.allocPrintSentinel(arena.allocator(), "wss{s}", .{resolved["https".len..]}, 0);
}
return error.SyntaxError;
@@ -181,7 +180,7 @@ pub fn init(url: []const u8, protocols: [][]const u8, exec: *const Execution) !*
const http_client = &exec.session.browser.http_client;
const self = try exec._factory.eventTargetWithAllocator(arena, WebSocket{
const self = try exec._factory.eventTargetWithAllocator(arena.allocator(), WebSocket{
._exec = exec,
._conn = null,
._arena = arena,
@@ -193,7 +192,7 @@ pub fn init(url: []const u8, protocols: [][]const u8, exec: *const Execution) !*
// This ensures that if we fail to connect, we have at least 1 event slot
// to register the close+error
try self._events.ensureTotalCapacity(arena, 1);
try self._events.ensureTotalCapacity(arena.allocator(), 1);
exec.httpOwner().addWS(self);
@@ -244,7 +243,7 @@ fn connect(self: *WebSocket, protocols: [][]const u8) !void {
errdefer headers.deinit();
if (protocols.len > 0) {
const header = try std.fmt.allocPrintSentinel(arena, "Sec-WebSocket-Protocol: {s}", .{try std.mem.join(arena, ", ", protocols)}, 0);
const header = try std.fmt.allocPrintSentinel(arena.allocator(), "Sec-WebSocket-Protocol: {s}", .{try std.mem.join(arena.allocator(), ", ", protocols)}, 0);
try headers.add(header);
}
@@ -254,13 +253,13 @@ fn connect(self: *WebSocket, protocols: [][]const u8) !void {
// protection on WS servers) reject upgrades that arrive without it.
// Non-tuple origins (about:blank, data:) serialize to "null", like
// Chrome sends for opaque origins.
const origin = (try URL.getOrigin(arena, exec.url.*)) orelse "null";
const header = try std.fmt.allocPrintSentinel(arena, "Origin: {s}", .{origin}, 0);
const origin = (try URL.getOrigin(arena.allocator(), exec.url.*)) orelse "null";
const header = try std.fmt.allocPrintSentinel(arena.allocator(), "Origin: {s}", .{origin}, 0);
try headers.add(header);
}
{
var buf: std.Io.Writer.Allocating = .init(arena);
var buf: std.Io.Writer.Allocating = .init(arena.allocator());
try exec.session.cookie_jar.forRequest(resolved_url, &buf.writer, .{
.is_http = true,
.is_navigation = false,
@@ -312,10 +311,10 @@ pub fn deinit(self: *WebSocket, page: *Page) void {
}
if (self._batch_arena) |arena| {
page.releaseArena(arena);
arena.release();
}
page.releaseArena(self._arena);
self._arena.release();
}
pub fn releaseRef(self: *WebSocket, page: *Page) void {
@@ -470,7 +469,7 @@ fn releaseTransport(self: *WebSocket) void {
// callback return value — never tear down from here, the pump may still be
// inside curl.
fn bufferEvent(self: *WebSocket, event: RecvEvent) !void {
try self._events.append(self._arena, event);
try self._events.append(self._arena.allocator(), event);
self.enqueueDispatch();
}
@@ -518,13 +517,13 @@ fn clearEvents(self: *WebSocket) void {
self._batch_bytes = 0;
if (self._batch_arena) |arena| {
self._batch_arena = null;
self._exec.releaseArena(arena);
arena.release();
}
}
fn queueMessage(self: *WebSocket, msg: Message) !void {
const was_empty = self._send_queue.items.len == 0;
try self._send_queue.append(self._arena, msg);
try self._send_queue.append(self._arena.allocator(), msg);
if (was_empty) {
// Unpause the send callback so libcurl will request data
@@ -587,7 +586,7 @@ pub fn send(self: *WebSocket, data: SendData) !void {
switch (data) {
.blob => |blob| {
const arena = try self._exec.getArena(blob._slice.len, "WebSocket.message");
errdefer self._exec.releaseArena(arena);
errdefer arena.release();
try self.queueMessage(.{ .binary = .{
.arena = arena,
.data = try arena.dupe(u8, blob._slice),
@@ -596,17 +595,17 @@ pub fn send(self: *WebSocket, data: SendData) !void {
.js_val => |js_val| {
if (js_val.isString()) |str| {
const arena = try self._exec.getArena(str.len(), "WebSocket.message");
errdefer self._exec.releaseArena(arena);
errdefer arena.release();
try self.queueMessage(.{ .text = .{
.arena = arena,
.data = try str.toSliceWithAlloc(arena),
.data = try str.toSliceWithAlloc(arena.allocator()),
} });
} else {
const binary = try js_val.toZig(BinaryData);
const buffer = binary.asBuffer();
const arena = try self._exec.getArena(buffer.len, "WebSocket.message");
errdefer self._exec.releaseArena(arena);
errdefer arena.release();
try self.queueMessage(.{ .binary = .{
.arena = arena,
.data = try arena.dupe(u8, buffer),
@@ -907,10 +906,10 @@ fn _receivedDataCallback(conn: *http.Connection, data: []const u8) !void {
if (meta.len > self._http_client.max_response_size) {
return error.MessageTooLarge;
}
try self._recv_buffer.ensureTotalCapacity(self._arena, meta.len);
try self._recv_buffer.ensureTotalCapacity(self._arena.allocator(), meta.len);
}
try self._recv_buffer.appendSlice(self._arena, data);
try self._recv_buffer.appendSlice(self._arena.allocator(), data);
if (meta.bytes_left > 0) {
// still more data waiting for this frame
@@ -1001,12 +1000,12 @@ const Message = union(enum) {
binary: Content,
const Content = struct {
arena: Allocator,
arena: *lp.Arena,
data: []const u8,
};
fn deinit(self: Message, page: *Page) void {
fn deinit(self: Message, _: *Page) void {
switch (self) {
.text, .binary => |msg| page.releaseArena(msg.arena),
.text, .binary => |msg| msg.arena.release(),
.close => {},
}
}
+12 -13
View File
@@ -39,7 +39,6 @@ const XMLHttpRequestUpload = @import("XMLHttpRequestUpload.zig");
const log = lp.log;
const Execution = js.Execution;
const Allocator = std.mem.Allocator;
const IS_DEBUG = @import("builtin").mode == .Debug;
const XMLHttpRequest = @This();
@@ -49,7 +48,7 @@ _rc: lp.RC = .{},
_exec: *const Execution,
_proto: *XMLHttpRequestEventTarget,
_upload: ?*XMLHttpRequestUpload = null,
_arena: Allocator,
_arena: *lp.Arena,
_http_transfer: ?*Transfer = null,
// number of inflight requests, we can have multiple, e.g. xhr calling its own
@@ -110,8 +109,8 @@ const ResponseType = enum {
pub fn init(exec: *const Execution) !*XMLHttpRequest {
const arena = try exec.getArena(.large, "XMLHttpRequest");
errdefer exec.releaseArena(arena);
const self = try exec._factory.xhrEventTarget(arena, XMLHttpRequest{
errdefer arena.release();
const self = try exec._factory.xhrEventTarget(arena.allocator(), XMLHttpRequest{
._exec = exec,
._arena = arena,
._proto = undefined,
@@ -120,7 +119,7 @@ pub fn init(exec: *const Execution) !*XMLHttpRequest {
return self;
}
pub fn deinit(self: *XMLHttpRequest, page: *Page) void {
pub fn deinit(self: *XMLHttpRequest, _: *Page) void {
if (self._http_transfer) |resp| {
resp.abort(error.Abort);
self._http_transfer = null;
@@ -134,7 +133,7 @@ pub fn deinit(self: *XMLHttpRequest, page: *Page) void {
if (self._upload) |upload| {
upload._proto.releaseListeners();
}
page.releaseArena(self._arena);
self._arena.release();
}
fn releaseSelfRef(self: *XMLHttpRequest) void {
@@ -212,7 +211,7 @@ pub fn open(self: *XMLHttpRequest, method_: []const u8, url: [:0]const u8) !void
const exec = self._exec;
self._method = try parseMethod(method_);
self._url = try URL.resolve(self._arena, exec.base(), url, .{ .encoding = exec.charset.* });
self._url = try URL.resolve(self._arena.allocator(), exec.base(), url, .{ .encoding = exec.charset.* });
try self.stateChanged(.opened, exec);
}
@@ -242,7 +241,7 @@ pub fn send(self: *XMLHttpRequest, body_: ?BodyInit, exec_: *const Execution) !v
if (body_) |b| {
if (self._method != .GET and self._method != .HEAD) {
const extracted = try b.extract(self._arena);
const extracted = try b.extract(self._arena.allocator());
self._request_body = extracted.bytes;
// Per XHR §4.7.6 "send()" step 4, the default Content-Type only
// applies if the author hasn't already set one via
@@ -322,7 +321,7 @@ pub fn getUpload(self: *XMLHttpRequest) !*XMLHttpRequestUpload {
return upload;
}
const upload = try self._exec._factory.xhrEventTarget(
self._arena,
self._arena.allocator(),
XMLHttpRequestUpload{ ._proto = undefined, ._xhr = self },
);
self._upload = upload;
@@ -529,14 +528,14 @@ fn httpHeaderDoneCallback(transfer: *Transfer) !Transfer.HeaderResult {
var it = transfer.responseHeaderIterator();
while (it.next()) |hdr| {
const joined = try std.fmt.allocPrint(self._arena, "{s}: {s}", .{ hdr.name, hdr.value });
try self._response_headers.append(self._arena, joined);
const joined = try std.fmt.allocPrint(self._arena.allocator(), "{s}: {s}", .{ hdr.name, hdr.value });
try self._response_headers.append(self._arena.allocator(), joined);
}
self._response_status = transfer.responseStatus().?;
if (transfer.getContentLength()) |cl| {
self._response_len = cl;
try self._response_data.ensureTotalCapacity(self._arena, cl);
try self._response_data.ensureTotalCapacity(self._arena.allocator(), cl);
}
self._response_url = try self._arena.dupeZ(u8, transfer.req.url);
@@ -555,7 +554,7 @@ fn httpHeaderDoneCallback(transfer: *Transfer) !Transfer.HeaderResult {
fn httpDataCallback(transfer: *Transfer, data: []const u8) !void {
const self: *XMLHttpRequest = @ptrCast(@alignCast(transfer.req.ctx));
try self._response_data.appendSlice(self._arena, data);
try self._response_data.appendSlice(self._arena.allocator(), data);
try self._proto.dispatch(.progress, .{
.total = self._response_len orelse 0,
+7 -5
View File
@@ -144,28 +144,30 @@ test "BodyInit: bytes pass through with text/plain" {
test "BodyInit: URLSearchParams emit urlencoded body + content-type" {
defer testing.reset();
const arena = testing.arena_allocator;
const arena = try testing.test_app.arena_pool.acquire(.small, "body_init test");
defer arena.release();
const usp = try arena.create(URLSearchParams);
usp.* = .{ ._arena = arena, ._params = .empty };
try usp.append("a", "1");
try usp.append("b", "2");
const r = try (BodyInit{ .url_search_params = usp }).extract(arena);
const r = try (BodyInit{ .url_search_params = usp }).extract(arena.allocator());
try testing.expectString("a=1&b=2", r.bytes);
try testing.expectString("application/x-www-form-urlencoded;charset=UTF-8", r.content_type.?);
}
test "BodyInit: FormData emits multipart with random boundary" {
defer testing.reset();
const arena = testing.arena_allocator;
const arena = try testing.test_app.arena_pool.acquire(.small, "body_init test");
defer arena.release();
const fd = try arena.create(FormData);
fd.* = .{ ._rc = .{}, ._arena = arena, ._entries = .empty };
try fd.appendText("username", "alice");
try fd.appendText("email", "alice@example.com");
const r = try (BodyInit{ .form_data = fd }).extract(arena);
const r = try (BodyInit{ .form_data = fd }).extract(arena.allocator());
// Body must contain the entries' Content-Disposition lines and end with
// the closing boundary marker.
@@ -177,7 +179,7 @@ test "BodyInit: FormData emits multipart with random boundary" {
try testing.expect(std.mem.indexOf(u8, r.bytes, "Content-Disposition: form-data; name=\"email\"") != null);
try testing.expect(std.mem.indexOf(u8, r.bytes, "alice") != null);
try testing.expect(std.mem.indexOf(u8, r.bytes, "alice@example.com") != null);
const closer = try std.fmt.allocPrint(arena, "--{s}--\r\n", .{boundary});
const closer = try std.fmt.allocPrint(arena.allocator(), "--{s}--\r\n", .{boundary});
try testing.expect(std.mem.endsWith(u8, r.bytes, closer));
}
+4 -5
View File
@@ -17,6 +17,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
const std = @import("std");
const lp = @import("lightpanda");
const Page = @import("../../Page.zig");
const Frame = @import("../../Frame.zig");
@@ -27,12 +28,10 @@ const Selector = @import("Selector.zig");
const TreeWalker = @import("../TreeWalker.zig").Full;
const GenericIterator = @import("../collections/iterator.zig").Entry;
const Allocator = std.mem.Allocator;
const List = @This();
_nodes: []const *Node,
_arena: Allocator,
_arena: *lp.Arena,
// For the [somewhat common] case where we just have an #id selector
// we can avoid allocating a slice and just use this.
_single_node: [1]*Node = undefined,
@@ -41,8 +40,8 @@ pub const EntryIterator = GenericIterator(Iterator, null);
pub const KeyIterator = GenericIterator(Iterator, "0");
pub const ValueIterator = GenericIterator(Iterator, "1");
pub fn deinit(self: *const List, page: *Page) void {
page.releaseArena(self._arena);
pub fn deinit(self: *const List, _: *Page) void {
self._arena.release();
}
pub fn collect(
+5 -5
View File
@@ -113,10 +113,10 @@ pub const Cache = struct {
}
};
fn collectAll(arena: Allocator, selectors: []const Selector, root: *Node, frame: *Frame) !*List {
fn collectAll(arena: *lp.Arena, selectors: []const Selector, root: *Node, frame: *Frame) !*List {
var nodes: std.AutoArrayHashMapUnmanaged(*Node, void) = .empty;
for (selectors) |selector| {
try List.collect(arena, root, selector, &nodes, frame);
try List.collect(arena.allocator(), root, selector, &nodes, frame);
}
const list = try arena.create(List);
@@ -142,7 +142,7 @@ pub fn querySelector(root: *Node, input: []const u8, frame: *Frame) !?*Node.Elem
pub fn querySelectorAll(root: *Node, input: []const u8, frame: *Frame) !*List {
const arena = try frame.getArena(.small, "querySelectorAll");
errdefer frame.releaseArena(arena);
errdefer arena.release();
return collectAll(arena, try cachedParse(frame._session.browser, input), root, frame);
}
@@ -171,8 +171,8 @@ pub fn querySelectorAllUncached(root: *Node, input: []const u8, frame: *Frame) !
return error.SyntaxError;
}
const arena = try frame.getArena(.small, "querySelectorAllUncached");
errdefer frame.releaseArena(arena);
return collectAll(arena, try Parser.parseList(arena, input), root, frame);
errdefer arena.release();
return collectAll(arena, try Parser.parseList(arena.allocator(), input), root, frame);
}
pub fn matchesUncached(arena: Allocator, el: *Node.Element, input: []const u8, frame: *Frame) !bool {
Loaded 100 of 123 files, more files were not shown because too many files have changed in this diff. Show more