default:blank as default document

This commit is contained in:
sjorsdonkers
2025-05-20 12:31:40 +02:00
committed by Sjors
parent 0929bd217d
commit 967ab18d53
12 changed files with 34 additions and 36 deletions

View File

@@ -30,7 +30,7 @@ pub const Comment = struct {
pub fn constructor(data: ?[]const u8, state: *const SessionState) !*parser.Comment { pub fn constructor(data: ?[]const u8, state: *const SessionState) !*parser.Comment {
return parser.documentCreateComment( return parser.documentCreateComment(
parser.documentHTMLToDocument(state.window.document.?), parser.documentHTMLToDocument(state.window.document),
data orelse "", data orelse "",
); );
} }

View File

@@ -41,12 +41,12 @@ pub const Document = struct {
pub fn constructor(state: *const SessionState) !*parser.DocumentHTML { pub fn constructor(state: *const SessionState) !*parser.DocumentHTML {
const doc = try parser.documentCreateDocument( 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. // we have to work w/ document instead of html document.
const ddoc = parser.documentHTMLToDocument(doc); 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.documentSetDocumentURI(ddoc, try parser.documentGetDocumentURI(ccur));
try parser.documentSetInputEncoding(ddoc, try parser.documentGetInputEncoding(ccur)); try parser.documentSetInputEncoding(ddoc, try parser.documentGetInputEncoding(ccur));

View File

@@ -29,7 +29,7 @@ pub const DocumentFragment = struct {
pub fn constructor(state: *const SessionState) !*parser.DocumentFragment { pub fn constructor(state: *const SessionState) !*parser.DocumentFragment {
return parser.documentCreateDocumentFragment( return parser.documentCreateDocumentFragment(
parser.documentHTMLToDocument(state.window.document.?), parser.documentHTMLToDocument(state.window.document),
); );
} }

View File

@@ -370,7 +370,7 @@ pub const Element = struct {
pub fn _getBoundingClientRect(self: *parser.Element, state: *SessionState) !DOMRect { 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. // 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)); 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 DOMRect{ .x = 0, .y = 0, .width = 0, .height = 0 };
} }
return state.renderer.getRect(self); 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 // Returns an empty array if the element is eventually detached from the main window
pub fn _getClientRects(self: *parser.Element, state: *SessionState) ![]DOMRect { pub fn _getClientRects(self: *parser.Element, state: *SessionState) ![]DOMRect {
const root = try parser.nodeGetRootNode(parser.elementToNode(self)); 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 &.{}; return &.{};
} }
const heap_ptr = try state.call_arena.create(DOMRect); const heap_ptr = try state.call_arena.create(DOMRect);

View File

@@ -50,7 +50,7 @@ pub const IntersectionObserver = struct {
// new IntersectionObserver(callback, options) [not supported yet] // new IntersectionObserver(callback, options) [not supported yet]
pub fn constructor(callback: Env.Callback, options_: ?IntersectionObserverOptions, state: *SessionState) !IntersectionObserver { pub fn constructor(callback: Env.Callback, options_: ?IntersectionObserverOptions, state: *SessionState) !IntersectionObserver {
var options = IntersectionObserverOptions{ var options = IntersectionObserverOptions{
.root = parser.documentToNode(parser.documentHTMLToDocument(state.window.document.?)), .root = parser.documentToNode(parser.documentHTMLToDocument(state.window.document)),
.rootMargin = "0px 0px 0px 0px", .rootMargin = "0px 0px 0px 0px",
.threshold = &.{0.0}, .threshold = &.{0.0},
}; };
@@ -142,7 +142,7 @@ pub const IntersectionObserverEntry = struct {
// Returns a DOMRectReadOnly for the intersection observer's root. // Returns a DOMRectReadOnly for the intersection observer's root.
pub fn get_rootBounds(self: *const IntersectionObserverEntry) !Element.DOMRect { pub fn get_rootBounds(self: *const IntersectionObserverEntry) !Element.DOMRect {
const root = self.options.root.?; 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(); return self.state.renderer.boundingRect();
} }

View File

@@ -41,7 +41,7 @@ pub const ProcessingInstruction = struct {
// a simple workaround. // a simple workaround.
pub fn _cloneNode(self: *parser.ProcessingInstruction, _: ?bool, state: *SessionState) !*parser.ProcessingInstruction { pub fn _cloneNode(self: *parser.ProcessingInstruction, _: ?bool, state: *SessionState) !*parser.ProcessingInstruction {
return try parser.documentCreateProcessingInstruction( return try parser.documentCreateProcessingInstruction(
@ptrCast(state.window.document.?), @ptrCast(state.window.document),
try get_target(self), try get_target(self),
(try get_data(self)) orelse "", (try get_data(self)) orelse "",
); );

View File

@@ -34,7 +34,7 @@ pub const Text = struct {
pub fn constructor(data: ?[]const u8, state: *const SessionState) !*parser.Text { pub fn constructor(data: ?[]const u8, state: *const SessionState) !*parser.Text {
return parser.documentCreateTextNode( return parser.documentCreateTextNode(
parser.documentHTMLToDocument(state.window.document.?), parser.documentHTMLToDocument(state.window.document),
data orelse "", data orelse "",
); );
} }

View File

@@ -255,10 +255,10 @@ pub const HTMLDocument = struct {
// Thus we can add the HtmlHtmlElement and it's child HTMLBodyElement to the returned list. // 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. // 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? // 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; 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(parser.bodyToElement(body)));
} }
list.appendAssumeCapacity(try Element.toInterface(doc_elem)); list.appendAssumeCapacity(try Element.toInterface(doc_elem));
@@ -383,12 +383,12 @@ test "Browser.HTML.Document" {
.{ "document.readyState", "loading" }, .{ "document.readyState", "loading" },
}, .{}); }, .{});
try HTMLDocument.documentIsLoaded(runner.window.document.?, &runner.state); try HTMLDocument.documentIsLoaded(runner.window.document, &runner.state);
try runner.testCases(&.{ try runner.testCases(&.{
.{ "document.readyState", "interactive" }, .{ "document.readyState", "interactive" },
}, .{}); }, .{});
try HTMLDocument.documentIsComplete(runner.window.document.?, &runner.state); try HTMLDocument.documentIsComplete(runner.window.document, &runner.state);
try runner.testCases(&.{ try runner.testCases(&.{
.{ "document.readyState", "complete" }, .{ "document.readyState", "complete" },
}, .{}); }, .{});

View File

@@ -44,7 +44,7 @@ pub const Window = struct {
// Extend libdom event target for pure zig struct. // Extend libdom event target for pure zig struct.
base: parser.EventTargetTBase = parser.EventTargetTBase{}, base: parser.EventTargetTBase = parser.EventTargetTBase{},
document: ?*parser.DocumentHTML = null, document: *parser.DocumentHTML,
target: []const u8 = "", target: []const u8 = "",
history: History = .{}, history: History = .{},
location: Location = .{}, location: Location = .{},
@@ -60,7 +60,13 @@ pub const Window = struct {
performance: Performance, performance: Performance,
pub fn create(target: ?[]const u8, navigator: ?Navigator) !Window { 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 .{ return .{
.document = html_doc,
.target = target orelse "", .target = target orelse "",
.navigator = navigator orelse .{}, .navigator = navigator orelse .{},
.performance = .{ .time_origin = try std.time.Timer.start() }, .performance = .{ .time_origin = try std.time.Timer.start() },
@@ -69,9 +75,7 @@ pub const Window = struct {
pub fn replaceLocation(self: *Window, loc: Location) !void { pub fn replaceLocation(self: *Window, loc: Location) !void {
self.location = loc; self.location = loc;
if (self.document) |doc| { try parser.documentHTMLSetLocation(Location, self.document, &self.location);
try parser.documentHTMLSetLocation(Location, doc, &self.location);
}
} }
pub fn replaceDocument(self: *Window, doc: *parser.DocumentHTML) !void { pub fn replaceDocument(self: *Window, doc: *parser.DocumentHTML) !void {

View File

@@ -60,8 +60,6 @@ pub const Page = struct {
// Serves are the root object of our JavaScript environment // Serves are the root object of our JavaScript environment
window: Window, window: Window,
doc: ?*parser.Document,
// The URL of the page // The URL of the page
url: URL, url: URL,
@@ -87,7 +85,6 @@ pub const Page = struct {
self.* = .{ self.* = .{
.window = try Window.create(null, null), .window = try Window.create(null, null),
.arena = arena, .arena = arena,
.doc = null,
.raw_data = null, .raw_data = null,
.url = URL.empty, .url = URL.empty,
.session = session, .session = session,
@@ -121,15 +118,14 @@ pub const Page = struct {
// dump writes the page content into the given file. // dump writes the page content into the given file.
pub fn dump(self: *const Page, out: std.fs.File) !void { pub fn dump(self: *const Page, out: std.fs.File) !void {
// if no HTML document pointer available, dump the data content only. if (self.raw_data) |raw_data| {
if (self.doc == null) { // raw_data was set if the document was not HTML, dump the data content only.
// no data loaded, nothing to do. return try out.writeAll(raw_data);
if (self.raw_data == null) return;
return try out.writeAll(self.raw_data.?);
} }
// if the page has a pointer to a document, dumps the HTML. // 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 { 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"); try self.loadHTMLDoc(fbs.reader(), "utf-8");
// We do not processHTMLDoc here as we know we don't have any scripts // 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 // 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; return;
} }
@@ -229,6 +225,7 @@ pub const Page = struct {
} orelse .unknown; } orelse .unknown;
if (mime.isHTML()) { if (mime.isHTML()) {
self.raw_data = null;
try self.loadHTMLDoc(&response, mime.charset orelse "utf-8"); try self.loadHTMLDoc(&response, mime.charset orelse "utf-8");
try self.processHTMLDoc(); try self.processHTMLDoc();
} else { } else {
@@ -256,9 +253,6 @@ pub const Page = struct {
const html_doc = try parser.documentHTMLParse(reader, ccharset); const html_doc = try parser.documentHTMLParse(reader, ccharset);
const doc = parser.documentHTMLToDocument(html_doc); 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. // inject the URL to the document including the fragment.
try parser.documentSetDocumentURI(doc, self.url.raw); try parser.documentSetDocumentURI(doc, self.url.raw);
@@ -270,8 +264,8 @@ pub const Page = struct {
} }
fn processHTMLDoc(self: *Page) !void { 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; const document_element = (try parser.documentGetDocumentElement(doc)) orelse return error.DocumentElementError;
try parser.eventTargetAddEventListener( try parser.eventTargetAddEventListener(

View File

@@ -59,7 +59,7 @@ fn getDocument(cmd: anytype) !void {
const bc = cmd.browser_context orelse return error.BrowserContextNotLoaded; const bc = cmd.browser_context orelse return error.BrowserContextNotLoaded;
const page = bc.session.currentPage() orelse return error.PageNotLoaded; 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)); const node = try bc.node_registry.register(parser.documentToNode(doc));
return cmd.sendResult(.{ .root = bc.nodeWriter(node, .{}) }, .{}); 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 bc = cmd.browser_context orelse return error.BrowserContextNotLoaded;
const page = bc.session.currentPage() orelse return error.PageNotLoaded; 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; const allocator = cmd.cdp.allocator;
var list = try css.querySelectorAll(allocator, parser.documentToNode(doc), params.query); var list = try css.querySelectorAll(allocator, parser.documentToNode(doc), params.query);

View File

@@ -116,7 +116,7 @@ fn run(arena: Allocator, test_file: []const u8, loader: *FileLoader, err_out: *?
try polyfill.load(arena, runner.scope); try polyfill.load(arena, runner.scope);
// loop over the scripts. // 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 scripts = try parser.documentGetElementsByTagName(doc, "script");
const script_count = try parser.nodeListLength(scripts); const script_count = try parser.nodeListLength(scripts);
for (0..script_count) |i| { for (0..script_count) |i| {