mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-02-04 14:33:47 +00:00
DOMRect constructor
More default computed styles (color and backgroundColor) HTMLMetaElement properties Case-insensitive findAdjacentNodes position parameter Allow computedStyle pseudo_element parameter (ignore, log not implemented) Window.isSecureContext always returns false
This commit is contained in:
@@ -18,16 +18,23 @@
|
|||||||
|
|
||||||
const DOMRect = @This();
|
const DOMRect = @This();
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
const js = @import("../js/js.zig");
|
const js = @import("../js/js.zig");
|
||||||
|
const Page = @import("../Page.zig");
|
||||||
|
|
||||||
_x: f64,
|
_x: f64,
|
||||||
_y: f64,
|
_y: f64,
|
||||||
_width: f64,
|
_width: f64,
|
||||||
_height: f64,
|
_height: f64,
|
||||||
_top: f64,
|
|
||||||
_right: f64,
|
pub fn init(x: f64, y: f64, width: f64, height: f64, page: *Page) !*DOMRect {
|
||||||
_bottom: f64,
|
return page._factory.create(DOMRect{
|
||||||
_left: f64,
|
._x = x,
|
||||||
|
._y = y,
|
||||||
|
._width = width,
|
||||||
|
._height = height,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pub fn getX(self: *DOMRect) f64 {
|
pub fn getX(self: *DOMRect) f64 {
|
||||||
return self._x;
|
return self._x;
|
||||||
@@ -46,19 +53,19 @@ pub fn getHeight(self: *DOMRect) f64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn getTop(self: *DOMRect) f64 {
|
pub fn getTop(self: *DOMRect) f64 {
|
||||||
return self._top;
|
return @min(self._y, self._y + self._height);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getRight(self: *DOMRect) f64 {
|
pub fn getRight(self: *DOMRect) f64 {
|
||||||
return self._right;
|
return @max(self._x, self._x + self._width);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getBottom(self: *DOMRect) f64 {
|
pub fn getBottom(self: *DOMRect) f64 {
|
||||||
return self._bottom;
|
return @max(self._y, self._y + self._height);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getLeft(self: *DOMRect) f64 {
|
pub fn getLeft(self: *DOMRect) f64 {
|
||||||
return self._left;
|
return @min(self._x, self._x + self._width);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const JsApi = struct {
|
pub const JsApi = struct {
|
||||||
@@ -70,6 +77,7 @@ pub const JsApi = struct {
|
|||||||
pub var class_id: bridge.ClassId = undefined;
|
pub var class_id: bridge.ClassId = undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const constructor = bridge.constructor(DOMRect.init, .{});
|
||||||
pub const x = bridge.accessor(DOMRect.getX, null, .{});
|
pub const x = bridge.accessor(DOMRect.getX, null, .{});
|
||||||
pub const y = bridge.accessor(DOMRect.getY, null, .{});
|
pub const y = bridge.accessor(DOMRect.getY, null, .{});
|
||||||
pub const width = bridge.accessor(DOMRect.getWidth, null, .{});
|
pub const width = bridge.accessor(DOMRect.getWidth, null, .{});
|
||||||
|
|||||||
@@ -392,7 +392,7 @@ pub fn elementFromPoint(self: *Document, x: f64, y: f64, page: *Page) !?*Element
|
|||||||
if (node.is(Element)) |element| {
|
if (node.is(Element)) |element| {
|
||||||
if (try element.checkVisibility(page)) {
|
if (try element.checkVisibility(page)) {
|
||||||
const rect = try element.getBoundingClientRect(page);
|
const rect = try element.getBoundingClientRect(page);
|
||||||
if (x >= rect._left and x <= rect._right and y >= rect._top and y <= rect._bottom) {
|
if (x >= rect.getLeft() and x <= rect.getRight() and y >= rect.getTop() and y <= rect.getBottom()) {
|
||||||
topmost = element;
|
topmost = element;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -821,10 +821,6 @@ pub fn getBoundingClientRect(self: *Element, page: *Page) !*DOMRect {
|
|||||||
._y = 0.0,
|
._y = 0.0,
|
||||||
._width = 0.0,
|
._width = 0.0,
|
||||||
._height = 0.0,
|
._height = 0.0,
|
||||||
._top = 0.0,
|
|
||||||
._right = 0.0,
|
|
||||||
._bottom = 0.0,
|
|
||||||
._left = 0.0,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -833,20 +829,12 @@ pub fn getBoundingClientRect(self: *Element, page: *Page) !*DOMRect {
|
|||||||
|
|
||||||
// Use sibling position for x coordinate to ensure siblings have different x values
|
// Use sibling position for x coordinate to ensure siblings have different x values
|
||||||
const x = calculateSiblingPosition(self.asNode());
|
const x = calculateSiblingPosition(self.asNode());
|
||||||
const top = y;
|
|
||||||
const left = x;
|
|
||||||
const right = x + dims.width;
|
|
||||||
const bottom = y + dims.height;
|
|
||||||
|
|
||||||
return page._factory.create(DOMRect{
|
return page._factory.create(DOMRect{
|
||||||
._x = x,
|
._x = x,
|
||||||
._y = y,
|
._y = y,
|
||||||
._width = dims.width,
|
._width = dims.width,
|
||||||
._height = dims.height,
|
._height = dims.height,
|
||||||
._top = top,
|
|
||||||
._right = right,
|
|
||||||
._bottom = bottom,
|
|
||||||
._left = left,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,10 +44,6 @@ var zero_rect: DOMRect = .{
|
|||||||
._y = 0.0,
|
._y = 0.0,
|
||||||
._width = 0.0,
|
._width = 0.0,
|
||||||
._height = 0.0,
|
._height = 0.0,
|
||||||
._top = 0.0,
|
|
||||||
._right = 0.0,
|
|
||||||
._bottom = 0.0,
|
|
||||||
._left = 0.0,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const ObserverInit = struct {
|
pub const ObserverInit = struct {
|
||||||
@@ -152,10 +148,6 @@ fn calculateIntersection(
|
|||||||
._y = 0.0,
|
._y = 0.0,
|
||||||
._width = 1920.0,
|
._width = 1920.0,
|
||||||
._height = 1080.0,
|
._height = 1080.0,
|
||||||
._top = 0.0,
|
|
||||||
._right = 1920.0,
|
|
||||||
._bottom = 1080.0,
|
|
||||||
._left = 0.0,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// For a headless browser without real layout, we treat all elements as fully visible.
|
// For a headless browser without real layout, we treat all elements as fully visible.
|
||||||
|
|||||||
@@ -120,19 +120,19 @@ pub fn is(self: *Node, comptime T: type) ?*T {
|
|||||||
/// * `target_node` is `*Node` (where we actually insert),
|
/// * `target_node` is `*Node` (where we actually insert),
|
||||||
/// * `previous_node` is `?*Node`.
|
/// * `previous_node` is `?*Node`.
|
||||||
pub fn findAdjacentNodes(self: *Node, position: []const u8) !struct { *Node, ?*Node } {
|
pub fn findAdjacentNodes(self: *Node, position: []const u8) !struct { *Node, ?*Node } {
|
||||||
// Prefer case-sensitive match.
|
// Case-insensitive match per HTML spec.
|
||||||
// "beforeend" was the most common case in my tests; we might adjust the order
|
// "beforeend" was the most common case in my tests; we might adjust the order
|
||||||
// depending on which ones websites prefer most.
|
// depending on which ones websites prefer most.
|
||||||
if (std.mem.eql(u8, position, "beforeend")) {
|
if (std.ascii.eqlIgnoreCase(position, "beforeend")) {
|
||||||
return .{ self, null };
|
return .{ self, null };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std.mem.eql(u8, position, "afterbegin")) {
|
if (std.ascii.eqlIgnoreCase(position, "afterbegin")) {
|
||||||
// Get the first child; null indicates there are no children.
|
// Get the first child; null indicates there are no children.
|
||||||
return .{ self, self.firstChild() };
|
return .{ self, self.firstChild() };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std.mem.eql(u8, position, "beforebegin")) {
|
if (std.ascii.eqlIgnoreCase(position, "beforebegin")) {
|
||||||
// The node must have a parent node in order to use this variant.
|
// The node must have a parent node in order to use this variant.
|
||||||
const parent_node = self.parentNode() orelse return error.NoModificationAllowed;
|
const parent_node = self.parentNode() orelse return error.NoModificationAllowed;
|
||||||
// Parent cannot be Document.
|
// Parent cannot be Document.
|
||||||
@@ -144,7 +144,7 @@ pub fn findAdjacentNodes(self: *Node, position: []const u8) !struct { *Node, ?*N
|
|||||||
return .{ parent_node, self };
|
return .{ parent_node, self };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std.mem.eql(u8, position, "afterend")) {
|
if (std.ascii.eqlIgnoreCase(position, "afterend")) {
|
||||||
// The node must have a parent node in order to use this variant.
|
// The node must have a parent node in order to use this variant.
|
||||||
const parent_node = self.parentNode() orelse return error.NoModificationAllowed;
|
const parent_node = self.parentNode() orelse return error.NoModificationAllowed;
|
||||||
// Parent cannot be Document.
|
// Parent cannot be Document.
|
||||||
|
|||||||
@@ -299,10 +299,21 @@ pub fn matchMedia(_: *const Window, query: []const u8, page: *Page) !*MediaQuery
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getComputedStyle(_: *const Window, element: *Element, page: *Page) !*CSSStyleProperties {
|
pub fn getComputedStyle(_: *const Window, element: *Element, pseudo_element: ?[]const u8, page: *Page) !*CSSStyleProperties {
|
||||||
|
if (pseudo_element) |pe| {
|
||||||
|
log.warn(.not_implemented, "window.GetComputedStyle", .{ .pseudo_element = pe });
|
||||||
|
}
|
||||||
return CSSStyleProperties.init(element, true, page);
|
return CSSStyleProperties.init(element, true, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn getIsSecureContext(_: *const Window) bool {
|
||||||
|
// Return false since we don't have secure-context-only APIs implemented
|
||||||
|
// (webcam, geolocation, clipboard, etc.)
|
||||||
|
// This is safer and could help avoid processing errors by hinting at
|
||||||
|
// sites not to try to access those features
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn postMessage(self: *Window, message: js.Object, target_origin: ?[]const u8, page: *Page) !void {
|
pub fn postMessage(self: *Window, message: js.Object, target_origin: ?[]const u8, page: *Page) !void {
|
||||||
// For now, we ignore targetOrigin checking and just dispatch the message
|
// For now, we ignore targetOrigin checking and just dispatch the message
|
||||||
// In a full implementation, we would validate the origin
|
// In a full implementation, we would validate the origin
|
||||||
@@ -666,6 +677,7 @@ pub const JsApi = struct {
|
|||||||
pub const atob = bridge.function(Window.atob, .{});
|
pub const atob = bridge.function(Window.atob, .{});
|
||||||
pub const reportError = bridge.function(Window.reportError, .{});
|
pub const reportError = bridge.function(Window.reportError, .{});
|
||||||
pub const getComputedStyle = bridge.function(Window.getComputedStyle, .{});
|
pub const getComputedStyle = bridge.function(Window.getComputedStyle, .{});
|
||||||
|
pub const isSecureContext = bridge.accessor(Window.getIsSecureContext, null, .{});
|
||||||
pub const frames = bridge.accessor(Window.getWindow, null, .{ .cache = "frames" });
|
pub const frames = bridge.accessor(Window.getWindow, null, .{ .cache = "frames" });
|
||||||
pub const index = bridge.indexed(Window.getFrame, .{ .null_as_undefined = true });
|
pub const index = bridge.indexed(Window.getFrame, .{ .null_as_undefined = true });
|
||||||
pub const length = bridge.accessor(Window.getFramesLength, null, .{ .cache = "length" });
|
pub const length = bridge.accessor(Window.getFramesLength, null, .{ .cache = "length" });
|
||||||
|
|||||||
@@ -219,6 +219,14 @@ fn getDefaultPropertyValue(self: *const CSSStyleDeclaration, normalized_name: []
|
|||||||
const element = self._element orelse return "";
|
const element = self._element orelse return "";
|
||||||
return getDefaultDisplay(element);
|
return getDefaultDisplay(element);
|
||||||
}
|
}
|
||||||
|
if (std.mem.eql(u8, normalized_name, "color")) {
|
||||||
|
const element = self._element orelse return "";
|
||||||
|
return getDefaultColor(element);
|
||||||
|
}
|
||||||
|
if (std.mem.eql(u8, normalized_name, "background-color")) {
|
||||||
|
// transparent
|
||||||
|
return "rgba(0, 0, 0, 0)";
|
||||||
|
}
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@@ -256,6 +264,18 @@ fn isInlineTag(tag_name: []const u8) bool {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn getDefaultColor(element: *const Element) []const u8 {
|
||||||
|
switch (element._type) {
|
||||||
|
.html => |html| {
|
||||||
|
return switch (html._type) {
|
||||||
|
.anchor => "rgb(0, 0, 238)", // blue
|
||||||
|
else => "rgb(0, 0, 0)",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
.svg => return "rgb(0, 0, 0)",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub const Property = struct {
|
pub const Property = struct {
|
||||||
_name: String,
|
_name: String,
|
||||||
_value: String,
|
_value: String,
|
||||||
|
|||||||
@@ -258,10 +258,10 @@ pub fn setInnerText(self: *HtmlElement, text: []const u8, page: *Page) !void {
|
|||||||
pub fn insertAdjacentHTML(
|
pub fn insertAdjacentHTML(
|
||||||
self: *HtmlElement,
|
self: *HtmlElement,
|
||||||
position: []const u8,
|
position: []const u8,
|
||||||
/// TODO: Add support for XML parsing.
|
html: []const u8,
|
||||||
html_or_xml: []const u8,
|
|
||||||
page: *Page,
|
page: *Page,
|
||||||
) !void {
|
) !void {
|
||||||
|
|
||||||
// Create a new HTMLDocument.
|
// Create a new HTMLDocument.
|
||||||
const doc = try page._factory.document(@import("../HTMLDocument.zig"){
|
const doc = try page._factory.document(@import("../HTMLDocument.zig"){
|
||||||
._proto = undefined,
|
._proto = undefined,
|
||||||
@@ -270,9 +270,12 @@ pub fn insertAdjacentHTML(
|
|||||||
|
|
||||||
const Parser = @import("../../parser/Parser.zig");
|
const Parser = @import("../../parser/Parser.zig");
|
||||||
var parser = Parser.init(page.call_arena, doc_node, page);
|
var parser = Parser.init(page.call_arena, doc_node, page);
|
||||||
parser.parse(html_or_xml);
|
parser.parse(html);
|
||||||
|
|
||||||
// Check if there's parsing error.
|
// Check if there's parsing error.
|
||||||
if (parser.err) |_| return error.Invalid;
|
if (parser.err) |_| {
|
||||||
|
return error.Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
// We always get it wrapped like so:
|
// We always get it wrapped like so:
|
||||||
// <html><head></head><body>{ ... }</body></html>
|
// <html><head></head><body>{ ... }</body></html>
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
// 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 js = @import("../../../js/js.zig");
|
const js = @import("../../../js/js.zig");
|
||||||
|
const Page = @import("../../../Page.zig");
|
||||||
const Node = @import("../../Node.zig");
|
const Node = @import("../../Node.zig");
|
||||||
const Element = @import("../../Element.zig");
|
const Element = @import("../../Element.zig");
|
||||||
const HtmlElement = @import("../Html.zig");
|
const HtmlElement = @import("../Html.zig");
|
||||||
@@ -35,6 +36,38 @@ pub fn asNode(self: *Meta) *Node {
|
|||||||
return self.asElement().asNode();
|
return self.asElement().asNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn getName(self: *Meta) []const u8 {
|
||||||
|
return self.asElement().getAttributeSafe("name") orelse return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setName(self: *Meta, value: []const u8, page: *Page) !void {
|
||||||
|
try self.asElement().setAttributeSafe("name", value, page);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getHttpEquiv(self: *Meta) []const u8 {
|
||||||
|
return self.asElement().getAttributeSafe("http-equiv") orelse return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setHttpEquiv(self: *Meta, value: []const u8, page: *Page) !void {
|
||||||
|
try self.asElement().setAttributeSafe("http-equiv", value, page);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getContent(self: *Meta) []const u8 {
|
||||||
|
return self.asElement().getAttributeSafe("content") orelse return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setContent(self: *Meta, value: []const u8, page: *Page) !void {
|
||||||
|
try self.asElement().setAttributeSafe("content", value, page);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getMedia(self: *Meta) []const u8 {
|
||||||
|
return self.asElement().getAttributeSafe("media") orelse return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setMedia(self: *Meta, value: []const u8, page: *Page) !void {
|
||||||
|
try self.asElement().setAttributeSafe("media", value, page);
|
||||||
|
}
|
||||||
|
|
||||||
pub const JsApi = struct {
|
pub const JsApi = struct {
|
||||||
pub const bridge = js.Bridge(MetaElement);
|
pub const bridge = js.Bridge(MetaElement);
|
||||||
|
|
||||||
@@ -43,4 +76,9 @@ pub const JsApi = struct {
|
|||||||
pub const prototype_chain = bridge.prototypeChain();
|
pub const prototype_chain = bridge.prototypeChain();
|
||||||
pub var class_id: bridge.ClassId = undefined;
|
pub var class_id: bridge.ClassId = undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const name = bridge.accessor(MetaElement.getName, MetaElement.setName, .{});
|
||||||
|
pub const httpEquiv = bridge.accessor(MetaElement.getHttpEquiv, MetaElement.setHttpEquiv, .{});
|
||||||
|
pub const content = bridge.accessor(MetaElement.getContent, MetaElement.setContent, .{});
|
||||||
|
pub const media = bridge.accessor(MetaElement.getMedia, MetaElement.setMedia, .{});
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user