mirror of
				https://github.com/lightpanda-io/browser.git
				synced 2025-10-30 15:41:48 +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
	 Karl Seguin
					Karl Seguin