diff --git a/src/browser/webapi/DOMNodeIterator.zig b/src/browser/webapi/DOMNodeIterator.zig index 6756e4d75..8d349265e 100644 --- a/src/browser/webapi/DOMNodeIterator.zig +++ b/src/browser/webapi/DOMNodeIterator.zig @@ -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 { diff --git a/src/browser/webapi/DOMTreeWalker.zig b/src/browser/webapi/DOMTreeWalker.zig index 483b94a98..354c3c2e2 100644 --- a/src/browser/webapi/DOMTreeWalker.zig +++ b/src/browser/webapi/DOMTreeWalker.zig @@ -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 { diff --git a/src/browser/webapi/NodeFilter.zig b/src/browser/webapi/NodeFilter.zig index a2519e718..d64aa4d26 100644 --- a/src/browser/webapi/NodeFilter.zig +++ b/src/browser/webapi/NodeFilter.zig @@ -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 {