mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-02-04 14:33:47 +00:00
Merge pull request #1426 from lightpanda-io/update_page_js
Some checks failed
e2e-test / zig build release (push) Has been cancelled
e2e-test / demo-scripts (push) Has been cancelled
e2e-test / cdp-and-hyperfine-bench (push) Has been cancelled
e2e-test / perf-fmt (push) Has been cancelled
e2e-test / browser fetch (push) Has been cancelled
zig-test / zig test (push) Has been cancelled
zig-test / perf-fmt (push) Has been cancelled
Some checks failed
e2e-test / zig build release (push) Has been cancelled
e2e-test / demo-scripts (push) Has been cancelled
e2e-test / cdp-and-hyperfine-bench (push) Has been cancelled
e2e-test / perf-fmt (push) Has been cancelled
e2e-test / browser fetch (push) Has been cancelled
zig-test / zig test (push) Has been cancelled
zig-test / perf-fmt (push) Has been cancelled
Update page.js based on the current context.
This commit is contained in:
@@ -112,6 +112,10 @@ pub fn runMicrotasks(self: *const Browser) void {
|
|||||||
self.env.runMicrotasks();
|
self.env.runMicrotasks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn runMacrotasks(self: *Browser) !?u64 {
|
||||||
|
return try self.env.runMacrotasks();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn runMessageLoop(self: *const Browser) void {
|
pub fn runMessageLoop(self: *const Browser) void {
|
||||||
while (self.env.pumpMessageLoop()) {
|
while (self.env.pumpMessageLoop()) {
|
||||||
if (comptime IS_DEBUG) {
|
if (comptime IS_DEBUG) {
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ const String = @import("../string.zig").String;
|
|||||||
const Mime = @import("Mime.zig");
|
const Mime = @import("Mime.zig");
|
||||||
const Factory = @import("Factory.zig");
|
const Factory = @import("Factory.zig");
|
||||||
const Session = @import("Session.zig");
|
const Session = @import("Session.zig");
|
||||||
const Scheduler = @import("Scheduler.zig");
|
|
||||||
const EventManager = @import("EventManager.zig");
|
const EventManager = @import("EventManager.zig");
|
||||||
const ScriptManager = @import("ScriptManager.zig");
|
const ScriptManager = @import("ScriptManager.zig");
|
||||||
|
|
||||||
@@ -202,8 +201,6 @@ document: *Document,
|
|||||||
// DOM version used to invalidate cached state of "live" collections
|
// DOM version used to invalidate cached state of "live" collections
|
||||||
version: usize,
|
version: usize,
|
||||||
|
|
||||||
scheduler: Scheduler,
|
|
||||||
|
|
||||||
_req_id: ?usize = null,
|
_req_id: ?usize = null,
|
||||||
_navigated_options: ?NavigatedOpts = null,
|
_navigated_options: ?NavigatedOpts = null,
|
||||||
|
|
||||||
@@ -237,10 +234,6 @@ pub fn deinit(self: *Page) void {
|
|||||||
// stats.print(&stream) catch unreachable;
|
// stats.print(&stream) catch unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This can release JS objects, so we need to do this while the js.Context
|
|
||||||
// is still around.
|
|
||||||
self.scheduler.deinit();
|
|
||||||
|
|
||||||
{
|
{
|
||||||
// some MicroTasks might be referencing the page, we need to drain it while
|
// some MicroTasks might be referencing the page, we need to drain it while
|
||||||
// the page still exists
|
// the page still exists
|
||||||
@@ -271,8 +264,6 @@ fn reset(self: *Page, comptime initializing: bool) !void {
|
|||||||
const browser = self._session.browser;
|
const browser = self._session.browser;
|
||||||
|
|
||||||
if (comptime initializing == false) {
|
if (comptime initializing == false) {
|
||||||
self.scheduler.deinit();
|
|
||||||
|
|
||||||
browser.env.destroyContext(self.js);
|
browser.env.destroyContext(self.js);
|
||||||
|
|
||||||
// We force a garbage collection between page navigations to keep v8
|
// We force a garbage collection between page navigations to keep v8
|
||||||
@@ -299,7 +290,6 @@ fn reset(self: *Page, comptime initializing: bool) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self._factory = Factory.init(self);
|
self._factory = Factory.init(self);
|
||||||
self.scheduler = Scheduler.init(self.arena);
|
|
||||||
|
|
||||||
self.version = 0;
|
self.version = 0;
|
||||||
self.url = "about:blank";
|
self.url = "about:blank";
|
||||||
@@ -381,7 +371,7 @@ fn registerBackgroundTasks(self: *Page) !void {
|
|||||||
|
|
||||||
const Browser = @import("Browser.zig");
|
const Browser = @import("Browser.zig");
|
||||||
|
|
||||||
try self.scheduler.add(self._session.browser, struct {
|
try self.js.scheduler.add(self._session.browser, struct {
|
||||||
fn runMessageLoop(ctx: *anyopaque) !?u32 {
|
fn runMessageLoop(ctx: *anyopaque) !?u32 {
|
||||||
const b: *Browser = @ptrCast(@alignCast(ctx));
|
const b: *Browser = @ptrCast(@alignCast(ctx));
|
||||||
b.runMessageLoop();
|
b.runMessageLoop();
|
||||||
@@ -887,8 +877,8 @@ fn _wait(self: *Page, wait_ms: u32) !Session.WaitResult {
|
|||||||
var timer = try std.time.Timer.start();
|
var timer = try std.time.Timer.start();
|
||||||
var ms_remaining = wait_ms;
|
var ms_remaining = wait_ms;
|
||||||
|
|
||||||
var scheduler = &self.scheduler;
|
const browser = self._session.browser;
|
||||||
var http_client = self._session.browser.http_client;
|
var http_client = browser.http_client;
|
||||||
|
|
||||||
// I'd like the page to know NOTHING about cdp_socket / CDP, but the
|
// I'd like the page to know NOTHING about cdp_socket / CDP, but the
|
||||||
// fact is that the behavior of wait changes depending on whether or
|
// fact is that the behavior of wait changes depending on whether or
|
||||||
@@ -941,7 +931,7 @@ fn _wait(self: *Page, wait_ms: u32) !Session.WaitResult {
|
|||||||
// scheduler.run could trigger new http transfers, so do not
|
// scheduler.run could trigger new http transfers, so do not
|
||||||
// store http_client.active BEFORE this call and then use
|
// store http_client.active BEFORE this call and then use
|
||||||
// it AFTER.
|
// it AFTER.
|
||||||
const ms_to_next_task = try scheduler.run();
|
const ms_to_next_task = try browser.runMacrotasks();
|
||||||
|
|
||||||
const http_active = http_client.active;
|
const http_active = http_client.active;
|
||||||
const total_network_activity = http_active + http_client.intercepted;
|
const total_network_activity = http_active + http_client.intercepted;
|
||||||
@@ -1077,16 +1067,16 @@ fn printWaitAnalysis(self: *Page) void {
|
|||||||
|
|
||||||
const now = milliTimestamp(.monotonic);
|
const now = milliTimestamp(.monotonic);
|
||||||
{
|
{
|
||||||
std.debug.print("\nhigh_priority schedule: {d}\n", .{self.scheduler.high_priority.count()});
|
std.debug.print("\nhigh_priority schedule: {d}\n", .{self.js.scheduler.high_priority.count()});
|
||||||
var it = self.scheduler.high_priority.iterator();
|
var it = self.js.scheduler.high_priority.iterator();
|
||||||
while (it.next()) |task| {
|
while (it.next()) |task| {
|
||||||
std.debug.print(" - {s} schedule: {d}ms\n", .{ task.name, task.run_at - now });
|
std.debug.print(" - {s} schedule: {d}ms\n", .{ task.name, task.run_at - now });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
std.debug.print("\nlow_priority schedule: {d}\n", .{self.scheduler.low_priority.count()});
|
std.debug.print("\nlow_priority schedule: {d}\n", .{self.js.scheduler.low_priority.count()});
|
||||||
var it = self.scheduler.low_priority.iterator();
|
var it = self.js.scheduler.low_priority.iterator();
|
||||||
while (it.next()) |task| {
|
while (it.next()) |task| {
|
||||||
std.debug.print(" - {s} schedule: {d}ms\n", .{ task.name, task.run_at - now });
|
std.debug.print(" - {s} schedule: {d}ms\n", .{ task.name, task.run_at - now });
|
||||||
}
|
}
|
||||||
@@ -1258,7 +1248,7 @@ pub fn notifyPerformanceObservers(self: *Page, entry: *Performance.Entry) !void
|
|||||||
}
|
}
|
||||||
self._performance_delivery_scheduled = true;
|
self._performance_delivery_scheduled = true;
|
||||||
|
|
||||||
return self.scheduler.add(
|
return self.js.scheduler.add(
|
||||||
self,
|
self,
|
||||||
struct {
|
struct {
|
||||||
fn run(_page: *anyopaque) anyerror!?u32 {
|
fn run(_page: *anyopaque) anyerror!?u32 {
|
||||||
|
|||||||
@@ -846,7 +846,7 @@ pub const Script = struct {
|
|||||||
defer {
|
defer {
|
||||||
// We should run microtasks even if script execution fails.
|
// We should run microtasks even if script execution fails.
|
||||||
local.runMicrotasks();
|
local.runMicrotasks();
|
||||||
_ = page.scheduler.run() catch |err| {
|
_ = page.js.scheduler.run() catch |err| {
|
||||||
log.err(.page, "scheduler", .{ .err = err });
|
log.err(.page, "scheduler", .{ .err = err });
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ const IS_DEBUG = @import("builtin").mode == .Debug;
|
|||||||
const Caller = @This();
|
const Caller = @This();
|
||||||
local: js.Local,
|
local: js.Local,
|
||||||
prev_local: ?*const js.Local,
|
prev_local: ?*const js.Local,
|
||||||
|
prev_context: *Context,
|
||||||
|
|
||||||
// Takes the raw v8 isolate and extracts the context from it.
|
// Takes the raw v8 isolate and extracts the context from it.
|
||||||
pub fn init(self: *Caller, v8_isolate: *v8.Isolate) void {
|
pub fn init(self: *Caller, v8_isolate: *v8.Isolate) void {
|
||||||
@@ -53,7 +54,9 @@ pub fn init(self: *Caller, v8_isolate: *v8.Isolate) void {
|
|||||||
.isolate = .{ .handle = v8_isolate },
|
.isolate = .{ .handle = v8_isolate },
|
||||||
},
|
},
|
||||||
.prev_local = ctx.local,
|
.prev_local = ctx.local,
|
||||||
|
.prev_context = ctx.page.js,
|
||||||
};
|
};
|
||||||
|
ctx.page.js = ctx;
|
||||||
ctx.local = &self.local;
|
ctx.local = &self.local;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,6 +82,7 @@ pub fn deinit(self: *Caller) void {
|
|||||||
|
|
||||||
ctx.call_depth = call_depth;
|
ctx.call_depth = call_depth;
|
||||||
ctx.local = self.prev_local;
|
ctx.local = self.prev_local;
|
||||||
|
ctx.page.js = self.prev_context;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const CallOpts = struct {
|
pub const CallOpts = struct {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ const log = @import("../../log.zig");
|
|||||||
const js = @import("js.zig");
|
const js = @import("js.zig");
|
||||||
const Env = @import("Env.zig");
|
const Env = @import("Env.zig");
|
||||||
const bridge = @import("bridge.zig");
|
const bridge = @import("bridge.zig");
|
||||||
|
const Scheduler = @import("Scheduler.zig");
|
||||||
|
|
||||||
const Page = @import("../Page.zig");
|
const Page = @import("../Page.zig");
|
||||||
const ScriptManager = @import("../ScriptManager.zig");
|
const ScriptManager = @import("../ScriptManager.zig");
|
||||||
@@ -118,6 +119,9 @@ module_identifier: std.AutoHashMapUnmanaged(u32, [:0]const u8) = .empty,
|
|||||||
// the page's script manager
|
// the page's script manager
|
||||||
script_manager: ?*ScriptManager,
|
script_manager: ?*ScriptManager,
|
||||||
|
|
||||||
|
// Our macrotasks
|
||||||
|
scheduler: Scheduler,
|
||||||
|
|
||||||
const ModuleEntry = struct {
|
const ModuleEntry = struct {
|
||||||
// Can be null if we're asynchrously loading the module, in
|
// Can be null if we're asynchrously loading the module, in
|
||||||
// which case resolver_promise cannot be null.
|
// which case resolver_promise cannot be null.
|
||||||
@@ -150,6 +154,14 @@ pub fn fromIsolate(isolate: js.Isolate) *Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Context) void {
|
pub fn deinit(self: *Context) void {
|
||||||
|
var page = self.page;
|
||||||
|
const prev_context = page.js;
|
||||||
|
page.js = self;
|
||||||
|
defer page.js = prev_context;
|
||||||
|
|
||||||
|
// This can release JS objects
|
||||||
|
self.scheduler.deinit();
|
||||||
|
|
||||||
{
|
{
|
||||||
var it = self.identity_map.valueIterator();
|
var it = self.identity_map.valueIterator();
|
||||||
while (it.next()) |global| {
|
while (it.next()) |global| {
|
||||||
|
|||||||
@@ -240,6 +240,7 @@ pub fn createContext(self: *Env, page: *Page, enter: bool) !*Context {
|
|||||||
.templates = self.templates,
|
.templates = self.templates,
|
||||||
.call_arena = page.call_arena,
|
.call_arena = page.call_arena,
|
||||||
.script_manager = &page._script_manager,
|
.script_manager = &page._script_manager,
|
||||||
|
.scheduler = .init(context_arena),
|
||||||
};
|
};
|
||||||
try context.identity_map.putNoClobber(context_arena, @intFromPtr(page.window), global_global);
|
try context.identity_map.putNoClobber(context_arena, @intFromPtr(page.window), global_global);
|
||||||
|
|
||||||
@@ -271,6 +272,17 @@ pub fn runMicrotasks(self: *const Env) void {
|
|||||||
self.isolate.performMicrotasksCheckpoint();
|
self.isolate.performMicrotasksCheckpoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn runMacrotasks(self: *Env) !?u64 {
|
||||||
|
var ms_to_next_task: ?u64 = null;
|
||||||
|
for (self.contexts.items) |ctx| {
|
||||||
|
const ms = (try ctx.scheduler.run()) orelse continue;
|
||||||
|
if (ms_to_next_task == null or ms < ms_to_next_task.?) {
|
||||||
|
ms_to_next_task = ms;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ms_to_next_task;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn pumpMessageLoop(self: *const Env) bool {
|
pub fn pumpMessageLoop(self: *const Env) bool {
|
||||||
var hs: v8.HandleScope = undefined;
|
var hs: v8.HandleScope = undefined;
|
||||||
v8.v8__HandleScope__CONSTRUCT(&hs, self.isolate.handle);
|
v8.v8__HandleScope__CONSTRUCT(&hs, self.isolate.handle);
|
||||||
|
|||||||
@@ -19,8 +19,8 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
const log = @import("../log.zig");
|
const log = @import("../../log.zig");
|
||||||
const milliTimestamp = @import("../datetime.zig").milliTimestamp;
|
const milliTimestamp = @import("../../datetime.zig").milliTimestamp;
|
||||||
|
|
||||||
const IS_DEBUG = builtin.mode == .Debug;
|
const IS_DEBUG = builtin.mode == .Debug;
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ pub fn createTimeout(delay: u32, page: *Page) !*AbortSignal {
|
|||||||
.signal = try init(page),
|
.signal = try init(page),
|
||||||
};
|
};
|
||||||
|
|
||||||
try page.scheduler.add(callback, TimeoutCallback.run, delay, .{
|
try page.js.scheduler.add(callback, TimeoutCallback.run, delay, .{
|
||||||
.name = "AbortSignal.timeout",
|
.name = "AbortSignal.timeout",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ pub fn postMessage(self: *MessagePort, message: js.Value.Global, page: *Page) !v
|
|||||||
.message = message,
|
.message = message,
|
||||||
});
|
});
|
||||||
|
|
||||||
try page.scheduler.add(callback, PostMessageCallback.run, 0, .{
|
try page.js.scheduler.add(callback, PostMessageCallback.run, 0, .{
|
||||||
.name = "MessagePort.postMessage",
|
.name = "MessagePort.postMessage",
|
||||||
.low_priority = false,
|
.low_priority = false,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -366,7 +366,7 @@ pub fn postMessage(self: *Window, message: js.Value.Global, target_origin: ?[]co
|
|||||||
.message = message,
|
.message = message,
|
||||||
.origin = try arena.dupe(u8, origin),
|
.origin = try arena.dupe(u8, origin),
|
||||||
};
|
};
|
||||||
try page.scheduler.add(callback, PostMessageCallback.run, 0, .{
|
try page.js.scheduler.add(callback, PostMessageCallback.run, 0, .{
|
||||||
.name = "postMessage",
|
.name = "postMessage",
|
||||||
.low_priority = false,
|
.low_priority = false,
|
||||||
.finalizer = PostMessageCallback.cancelled,
|
.finalizer = PostMessageCallback.cancelled,
|
||||||
@@ -447,7 +447,7 @@ pub fn scrollTo(self: *Window, opts: ScrollToOpts, y: ?i32, page: *Page) !void {
|
|||||||
|
|
||||||
// We dispatch scroll event asynchronously after 10ms. So we can throttle
|
// We dispatch scroll event asynchronously after 10ms. So we can throttle
|
||||||
// them.
|
// them.
|
||||||
try page.scheduler.add(
|
try page.js.scheduler.add(
|
||||||
page,
|
page,
|
||||||
struct {
|
struct {
|
||||||
fn dispatch(_page: *anyopaque) anyerror!?u32 {
|
fn dispatch(_page: *anyopaque) anyerror!?u32 {
|
||||||
@@ -471,7 +471,7 @@ pub fn scrollTo(self: *Window, opts: ScrollToOpts, y: ?i32, page: *Page) !void {
|
|||||||
.{ .low_priority = true },
|
.{ .low_priority = true },
|
||||||
);
|
);
|
||||||
// We dispatch scrollend event asynchronously after 20ms.
|
// We dispatch scrollend event asynchronously after 20ms.
|
||||||
try page.scheduler.add(
|
try page.js.scheduler.add(
|
||||||
page,
|
page,
|
||||||
struct {
|
struct {
|
||||||
fn dispatch(_page: *anyopaque) anyerror!?u32 {
|
fn dispatch(_page: *anyopaque) anyerror!?u32 {
|
||||||
@@ -545,7 +545,7 @@ fn scheduleCallback(self: *Window, cb: js.Function.Temp, delay_ms: u32, opts: Sc
|
|||||||
};
|
};
|
||||||
gop.value_ptr.* = callback;
|
gop.value_ptr.* = callback;
|
||||||
|
|
||||||
try page.scheduler.add(callback, ScheduleCallback.run, delay_ms, .{
|
try page.js.scheduler.add(callback, ScheduleCallback.run, delay_ms, .{
|
||||||
.name = opts.name,
|
.name = opts.name,
|
||||||
.low_priority = opts.low_priority,
|
.low_priority = opts.low_priority,
|
||||||
.finalizer = ScheduleCallback.cancelled,
|
.finalizer = ScheduleCallback.cancelled,
|
||||||
|
|||||||
Reference in New Issue
Block a user