mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-09-17 08:27:11 -04:00
Merge pull request #3553 from lightpanda-io/semantic-tree-init
SemanticTree: resolve the owner frame once in init
This commit is contained in:
4 files changed
+43
-66
No files matched your search
+33
-38
@@ -40,12 +40,33 @@ dom_node: *Node,
|
||||
registry: *NodeRegistry,
|
||||
frame: *Frame, // we never visit iframes, every node we visit is in the same frame as dom_node
|
||||
arena: std.mem.Allocator,
|
||||
prune: bool = true,
|
||||
interactive_only: bool = false,
|
||||
max_depth: u32 = std.math.maxInt(u32) - 1,
|
||||
prune: bool,
|
||||
interactive_only: bool,
|
||||
max_depth: u32,
|
||||
|
||||
pub const Opts = struct {
|
||||
prune: bool = true,
|
||||
interactive_only: bool = false,
|
||||
max_depth: u32 = std.math.maxInt(u32) - 1,
|
||||
};
|
||||
|
||||
/// `frame` only seeds the owner lookup; the tree is walked with the frame
|
||||
/// that owns `node`. A node whose document has no frame (DOMParser, XHR, or
|
||||
/// a frame that has since navigated away) has no styles or layout to
|
||||
/// describe.
|
||||
pub fn init(arena: std.mem.Allocator, node: *Node, registry: *NodeRegistry, frame: *Frame, opts: Opts) error{FramelessNode}!Self {
|
||||
return .{
|
||||
.dom_node = node,
|
||||
.registry = registry,
|
||||
.frame = node.ownerFrame(frame) orelse return error.FramelessNode,
|
||||
.arena = arena,
|
||||
.prune = opts.prune,
|
||||
.interactive_only = opts.interactive_only,
|
||||
.max_depth = opts.max_depth,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn jsonStringify(self: @This(), jw: *std.json.Stringify) error{WriteFailed}!void {
|
||||
assertOwns(self.frame, self.dom_node);
|
||||
var visitor = JsonVisitor{ .jw = jw, .tree = self };
|
||||
var xpath_buffer: std.ArrayList(u8) = .empty;
|
||||
const listener_targets = interactive.buildListenerTargetMap(self.frame, self.arena) catch |err| {
|
||||
@@ -65,7 +86,6 @@ pub fn jsonStringify(self: @This(), jw: *std.json.Stringify) error{WriteFailed}!
|
||||
}
|
||||
|
||||
pub fn textStringify(self: @This(), writer: *std.Io.Writer) error{WriteFailed}!void {
|
||||
assertOwns(self.frame, self.dom_node);
|
||||
var visitor = TextVisitor{ .writer = writer, .tree = self, .depth = 0 };
|
||||
var xpath_buffer: std.ArrayList(u8) = .empty;
|
||||
const listener_targets = interactive.buildListenerTargetMap(self.frame, self.arena) catch |err| {
|
||||
@@ -651,14 +671,12 @@ const NodeDetails = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub fn getNodeDetails(
|
||||
arena: std.mem.Allocator,
|
||||
node: *Node,
|
||||
registry: *NodeRegistry,
|
||||
frame: *Frame,
|
||||
) !NodeDetails {
|
||||
assertOwns(frame, node);
|
||||
const cdp_node = try registry.register(node);
|
||||
pub fn nodeDetails(self: Self) !NodeDetails {
|
||||
const arena = self.arena;
|
||||
const node = self.dom_node;
|
||||
const frame = self.frame;
|
||||
|
||||
const cdp_node = try self.registry.register(node);
|
||||
const axn = AXNode.fromNode(node);
|
||||
const role = try axn.getRole();
|
||||
var labels: Label.LabelByForIndex = .{};
|
||||
@@ -733,13 +751,6 @@ pub fn getNodeDetails(
|
||||
};
|
||||
}
|
||||
|
||||
fn assertOwns(frame: *const Frame, node: *const Node) void {
|
||||
if (comptime lp.IS_DEBUG == false) {
|
||||
return;
|
||||
}
|
||||
std.debug.assert(node.ownerFrame(frame) == frame);
|
||||
}
|
||||
|
||||
const testing = @import("testing.zig");
|
||||
|
||||
test "SemanticTree backendDOMNodeId" {
|
||||
@@ -750,15 +761,7 @@ test "SemanticTree backendDOMNodeId" {
|
||||
defer page.close();
|
||||
const frame = page.frame().?;
|
||||
|
||||
const st: Self = .{
|
||||
.dom_node = frame.window._document.asNode(),
|
||||
.registry = ®istry,
|
||||
.frame = frame,
|
||||
.arena = testing.arena_allocator,
|
||||
.prune = false,
|
||||
.interactive_only = false,
|
||||
.max_depth = std.math.maxInt(u32) - 1,
|
||||
};
|
||||
const st: Self = try .init(testing.arena_allocator, frame.window._document.asNode(), ®istry, frame, .{ .prune = false });
|
||||
|
||||
const json_str = try std.json.Stringify.valueAlloc(testing.allocator, st, .{});
|
||||
defer testing.allocator.free(json_str);
|
||||
@@ -774,15 +777,7 @@ test "SemanticTree max_depth" {
|
||||
defer page.close();
|
||||
const frame = page.frame().?;
|
||||
|
||||
const st: Self = .{
|
||||
.dom_node = frame.window._document.asNode(),
|
||||
.registry = ®istry,
|
||||
.frame = frame,
|
||||
.arena = testing.arena_allocator,
|
||||
.prune = false,
|
||||
.interactive_only = false,
|
||||
.max_depth = 1,
|
||||
};
|
||||
const st: Self = try .init(testing.arena_allocator, frame.window._document.asNode(), ®istry, frame, .{ .prune = false, .max_depth = 1 });
|
||||
|
||||
var aw: std.Io.Writer.Allocating = .init(testing.allocator);
|
||||
defer aw.deinit();
|
||||
|
||||
+4
-12
@@ -1430,16 +1430,9 @@ fn execTree(arena: std.mem.Allocator, session: *lp.Session, registry: *NodeRegis
|
||||
const page = try ensurePage(session, registry, args.url, args.timeout);
|
||||
|
||||
const root_node = (try resolveOptionalNode(registry, args.backendNodeId)) orelse page.document.asNode();
|
||||
const frame = root_node.ownerFrame(page) orelse return ToolError.NodeNotFound;
|
||||
|
||||
const st = lp.SemanticTree{
|
||||
.dom_node = root_node,
|
||||
.registry = registry,
|
||||
.frame = frame,
|
||||
.arena = arena,
|
||||
.prune = true,
|
||||
const st = lp.SemanticTree.init(arena, root_node, registry, page, .{
|
||||
.max_depth = args.maxDepth orelse std.math.maxInt(u32) - 1,
|
||||
};
|
||||
}) catch return ToolError.NodeNotFound;
|
||||
|
||||
var aw: std.Io.Writer.Allocating = .init(arena);
|
||||
st.textStringify(&aw.writer) catch return ToolError.InternalError;
|
||||
@@ -1454,9 +1447,8 @@ fn execNodeDetails(arena: std.mem.Allocator, session: *lp.Session, registry: *No
|
||||
|
||||
const node = registry.lookup_by_id.get(args.backendNodeId) orelse
|
||||
return ToolError.NodeNotFound;
|
||||
const frame = node.dom.ownerFrame(page) orelse return ToolError.NodeNotFound;
|
||||
const details = lp.SemanticTree.getNodeDetails(arena, node.dom, registry, frame) catch
|
||||
return ToolError.InternalError;
|
||||
const st = lp.SemanticTree.init(arena, node.dom, registry, page, .{}) catch return ToolError.NodeNotFound;
|
||||
const details = st.nodeDetails() catch return ToolError.InternalError;
|
||||
return renderJson(arena, &details);
|
||||
}
|
||||
|
||||
|
||||
+2
-6
@@ -495,13 +495,9 @@ fn dumpContent(app: *App, mode: Config.DumpFormat, opts: FetchOpts, frame: *Fram
|
||||
var registry = NodeRegistry.init(app.allocator);
|
||||
defer registry.deinit();
|
||||
|
||||
const st: SemanticTree = .{
|
||||
.dom_node = state.root,
|
||||
.registry = ®istry,
|
||||
.frame = frame,
|
||||
.arena = frame.call_arena,
|
||||
const st: SemanticTree = try .init(frame.call_arena, state.root, ®istry, frame, .{
|
||||
.prune = (mode == .semantic_tree_text),
|
||||
};
|
||||
});
|
||||
|
||||
if (mode == .semantic_tree) {
|
||||
try std.json.Stringify.value(st, .{}, writer);
|
||||
|
||||
@@ -133,17 +133,12 @@ fn getSemanticTree(cmd: anytype) !void {
|
||||
(bc.node_registry.lookup_by_id.get(nodeId) orelse return error.InvalidNodeId).dom
|
||||
else
|
||||
root.document.asNode();
|
||||
const frame = dom_node.ownerFrame(root) orelse return error.InvalidNodeId;
|
||||
|
||||
var st = SemanticTree{
|
||||
.dom_node = dom_node,
|
||||
.registry = &bc.node_registry,
|
||||
.frame = frame,
|
||||
.arena = cmd.arena,
|
||||
const st = SemanticTree.init(cmd.arena, dom_node, &bc.node_registry, root, .{
|
||||
.prune = params.prune orelse true,
|
||||
.interactive_only = params.interactiveOnly orelse false,
|
||||
.max_depth = params.maxDepth orelse std.math.maxInt(u32) - 1,
|
||||
};
|
||||
}) catch return error.InvalidNodeId;
|
||||
|
||||
if (params.format) |format| {
|
||||
if (format == .text) {
|
||||
@@ -274,9 +269,8 @@ fn getNodeDetails(cmd: anytype) !void {
|
||||
const root = bc.mainFrame() orelse return error.FrameNotLoaded;
|
||||
|
||||
const node = (bc.node_registry.lookup_by_id.get(params.backendNodeId) orelse return error.InvalidNodeId).dom;
|
||||
const frame = node.ownerFrame(root) orelse return error.InvalidNodeId;
|
||||
|
||||
const details = SemanticTree.getNodeDetails(cmd.arena, node, &bc.node_registry, frame) catch return error.InternalError;
|
||||
const st = SemanticTree.init(cmd.arena, node, &bc.node_registry, root, .{}) catch return error.InvalidNodeId;
|
||||
const details = st.nodeDetails() catch return error.InternalError;
|
||||
|
||||
return cmd.sendResult(.{
|
||||
.nodeDetails = details,
|
||||
|
||||
Reference in new issue
Block a user