Skip to content

Commit 0cc26c0

Browse files
authored
browser(firefox): introduce Page.scrollIntoViewIfNeeded (#848)
dgozman/gecko-dev@1cfb6fd
1 parent a2ab645 commit 0cc26c0

File tree

2 files changed

+72
-12
lines changed

2 files changed

+72
-12
lines changed

browser_patches/firefox/BUILD_NUMBER

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1021
1+
1022

browser_patches/firefox/patches/bootstrap.diff

Lines changed: 71 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2169,10 +2169,10 @@ index 0000000000000000000000000000000000000000..2508cce41565023b7fee9c7b85afe8ec
21692169
+
21702170
diff --git a/testing/juggler/content/PageAgent.js b/testing/juggler/content/PageAgent.js
21712171
new file mode 100644
2172-
index 0000000000000000000000000000000000000000..9e10bd1eb3c1c3dd800e244a2372205a2818e6c5
2172+
index 0000000000000000000000000000000000000000..d592ad9355e7e74a1685acd9338b387a8aa1b032
21732173
--- /dev/null
21742174
+++ b/testing/juggler/content/PageAgent.js
2175-
@@ -0,0 +1,846 @@
2175+
@@ -0,0 +1,895 @@
21762176
+"use strict";
21772177
+const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
21782178
+const Ci = Components.interfaces;
@@ -2750,16 +2750,54 @@ index 0000000000000000000000000000000000000000..9e10bd1eb3c1c3dd800e244a2372205a
27502750
+ };
27512751
+ }
27522752
+
2753-
+ async getBoundingBox({frameId, objectId}) {
2753+
+ async scrollIntoViewIfNeeded({objectId, frameId, rect}) {
27542754
+ const frame = this._frameTree.frame(frameId);
27552755
+ if (!frame)
27562756
+ throw new Error('Failed to find frame with id = ' + frameId);
27572757
+ 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) {
27582796
+ if (!unsafeObject.getBoxQuads)
27592797
+ throw new Error('RemoteObject is not a node');
27602798
+ const quads = unsafeObject.getBoxQuads({relativeTo: this._frameTree.mainFrame().domWindow().document});
27612799
+ if (!quads.length)
2762-
+ return {boundingBox: null};
2800+
+ return;
27632801
+ let x1 = Infinity;
27642802
+ let y1 = Infinity;
27652803
+ let x2 = -Infinity;
@@ -2771,7 +2809,18 @@ index 0000000000000000000000000000000000000000..9e10bd1eb3c1c3dd800e244a2372205a
27712809
+ x2 = Math.max(boundingBox.x + boundingBox.width, x2);
27722810
+ y2 = Math.max(boundingBox.y + boundingBox.height, y2);
27732811
+ }
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}};
27752824
+ }
27762825
+
27772826
+ async screenshot({mimeType, fullPage, clip}) {
@@ -4441,10 +4490,10 @@ index 0000000000000000000000000000000000000000..5d776ab6f28ccff44ef4663e8618ad9c
44414490
+this.NetworkHandler = NetworkHandler;
44424491
diff --git a/testing/juggler/protocol/PageHandler.js b/testing/juggler/protocol/PageHandler.js
44434492
new file mode 100644
4444-
index 0000000000000000000000000000000000000000..23a32be2200e90e2e05d31aec85874a829cb1bbe
4493+
index 0000000000000000000000000000000000000000..5413f55e8a9d70c8d3a87f4a8b7c894c85f9f495
44454494
--- /dev/null
44464495
+++ b/testing/juggler/protocol/PageHandler.js
4447-
@@ -0,0 +1,285 @@
4496+
@@ -0,0 +1,289 @@
44484497
+"use strict";
44494498
+
44504499
+const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js');
@@ -4626,6 +4675,10 @@ index 0000000000000000000000000000000000000000..23a32be2200e90e2e05d31aec85874a8
46264675
+ return await this._contentSession.send('Page.describeNode', options);
46274676
+ }
46284677
+
4678+
+ async scrollIntoViewIfNeeded(options) {
4679+
+ return await this._contentSession.send('Page.scrollIntoViewIfNeeded', options);
4680+
+ }
4681+
+
46294682
+ async addScriptToEvaluateOnNewDocument(options) {
46304683
+ return await this._contentSession.send('Page.addScriptToEvaluateOnNewDocument', options);
46314684
+ }
@@ -4881,10 +4934,10 @@ index 0000000000000000000000000000000000000000..78b6601b91d0b7fcda61114e6846aa07
48814934
+this.EXPORTED_SYMBOLS = ['t', 'checkScheme'];
48824935
diff --git a/testing/juggler/protocol/Protocol.js b/testing/juggler/protocol/Protocol.js
48834936
new file mode 100644
4884-
index 0000000000000000000000000000000000000000..d0d27b9bd8132190841a7a4785d31a20738e3b18
4937+
index 0000000000000000000000000000000000000000..db7516be616a7f9b907d49acea837b7a5b00001d
48854938
--- /dev/null
48864939
+++ b/testing/juggler/protocol/Protocol.js
4887-
@@ -0,0 +1,749 @@
4940+
@@ -0,0 +1,756 @@
48884941
+const {t, checkScheme} = ChromeUtils.import('chrome://juggler/content/protocol/PrimitiveTypes.js');
48894942
+
48904943
+// Protocol-specific types.
@@ -4931,7 +4984,7 @@ index 0000000000000000000000000000000000000000..d0d27b9bd8132190841a7a4785d31a20
49314984
+ y: t.Number,
49324985
+};
49334986
+
4934-
+pageTypes.BoundingBox = {
4987+
+pageTypes.Rect = {
49354988
+ x: t.Number,
49364989
+ y: t.Number,
49374990
+ width: t.Number,
@@ -5464,6 +5517,13 @@ index 0000000000000000000000000000000000000000..d0d27b9bd8132190841a7a4785d31a20
54645517
+ ownerFrameId: t.Optional(t.String),
54655518
+ },
54665519
+ },
5520+
+ 'scrollIntoViewIfNeeded': {
5521+
+ params: {
5522+
+ frameId: t.String,
5523+
+ objectId: t.String,
5524+
+ rect: t.Optional(pageTypes.Rect),
5525+
+ },
5526+
+ },
54675527
+ 'addScriptToEvaluateOnNewDocument': {
54685528
+ params: {
54695529
+ script: t.String,
@@ -5522,7 +5582,7 @@ index 0000000000000000000000000000000000000000..d0d27b9bd8132190841a7a4785d31a20
55225582
+ objectId: t.String,
55235583
+ },
55245584
+ returns: {
5525-
+ boundingBox: t.Nullable(pageTypes.BoundingBox),
5585+
+ boundingBox: t.Nullable(pageTypes.Rect),
55265586
+ },
55275587
+ },
55285588
+ 'adoptNode': {

0 commit comments

Comments
 (0)