@@ -37,6 +37,7 @@ pub fn processMessage(cmd: anytype) !void {
3737 describeNode ,
3838 scrollIntoViewIfNeeded ,
3939 getContentQuads ,
40+ getBoxModel ,
4041 }, cmd .input .action ) orelse return error .UnknownMethod ;
4142
4243 switch (action ) {
@@ -51,6 +52,7 @@ pub fn processMessage(cmd: anytype) !void {
5152 .describeNode = > return describeNode (cmd ),
5253 .scrollIntoViewIfNeeded = > return scrollIntoViewIfNeeded (cmd ),
5354 .getContentQuads = > return getContentQuads (cmd ),
55+ .getBoxModel = > return getBoxModel (cmd ),
5456 }
5557}
5658
@@ -311,6 +313,16 @@ fn describeNode(cmd: anytype) !void {
311313// We are assuming the start/endpoint is not repeated.
312314const Quad = [8 ]f64 ;
313315
316+ const BoxModel = struct {
317+ content : Quad ,
318+ padding : Quad ,
319+ border : Quad ,
320+ margin : Quad ,
321+ width : i32 ,
322+ height : i32 ,
323+ // shapeOutside: ?ShapeOutsideInfo,
324+ };
325+
314326fn rectToQuad (rect : Element.DOMRect ) Quad {
315327 return Quad {
316328 rect .x ,
@@ -391,6 +403,34 @@ fn getContentQuads(cmd: anytype) !void {
391403 return cmd .sendResult (.{ .quads = &.{quad } }, .{});
392404}
393405
406+ fn getBoxModel (cmd : anytype ) ! void {
407+ const params = (try cmd .params (struct {
408+ nodeId : ? Node.Id = null ,
409+ backendNodeId : ? u32 = null ,
410+ objectId : ? []const u8 = null ,
411+ })) orelse return error .InvalidParams ;
412+
413+ const bc = cmd .browser_context orelse return error .BrowserContextNotLoaded ;
414+
415+ const node = try getNode (cmd .arena , bc , params .nodeId , params .backendNodeId , params .objectId );
416+
417+ // TODO implement for document or text
418+ if (try parser .nodeType (node ._node ) != .element ) return error .NodeIsNotAnElement ;
419+ const element = parser .nodeToElement (node ._node );
420+
421+ const rect = try Element ._getBoundingClientRect (element , & bc .session .page .? .state );
422+ const quad = rectToQuad (rect );
423+
424+ return cmd .sendResult (.{ .model = BoxModel {
425+ .content = quad ,
426+ .padding = quad ,
427+ .border = quad ,
428+ .margin = quad ,
429+ .width = @intFromFloat (rect .width ),
430+ .height = @intFromFloat (rect .height ),
431+ } }, .{});
432+ }
433+
394434const testing = @import ("../testing.zig" );
395435
396436test "cdp.dom: getSearchResults unknown search id" {
@@ -532,3 +572,36 @@ test "cdp.dom: querySelector Nodes found" {
532572 try ctx .expectSentEvent ("DOM.setChildNodes" , null , .{});
533573 try ctx .expectSentResult (.{ .nodeIds = &.{5 } }, .{ .id = 5 });
534574}
575+
576+ test "cdp.dom: getBoxModel" {
577+ var ctx = testing .context ();
578+ defer ctx .deinit ();
579+
580+ _ = try ctx .loadBrowserContext (.{ .id = "BID-A" , .html = "<div><p>2</p></div>" });
581+
582+ try ctx .processMessage (.{ // Hacky way to make sure nodeId 0 exists in the registry
583+ .id = 3 ,
584+ .method = "DOM.getDocument" ,
585+ });
586+
587+ try ctx .processMessage (.{
588+ .id = 4 ,
589+ .method = "DOM.querySelector" ,
590+ .params = .{ .nodeId = 0 , .selector = "p" },
591+ });
592+ try ctx .expectSentResult (.{ .nodeId = 2 }, .{ .id = 4 });
593+
594+ try ctx .processMessage (.{
595+ .id = 5 ,
596+ .method = "DOM.getBoxModel" ,
597+ .params = .{ .nodeId = 5 },
598+ });
599+ try ctx .expectSentResult (.{ .model = BoxModel {
600+ .content = Quad { 0.0 , 0.0 , 1.0 , 0.0 , 1.0 , 1.0 , 0.0 , 1.0 },
601+ .padding = Quad { 0.0 , 0.0 , 1.0 , 0.0 , 1.0 , 1.0 , 0.0 , 1.0 },
602+ .border = Quad { 0.0 , 0.0 , 1.0 , 0.0 , 1.0 , 1.0 , 0.0 , 1.0 },
603+ .margin = Quad { 0.0 , 0.0 , 1.0 , 0.0 , 1.0 , 1.0 , 0.0 , 1.0 },
604+ .width = 1 ,
605+ .height = 1 ,
606+ } }, .{ .id = 5 });
607+ }
0 commit comments