mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-07-31 01:36:15 -04:00
webapi: NodeFilter follows WebIDL callback interface semantics
Fixes the 5 failing subtests of WPT /dom/traversal/TreeWalker-acceptNode-filter.html (7/12 -> 12/12): - A filter object was converted eagerly at createTreeWalker time, so an object without a callable acceptNode threw "invalid argument" at creation. Per WebIDL any object converts to the NodeFilter callback interface; the TypeError belongs at invocation time. - The acceptNode member was cached at conversion. Per "call a user object's operation" it must be looked up with a fresh Get on every traversal, rethrowing errors from a throwing getter. - The callback was invoked with the default this; the spec requires the filter object itself as the this value. NodeFilter now stores the raw function or object (js.Object.Global) and performs the per-invocation lookup, callability check and this-binding in acceptNode. Coverage: /dom/traversal/TreeWalker-acceptNode-filter.html 7/12 -> 12/12 (fully green). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -60,7 +60,7 @@ pub fn getWhatToShow(self: *const DOMNodeIterator) u32 {
|
||||
}
|
||||
|
||||
pub fn getFilter(self: *const DOMNodeIterator) ?FilterOpts {
|
||||
return self._filter._original_filter;
|
||||
return self._filter._opts;
|
||||
}
|
||||
|
||||
pub fn nextNode(self: *DOMNodeIterator, frame: *Frame) !?*Node {
|
||||
|
||||
@@ -52,7 +52,7 @@ pub fn getWhatToShow(self: *const DOMTreeWalker) u32 {
|
||||
}
|
||||
|
||||
pub fn getFilter(self: *const DOMTreeWalker) ?FilterOpts {
|
||||
return self._filter._original_filter;
|
||||
return self._filter._opts;
|
||||
}
|
||||
|
||||
pub fn getCurrentNode(self: *const DOMTreeWalker) *Node {
|
||||
|
||||
@@ -21,27 +21,17 @@ const Node = @import("Node.zig");
|
||||
|
||||
const NodeFilter = @This();
|
||||
|
||||
_func: ?js.Function.Global,
|
||||
_original_filter: ?FilterOpts,
|
||||
_opts: ?FilterOpts,
|
||||
|
||||
pub const FilterOpts = union(enum) {
|
||||
function: js.Function.Global,
|
||||
object: struct {
|
||||
pub const js_as_object = true;
|
||||
acceptNode: js.Function.Global,
|
||||
},
|
||||
// Any object is a valid callback interface; whether its acceptNode
|
||||
// member is callable is only checked when the filter is invoked.
|
||||
object: js.Object.Global,
|
||||
};
|
||||
|
||||
pub fn init(opts_: ?FilterOpts) !NodeFilter {
|
||||
const opts = opts_ orelse return .{ ._func = null, ._original_filter = null };
|
||||
const func = switch (opts) {
|
||||
.function => |func| func,
|
||||
.object => |obj| obj.acceptNode,
|
||||
};
|
||||
return .{
|
||||
._func = func,
|
||||
._original_filter = opts_,
|
||||
};
|
||||
return .{ ._opts = opts_ };
|
||||
}
|
||||
|
||||
// Constants
|
||||
@@ -65,8 +55,23 @@ pub const SHOW_DOCUMENT_FRAGMENT: u32 = 0x400;
|
||||
pub const SHOW_NOTATION: u32 = 0x800;
|
||||
|
||||
pub fn acceptNode(self: *const NodeFilter, node: *Node, local: *const js.Local) !i32 {
|
||||
const func = self._func orelse return FILTER_ACCEPT;
|
||||
return local.toLocal(func).callRethrow(i32, .{node});
|
||||
const opts = self._opts orelse return FILTER_ACCEPT;
|
||||
switch (opts) {
|
||||
.function => |func| return local.toLocal(func).callRethrow(i32, .{node}),
|
||||
.object => |obj| {
|
||||
// Per WebIDL "call a user object's operation": the acceptNode
|
||||
// member is looked up on every invocation (rethrowing getter
|
||||
// errors), must be callable (TypeError otherwise), and is
|
||||
// invoked with the filter object as its this value.
|
||||
const filter_obj = obj.local(local);
|
||||
const member = try filter_obj.get("acceptNode");
|
||||
if (!member.isFunction()) {
|
||||
return error.TypeError;
|
||||
}
|
||||
const func = js.Function{ .local = local, .handle = @ptrCast(member.handle) };
|
||||
return func.callWithThisRethrow(i32, filter_obj, .{node});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn shouldShow(node: *const Node, what_to_show: u32) bool {
|
||||
|
||||
Reference in New Issue
Block a user