Merge pull request #962 from lightpanda-io/compareBoundaryPoints

Add Range.compareBoundaryPoints
This commit is contained in:
Pierre Tachoire
2025-08-22 09:08:22 +02:00
committed by GitHub

View File

@@ -32,9 +32,9 @@ pub const Interfaces = .{
pub const AbstractRange = struct { pub const AbstractRange = struct {
collapsed: bool, collapsed: bool,
end_container: *parser.Node, end_node: *parser.Node,
end_offset: u32, end_offset: u32,
start_container: *parser.Node, start_node: *parser.Node,
start_offset: u32, start_offset: u32,
pub fn updateCollapsed(self: *AbstractRange) void { pub fn updateCollapsed(self: *AbstractRange) void {
@@ -47,7 +47,7 @@ pub const AbstractRange = struct {
} }
pub fn get_endContainer(self: *const AbstractRange) !NodeUnion { pub fn get_endContainer(self: *const AbstractRange) !NodeUnion {
return Node.toInterface(self.end_container); return Node.toInterface(self.end_node);
} }
pub fn get_endOffset(self: *const AbstractRange) u32 { pub fn get_endOffset(self: *const AbstractRange) u32 {
@@ -55,7 +55,7 @@ pub const AbstractRange = struct {
} }
pub fn get_startContainer(self: *const AbstractRange) !NodeUnion { pub fn get_startContainer(self: *const AbstractRange) !NodeUnion {
return Node.toInterface(self.start_container); return Node.toInterface(self.start_node);
} }
pub fn get_startOffset(self: *const AbstractRange) u32 { pub fn get_startOffset(self: *const AbstractRange) u32 {
@@ -69,15 +69,20 @@ pub const Range = struct {
proto: AbstractRange, proto: AbstractRange,
pub const _START_TO_START = 0;
pub const _START_TO_END = 1;
pub const _END_TO_END = 2;
pub const _END_TO_START = 3;
// The Range() constructor returns a newly created Range object whose start // The Range() constructor returns a newly created Range object whose start
// and end is the global Document object. // and end is the global Document object.
// https://developer.mozilla.org/en-US/docs/Web/API/Range/Range // https://developer.mozilla.org/en-US/docs/Web/API/Range/Range
pub fn constructor(page: *Page) Range { pub fn constructor(page: *Page) Range {
const proto: AbstractRange = .{ const proto: AbstractRange = .{
.collapsed = true, .collapsed = true,
.end_container = parser.documentHTMLToNode(page.window.document), .end_node = parser.documentHTMLToNode(page.window.document),
.end_offset = 0, .end_offset = 0,
.start_container = parser.documentHTMLToNode(page.window.document), .start_node = parser.documentHTMLToNode(page.window.document),
.start_offset = 0, .start_offset = 0,
}; };
@@ -87,11 +92,11 @@ pub const Range = struct {
pub fn _setStart(self: *Range, node: *parser.Node, offset_: i32) !void { pub fn _setStart(self: *Range, node: *parser.Node, offset_: i32) !void {
try ensureValidOffset(node, offset_); try ensureValidOffset(node, offset_);
const offset: u32 = @intCast(offset_); const offset: u32 = @intCast(offset_);
const position = compare(node, offset, self.proto.start_container, self.proto.start_offset) catch |err| switch (err) { const position = compare(node, offset, self.proto.start_node, self.proto.start_offset) catch |err| switch (err) {
error.WrongDocument => blk: { error.WrongDocument => blk: {
// allow a node with a different root than the current, or // allow a node with a different root than the current, or
// a disconnected one. Treat it as if it's "after", so that // a disconnected one. Treat it as if it's "after", so that
// we also update the end_offset and end_container. // we also update the end_offset and end_node.
break :blk 1; break :blk 1;
}, },
else => return err, else => return err,
@@ -101,22 +106,22 @@ pub const Range = struct {
// if we're setting the node after the current start, the end must // if we're setting the node after the current start, the end must
// be set too. // be set too.
self.proto.end_offset = offset; self.proto.end_offset = offset;
self.proto.end_container = node; self.proto.end_node = node;
} }
self.proto.start_container = node; self.proto.start_node = node;
self.proto.start_offset = offset; self.proto.start_offset = offset;
self.proto.updateCollapsed(); self.proto.updateCollapsed();
} }
pub fn _setStartBefore(self: *Range, node: *parser.Node) !void { pub fn _setStartBefore(self: *Range, node: *parser.Node) !void {
const parent, const index = try getParentAndIndex(node); const parent, const index = try getParentAndIndex(node);
self.proto.start_container = parent; self.proto.start_node = parent;
self.proto.start_offset = index; self.proto.start_offset = index;
} }
pub fn _setStartAfter(self: *Range, node: *parser.Node) !void { pub fn _setStartAfter(self: *Range, node: *parser.Node) !void {
const parent, const index = try getParentAndIndex(node); const parent, const index = try getParentAndIndex(node);
self.proto.start_container = parent; self.proto.start_node = parent;
self.proto.start_offset = index + 1; self.proto.start_offset = index + 1;
} }
@@ -124,11 +129,11 @@ pub const Range = struct {
try ensureValidOffset(node, offset_); try ensureValidOffset(node, offset_);
const offset: u32 = @intCast(offset_); const offset: u32 = @intCast(offset_);
const position = compare(node, offset, self.proto.start_container, self.proto.start_offset) catch |err| switch (err) { const position = compare(node, offset, self.proto.start_node, self.proto.start_offset) catch |err| switch (err) {
error.WrongDocument => blk: { error.WrongDocument => blk: {
// allow a node with a different root than the current, or // allow a node with a different root than the current, or
// a disconnected one. Treat it as if it's "before", so that // a disconnected one. Treat it as if it's "before", so that
// we also update the end_offset and end_container. // we also update the end_offset and end_node.
break :blk -1; break :blk -1;
}, },
else => return err, else => return err,
@@ -138,23 +143,23 @@ pub const Range = struct {
// if we're setting the node before the current start, the start // if we're setting the node before the current start, the start
// must be set too. // must be set too.
self.proto.start_offset = offset; self.proto.start_offset = offset;
self.proto.start_container = node; self.proto.start_node = node;
} }
self.proto.end_container = node; self.proto.end_node = node;
self.proto.end_offset = offset; self.proto.end_offset = offset;
self.proto.updateCollapsed(); self.proto.updateCollapsed();
} }
pub fn _setEndBefore(self: *Range, node: *parser.Node) !void { pub fn _setEndBefore(self: *Range, node: *parser.Node) !void {
const parent, const index = try getParentAndIndex(node); const parent, const index = try getParentAndIndex(node);
self.proto.end_container = parent; self.proto.end_node = parent;
self.proto.end_offset = index; self.proto.end_offset = index;
} }
pub fn _setEndAfter(self: *Range, node: *parser.Node) !void { pub fn _setEndAfter(self: *Range, node: *parser.Node) !void {
const parent, const index = try getParentAndIndex(node); const parent, const index = try getParentAndIndex(node);
self.proto.end_container = parent; self.proto.end_node = parent;
self.proto.end_offset = index + 1; self.proto.end_offset = index + 1;
} }
@@ -166,9 +171,9 @@ pub const Range = struct {
} }
pub fn _selectNodeContents(self: *Range, node: *parser.Node) !void { pub fn _selectNodeContents(self: *Range, node: *parser.Node) !void {
self.proto.start_container = node; self.proto.start_node = node;
self.proto.start_offset = 0; self.proto.start_offset = 0;
self.proto.end_container = node; self.proto.end_node = node;
// Set end_offset // Set end_offset
switch (try parser.nodeType(node)) { switch (try parser.nodeType(node)) {
@@ -196,16 +201,16 @@ pub const Range = struct {
return .{ return .{
.proto = .{ .proto = .{
.collapsed = self.proto.collapsed, .collapsed = self.proto.collapsed,
.end_container = self.proto.end_container, .end_node = self.proto.end_node,
.end_offset = self.proto.end_offset, .end_offset = self.proto.end_offset,
.start_container = self.proto.start_container, .start_node = self.proto.start_node,
.start_offset = self.proto.start_offset, .start_offset = self.proto.start_offset,
}, },
}; };
} }
pub fn _comparePoint(self: *const Range, node: *parser.Node, offset_: i32) !i32 { pub fn _comparePoint(self: *const Range, node: *parser.Node, offset_: i32) !i32 {
const start = self.proto.start_container; const start = self.proto.start_node;
if (try parser.nodeGetRootNode(start) != try parser.nodeGetRootNode(node)) { if (try parser.nodeGetRootNode(start) != try parser.nodeGetRootNode(node)) {
// WPT really wants this error to be first. Later, when we check // WPT really wants this error to be first. Later, when we check
// if the relative position is 'disconnected', it'll also catch this // if the relative position is 'disconnected', it'll also catch this
@@ -225,7 +230,7 @@ pub const Range = struct {
return -1; return -1;
} }
if (try compare(node, offset, self.proto.end_container, self.proto.end_offset) == 1) { if (try compare(node, offset, self.proto.end_node, self.proto.end_offset) == 1) {
return 1; return 1;
} }
@@ -240,7 +245,7 @@ pub const Range = struct {
} }
pub fn _intersectsNode(self: *const Range, node: *parser.Node) !bool { pub fn _intersectsNode(self: *const Range, node: *parser.Node) !bool {
const start_root = try parser.nodeGetRootNode(self.proto.start_container); const start_root = try parser.nodeGetRootNode(self.proto.start_node);
const node_root = try parser.nodeGetRootNode(node); const node_root = try parser.nodeGetRootNode(node);
if (start_root != node_root) { if (start_root != node_root) {
return false; return false;
@@ -251,12 +256,12 @@ pub const Range = struct {
else => return err, else => return err,
}; };
if (try compare(parent, index + 1, self.proto.start_container, self.proto.start_offset) != 1) { if (try compare(parent, index + 1, self.proto.start_node, self.proto.start_offset) != 1) {
// node isn't after start, can't intersect // node isn't after start, can't intersect
return false; return false;
} }
if (try compare(parent, index, self.proto.end_container, self.proto.end_offset) != -1) { if (try compare(parent, index, self.proto.end_node, self.proto.end_offset) != -1) {
// node isn't before end, can't intersect // node isn't before end, can't intersect
return false; return false;
} }
@@ -264,6 +269,16 @@ pub const Range = struct {
return true; return true;
} }
pub fn _compareBoundaryPoints(self: *const Range, how: i32, other: *const Range) !i32 {
return switch (how) {
_START_TO_START => compare(self.proto.start_node, self.proto.start_offset, other.proto.start_node, other.proto.start_offset),
_START_TO_END => compare(self.proto.start_node, self.proto.start_offset, other.proto.end_node, other.proto.end_offset),
_END_TO_END => compare(self.proto.end_node, self.proto.end_offset, other.proto.end_node, other.proto.end_offset),
_END_TO_START => compare(self.proto.end_node, self.proto.end_offset, other.proto.start_node, other.proto.start_offset),
else => error.NotSupported, // this is the correct DOM Exception to return
};
}
// The Range.detach() method does nothing. It used to disable the Range // The Range.detach() method does nothing. It used to disable the Range
// object and enable the browser to release associated resources. The // object and enable the browser to release associated resources. The
// method has been kept for compatibility. // method has been kept for compatibility.