Bug 1718761 - Move {Start,Stop}ApzAutoscroll to CanonicalBrowsingContext, r=Gijs,hiro
authorKashav Madan <kshvmdn@gmail.com>
Sat, 31 Jul 2021 01:39:09 +0000
changeset 587301 e02e9a1e0b154758dba67fbb06dfc0440da9277f
parent 587300 401ac449696446fe0a4bddce98d8874d5dfb2c9c
child 587302 84bb91189ce544a5bb914aa2f55a5655c69dceea
push id38660
push usernerli@mozilla.com
push dateSat, 31 Jul 2021 09:47:32 +0000
treeherdermozilla-central@e02e9a1e0b15 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersGijs, hiro
bugs1718761
milestone92.0a1
first release with
nightly linux32
e02e9a1e0b15 / 92.0a1 / 20210731094732 / files
nightly linux64
e02e9a1e0b15 / 92.0a1 / 20210731094732 / files
nightly mac
e02e9a1e0b15 / 92.0a1 / 20210731094732 / files
nightly win32
e02e9a1e0b15 / 92.0a1 / 20210731094732 / files
nightly win64
e02e9a1e0b15 / 92.0a1 / 20210731094732 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1718761 - Move {Start,Stop}ApzAutoscroll to CanonicalBrowsingContext, r=Gijs,hiro This accomplishes 2 things: 1. Allows us to directly fetch the layersId of the process that is autoscrolling, which avoids having to fetch it in AutoScrollChild and pass it around. This fixes autoscrolling out-of-process frames with Fission enabled. 2. Makes it easier to handle autoscrolling of in-process documents, since that can't happen through PBrowser. Differential Revision: https://phabricator.services.mozilla.com/D120766
docshell/base/CanonicalBrowsingContext.cpp
docshell/base/CanonicalBrowsingContext.h
dom/chrome-webidl/BrowsingContext.webidl
dom/interfaces/base/nsIRemoteTab.idl
dom/ipc/BrowserHost.cpp
dom/ipc/BrowserParent.cpp
dom/ipc/BrowserParent.h
gfx/layers/apz/test/mochitest/browser.ini
gfx/layers/apz/test/mochitest/browser_test_autoscrolling_in_extension_popup_window.js
gfx/layers/apz/test/mochitest/browser_test_autoscrolling_in_oop_frame.js
gfx/layers/apz/test/mochitest/helper_test_autoscrolling_in_oop_frame.html
toolkit/content/widgets/browser-custom-element.js
widget/nsBaseWidget.cpp
widget/nsBaseWidget.h
widget/nsIWidget.h
--- a/docshell/base/CanonicalBrowsingContext.cpp
+++ b/docshell/base/CanonicalBrowsingContext.cpp
@@ -42,16 +42,17 @@
 #include "nsSecureBrowserUI.h"
 #include "nsQueryObject.h"
 #include "nsBrowserStatusFilter.h"
 #include "nsIBrowser.h"
 #include "nsTHashSet.h"
 #include "SessionStoreFunctions.h"
 #include "nsIXPConnect.h"
 #include "nsImportModule.h"
+#include "UnitTransforms.h"
 
 #ifdef NS_PRINTING
 #  include "mozilla/embedding/printingui/PrintingParent.h"
 #  include "nsIWebBrowserPrint.h"
 #endif
 
 using namespace mozilla::ipc;
 
@@ -2546,16 +2547,96 @@ void CanonicalBrowsingContext::CloneDocu
                     NS_ERROR_FAILURE, __func__);
               });
 
   mClonePromise->Then(
       GetMainThreadSerialEventTarget(), __func__,
       [self = RefPtr{this}]() { self->mClonePromise = nullptr; });
 }
 
