@@ -2169,10 +2169,10 @@ index 0000000000000000000000000000000000000000..2508cce41565023b7fee9c7b85afe8ec
2169
2169
+
2170
2170
diff --git a/testing/juggler/content/PageAgent.js b/testing/juggler/content/PageAgent.js
2171
2171
new file mode 100644
2172
- index 0000000000000000000000000000000000000000..9e10bd1eb3c1c3dd800e244a2372205a2818e6c5
2172
+ index 0000000000000000000000000000000000000000..d592ad9355e7e74a1685acd9338b387a8aa1b032
2173
2173
--- /dev/null
2174
2174
+++ b/testing/juggler/content/PageAgent.js
2175
- @@ -0,0 +1,846 @@
2175
+ @@ -0,0 +1,895 @@
2176
2176
+ "use strict";
2177
2177
+ const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
2178
2178
+ const Ci = Components.interfaces;
@@ -2750,16 +2750,54 @@ index 0000000000000000000000000000000000000000..9e10bd1eb3c1c3dd800e244a2372205a
2750
2750
+ };
2751
2751
+ }
2752
2752
+
2753
- + async getBoundingBox({ frameId, objectId }) {
2753
+ + async scrollIntoViewIfNeeded({objectId, frameId, rect }) {
2754
2754
+ const frame = this._frameTree.frame(frameId);
2755
2755
+ if (!frame)
2756
2756
+ throw new Error('Failed to find frame with id = ' + frameId);
2757
2757
+ const unsafeObject = this._frameData.get(frame).unsafeObject(objectId);
2758
+ + if (!unsafeObject.isConnected)
2759
+ + throw new Error('Node is detached from document');
2760
+ + await this._scrollNodeIntoViewIfNeeded(unsafeObject);
2761
+ + const box = this._getBoundingBox(unsafeObject);
2762
+ + if (rect) {
2763
+ + box.x += rect.x;
2764
+ + box.y += rect.y;
2765
+ + box.width = rect.width;
2766
+ + box.height = rect.height;
2767
+ + }
2768
+ + this._scrollRectIntoViewIfNeeded(unsafeObject, box);
2769
+ + }
2770
+ +
2771
+ + async _scrollNodeIntoViewIfNeeded(node) {
2772
+ + if (node.nodeType !== 1)
2773
+ + node = node.parentElement;
2774
+ + if (!node.ownerDocument || !node.ownerDocument.defaultView)
2775
+ + return;
2776
+ + const global = node.ownerDocument.defaultView;
2777
+ + const visibleRatio = await new Promise(resolve => {
2778
+ + const observer = new global.IntersectionObserver(entries => {
2779
+ + resolve(entries[0].intersectionRatio);
2780
+ + observer.disconnect();
2781
+ + });
2782
+ + observer.observe(node);
2783
+ + // Firefox doesn't call IntersectionObserver callback unless
2784
+ + // there are rafs.
2785
+ + global.requestAnimationFrame(() => {});
2786
+ + });
2787
+ + if (visibleRatio !== 1.0)
2788
+ + node.scrollIntoView({block: 'center', inline: 'center', behavior: 'instant'});
2789
+ + }
2790
+ +
2791
+ + _scrollRectIntoViewIfNeeded(node, rect) {
2792
+ + // TODO: implement.
2793
+ + }
2794
+ +
2795
+ + _getBoundingBox(unsafeObject) {
2758
2796
+ if (!unsafeObject.getBoxQuads)
2759
2797
+ throw new Error('RemoteObject is not a node');
2760
2798
+ const quads = unsafeObject.getBoxQuads({relativeTo: this._frameTree.mainFrame().domWindow().document});
2761
2799
+ if (!quads.length)
2762
- + return {boundingBox: null} ;
2800
+ + return;
2763
2801
+ let x1 = Infinity;
2764
2802
+ let y1 = Infinity;
2765
2803
+ let x2 = -Infinity;
@@ -2771,7 +2809,18 @@ index 0000000000000000000000000000000000000000..9e10bd1eb3c1c3dd800e244a2372205a
2771
2809
+ x2 = Math.max(boundingBox.x + boundingBox.width, x2);
2772
2810
+ y2 = Math.max(boundingBox.y + boundingBox.height, y2);
2773
2811
+ }
2774
- + return {boundingBox: {x: x1 + frame.domWindow().scrollX, y: y1 + frame.domWindow().scrollY, width: x2 - x1, height: y2 - y1}};
2812
+ + return {x: x1, y: y1, width: x2 - x1, height: y2 - y1};
2813
+ + }
2814
+ +
2815
+ + async getBoundingBox({frameId, objectId}) {
2816
+ + const frame = this._frameTree.frame(frameId);
2817
+ + if (!frame)
2818
+ + throw new Error('Failed to find frame with id = ' + frameId);
2819
+ + const unsafeObject = this._frameData.get(frame).unsafeObject(objectId);
2820
+ + const box = this._getBoundingBox(unsafeObject);
2821
+ + if (!box)
2822
+ + return {boundingBox: null};
2823
+ + return {boundingBox: {x: box.x + frame.domWindow().scrollX, y: box.y + frame.domWindow().scrollY, width: box.width, height: box.height}};
2775
2824
+ }
2776
2825
+
2777
2826
+ async screenshot({mimeType, fullPage, clip}) {
@@ -4441,10 +4490,10 @@ index 0000000000000000000000000000000000000000..5d776ab6f28ccff44ef4663e8618ad9c
4441
4490
+ this.NetworkHandler = NetworkHandler;
4442
4491
diff --git a/testing/juggler/protocol/PageHandler.js b/testing/juggler/protocol/PageHandler.js
4443
4492
new file mode 100644
4444
- index 0000000000000000000000000000000000000000..23a32be2200e90e2e05d31aec85874a829cb1bbe
4493
+ index 0000000000000000000000000000000000000000..5413f55e8a9d70c8d3a87f4a8b7c894c85f9f495
4445
4494
--- /dev/null
4446
4495
+++ b/testing/juggler/protocol/PageHandler.js
4447
- @@ -0,0 +1,285 @@
4496
+ @@ -0,0 +1,289 @@
4448
4497
+ "use strict";
4449
4498
+
4450
4499
+ const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js');
@@ -4626,6 +4675,10 @@ index 0000000000000000000000000000000000000000..23a32be2200e90e2e05d31aec85874a8
4626
4675
+ return await this._contentSession.send('Page.describeNode', options);
4627
4676
+ }
4628
4677
+
4678
+ + async scrollIntoViewIfNeeded(options) {
4679
+ + return await this._contentSession.send('Page.scrollIntoViewIfNeeded', options);
4680
+ + }
4681
+ +
4629
4682
+ async addScriptToEvaluateOnNewDocument(options) {
4630
4683
+ return await this._contentSession.send('Page.addScriptToEvaluateOnNewDocument', options);
4631
4684
+ }
@@ -4881,10 +4934,10 @@ index 0000000000000000000000000000000000000000..78b6601b91d0b7fcda61114e6846aa07
4881
4934
+ this.EXPORTED_SYMBOLS = ['t', 'checkScheme'];
4882
4935
diff --git a/testing/juggler/protocol/Protocol.js b/testing/juggler/protocol/Protocol.js
4883
4936
new file mode 100644
4884
- index 0000000000000000000000000000000000000000..d0d27b9bd8132190841a7a4785d31a20738e3b18
4937
+ index 0000000000000000000000000000000000000000..db7516be616a7f9b907d49acea837b7a5b00001d
4885
4938
--- /dev/null
4886
4939
+++ b/testing/juggler/protocol/Protocol.js
4887
- @@ -0,0 +1,749 @@
4940
+ @@ -0,0 +1,756 @@
4888
4941
+ const {t, checkScheme} = ChromeUtils.import('chrome://juggler/content/protocol/PrimitiveTypes.js');
4889
4942
+
4890
4943
+ // Protocol-specific types.
@@ -4931,7 +4984,7 @@ index 0000000000000000000000000000000000000000..d0d27b9bd8132190841a7a4785d31a20
4931
4984
+ y: t.Number,
4932
4985
+ };
4933
4986
+
4934
- + pageTypes.BoundingBox = {
4987
+ + pageTypes.Rect = {
4935
4988
+ x: t.Number,
4936
4989
+ y: t.Number,
4937
4990
+ width: t.Number,
@@ -5464,6 +5517,13 @@ index 0000000000000000000000000000000000000000..d0d27b9bd8132190841a7a4785d31a20
5464
5517
+ ownerFrameId: t.Optional(t.String),
5465
5518
+ },
5466
5519
+ },
5520
+ + 'scrollIntoViewIfNeeded': {
5521
+ + params: {
5522
+ + frameId: t.String,
5523
+ + objectId: t.String,
5524
+ + rect: t.Optional(pageTypes.Rect),
5525
+ + },
5526
+ + },
5467
5527
+ 'addScriptToEvaluateOnNewDocument': {
5468
5528
+ params: {
5469
5529
+ script: t.String,
@@ -5522,7 +5582,7 @@ index 0000000000000000000000000000000000000000..d0d27b9bd8132190841a7a4785d31a20
5522
5582
+ objectId: t.String,
5523
5583
+ },
5524
5584
+ returns: {
5525
- + boundingBox: t.Nullable(pageTypes.BoundingBox ),
5585
+ + boundingBox: t.Nullable(pageTypes.Rect ),
5526
5586
+ },
5527
5587
+ },
5528
5588
+ 'adoptNode': {
0 commit comments