diff --git a/src/browser/cssom/css_rule.zig b/src/browser/cssom/css_rule.zig new file mode 100644 index 000000000..857c0a8aa --- /dev/null +++ b/src/browser/cssom/css_rule.zig @@ -0,0 +1,42 @@ +// Copyright (C) 2023-2024 Lightpanda (Selecy SAS) +// +// Francis Bouvier +// Pierre Tachoire +// +// 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 . + +const std = @import("std"); + +const CSSStyleSheet = @import("css_stylesheet.zig").CSSStyleSheet; + +pub const Interfaces = .{ + CSSRule, + CSSImportRule, +}; + +// https://developer.mozilla.org/en-US/docs/Web/API/CSSRule +pub const CSSRule = struct { + css_text: []const u8, + parent_rule: ?*CSSRule = null, + parent_stylesheet: ?*CSSStyleSheet = null, +}; + +pub const CSSImportRule = struct { + pub const prototype = *CSSRule; + href: []const u8, + layer_name: ?[]const u8, + media: void, + style_sheet: CSSStyleSheet, + supports_text: ?[]const u8, +}; diff --git a/src/browser/cssom/css_rule_list.zig b/src/browser/cssom/css_rule_list.zig new file mode 100644 index 000000000..bf5222f28 --- /dev/null +++ b/src/browser/cssom/css_rule_list.zig @@ -0,0 +1,60 @@ +// Copyright (C) 2023-2024 Lightpanda (Selecy SAS) +// +// Francis Bouvier +// Pierre Tachoire +// +// 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 . + +const std = @import("std"); + +const StyleSheet = @import("stylesheet.zig").StyleSheet; +const CSSRule = @import("css_rule.zig").CSSRule; +const CSSImportRule = @import("css_rule.zig").CSSImportRule; + +pub const CSSRuleList = struct { + list: std.ArrayListUnmanaged([]const u8), + + pub fn constructor() CSSRuleList { + return .{ .list = .empty }; + } + + pub fn _item(self: *CSSRuleList, _index: u32) ?CSSRule { + const index: usize = @intCast(_index); + + if (index > self.list.items.len) { + return null; + } + + // todo: for now, just return null. + // this depends on properly parsing CSSRule + return null; + } + + pub fn get_length(self: *CSSRuleList) u32 { + return @intCast(self.list.items.len); + } +}; + +const testing = @import("../../testing.zig"); +test "Browser.CSS.CSSRuleList" { + var runner = try testing.jsRunner(testing.tracking_allocator, .{}); + defer runner.deinit(); + + try runner.testCases(&.{ + .{ "let list = new CSSRuleList()", "undefined" }, + .{ "list instanceof CSSRuleList", "true" }, + .{ "list.length", "0" }, + .{ "list.item(0)", "null" }, + }, .{}); +} diff --git a/src/browser/cssom/css_style_declaration.zig b/src/browser/cssom/css_style_declaration.zig index 98a9015d5..6ec1d880e 100644 --- a/src/browser/cssom/css_style_declaration.zig +++ b/src/browser/cssom/css_style_declaration.zig @@ -20,15 +20,9 @@ const std = @import("std"); const CSSParser = @import("./css_parser.zig").CSSParser; const CSSValueAnalyzer = @import("./css_value_analyzer.zig").CSSValueAnalyzer; +const CSSRule = @import("css_rule.zig").CSSRule; const Page = @import("../page.zig").Page; -pub const Interfaces = .{ - CSSStyleDeclaration, - CSSRule, -}; - -const CSSRule = struct {}; - pub const CSSStyleDeclaration = struct { store: std.StringHashMapUnmanaged(Property), order: std.ArrayListUnmanaged([]const u8), diff --git a/src/browser/cssom/css_stylesheet.zig b/src/browser/cssom/css_stylesheet.zig new file mode 100644 index 000000000..bb03d79cc --- /dev/null +++ b/src/browser/cssom/css_stylesheet.zig @@ -0,0 +1,91 @@ +// Copyright (C) 2023-2024 Lightpanda (Selecy SAS) +// +// Francis Bouvier +// Pierre Tachoire +// +// 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 . + +const std = @import("std"); + +const Page = @import("../page.zig").Page; +const StyleSheet = @import("stylesheet.zig").StyleSheet; + +const CSSRuleList = @import("css_rule_list.zig").CSSRuleList; +const CSSImportRule = @import("css_rule.zig").CSSImportRule; + +pub const CSSStyleSheet = struct { + pub const prototype = *StyleSheet; + + proto: StyleSheet, + css_rules: CSSRuleList, + owner_rule: ?*CSSImportRule, + + const CSSStyleSheetOpts = struct { + base_url: ?[]const u8 = null, + // TODO: Suupport media + disabled: bool = false, + }; + + pub fn constructor(_opts: ?CSSStyleSheetOpts) !CSSStyleSheet { + const opts = _opts orelse CSSStyleSheetOpts{}; + return .{ + .proto = StyleSheet{ .disabled = opts.disabled }, + .css_rules = .constructor(), + .owner_rule = null, + }; + } + + pub fn get_ownerRule(_: *CSSStyleSheet) ?*CSSImportRule { + return null; + } + + pub fn get_cssRules(self: *CSSStyleSheet) *CSSRuleList { + return &self.css_rules; + } + + pub fn _insertRule(self: *CSSStyleSheet, rule: []const u8, _index: ?usize, page: *Page) !usize { + const index = _index orelse 0; + if (index > self.css_rules.list.items.len) { + return error.IndexSize; + } + + const arena = page.arena; + try self.css_rules.list.insert(arena, index, try arena.dupe(u8, rule)); + return index; + } + + pub fn _deleteRule(self: *CSSStyleSheet, index: usize) !void { + if (index > self.css_rules.list.items.len) { + return error.IndexSize; + } + + _ = self.css_rules.list.orderedRemove(index); + } +}; + +const testing = @import("../../testing.zig"); +test "Browser.CSS.StyleSheet" { + var runner = try testing.jsRunner(testing.tracking_allocator, .{}); + defer runner.deinit(); + + try runner.testCases(&.{ + .{ "let css = new CSSStyleSheet()", "undefined" }, + .{ "css instanceof CSSStyleSheet", "true" }, + .{ "css.cssRules.length", "0" }, + .{ "css.ownerRule", "null" }, + .{ "let index1 = css.insertRule('body { color: red; }', 0)", "undefined" }, + .{ "index1", "0" }, + .{ "css.cssRules.length", "1" }, + }, .{}); +} diff --git a/src/browser/cssom/cssom.zig b/src/browser/cssom/cssom.zig new file mode 100644 index 000000000..ffd2eabb3 --- /dev/null +++ b/src/browser/cssom/cssom.zig @@ -0,0 +1,30 @@ +// Copyright (C) 2023-2024 Lightpanda (Selecy SAS) +// +// Francis Bouvier +// Pierre Tachoire +// +// 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 . + +pub const Stylesheet = @import("stylesheet.zig").StyleSheet; +pub const CSSStylesheet = @import("css_stylesheet.zig").CSSStyleSheet; +pub const CSSStyleDeclaration = @import("css_style_declaration.zig").CSSStyleDeclaration; +pub const CSSRuleList = @import("css_rule_list.zig").CSSRuleList; + +pub const Interfaces = .{ + Stylesheet, + CSSStylesheet, + CSSStyleDeclaration, + CSSRuleList, + @import("css_rule.zig").Interfaces, +}; diff --git a/src/browser/cssom/stylesheet.zig b/src/browser/cssom/stylesheet.zig new file mode 100644 index 000000000..7086063ce --- /dev/null +++ b/src/browser/cssom/stylesheet.zig @@ -0,0 +1,55 @@ +// Copyright (C) 2023-2024 Lightpanda (Selecy SAS) +// +// Francis Bouvier +// Pierre Tachoire +// +// 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 . + +const parser = @import("../netsurf.zig"); + +// https://developer.mozilla.org/en-US/docs/Web/API/StyleSheet#specifications +pub const StyleSheet = struct { + disabled: bool = false, + href: []const u8 = "", + owner_node: ?*parser.Node = null, + parent_stylesheet: ?*StyleSheet = null, + title: []const u8 = "", + type: []const u8 = "text/css", + + pub fn get_disabled(self: *const StyleSheet) bool { + return self.disabled; + } + + pub fn get_href(self: *const StyleSheet) []const u8 { + return self.href; + } + + // TODO: media + + pub fn get_ownerNode(self: *const StyleSheet) ?*parser.Node { + return self.owner_node; + } + + pub fn get_parentStyleSheet(self: *const StyleSheet) ?*StyleSheet { + return self.parent_stylesheet; + } + + pub fn get_title(self: *const StyleSheet) []const u8 { + return self.title; + } + + pub fn get_type(self: *const StyleSheet) []const u8 { + return self.type; + } +}; diff --git a/src/browser/env.zig b/src/browser/env.zig index 806391e5e..aa03c9be6 100644 --- a/src/browser/env.zig +++ b/src/browser/env.zig @@ -22,7 +22,7 @@ const WebApis = struct { pub const Interfaces = generate.Tuple(.{ @import("crypto/crypto.zig").Crypto, @import("console/console.zig").Console, - @import("cssom/css_style_declaration.zig").Interfaces, + @import("cssom/cssom.zig").Interfaces, @import("dom/dom.zig").Interfaces, @import("encoding/text_encoder.zig").Interfaces, @import("events/event.zig").Interfaces, diff --git a/src/cdp/cdp.zig b/src/cdp/cdp.zig index ed3388a4e..275440639 100644 --- a/src/cdp/cdp.zig +++ b/src/cdp/cdp.zig @@ -320,6 +320,7 @@ pub fn BrowserContext(comptime CDP_T: type) type { inspector: Inspector, isolated_world: ?IsolatedWorld, + http_proxy_before: ??std.Uri = null, const Self = @This(); @@ -374,6 +375,8 @@ pub fn BrowserContext(comptime CDP_T: type) type { self.node_registry.deinit(); self.node_search_list.deinit(); self.cdp.browser.notification.unregisterAll(self); + + if (self.http_proxy_before) |prev_proxy| self.cdp.browser.http_client.http_proxy = prev_proxy; } pub fn reset(self: *Self) void { diff --git a/src/cdp/domains/target.zig b/src/cdp/domains/target.zig index c0d76ec00..5b2a4f736 100644 --- a/src/cdp/domains/target.zig +++ b/src/cdp/domains/target.zig @@ -66,11 +66,30 @@ fn getBrowserContexts(cmd: anytype) !void { } fn createBrowserContext(cmd: anytype) !void { + const params = try cmd.params(struct { + disposeOnDetach: bool = false, + proxyServer: ?[]const u8 = null, + proxyBypassList: ?[]const u8 = null, + originsWithUniversalNetworkAccess: ?[]const []const u8 = null, + }); + if (params) |p| { + if (p.disposeOnDetach or p.proxyBypassList != null or p.originsWithUniversalNetworkAccess != null) std.debug.print("Target.createBrowserContext: Not implemented param set\n", .{}); + } + const bc = cmd.createBrowserContext() catch |err| switch (err) { error.AlreadyExists => return cmd.sendError(-32000, "Cannot have more than one browser context at a time"), else => return err, }; + if (params) |p| { + if (p.proxyServer) |proxy| { + // For now the http client is not in the browser context so we assume there is just 1. + bc.http_proxy_before = cmd.cdp.browser.http_client.http_proxy; + const proxy_cp = try cmd.cdp.browser.http_client.allocator.dupe(u8, proxy); + cmd.cdp.browser.http_client.http_proxy = try std.Uri.parse(proxy_cp); + } + } + return cmd.sendResult(.{ .browserContextId = bc.id, }, .{});