+bool CanonicalBrowsingContext::StartApzAutoscroll(float aAnchorX,
+                                                  float aAnchorY,
+                                                  nsViewID aScrollId,
+                                                  uint32_t aPresShellId) {
+  nsCOMPtr<nsIWidget> widget;
+  mozilla::layers::LayersId layersId{0};
+
+  if (IsInProcess()) {
+    nsCOMPtr<nsPIDOMWindowOuter> outer = GetDOMWindow();
+    if (!outer) {
+      return false;
+    }
+
+    widget = widget::WidgetUtils::DOMWindowToWidget(outer);
+    if (widget) {
+      layersId = widget->GetRootLayerTreeId();
+    }
+  } else {
+    RefPtr<BrowserParent> parent = GetBrowserParent();
+    if (!parent) {
+      return false;
+    }
+
+    widget = parent->GetWidget();
+    layersId = parent->GetLayersId();
+  }
+
+  if (!widget || !widget->AsyncPanZoomEnabled()) {
+    return false;
+  }
+
+  // The anchor coordinates that are passed in are relative to the origin
+  // of the screen, but we are sending them to APZ which only knows about
+  // coordinates relative to the widget, so convert them accordingly.
+  CSSPoint anchorCss{aAnchorX, aAnchorY};
+  LayoutDeviceIntPoint anchor =
+      RoundedToInt(anchorCss * widget->GetDefaultScale());
+  anchor -= widget->WidgetToScreenOffset();
+
+  mozilla::layers::ScrollableLayerGuid guid(layersId, aPresShellId, aScrollId);
+
+  return widget->StartAsyncAutoscroll(
+      ViewAs<ScreenPixel>(
+          anchor, PixelCastJustification::LayoutDeviceIsScreenForBounds),
+      guid);
+}
+
+void CanonicalBrowsingContext::StopApzAutoscroll(nsViewID aScrollId,
+                                                 uint32_t aPresShellId) {
+  nsCOMPtr<nsIWidget> widget;
+  mozilla::layers::LayersId layersId{0};
+
+  if (IsInProcess()) {
+    nsCOMPtr<nsPIDOMWindowOuter> outer = GetDOMWindow();
+    if (!outer) {
+      return;
+    }
+
+    widget = widget::WidgetUtils::DOMWindowToWidget(outer);
+    if (widget) {
+      layersId = widget->GetRootLayerTreeId();
+    }
+  } else {
+    RefPtr<BrowserParent> parent = GetBrowserParent();
+    if (!parent) {
+      return;
+    }
+
+    widget = parent->GetWidget();
+    layersId = parent->GetLayersId();
+  }
+
+  if (!widget || !widget->AsyncPanZoomEnabled()) {
+    return;
+  }
+
+  mozilla::layers::ScrollableLayerGuid guid(layersId, aPresShellId, aScrollId);
+  widget->StopAsyncAutoscroll(guid);
+}
+
 NS_IMPL_CYCLE_COLLECTION_CLASS(CanonicalBrowsingContext)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(CanonicalBrowsingContext,
                                                 BrowsingContext)
   tmp->mPermanentKey.setNull();
   if (tmp->mSessionHistory) {
     tmp->mSessionHistory->SetBrowsingContext(nullptr);
   }
--- a/docshell/base/CanonicalBrowsingContext.h
+++ b/docshell/base/CanonicalBrowsingContext.h
@@ -340,16 +340,20 @@ class CanonicalBrowsingContext final : p
                              embedding::PrintData&& aPrintData);
 
   // Returns a Promise which resolves when cloning documents for printing
   // finished if this browsing context is cloning document tree.
   RefPtr<GenericNonExclusivePromise> GetClonePromise() const {
     return mClonePromise;
   }
 
+  bool StartApzAutoscroll(float aAnchorX, float aAnchorY, nsViewID aScrollId,
+                          uint32_t aPresShellId);
+  void StopApzAutoscroll(nsViewID aScrollId, uint32_t aPresShellId);
+
  protected:
   // Called when the browsing context is being discarded.
   void CanonicalDiscard();
 
   // Called when the browsing context is being attached.
   void CanonicalAttach();
 
   // Called when the browsing context private mode is changed after
--- a/dom/chrome-webidl/BrowsingContext.webidl
+++ b/dom/chrome-webidl/BrowsingContext.webidl
@@ -308,16 +308,40 @@ interface CanonicalBrowsingContext : Bro
 
   /**
    * This allows chrome to override the default choice of whether touch events
    * are available in a specific BrowsingContext and its descendents.
    */
   [SetterThrows] inherit attribute TouchEventsOverride touchEventsOverride;
 
   readonly attribute boolean isReplaced;
