diff --git a/src/dom/dom.zig b/src/dom/dom.zig index 9fb3ad79..6a29a937 100644 --- a/src/dom/dom.zig +++ b/src/dom/dom.zig @@ -2,11 +2,13 @@ const generate = @import("../generate.zig"); const DOMException = @import("exceptions.zig").DOMException; const EventTarget = @import("event_target.zig").EventTarget; +const DOMImplementation = @import("implementation.zig").DOMImplementation; const Nod = @import("node.zig"); pub const Interfaces = generate.Tuple(.{ DOMException, EventTarget, + DOMImplementation, Nod.Node, Nod.Interfaces, }); diff --git a/src/dom/implementation.zig b/src/dom/implementation.zig new file mode 100644 index 00000000..c81aabce --- /dev/null +++ b/src/dom/implementation.zig @@ -0,0 +1,82 @@ +const std = @import("std"); + +const parser = @import("../netsurf.zig"); + +const jsruntime = @import("jsruntime"); +const Case = jsruntime.test_utils.Case; +const checkCases = jsruntime.test_utils.checkCases; + +const Document = @import("document.zig").Document; +const DocumentType = @import("document_type.zig").DocumentType; + +// WEB IDL https://dom.spec.whatwg.org/#domimplementation +pub const DOMImplementation = struct { + pub const mem_guarantied = true; + + pub fn _createDocumentType( + self: *DOMImplementation, + allocator: std.mem.Allocator, + qname: []const u8, + publicId: []const u8, + systemId: []const u8, + ) !*parser.DocumentType { + _ = self; + const cqname = try allocator.dupeZ(u8, qname); + defer allocator.free(cqname); + + const cpublicId = try allocator.dupeZ(u8, publicId); + defer allocator.free(cpublicId); + + const csystemId = try allocator.dupeZ(u8, systemId); + defer allocator.free(csystemId); + + const dt = parser.domImplementationCreateDocumentType(cqname, cpublicId, csystemId); + return dt; + } + + pub fn _createDocument( + self: *DOMImplementation, + allocator: std.mem.Allocator, + namespace: ?[]const u8, + qname: ?[]const u8, + doctype: ?*parser.DocumentType, + ) !*parser.Document { + _ = self; + var cnamespace: ?[:0]const u8 = null; + if (namespace != null) { + cnamespace = try allocator.dupeZ(u8, namespace.?); + defer allocator.free(cnamespace.?); + } + + var cqname: ?[:0]const u8 = null; + if (qname != null) { + cqname = try allocator.dupeZ(u8, qname.?); + defer allocator.free(cqname.?); + } + + const doc = parser.domImplementationCreateDocument(cnamespace, cqname, doctype); + return doc; + } + + pub fn _createHTMLDocument(_: *DOMImplementation, title: ?[]const u8) *parser.Document { + const doc = parser.domImplementationCreateHTMLDocument(title); + return doc; + } +}; + +// Tests +// ----- + +pub fn testExecFn( + _: std.mem.Allocator, + js_env: *jsruntime.Env, + comptime _: []jsruntime.API, +) !void { + var getImplementation = [_]Case{ + .{ .src = "let impl = document.implementation", .ex = "undefined" }, + .{ .src = "impl.createHTMLDocument();", .ex = "[object Document]" }, + .{ .src = "impl.createDocument(null, 'foo');", .ex = "[object Document]" }, + .{ .src = "impl.createDocumentType('foo', 'bar', 'baz');", .ex = "[object DocumentType]" }, + }; + try checkCases(js_env, &getImplementation); +} diff --git a/src/netsurf.zig b/src/netsurf.zig index dbb3e61e..0605f005 100644 --- a/src/netsurf.zig +++ b/src/netsurf.zig @@ -826,6 +826,54 @@ pub inline fn documentTypeGetSystemId(dt: *DocumentType) []const u8 { return stringToData(s.?); } +// DOMImplementation +pub inline fn domImplementationCreateDocument(namespace: ?[:0]const u8, qname: ?[:0]const u8, doctype: ?*DocumentType) *Document { + var doc: ?*Document = undefined; + + var ptrnamespace: [*c]const u8 = null; + if (namespace != null) { + ptrnamespace = namespace.?.ptr; + } + + var ptrqname: [*c]const u8 = null; + if (qname != null) { + ptrqname = qname.?.ptr; + } + + _ = c.dom_implementation_create_document( + c.DOM_IMPLEMENTATION_XML, + ptrnamespace, + ptrqname, + doctype, + null, + null, + &doc, + ); + return doc.?; +} + +pub inline fn domImplementationCreateDocumentType(qname: [:0]const u8, publicId: [:0]const u8, systemId: [:0]const u8) *DocumentType { + var dt: ?*DocumentType = undefined; + _ = c.dom_implementation_create_document_type(qname.ptr, publicId.ptr, systemId.ptr, &dt); + return dt.?; +} + +pub inline fn domImplementationCreateHTMLDocument(title: ?[]const u8) *Document { + _ = title; + var doc: ?*Document = undefined; + _ = c.dom_implementation_create_document( + c.DOM_IMPLEMENTATION_HTML, + null, + null, + null, + null, + null, + &doc, + ); + // TODO set title + return doc.?; +} + // Document pub const Document = c.dom_document; @@ -915,7 +963,7 @@ pub fn documentHTMLParseFromFile(filename: [:0]const u8) !*DocumentHTML { // The allocator is required to create a null terminated string. // The c string allocated is freed by the function. // The caller is responsible for closing the document. -pub fn documentHTMLParseFromStrAlloc(allocator: std.mem.Allocator, str: [:0]const u8) !*DocumentHTML { +pub fn documentHTMLParseFromStrAlloc(allocator: std.mem.Allocator, str: []const u8) !*DocumentHTML { // create a null terminated c string. const cstr = try allocator.dupeZ(u8, str); defer allocator.free(cstr); diff --git a/src/run_tests.zig b/src/run_tests.zig index 8acad71c..3a7dec64 100644 --- a/src/run_tests.zig +++ b/src/run_tests.zig @@ -13,6 +13,7 @@ const characterDataTestExecFn = @import("dom/character_data.zig").testExecFn; const textTestExecFn = @import("dom/text.zig").testExecFn; const HTMLCollectionTestExecFn = @import("dom/html_collection.zig").testExecFn; const DOMExceptionTestExecFn = @import("dom/exceptions.zig").testExecFn; +const DOMImplementationExecFn = @import("dom/implementation.zig").testExecFn; var doc: *parser.DocumentHTML = undefined; @@ -55,6 +56,7 @@ fn testsAllExecFn( textTestExecFn, HTMLCollectionTestExecFn, DOMExceptionTestExecFn, + DOMImplementationExecFn, }; inline for (testFns) |testFn| {