Bug 1530661 - Make APZ report the per LayersId layer-to-screen transform matrices to the chrome process. r=kats
authorHenri Sivonen <hsivonen@hsivonen.fi>
Sat, 09 Mar 2019 20:33:17 +0000
changeset 524266 91d0c9066fd139285e025b0b87a70f61823281af
parent 524265 3c4b55694127237c3dd740d5ed055959c4d783fe
child 524267 fc3a2f173e667a9ce3ca641f70d9562bdf355bb1
push id2032
push userffxbld-merge
push dateMon, 13 May 2019 09:36:57 +0000
treeherdermozilla-release@455c1065dcbe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskats
bugs1530661
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1530661 - Make APZ report the per LayersId layer-to-screen transform matrices to the chrome process. r=kats Differential Revision: https://phabricator.services.mozilla.com/D22082
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
gfx/layers/apz/public/GeckoContentController.h
gfx/layers/apz/public/MatrixMessage.h
gfx/layers/apz/src/APZCTreeManager.cpp
gfx/layers/apz/src/APZCTreeManager.h
gfx/layers/apz/src/HitTestingTreeNode.cpp
gfx/layers/apz/src/HitTestingTreeNode.h
gfx/layers/apz/test/gtest/APZTestCommon.h
gfx/layers/apz/util/APZCCallbackHelper.cpp
gfx/layers/apz/util/APZCCallbackHelper.h
gfx/layers/apz/util/ChromeProcessController.cpp
gfx/layers/apz/util/ChromeProcessController.h
gfx/layers/apz/util/ContentProcessController.cpp
gfx/layers/apz/util/ContentProcessController.h
gfx/layers/ipc/APZChild.cpp
gfx/layers/ipc/APZChild.h
gfx/layers/ipc/LayersMessageUtils.h
gfx/layers/ipc/PAPZ.ipdl
gfx/layers/ipc/RemoteContentController.cpp
gfx/layers/ipc/RemoteContentController.h
gfx/layers/moz.build
gfx/thebes/gfxPrefs.h
layout/base/UnitTransforms.h
layout/base/Units.h
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -1999,22 +1999,28 @@ LayoutDeviceIntRect TabParent::Transform
   LayoutDeviceRect floatTransformed = matrix.TransformBounds(floatRect);
   // The next line loses precision if an out-of-process iframe
   // has been scaled or rotated.
   return RoundedToInt(floatTransformed);
 }
 
 LayoutDeviceToLayoutDeviceMatrix4x4
 TabParent::GetChildToParentConversionMatrix() {
-  // Placeholder: Replace this implementation with one that obtains the
-  // matrix from APZ/WebRender.
+  if (mChildToParentConversionMatrix) {
+    return *mChildToParentConversionMatrix;
+  }
   LayoutDevicePoint offset(-GetChildProcessOffset());
   return LayoutDeviceToLayoutDeviceMatrix4x4::Translation(offset);
 }
 