+
+
+  /**
+   * Notify APZ to start autoscrolling.
+   *
+   * (aAnchorX, aAnchorY) are the coordinates of the autoscroll anchor, in CSS
+   *                      coordinates relative to the screen.
+   * aScrollId and aPresShellId identify the scroll frame that content chose to
+   *                            scroll.
+   *
+   * Returns whether we were successfully able to notify APZ.
+   * If this function returns true, APZ (which may live in another process)
+   * may still reject the autoscroll, but it's then APZ's reponsibility
+   * to notify content via an "autoscroll-rejected-by-apz" message.
+   */
+  boolean startApzAutoscroll(float aAnchorX, float aAnchorY,
+                             unsigned long long aScrollId,
+                             unsigned long aPresShellId);
+
+  /**
+   * Notify APZ to stop autoscrolling.
+   */
+  void stopApzAutoscroll(unsigned long long aScrollId,
+                         unsigned long aPresShellId);
 };
 
 [Exposed=Window, ChromeOnly]
 interface BrowsingContextGroup {
   sequence<BrowsingContext> getToplevels();
 
   readonly attribute unsigned long long id;
 };
--- a/dom/interfaces/base/nsIRemoteTab.idl
+++ b/dom/interfaces/base/nsIRemoteTab.idl
@@ -68,36 +68,16 @@ interface nsIRemoteTab : nsISupports
    *
    * @param aPrincipal the principal to use for the new document.
    * @param aPartitionedPrincipal the partitioned principal to use for the new
    *        document.
    */
   void createAboutBlankContentViewer(in nsIPrincipal aPrincipal,
                                      in nsIPrincipal aPartitionedPrincipal);
 
-  /**
-   * Notify APZ to start autoscrolling.
-   * (aAnchorX, aAnchorY) are the coordinates of the autoscroll anchor,
-   * in CSS coordinates relative to the screen. aScrollId and
-   * aPresShellId identify the scroll frame that content chose to scroll.
-   * Returns whether we were successfully able to notify APZ.
-   * If this function returns true, APZ (which may live in another process)
-   * may still reject the autoscroll, but it's then APZ's reponsibility
-   * to notify content via an "autoscroll-rejected-by-apz" message.
-   */
-  boolean startApzAutoscroll(in float aAnchorX, in float aAnchorY,
-                             in nsViewID aScrollId, in uint32_t aPresShellId);
-
-  /**
-   * Notify APZ to stop autoscrolling.
-   * aScrollId and aPresShellId identify the scroll frame that is being
-   * autoscrolled.
-   */
-  void stopApzAutoscroll(in nsViewID aScrollId, in uint32_t aPresShellId);
-
   cenum NavigationType : 8 {
     NAVIGATE_BACK = 0,
     NAVIGATE_FORWARD = 1,
     NAVIGATE_INDEX = 2,
     NAVIGATE_URL = 3
   };
 
   /**
--- a/dom/ipc/BrowserHost.cpp
+++ b/dom/ipc/BrowserHost.cpp
@@ -234,40 +234,16 @@ BrowserHost::CreateAboutBlankContentView
     return rv;
   }
 
   Unused << mRoot->SendCreateAboutBlankContentViewer(aPrincipal,
                                                      aPartitionedPrincipal);
   return NS_OK;
 }
 
-/* boolean startApzAutoscroll (in float aAnchorX, in float aAnchorY, in nsViewID
- * aScrollId, in uint32_t aPresShellId); */
-NS_IMETHODIMP
-BrowserHost::StartApzAutoscroll(float aAnchorX, float aAnchorY,
-                                nsViewID aScrollId, uint32_t aPresShellId,
-                                bool* _retval) {
-  if (!mRoot) {
-    return NS_OK;
-  }
-  *_retval =
-      mRoot->StartApzAutoscroll(aAnchorX, aAnchorY, aScrollId, aPresShellId);
-  return NS_OK;
-}
-
-/* void stopApzAutoscroll (in nsViewID aScrollId, in uint32_t aPresShellId); */
-NS_IMETHODIMP
-BrowserHost::StopApzAutoscroll(nsViewID aScrollId, uint32_t aPresShellId) {
-  if (!mRoot) {
-    return NS_OK;
-  }
-  mRoot->StopApzAutoscroll(aScrollId, aPresShellId);
-  return NS_OK;
-}
-
 NS_IMETHODIMP
 BrowserHost::MaybeCancelContentJSExecutionFromScript(
     nsIRemoteTab::NavigationType aNavigationType,
     JS::Handle<JS::Value> aCancelContentJSOptions, JSContext* aCx) {
   // If we're in the process of creating a new window (via window.open), then
   // the load that called this function isn't a "normal" load and should be
   // ignored for the purposes of cancelling content JS.
   if (!mRoot || mRoot->CreatingWindow()) {
--- a/dom/ipc/BrowserParent.cpp
+++ b/dom/ipc/BrowserParent.cpp
@@ -3439,62 +3439,16 @@ void BrowserParent::NotifyResolutionChan
     // fails to cache the values, then mDefaultScale.scale might be invalid.
     // We don't want to send that value to content. Just send -1 for it too in
     // that case.
     Unused << SendUIResolutionChanged(mDPI, mRounding,
                                       mDPI < 0 ? -1.0 : mDefaultScale.scale);
   }
 }
 
