mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 07:03:29 +00:00
@@ -39,3 +39,5 @@ pub const Interfaces = generate.Tuple(.{
|
|||||||
Storage.Interfaces,
|
Storage.Interfaces,
|
||||||
URL.Interfaces,
|
URL.Interfaces,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
pub const UserContext = @import("user_context.zig").UserContext;
|
||||||
|
|||||||
@@ -39,6 +39,9 @@ const storage = @import("../storage/storage.zig");
|
|||||||
|
|
||||||
const FetchResult = std.http.Client.FetchResult;
|
const FetchResult = std.http.Client.FetchResult;
|
||||||
|
|
||||||
|
const UserContext = @import("../user_context.zig").UserContext;
|
||||||
|
const HttpClient = @import("../async/Client.zig");
|
||||||
|
|
||||||
const log = std.log.scoped(.browser);
|
const log = std.log.scoped(.browser);
|
||||||
|
|
||||||
// Browser is an instance of the browser.
|
// Browser is an instance of the browser.
|
||||||
@@ -92,6 +95,7 @@ pub const Session = struct {
|
|||||||
// TODO move the shed to the browser?
|
// TODO move the shed to the browser?
|
||||||
storageShed: storage.Shed,
|
storageShed: storage.Shed,
|
||||||
page: ?*Page = null,
|
page: ?*Page = null,
|
||||||
|
httpClient: HttpClient,
|
||||||
|
|
||||||
jstypes: [Types.len]usize = undefined,
|
jstypes: [Types.len]usize = undefined,
|
||||||
|
|
||||||
@@ -105,9 +109,11 @@ pub const Session = struct {
|
|||||||
.loader = Loader.init(alloc),
|
.loader = Loader.init(alloc),
|
||||||
.loop = try Loop.init(alloc),
|
.loop = try Loop.init(alloc),
|
||||||
.storageShed = storage.Shed.init(alloc),
|
.storageShed = storage.Shed.init(alloc),
|
||||||
|
.httpClient = undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.env = try Env.init(self.arena.allocator(), &self.loop);
|
self.env = try Env.init(self.arena.allocator(), &self.loop, null);
|
||||||
|
self.httpClient = .{ .allocator = alloc, .loop = &self.loop };
|
||||||
try self.env.load(&self.jstypes);
|
try self.env.load(&self.jstypes);
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -122,6 +128,7 @@ pub const Session = struct {
|
|||||||
self.loader.deinit();
|
self.loader.deinit();
|
||||||
self.loop.deinit();
|
self.loop.deinit();
|
||||||
self.storageShed.deinit();
|
self.storageShed.deinit();
|
||||||
|
self.httpClient.deinit();
|
||||||
self.alloc.destroy(self);
|
self.alloc.destroy(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,6 +296,12 @@ pub const Page = struct {
|
|||||||
log.debug("start js env", .{});
|
log.debug("start js env", .{});
|
||||||
try self.session.env.start(alloc);
|
try self.session.env.start(alloc);
|
||||||
|
|
||||||
|
// replace the user context document with the new one.
|
||||||
|
try self.session.env.setUserContext(.{
|
||||||
|
.document = html_doc,
|
||||||
|
.httpClient = &self.session.httpClient,
|
||||||
|
});
|
||||||
|
|
||||||
// add global objects
|
// add global objects
|
||||||
log.debug("setup global env", .{});
|
log.debug("setup global env", .{});
|
||||||
try self.session.env.bindGlobal(&self.session.window);
|
try self.session.env.bindGlobal(&self.session.window);
|
||||||
|
|||||||
@@ -15,13 +15,45 @@
|
|||||||
//
|
//
|
||||||
// You should have received a copy of the GNU Affero General Public License
|
// 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/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
const parser = @import("../netsurf.zig");
|
const parser = @import("../netsurf.zig");
|
||||||
|
|
||||||
|
const jsruntime = @import("jsruntime");
|
||||||
|
const Case = jsruntime.test_utils.Case;
|
||||||
|
const checkCases = jsruntime.test_utils.checkCases;
|
||||||
|
|
||||||
const CharacterData = @import("character_data.zig").CharacterData;
|
const CharacterData = @import("character_data.zig").CharacterData;
|
||||||
|
|
||||||
|
const UserContext = @import("../user_context.zig").UserContext;
|
||||||
|
|
||||||
|
// https://dom.spec.whatwg.org/#interface-comment
|
||||||
pub const Comment = struct {
|
pub const Comment = struct {
|
||||||
pub const Self = parser.Comment;
|
pub const Self = parser.Comment;
|
||||||
pub const prototype = *CharacterData;
|
pub const prototype = *CharacterData;
|
||||||
pub const mem_guarantied = true;
|
pub const mem_guarantied = true;
|
||||||
|
|
||||||
|
pub fn constructor(userctx: UserContext, data: ?[]const u8) !*parser.Comment {
|
||||||
|
return parser.documentCreateComment(
|
||||||
|
parser.documentHTMLToDocument(userctx.document),
|
||||||
|
data orelse "",
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Tests
|
||||||
|
// -----
|
||||||
|
|
||||||
|
pub fn testExecFn(
|
||||||
|
_: std.mem.Allocator,
|
||||||
|
js_env: *jsruntime.Env,
|
||||||
|
) anyerror!void {
|
||||||
|
var constructor = [_]Case{
|
||||||
|
.{ .src = "let comment = new Comment('foo')", .ex = "undefined" },
|
||||||
|
.{ .src = "comment.data", .ex = "foo" },
|
||||||
|
|
||||||
|
.{ .src = "let emptycomment = new Comment()", .ex = "undefined" },
|
||||||
|
.{ .src = "emptycomment.data", .ex = "" },
|
||||||
|
};
|
||||||
|
try checkCases(js_env, &constructor);
|
||||||
|
}
|
||||||
|
|||||||
@@ -40,14 +40,26 @@ const DocumentType = @import("document_type.zig").DocumentType;
|
|||||||
const DocumentFragment = @import("document_fragment.zig").DocumentFragment;
|
const DocumentFragment = @import("document_fragment.zig").DocumentFragment;
|
||||||
const DOMImplementation = @import("implementation.zig").DOMImplementation;
|
const DOMImplementation = @import("implementation.zig").DOMImplementation;
|
||||||
|
|
||||||
|
const UserContext = @import("../user_context.zig").UserContext;
|
||||||
|
|
||||||
// WEB IDL https://dom.spec.whatwg.org/#document
|
// WEB IDL https://dom.spec.whatwg.org/#document
|
||||||
pub const Document = struct {
|
pub const Document = struct {
|
||||||
pub const Self = parser.Document;
|
pub const Self = parser.Document;
|
||||||
pub const prototype = *Node;
|
pub const prototype = *Node;
|
||||||
pub const mem_guarantied = true;
|
pub const mem_guarantied = true;
|
||||||
|
|
||||||
pub fn constructor() !*parser.Document {
|
pub fn constructor(userctx: UserContext) !*parser.DocumentHTML {
|
||||||
return try parser.domImplementationCreateHTMLDocument(null);
|
const doc = try parser.documentCreateDocument(
|
||||||
|
try parser.documentHTMLGetTitle(userctx.document),
|
||||||
|
);
|
||||||
|
|
||||||
|
// we have to work w/ document instead of html document.
|
||||||
|
const ddoc = parser.documentHTMLToDocument(doc);
|
||||||
|
const ccur = parser.documentHTMLToDocument(userctx.document);
|
||||||
|
try parser.documentSetDocumentURI(ddoc, try parser.documentGetDocumentURI(ccur));
|
||||||
|
try parser.documentSetInputEncoding(ddoc, try parser.documentGetInputEncoding(ccur));
|
||||||
|
|
||||||
|
return doc;
|
||||||
}
|
}
|
||||||
|
|
||||||
// JS funcs
|
// JS funcs
|
||||||
@@ -262,6 +274,13 @@ pub fn testExecFn(
|
|||||||
.{ .src = "newdoc.children.length", .ex = "0" },
|
.{ .src = "newdoc.children.length", .ex = "0" },
|
||||||
.{ .src = "newdoc.getElementsByTagName('*').length", .ex = "0" },
|
.{ .src = "newdoc.getElementsByTagName('*').length", .ex = "0" },
|
||||||
.{ .src = "newdoc.getElementsByTagName('*').item(0)", .ex = "null" },
|
.{ .src = "newdoc.getElementsByTagName('*').item(0)", .ex = "null" },
|
||||||
|
.{ .src = "newdoc.inputEncoding === document.inputEncoding", .ex = "true" },
|
||||||
|
.{ .src = "newdoc.documentURI === document.documentURI", .ex = "true" },
|
||||||
|
.{ .src = "newdoc.URL === document.URL", .ex = "true" },
|
||||||
|
.{ .src = "newdoc.compatMode === document.compatMode", .ex = "true" },
|
||||||
|
.{ .src = "newdoc.characterSet === document.characterSet", .ex = "true" },
|
||||||
|
.{ .src = "newdoc.charset === document.charset", .ex = "true" },
|
||||||
|
.{ .src = "newdoc.contentType === document.contentType", .ex = "true" },
|
||||||
};
|
};
|
||||||
try checkCases(js_env, &constructor);
|
try checkCases(js_env, &constructor);
|
||||||
|
|
||||||
|
|||||||
@@ -20,20 +20,37 @@ const std = @import("std");
|
|||||||
|
|
||||||
const parser = @import("../netsurf.zig");
|
const parser = @import("../netsurf.zig");
|
||||||
|
|
||||||
|
const jsruntime = @import("jsruntime");
|
||||||
|
const Case = jsruntime.test_utils.Case;
|
||||||
|
const checkCases = jsruntime.test_utils.checkCases;
|
||||||
|
|
||||||
const Node = @import("node.zig").Node;
|
const Node = @import("node.zig").Node;
|
||||||
|
|
||||||
|
const UserContext = @import("../user_context.zig").UserContext;
|
||||||
|
|
||||||
// WEB IDL https://dom.spec.whatwg.org/#documentfragment
|
// WEB IDL https://dom.spec.whatwg.org/#documentfragment
|
||||||
pub const DocumentFragment = struct {
|
pub const DocumentFragment = struct {
|
||||||
pub const Self = parser.DocumentFragment;
|
pub const Self = parser.DocumentFragment;
|
||||||
pub const prototype = *Node;
|
pub const prototype = *Node;
|
||||||
pub const mem_guarantied = true;
|
pub const mem_guarantied = true;
|
||||||
|
|
||||||
// TODO add constructor, but I need to associate the new DocumentFragment
|
pub fn constructor(userctx: UserContext) !*parser.DocumentFragment {
|
||||||
// with the current document global object...
|
return parser.documentCreateDocumentFragment(
|
||||||
// > The new DocumentFragment() constructor steps are to set this’s node
|
parser.documentHTMLToDocument(userctx.document),
|
||||||
// > document to current global object’s associated Document.
|
);
|
||||||
// https://dom.spec.whatwg.org/#dom-documentfragment-documentfragment
|
|
||||||
pub fn constructor() !*parser.DocumentFragment {
|
|
||||||
return error.NotImplemented;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Tests
|
||||||
|
// -----
|
||||||
|
|
||||||
|
pub fn testExecFn(
|
||||||
|
_: std.mem.Allocator,
|
||||||
|
js_env: *jsruntime.Env,
|
||||||
|
) anyerror!void {
|
||||||
|
var constructor = [_]Case{
|
||||||
|
.{ .src = "const dc = new DocumentFragment()", .ex = "undefined" },
|
||||||
|
.{ .src = "dc.constructor.name", .ex = "DocumentFragment" },
|
||||||
|
};
|
||||||
|
try checkCases(js_env, &constructor);
|
||||||
|
}
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ pub const DOMImplementation = struct {
|
|||||||
return try parser.domImplementationCreateDocument(cnamespace, cqname, doctype);
|
return try parser.domImplementationCreateDocument(cnamespace, cqname, doctype);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn _createHTMLDocument(_: *DOMImplementation, title: ?[]const u8) !*parser.Document {
|
pub fn _createHTMLDocument(_: *DOMImplementation, title: ?[]const u8) !*parser.DocumentHTML {
|
||||||
return try parser.domImplementationCreateHTMLDocument(title);
|
return try parser.domImplementationCreateHTMLDocument(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +95,8 @@ pub fn testExecFn(
|
|||||||
) anyerror!void {
|
) anyerror!void {
|
||||||
var getImplementation = [_]Case{
|
var getImplementation = [_]Case{
|
||||||
.{ .src = "let impl = document.implementation", .ex = "undefined" },
|
.{ .src = "let impl = document.implementation", .ex = "undefined" },
|
||||||
.{ .src = "impl.createHTMLDocument();", .ex = "[object Document]" },
|
.{ .src = "impl.createHTMLDocument();", .ex = "[object HTMLDocument]" },
|
||||||
|
.{ .src = "impl.createHTMLDocument('foo');", .ex = "[object HTMLDocument]" },
|
||||||
.{ .src = "impl.createDocument(null, 'foo');", .ex = "[object Document]" },
|
.{ .src = "impl.createDocument(null, 'foo');", .ex = "[object Document]" },
|
||||||
.{ .src = "impl.createDocumentType('foo', 'bar', 'baz')", .ex = "[object DocumentType]" },
|
.{ .src = "impl.createDocumentType('foo', 'bar', 'baz')", .ex = "[object DocumentType]" },
|
||||||
.{ .src = "impl.hasFeature()", .ex = "true" },
|
.{ .src = "impl.hasFeature()", .ex = "true" },
|
||||||
|
|||||||
@@ -277,14 +277,30 @@ pub const Node = struct {
|
|||||||
return try Node.toInterface(res);
|
return try Node.toInterface(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the hierarchy node tree constraints are respected.
|
||||||
|
// For now, it checks only if new nodes are not self.
|
||||||
|
// TODO implements the others contraints.
|
||||||
|
// see https://dom.spec.whatwg.org/#concept-node-tree
|
||||||
|
pub fn hierarchy(self: *parser.Node, nodes: ?Variadic(*parser.Node)) !bool {
|
||||||
|
if (nodes == null) return true;
|
||||||
|
if (nodes.?.slice.len == 0) return true;
|
||||||
|
|
||||||
|
for (nodes.?.slice) |node| if (self == node) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO according with https://dom.spec.whatwg.org/#parentnode, the
|
// TODO according with https://dom.spec.whatwg.org/#parentnode, the
|
||||||
// function must accept either node or string.
|
// function must accept either node or string.
|
||||||
// blocked by https://github.com/lightpanda-io/jsruntime-lib/issues/114
|
// blocked by https://github.com/lightpanda-io/jsruntime-lib/issues/114
|
||||||
pub fn prepend(self: *parser.Node, nodes: ?Variadic(*parser.Node)) !void {
|
pub fn prepend(self: *parser.Node, nodes: ?Variadic(*parser.Node)) !void {
|
||||||
if (nodes == null) return;
|
if (nodes == null) return;
|
||||||
if (nodes.?.slice.len == 0) return;
|
if (nodes.?.slice.len == 0) return;
|
||||||
const first = try parser.nodeFirstChild(self);
|
|
||||||
|
|
||||||
|
// check hierarchy
|
||||||
|
if (!try hierarchy(self, nodes)) return parser.DOMError.HierarchyRequest;
|
||||||
|
|
||||||
|
const first = try parser.nodeFirstChild(self);
|
||||||
if (first == null) {
|
if (first == null) {
|
||||||
for (nodes.?.slice) |node| {
|
for (nodes.?.slice) |node| {
|
||||||
_ = try parser.nodeAppendChild(self, node);
|
_ = try parser.nodeAppendChild(self, node);
|
||||||
@@ -303,6 +319,10 @@ pub const Node = struct {
|
|||||||
pub fn append(self: *parser.Node, nodes: ?Variadic(*parser.Node)) !void {
|
pub fn append(self: *parser.Node, nodes: ?Variadic(*parser.Node)) !void {
|
||||||
if (nodes == null) return;
|
if (nodes == null) return;
|
||||||
if (nodes.?.slice.len == 0) return;
|
if (nodes.?.slice.len == 0) return;
|
||||||
|
|
||||||
|
// check hierarchy
|
||||||
|
if (!try hierarchy(self, nodes)) return parser.DOMError.HierarchyRequest;
|
||||||
|
|
||||||
for (nodes.?.slice) |node| {
|
for (nodes.?.slice) |node| {
|
||||||
_ = try parser.nodeAppendChild(self, node);
|
_ = try parser.nodeAppendChild(self, node);
|
||||||
}
|
}
|
||||||
@@ -312,12 +332,15 @@ pub const Node = struct {
|
|||||||
// function must accept either node or string.
|
// function must accept either node or string.
|
||||||
// blocked by https://github.com/lightpanda-io/jsruntime-lib/issues/114
|
// blocked by https://github.com/lightpanda-io/jsruntime-lib/issues/114
|
||||||
pub fn replaceChildren(self: *parser.Node, nodes: ?Variadic(*parser.Node)) !void {
|
pub fn replaceChildren(self: *parser.Node, nodes: ?Variadic(*parser.Node)) !void {
|
||||||
// remove existing children
|
|
||||||
try removeChildren(self);
|
|
||||||
|
|
||||||
if (nodes == null) return;
|
if (nodes == null) return;
|
||||||
if (nodes.?.slice.len == 0) return;
|
if (nodes.?.slice.len == 0) return;
|
||||||
|
|
||||||
|
// check hierarchy
|
||||||
|
if (!try hierarchy(self, nodes)) return parser.DOMError.HierarchyRequest;
|
||||||
|
|
||||||
|
// remove existing children
|
||||||
|
try removeChildren(self);
|
||||||
|
|
||||||
// add new children
|
// add new children
|
||||||
for (nodes.?.slice) |node| {
|
for (nodes.?.slice) |node| {
|
||||||
_ = try parser.nodeAppendChild(self, node);
|
_ = try parser.nodeAppendChild(self, node);
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ const parser = @import("../netsurf.zig");
|
|||||||
const CharacterData = @import("character_data.zig").CharacterData;
|
const CharacterData = @import("character_data.zig").CharacterData;
|
||||||
const CDATASection = @import("cdata_section.zig").CDATASection;
|
const CDATASection = @import("cdata_section.zig").CDATASection;
|
||||||
|
|
||||||
|
const UserContext = @import("../user_context.zig").UserContext;
|
||||||
|
|
||||||
// Text interfaces
|
// Text interfaces
|
||||||
pub const Interfaces = generate.Tuple(.{
|
pub const Interfaces = generate.Tuple(.{
|
||||||
CDATASection,
|
CDATASection,
|
||||||
@@ -38,6 +40,13 @@ pub const Text = struct {
|
|||||||
pub const prototype = *CharacterData;
|
pub const prototype = *CharacterData;
|
||||||
pub const mem_guarantied = true;
|
pub const mem_guarantied = true;
|
||||||
|
|
||||||
|
pub fn constructor(userctx: UserContext, data: ?[]const u8) !*parser.Text {
|
||||||
|
return parser.documentCreateTextNode(
|
||||||
|
parser.documentHTMLToDocument(userctx.document),
|
||||||
|
data orelse "",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// JS funcs
|
// JS funcs
|
||||||
// --------
|
// --------
|
||||||
|
|
||||||
@@ -62,6 +71,15 @@ pub fn testExecFn(
|
|||||||
_: std.mem.Allocator,
|
_: std.mem.Allocator,
|
||||||
js_env: *jsruntime.Env,
|
js_env: *jsruntime.Env,
|
||||||
) anyerror!void {
|
) anyerror!void {
|
||||||
|
var constructor = [_]Case{
|
||||||
|
.{ .src = "let t = new Text('foo')", .ex = "undefined" },
|
||||||
|
.{ .src = "t.data", .ex = "foo" },
|
||||||
|
|
||||||
|
.{ .src = "let emptyt = new Text()", .ex = "undefined" },
|
||||||
|
.{ .src = "emptyt.data", .ex = "" },
|
||||||
|
};
|
||||||
|
try checkCases(js_env, &constructor);
|
||||||
|
|
||||||
var get_whole_text = [_]Case{
|
var get_whole_text = [_]Case{
|
||||||
.{ .src = "let text = document.getElementById('link').firstChild", .ex = "undefined" },
|
.{ .src = "let text = document.getElementById('link').firstChild", .ex = "undefined" },
|
||||||
.{ .src = "text.wholeText === 'OK'", .ex = "true" },
|
.{ .src = "text.wholeText === 'OK'", .ex = "true" },
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ const apiweb = @import("apiweb.zig");
|
|||||||
const Window = @import("html/window.zig").Window;
|
const Window = @import("html/window.zig").Window;
|
||||||
|
|
||||||
pub const Types = jsruntime.reflect(apiweb.Interfaces);
|
pub const Types = jsruntime.reflect(apiweb.Interfaces);
|
||||||
|
pub const UserContext = apiweb.UserContext;
|
||||||
|
|
||||||
const socket_path = "/tmp/browsercore-server.sock";
|
const socket_path = "/tmp/browsercore-server.sock";
|
||||||
|
|
||||||
@@ -103,5 +104,5 @@ pub fn main() !void {
|
|||||||
try server.listen(addr);
|
try server.listen(addr);
|
||||||
std.debug.print("Listening on: {s}...\n", .{socket_path});
|
std.debug.print("Listening on: {s}...\n", .{socket_path});
|
||||||
|
|
||||||
try jsruntime.loadEnv(&arena, execJS);
|
try jsruntime.loadEnv(&arena, null, execJS);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ const jsruntime = @import("jsruntime");
|
|||||||
const apiweb = @import("apiweb.zig");
|
const apiweb = @import("apiweb.zig");
|
||||||
|
|
||||||
pub const Types = jsruntime.reflect(apiweb.Interfaces);
|
pub const Types = jsruntime.reflect(apiweb.Interfaces);
|
||||||
|
pub const UserContext = apiweb.UserContext;
|
||||||
|
|
||||||
pub const std_options = struct {
|
pub const std_options = struct {
|
||||||
pub const log_level = .debug;
|
pub const log_level = .debug;
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ const storage = @import("storage/storage.zig");
|
|||||||
const html_test = @import("html_test.zig").html;
|
const html_test = @import("html_test.zig").html;
|
||||||
|
|
||||||
pub const Types = jsruntime.reflect(apiweb.Interfaces);
|
pub const Types = jsruntime.reflect(apiweb.Interfaces);
|
||||||
|
pub const UserContext = apiweb.UserContext;
|
||||||
|
const Client = @import("async/Client.zig");
|
||||||
|
|
||||||
var doc: *parser.DocumentHTML = undefined;
|
var doc: *parser.DocumentHTML = undefined;
|
||||||
|
|
||||||
@@ -39,6 +41,14 @@ fn execJS(
|
|||||||
try js_env.start(alloc);
|
try js_env.start(alloc);
|
||||||
defer js_env.stop();
|
defer js_env.stop();
|
||||||
|
|
||||||
|
var cli = Client{ .allocator = alloc, .loop = js_env.nat_ctx.loop };
|
||||||
|
defer cli.deinit();
|
||||||
|
|
||||||
|
try js_env.setUserContext(UserContext{
|
||||||
|
.document = doc,
|
||||||
|
.httpClient = &cli,
|
||||||
|
});
|
||||||
|
|
||||||
var storageShelf = storage.Shelf.init(alloc);
|
var storageShelf = storage.Shelf.init(alloc);
|
||||||
defer storageShelf.deinit();
|
defer storageShelf.deinit();
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ const Out = enum {
|
|||||||
|
|
||||||
pub const Types = jsruntime.reflect(apiweb.Interfaces);
|
pub const Types = jsruntime.reflect(apiweb.Interfaces);
|
||||||
pub const GlobalType = apiweb.GlobalType;
|
pub const GlobalType = apiweb.GlobalType;
|
||||||
|
pub const UserContext = apiweb.UserContext;
|
||||||
|
|
||||||
// TODO For now the WPT tests run is specific to WPT.
|
// TODO For now the WPT tests run is specific to WPT.
|
||||||
// It manually load js framwork libs, and run the first script w/ js content in
|
// It manually load js framwork libs, and run the first script w/ js content in
|
||||||
|
|||||||
@@ -1763,21 +1763,29 @@ pub inline fn domImplementationCreateDocumentType(
|
|||||||
return dt.?;
|
return dt.?;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub inline fn domImplementationCreateHTMLDocument(title: ?[]const u8) !*Document {
|
pub inline fn domImplementationCreateHTMLDocument(title: ?[]const u8) !*DocumentHTML {
|
||||||
var doc: ?*Document = undefined;
|
const doc_html = try documentCreateDocument(title);
|
||||||
const err = c.dom_implementation_create_document(
|
const doc = documentHTMLToDocument(doc_html);
|
||||||
c.DOM_IMPLEMENTATION_HTML,
|
|
||||||
null,
|
// add hierarchy: html, head, body.
|
||||||
null,
|
const html = try documentCreateElement(doc, "html");
|
||||||
null,
|
_ = try nodeAppendChild(documentToNode(doc), elementToNode(html));
|
||||||
null,
|
|
||||||
null,
|
const head = try documentCreateElement(doc, "head");
|
||||||
&doc,
|
_ = try nodeAppendChild(elementToNode(html), elementToNode(head));
|
||||||
);
|
|
||||||
try DOMErr(err);
|
if (title) |t| {
|
||||||
// TODO set title
|
try documentHTMLSetTitle(doc_html, t);
|
||||||
_ = title;
|
const htitle = try documentCreateElement(doc, "title");
|
||||||
return doc.?;
|
const txt = try documentCreateTextNode(doc, t);
|
||||||
|
_ = try nodeAppendChild(elementToNode(htitle), @as(*Node, @ptrCast(txt)));
|
||||||
|
_ = try nodeAppendChild(elementToNode(head), elementToNode(htitle));
|
||||||
|
}
|
||||||
|
|
||||||
|
const body = try documentCreateElement(doc, "body");
|
||||||
|
_ = try nodeAppendChild(elementToNode(html), elementToNode(body));
|
||||||
|
|
||||||
|
return doc_html;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Document
|
// Document
|
||||||
@@ -1833,6 +1841,28 @@ pub inline fn documentGetInputEncoding(doc: *Document) ![]const u8 {
|
|||||||
return strToData(s.?);
|
return strToData(s.?);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub inline fn documentSetInputEncoding(doc: *Document, enc: []const u8) !void {
|
||||||
|
const err = documentVtable(doc).dom_document_set_input_encoding.?(doc, try strFromData(enc));
|
||||||
|
try DOMErr(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn documentCreateDocument(title: ?[]const u8) !*DocumentHTML {
|
||||||
|
var doc: ?*Document = undefined;
|
||||||
|
const err = c.dom_implementation_create_document(
|
||||||
|
c.DOM_IMPLEMENTATION_HTML,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
&doc,
|
||||||
|
);
|
||||||
|
try DOMErr(err);
|
||||||
|
const doc_html = @as(*DocumentHTML, @ptrCast(doc.?));
|
||||||
|
if (title) |t| try documentHTMLSetTitle(doc_html, t);
|
||||||
|
return doc_html;
|
||||||
|
}
|
||||||
|
|
||||||
pub inline fn documentCreateElement(doc: *Document, tag_name: []const u8) !*Element {
|
pub inline fn documentCreateElement(doc: *Document, tag_name: []const u8) !*Element {
|
||||||
var elem: ?*Element = undefined;
|
var elem: ?*Element = undefined;
|
||||||
const err = documentVtable(doc).dom_document_create_element.?(doc, try strFromData(tag_name), &elem);
|
const err = documentVtable(doc).dom_document_create_element.?(doc, try strFromData(tag_name), &elem);
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ const xhr = @import("xhr/xhr.zig");
|
|||||||
const storage = @import("storage/storage.zig");
|
const storage = @import("storage/storage.zig");
|
||||||
const url = @import("url/url.zig");
|
const url = @import("url/url.zig");
|
||||||
const urlquery = @import("url/query.zig");
|
const urlquery = @import("url/query.zig");
|
||||||
|
const Client = @import("async/Client.zig");
|
||||||
|
|
||||||
const documentTestExecFn = @import("dom/document.zig").testExecFn;
|
const documentTestExecFn = @import("dom/document.zig").testExecFn;
|
||||||
const HTMLDocumentTestExecFn = @import("html/document.zig").testExecFn;
|
const HTMLDocumentTestExecFn = @import("html/document.zig").testExecFn;
|
||||||
@@ -46,6 +47,8 @@ const NodeListTestExecFn = @import("dom/nodelist.zig").testExecFn;
|
|||||||
const AttrTestExecFn = @import("dom/attribute.zig").testExecFn;
|
const AttrTestExecFn = @import("dom/attribute.zig").testExecFn;
|
||||||
const EventTargetTestExecFn = @import("dom/event_target.zig").testExecFn;
|
const EventTargetTestExecFn = @import("dom/event_target.zig").testExecFn;
|
||||||
const ProcessingInstructionTestExecFn = @import("dom/processing_instruction.zig").testExecFn;
|
const ProcessingInstructionTestExecFn = @import("dom/processing_instruction.zig").testExecFn;
|
||||||
|
const CommentTestExecFn = @import("dom/comment.zig").testExecFn;
|
||||||
|
const DocumentFragmentTestExecFn = @import("dom/document_fragment.zig").testExecFn;
|
||||||
const EventTestExecFn = @import("events/event.zig").testExecFn;
|
const EventTestExecFn = @import("events/event.zig").testExecFn;
|
||||||
const XHRTestExecFn = xhr.testExecFn;
|
const XHRTestExecFn = xhr.testExecFn;
|
||||||
const ProgressEventTestExecFn = @import("xhr/progress_event.zig").testExecFn;
|
const ProgressEventTestExecFn = @import("xhr/progress_event.zig").testExecFn;
|
||||||
@@ -54,6 +57,7 @@ const URLTestExecFn = url.testExecFn;
|
|||||||
const HTMLElementTestExecFn = @import("html/elements.zig").testExecFn;
|
const HTMLElementTestExecFn = @import("html/elements.zig").testExecFn;
|
||||||
|
|
||||||
pub const Types = jsruntime.reflect(apiweb.Interfaces);
|
pub const Types = jsruntime.reflect(apiweb.Interfaces);
|
||||||
|
pub const UserContext = @import("user_context.zig").UserContext;
|
||||||
|
|
||||||
var doc: *parser.DocumentHTML = undefined;
|
var doc: *parser.DocumentHTML = undefined;
|
||||||
|
|
||||||
@@ -81,6 +85,14 @@ fn testExecFn(
|
|||||||
std.debug.print("documentHTMLClose error: {s}\n", .{@errorName(err)});
|
std.debug.print("documentHTMLClose error: {s}\n", .{@errorName(err)});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var cli = Client{ .allocator = alloc, .loop = js_env.nat_ctx.loop };
|
||||||
|
defer cli.deinit();
|
||||||
|
|
||||||
|
try js_env.setUserContext(.{
|
||||||
|
.document = doc,
|
||||||
|
.httpClient = &cli,
|
||||||
|
});
|
||||||
|
|
||||||
// alias global as self and window
|
// alias global as self and window
|
||||||
var window = Window.create(null);
|
var window = Window.create(null);
|
||||||
|
|
||||||
@@ -111,6 +123,8 @@ fn testsAllExecFn(
|
|||||||
DOMTokenListExecFn,
|
DOMTokenListExecFn,
|
||||||
NodeListTestExecFn,
|
NodeListTestExecFn,
|
||||||
AttrTestExecFn,
|
AttrTestExecFn,
|
||||||
|
CommentTestExecFn,
|
||||||
|
DocumentFragmentTestExecFn,
|
||||||
EventTargetTestExecFn,
|
EventTargetTestExecFn,
|
||||||
EventTestExecFn,
|
EventTestExecFn,
|
||||||
XHRTestExecFn,
|
XHRTestExecFn,
|
||||||
@@ -315,7 +329,7 @@ fn testJSRuntime(alloc: std.mem.Allocator) !void {
|
|||||||
var arena_alloc = std.heap.ArenaAllocator.init(alloc);
|
var arena_alloc = std.heap.ArenaAllocator.init(alloc);
|
||||||
defer arena_alloc.deinit();
|
defer arena_alloc.deinit();
|
||||||
|
|
||||||
try jsruntime.loadEnv(&arena_alloc, testsAllExecFn);
|
try jsruntime.loadEnv(&arena_alloc, null, testsAllExecFn);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "DocumentHTMLParseFromStr" {
|
test "DocumentHTMLParseFromStr" {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ const std = @import("std");
|
|||||||
const tests = @import("run_tests.zig");
|
const tests = @import("run_tests.zig");
|
||||||
|
|
||||||
pub const Types = tests.Types;
|
pub const Types = tests.Types;
|
||||||
|
pub const UserContext = tests.UserContext;
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
try tests.main();
|
try tests.main();
|
||||||
|
|||||||
8
src/user_context.zig
Normal file
8
src/user_context.zig
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const parser = @import("netsurf.zig");
|
||||||
|
const Client = @import("async/Client.zig");
|
||||||
|
|
||||||
|
pub const UserContext = struct {
|
||||||
|
document: *parser.DocumentHTML,
|
||||||
|
httpClient: *Client,
|
||||||
|
};
|
||||||
@@ -30,6 +30,8 @@ const Window = @import("../html/window.zig").Window;
|
|||||||
const storage = @import("../storage/storage.zig");
|
const storage = @import("../storage/storage.zig");
|
||||||
|
|
||||||
const Types = @import("../main_wpt.zig").Types;
|
const Types = @import("../main_wpt.zig").Types;
|
||||||
|
const UserContext = @import("../main_wpt.zig").UserContext;
|
||||||
|
const Client = @import("../async/Client.zig");
|
||||||
|
|
||||||
// runWPT parses the given HTML file, starts a js env and run the first script
|
// runWPT parses the given HTML file, starts a js env and run the first script
|
||||||
// tags containing javascript sources.
|
// tags containing javascript sources.
|
||||||
@@ -50,7 +52,14 @@ pub fn run(arena: *std.heap.ArenaAllocator, comptime dir: []const u8, f: []const
|
|||||||
// create JS env
|
// create JS env
|
||||||
var loop = try Loop.init(alloc);
|
var loop = try Loop.init(alloc);
|
||||||
defer loop.deinit();
|
defer loop.deinit();
|
||||||
var js_env = try Env.init(alloc, &loop);
|
|
||||||
|
var cli = Client{ .allocator = alloc, .loop = &loop };
|
||||||
|
defer cli.deinit();
|
||||||
|
|
||||||
|
var js_env = try Env.init(alloc, &loop, UserContext{
|
||||||
|
.document = html_doc,
|
||||||
|
.httpClient = &cli,
|
||||||
|
});
|
||||||
defer js_env.deinit();
|
defer js_env.deinit();
|
||||||
|
|
||||||
var storageShelf = storage.Shelf.init(alloc);
|
var storageShelf = storage.Shelf.init(alloc);
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ const Client = @import("../async/Client.zig");
|
|||||||
|
|
||||||
const parser = @import("../netsurf.zig");
|
const parser = @import("../netsurf.zig");
|
||||||
|
|
||||||
|
const UserContext = @import("../user_context.zig").UserContext;
|
||||||
|
|
||||||
const log = std.log.scoped(.xhr);
|
const log = std.log.scoped(.xhr);
|
||||||
|
|
||||||
// XHR interfaces
|
// XHR interfaces
|
||||||
@@ -149,7 +151,7 @@ pub const XMLHttpRequest = struct {
|
|||||||
|
|
||||||
proto: XMLHttpRequestEventTarget = XMLHttpRequestEventTarget{},
|
proto: XMLHttpRequestEventTarget = XMLHttpRequestEventTarget{},
|
||||||
alloc: std.mem.Allocator,
|
alloc: std.mem.Allocator,
|
||||||
cli: Client,
|
cli: *Client,
|
||||||
impl: YieldImpl,
|
impl: YieldImpl,
|
||||||
|
|
||||||
priv_state: PrivState = .new,
|
priv_state: PrivState = .new,
|
||||||
@@ -185,7 +187,7 @@ pub const XMLHttpRequest = struct {
|
|||||||
|
|
||||||
const min_delay: u64 = 50000000; // 50ms
|
const min_delay: u64 = 50000000; // 50ms
|
||||||
|
|
||||||
pub fn constructor(alloc: std.mem.Allocator, loop: *Loop) !XMLHttpRequest {
|
pub fn constructor(alloc: std.mem.Allocator, loop: *Loop, userctx: UserContext) !XMLHttpRequest {
|
||||||
return .{
|
return .{
|
||||||
.alloc = alloc,
|
.alloc = alloc,
|
||||||
.headers = .{ .allocator = alloc, .owned = true },
|
.headers = .{ .allocator = alloc, .owned = true },
|
||||||
@@ -195,8 +197,7 @@ pub const XMLHttpRequest = struct {
|
|||||||
.url = null,
|
.url = null,
|
||||||
.uri = undefined,
|
.uri = undefined,
|
||||||
.state = UNSENT,
|
.state = UNSENT,
|
||||||
// TODO retrieve the HTTP client globally to reuse existing connections.
|
.cli = userctx.httpClient,
|
||||||
.cli = .{ .allocator = alloc, .loop = loop },
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,9 +236,6 @@ pub const XMLHttpRequest = struct {
|
|||||||
self.response_headers.deinit();
|
self.response_headers.deinit();
|
||||||
|
|
||||||
self.proto.deinit(alloc);
|
self.proto.deinit(alloc);
|
||||||
|
|
||||||
// TODO the client must be shared between requests.
|
|
||||||
self.cli.deinit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_readyState(self: *XMLHttpRequest) u16 {
|
pub fn get_readyState(self: *XMLHttpRequest) u16 {
|
||||||
|
|||||||
2
vendor/zig-js-runtime
vendored
2
vendor/zig-js-runtime
vendored
Submodule vendor/zig-js-runtime updated: fff1a6778d...d4a2eaefd8
Reference in New Issue
Block a user