Bug 1289650 - Move PAPZ from PContent to PCompositorBridge. r?kats draft
authorRyan Hunt <rhunt@mozilla.com>
Mon, 01 Aug 2016 23:59:00 -0700
changeset 404196 e9cd7461377caa9248bafdf5229eadbc7f65a6c3
parent 404195 465a434cd4e8af8d3fd06a554165988dfbabb38d
child 404197 b587abef249588a79c65d5f0651f137a16f64e50
push id27151
push userbmo:rhunt@mozilla.com
push dateTue, 23 Aug 2016 04:32:21 +0000
reviewerskats
bugs1289650
milestone51.0a1
Bug 1289650 - Move PAPZ from PContent to PCompositorBridge. r?kats MozReview-Commit-ID: GzU1iEVqSx6
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
gfx/ipc/GPUProcessManager.cpp
gfx/ipc/GPUProcessManager.h
gfx/layers/apz/public/GeckoContentController.h
gfx/layers/apz/src/APZCTreeManager.cpp
gfx/layers/apz/src/AsyncPanZoomController.cpp
gfx/layers/apz/test/gtest/APZTestCommon.h
gfx/layers/apz/util/ChromeProcessController.cpp
gfx/layers/apz/util/ChromeProcessController.h
gfx/layers/ipc/APZChild.cpp
gfx/layers/ipc/APZChild.h
gfx/layers/ipc/CompositorBridgeChild.cpp
gfx/layers/ipc/CompositorBridgeChild.h
gfx/layers/ipc/CompositorBridgeParent.cpp
gfx/layers/ipc/CompositorBridgeParent.h
gfx/layers/ipc/PAPZ.ipdl
gfx/layers/ipc/PCompositorBridge.ipdl
gfx/layers/ipc/RemoteContentController.cpp
gfx/layers/ipc/RemoteContentController.h
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -1155,29 +1155,16 @@ ContentChild::AllocPContentBridgeParent(
 
 PGMPServiceChild*
 ContentChild::AllocPGMPServiceChild(mozilla::ipc::Transport* aTransport,
                                     base::ProcessId aOtherProcess)
 {
   return GMPServiceChild::Create(aTransport, aOtherProcess);
 }
 
-PAPZChild*
-ContentChild::AllocPAPZChild(const TabId& aTabId)
-{
-  return APZChild::Create(aTabId);
-}
-
-bool
-ContentChild::DeallocPAPZChild(PAPZChild* aActor)
-{
-  delete aActor;
-  return true;
-}
-
 bool
 ContentChild::RecvInitCompositor(Endpoint<PCompositorBridgeChild>&& aEndpoint)
 {
   return CompositorBridgeChild::InitForContent(Move(aEndpoint));
 }
 
 bool
 ContentChild::RecvInitImageBridge(Endpoint<PImageBridgeChild>&& aEndpoint)
@@ -1387,16 +1374,23 @@ ContentChild::RecvSetProcessSandbox(cons
 #endif /* XP_LINUX && !OS_ANDROID */
 #endif /* MOZ_CRASHREPORTER */
 #endif /* MOZ_CONTENT_SANDBOX */
 
   return true;
 }
 
 bool
+ContentChild::RecvNotifyLayerAllocated(const dom::TabId& aTabId, const uint64_t& aLayersId)
+{
+  APZChild* apz = APZChild::Create(aTabId);
+  return CompositorBridgeChild::Get()->SendPAPZConstructor(apz, aLayersId);
+}
+
+bool
 ContentChild::RecvSpeakerManagerNotify()
 {
 #ifdef MOZ_WIDGET_GONK
   // Only notify the process which has the SpeakerManager instance.
   RefPtr<SpeakerManagerService> service =
     SpeakerManagerService::GetSpeakerManagerService();
   if (service) {
     service->Notify();
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -138,21 +138,16 @@ public:
   PContentBridgeChild*
   AllocPContentBridgeChild(mozilla::ipc::Transport* transport,
                            base::ProcessId otherProcess) override;
 
   PGMPServiceChild*
   AllocPGMPServiceChild(mozilla::ipc::Transport* transport,
                         base::ProcessId otherProcess) override;
 
-  PAPZChild*
-  AllocPAPZChild(const TabId& aTabId) override;
-  bool
-  DeallocPAPZChild(PAPZChild* aActor) override;
-
   bool
   RecvInitCompositor(Endpoint<PCompositorBridgeChild>&& aEndpoint) override;
   bool
   RecvInitImageBridge(Endpoint<PImageBridgeChild>&& aEndpoint) override;
   bool
   RecvInitVRManager(Endpoint<PVRManagerChild>&& aEndpoint) override;
 
   PSharedBufferManagerChild*
@@ -392,16 +387,18 @@ public:
   virtual PRemoteSpellcheckEngineChild* AllocPRemoteSpellcheckEngineChild() override;
 
   virtual bool DeallocPRemoteSpellcheckEngineChild(PRemoteSpellcheckEngineChild*) override;
 
   virtual bool RecvSetOffline(const bool& offline) override;
 
   virtual bool RecvSetConnectivity(const bool& connectivity) override;
 
+  virtual bool RecvNotifyLayerAllocated(const dom::TabId& aTabId, const uint64_t& aLayersId) override;
+
   virtual bool RecvSpeakerManagerNotify() override;
 
   virtual bool RecvBidiKeyboardNotify(const bool& isLangRTL,
                                       const bool& haveBidiKeyboards) override;
 
   virtual bool RecvNotifyVisited(const URIParams& aURI) override;
 
   // auto remove when alertfinished is received.
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -1711,17 +1711,17 @@ ContentParent::AllocateLayerTreeId(Conte
   if (!gfxPlatform::AsyncPanZoomEnabled()) {
     return true;
   }
 
   if (!aContent || !aTopLevel) {
     return false;
   }
 
-  return gpu->UpdateRemoteContentController(*aId, aContent, aTabId, aTopLevel);
+  return aContent->SendNotifyLayerAllocated(aTabId, *aId);
 }
 
 bool
 ContentParent::RecvAllocateLayerTreeId(const ContentParentId& aCpId,
                                        const TabId& aTabId, uint64_t* aId)
 {
   // Protect against spoofing by a compromised child. aCpId must either
   // correspond to the process that this ContentParent represents or be a
@@ -2892,31 +2892,16 @@ ContentParent::Observe(nsISupports* aSub
 
 PGMPServiceParent*
 ContentParent::AllocPGMPServiceParent(mozilla::ipc::Transport* aTransport,
                                       base::ProcessId aOtherProcess)
 {
   return GMPServiceParent::Create(aTransport, aOtherProcess);
 }
 
-PAPZParent*
-ContentParent::AllocPAPZParent(const TabId& aTabId)
-{
-  // The PAPZParent should just be created in the main process and then an IPDL
-  // constructor message sent to hook it up.
-  MOZ_CRASH("This shouldn't be called");
-  return nullptr;
-}
-
-bool
-ContentParent::DeallocPAPZParent(PAPZParent* aActor)
-{
-  return true;
-}
-
 PBackgroundParent*
 ContentParent::AllocPBackgroundParent(Transport* aTransport,
                                       ProcessId aOtherProcess)
 {
   return BackgroundParent::Alloc(this, aTransport, aOtherProcess);
 }
 
 PProcessHangMonitorParent*
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -698,21 +698,16 @@ private:
   static bool AllocateLayerTreeId(ContentParent* aContent,
                                   TabParent* aTopLevel, const TabId& aTabId,
                                   uint64_t* aId);
 
   PGMPServiceParent*
   AllocPGMPServiceParent(mozilla::ipc::Transport* aTransport,
                          base::ProcessId aOtherProcess) override;
 
-  PAPZParent*
-  AllocPAPZParent(const TabId& aTabId) override;
-  bool
-  DeallocPAPZParent(PAPZParent* aActor) override;
-
   PSharedBufferManagerParent*
   AllocPSharedBufferManagerParent(mozilla::ipc::Transport* aTranport,
                                    base::ProcessId aOtherProcess) override;
 
   PBackgroundParent*
   AllocPBackgroundParent(Transport* aTransport, ProcessId aOtherProcess)
                          override;
 
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -1,15 +1,14 @@
 /* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8 -*- */
 /* vim: set sw=4 ts=8 et tw=80 ft=cpp : */
 /* 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/. */
 
-include protocol PAPZ;
 include protocol PBackground;
 include protocol PBlob;
 include protocol PBluetooth;
 include protocol PBrowser;
 include protocol PCellBroadcast;
 include protocol PCompositorBridge;
 include protocol PContentBridge;
 include protocol PContentPermissionRequest;
@@ -384,17 +383,16 @@ prio(normal upto urgent) sync protocol P
 {
     parent spawns PPluginModule;
 
     parent opens PProcessHangMonitor;
     parent opens PSharedBufferManager;
     parent opens PGMPService;
     child opens PBackground;
 
-    manages PAPZ;
     manages PBlob;
     manages PBluetooth;
     manages PBrowser;
     manages PCellBroadcast;
     manages PContentPermissionRequest;
     manages PCrashReporter;
     manages PCycleCollectWithLogs;
     manages PDeviceStorageRequest;
@@ -478,16 +476,21 @@ child:
      * usually only be performed zero or one times.  The child may
      * abnormally exit if this fails; the details are OS-specific.
      */
     async SetProcessSandbox(MaybeFileDesc aBroker);
 
     async PMemoryReportRequest(uint32_t generation, bool anonymize,
                                bool minimizeMemoryUsage, MaybeFileDesc DMDFile);
 
+    /**
+     * Sent to notify that aTabId has been allocated aLayersId
+     */
+    async NotifyLayerAllocated(TabId aTabId, uint64_t aLayersId);
+
     async SpeakerManagerNotify();
 
     /**
      * Communication between the PuppetBidiKeyboard and the actual
      * BidiKeyboard hosted by the parent
      */
     async BidiKeyboardNotify(bool isLangRTL, bool haveBidiKeyboards);
 
@@ -498,18 +501,16 @@ child:
      * nsIMemoryInfoDumper.idl
      */
     async PCycleCollectWithLogs(bool dumpAllTraces,
                                 FileDescriptor gcLog,
                                 FileDescriptor ccLog);
 
     async PTestShell();
 
-    async PAPZ(TabId tabId);
-
     async RegisterChrome(ChromePackage[] packages, SubstitutionMapping[] substitutions,
                          OverrideMapping[] overrides, nsCString locale, bool reset);
     async RegisterChromeItem(ChromeRegistryItem item);
 
     async ClearImageCache(bool privateLoader, bool chrome);
 
     async SetOffline(bool offline);
     async SetConnectivity(bool connectivity);
--- a/gfx/ipc/GPUProcessManager.cpp
+++ b/gfx/ipc/GPUProcessManager.cpp
@@ -560,29 +560,16 @@ GPUProcessManager::RequestNotifyLayerTre
 }
 
 void
 GPUProcessManager::SwapLayerTreeObservers(uint64_t aLayer, uint64_t aOtherLayer)
 {
   CompositorBridgeParent::SwapLayerTreeObservers(aLayer, aOtherLayer);
 }
 
-bool
-GPUProcessManager::UpdateRemoteContentController(uint64_t aLayersId,
-                                                 dom::ContentParent* aContentParent,
-                                                 const dom::TabId& aTabId,
-                                                 dom::TabParent* aBrowserParent)
-{
-  return CompositorBridgeParent::UpdateRemoteContentController(
-    aLayersId,
-    aContentParent,
-    aTabId,
-    aBrowserParent);
-}
-
 void
 GPUProcessManager::EnsureVsyncIOThread()
 {
   if (mVsyncIOThread) {
     return;
   }
 
   mVsyncIOThread = new VsyncIOThreadHolder();
--- a/gfx/ipc/GPUProcessManager.h
+++ b/gfx/ipc/GPUProcessManager.h
@@ -110,28 +110,16 @@ public:
   //
   // Must run on the content main thread.
   void DeallocateLayerTreeId(uint64_t aLayersId);
 
   void RequestNotifyLayerTreeReady(uint64_t aLayersId, CompositorUpdateObserver* aObserver);
   void RequestNotifyLayerTreeCleared(uint64_t aLayersId, CompositorUpdateObserver* aObserver);
   void SwapLayerTreeObservers(uint64_t aLayer, uint64_t aOtherLayer);
 
-  // Creates a new RemoteContentController for aTabId. Should only be called on
-  // the main thread.
-  //
-  // aLayersId      The layers id for the browser corresponding to aTabId.
-  // aContentParent The ContentParent for the process that the TabChild for
-  //                aTabId lives in.
-  // aBrowserParent The toplevel TabParent for aTabId.
-  bool UpdateRemoteContentController(uint64_t aLayersId,
-                                     dom::ContentParent* aContentParent,
-                                     const dom::TabId& aTabId,
-                                     dom::TabParent* aBrowserParent);
-
   void OnProcessLaunchComplete(GPUProcessHost* aHost) override;
   void OnProcessUnexpectedShutdown(GPUProcessHost* aHost) override;
 
   // Notify the GPUProcessManager that a top-level PGPU protocol has been
   // terminated. This may be called from any thread.
   void NotifyRemoteActorDestroyed(const uint64_t& aProcessToken);
 
   // Returns access to the PGPU protocol if a GPU process is present.
--- a/gfx/layers/apz/public/GeckoContentController.h
+++ b/gfx/layers/apz/public/GeckoContentController.h
@@ -7,33 +7,27 @@
 #ifndef mozilla_layers_GeckoContentController_h
 #define mozilla_layers_GeckoContentController_h
 
 #include "FrameMetrics.h"               // for FrameMetrics, etc
 #include "Units.h"                      // for CSSPoint, CSSRect, etc
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT_HELPER2
 #include "mozilla/EventForwards.h"      // for Modifiers
 #include "nsISupportsImpl.h"
-#include "ThreadSafeRefcountingWithMainThreadDestruction.h"
 
 namespace mozilla {
 
 class Runnable;
 
 namespace layers {
 
 class GeckoContentController
 {
 public:
-  /**
-   * At least one class deriving from GeckoContentController needs to do
-   * synchronous cleanup on the main thread, so we use
-   * NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION.
-   */
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(GeckoContentController)
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GeckoContentController)
 
   /**
    * Requests a paint of the given FrameMetrics |aFrameMetrics| from Gecko.
    * Implementations per-platform are responsible for actually handling this.
    * This method will always be called on the Gecko main thread.
    */
   virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) = 0;
 
@@ -67,16 +61,26 @@ public:
   /**
    * Schedules a runnable to run on the controller/UI thread at some time
    * in the future.
    * This method must always be called on the controller thread.
    */
   virtual void PostDelayedTask(already_AddRefed<Runnable> aRunnable, int aDelayMs) = 0;
 
   /**
+   * Returns true if we are currently on the thread that can send repaint requests.
+   */
+  virtual bool IsRepaintThread() = 0;
+
+  /**
+   * Runs the given task on the "repaint" thread.
+   */
+  virtual void DispatchToRepaintThread(already_AddRefed<Runnable> aTask) = 0;
+
+  /**
    * APZ uses |FrameMetrics::mCompositionBounds| for hit testing. Sometimes,
    * widget code has knowledge of a touch-sensitive region that should
    * additionally constrain hit testing for all frames associated with the
    * controller. This method allows APZ to query the controller for such a
    * region. A return value of true indicates that the controller has such a
    * region, and it is returned in |aOutRegion|.
    * This method needs to be called on the main thread.
    * TODO: once bug 928833 is implemented, this should be removed, as
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -622,18 +622,18 @@ APZCTreeManager::FlushApzRepaints(uint64
 {
   // Previously, paints were throttled and therefore this method was used to
   // ensure any pending paints were flushed. Now, paints are flushed
   // immediately, so it is safe to simply send a notification now.
   APZCTM_LOG("Flushing repaints for layers id %" PRIu64, aLayersId);
   const CompositorBridgeParent::LayerTreeState* state =
     CompositorBridgeParent::GetIndirectShadowTree(aLayersId);
   MOZ_ASSERT(state && state->mController);
-  NS_DispatchToMainThread(NewRunnableMethod(
-    state->mController, &GeckoContentController::NotifyFlushComplete));
+  state->mController->DispatchToRepaintThread(NewRunnableMethod(
+     state->mController, &GeckoContentController::NotifyFlushComplete));
 }
 
 nsEventStatus
 APZCTreeManager::ReceiveInputEvent(InputData& aEvent,
                                    ScrollableLayerGuid* aOutTargetGuid,
                                    uint64_t* aOutInputBlockId)
 {
   APZThreadUtils::AssertOnControllerThread();
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -2814,29 +2814,28 @@ bool AsyncPanZoomController::IsPannable(
 }
 
 int32_t AsyncPanZoomController::GetLastTouchIdentifier() const {
   RefPtr<GestureEventListener> listener = GetGestureEventListener();
   return listener ? listener->GetLastTouchIdentifier() : -1;
 }
 
 void AsyncPanZoomController::RequestContentRepaint() {
-  // Reinvoke this method on the main thread if it's not there already. It's
-  // important to do this before the call to CalculatePendingDisplayPort, so
-  // that CalculatePendingDisplayPort uses the most recent available version of
-  // mFrameMetrics, just before the paint request is dispatched to content.
-  if (!NS_IsMainThread()) {
-    // use the local variable to resolve the function overload.
+  RefPtr<GeckoContentController> controller = GetGeckoContentController();
+  if (!controller) {
+    return;
+  }
+  if (!controller->IsRepaintThread()) {
     auto func = static_cast<void (AsyncPanZoomController::*)()>
         (&AsyncPanZoomController::RequestContentRepaint);
-    NS_DispatchToMainThread(NewRunnableMethod(this, func));
+    controller->DispatchToRepaintThread(NewRunnableMethod(this, func));
     return;
   }
 
-  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(controller->IsRepaintThread());
 
   ReentrantMonitorAutoEnter lock(mMonitor);
   ParentLayerPoint velocity = GetVelocityVector();
   mFrameMetrics.SetDisplayPortMargins(CalculatePendingDisplayPort(mFrameMetrics, velocity));
   mFrameMetrics.SetUseDisplayPortMargins(true);
   mFrameMetrics.SetPaintRequestTime(TimeStamp::Now());
   RequestContentRepaint(mFrameMetrics, velocity);
 }
@@ -2851,17 +2850,21 @@ GetDisplayPortRect(const FrameMetrics& a
   baseRect.Inflate(aFrameMetrics.GetDisplayPortMargins() / aFrameMetrics.DisplayportPixelsPerCSSPixel());
   return baseRect;
 }
 
 void
 AsyncPanZoomController::RequestContentRepaint(const FrameMetrics& aFrameMetrics,
                                               const ParentLayerPoint& aVelocity)
 {
-  MOZ_ASSERT(NS_IsMainThread());
+  RefPtr<GeckoContentController> controller = GetGeckoContentController();
+  if (!controller) {
+    return;
+  }
+  MOZ_ASSERT(controller->IsRepaintThread());
 
   // If we're trying to paint what we already think is painted, discard this
   // request since it's a pointless paint.
   ScreenMargin marginDelta = (mLastPaintRequestMetrics.GetDisplayPortMargins()
                            - aFrameMetrics.GetDisplayPortMargins());
   if (fabsf(marginDelta.left) < EPSILON &&
       fabsf(marginDelta.top) < EPSILON &&
       fabsf(marginDelta.right) < EPSILON &&
@@ -2875,21 +2878,16 @@ AsyncPanZoomController::RequestContentRe
       fabsf(aFrameMetrics.GetViewport().width -
             mLastPaintRequestMetrics.GetViewport().width) < EPSILON &&
       fabsf(aFrameMetrics.GetViewport().height -
             mLastPaintRequestMetrics.GetViewport().height) < EPSILON &&
       aFrameMetrics.GetScrollGeneration() == mLastPaintRequestMetrics.GetScrollGeneration()) {
     return;
   }
 
-  RefPtr<GeckoContentController> controller = GetGeckoContentController();
-  if (!controller) {
-    return;
-  }
-
   APZC_LOG_FM(aFrameMetrics, "%p requesting content repaint", this);
   { // scope lock
     MutexAutoLock lock(mCheckerboardEventLock);
     if (mCheckerboardEvent && mCheckerboardEvent->IsRecordingTrace()) {
       std::stringstream info;
       info << " velocity " << aVelocity;
       std::string str = info.str();
       mCheckerboardEvent->UpdateRendertraceProperty(
@@ -3556,23 +3554,27 @@ void AsyncPanZoomController::ZoomToRect(
 
     // Schedule a repaint now, so the new displayport will be painted before the
     // animation finishes.
     ParentLayerPoint velocity(0, 0);
     endZoomToMetrics.SetDisplayPortMargins(
       CalculatePendingDisplayPort(endZoomToMetrics, velocity));
     endZoomToMetrics.SetUseDisplayPortMargins(true);
     endZoomToMetrics.SetPaintRequestTime(TimeStamp::Now());
-    if (NS_IsMainThread()) {
+
+    RefPtr<GeckoContentController> controller = GetGeckoContentController();
+    if (!controller)
+      return;
+    if (controller->IsRepaintThread()) {
       RequestContentRepaint(endZoomToMetrics, velocity);
     } else {
       // use a local var to resolve the function overload
       auto func = static_cast<void (AsyncPanZoomController::*)(const FrameMetrics&, const ParentLayerPoint&)>
           (&AsyncPanZoomController::RequestContentRepaint);
-      NS_DispatchToMainThread(
+      controller->DispatchToRepaintThread(
           NewRunnableMethod<FrameMetrics, ParentLayerPoint>(
               this, func, endZoomToMetrics, velocity));
     }
   }
 }
 
 CancelableBlockState*
 AsyncPanZoomController::CurrentInputBlock() const
--- a/gfx/layers/apz/test/gtest/APZTestCommon.h
+++ b/gfx/layers/apz/test/gtest/APZTestCommon.h
@@ -77,16 +77,22 @@ public:
   MOCK_METHOD1(RequestContentRepaint, void(const FrameMetrics&));
   MOCK_METHOD2(RequestFlingSnap, void(const FrameMetrics::ViewID& aScrollId, const mozilla::CSSPoint& aDestination));
   MOCK_METHOD2(AcknowledgeScrollUpdate, void(const FrameMetrics::ViewID&, const uint32_t& aScrollGeneration));
   MOCK_METHOD5(HandleTap, void(TapType, const LayoutDevicePoint&, Modifiers, const ScrollableLayerGuid&, uint64_t));
   // Can't use the macros with already_AddRefed :(
   void PostDelayedTask(already_AddRefed<Runnable> aTask, int aDelayMs) {
     RefPtr<Runnable> task = aTask;
   }
+  bool IsRepaintThread() {
+    return NS_IsMainThread();
+  }
+  void DispatchToRepaintThread(already_AddRefed<Runnable> aTask) {
+    NS_DispatchToMainThread(Move(aTask));
+  }
   MOCK_METHOD3(NotifyAPZStateChange, void(const ScrollableLayerGuid& aGuid, APZStateChange aChange, int aArg));
   MOCK_METHOD0(NotifyFlushComplete, void());
 };
 
 class MockContentControllerDelayed : public MockContentController {
 public:
   MockContentControllerDelayed()
     : mTime(GetStartupTime())
--- a/gfx/layers/apz/util/ChromeProcessController.cpp
+++ b/gfx/layers/apz/util/ChromeProcessController.cpp
@@ -45,32 +45,44 @@ void
 ChromeProcessController::InitializeRoot()
 {
   APZCCallbackHelper::InitializeRootDisplayport(GetPresShell());
 }
 
 void
 ChromeProcessController::RequestContentRepaint(const FrameMetrics& aFrameMetrics)
 {
-  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(IsRepaintThread());
 
   FrameMetrics metrics = aFrameMetrics;
   if (metrics.IsRootContent()) {
     APZCCallbackHelper::UpdateRootFrame(metrics);
   } else {
     APZCCallbackHelper::UpdateSubFrame(metrics);
   }
 }
 
 void
 ChromeProcessController::PostDelayedTask(already_AddRefed<Runnable> aTask, int aDelayMs)
 {
   MessageLoop::current()->PostDelayedTask(Move(aTask), aDelayMs);
 }
 
+bool
+ChromeProcessController::IsRepaintThread()
+{
+  return NS_IsMainThread();
+}
+
+void
+ChromeProcessController::DispatchToRepaintThread(already_AddRefed<Runnable> aTask)
+{
+  NS_DispatchToMainThread(Move(aTask));
+}
+
 void
 ChromeProcessController::Destroy()
 {
   if (MessageLoop::current() != mUILoop) {
     mUILoop->PostTask(NewRunnableMethod(this, &ChromeProcessController::Destroy));
     return;
   }
 
@@ -219,11 +231,12 @@ ChromeProcessController::NotifyMozMouseS
   }
 
   APZCCallbackHelper::NotifyMozMouseScrollEvent(aScrollId, aEvent);
 }
 
 void
 ChromeProcessController::NotifyFlushComplete()
 {
-  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(IsRepaintThread());
+
   APZCCallbackHelper::NotifyFlushComplete(GetPresShell());
 }
--- a/gfx/layers/apz/util/ChromeProcessController.h
+++ b/gfx/layers/apz/util/ChromeProcessController.h
@@ -35,16 +35,18 @@ protected:
 public:
   explicit ChromeProcessController(nsIWidget* aWidget, APZEventState* aAPZEventState, IAPZCTreeManager* aAPZCTreeManager);
   ~ChromeProcessController();
   virtual void Destroy() override;
 
   // GeckoContentController interface
   virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) override;
   virtual void PostDelayedTask(already_AddRefed<Runnable> aTask, int aDelayMs) override;
+  virtual bool IsRepaintThread() override;
+  virtual void DispatchToRepaintThread(already_AddRefed<Runnable> aTask) override;
   virtual void HandleTap(TapType aType,
                          const mozilla::LayoutDevicePoint& aPoint,
                          Modifiers aModifiers,
                          const ScrollableLayerGuid& aGuid,
                          uint64_t aInputBlockId) override;
   virtual void NotifyAPZStateChange(const ScrollableLayerGuid& aGuid,
                                     APZStateChange aChange,
                                     int aArg) override;
--- a/gfx/layers/ipc/APZChild.cpp
+++ b/gfx/layers/ipc/APZChild.cpp
@@ -102,22 +102,33 @@ APZChild::RecvRequestContentRepaint(cons
 bool
 APZChild::RecvHandleTap(const TapType& aType,
                         const LayoutDevicePoint& aPoint,
                         const Modifiers& aModifiers,
                         const ScrollableLayerGuid& aGuid,
                         const uint64_t& aInputBlockId,
                         const bool& aCallTakeFocusForClickFromTap)
 {
-  mBrowser->HandleTap(aType, aPoint, aModifiers, aGuid,
+  mBrowser->HandleTap(aType, aPoint - mBrowser->GetChromeDisplacement(), aModifiers, aGuid,
       aInputBlockId, aCallTakeFocusForClickFromTap);
   return true;
 }
 
 bool
+APZChild::RecvNotifyMozMouseScrollEvent(const uint64_t& aLayersId,
+                                        const ViewID& aScrollId,
+                                        const nsString& aEvent)
+{
+  if (mBrowser) {
+    mBrowser->RecvMouseScrollTestEvent(aLayersId, aScrollId, aEvent);
+  }
+  return true;
+}
+
+bool
 APZChild::RecvNotifyAPZStateChange(const ViewID& aViewId,
                                    const APZStateChange& aChange,
                                    const int& aArg)
 {
   return mBrowser->NotifyAPZStateChange(aViewId, aChange, aArg);
 }
 
 bool
@@ -134,17 +145,16 @@ APZChild::RecvNotifyFlushComplete()
 bool
 APZChild::RecvDestroy()
 {
   mDestroyed = true;
   if (mBrowser) {
     mBrowser->SetAPZChild(nullptr);
     mBrowser = nullptr;
   }
-  PAPZChild::Send__delete__(this);
   return true;
 }
 
 void
 APZChild::SetObserver(nsIObserver* aObserver)
 {
   MOZ_ASSERT(!mBrowser);
   mObserver = aObserver;
--- a/gfx/layers/ipc/APZChild.h
+++ b/gfx/layers/ipc/APZChild.h
@@ -32,16 +32,20 @@ public:
 
   bool RecvHandleTap(const TapType& aType,
                      const LayoutDevicePoint& aPoint,
                      const Modifiers& aModifiers,
                      const ScrollableLayerGuid& aGuid,
                      const uint64_t& aInputBlockId,
                      const bool& aCallTakeFocusForClickFromTap) override;
 
+  bool RecvNotifyMozMouseScrollEvent(const uint64_t& aLayersId,
+                                     const ViewID& aScrollId,
+                                     const nsString& aEvent) override;
+
   bool RecvNotifyAPZStateChange(const ViewID& aViewId,
                                 const APZStateChange& aChange,
                                 const int& aArg) override;
 
   bool RecvNotifyFlushComplete() override;
 
   bool RecvDestroy() override;
 
--- a/gfx/layers/ipc/CompositorBridgeChild.cpp
+++ b/gfx/layers/ipc/CompositorBridgeChild.cpp
@@ -8,16 +8,17 @@
 #include "mozilla/layers/CompositorBridgeParent.h"
 #include "mozilla/layers/CompositorThread.h"
 #include <stddef.h>                     // for size_t
 #include "ClientLayerManager.h"         // for ClientLayerManager
 #include "base/message_loop.h"          // for MessageLoop
 #include "base/task.h"                  // for NewRunnableMethod, etc
 #include "gfxPrefs.h"
 #include "mozilla/layers/ImageBridgeChild.h"
+#include "mozilla/layers/APZChild.h"
 #include "mozilla/layers/IAPZCTreeManager.h"
 #include "mozilla/layers/APZCTreeManagerChild.h"
 #include "mozilla/layers/LayerTransactionChild.h"
 #include "mozilla/layers/PLayerTransactionChild.h"
 #include "mozilla/layers/TextureClient.h"// for TextureClient
 #include "mozilla/layers/TextureClientPool.h"// for TextureClientPool
 #include "mozilla/gfx/gfxVars.h"
 #include "mozilla/gfx/GPUProcessManager.h"
@@ -1031,16 +1032,31 @@ CompositorBridgeChild::GetAPZCTreeManage
 PAPZCTreeManagerChild*
 CompositorBridgeChild::AllocPAPZCTreeManagerChild(const uint64_t& aLayersId)
 {
   APZCTreeManagerChild* child = new APZCTreeManagerChild();
   child->AddRef();
   return child;
 }
 
+PAPZChild*
+CompositorBridgeChild::AllocPAPZChild(const uint64_t& aLayersId)
+{
+  // We send the constructor manually.
+  MOZ_CRASH("Should not be called");
+  return nullptr;
+}
+
+bool
+CompositorBridgeChild::DeallocPAPZChild(PAPZChild* aActor)
+{
+  delete aActor;
+  return true;
+}
+
 bool
 CompositorBridgeChild::DeallocPAPZCTreeManagerChild(PAPZCTreeManagerChild* aActor)
 {
   APZCTreeManagerChild* parent = static_cast<APZCTreeManagerChild*>(aActor);
   parent->Release();
   return true;
 }
 
--- a/gfx/layers/ipc/CompositorBridgeChild.h
+++ b/gfx/layers/ipc/CompositorBridgeChild.h
@@ -211,16 +211,19 @@ public:
   PCompositorWidgetChild* AllocPCompositorWidgetChild(const CompositorWidgetInitData& aInitData) override;
   bool DeallocPCompositorWidgetChild(PCompositorWidgetChild* aActor) override;
 
   RefPtr<IAPZCTreeManager> GetAPZCTreeManager(uint64_t aLayerTreeId);
 
   PAPZCTreeManagerChild* AllocPAPZCTreeManagerChild(const uint64_t& aLayersId) override;
   bool DeallocPAPZCTreeManagerChild(PAPZCTreeManagerChild* aActor) override;
 
+  PAPZChild* AllocPAPZChild(const uint64_t& aLayersId) override;
+  bool DeallocPAPZChild(PAPZChild* aActor) override;
+
   virtual ShmemAllocator* AsShmemAllocator() override { return this; }
 
   void ProcessingError(Result aCode, const char* aReason) override;
 
 private:
   // Private destructor, to discourage deletion outside of Release():
   virtual ~CompositorBridgeChild();
 
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -20,17 +20,17 @@
 #include "TreeTraversal.h"              // for ForEachNode
 #ifdef MOZ_WIDGET_GTK
 #include "gfxPlatformGtk.h"             // for gfxPlatform
 #endif
 #include "gfxPrefs.h"                   // for gfxPrefs
 #include "mozilla/AutoRestore.h"        // for AutoRestore
 #include "mozilla/ClearOnShutdown.h"    // for ClearOnShutdown
 #include "mozilla/DebugOnly.h"          // for DebugOnly
-#include "mozilla/dom/ContentParent.h"
+#include "mozilla/dom/TabParent.h"
 #include "mozilla/gfx/2D.h"          // for DrawTarget
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/gfx/Rect.h"          // for IntSize
 #include "VRManager.h"                  // for VRManager
 #include "mozilla/ipc/Transport.h"      // for Transport
 #include "mozilla/layers/APZCTreeManager.h"  // for APZCTreeManager
 #include "mozilla/layers/APZCTreeManagerParent.h"  // for APZCTreeManagerParent
 #include "mozilla/layers/APZThreadUtils.h"  // for APZCTreeManager
@@ -1352,16 +1352,28 @@ CompositorBridgeParent::AllocPAPZCTreeMa
 }
 
 bool
 CompositorBridgeParent::DeallocPAPZCTreeManagerParent(PAPZCTreeManagerParent* aActor)
 {
   return false;
 }
 
+PAPZParent*
+CompositorBridgeParent::AllocPAPZParent(const uint64_t& aLayersId)
+{
+  return nullptr;
+}
+
+bool
+CompositorBridgeParent::DeallocPAPZParent(PAPZParent* aActor)
+{
+  return false;
+}
+
 bool
 CompositorBridgeParent::RecvAsyncPanZoomEnabled(const uint64_t& aLayersId, bool* aHasAPZ)
 {
   return false;
 }
 
 RefPtr<APZCTreeManager>
 CompositorBridgeParent::GetAPZCTreeManager()
@@ -1763,39 +1775,16 @@ CompositorBridgeParent::RecvNotifyChildC
 void
 CompositorBridgeParent::NotifyChildCreated(uint64_t aChild)
 {
   sIndirectLayerTreesLock->AssertCurrentThreadOwns();
   sIndirectLayerTrees[aChild].mParent = this;
   sIndirectLayerTrees[aChild].mLayerManager = mLayerManager;
 }
 
-/* static */ bool
-CompositorBridgeParent::UpdateRemoteContentController(uint64_t aLayersId,
-                                                      dom::ContentParent* aContent,
-                                                      const dom::TabId& aTabId,
-                                                      dom::TabParent* aTopLevel)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  MonitorAutoLock lock(*sIndirectLayerTreesLock);
-  LayerTreeState& state = sIndirectLayerTrees[aLayersId];
-  // RemoteContentController needs to know the layers id and the top level
-  // TabParent, so we pass that to its constructor here and then set up the
-  // PAPZ protocol by calling SendPAPZConstructor (and pass in the tab id for
-  // the PBrowser that it corresponds to).
-  RefPtr<RemoteContentController> controller =
-    new RemoteContentController(aLayersId, aTopLevel);
-  if (!aContent->SendPAPZConstructor(controller, aTabId)) {
-    return false;
-  }
-  state.mController = controller;
-  return true;
-}
-
 bool
 CompositorBridgeParent::RecvAdoptChild(const uint64_t& child)
 {
   APZCTreeManagerParent* parent;
   {
     MonitorAutoLock lock(*sIndirectLayerTreesLock);
     NotifyChildCreated(child);
     if (sIndirectLayerTrees[child].mLayerTree) {
@@ -2165,16 +2154,19 @@ public:
     return false;
   }
 
   virtual bool RecvAsyncPanZoomEnabled(const uint64_t& aLayersId, bool* aHasAPZ) override;
 
   virtual PAPZCTreeManagerParent* AllocPAPZCTreeManagerParent(const uint64_t& aLayersId) override;
   virtual bool DeallocPAPZCTreeManagerParent(PAPZCTreeManagerParent* aActor) override;
 
+  virtual PAPZParent* AllocPAPZParent(const uint64_t& aLayersId) override;
+  virtual bool DeallocPAPZParent(PAPZParent* aActor) override;
+
   virtual CompositorBridgeParentIPCAllocator* AsCompositorBridgeParentIPCAllocator() override { return this; }
 
   virtual void UpdatePaintTime(LayerTransactionParent* aLayerTree, const TimeDuration& aPaintTime) override {
     uint64_t id = aLayerTree->GetId();
     MOZ_ASSERT(id != 0);
 
     CompositorBridgeParent::LayerTreeState* state =
       CompositorBridgeParent::GetIndirectShadowTree(id);
@@ -2550,16 +2542,41 @@ CrossProcessCompositorBridgeParent::Deal
     state.mApzcTreeManagerParent = nullptr;
   }
 
   delete parent;
 
   return true;
 }
 
+PAPZParent*
+CrossProcessCompositorBridgeParent::AllocPAPZParent(const uint64_t& aLayersId)
+{
+  // Check to see if this child process has access to this layer tree.
+  if (!LayerTreeOwnerTracker::Get()->IsMapped(aLayersId, OtherPid())) {
+    NS_ERROR("Unexpected layers id in AllocPAPZParent; dropping message...");
+    return nullptr;
+  }
+
+  RefPtr<RemoteContentController> controller = new RemoteContentController(aLayersId);
+
+  MonitorAutoLock lock(*sIndirectLayerTreesLock);
+  CompositorBridgeParent::LayerTreeState& state = sIndirectLayerTrees[aLayersId];
+  MOZ_ASSERT(!state.mController);
+  state.mController = controller;
+
+  return controller;
+}
+
+bool
+CrossProcessCompositorBridgeParent::DeallocPAPZParent(PAPZParent* aActor)
+{
+  return true;
+}
+
 bool
 CrossProcessCompositorBridgeParent::RecvNotifyChildCreated(const uint64_t& child)
 {
   MonitorAutoLock lock(*sIndirectLayerTreesLock);
   for (LayerTreeMap::iterator it = sIndirectLayerTrees.begin();
        it != sIndirectLayerTrees.end(); it++) {
     CompositorBridgeParent::LayerTreeState* lts = &it->second;
     if (lts->mParent && lts->mCrossProcessParent == this) {
--- a/gfx/layers/ipc/CompositorBridgeParent.h
+++ b/gfx/layers/ipc/CompositorBridgeParent.h
@@ -489,16 +489,19 @@ public:
 
   widget::CompositorWidget* GetWidget() { return mWidget; }
 
   void ForceComposeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr);
 
   PAPZCTreeManagerParent* AllocPAPZCTreeManagerParent(const uint64_t& aLayersId) override;
   bool DeallocPAPZCTreeManagerParent(PAPZCTreeManagerParent* aActor) override;
 
+  PAPZParent* AllocPAPZParent(const uint64_t& aLayersId) override;
+  bool DeallocPAPZParent(PAPZParent* aActor) override;
+
   bool RecvAsyncPanZoomEnabled(const uint64_t& aLayersId, bool* aHasAPZ) override;
 
   RefPtr<APZCTreeManager> GetAPZCTreeManager();
 
   bool AsyncPanZoomEnabled() const {
     return !!mApzcTreeManager;
   }
 
@@ -523,30 +526,16 @@ private:
    * Must run on the content main thread.
    */
   static void DeallocateLayerTreeId(uint64_t aId);
 
   static void RequestNotifyLayerTreeReady(uint64_t aLayersId, CompositorUpdateObserver* aObserver);
   static void RequestNotifyLayerTreeCleared(uint64_t aLayersId, CompositorUpdateObserver* aObserver);
   static void SwapLayerTreeObservers(uint64_t aLayer, uint64_t aOtherLayer);
 
-  /**
-   * Creates a new RemoteContentController for aTabId. Should only be called on
-   * the main thread.
-   *
-   * aLayersId The layers id for the browser corresponding to aTabId.
-   * aContentParent The ContentParent for the process that the TabChild for
-   *                aTabId lives in.
-   * aBrowserParent The toplevel TabParent for aTabId.
-   */
-  static bool UpdateRemoteContentController(uint64_t aLayersId,
-                                            dom::ContentParent* aContentParent,
-                                            const dom::TabId& aTabId,
-                                            dom::TabParent* aBrowserParent);
-
 protected:
   // Protected destructor, to discourage deletion outside of Release():
   virtual ~CompositorBridgeParent();
 
   void DeferredDestroy();
 
   virtual PLayerTransactionParent*
     AllocPLayerTransactionParent(const nsTArray<LayersBackend>& aBackendHints,
--- a/gfx/layers/ipc/PAPZ.ipdl
+++ b/gfx/layers/ipc/PAPZ.ipdl
@@ -2,17 +2,17 @@
  * vim: sw=2 ts=8 et :
  */
 /* 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/. */
 
 include "mozilla/GfxMessageUtils.h";
 
-include protocol PContent;
+include protocol PCompositorBridge;
 
 using mozilla::LayoutDevicePoint from "Units.h";
 using CSSRect from "Units.h";
 using struct mozilla::layers::FrameMetrics from "FrameMetrics.h";
 using struct mozilla::layers::ScrollableLayerGuid from "FrameMetrics.h";
 using mozilla::layers::FrameMetrics::ViewID from "FrameMetrics.h";
 using mozilla::layers::MaybeZoomConstraints from "FrameMetrics.h";
 using mozilla::layers::TouchBehaviorFlags from "mozilla/layers/APZUtils.h";
@@ -34,17 +34,17 @@ namespace layers {
  * PBrowser parent actor doesn't necessarily live in the main process, for
  * example with nested browsers). This will typically be set up when the layers
  * id is allocated for the PBrowser.
  *
  * Opened through PContent and runs on the main thread in both parent and child.
  */
 sync protocol PAPZ
 {
-  manager PContent;
+  manager PCompositorBridge;
 
 parent:
 
   async UpdateHitRegion(nsRegion aRegion);
 
   async __delete__();
 
 child:
@@ -52,16 +52,18 @@ child:
 
   // The aCallTakeFocusForClickFromTap argument is used for eSingleTap types,
   // to request that the child take focus before dispatching the mouse events
   // for the tap (otherwise the resulting focus behaviour is incorrect).
   async HandleTap(TapType aType, LayoutDevicePoint point, Modifiers aModifiers,
                   ScrollableLayerGuid aGuid, uint64_t aInputBlockId,
                   bool aCallTakeFocusForClickFromTap);
 
+  async NotifyMozMouseScrollEvent(uint64_t aLayersId, ViewID aScrollId, nsString aEvent);
+
   async NotifyAPZStateChange(ViewID aViewId, APZStateChange aChange, int aArg);
 
   async NotifyFlushComplete();
 
   async Destroy();
 };
 
 } // layers
--- a/gfx/layers/ipc/PCompositorBridge.ipdl
+++ b/gfx/layers/ipc/PCompositorBridge.ipdl
@@ -3,16 +3,17 @@
  */
 /* 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/. */
 
 include LayersSurfaces;
 include LayersMessages;
 include PlatformWidgetTypes;
+include protocol PAPZ;
 include protocol PAPZCTreeManager;
 include protocol PBrowser;
 include protocol PCompositable;
 include protocol PCompositorWidget;
 include protocol PImageContainer;
 include protocol PLayer;
 include protocol PLayerTransaction;
 include protocol PTexture;
@@ -42,16 +43,17 @@ namespace layers {
 
 /**
  * The PCompositorBridge protocol is used to manage communication between
  * the main thread and the compositor thread context. It's primary
  * purpose is to manage the PLayerTransaction sub protocol.
  */
 sync protocol PCompositorBridge
 {
+  manages PAPZ;
   manages PAPZCTreeManager;
   // A Compositor manages a single Layer Manager (PLayerTransaction)
   manages PLayerTransaction;
   manages PTexture;
   manages PCompositorWidget;
 
 child:
   // The child should invalidate retained layers. This is used for local
@@ -120,16 +122,17 @@ parent:
 
   // When out-of-process, this must be called to finish initialization.
   sync Initialize(uint64_t rootLayerTreeId);
 
   // Returns whether this Compositor has APZ enabled or not.
   sync AsyncPanZoomEnabled(uint64_t layersId) returns (bool aHasAPZ);
 
   // Must be called after Initialize(), and only succeeds if AsyncPanZoomEnabled() is true.
+  async PAPZ(uint64_t layersId);
   async PAPZCTreeManager(uint64_t layersId);
 
   /**
    * Confirmation callback for UpdatePluginConfigurations and HideAllPlugins.
    */
   async RemotePluginsReady();
 
   // Confirmation that the child has invalidated all its layers, and will not
--- a/gfx/layers/ipc/RemoteContentController.cpp
+++ b/gfx/layers/ipc/RemoteContentController.cpp
@@ -23,175 +23,173 @@
 
 namespace mozilla {
 namespace layers {
 
 using namespace mozilla::gfx;
 
 static std::map<uint64_t, RefPtr<RemoteContentController>> sDestroyedControllers;
 
-RemoteContentController::RemoteContentController(uint64_t aLayersId,
-                                                 dom::TabParent* aBrowserParent)
-  : mUILoop(MessageLoop::current())
+RemoteContentController::RemoteContentController(uint64_t aLayersId)
+  : mCompositorThread(MessageLoop::current())
   , mLayersId(aLayersId)
-  , mBrowserParent(aBrowserParent)
+  , mCanSend(true)
   , mMutex("RemoteContentController")
 {
-  MOZ_ASSERT(NS_IsMainThread());
 }
 
 RemoteContentController::~RemoteContentController()
 {
 }
 
 void
 RemoteContentController::RequestContentRepaint(const FrameMetrics& aFrameMetrics)
 {
-  MOZ_ASSERT(NS_IsMainThread());
-  if (CanSend()) {
+  MOZ_ASSERT(IsRepaintThread());
+
+  if (mCanSend) {
     Unused << SendRequestContentRepaint(aFrameMetrics);
   }
 }
 
 void
 RemoteContentController::HandleTap(TapType aTapType,
                                    const LayoutDevicePoint& aPoint,
                                    Modifiers aModifiers,
                                    const ScrollableLayerGuid& aGuid,
                                    uint64_t aInputBlockId)
 {
-  if (MessageLoop::current() != mUILoop) {
-    // We have to send this message from the "UI thread" (main
-    // thread).
-    mUILoop->PostTask(NewRunnableMethod<TapType, LayoutDevicePoint, Modifiers,
+  if (MessageLoop::current() != mCompositorThread) {
+    // We have to send messages from the compositor thread
+    mCompositorThread->PostTask(NewRunnableMethod<TapType, LayoutDevicePoint, Modifiers,
                                         ScrollableLayerGuid, uint64_t>(this,
                                           &RemoteContentController::HandleTap,
                                           aTapType, aPoint, aModifiers, aGuid,
                                           aInputBlockId));
     return;
   }
 
   bool callTakeFocusForClickFromTap = (aTapType == TapType::eSingleTap);
-  if (callTakeFocusForClickFromTap && mBrowserParent) {
-    layout::RenderFrameParent* frame = mBrowserParent->GetRenderFrame();
-    if (frame && mLayersId == frame->GetLayersId()) {
-      // Avoid going over IPC and back for calling TakeFocusForClickFromTap,
-      // since the right RenderFrameParent is living in this process.
-      frame->TakeFocusForClickFromTap();
-      callTakeFocusForClickFromTap = false;
-    }
-  }
 
-  if (CanSend()) {
-    Unused << SendHandleTap(aTapType, mBrowserParent->AdjustTapToChildWidget(aPoint),
+  if (mCanSend) {
+    Unused << SendHandleTap(aTapType, aPoint,
             aModifiers, aGuid, aInputBlockId, callTakeFocusForClickFromTap);
   }
 }
 
 void
 RemoteContentController::PostDelayedTask(already_AddRefed<Runnable> aTask, int aDelayMs)
 {
 #ifdef MOZ_WIDGET_ANDROID
   AndroidBridge::Bridge()->PostTaskToUiThread(Move(aTask), aDelayMs);
 #else
-  (MessageLoop::current() ? MessageLoop::current() : mUILoop)->
+  (MessageLoop::current() ? MessageLoop::current() : mCompositorThread)->
     PostDelayedTask(Move(aTask), aDelayMs);
 #endif
 }
 
 bool
+RemoteContentController::IsRepaintThread()
+{
+  return MessageLoop::current() == mCompositorThread;
+}
+
+void
+RemoteContentController::DispatchToRepaintThread(already_AddRefed<Runnable> aTask)
+{
+  mCompositorThread->PostTask(Move(aTask));
+}
+
+bool
 RemoteContentController::GetTouchSensitiveRegion(CSSRect* aOutRegion)
 {
   MutexAutoLock lock(mMutex);
   if (mTouchSensitiveRegion.IsEmpty()) {
     return false;
   }
 
   *aOutRegion = CSSRect::FromAppUnits(mTouchSensitiveRegion.GetBounds());
   return true;
 }
 
 void
 RemoteContentController::NotifyAPZStateChange(const ScrollableLayerGuid& aGuid,
                                               APZStateChange aChange,
                                               int aArg)
 {
-  if (MessageLoop::current() != mUILoop) {
-    mUILoop->PostTask(NewRunnableMethod<ScrollableLayerGuid,
+  if (MessageLoop::current() != mCompositorThread) {
+    // We have to send messages from the compositor thread
+    mCompositorThread->PostTask(NewRunnableMethod<ScrollableLayerGuid,
                                         APZStateChange,
                                         int>(this,
                                              &RemoteContentController::NotifyAPZStateChange,
                                              aGuid, aChange, aArg));
     return;
   }
-  if (CanSend()) {
+
+  if (mCanSend) {
     Unused << SendNotifyAPZStateChange(aGuid.mScrollId, aChange, aArg);
   }
 }
 
 void
 RemoteContentController::NotifyMozMouseScrollEvent(const FrameMetrics::ViewID& aScrollId,
                                                    const nsString& aEvent)
 {
-  if (MessageLoop::current() != mUILoop) {
-    mUILoop->PostTask(NewRunnableMethod<FrameMetrics::ViewID,
+  if (MessageLoop::current() != mCompositorThread) {
+    // We have to send messages from the compositor thread
+    mCompositorThread->PostTask(NewRunnableMethod<FrameMetrics::ViewID,
                                         nsString>(this,
                                                   &RemoteContentController::NotifyMozMouseScrollEvent,
                                                   aScrollId, aEvent));
     return;
   }
 
-  if (mBrowserParent) {
-    Unused << mBrowserParent->SendMouseScrollTestEvent(mLayersId, aScrollId, aEvent);
+  if (mCanSend) {
+    Unused << SendNotifyMozMouseScrollEvent(mLayersId, aScrollId, aEvent);
   }
 }
 
 void
 RemoteContentController::NotifyFlushComplete()
 {
-  MOZ_ASSERT(NS_IsMainThread());
-  if (CanSend()) {
+  MOZ_ASSERT(IsRepaintThread());
+
+  if (mCanSend) {
     Unused << SendNotifyFlushComplete();
   }
 }
 
 bool
 RemoteContentController::RecvUpdateHitRegion(const nsRegion& aRegion)
 {
   MutexAutoLock lock(mMutex);
   mTouchSensitiveRegion = aRegion;
   return true;
 }
 
 void
 RemoteContentController::ActorDestroy(ActorDestroyReason aWhy)
 {
-  mBrowserParent = nullptr;
+  mCanSend = false;
 
-  uint64_t key = mLayersId;
-  NS_DispatchToMainThread(NS_NewRunnableFunction([key]() {
-    // sDestroyedControllers may or may not contain the key, depending on
-    // whether or not SendDestroy() was successfully sent out or not.
-    sDestroyedControllers.erase(key);
-  }));
+  // sDestroyedControllers may or may not contain the key, depending on
+  // whether or not SendDestroy() was successfully sent out or not.
+  sDestroyedControllers.erase(mLayersId);
 }
 
 void
 RemoteContentController::Destroy()
 {
-  RefPtr<RemoteContentController> controller = this;
-  NS_DispatchToMainThread(NS_NewRunnableFunction([controller] {
-    if (controller->CanSend()) {
-      // Gfx code is done with this object, and it will probably get destroyed
-      // soon. However, if CanSend() is true, ActorDestroy has not yet been
-      // called, which means IPC code still has a handle to this object. We need
-      // to keep it alive until we get the ActorDestroy call, either via the
-      // __delete__ message or via IPC shutdown on our end.
-      uint64_t key = controller->mLayersId;
-      MOZ_ASSERT(sDestroyedControllers.find(key) == sDestroyedControllers.end());
-      sDestroyedControllers[key] = controller;
-      Unused << controller->SendDestroy();
-    }
-  }));
+  if (mCanSend) {
+    // Gfx code is done with this object, and it will probably get destroyed
+    // soon. However, if mCanSend is true, ActorDestroy has not yet been
+    // called, which means IPC code still has a handle to this object. We need
+    // to keep it alive until we get the ActorDestroy call, either via the
+    // __delete__ message or via IPC shutdown on our end.
+    MOZ_ASSERT(sDestroyedControllers.find(mLayersId) == sDestroyedControllers.end());
+    sDestroyedControllers[mLayersId] = this;
+    Unused << SendDestroy();
+  }
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/ipc/RemoteContentController.h
+++ b/gfx/layers/ipc/RemoteContentController.h
@@ -28,60 +28,55 @@ namespace layers {
  */
 class RemoteContentController : public GeckoContentController
                               , public PAPZParent
 {
   using GeckoContentController::TapType;
   using GeckoContentController::APZStateChange;
 
 public:
-  explicit RemoteContentController(uint64_t aLayersId,
-                                   dom::TabParent* aBrowserParent);
+  explicit RemoteContentController(uint64_t aLayersId);
 
   virtual ~RemoteContentController();
 
-  // Needs to be called on the main thread.
   virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) override;
 
   virtual void HandleTap(TapType aTapType,
                          const LayoutDevicePoint& aPoint,
                          Modifiers aModifiers,
                          const ScrollableLayerGuid& aGuid,
                          uint64_t aInputBlockId) override;
 
   virtual void PostDelayedTask(already_AddRefed<Runnable> aTask, int aDelayMs) override;
 
+  virtual bool IsRepaintThread() override;
+
+  virtual void DispatchToRepaintThread(already_AddRefed<Runnable> aTask) override;
+
   virtual bool GetTouchSensitiveRegion(CSSRect* aOutRegion) override;
 
   virtual void NotifyAPZStateChange(const ScrollableLayerGuid& aGuid,
                                     APZStateChange aChange,
                                     int aArg) override;
 
   virtual void NotifyMozMouseScrollEvent(const FrameMetrics::ViewID& aScrollId,
                                          const nsString& aEvent) override;
 
-  // Needs to be called on the main thread.
   virtual void NotifyFlushComplete() override;
 
   virtual bool RecvUpdateHitRegion(const nsRegion& aRegion) override;
 
   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
 
   virtual void Destroy() override;
 
 private:
-  bool CanSend()
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-    return !!mBrowserParent;
-  }
-
-  MessageLoop* mUILoop;
+  MessageLoop* mCompositorThread;
   uint64_t mLayersId;
-  RefPtr<dom::TabParent> mBrowserParent;
+  bool mCanSend;
 
   // Mutex protecting members below accessed from multiple threads.
   mozilla::Mutex mMutex;
   nsRegion mTouchSensitiveRegion;
 };
 
 } // namespace layers