+void TabParent::SetChildToParentConversionMatrix(
+    const LayoutDeviceToLayoutDeviceMatrix4x4& aMatrix) {
+  mChildToParentConversionMatrix = Some(aMatrix);
+}
+
 LayoutDeviceIntPoint TabParent::GetChildProcessOffset() {
   // The "toplevel widget" in child processes is always at position
   // 0,0.  Map the event coordinates to match that.
 
   LayoutDeviceIntPoint offset(0, 0);
   RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
   if (!frameLoader) {
     return offset;
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -513,16 +513,19 @@ class TabParent final : public PBrowserP
       const LayoutDeviceIntPoint& aPoint);
   LayoutDevicePoint TransformChildToParent(const LayoutDevicePoint& aPoint);
   LayoutDeviceIntRect TransformChildToParent(const LayoutDeviceIntRect& aRect);
 
   // Returns the matrix that transforms event coordinates from the coordinate
   // space of the child process to the coordinate space of the parent process.
   LayoutDeviceToLayoutDeviceMatrix4x4 GetChildToParentConversionMatrix();
 
+  void SetChildToParentConversionMatrix(
+      const LayoutDeviceToLayoutDeviceMatrix4x4& aMatrix);
+
   // Returns the offset from the origin of our frameloader's nearest widget to
   // the origin of its layout frame. This offset is used to translate event
   // coordinates relative to the PuppetWidget origin in the child process.
   //
   // GOING AWAY. PLEASE AVOID ADDING CALLERS. Use the above tranformation
   // methods instead.
   LayoutDeviceIntPoint GetChildProcessOffset();
 
@@ -762,16 +765,18 @@ class TabParent final : public PBrowserP
   static void AddTabParentToTable(layers::LayersId aLayersId,
                                   TabParent* aTabParent);
 
   static void RemoveTabParentFromTable(layers::LayersId aLayersId);
 
   layout::RenderFrame mRenderFrame;
   LayersObserverEpoch mLayerTreeEpoch;
 
+  Maybe<LayoutDeviceToLayoutDeviceMatrix4x4> mChildToParentConversionMatrix;
+
   // If this flag is set, then the tab's layers will be preserved even when
   // the tab's docshell is inactive.
   bool mPreserveLayers;
 
   // Holds the most recent value passed to the RenderLayers function. This
   // does not necessarily mean that the layers have finished rendering
   // and have uploaded - for that, use mHasLayers.
   bool mRenderLayers;
--- a/gfx/layers/apz/public/GeckoContentController.h
+++ b/gfx/layers/apz/public/GeckoContentController.h
@@ -8,31 +8,41 @@
 #define mozilla_layers_GeckoContentController_h
 
 #include "InputData.h"                           // for PinchGestureInput
 #include "LayersTypes.h"                         // for ScrollDirection
 #include "Units.h"                               // for CSSPoint, CSSRect, etc
 #include "mozilla/Assertions.h"                  // for MOZ_ASSERT_HELPER2
 #include "mozilla/DefineEnum.h"                  // for MOZ_DEFINE_ENUM
 #include "mozilla/EventForwards.h"               // for Modifiers
+#include "mozilla/layers/MatrixMessage.h"        // for MatrixMessage
 #include "mozilla/layers/RepaintRequest.h"       // for RepaintRequest
 #include "mozilla/layers/ScrollableLayerGuid.h"  // for ScrollableLayerGuid, etc
 #include "nsISupportsImpl.h"
 
 namespace mozilla {
 
 class Runnable;
 
 namespace layers {
 
 class GeckoContentController {
  public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GeckoContentController)
 
   /**
+   * Notifies the content side of the most recently computed transforms for
+   * each layers subtree to the root. The nsTArray will contain one
+   *  MatrixMessage for each layers id in the current APZ tree, along with the
+   * corresponding transform.
+   */
+  virtual void NotifyLayerTransforms(
+      const nsTArray<MatrixMessage>& aTransforms) = 0;
+
+  /**
    * Requests a paint of the given RepaintRequest |aRequest| from Gecko.
    * Implementations per-platform are responsible for actually handling this.
    *
    * This method must always be called on the repaint thread, which depends
    * on the GeckoContentController. For ChromeProcessController it is the
    * Gecko main thread, while for RemoteContentController it is the compositor
    * thread where it can send IPDL messages.
    */
@@ -185,16 +195,21 @@ class GeckoContentController {
 
   GeckoContentController() {}
 
   /**
    * Needs to be called on the main thread.
    */
   virtual void Destroy() {}
 
+  /**
+   * Whether this is RemoteContentController.
+   */
+  virtual bool IsRemote() { return false; }
+
  protected:
   // Protected destructor, to discourage deletion outside of Release():
   virtual ~GeckoContentController() {}
 };
 
 }  // namespace layers
 }  // namespace mozilla
 
new file mode 100644
--- /dev/null
+++ b/gfx/layers/apz/public/MatrixMessage.h
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_layers_MatrixMessage_h
+#define mozilla_layers_MatrixMessage_h
+
+#include "mozilla/gfx/Matrix.h"
+#include "mozilla/layers/LayersTypes.h"
+
+namespace mozilla {
+namespace layers {
+class MatrixMessage {
+ public:
+  // Don't use this one directly
+  MatrixMessage() {}
+
+  MatrixMessage(const LayerToScreenMatrix4x4& aMatrix,
+                const LayersId& aLayersId)
+      : mMatrix(aMatrix.ToUnknownMatrix()), mLayersId(aLayersId) {}
+
+  inline LayerToScreenMatrix4x4 GetMatrix() const {
+    return LayerToScreenMatrix4x4::FromUnknownMatrix(mMatrix);
+  }
+
+  inline const LayersId& GetLayersId() const { return mLayersId; }
+
+  // Fields are public for IPC. Don't access directly
+  // elsewhere.
+  gfx::Matrix4x4 mMatrix;  // Untyped for IPC
+  LayersId mLayersId;
+};
+};  // namespace layers
+};  // namespace mozilla
+
+#endif  // mozilla_layers_MatrixMessage_h
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -27,16 +27,17 @@
 #endif
 #include "mozilla/layers/APZSampler.h"      // for APZSampler
 #include "mozilla/layers/APZThreadUtils.h"  // for AssertOnControllerThread, etc
 #include "mozilla/layers/APZUpdater.h"      // for APZUpdater
 #include "mozilla/layers/AsyncCompositionManager.h"  // for ViewTransform
 #include "mozilla/layers/AsyncDragMetrics.h"         // for AsyncDragMetrics
 #include "mozilla/layers/CompositorBridgeParent.h"  // for CompositorBridgeParent, etc
 #include "mozilla/layers/LayerMetricsWrapper.h"
+#include "mozilla/layers/MatrixMessage.h"
 #include "mozilla/layers/WebRenderScrollDataWrapper.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/mozalloc.h"  // for operator new
 #include "mozilla/TouchEvents.h"
 #include "mozilla/Preferences.h"        // for Preferences
 #include "mozilla/EventStateManager.h"  // for WheelPrefs
 #include "mozilla/webrender/WebRenderAPI.h"
 #include "nsDebug.h"                 // for NS_WARNING
@@ -547,16 +548,17 @@ APZCTreeManager::UpdateHitTestingTreeImp
 
 #if ENABLE_APZCTM_LOGGING
   // Make the hit-test tree line up with the layer dump
   printf_stderr("APZCTreeManager (%p)\n", this);
   if (mRootNode) {
     mRootNode->Dump("  ");
   }
 #endif
+  CollectTransformsForChromeMainThread(aRootLayerTreeId);
 }
 
 void APZCTreeManager::UpdateFocusState(LayersId aRootLayerTreeId,
                                        LayersId aOriginatingLayersId,
                                        const FocusTarget& aFocusTarget) {
   AssertOnUpdaterThread();
 
   if (!gfxPrefs::APZKeyboardEnabled()) {
@@ -3166,16 +3168,48 @@ bool APZCTreeManager::GetAPZTestData(Lay
   auto it = mTestData.find(aLayersId);
   if (it == mTestData.end()) {
     return false;
   }
   *aOutData = *(it->second);
   return true;
 }
 
+void APZCTreeManager::CollectTransformsForChromeMainThread(
+    LayersId aRootLayerTreeId) {
+  RefPtr<GeckoContentController> controller =
+      GetContentController(aRootLayerTreeId);
+  if (!controller) {
+    return;
+  }
+  if (controller->IsRemote() && !gfxPrefs::FissionApzMatricesWithGpuProcess()) {
+    // Avoid IPC errors in the GPU process case until
+    // https://bugzilla.mozilla.org/show_bug.cgi?id=1533673
+    // is resolved.
+    return;
+  }
+  nsTArray<MatrixMessage> messages;
+  {
+    RecursiveMutexAutoLock lock(mTreeLock);
+    // This formulation duplicates matrix multiplications closer
+    // to the root of the tree. For now, aiming for separation
+    // of concerns rather than minimum number of multiplications.
+    ForEachNode<ReverseIterator>(
+        mRootNode.get(), [&messages](HitTestingTreeNode* aNode) {
+          LayersId layersId = aNode->GetLayersId();
+          HitTestingTreeNode* parent = aNode->GetParent();
+          if (!parent || layersId != parent->GetLayersId()) {
+            messages.AppendElement(
+                MatrixMessage(aNode->GetCSSTransformToRoot(), layersId));
+          }
+        });
+  }
+  controller->NotifyLayerTransforms(messages);
+}
+
 /*static*/
 LayerToParentLayerMatrix4x4 APZCTreeManager::ComputeTransformForScrollThumb(
     const LayerToParentLayerMatrix4x4& aCurrentTransform,
     const Matrix4x4& aScrollableContentTransform, AsyncPanZoomController* aApzc,
     const FrameMetrics& aMetrics, const ScrollbarData& aScrollbarData,
     bool aScrollbarIsDescendant,
     AsyncTransformComponentMatrix* aOutClipTransform) {
   // We only apply the transform if the scroll-target layer has non-container
--- a/gfx/layers/apz/src/APZCTreeManager.h
+++ b/gfx/layers/apz/src/APZCTreeManager.h
@@ -14,23 +14,23 @@
 #include "mozilla/Assertions.h"  // for MOZ_ASSERT_HELPER2
 #include "mozilla/gfx/CompositorHitTestInfo.h"
 #include "mozilla/gfx/Logging.h"              // for gfx::TreeLog
 #include "mozilla/gfx/Matrix.h"               // for Matrix4x4
 #include "mozilla/layers/APZInputBridge.h"    // for APZInputBridge
 #include "mozilla/layers/APZTestData.h"       // for APZTestData
 #include "mozilla/layers/IAPZCTreeManager.h"  // for IAPZCTreeManager
 #include "mozilla/layers/LayersTypes.h"
-#include "mozilla/layers/KeyboardMap.h"  // for KeyboardMap
-#include "mozilla/layers/TouchCounter.h" // for TouchCounter
-#include "mozilla/RecursiveMutex.h"      // for RecursiveMutex
-#include "mozilla/RefPtr.h"              // for RefPtr
-#include "mozilla/TimeStamp.h"           // for mozilla::TimeStamp
-#include "mozilla/UniquePtr.h"           // for UniquePtr
-#include "nsCOMPtr.h"                    // for already_AddRefed
+#include "mozilla/layers/KeyboardMap.h"   // for KeyboardMap
+#include "mozilla/layers/TouchCounter.h"  // for TouchCounter
+#include "mozilla/RecursiveMutex.h"       // for RecursiveMutex
+#include "mozilla/RefPtr.h"               // for RefPtr
+#include "mozilla/TimeStamp.h"            // for mozilla::TimeStamp
+#include "mozilla/UniquePtr.h"            // for UniquePtr
+#include "nsCOMPtr.h"                     // for already_AddRefed
 
 #if defined(MOZ_WIDGET_ANDROID)
 #  include "mozilla/layers/AndroidDynamicToolbarAnimator.h"
 #endif  // defined(MOZ_WIDGET_ANDROID)
 
 namespace mozilla {
 class MultiTouchInput;
 
@@ -496,16 +496,23 @@ class APZCTreeManager : public IAPZCTree
                              LayersId* aOutLayersId) override;
 
   void UpdateWheelTransaction(LayoutDeviceIntPoint aRefPoint,
                               EventMessage aEventMessage) override;
 
   bool GetAPZTestData(LayersId aLayersId, APZTestData* aOutData);
 
   /**
+   * Iterates over the hit testing tree, collects LayersIds and associated
+   * transforms from layer coordinate space to root coordinate space, and
+   * sends these over to the main thread of the chrome process.
+   */
+  void CollectTransformsForChromeMainThread(LayersId aRootLayerTreeId);
+
+  /**
    * Compute the updated shadow transform for a scroll thumb layer that
    * reflects async scrolling of the associated scroll frame.
    *
    * @param aCurrentTransform The current shadow transform on the scroll thumb
    *    layer, as returned by Layer::GetLocalTransform() or similar.
    * @param aScrollableContentTransform The current content transform on the
    *    scrollable content, as returned by Layer::GetTransform().
    * @param aApzc The APZC that scrolls the scroll frame.
--- a/gfx/layers/apz/src/HitTestingTreeNode.cpp
+++ b/gfx/layers/apz/src/HitTestingTreeNode.cpp
@@ -305,16 +305,32 @@ CompositorHitTestInfo HitTestingTreeNode
 EventRegionsOverride HitTestingTreeNode::GetEventRegionsOverride() const {
   return mOverride;
 }
 
 const CSSTransformMatrix& HitTestingTreeNode::GetTransform() const {
   return mTransform;
 }
 
+LayerToScreenMatrix4x4 HitTestingTreeNode::GetCSSTransformToRoot() const {
+  if (mParent) {
+    LayerToParentLayerMatrix4x4 thisToParent =
+        mTransform * AsyncTransformMatrix();
+    ParentLayerToScreenMatrix4x4 parentToRoot =
+        ViewAs<ParentLayerToScreenMatrix4x4>(
+            mParent->GetCSSTransformToRoot(),
+            PixelCastJustification::MovingDownToChildren);
+    return thisToParent * parentToRoot;
+  }
+
+  return ViewAs<LayerToScreenMatrix4x4>(
+      mTransform * AsyncTransformMatrix(),
+      PixelCastJustification::ScreenIsParentLayerForRoot);
+}
+
 const LayerIntRegion& HitTestingTreeNode::GetVisibleRegion() const {
   return mVisibleRegion;
 }
 
 bool HitTestingTreeNode::IsAsyncZoomContainer() const {
   return mIsAsyncZoomContainer;
 }
 
--- a/gfx/layers/apz/src/HitTestingTreeNode.h
+++ b/gfx/layers/apz/src/HitTestingTreeNode.h
@@ -134,16 +134,17 @@ class HitTestingTreeNode {
       const ParentLayerPoint& aPoint,
       const LayerToParentLayerMatrix4x4& aTransform) const;
   /* Assuming aPoint is inside the clip region for this node, check which of the
    * event region spaces it falls inside. */
   gfx::CompositorHitTestInfo HitTest(const LayerPoint& aPoint) const;
   /* Returns the mOverride flag. */
   EventRegionsOverride GetEventRegionsOverride() const;
   const CSSTransformMatrix& GetTransform() const;
+  LayerToScreenMatrix4x4 GetCSSTransformToRoot() const;
   const LayerIntRegion& GetVisibleRegion() const;
 
   bool IsAsyncZoomContainer() const;
 
   /* Debug helpers */
   void Dump(const char* aPrefix = "") const;
 
  private:
--- a/gfx/layers/apz/test/gtest/APZTestCommon.h
+++ b/gfx/layers/apz/test/gtest/APZTestCommon.h
@@ -17,16 +17,17 @@
 
 #include "mozilla/Attributes.h"
 #include "mozilla/gfx/gfxVars.h"
 #include "mozilla/layers/AsyncCompositionManager.h"  // for ViewTransform
 #include "mozilla/layers/GeckoContentController.h"
 #include "mozilla/layers/CompositorBridgeParent.h"
 #include "mozilla/layers/LayerMetricsWrapper.h"
 #include "mozilla/layers/APZThreadUtils.h"
+#include "mozilla/layers/MatrixMessage.h"
 #include "mozilla/TypedEnumBits.h"
 #include "mozilla/UniquePtr.h"
 #include "apz/src/APZCTreeManager.h"
 #include "apz/src/AsyncPanZoomController.h"
 #include "apz/src/HitTestingTreeNode.h"
 #include "base/task.h"
 #include "Layers.h"
 #include "TestLayers.h"
@@ -98,16 +99,17 @@ class ScopedGfxSetting {
 
 static TimeStamp GetStartupTime() {
   static TimeStamp sStartupTime = TimeStamp::Now();
   return sStartupTime;
 }
 
 class MockContentController : public GeckoContentController {
  public:
+  MOCK_METHOD1(NotifyLayerTransforms, void(const nsTArray<MatrixMessage>&));
   MOCK_METHOD1(RequestContentRepaint, void(const RepaintRequest&));
   MOCK_METHOD2(RequestFlingSnap,
                void(const ScrollableLayerGuid::ViewID& aScrollId,
                     const mozilla::CSSPoint& aDestination));
   MOCK_METHOD2(AcknowledgeScrollUpdate,
                void(const ScrollableLayerGuid::ViewID&,
                     const uint32_t& aScrollGeneration));
   MOCK_METHOD5(HandleTap, void(TapType, const LayoutDevicePoint&, Modifiers,
--- a/gfx/layers/apz/util/APZCCallbackHelper.cpp
+++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp
@@ -272,16 +272,30 @@ static void SetDisplayPortMargins(nsIPre
 
 static void SetPaintRequestTime(nsIContent* aContent,
                                 const TimeStamp& aPaintRequestTime) {
   aContent->SetProperty(nsGkAtoms::paintRequestTime,
                         new TimeStamp(aPaintRequestTime),
                         nsINode::DeleteProperty<TimeStamp>);
 }
 
+void APZCCallbackHelper::NotifyLayerTransforms(
+    const nsTArray<MatrixMessage>& aTransforms) {
+  MOZ_ASSERT(NS_IsMainThread());
+  for (const MatrixMessage& msg : aTransforms) {
+    TabParent* parent = TabParent::GetTabParentFromLayersId(msg.GetLayersId());
+    if (parent) {
+      parent->SetChildToParentConversionMatrix(
+          ViewAs<LayoutDeviceToLayoutDeviceMatrix4x4>(
+              msg.GetMatrix(),
+              PixelCastJustification::ContentProcessIsLayerInUiProcess));
+    }
+  }
+}
+
 void APZCCallbackHelper::UpdateRootFrame(const RepaintRequest& aRequest) {
   if (aRequest.GetScrollId() == ScrollableLayerGuid::NULL_SCROLL_ID) {
     return;
   }
   nsIContent* content = nsLayoutUtils::FindContentFor(aRequest.GetScrollId());
   if (!content) {
     return;
   }
--- a/gfx/layers/apz/util/APZCCallbackHelper.h
+++ b/gfx/layers/apz/util/APZCCallbackHelper.h
@@ -5,16 +5,17 @@
 
 #ifndef mozilla_layers_APZCCallbackHelper_h
 #define mozilla_layers_APZCCallbackHelper_h
 
 #include "InputData.h"
 #include "LayersTypes.h"
 #include "mozilla/EventForwards.h"
 #include "mozilla/layers/APZUtils.h"
+#include "mozilla/layers/MatrixMessage.h"
 #include "mozilla/layers/RepaintRequest.h"
 #include "nsIDOMWindowUtils.h"
 #include "nsRefreshDriver.h"
 
 #include <functional>
 
 class nsIContent;
 class nsIPresShell;
@@ -54,16 +55,18 @@ class DisplayportSetListener : public ns
    interface in similar-but- not-quite-the-same ways, this utility class
    provides some helpful methods to hold code that can be shared across the
    different platform implementations.
  */
 class APZCCallbackHelper {
   typedef mozilla::layers::ScrollableLayerGuid ScrollableLayerGuid;
 
  public:
+  static void NotifyLayerTransforms(const nsTArray<MatrixMessage>& aTransforms);
+
   /* Applies the scroll and zoom parameters from the given RepaintRequest object
      to the root frame for the given metrics' scrollId. If tiled thebes layers
      are enabled, this will align the displayport to tile boundaries. Setting
      the scroll position can cause some small adjustments to be made to the
      actual scroll position. */
   static void UpdateRootFrame(const RepaintRequest& aRequest);
 
   /* Applies the scroll parameters from the given RepaintRequest object to the
--- a/gfx/layers/apz/util/ChromeProcessController.cpp
+++ b/gfx/layers/apz/util/ChromeProcessController.cpp
@@ -43,16 +43,28 @@ ChromeProcessController::ChromeProcessCo
 }
 
 ChromeProcessController::~ChromeProcessController() {}
 
 void ChromeProcessController::InitializeRoot() {
   APZCCallbackHelper::InitializeRootDisplayport(GetPresShell());
 }
 
+void ChromeProcessController::NotifyLayerTransforms(
+    const nsTArray<MatrixMessage>& aTransforms) {
+  if (MessageLoop::current() != mUILoop) {
+    mUILoop->PostTask(NewRunnableMethod<nsTArray<MatrixMessage>>(
+        "layers::ChromeProcessController::NotifyLayerTransforms", this,
+        &ChromeProcessController::NotifyLayerTransforms, aTransforms));
+    return;
+  }
+
+  APZCCallbackHelper::NotifyLayerTransforms(aTransforms);
+}
+
 void ChromeProcessController::RequestContentRepaint(
     const RepaintRequest& aRequest) {
   MOZ_ASSERT(IsRepaintThread());
 
   if (aRequest.IsRootContent()) {
     APZCCallbackHelper::UpdateRootFrame(aRequest);
   } else {
     APZCCallbackHelper::UpdateSubFrame(aRequest);
--- a/gfx/layers/apz/util/ChromeProcessController.h
+++ b/gfx/layers/apz/util/ChromeProcessController.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_layers_ChromeProcessController_h
 #define mozilla_layers_ChromeProcessController_h
 
 #include "mozilla/layers/GeckoContentController.h"
 #include "nsCOMPtr.h"
 #include "mozilla/RefPtr.h"
+#include "mozilla/layers/MatrixMessage.h"
 
 class nsIDOMWindowUtils;
 
 class nsIPresShell;
 class nsIWidget;
 class MessageLoop;
 
 namespace mozilla {
@@ -44,16 +45,18 @@ class ChromeProcessController : public m
  public:
   explicit ChromeProcessController(nsIWidget* aWidget,
                                    APZEventState* aAPZEventState,
                                    IAPZCTreeManager* aAPZCTreeManager);
   ~ChromeProcessController();
   virtual void Destroy() override;
 
   // GeckoContentController interface
+  virtual void NotifyLayerTransforms(
+      const nsTArray<MatrixMessage>& aTransforms) override;
   virtual void RequestContentRepaint(const RepaintRequest& aRequest) override;
   virtual void PostDelayedTask(already_AddRefed<Runnable> aTask,
                                int aDelayMs) override;
   virtual bool IsRepaintThread() override;
   virtual void DispatchToRepaintThread(
       already_AddRefed<Runnable> aTask) override;
   MOZ_CAN_RUN_SCRIPT
   virtual void HandleTap(TapType aType,
--- a/gfx/layers/apz/util/ContentProcessController.cpp
+++ b/gfx/layers/apz/util/ContentProcessController.cpp
@@ -17,16 +17,22 @@ namespace mozilla {
 namespace layers {
 
 ContentProcessController::ContentProcessController(
     const RefPtr<dom::TabChild>& aBrowser)
     : mBrowser(aBrowser) {
   MOZ_ASSERT(mBrowser);
 }
 
+void ContentProcessController::NotifyLayerTransforms(
+    const nsTArray<MatrixMessage>& aTransforms) {
+  // This should never get called
+  MOZ_ASSERT(false);
+}
+
 void ContentProcessController::RequestContentRepaint(
     const RepaintRequest& aRequest) {
   if (mBrowser) {
     mBrowser->UpdateFrame(aRequest);
   }
 }
 
 void ContentProcessController::HandleTap(TapType aType,
--- a/gfx/layers/apz/util/ContentProcessController.h
+++ b/gfx/layers/apz/util/ContentProcessController.h
@@ -34,16 +34,19 @@ class APZChild;
  * updated to handle it.
  */
 class ContentProcessController final : public GeckoContentController {
  public:
   explicit ContentProcessController(const RefPtr<dom::TabChild>& aBrowser);
 
   // GeckoContentController
 
+  void NotifyLayerTransforms(
+      const nsTArray<MatrixMessage>& aTransforms) override;
+
   void RequestContentRepaint(const RepaintRequest& aRequest) override;
 
   void HandleTap(TapType aType, const LayoutDevicePoint& aPoint,
                  Modifiers aModifiers, const ScrollableLayerGuid& aGuid,
                  uint64_t aInputBlockId) override;
 
   void NotifyPinchGesture(PinchGestureInput::PinchGestureType aType,
                           const ScrollableLayerGuid& aGuid,
--- a/gfx/layers/ipc/APZChild.cpp
+++ b/gfx/layers/ipc/APZChild.cpp
@@ -22,16 +22,22 @@ APZChild::APZChild(RefPtr<GeckoContentCo
 
 APZChild::~APZChild() {
   if (mController) {
     mController->Destroy();
     mController = nullptr;
   }
 }
 
+mozilla::ipc::IPCResult APZChild::RecvLayerTransforms(
+    const nsTArray<MatrixMessage>& aTransforms) {
+  mController->NotifyLayerTransforms(aTransforms);
+  return IPC_OK();
+}
+
 mozilla::ipc::IPCResult APZChild::RecvRequestContentRepaint(
     const RepaintRequest& aRequest) {
   MOZ_ASSERT(mController->IsRepaintThread());
 
   mController->RequestContentRepaint(aRequest);
   return IPC_OK();
 }
 
--- a/gfx/layers/ipc/APZChild.h
+++ b/gfx/layers/ipc/APZChild.h
@@ -19,16 +19,19 @@ class GeckoContentController;
  * APZChild implements PAPZChild and is used to remote a GeckoContentController
  * that lives in a different process than where APZ lives.
  */
 class APZChild final : public PAPZChild {
  public:
   explicit APZChild(RefPtr<GeckoContentController> aController);
   ~APZChild();
 
+  mozilla::ipc::IPCResult RecvLayerTransforms(
+      const nsTArray<MatrixMessage>& aTransforms);
+
   mozilla::ipc::IPCResult RecvRequestContentRepaint(
       const RepaintRequest& aRequest);
 
   mozilla::ipc::IPCResult RecvUpdateOverscrollVelocity(
       const float& aX, const float& aY, const bool& aIsRootContent);
 
   mozilla::ipc::IPCResult RecvUpdateOverscrollOffset(
       const float& aX, const float& aY, const bool& aIsRootContent);
--- a/gfx/layers/ipc/LayersMessageUtils.h
+++ b/gfx/layers/ipc/LayersMessageUtils.h
@@ -17,16 +17,17 @@
 #include "mozilla/layers/AsyncDragMetrics.h"
 #include "mozilla/layers/CompositorOptions.h"
 #include "mozilla/layers/CompositorTypes.h"
 #include "mozilla/layers/FocusTarget.h"
 #include "mozilla/layers/GeckoContentController.h"
 #include "mozilla/layers/KeyboardMap.h"
 #include "mozilla/layers/LayerAttributes.h"
 #include "mozilla/layers/LayersTypes.h"
+#include "mozilla/layers/MatrixMessage.h"
 #include "mozilla/layers/RefCountedShmem.h"
 #include "mozilla/layers/RepaintRequest.h"
 #include "VsyncSource.h"
 #include "mozilla/Move.h"
 
 #include <stdint.h>
 
 #ifdef _MSC_VER
@@ -58,16 +59,20 @@ struct ParamTraits<mozilla::VsyncEvent> 
   static bool Read(const Message* msg, PickleIterator* iter,
                    paramType* result) {
     return ReadParam(msg, iter, &result->mId) &&
            ReadParam(msg, iter, &result->mTime);
   }
 };
 
 template <>
+struct ParamTraits<mozilla::layers::MatrixMessage>
+    : public PlainOldDataSerializer<mozilla::layers::MatrixMessage> {};
+
+template <>
 struct ParamTraits<mozilla::layers::LayersObserverEpoch>
     : public PlainOldDataSerializer<mozilla::layers::LayersObserverEpoch> {};
 
 template <>
 struct ParamTraits<mozilla::layers::LayersBackend>
     : public ContiguousEnumSerializer<
           mozilla::layers::LayersBackend,
           mozilla::layers::LayersBackend::LAYERS_NONE,
--- a/gfx/layers/ipc/PAPZ.ipdl
+++ b/gfx/layers/ipc/PAPZ.ipdl
@@ -12,16 +12,17 @@ include protocol PCompositorBridge;
 
 using CSSRect from "Units.h";
 using struct mozilla::layers::RepaintRequest from "mozilla/layers/RepaintRequest.h";
 using struct mozilla::layers::ScrollableLayerGuid from "mozilla/layers/ScrollableLayerGuid.h";
 using mozilla::layers::ScrollableLayerGuid::ViewID from "mozilla/layers/ScrollableLayerGuid.h";
 using mozilla::layers::MaybeZoomConstraints from "mozilla/layers/ZoomConstraints.h";
 using mozilla::layers::GeckoContentController::APZStateChange from "mozilla/layers/GeckoContentController.h";
 using mozilla::layers::ScrollDirection from "mozilla/layers/LayersTypes.h";
+using mozilla::layers::MatrixMessage from "mozilla/layers/MatrixMessage.h";
 using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
 using mozilla::dom::ContentParentId from "mozilla/dom/ipc/IdType.h";
 using mozilla::layers::AsyncDragMetrics from "mozilla/layers/AsyncDragMetrics.h";
 using class nsRegion from "nsRegion.h";
 
 namespace mozilla {
 namespace layers {
 
@@ -45,16 +46,17 @@ sync protocol PAPZ
 {
   manager PCompositorBridge;
 
 parent:
 
   async __delete__();
 
 child:
+  async LayerTransforms(MatrixMessage[] aTransforms);
 
   async RequestContentRepaint(RepaintRequest request);
 
   async UpdateOverscrollVelocity(float aX, float aY, bool aIsRootContent);
 
   async UpdateOverscrollOffset(float aX, float aY, bool aIsRootContent);
 
   async NotifyMozMouseScrollEvent(ViewID aScrollId, nsString aEvent);
--- a/gfx/layers/ipc/RemoteContentController.cpp
+++ b/gfx/layers/ipc/RemoteContentController.cpp
@@ -8,30 +8,46 @@
 
 #include "base/message_loop.h"
 #include "base/task.h"
 #include "MainThreadUtils.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/layers/APZCCallbackHelper.h"
 #include "mozilla/layers/APZCTreeManagerParent.h"  // for APZCTreeManagerParent
 #include "mozilla/layers/APZThreadUtils.h"
+#include "mozilla/layers/MatrixMessage.h"
 #include "mozilla/gfx/GPUProcessManager.h"
 #include "mozilla/Unused.h"
 #include "Units.h"
 
 namespace mozilla {
 namespace layers {
 
 using namespace mozilla::gfx;
 
 RemoteContentController::RemoteContentController()
     : mCompositorThread(MessageLoop::current()), mCanSend(true) {}
 
 RemoteContentController::~RemoteContentController() {}
 
+void RemoteContentController::NotifyLayerTransforms(
+    const nsTArray<MatrixMessage>& aTransforms) {
+  if (MessageLoop::current() != mCompositorThread) {
+    // We have to send messages from the compositor thread
+    mCompositorThread->PostTask(NewRunnableMethod<nsTArray<MatrixMessage>>(
+        "layers::RemoteContentController::NotifyLayerTransforms", this,
+        &RemoteContentController::NotifyLayerTransforms, aTransforms));
+    return;
+  }
+
+  if (mCanSend) {
+    Unused << SendLayerTransforms(aTransforms);
+  }
+}
+
 void RemoteContentController::RequestContentRepaint(
     const RepaintRequest& aRequest) {
   MOZ_ASSERT(IsRepaintThread());
 
   if (mCanSend) {
     Unused << SendRequestContentRepaint(aRequest);
   }
 }
@@ -349,10 +365,12 @@ void RemoteContentController::ActorDestr
 
 void RemoteContentController::Destroy() {
   if (mCanSend) {
     mCanSend = false;
     Unused << SendDestroy();
   }
 }
 
+bool RemoteContentController::IsRemote() { return true; }
+
 }  // namespace layers
 }  // namespace mozilla
--- a/gfx/layers/ipc/RemoteContentController.h
+++ b/gfx/layers/ipc/RemoteContentController.h
@@ -33,16 +33,19 @@ class RemoteContentController : public G
   using GeckoContentController::APZStateChange;
   using GeckoContentController::TapType;
 
  public:
   RemoteContentController();
 
   virtual ~RemoteContentController();
 
+  virtual void NotifyLayerTransforms(
+      const nsTArray<MatrixMessage>& aTransforms) override;
+
   virtual void RequestContentRepaint(const RepaintRequest& aRequest) override;
 
   virtual void HandleTap(TapType aTapType, const LayoutDevicePoint& aPoint,
                          Modifiers aModifiers, const ScrollableLayerGuid& aGuid,
                          uint64_t aInputBlockId) override;
 
   virtual void NotifyPinchGesture(PinchGestureInput::PinchGestureType aType,
                                   const ScrollableLayerGuid& aGuid,
@@ -82,16 +85,18 @@ class RemoteContentController : public G
       const ScrollableLayerGuid::ViewID& aScrollId) override;
 
   virtual void CancelAutoscroll(const ScrollableLayerGuid& aScrollId) override;
 
   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
 
   virtual void Destroy() override;
 
+  virtual bool IsRemote() override;
+
  private:
   MessageLoop* mCompositorThread;
   bool mCanSend;
 
   void HandleTapOnMainThread(TapType aType, LayoutDevicePoint aPoint,
                              Modifiers aModifiers, ScrollableLayerGuid aGuid,
                              uint64_t aInputBlockId);
   void HandleTapOnCompositorThread(TapType aType, LayoutDevicePoint aPoint,
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -94,16 +94,17 @@ EXPORTS.mozilla.layers += [
     'AnimationHelper.h',
     'AnimationInfo.h',
     'apz/public/APZInputBridge.h',
     'apz/public/APZSampler.h',
     'apz/public/APZUpdater.h',
     'apz/public/CompositorController.h',
     'apz/public/GeckoContentController.h',
     'apz/public/IAPZCTreeManager.h',
+    'apz/public/MatrixMessage.h',
     'apz/public/MetricsSharingController.h',
     # exporting things from apz/src is temporary until we extract a
     # proper interface for the code there
     'apz/src/APZUtils.h',
     'apz/src/AsyncDragMetrics.h',
     'apz/src/FocusTarget.h',
     'apz/src/KeyboardMap.h',
     'apz/src/KeyboardScrollAction.h',
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -401,16 +401,21 @@ class gfxPrefs final {
   DECL_GFX_PREF(Live, "dom.vr.require-gesture",                VRRequireGesture, bool, true);
   DECL_GFX_PREF(Live, "dom.vr.puppet.enabled",                 VRPuppetEnabled, bool, false);
   DECL_GFX_PREF(Live, "dom.vr.puppet.submitframe",             VRPuppetSubmitFrame, uint32_t, 0);
   DECL_GFX_PREF(Live, "dom.vr.display.rafMaxDuration",         VRDisplayRafMaxDuration, uint32_t, 50);
   DECL_GFX_PREF(Once, "dom.vr.process.enabled",                VRProcessEnabled, bool, false);
   DECL_GFX_PREF(Once, "dom.vr.service.enabled",                VRServiceEnabled, bool, true);
   DECL_GFX_PREF(Live, "dom.w3c_pointer_events.enabled",        PointerEventsEnabled, bool, false);
 
+  // Make APZ send child-to-screen layer matrices to the chrome process
+  // even when the GPU process is in use (behind pref due to IPC errors
+  // in reftests) https://bugzilla.mozilla.org/show_bug.cgi?id=1533673
+  DECL_GFX_PREF(Live, "fission.apz-matrices-with-gpu-process", FissionApzMatricesWithGpuProcess, bool, false);
+
   DECL_GFX_PREF(Live, "general.smoothScroll",                  SmoothScrollEnabled, bool, true);
   DECL_GFX_PREF(Live, "general.smoothScroll.currentVelocityWeighting",
                 SmoothScrollCurrentVelocityWeighting, float, 0.25);
   DECL_GFX_PREF(Live, "general.smoothScroll.durationToIntervalRatio",
                 SmoothScrollDurationToIntervalRatio, int32_t, 200);
   DECL_GFX_PREF(Live, "general.smoothScroll.lines.durationMaxMS",
                 LineSmoothScrollMaxDurationMs, int32_t, 150);
   DECL_GFX_PREF(Live, "general.smoothScroll.lines.durationMinMS",
--- a/layout/base/UnitTransforms.h
+++ b/layout/base/UnitTransforms.h
@@ -56,16 +56,21 @@ enum class PixelCastJustification : uint
   MultipleAsyncTransforms,
   // We have reason to believe a layer doesn't have a local transform.
   // Should only be used if we've already checked or asserted this.
   NoTransformOnLayer,
   // LayerPixels are ImagePixels
   LayerIsImage,
   // External pixels are the same scale as screen pixels
   ExternalIsScreen,
+  // LayerToScreenMatrix is used as LayoutDeviceToLayoutDevice, because
+  // out-of-process iframes uses LayoutDevicePixels as the type system-visible
+  // type of their top-level event coordinate space even if technically
+  // inaccurate.
+  ContentProcessIsLayerInUiProcess,
 };
 
 template <class TargetUnits, class SourceUnits>
 gfx::CoordTyped<TargetUnits> ViewAs(const gfx::CoordTyped<SourceUnits>& aCoord,
                                     PixelCastJustification) {
   return gfx::CoordTyped<TargetUnits>(aCoord.value);
 }
 template <class TargetUnits, class SourceUnits>
--- a/layout/base/Units.h
+++ b/layout/base/Units.h
@@ -222,16 +222,17 @@ typedef gfx::ScaleFactors2D<ParentLayerP
     ParentLayerToScreenScale2D;
 typedef gfx::ScaleFactors2D<ParentLayerPixel, ParentLayerPixel>
     ParentLayerToParentLayerScale2D;
 
 typedef gfx::Matrix4x4Typed<LayoutDevicePixel, LayoutDevicePixel>
     LayoutDeviceToLayoutDeviceMatrix4x4;
 typedef gfx::Matrix4x4Typed<LayerPixel, ParentLayerPixel>
     LayerToParentLayerMatrix4x4;
+typedef gfx::Matrix4x4Typed<LayerPixel, ScreenPixel> LayerToScreenMatrix4x4;
 typedef gfx::Matrix4x4Typed<ScreenPixel, ScreenPixel> ScreenToScreenMatrix4x4;
 typedef gfx::Matrix4x4Typed<ScreenPixel, ParentLayerPixel>
     ScreenToParentLayerMatrix4x4;
 typedef gfx::Matrix4x4Typed<ParentLayerPixel, LayerPixel>
     ParentLayerToLayerMatrix4x4;
 typedef gfx::Matrix4x4Typed<ParentLayerPixel, ScreenPixel>
     ParentLayerToScreenMatrix4x4;
 typedef gfx::Matrix4x4Typed<ParentLayerPixel, ParentLayerPixel>