1717// along with this program. If not, see <https://www.gnu.org/licenses/>.
1818
1919const std = @import ("std" );
20+ const Allocator = std .mem .Allocator ;
2021const Node = @import ("../Node.zig" );
2122const css = @import ("../../browser/dom/css.zig" );
2223const parser = @import ("../../browser/netsurf.zig" );
2324const dom_node = @import ("../../browser/dom/node.zig" );
25+ const DOMRect = @import ("../../browser/dom/element.zig" ).Element .DOMRect ;
2426
2527pub fn processMessage (cmd : anytype ) ! void {
2628 const action = std .meta .stringToEnum (enum {
@@ -31,6 +33,8 @@ pub fn processMessage(cmd: anytype) !void {
3133 discardSearchResults ,
3234 resolveNode ,
3335 describeNode ,
36+ scrollIntoViewIfNeeded ,
37+ getContentQuads ,
3438 }, cmd .input .action ) orelse return error .UnknownMethod ;
3539
3640 switch (action ) {
@@ -41,6 +45,8 @@ pub fn processMessage(cmd: anytype) !void {
4145 .discardSearchResults = > return discardSearchResults (cmd ),
4246 .resolveNode = > return resolveNode (cmd ),
4347 .describeNode = > return describeNode (cmd ),
48+ .scrollIntoViewIfNeeded = > return scrollIntoViewIfNeeded (cmd ),
49+ .getContentQuads = > return getContentQuads (cmd ),
4450 }
4551}
4652
@@ -233,25 +239,100 @@ fn describeNode(cmd: anytype) !void {
233239 depth : u32 = 1 ,
234240 pierce : bool = false ,
235241 })) orelse return error .InvalidParams ;
236- if (params .backendNodeId != null or params .depth != 1 or params .pierce ) {
237- return error .NotYetImplementedParams ;
238- }
239242
243+ if (params .depth != 1 or params .pierce ) return error .NotYetImplementedParams ;
240244 const bc = cmd .browser_context orelse return error .BrowserContextNotLoaded ;
241245
242- if (params .nodeId != null ) {
243- const node = bc .node_registry .lookup_by_id .get (params .nodeId .? ) orelse return error .NodeNotFound ;
244- return cmd .sendResult (.{ .node = bc .nodeWriter (node , .{}) }, .{});
246+ const node = try getNode (cmd .arena , bc , params .nodeId , params .backendNodeId , params .objectId );
247+
248+ return cmd .sendResult (.{ .node = bc .nodeWriter (node , .{}) }, .{});
249+ }
250+
251+ // An array of quad vertices, x immediately followed by y for each point, points clock-wise.
252+ // Note Y points downward
253+ // We are assuming the start/endpoint is not repeated.
254+ const Quad = [8 ]f64 ;
255+
256+ fn rectToQuad (rect : DOMRect ) Quad {
257+ return Quad {
258+ rect .x ,
259+ rect .y ,
260+ rect .x + rect .width ,
261+ rect .y ,
262+ rect .x + rect .width ,
263+ rect .y + rect .height ,
264+ rect .x ,
265+ rect .y + rect .height ,
266+ };
267+ }
268+
269+ fn scrollIntoViewIfNeeded (cmd : anytype ) ! void {
270+ const params = (try cmd .params (struct {
271+ nodeId : ? Node.Id = null ,
272+ backendNodeId : ? u32 = null ,
273+ objectId : ? []const u8 = null ,
274+ rect : ? DOMRect = null ,
275+ })) orelse return error .InvalidParams ;
276+ // Only 1 of nodeId, backendNodeId, objectId may be set, but chrome just takes the first non-null
277+
278+ // We retrieve the node to at least check if it exists and is valid.
279+ const bc = cmd .browser_context orelse return error .BrowserContextNotLoaded ;
280+ const node = try getNode (cmd .arena , bc , params .nodeId , params .backendNodeId , params .objectId );
281+
282+ const node_type = parser .nodeType (node ._node ) catch return error .InvalidNode ;
283+ switch (node_type ) {
284+ .element = > {},
285+ .document = > {},
286+ .text = > {},
287+ else = > return error .NodeDoesNotHaveGeometry ,
245288 }
246- if (params .objectId != null ) {
289+
290+ return cmd .sendResult (null , .{});
291+ }
292+
293+ fn getNode (arena : Allocator , browser_context : anytype , node_id : ? Node.Id , backend_node_id : ? Node.Id , object_id : ? []const u8 ) ! * Node {
294+ const input_node_id = node_id orelse backend_node_id ;
295+ if (input_node_id ) | input_node_id_ | {
296+ return browser_context .node_registry .lookup_by_id .get (input_node_id_ ) orelse return error .NodeNotFound ;
297+ }
298+ if (object_id ) | object_id_ | {
247299 // Retrieve the object from which ever context it is in.
248- const parser_node = try bc .inspector .getNodePtr (cmd .arena , params .objectId .? );
249- const node = try bc .node_registry .register (@ptrCast (parser_node ));
250- return cmd .sendResult (.{ .node = bc .nodeWriter (node , .{}) }, .{});
300+ const parser_node = try browser_context .inspector .getNodePtr (arena , object_id_ );
301+ return try browser_context .node_registry .register (@ptrCast (parser_node ));
251302 }
252303 return error .MissingParams ;
253304}
254305
306+ // https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-getContentQuads
307+ // Related to: https://drafts.csswg.org/cssom-view/#the-geometryutils-interface
308+ fn getContentQuads (cmd : anytype ) ! void {
309+ const params = (try cmd .params (struct {
310+ nodeId : ? Node.Id = null ,
311+ backendNodeId : ? Node.Id = null ,
312+ objectId : ? []const u8 = null ,
313+ })) orelse return error .InvalidParams ;
314+
315+ const bc = cmd .browser_context orelse return error .BrowserContextNotLoaded ;
316+
317+ const node = try getNode (cmd .arena , bc , params .nodeId , params .backendNodeId , params .objectId );
318+
319+ // TODO likely if the following CSS properties are set the quads should be empty
320+ // visibility: hidden
321+ // display: none
322+
323+ if (try parser .nodeType (node ._node ) != .element ) return error .NodeIsNotAnElement ;
324+ // TODO implement for document or text
325+ // Most likely document would require some hierachgy in the renderer. It is left unimplemented till we have a good example.
326+ // Text may be tricky, multiple quads in case of multiple lines? empty quads of text = ""?
327+ // Elements like SVGElement may have multiple quads.
328+
329+ const element = parser .nodeToElement (node ._node );
330+ const rect = try bc .session .page .? .state .renderer .getRect (element );
331+ const quad = rectToQuad (rect );
332+
333+ return cmd .sendResult (.{ .quads = &.{quad } }, .{});
334+ }
335+
255336const testing = @import ("../testing.zig" );
256337
257338test "cdp.dom: getSearchResults unknown search id" {
0 commit comments