// Copyright (C) 2023-2025 Lightpanda (Selecy SAS) // // Francis Bouvier // Pierre Tachoire // // 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 . const std = @import("std"); const Allocator = std.mem.Allocator; const ArenaAllocator = std.heap.ArenaAllocator; const js = @import("js/js.zig"); const log = @import("../log.zig"); const App = @import("../App.zig"); const HttpClient = @import("HttpClient.zig"); const ArenaPool = App.ArenaPool; const IS_DEBUG = @import("builtin").mode == .Debug; const Session = @import("Session.zig"); const Notification = @import("../Notification.zig"); // Browser is an instance of the browser. // You can create multiple browser instances. // A browser contains only one session. const Browser = @This(); env: js.Env, app: *App, session: ?Session, allocator: Allocator, arena_pool: *ArenaPool, http_client: *HttpClient, const InitOpts = struct { env: js.Env.InitOpts = .{}, http_client: *HttpClient, }; pub fn init(app: *App, opts: InitOpts) !Browser { const allocator = app.allocator; var env = try js.Env.init(app, opts.env); errdefer env.deinit(); return .{ .app = app, .env = env, .session = null, .allocator = allocator, .arena_pool = &app.arena_pool, .http_client = opts.http_client, }; } pub fn deinit(self: *Browser) void { self.closeSession(); self.env.deinit(); } pub fn newSession(self: *Browser, notification: *Notification) !*Session { self.closeSession(); self.session = @as(Session, undefined); const session = &self.session.?; try Session.init(session, self, notification); return session; } pub fn closeSession(self: *Browser) void { if (self.session) |*session| { session.deinit(); self.session = null; self.env.memoryPressureNotification(.critical); } } pub fn runMicrotasks(self: *Browser) void { self.env.runMicrotasks(); } pub fn runMacrotasks(self: *Browser) !?u64 { const env = &self.env; const time_to_next = try self.env.runMacrotasks(); env.pumpMessageLoop(); // either of the above could have queued more microtasks env.runMicrotasks(); return time_to_next; } pub fn hasBackgroundTasks(self: *Browser) bool { return self.env.hasBackgroundTasks(); } pub fn waitForBackgroundTasks(self: *Browser) void { self.env.waitForBackgroundTasks(); } pub fn runIdleTasks(self: *const Browser) void { self.env.runIdleTasks(); }