-bool BrowserParent::StartApzAutoscroll(float aAnchorX, float aAnchorY,
-                                       nsViewID aScrollId,
-                                       uint32_t aPresShellId) {
-  if (!AsyncPanZoomEnabled()) {
-    return false;
-  }
-
-  bool success = false;
-  if (mRemoteLayerTreeOwner.IsInitialized()) {
-    layers::LayersId layersId = mRemoteLayerTreeOwner.GetLayersId();
-    if (nsCOMPtr<nsIWidget> widget = GetWidget()) {
-      ScrollableLayerGuid guid(layersId, aPresShellId, aScrollId);
-
-      // The anchor coordinates that are passed in are relative to the origin
-      // of the screen, but we are sending them to APZ which only knows about
-      // coordinates relative to the widget, so convert them accordingly.
-      CSSPoint anchorCss{aAnchorX, aAnchorY};
-      LayoutDeviceIntPoint anchor =
-          RoundedToInt(anchorCss * widget->GetDefaultScale());
-      anchor -= widget->WidgetToScreenOffset();
-
-      success = widget->StartAsyncAutoscroll(
-          ViewAs<ScreenPixel>(
-              anchor, PixelCastJustification::LayoutDeviceIsScreenForBounds),
-          guid);
-    }
-  }
-  return success;
-}
-
-void BrowserParent::StopApzAutoscroll(nsViewID aScrollId,
-                                      uint32_t aPresShellId) {
-  if (!AsyncPanZoomEnabled()) {
-    return;
-  }
-
-  if (mRemoteLayerTreeOwner.IsInitialized()) {
-    layers::LayersId layersId = mRemoteLayerTreeOwner.GetLayersId();
-    if (nsCOMPtr<nsIWidget> widget = GetWidget()) {
-      ScrollableLayerGuid guid(layersId, aPresShellId, aScrollId);
-
-      widget->StopAsyncAutoscroll(guid);
-    }
-  }
-}
-
 bool BrowserParent::CanCancelContentJS(
     nsIRemoteTab::NavigationType aNavigationType, int32_t aNavigationIndex,
     nsIURI* aNavigationURI) const {
   // Pre-checking if we can cancel content js in the parent is only
   // supported when session history in the parent is enabled.
   if (!mozilla::SessionHistoryInParent()) {
     // If session history in the parent isn't enabled, this check will
     // be fully done in BrowserChild::CanCancelContentJS
--- a/dom/ipc/BrowserParent.h
+++ b/dom/ipc/BrowserParent.h
@@ -691,20 +691,16 @@ class BrowserParent final : public PBrow
 
   bool GetHasPresented();
   bool GetHasLayers();
   bool GetRenderLayers();
   void SetRenderLayers(bool aRenderLayers);
   void PreserveLayers(bool aPreserveLayers);
   void NotifyResolutionChanged();
 
-  bool StartApzAutoscroll(float aAnchorX, float aAnchorY, nsViewID aScrollId,
-                          uint32_t aPresShellId);
-  void StopApzAutoscroll(nsViewID aScrollId, uint32_t aPresShellId);
-
   bool CanCancelContentJS(nsIRemoteTab::NavigationType aNavigationType,
                           int32_t aNavigationIndex,
                           nsIURI* aNavigationURI) const;
 
   // Called when the BrowserParent is being destroyed or entering bfcache.
   void Deactivated();
 
  protected:
--- a/gfx/layers/apz/test/mochitest/browser.ini
+++ b/gfx/layers/apz/test/mochitest/browser.ini
@@ -36,8 +36,12 @@ support-files =
 skip-if = verify || os == 'linux' # Bug 1713052
 [browser_test_scrolling_in_extension_popup_window.js]
 [browser_test_scrolling_on_inactive_scroller_in_extension_popup_window.js]
 run-if = (os == 'mac') # bug 1700805
 [browser_test_scroll_thumb_dragging.js]
 support-files =
   helper_scroll_thumb_dragging.html
 [browser_test_autoscrolling_in_extension_popup_window.js]
+[browser_test_autoscrolling_in_oop_frame.js]
+skip-if = !fission
+support-files =
+  helper_test_autoscrolling_in_oop_frame.html
--- a/gfx/layers/apz/test/mochitest/browser_test_autoscrolling_in_extension_popup_window.js
+++ b/gfx/layers/apz/test/mochitest/browser_test_autoscrolling_in_extension_popup_window.js
@@ -112,17 +112,17 @@ add_task(async () => {
         viewId: winUtils.getViewId(content.document.documentElement),
         presShellId: winUtils.getPresShellId(),
       };
     }
   );
 
   // Start autoscrolling.
   ok(
-    browserForPopup.frameLoader.remoteTab.startApzAutoscroll(
+    browserForPopup.browsingContext.startApzAutoscroll(
       screenX + 100,
       screenY + 50,
       viewId,
       presShellId
     )
   );
 
   const scrollEventPromise = SpecialPowers.spawn(
@@ -158,14 +158,14 @@ add_task(async () => {
 
   await Promise.all([apzPromise, scrollEventPromise]);
 
   const scrollY = await SpecialPowers.spawn(browserForPopup, [], () => {
     return content.window.scrollY;
   });
   ok(scrollY > 0, "Autoscrolling works in the popup window");
 
-  browserForPopup.frameLoader.remoteTab.stopApzAutoscroll(viewId, presShellId);
+  browserForPopup.browsingContext.stopApzAutoscroll(viewId, presShellId);
 
   await closeBrowserAction(extension);
 
   await extension.unload();
 });
new file mode 100644
--- /dev/null
+++ b/gfx/layers/apz/test/mochitest/browser_test_autoscrolling_in_oop_frame.js
@@ -0,0 +1,111 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+Services.scriptloader.loadSubScript(
+  "chrome://mochitests/content/browser/gfx/layers/apz/test/mochitest/apz_test_utils.js",
+  this
+);
+
+Services.scriptloader.loadSubScript(
+  "chrome://mochitests/content/browser/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js",
+  this
+);
+
+add_task(async function setup() {
+  await SpecialPowers.pushPrefEnv({
+    set: [
+      ["general.autoScroll", true],
+      ["middlemouse.contentLoadURL", false],
+      ["test.events.async.enabled", true],
+    ],
+  });
+});
+
+add_task(async function test_main() {
+  function httpURL(filename) {
+    const chromeURL = getRootDirectory(gTestPath) + filename;
+    return chromeURL.replace(
+      "chrome://mochitests/content/",
+      "http://mochi.test:8888/"
+    );
+  }
+
+  function getScrollY(context) {
+    return SpecialPowers.spawn(context, [], () => content.scrollY);
+  }
+
+  const pageUrl = httpURL("helper_test_autoscrolling_in_oop_frame.html");
+
+  await BrowserTestUtils.withNewTab(pageUrl, async function(browser) {
+    await flushApzRepaintsInPopup(browser);
+
+    const iframeContext = browser.browsingContext.children[0];
+    await flushApzRepaintsInPopup(iframeContext);
+
+    const { screenX, screenY, viewId, presShellId } = await SpecialPowers.spawn(
+      iframeContext,
+      [],
+      () => {
+        const winUtils = SpecialPowers.getDOMWindowUtils(content);
+        return {
+          screenX: content.mozInnerScreenX,
+          screenY: content.mozInnerScreenY,
+          viewId: winUtils.getViewId(content.document.documentElement),
+          presShellId: winUtils.getPresShellId(),
+        };
+      }
+    );
+
+    ok(
+      iframeContext.startApzAutoscroll(
+        screenX + 100,
+        screenY + 50,
+        viewId,
+        presShellId
+      ),
+      "Started autscroll"
+    );
+
+    const scrollEventPromise = SpecialPowers.spawn(
+      iframeContext,
+      [],
+      async () => {
+        return new Promise(resolve => {
+          content.addEventListener(
+            "scroll",
+            event => {
+              dump("Got a scroll event in the iframe\n");
+              resolve();
+            },
+            { once: true }
+          );
+        });
+      }
+    );
+
+    // Send sequential mousemove events to cause autoscrolling.
+    for (let i = 0; i < 10; i++) {
+      await promiseNativeMouseEventWithAPZ({
+        type: "mousemove",
+        target: browser,
+        offsetX: 100,
+        offsetY: 50 + i * 10,
+      });
+    }
+
+    // Flush APZ repaints and waits for MozAfterPaint to make sure the scroll has
+    // been reflected on the main thread.
+    const apzPromise = flushApzRepaintsInPopup(browser);
+
+    await Promise.all([apzPromise, scrollEventPromise]);
+
+    const frameScrollY = await getScrollY(iframeContext);
+    ok(frameScrollY > 0, "Autoscrolled the iframe");
+
+    const rootScrollY = await getScrollY(browser);
+    ok(rootScrollY == 0, "Didn't scroll the root document");
+
+    iframeContext.stopApzAutoscroll(viewId, presShellId);
+  });
+});
new file mode 100644
--- /dev/null
+++ b/gfx/layers/apz/test/mochitest/helper_test_autoscrolling_in_oop_frame.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+</head>
+<body>
+  <iframe src="http://example.net" style="height: 90vh; width: 90vw;"></iframe>
+  <div style="height: 200px"></div>
+</body>
+</html>
--- a/toolkit/content/widgets/browser-custom-element.js
+++ b/toolkit/content/widgets/browser-custom-element.js
@@ -1246,35 +1246,34 @@
         window.removeEventListener("keyup", this, true);
 
         let autoScrollWnd = this._autoScrollBrowsingContext.currentWindowGlobal;
         if (autoScrollWnd) {
           autoScrollWnd
             .getActor("AutoScroll")
             .sendAsyncMessage("Autoscroll:Stop", {});
         }
-        this._autoScrollBrowsingContext = null;
 
         try {
           Services.obs.removeObserver(this.observer, "apz:cancel-autoscroll");
         } catch (ex) {
           // It's not clear why this sometimes throws an exception
         }
 
-        if (this.isRemoteBrowser && this._autoScrollScrollId != null) {
-          let { remoteTab } = this.frameLoader;
-          if (remoteTab) {
-            remoteTab.stopApzAutoscroll(
-              this._autoScrollScrollId,
-              this._autoScrollPresShellId
-            );
-          }
+        if (this._autoScrollScrollId != null) {
+          this._autoScrollBrowsingContext.stopApzAutoscroll(
+            this._autoScrollScrollId,
+            this._autoScrollPresShellId
+          );
+
           this._autoScrollScrollId = null;
           this._autoScrollPresShellId = null;
         }
+
+        this._autoScrollBrowsingContext = null;
       }
     }
 
     _getAndMaybeCreateAutoScrollPopup() {
       let autoscrollPopup = document.getElementById("autoscroller");
       if (!autoscrollPopup) {
         autoscrollPopup = document.createXULElement("panel");
         autoscrollPopup.className = "autoscroller";
@@ -1367,39 +1366,33 @@
       window.addEventListener("mouseup", this, true);
       window.addEventListener("DOMMouseScroll", this, true);
       window.addEventListener("contextmenu", this, true);
       window.addEventListener("keydown", this, true);
       window.addEventListener("keypress", this, true);
       window.addEventListener("keyup", this, true);
 
       let usingApz = false;
+
       if (
-        this.isRemoteBrowser &&
         scrollId != null &&
         this.mPrefs.getBoolPref("apz.autoscroll.enabled", false)
       ) {
-        let { remoteTab } = this.frameLoader;
-        if (remoteTab) {
-          // If APZ is handling the autoscroll, it may decide to cancel
-          // it of its own accord, so register an observer to allow it
-          // to notify us of that.
-          Services.obs.addObserver(
-            this.observer,
-            "apz:cancel-autoscroll",
-            true
-          );
+        // If APZ is handling the autoscroll, it may decide to cancel
+        // it of its own accord, so register an observer to allow it
+        // to notify us of that.
+        Services.obs.addObserver(this.observer, "apz:cancel-autoscroll", true);
 
-          usingApz = remoteTab.startApzAutoscroll(
-            screenX,
-            screenY,
-            scrollId,
-            presShellId
-          );
-        }
+        usingApz = browsingContext.startApzAutoscroll(
+          screenX,
+          screenY,
+          scrollId,
+          presShellId
+        );
+
         // Save the IDs for later
         this._autoScrollScrollId = scrollId;
         this._autoScrollPresShellId = presShellId;
       }
 
       return { autoscrollEnabled: true, usingApz };
     }
 
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -1973,16 +1973,21 @@ bool nsBaseWidget::StartAsyncAutoscroll(
 }
 
 void nsBaseWidget::StopAsyncAutoscroll(const ScrollableLayerGuid& aGuid) {
   MOZ_ASSERT(XRE_IsParentProcess() && AsyncPanZoomEnabled());
 
   mAPZC->StopAutoscroll(aGuid);
 }
 
+LayersId nsBaseWidget::GetRootLayerTreeId() {
+  return mCompositorSession ? mCompositorSession->RootLayerTreeId()
+                            : LayersId{0};
+}
+
 already_AddRefed<nsIScreen> nsBaseWidget::GetWidgetScreen() {
   nsCOMPtr<nsIScreenManager> screenManager;
   screenManager = do_GetService("@mozilla.org/gfx/screenmanager;1");
   if (!screenManager) {
     return nullptr;
   }
 
   LayoutDeviceIntRect bounds = GetScreenBounds();
--- a/widget/nsBaseWidget.h
+++ b/widget/nsBaseWidget.h
@@ -378,16 +378,18 @@ class nsBaseWidget : public nsIWidget, p
 
   void StartAsyncScrollbarDrag(const AsyncDragMetrics& aDragMetrics) override;
 
   bool StartAsyncAutoscroll(const ScreenPoint& aAnchorLocation,
                             const ScrollableLayerGuid& aGuid) override;
 
   void StopAsyncAutoscroll(const ScrollableLayerGuid& aGuid) override;
 
+  mozilla::layers::LayersId GetRootLayerTreeId() override;
+
   /**
    * Use this when GetLayerManager() returns a BasicLayerManager
    * (nsBaseWidget::GetLayerManager() does). This sets up the widget's
    * layer manager to temporarily render into aTarget.
    *
    * |aNaturalWidgetBounds| is the un-rotated bounds of |aWidget|.
    * |aRotation| is the "virtual rotation" to apply when rendering to
    * the target.  When |aRotation| is ROTATION_0,
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -376,16 +376,17 @@ class nsIWidget : public nsISupports {
  public:
   typedef mozilla::layers::CompositorBridgeChild CompositorBridgeChild;
   typedef mozilla::layers::AsyncDragMetrics AsyncDragMetrics;
   typedef mozilla::layers::FrameMetrics FrameMetrics;
   typedef mozilla::layers::LayerManager LayerManager;
   typedef mozilla::WindowRenderer WindowRenderer;
   typedef mozilla::layers::LayerManagerComposite LayerManagerComposite;
   typedef mozilla::layers::LayersBackend LayersBackend;
+  typedef mozilla::layers::LayersId LayersId;
   typedef mozilla::layers::PLayerTransactionChild PLayerTransactionChild;
   typedef mozilla::layers::ScrollableLayerGuid ScrollableLayerGuid;
   typedef mozilla::layers::ZoomConstraints ZoomConstraints;
   typedef mozilla::widget::IMEEnabled IMEEnabled;
   typedef mozilla::widget::IMEMessage IMEMessage;
   typedef mozilla::widget::IMENotification IMENotification;
   typedef mozilla::widget::IMENotificationRequests IMENotificationRequests;
   typedef mozilla::widget::IMEState IMEState;
@@ -1753,16 +1754,18 @@ class nsIWidget : public nsISupports {
                                     const ScrollableLayerGuid& aGuid) = 0;
 
   /**
    * Notify APZ to stop autoscrolling.
    * @param aGuid identifies the scroll frame which is being autoscrolled.
    */
   virtual void StopAsyncAutoscroll(const ScrollableLayerGuid& aGuid) = 0;
 
+  virtual LayersId GetRootLayerTreeId() = 0;
+
   // If this widget supports out-of-process compositing, it can override
   // this method to provide additional information to the compositor.
   virtual void GetCompositorWidgetInitData(
       mozilla::widget::CompositorWidgetInitData* aInitData) {}
 
   /**
    * Setter/Getter of the system font setting for testing.
    */