mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 15:13:28 +00:00
Merge pull request #761 from lightpanda-io/pozo_for_custom_state
Some checks failed
e2e-test / zig build release (push) Has been cancelled
e2e-test / puppeteer-perf (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
zig-test / zig build dev (push) Has been cancelled
zig-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 / puppeteer-perf (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
zig-test / zig build dev (push) Has been cancelled
zig-test / browser fetch (push) Has been cancelled
zig-test / zig test (push) Has been cancelled
zig-test / perf-fmt (push) Has been cancelled
Improve usability of NodeWrapper
This commit is contained in:
65
src/browser/State.zig
Normal file
65
src/browser/State.zig
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
// Copyright (C) 2023-2024 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/>.
|
||||||
|
|
||||||
|
// Sometimes we need to extend libdom. For example, its HTMLDocument doesn't
|
||||||
|
// have a readyState. We have a couple different options, such as making the
|
||||||
|
// correction in libdom directly. Another option stems from the fact that every
|
||||||
|
// libdom node has an opaque embedder_data field. This is the struct that we
|
||||||
|
// lazily load into that field.
|
||||||
|
//
|
||||||
|
// It didn't originally start off as a collection of every single extension, but
|
||||||
|
// this quickly proved necessary, since different fields are needed on the same
|
||||||
|
// data at different levels of the prototype chain. This isn't memory efficient.
|
||||||
|
|
||||||
|
const Env = @import("env.zig").Env;
|
||||||
|
const parser = @import("netsurf.zig");
|
||||||
|
const CSSStyleDeclaration = @import("cssom/css_style_declaration.zig").CSSStyleDeclaration;
|
||||||
|
|
||||||
|
// for HTMLScript (but probably needs to be added to more)
|
||||||
|
onload: ?Env.Function = null,
|
||||||
|
onerror: ?Env.Function = null,
|
||||||
|
|
||||||
|
// for HTMLElement
|
||||||
|
style: CSSStyleDeclaration = .empty,
|
||||||
|
|
||||||
|
// for html/document
|
||||||
|
ready_state: ReadyState = .loading,
|
||||||
|
|
||||||
|
// for dom/document
|
||||||
|
active_element: ?*parser.Element = null,
|
||||||
|
|
||||||
|
// for HTMLSelectElement
|
||||||
|
// By default, if no option is explicitly selected, the first option should
|
||||||
|
// be selected. However, libdom doesn't do this, and it sets the
|
||||||
|
// selectedIndex to -1, which is a valid value for "nothing selected".
|
||||||
|
// Therefore, when libdom says the selectedIndex == -1, we don't know if
|
||||||
|
// it means that nothing is selected, or if the first option is selected by
|
||||||
|
// default.
|
||||||
|
// There are cases where this won't work, but when selectedIndex is
|
||||||
|
// explicitly set, we set this boolean flag. Then, when we're getting then
|
||||||
|
// selectedIndex, if this flag is == false, which is to say that if
|
||||||
|
// selectedIndex hasn't been explicitly set AND if we have at least 1 option
|
||||||
|
// AND if it isn't a multi select, we can make the 1st item selected by
|
||||||
|
// default (by returning selectedIndex == 0).
|
||||||
|
explicit_index_set: bool = false,
|
||||||
|
|
||||||
|
const ReadyState = enum {
|
||||||
|
loading,
|
||||||
|
interactive,
|
||||||
|
complete,
|
||||||
|
};
|
||||||
@@ -21,6 +21,7 @@ const std = @import("std");
|
|||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const ArenaAllocator = std.heap.ArenaAllocator;
|
const ArenaAllocator = std.heap.ArenaAllocator;
|
||||||
|
|
||||||
|
const State = @import("State.zig");
|
||||||
const Env = @import("env.zig").Env;
|
const Env = @import("env.zig").Env;
|
||||||
const App = @import("../app.zig").App;
|
const App = @import("../app.zig").App;
|
||||||
const Session = @import("session.zig").Session;
|
const Session = @import("session.zig").Session;
|
||||||
@@ -41,6 +42,7 @@ pub const Browser = struct {
|
|||||||
session_arena: ArenaAllocator,
|
session_arena: ArenaAllocator,
|
||||||
transfer_arena: ArenaAllocator,
|
transfer_arena: ArenaAllocator,
|
||||||
notification: *Notification,
|
notification: *Notification,
|
||||||
|
state_pool: std.heap.MemoryPool(State),
|
||||||
|
|
||||||
pub fn init(app: *App) !Browser {
|
pub fn init(app: *App) !Browser {
|
||||||
const allocator = app.allocator;
|
const allocator = app.allocator;
|
||||||
@@ -61,6 +63,7 @@ pub const Browser = struct {
|
|||||||
.page_arena = ArenaAllocator.init(allocator),
|
.page_arena = ArenaAllocator.init(allocator),
|
||||||
.session_arena = ArenaAllocator.init(allocator),
|
.session_arena = ArenaAllocator.init(allocator),
|
||||||
.transfer_arena = ArenaAllocator.init(allocator),
|
.transfer_arena = ArenaAllocator.init(allocator),
|
||||||
|
.state_pool = std.heap.MemoryPool(State).init(allocator),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,6 +74,7 @@ pub const Browser = struct {
|
|||||||
self.session_arena.deinit();
|
self.session_arena.deinit();
|
||||||
self.transfer_arena.deinit();
|
self.transfer_arena.deinit();
|
||||||
self.notification.deinit();
|
self.notification.deinit();
|
||||||
|
self.state_pool.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn newSession(self: *Browser) !*Session {
|
pub fn newSession(self: *Browser) !*Session {
|
||||||
|
|||||||
@@ -42,8 +42,6 @@ pub const Document = struct {
|
|||||||
pub const prototype = *Node;
|
pub const prototype = *Node;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
active_element: ?*parser.Element = null,
|
|
||||||
|
|
||||||
pub fn constructor(page: *const Page) !*parser.DocumentHTML {
|
pub fn constructor(page: *const Page) !*parser.DocumentHTML {
|
||||||
const doc = try parser.documentCreateDocument(
|
const doc = try parser.documentCreateDocument(
|
||||||
try parser.documentHTMLGetTitle(page.window.document),
|
try parser.documentHTMLGetTitle(page.window.document),
|
||||||
@@ -245,9 +243,9 @@ pub const Document = struct {
|
|||||||
return try TreeWalker.init(root, what_to_show, filter);
|
return try TreeWalker.init(root, what_to_show, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_activeElement(doc: *parser.Document, page: *Page) !?ElementUnion {
|
pub fn get_activeElement(self: *parser.Document, page: *Page) !?ElementUnion {
|
||||||
const self = try page.getOrCreateNodeWrapper(Document, @ptrCast(doc));
|
const state = try page.getOrCreateNodeState(@ptrCast(self));
|
||||||
if (self.active_element) |ae| {
|
if (state.active_element) |ae| {
|
||||||
return try Element.toInterface(ae);
|
return try Element.toInterface(ae);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,7 +253,16 @@ pub const Document = struct {
|
|||||||
return try Element.toInterface(@ptrCast(body));
|
return try Element.toInterface(@ptrCast(body));
|
||||||
}
|
}
|
||||||
|
|
||||||
return get_documentElement(doc);
|
return get_documentElement(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: some elements can't be focused, like if they're disabled
|
||||||
|
// but there doesn't seem to be a generic way to check this. For example
|
||||||
|
// we could look for the "disabled" attribute, but that's only meaningful
|
||||||
|
// on certain types, and libdom's vtable doesn't seem to expose this.
|
||||||
|
pub fn setFocus(self: *parser.Document, e: *parser.ElementHTML, page: *Page) !void {
|
||||||
|
const state = try page.getOrCreateNodeState(@ptrCast(self));
|
||||||
|
state.active_element = @ptrCast(e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -39,14 +39,6 @@ pub const HTMLDocument = struct {
|
|||||||
pub const prototype = *Document;
|
pub const prototype = *Document;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
ready_state: ReadyState = .loading,
|
|
||||||
|
|
||||||
const ReadyState = enum {
|
|
||||||
loading,
|
|
||||||
interactive,
|
|
||||||
complete,
|
|
||||||
};
|
|
||||||
|
|
||||||
// JS funcs
|
// JS funcs
|
||||||
// --------
|
// --------
|
||||||
|
|
||||||
@@ -191,9 +183,9 @@ pub const HTMLDocument = struct {
|
|||||||
return &page.window;
|
return &page.window;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_readyState(node: *parser.DocumentHTML, page: *Page) ![]const u8 {
|
pub fn get_readyState(self: *parser.DocumentHTML, page: *Page) ![]const u8 {
|
||||||
const self = try page.getOrCreateNodeWrapper(HTMLDocument, @ptrCast(node));
|
const state = try page.getOrCreateNodeState(@ptrCast(self));
|
||||||
return @tagName(self.ready_state);
|
return @tagName(state.ready_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
// noop legacy functions
|
// noop legacy functions
|
||||||
@@ -270,9 +262,9 @@ pub const HTMLDocument = struct {
|
|||||||
return list.items;
|
return list.items;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn documentIsLoaded(html_doc: *parser.DocumentHTML, page: *Page) !void {
|
pub fn documentIsLoaded(self: *parser.DocumentHTML, page: *Page) !void {
|
||||||
const self = try page.getOrCreateNodeWrapper(HTMLDocument, @ptrCast(html_doc));
|
const state = try page.getOrCreateNodeState(@ptrCast(self));
|
||||||
self.ready_state = .interactive;
|
state.ready_state = .interactive;
|
||||||
|
|
||||||
const evt = try parser.eventCreate();
|
const evt = try parser.eventCreate();
|
||||||
defer parser.eventDestroy(evt);
|
defer parser.eventDestroy(evt);
|
||||||
@@ -282,12 +274,12 @@ pub const HTMLDocument = struct {
|
|||||||
.source = "document",
|
.source = "document",
|
||||||
});
|
});
|
||||||
try parser.eventInit(evt, "DOMContentLoaded", .{ .bubbles = true, .cancelable = true });
|
try parser.eventInit(evt, "DOMContentLoaded", .{ .bubbles = true, .cancelable = true });
|
||||||
_ = try parser.eventTargetDispatchEvent(parser.toEventTarget(parser.DocumentHTML, html_doc), evt);
|
_ = try parser.eventTargetDispatchEvent(parser.toEventTarget(parser.DocumentHTML, self), evt);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn documentIsComplete(html_doc: *parser.DocumentHTML, page: *Page) !void {
|
pub fn documentIsComplete(self: *parser.DocumentHTML, page: *Page) !void {
|
||||||
const self = try page.getOrCreateNodeWrapper(HTMLDocument, @ptrCast(html_doc));
|
const state = try page.getOrCreateNodeState(@ptrCast(self));
|
||||||
self.ready_state = .complete;
|
state.ready_state = .complete;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -112,11 +112,9 @@ pub const HTMLElement = struct {
|
|||||||
pub const prototype = *Element;
|
pub const prototype = *Element;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
style: CSSStyleDeclaration = .empty,
|
|
||||||
|
|
||||||
pub fn get_style(e: *parser.ElementHTML, page: *Page) !*CSSStyleDeclaration {
|
pub fn get_style(e: *parser.ElementHTML, page: *Page) !*CSSStyleDeclaration {
|
||||||
const self = try page.getOrCreateNodeWrapper(HTMLElement, @ptrCast(e));
|
const state = try page.getOrCreateNodeState(@ptrCast(e));
|
||||||
return &self.style;
|
return &state.style;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_innerText(e: *parser.ElementHTML) ![]const u8 {
|
pub fn get_innerText(e: *parser.ElementHTML) ![]const u8 {
|
||||||
@@ -159,16 +157,9 @@ pub const HTMLElement = struct {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const root_node = try parser.nodeGetRootNode(@ptrCast(e));
|
|
||||||
|
|
||||||
const Document = @import("../dom/document.zig").Document;
|
const Document = @import("../dom/document.zig").Document;
|
||||||
const document = try page.getOrCreateNodeWrapper(Document, @ptrCast(root_node));
|
const root_node = try parser.nodeGetRootNode(@ptrCast(e));
|
||||||
|
try Document.setFocus(@ptrCast(root_node), e, page);
|
||||||
// TODO: some elements can't be focused, like if they're disabled
|
|
||||||
// but there doesn't seem to be a generic way to check this. For example
|
|
||||||
// we could look for the "disabled" attribute, but that's only meaningful
|
|
||||||
// on certain types, and libdom's vtable doesn't seem to expose this.
|
|
||||||
document.active_element = @ptrCast(e);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -852,9 +843,6 @@ pub const HTMLScriptElement = struct {
|
|||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
onload: ?Env.Function = null,
|
|
||||||
onerror: ?Env.Function = null,
|
|
||||||
|
|
||||||
pub fn get_src(self: *parser.Script) !?[]const u8 {
|
pub fn get_src(self: *parser.Script) !?[]const u8 {
|
||||||
return try parser.elementGetAttribute(
|
return try parser.elementGetAttribute(
|
||||||
parser.scriptToElt(self),
|
parser.scriptToElt(self),
|
||||||
@@ -964,24 +952,24 @@ pub const HTMLScriptElement = struct {
|
|||||||
return try parser.elementRemoveAttribute(parser.scriptToElt(self), "nomodule");
|
return try parser.elementRemoveAttribute(parser.scriptToElt(self), "nomodule");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_onload(script: *parser.Script, page: *Page) !?Env.Function {
|
pub fn get_onload(self: *parser.Script, page: *Page) !?Env.Function {
|
||||||
const self = page.getNodeWrapper(HTMLScriptElement, @ptrCast(script)) orelse return null;
|
const state = page.getNodeState(@ptrCast(self)) orelse return null;
|
||||||
return self.onload;
|
return state.onload;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_onload(script: *parser.Script, function: ?Env.Function, page: *Page) !void {
|
pub fn set_onload(self: *parser.Script, function: ?Env.Function, page: *Page) !void {
|
||||||
const self = try page.getOrCreateNodeWrapper(HTMLScriptElement, @ptrCast(script));
|
const state = try page.getOrCreateNodeState(@ptrCast(self));
|
||||||
self.onload = function;
|
state.onload = function;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_onerror(script: *parser.Script, page: *Page) !?Env.Function {
|
pub fn get_onerror(self: *parser.Script, page: *Page) !?Env.Function {
|
||||||
const self = page.getNodeWrapper(HTMLScriptElement, @ptrCast(script)) orelse return null;
|
const state = page.getNodeState(@ptrCast(self)) orelse return null;
|
||||||
return self.onerror;
|
return state.onerror;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_onerror(script: *parser.Script, function: ?Env.Function, page: *Page) !void {
|
pub fn set_onerror(self: *parser.Script, function: ?Env.Function, page: *Page) !void {
|
||||||
const self = try page.getOrCreateNodeWrapper(HTMLScriptElement, @ptrCast(script));
|
const state = try page.getOrCreateNodeState(@ptrCast(self));
|
||||||
self.onerror = function;
|
state.onerror = function;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -26,20 +26,6 @@ pub const HTMLSelectElement = struct {
|
|||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
// By default, if no option is explicitly selected, the first option should
|
|
||||||
// be selected. However, libdom doesn't do this, and it sets the
|
|
||||||
// selectedIndex to -1, which is a valid value for "nothing selected".
|
|
||||||
// Therefore, when libdom says the selectedIndex == -1, we don't know if
|
|
||||||
// it means that nothing is selected, or if the first option is selected by
|
|
||||||
// default.
|
|
||||||
// There are cases where this won't work, but when selectedIndex is
|
|
||||||
// explicitly set, we set this boolean flag. Then, when we're getting then
|
|
||||||
// selectedIndex, if this flag is == false, which is to say that if
|
|
||||||
// selectedIndex hasn't been explicitly set AND if we have at least 1 option
|
|
||||||
// AND if it isn't a multi select, we can make the 1st item selected by
|
|
||||||
// default (by returning selectedIndex == 0).
|
|
||||||
explicit_index_set: bool = false,
|
|
||||||
|
|
||||||
pub fn get_length(select: *parser.Select) !u32 {
|
pub fn get_length(select: *parser.Select) !u32 {
|
||||||
return parser.selectGetLength(select);
|
return parser.selectGetLength(select);
|
||||||
}
|
}
|
||||||
@@ -70,11 +56,11 @@ pub const HTMLSelectElement = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_selectedIndex(select: *parser.Select, page: *Page) !i32 {
|
pub fn get_selectedIndex(select: *parser.Select, page: *Page) !i32 {
|
||||||
const self = try page.getOrCreateNodeWrapper(HTMLSelectElement, @ptrCast(select));
|
const state = try page.getOrCreateNodeState(@ptrCast(select));
|
||||||
const selected_index = try parser.selectGetSelectedIndex(select);
|
const selected_index = try parser.selectGetSelectedIndex(select);
|
||||||
|
|
||||||
// See the explicit_index_set field documentation
|
// See the explicit_index_set field documentation
|
||||||
if (!self.explicit_index_set) {
|
if (!state.explicit_index_set) {
|
||||||
if (selected_index == -1) {
|
if (selected_index == -1) {
|
||||||
if (try parser.selectGetMultiple(select) == false) {
|
if (try parser.selectGetMultiple(select) == false) {
|
||||||
if (try get_length(select) > 0) {
|
if (try get_length(select) > 0) {
|
||||||
@@ -89,8 +75,8 @@ pub const HTMLSelectElement = struct {
|
|||||||
// Libdom's dom_html_select_select_set_selected_index will crash if index
|
// Libdom's dom_html_select_select_set_selected_index will crash if index
|
||||||
// is out of range, and it doesn't properly unset options
|
// is out of range, and it doesn't properly unset options
|
||||||
pub fn set_selectedIndex(select: *parser.Select, index: i32, page: *Page) !void {
|
pub fn set_selectedIndex(select: *parser.Select, index: i32, page: *Page) !void {
|
||||||
var self = try page.getOrCreateNodeWrapper(HTMLSelectElement, @ptrCast(select));
|
var state = try page.getOrCreateNodeState(@ptrCast(select));
|
||||||
self.explicit_index_set = true;
|
state.explicit_index_set = true;
|
||||||
|
|
||||||
const options = try parser.selectGetOptions(select);
|
const options = try parser.selectGetOptions(select);
|
||||||
const len = try parser.optionCollectionGetLength(options);
|
const len = try parser.optionCollectionGetLength(options);
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ const builtin = @import("builtin");
|
|||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
const Dump = @import("dump.zig");
|
const Dump = @import("dump.zig");
|
||||||
|
const State = @import("State.zig");
|
||||||
const Env = @import("env.zig").Env;
|
const Env = @import("env.zig").Env;
|
||||||
const Mime = @import("mime.zig").Mime;
|
const Mime = @import("mime.zig").Mime;
|
||||||
const DataURI = @import("datauri.zig").DataURI;
|
const DataURI = @import("datauri.zig").DataURI;
|
||||||
@@ -95,6 +96,8 @@ pub const Page = struct {
|
|||||||
// indicates intention to navigate to another page on the next loop execution.
|
// indicates intention to navigate to another page on the next loop execution.
|
||||||
delayed_navigation: bool = false,
|
delayed_navigation: bool = false,
|
||||||
|
|
||||||
|
state_pool: *std.heap.MemoryPool(State),
|
||||||
|
|
||||||
pub fn init(self: *Page, arena: Allocator, session: *Session) !void {
|
pub fn init(self: *Page, arena: Allocator, session: *Session) !void {
|
||||||
const browser = session.browser;
|
const browser = session.browser;
|
||||||
self.* = .{
|
self.* = .{
|
||||||
@@ -106,6 +109,7 @@ pub const Page = struct {
|
|||||||
.call_arena = undefined,
|
.call_arena = undefined,
|
||||||
.loop = browser.app.loop,
|
.loop = browser.app.loop,
|
||||||
.renderer = Renderer.init(arena),
|
.renderer = Renderer.init(arena),
|
||||||
|
.state_pool = &browser.state_pool,
|
||||||
.cookie_jar = &session.cookie_jar,
|
.cookie_jar = &session.cookie_jar,
|
||||||
.microtask_node = .{ .func = microtaskCallback },
|
.microtask_node = .{ .func = microtaskCallback },
|
||||||
.window_clicked_event_node = .{ .func = windowClicked },
|
.window_clicked_event_node = .{ .func = windowClicked },
|
||||||
@@ -597,21 +601,21 @@ pub const Page = struct {
|
|||||||
_ = try self.loop.timeout(0, &navi.navigate_node);
|
_ = try self.loop.timeout(0, &navi.navigate_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getOrCreateNodeWrapper(self: *Page, comptime T: type, node: *parser.Node) !*T {
|
pub fn getOrCreateNodeState(self: *Page, node: *parser.Node) !*State {
|
||||||
if (self.getNodeWrapper(T, node)) |wrap| {
|
if (self.getNodeState(node)) |wrap| {
|
||||||
return wrap;
|
return wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
const wrap = try self.arena.create(T);
|
const state = try self.state_pool.create();
|
||||||
wrap.* = T{};
|
state.* = .{};
|
||||||
|
|
||||||
parser.nodeSetEmbedderData(node, wrap);
|
parser.nodeSetEmbedderData(node, state);
|
||||||
return wrap;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getNodeWrapper(_: *const Page, comptime T: type, node: *parser.Node) ?*T {
|
pub fn getNodeState(_: *const Page, node: *parser.Node) ?*State {
|
||||||
if (parser.nodeGetEmbedderData(node)) |wrap| {
|
if (parser.nodeGetEmbedderData(node)) |state| {
|
||||||
return @alignCast(@ptrCast(wrap));
|
return @alignCast(@ptrCast(state));
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -743,8 +747,7 @@ const Script = struct {
|
|||||||
// attached to it. But this seems quite unlikely and it does help
|
// attached to it. But this seems quite unlikely and it does help
|
||||||
// optimize loading scripts, of which there can be hundreds for a
|
// optimize loading scripts, of which there can be hundreds for a
|
||||||
// page.
|
// page.
|
||||||
const HTMLScriptElement = @import("html/elements.zig").HTMLScriptElement;
|
if (page.getNodeState(@ptrCast(e))) |se| {
|
||||||
if (page.getNodeWrapper(HTMLScriptElement, @ptrCast(e))) |se| {
|
|
||||||
if (se.onload) |function| {
|
if (se.onload) |function| {
|
||||||
onload = .{ .function = function };
|
onload = .{ .function = function };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ pub const Session = struct {
|
|||||||
|
|
||||||
const page_arena = &self.browser.page_arena;
|
const page_arena = &self.browser.page_arena;
|
||||||
_ = page_arena.reset(.{ .retain_with_limit = 1 * 1024 * 1024 });
|
_ = page_arena.reset(.{ .retain_with_limit = 1 * 1024 * 1024 });
|
||||||
|
_ = self.browser.state_pool.reset(.{ .retain_with_limit = 4 * 1024 });
|
||||||
|
|
||||||
self.page = @as(Page, undefined);
|
self.page = @as(Page, undefined);
|
||||||
const page = &self.page.?;
|
const page = &self.page.?;
|
||||||
|
|||||||
Reference in New Issue
Block a user