From 967ab18d534d2f4b6b34cc7684b3d0db92745135 Mon Sep 17 00:00:00 2001 From: sjorsdonkers <72333389+sjorsdonkers@users.noreply.github.com> Date: Tue, 20 May 2025 12:31:40 +0200 Subject: [PATCH] default:blank as default document --- src/browser/dom/comment.zig | 2 +- src/browser/dom/document.zig | 4 ++-- src/browser/dom/document_fragment.zig | 2 +- src/browser/dom/element.zig | 4 ++-- src/browser/dom/intersection_observer.zig | 4 ++-- src/browser/dom/processing_instruction.zig | 2 +- src/browser/dom/text.zig | 2 +- src/browser/html/document.zig | 8 ++++---- src/browser/html/window.zig | 12 +++++++---- src/browser/page.zig | 24 ++++++++-------------- src/cdp/domains/dom.zig | 4 ++-- src/main_wpt.zig | 2 +- 12 files changed, 34 insertions(+), 36 deletions(-) diff --git a/src/browser/dom/comment.zig b/src/browser/dom/comment.zig index 26bc9e3a..19aa9781 100644 --- a/src/browser/dom/comment.zig +++ b/src/browser/dom/comment.zig @@ -30,7 +30,7 @@ pub const Comment = struct { pub fn constructor(data: ?[]const u8, state: *const SessionState) !*parser.Comment { return parser.documentCreateComment( - parser.documentHTMLToDocument(state.window.document.?), + parser.documentHTMLToDocument(state.window.document), data orelse "", ); } diff --git a/src/browser/dom/document.zig b/src/browser/dom/document.zig index 910737cb..e3bf4f6b 100644 --- a/src/browser/dom/document.zig +++ b/src/browser/dom/document.zig @@ -41,12 +41,12 @@ pub const Document = struct { pub fn constructor(state: *const SessionState) !*parser.DocumentHTML { const doc = try parser.documentCreateDocument( - try parser.documentHTMLGetTitle(state.window.document.?), + try parser.documentHTMLGetTitle(state.window.document), ); // we have to work w/ document instead of html document. const ddoc = parser.documentHTMLToDocument(doc); - const ccur = parser.documentHTMLToDocument(state.window.document.?); + const ccur = parser.documentHTMLToDocument(state.window.document); try parser.documentSetDocumentURI(ddoc, try parser.documentGetDocumentURI(ccur)); try parser.documentSetInputEncoding(ddoc, try parser.documentGetInputEncoding(ccur)); diff --git a/src/browser/dom/document_fragment.zig b/src/browser/dom/document_fragment.zig index daff1009..7bb0e5c1 100644 --- a/src/browser/dom/document_fragment.zig +++ b/src/browser/dom/document_fragment.zig @@ -29,7 +29,7 @@ pub const DocumentFragment = struct { pub fn constructor(state: *const SessionState) !*parser.DocumentFragment { return parser.documentCreateDocumentFragment( - parser.documentHTMLToDocument(state.window.document.?), + parser.documentHTMLToDocument(state.window.document), ); } diff --git a/src/browser/dom/element.zig b/src/browser/dom/element.zig index 77d527ea..dd2a863d 100644 --- a/src/browser/dom/element.zig +++ b/src/browser/dom/element.zig @@ -370,7 +370,7 @@ pub const Element = struct { pub fn _getBoundingClientRect(self: *parser.Element, state: *SessionState) !DOMRect { // Since we are lazy rendering we need to do this check. We could store the renderer in a viewport such that it could cache these, but it would require tracking changes. const root = try parser.nodeGetRootNode(parser.elementToNode(self)); - if (root != parser.documentToNode(parser.documentHTMLToDocument(state.window.document.?))) { + if (root != parser.documentToNode(parser.documentHTMLToDocument(state.window.document))) { return DOMRect{ .x = 0, .y = 0, .width = 0, .height = 0 }; } return state.renderer.getRect(self); @@ -381,7 +381,7 @@ pub const Element = struct { // Returns an empty array if the element is eventually detached from the main window pub fn _getClientRects(self: *parser.Element, state: *SessionState) ![]DOMRect { const root = try parser.nodeGetRootNode(parser.elementToNode(self)); - if (root != parser.documentToNode(parser.documentHTMLToDocument(state.window.document.?))) { + if (root != parser.documentToNode(parser.documentHTMLToDocument(state.window.document))) { return &.{}; } const heap_ptr = try state.call_arena.create(DOMRect); diff --git a/src/browser/dom/intersection_observer.zig b/src/browser/dom/intersection_observer.zig index 35ad8bbc..0608b70d 100644 --- a/src/browser/dom/intersection_observer.zig +++ b/src/browser/dom/intersection_observer.zig @@ -50,7 +50,7 @@ pub const IntersectionObserver = struct { // new IntersectionObserver(callback, options) [not supported yet] pub fn constructor(callback: Env.Callback, options_: ?IntersectionObserverOptions, state: *SessionState) !IntersectionObserver { var options = IntersectionObserverOptions{ - .root = parser.documentToNode(parser.documentHTMLToDocument(state.window.document.?)), + .root = parser.documentToNode(parser.documentHTMLToDocument(state.window.document)), .rootMargin = "0px 0px 0px 0px", .threshold = &.{0.0}, }; @@ -142,7 +142,7 @@ pub const IntersectionObserverEntry = struct { // Returns a DOMRectReadOnly for the intersection observer's root. pub fn get_rootBounds(self: *const IntersectionObserverEntry) !Element.DOMRect { const root = self.options.root.?; - if (@intFromPtr(root) == @intFromPtr(self.state.window.document.?)) { + if (@intFromPtr(root) == @intFromPtr(self.state.window.document)) { return self.state.renderer.boundingRect(); } diff --git a/src/browser/dom/processing_instruction.zig b/src/browser/dom/processing_instruction.zig index 97a8c6b8..ae4d93f6 100644 --- a/src/browser/dom/processing_instruction.zig +++ b/src/browser/dom/processing_instruction.zig @@ -41,7 +41,7 @@ pub const ProcessingInstruction = struct { // a simple workaround. pub fn _cloneNode(self: *parser.ProcessingInstruction, _: ?bool, state: *SessionState) !*parser.ProcessingInstruction { return try parser.documentCreateProcessingInstruction( - @ptrCast(state.window.document.?), + @ptrCast(state.window.document), try get_target(self), (try get_data(self)) orelse "", ); diff --git a/src/browser/dom/text.zig b/src/browser/dom/text.zig index 57c380cd..c12d3402 100644 --- a/src/browser/dom/text.zig +++ b/src/browser/dom/text.zig @@ -34,7 +34,7 @@ pub const Text = struct { pub fn constructor(data: ?[]const u8, state: *const SessionState) !*parser.Text { return parser.documentCreateTextNode( - parser.documentHTMLToDocument(state.window.document.?), + parser.documentHTMLToDocument(state.window.document), data orelse "", ); } diff --git a/src/browser/html/document.zig b/src/browser/html/document.zig index c5f6f572..a46474c0 100644 --- a/src/browser/html/document.zig +++ b/src/browser/html/document.zig @@ -255,10 +255,10 @@ pub const HTMLDocument = struct { // Thus we can add the HtmlHtmlElement and it's child HTMLBodyElement to the returned list. // TBD Should we instead return every parent that is an element? Note that a child does not physically need to be overlapping the parent. // Should we do a render pass on demand? - const doc_elem = try parser.documentGetDocumentElement(parser.documentHTMLToDocument(state.window.document.?)) orelse { + const doc_elem = try parser.documentGetDocumentElement(parser.documentHTMLToDocument(state.window.document)) orelse { return list.items; }; - if (try parser.documentHTMLBody(state.window.document.?)) |body| { + if (try parser.documentHTMLBody(state.window.document)) |body| { list.appendAssumeCapacity(try Element.toInterface(parser.bodyToElement(body))); } list.appendAssumeCapacity(try Element.toInterface(doc_elem)); @@ -383,12 +383,12 @@ test "Browser.HTML.Document" { .{ "document.readyState", "loading" }, }, .{}); - try HTMLDocument.documentIsLoaded(runner.window.document.?, &runner.state); + try HTMLDocument.documentIsLoaded(runner.window.document, &runner.state); try runner.testCases(&.{ .{ "document.readyState", "interactive" }, }, .{}); - try HTMLDocument.documentIsComplete(runner.window.document.?, &runner.state); + try HTMLDocument.documentIsComplete(runner.window.document, &runner.state); try runner.testCases(&.{ .{ "document.readyState", "complete" }, }, .{}); diff --git a/src/browser/html/window.zig b/src/browser/html/window.zig index 10caf60e..e903e06c 100644 --- a/src/browser/html/window.zig +++ b/src/browser/html/window.zig @@ -44,7 +44,7 @@ pub const Window = struct { // Extend libdom event target for pure zig struct. base: parser.EventTargetTBase = parser.EventTargetTBase{}, - document: ?*parser.DocumentHTML = null, + document: *parser.DocumentHTML, target: []const u8 = "", history: History = .{}, location: Location = .{}, @@ -60,7 +60,13 @@ pub const Window = struct { performance: Performance, pub fn create(target: ?[]const u8, navigator: ?Navigator) !Window { + var fbs = std.io.fixedBufferStream(""); + const html_doc = try parser.documentHTMLParse(fbs.reader(), "utf-8"); + const doc = parser.documentHTMLToDocument(html_doc); + try parser.documentSetDocumentURI(doc, "about:blank"); + return .{ + .document = html_doc, .target = target orelse "", .navigator = navigator orelse .{}, .performance = .{ .time_origin = try std.time.Timer.start() }, @@ -69,9 +75,7 @@ pub const Window = struct { pub fn replaceLocation(self: *Window, loc: Location) !void { self.location = loc; - if (self.document) |doc| { - try parser.documentHTMLSetLocation(Location, doc, &self.location); - } + try parser.documentHTMLSetLocation(Location, self.document, &self.location); } pub fn replaceDocument(self: *Window, doc: *parser.DocumentHTML) !void { diff --git a/src/browser/page.zig b/src/browser/page.zig index 06fdf018..fadb1929 100644 --- a/src/browser/page.zig +++ b/src/browser/page.zig @@ -60,8 +60,6 @@ pub const Page = struct { // Serves are the root object of our JavaScript environment window: Window, - doc: ?*parser.Document, - // The URL of the page url: URL, @@ -87,7 +85,6 @@ pub const Page = struct { self.* = .{ .window = try Window.create(null, null), .arena = arena, - .doc = null, .raw_data = null, .url = URL.empty, .session = session, @@ -121,15 +118,14 @@ pub const Page = struct { // dump writes the page content into the given file. pub fn dump(self: *const Page, out: std.fs.File) !void { - // if no HTML document pointer available, dump the data content only. - if (self.doc == null) { - // no data loaded, nothing to do. - if (self.raw_data == null) return; - return try out.writeAll(self.raw_data.?); + if (self.raw_data) |raw_data| { + // raw_data was set if the document was not HTML, dump the data content only. + return try out.writeAll(raw_data); } // if the page has a pointer to a document, dumps the HTML. - try Dump.writeHTML(self.doc.?, out); + const doc = parser.documentHTMLToDocument(self.window.document); + try Dump.writeHTML(doc, out); } pub fn fetchModuleSource(ctx: *anyopaque, specifier: []const u8) !?[]const u8 { @@ -187,7 +183,7 @@ pub const Page = struct { try self.loadHTMLDoc(fbs.reader(), "utf-8"); // We do not processHTMLDoc here as we know we don't have any scripts // This assumption may be false when CDP Page.addScriptToEvaluateOnNewDocument is implemented - try HTMLDocument.documentIsComplete(self.window.document.?, &self.state); + try HTMLDocument.documentIsComplete(self.window.document, &self.state); return; } @@ -229,6 +225,7 @@ pub const Page = struct { } orelse .unknown; if (mime.isHTML()) { + self.raw_data = null; try self.loadHTMLDoc(&response, mime.charset orelse "utf-8"); try self.processHTMLDoc(); } else { @@ -256,9 +253,6 @@ pub const Page = struct { const html_doc = try parser.documentHTMLParse(reader, ccharset); const doc = parser.documentHTMLToDocument(html_doc); - // save a document's pointer in the page. - self.doc = doc; - // inject the URL to the document including the fragment. try parser.documentSetDocumentURI(doc, self.url.raw); @@ -270,8 +264,8 @@ pub const Page = struct { } fn processHTMLDoc(self: *Page) !void { - const doc = self.doc.?; - const html_doc = self.window.document.?; + const html_doc = self.window.document; + const doc = parser.documentHTMLToDocument(html_doc); const document_element = (try parser.documentGetDocumentElement(doc)) orelse return error.DocumentElementError; try parser.eventTargetAddEventListener( diff --git a/src/cdp/domains/dom.zig b/src/cdp/domains/dom.zig index e6425e07..79410c97 100644 --- a/src/cdp/domains/dom.zig +++ b/src/cdp/domains/dom.zig @@ -59,7 +59,7 @@ fn getDocument(cmd: anytype) !void { const bc = cmd.browser_context orelse return error.BrowserContextNotLoaded; const page = bc.session.currentPage() orelse return error.PageNotLoaded; - const doc = page.doc orelse return error.DocumentNotLoaded; + const doc = parser.documentHTMLToDocument(page.window.document); const node = try bc.node_registry.register(parser.documentToNode(doc)); return cmd.sendResult(.{ .root = bc.nodeWriter(node, .{}) }, .{}); @@ -74,7 +74,7 @@ fn performSearch(cmd: anytype) !void { const bc = cmd.browser_context orelse return error.BrowserContextNotLoaded; const page = bc.session.currentPage() orelse return error.PageNotLoaded; - const doc = page.doc orelse return error.DocumentNotLoaded; + const doc = parser.documentHTMLToDocument(page.window.document); const allocator = cmd.cdp.allocator; var list = try css.querySelectorAll(allocator, parser.documentToNode(doc), params.query); diff --git a/src/main_wpt.zig b/src/main_wpt.zig index 3ad2caf2..cd2b5536 100644 --- a/src/main_wpt.zig +++ b/src/main_wpt.zig @@ -116,7 +116,7 @@ fn run(arena: Allocator, test_file: []const u8, loader: *FileLoader, err_out: *? try polyfill.load(arena, runner.scope); // loop over the scripts. - const doc = parser.documentHTMLToDocument(runner.state.window.document.?); + const doc = parser.documentHTMLToDocument(runner.state.window.document); const scripts = try parser.documentGetElementsByTagName(doc, "script"); const script_count = try parser.nodeListLength(scripts); for (0..script_count) |i| {