Skip to content

Commit 8c37d56

Browse files
committed
isolated polyfill + create when needed
1 parent a4f7393 commit 8c37d56

File tree

6 files changed

+70
-22
lines changed

6 files changed

+70
-22
lines changed

src/browser/browser.zig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,11 +163,16 @@ pub const Session = struct {
163163

164164
// start JS env
165165
log.debug("start new js scope", .{});
166+
// Inform CDP the main page has been created such that additional context for other Worlds can be created as well
167+
self.browser.notification.dispatch(.page_created, page);
166168

167169
return page;
168170
}
169171

170172
pub fn removePage(self: *Session) void {
173+
// Inform CDP the page is going to be removed, allowing other worlds to remove themselves before the main one
174+
self.browser.notification.dispatch(.page_remove, .{});
175+
171176
std.debug.assert(self.page != null);
172177
// Reset all existing callbacks.
173178
self.browser.app.loop.resetJS();

src/cdp/cdp.zig

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,8 @@ pub fn BrowserContext(comptime CDP_T: type) type {
340340
self.node_search_list = Node.Search.List.init(allocator, &self.node_registry);
341341
errdefer self.deinit();
342342

343+
try cdp.browser.notification.register(.page_remove, self, onPageRemove);
344+
try cdp.browser.notification.register(.page_created, self, onPageCreated);
343345
try cdp.browser.notification.register(.page_navigate, self, onPageNavigate);
344346
try cdp.browser.notification.register(.page_navigated, self, onPageNavigated);
345347
}
@@ -365,7 +367,7 @@ pub fn BrowserContext(comptime CDP_T: type) type {
365367
self.node_search_list.reset();
366368
}
367369

368-
pub fn createIsolatedWorld(self: *Self, page: *Page) !void {
370+
pub fn createIsolatedWorld(self: *Self, page: *Page, world_name: []const u8, grant_universal_access: bool) !*IsolatedWorld {
369371
if (self.isolated_world != null) {
370372
return error.CurrentlyOnly1IsolatedWorldSupported;
371373
}
@@ -374,19 +376,14 @@ pub fn BrowserContext(comptime CDP_T: type) type {
374376
errdefer executor.deinit();
375377

376378
self.isolated_world = .{
377-
.name = "",
379+
.name = try self.arena.dupe(u8, world_name),
378380
.scope = undefined,
379381
.executor = executor,
380-
.grant_universal_access = true,
382+
.grant_universal_access = grant_universal_access,
381383
};
382-
var world = &self.isolated_world.?;
383-
384-
// The isolate world must share at least some of the state with the related page, specifically the DocumentHTML
385-
// (assuming grantUniveralAccess will be set to True!).
386-
// We just created the world and the page. The page's state lives in the session, but is update on navigation.
387-
// This also means this pointer becomes invalid after removePage untill a new page is created.
388-
// Currently we have only 1 page/frame and thus also only 1 state in the isolate world.
389-
world.scope = try world.executor.startScope(&page.window, &page.state, {}, false);
384+
const world = &self.isolated_world.?;
385+
try world.createContext(page);
386+
return world;
390387
}
391388

392389
pub fn nodeWriter(self: *Self, node: *const Node, opts: Node.Writer.Opts) Node.Writer {
@@ -403,6 +400,16 @@ pub fn BrowserContext(comptime CDP_T: type) type {
403400
return if (raw_url.len == 0) null else raw_url;
404401
}
405402

403+
pub fn onPageRemove(ctx: *anyopaque, _: Notification.PageRemove) !void {
404+
const self: *Self = @alignCast(@ptrCast(ctx));
405+
return @import("domains/page.zig").pageRemove(self);
406+
}
407+
408+
pub fn onPageCreated(ctx: *anyopaque, page: *Page) !void {
409+
const self: *Self = @alignCast(@ptrCast(ctx));
410+
return @import("domains/page.zig").pageCreated(self, page);
411+
}
412+
406413
pub fn onPageNavigate(ctx: *anyopaque, data: *const Notification.PageNavigate) !void {
407414
const self: *Self = @alignCast(@ptrCast(ctx));
408415
return @import("domains/page.zig").pageNavigate(self, data);
@@ -506,12 +513,26 @@ pub fn BrowserContext(comptime CDP_T: type) type {
506513
/// An object id is unique across all contexts, different object ids can refer to the same Node in different contexts.
507514
const IsolatedWorld = struct {
508515
name: []const u8,
509-
scope: *Env.Scope,
516+
scope: ?*Env.Scope,
510517
executor: Env.Executor,
511518
grant_universal_access: bool,
512519

513520
pub fn deinit(self: *IsolatedWorld) void {
514521
self.executor.deinit();
522+
self.scope = null;
523+
}
524+
pub fn removeContext(self: *IsolatedWorld) void {
525+
self.executor.endScope();
526+
self.scope = null;
527+
}
528+
529+
// The isolate world must share at least some of the state with the related page, specifically the DocumentHTML
530+
// (assuming grantUniveralAccess will be set to True!).
531+
// We just created the world and the page. The page's state lives in the session, but is update on navigation.
532+
// This also means this pointer becomes invalid after removePage untill a new page is created.
533+
// Currently we have only 1 page/frame and thus also only 1 state in the isolate world.
534+
pub fn createContext(self: *IsolatedWorld, page: *Page) !void {
535+
self.scope = try self.executor.startScope(&page.window, &page.state, {}, false);
515536
}
516537
};
517538

src/cdp/domains/dom.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ fn resolveNode(cmd: anytype) !void {
135135
if (params.executionContextId) |context_id| {
136136
if (scope.context.debugContextId() != context_id) {
137137
const isolated_world = bc.isolated_world orelse return error.ContextNotFound;
138-
scope = isolated_world.scope;
138+
scope = isolated_world.scope orelse return error.ContextNotFound;
139139

140140
if (scope.context.debugContextId() != context_id) return error.ContextNotFound;
141141
}

src/cdp/domains/page.zig

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const std = @import("std");
2020
const runtime = @import("runtime.zig");
2121
const URL = @import("../../url.zig").URL;
2222
const Notification = @import("../../notification.zig").Notification;
23+
const Page = @import("../../browser/browser.zig").Page;
2324

2425
pub fn processMessage(cmd: anytype) !void {
2526
const action = std.meta.stringToEnum(enum {
@@ -112,15 +113,16 @@ fn createIsolatedWorld(cmd: anytype) !void {
112113
}
113114
const bc = cmd.browser_context orelse return error.BrowserContextNotLoaded;
114115

115-
const world = &bc.isolated_world.?;
116-
world.name = try bc.arena.dupe(u8, params.worldName);
117-
world.grant_universal_access = params.grantUniveralAccess;
116+
const page = bc.session.currentPage().?;
117+
const world = try bc.createIsolatedWorld(page, params.worldName, params.grantUniveralAccess);
118+
const scope = world.scope.?;
119+
118120
// Create the auxdata json for the contextCreated event
119121
// Calling contextCreated will assign a Id to the context and send the contextCreated event
120122
const aux_data = try std.fmt.allocPrint(cmd.arena, "{{\"isDefault\":false,\"type\":\"isolated\",\"frameId\":\"{s}\"}}", .{params.frameId});
121-
bc.inspector.contextCreated(world.scope, world.name, "", aux_data, false);
123+
bc.inspector.contextCreated(scope, world.name, "", aux_data, false);
122124

123-
return cmd.sendResult(.{ .executionContextId = world.scope.context.debugContextId() }, .{});
125+
return cmd.sendResult(.{ .executionContextId = scope.context.debugContextId() }, .{});
124126
}
125127

126128
fn navigate(cmd: anytype) !void {
@@ -230,12 +232,11 @@ pub fn pageNavigate(bc: anytype, event: *const Notification.PageNavigate) !void
230232
true,
231233
);
232234
}
233-
234235
if (bc.isolated_world) |*isolated_world| {
235236
const aux_json = try std.fmt.bufPrint(&buffer, "{{\"isDefault\":false,\"type\":\"isolated\",\"frameId\":\"{s}\"}}", .{target_id});
236237
// Calling contextCreated will assign a new Id to the context and send the contextCreated event
237238
bc.inspector.contextCreated(
238-
isolated_world.scope,
239+
isolated_world.scope.?,
239240
isolated_world.name,
240241
"://",
241242
aux_json,
@@ -244,6 +245,23 @@ pub fn pageNavigate(bc: anytype, event: *const Notification.PageNavigate) !void
244245
}
245246
}
246247

248+
pub fn pageRemove(bc: anytype) !void {
249+
// The main page is going to be removed, we need to remove contexts from other worlds first.
250+
if (bc.isolated_world) |*isolated_world| {
251+
isolated_world.removeContext();
252+
}
253+
}
254+
255+
pub fn pageCreated(bc: anytype, page: *Page) !void {
256+
if (bc.isolated_world) |*isolated_world| {
257+
// We need to recreate the isolated world context
258+
try isolated_world.createContext(page);
259+
260+
const polyfill = @import("../../browser/polyfill/polyfill.zig");
261+
try polyfill.load(bc.arena, isolated_world.scope.?);
262+
}
263+
}
264+
247265
pub fn pageNavigated(bc: anytype, event: *const Notification.PageNavigated) !void {
248266
// I don't think it's possible that we get these notifications and don't
249267
// have these things setup.

src/cdp/domains/target.zig

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,6 @@ fn createTarget(cmd: anytype) !void {
125125
bc.target_id = target_id;
126126

127127
var page = try bc.session.createPage();
128-
try bc.createIsolatedWorld(page);
129-
130128
{
131129
const aux_data = try std.fmt.allocPrint(cmd.arena, "{{\"isDefault\":true,\"type\":\"default\",\"frameId\":\"{s}\"}}", .{target_id});
132130
bc.inspector.contextCreated(

src/notification.zig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,18 +55,24 @@ pub const Notification = struct {
5555
node_pool: std.heap.MemoryPool(Node),
5656

5757
const EventListeners = struct {
58+
page_remove: List = .{},
59+
page_created: List = .{},
5860
page_navigate: List = .{},
5961
page_navigated: List = .{},
6062
notification_created: List = .{},
6163
};
6264

6365
const Events = union(enum) {
66+
page_remove: PageRemove,
67+
page_created: *browser.Page,
6468
page_navigate: *const PageNavigate,
6569
page_navigated: *const PageNavigated,
6670
notification_created: *Notification,
6771
};
6872
const EventType = std.meta.FieldEnum(Events);
6973

74+
pub const PageRemove = struct {};
75+
7076
pub const PageNavigate = struct {
7177
timestamp: u32,
7278
url: *const URL,

0 commit comments

Comments
 (0)