Bug 1298173 - Push HandleTap from the GPU process back to the parent process before passing it on to the child process. r=dvander draft
authorKartikaya Gupta <kgupta@mozilla.com>
Tue, 20 Sep 2016 16:39:13 -0400
changeset 415667 1fff2f95a91c9884b099ca707bf3cc893c17cddc
parent 415666 f8be72889252ae4c0047a40238111128ad9779ad
child 531667 6eda389650a9a9b1202f151eb109628f24b7f165
push id29931
push userkgupta@mozilla.com
push dateTue, 20 Sep 2016 20:40:10 +0000
reviewersdvander
bugs1298173
milestone52.0a1
Bug 1298173 - Push HandleTap from the GPU process back to the parent process before passing it on to the child process. r=dvander Sending it back via the parent process ensures that it will take the same path that regular touch events do, and so guarantees that the Tap event won't overtake the touch events and get dispatched to content first. MozReview-Commit-ID: JBYah6DmxNZ
dom/ipc/PBrowser.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
gfx/ipc/RemoteCompositorSession.cpp
gfx/ipc/RemoteCompositorSession.h
gfx/layers/apz/util/ContentProcessController.cpp
gfx/layers/ipc/APZCTreeManagerChild.cpp
gfx/layers/ipc/APZCTreeManagerChild.h
gfx/layers/ipc/APZCTreeManagerParent.cpp
gfx/layers/ipc/APZCTreeManagerParent.h
gfx/layers/ipc/APZChild.cpp
gfx/layers/ipc/APZChild.h
gfx/layers/ipc/CompositorBridgeParent.cpp
gfx/layers/ipc/CompositorBridgeParent.h
gfx/layers/ipc/PAPZ.ipdl
gfx/layers/ipc/PAPZCTreeManager.ipdl
gfx/layers/ipc/RemoteContentController.cpp
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -26,22 +26,24 @@ include PTabContext;
 
 using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h";
 using class mozilla::gfx::Matrix from "mozilla/gfx/Matrix.h";
 using struct gfxSize from "gfxPoint.h";
 using CSSRect from "Units.h";
 using CSSSize from "Units.h";
 using mozilla::LayoutDeviceIntRect from "Units.h";
 using mozilla::LayoutDeviceIntPoint from "Units.h";
+using mozilla::LayoutDevicePoint from "Units.h";
 using mozilla::ScreenIntPoint from "Units.h";
 using ScreenIntSize from "Units.h";
 using struct mozilla::layers::FrameMetrics from "FrameMetrics.h";
 using struct mozilla::layers::ScrollableLayerGuid from "FrameMetrics.h";
 using struct mozilla::layers::ZoomConstraints from "FrameMetrics.h";
 using mozilla::layers::MaybeZoomConstraints from "FrameMetrics.h";
+using mozilla::layers::GeckoContentController::TapType from "mozilla/layers/GeckoContentController.h";
 using FrameMetrics::ViewID from "FrameMetrics.h";
 using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
 using mozilla::WindowsHandle from "ipc/IPCMessageUtils.h";
 using nscolor from "nsColor.h";
 using class mozilla::WidgetCompositionEvent from "ipc/nsGUIEventIPC.h";
 using struct mozilla::widget::IMENotification from "nsIWidget.h";
 using struct nsIMEUpdatePreference from "nsIWidget.h";
 using mozilla::gfx::IntSize from "mozilla/gfx/Point.h";
@@ -64,16 +66,17 @@ using mozilla::CommandInt from "mozilla/
 using mozilla::WritingMode from "mozilla/WritingModes.h";
 using mozilla::layers::TouchBehaviorFlags from "mozilla/layers/APZUtils.h";
 using nsIWidget::TouchPointerState from "nsIWidget.h";
 using struct LookAndFeelInt from "mozilla/widget/WidgetMessageUtils.h";
 using class mozilla::dom::MessagePort from "mozilla/dom/MessagePort.h";
 using class mozilla::dom::ipc::StructuredCloneData from "mozilla/dom/ipc/StructuredCloneData.h";
 using mozilla::EventMessage from "mozilla/EventForwards.h";
 using nsEventStatus from "mozilla/EventForwards.h";
+using mozilla::Modifiers from "mozilla/EventForwards.h";
 using nsSizeMode from "nsIWidgetListener.h";
 using mozilla::widget::CandidateWindowPosition from "ipc/nsGUIEventIPC.h";
 using class mozilla::NativeEventData from "ipc/nsGUIEventIPC.h";
 using mozilla::FontRange from "ipc/nsGUIEventIPC.h";
 
 namespace mozilla {
 namespace dom {
 
@@ -654,16 +657,18 @@ child:
     async SynthMouseMoveEvent(WidgetMouseEvent event, ScrollableLayerGuid aGuid, uint64_t aInputBlockId);
     async RealMouseButtonEvent(WidgetMouseEvent event, ScrollableLayerGuid aGuid, uint64_t aInputBlockId);
     async RealKeyEvent(WidgetKeyboardEvent event, MaybeNativeKeyBinding keyBinding);
     async MouseWheelEvent(WidgetWheelEvent event, ScrollableLayerGuid aGuid, uint64_t aInputBlockId);
     async RealTouchEvent(WidgetTouchEvent aEvent,
                          ScrollableLayerGuid aGuid,
                          uint64_t aInputBlockId,
                          nsEventStatus aApzResponse);
+    async HandleTap(TapType aType, LayoutDevicePoint point, Modifiers aModifiers,
+                    ScrollableLayerGuid aGuid, uint64_t aInputBlockId);
     async RealTouchMoveEvent(WidgetTouchEvent aEvent,
                              ScrollableLayerGuid aGuid,
                              uint64_t aInputBlockId,
                              nsEventStatus aApzResponse);
     async RealDragEvent(WidgetDragEvent aEvent, uint32_t aDragAction, uint32_t aDropEffect);
     async PluginEvent(WidgetPluginEvent aEvent);
 
     /**
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -1719,27 +1719,29 @@ TabChild::HandleDoubleTap(const CSSPoint
   if (APZCCallbackHelper::GetOrCreateScrollIdentifiers(
       document->GetDocumentElement(), &presShellId, &viewId) && mApzcTreeManager) {
     ScrollableLayerGuid guid(mLayersId, presShellId, viewId);
 
     mApzcTreeManager->ZoomToRect(guid, zoomToRect, DEFAULT_BEHAVIOR);
   }
 }
 
-void
-TabChild::HandleTap(GeckoContentController::TapType aType,
-                    const LayoutDevicePoint& aPoint, const Modifiers& aModifiers,
-                    const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId)
+bool
+TabChild::RecvHandleTap(const GeckoContentController::TapType& aType,
+                        const LayoutDevicePoint& aPoint,
+                        const Modifiers& aModifiers,
+                        const ScrollableLayerGuid& aGuid,
+                        const uint64_t& aInputBlockId)
 {
   nsCOMPtr<nsIPresShell> presShell = GetPresShell();
   if (!presShell) {
-    return;
+    return true;
   }
   if (!presShell->GetPresContext()) {
-    return;
+    return true;
   }
   CSSToLayoutDeviceScale scale(presShell->GetPresContext()->CSSToDevPixelScale());
   CSSPoint point = APZCCallbackHelper::ApplyCallbackTransform(aPoint / scale, aGuid);
 
   switch (aType) {
   case GeckoContentController::TapType::eSingleTap:
     if (mRemoteFrame) {
       mRemoteFrame->SendTakeFocusForClickFromTap();
@@ -1763,16 +1765,17 @@ TabChild::HandleTap(GeckoContentControll
     }
     break;
   case GeckoContentController::TapType::eSentinel:
     // Should never happen, but we need to handle this case to make the compiler
     // happy.
     MOZ_ASSERT(false);
     break;
   }
+  return true;
 }
 
 bool
 TabChild::NotifyAPZStateChange(const ViewID& aViewId,
                                const layers::GeckoContentController::APZStateChange& aChange,
                                const int& aArg)
 {
   mAPZEventState->ProcessAPZStateChange(GetDocument(), aViewId, aChange, aArg);
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -621,21 +621,21 @@ public:
                   PRenderFrameChild* aRenderFrame,
                   const ShowInfo& aShowInfo);
 
   void ContentReceivedInputBlock(const ScrollableLayerGuid& aGuid,
                                  uint64_t aInputBlockId,
                                  bool aPreventDefault) const;
   void SetTargetAPZC(uint64_t aInputBlockId,
                     const nsTArray<ScrollableLayerGuid>& aTargets) const;
-  void HandleTap(layers::GeckoContentController::TapType aType,
-                 const LayoutDevicePoint& aPoint,
-                 const Modifiers& aModifiers,
-                 const mozilla::layers::ScrollableLayerGuid& aGuid,
-                 const uint64_t& aInputBlockId);
+  bool RecvHandleTap(const layers::GeckoContentController::TapType& aType,
+                     const LayoutDevicePoint& aPoint,
+                     const Modifiers& aModifiers,
+                     const ScrollableLayerGuid& aGuid,
+                     const uint64_t& aInputBlockId) override;
   void SetAllowedTouchBehavior(uint64_t aInputBlockId,
                                const nsTArray<TouchBehaviorFlags>& aFlags) const;
 
   bool UpdateFrame(const FrameMetrics& aFrameMetrics);
   bool NotifyAPZStateChange(const ViewID& aViewId,
                             const layers::GeckoContentController::APZStateChange& aChange,
                             const int& aArg);
   void StartScrollbarDrag(const layers::AsyncDragMetrics& aDragMetrics);
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -1655,16 +1655,31 @@ bool TabParent::SendRealTouchEvent(Widge
   }
 
   return (event.mMessage == eTouchMove) ?
     PBrowserParent::SendRealTouchMoveEvent(event, guid, blockId, apzResponse) :
     PBrowserParent::SendRealTouchEvent(event, guid, blockId, apzResponse);
 }
 
 bool
+TabParent::SendHandleTap(TapType aType,
+                         const LayoutDevicePoint& aPoint,
+                         Modifiers aModifiers,
+                         const ScrollableLayerGuid& aGuid,
+                         uint64_t aInputBlockId)
+{
+  if (mIsDestroyed) {
+    return false;
+  }
+  LayoutDeviceIntPoint offset = GetChildProcessOffset();
+  return PBrowserParent::SendHandleTap(aType, aPoint + offset, aModifiers, aGuid,
+      aInputBlockId);
+}
+
+bool
 TabParent::RecvSyncMessage(const nsString& aMessage,
                            const ClonedMessageData& aData,
                            InfallibleTArray<CpowEntry>&& aCpows,
                            const IPC::Principal& aPrincipal,
                            nsTArray<StructuredCloneData>* aRetVal)
 {
   // FIXME Permission check for TabParent in Content process
   nsIPrincipal* principal = aPrincipal;
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -458,16 +458,22 @@ public:
                          uint32_t aDropEffect);
 
   bool SendMouseWheelEvent(mozilla::WidgetWheelEvent& event);
 
   bool SendRealKeyEvent(mozilla::WidgetKeyboardEvent& event);
 
   bool SendRealTouchEvent(WidgetTouchEvent& event);
 
+  bool SendHandleTap(TapType aType,
+                     const LayoutDevicePoint& aPoint,
+                     Modifiers aModifiers,
+                     const ScrollableLayerGuid& aGuid,
+                     uint64_t aInputBlockId);
+
   virtual PDocumentRendererParent*
   AllocPDocumentRendererParent(const nsRect& documentRect,
                                const gfx::Matrix& transform,
                                const nsString& bgcolor,
                                const uint32_t& renderFlags,
                                const bool& flushLayout,
                                const nsIntSize& renderSize) override;
 
--- a/gfx/ipc/RemoteCompositorSession.cpp
+++ b/gfx/ipc/RemoteCompositorSession.cpp
@@ -17,38 +17,48 @@ using namespace widget;
 
 RemoteCompositorSession::RemoteCompositorSession(CompositorBridgeChild* aChild,
                                                  CompositorWidgetDelegate* aWidgetDelegate,
                                                  APZCTreeManagerChild* aAPZ,
                                                  const uint64_t& aRootLayerTreeId)
  : CompositorSession(aWidgetDelegate, aChild, aRootLayerTreeId)
  , mAPZ(aAPZ)
 {
+  mAPZ->SetCompositorSession(this);
 }
 
 CompositorBridgeParent*
 RemoteCompositorSession::GetInProcessBridge() const
 {
   return nullptr;
 }
 
 void
 RemoteCompositorSession::SetContentController(GeckoContentController* aController)
 {
+  mContentController = aController;
   mCompositorBridgeChild->SendPAPZConstructor(new APZChild(aController), 0);
 }
 
+GeckoContentController*
+RemoteCompositorSession::GetContentController()
+{
+  return mContentController.get();
+}
+
 RefPtr<IAPZCTreeManager>
 RemoteCompositorSession::GetAPZCTreeManager() const
 {
   return mAPZ;
 }
 
 void
 RemoteCompositorSession::Shutdown()
 {
+  mContentController = nullptr;
+  mAPZ->SetCompositorSession(nullptr);
   mCompositorBridgeChild->Destroy();
   mCompositorBridgeChild = nullptr;
   mCompositorWidgetDelegate = nullptr;
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/ipc/RemoteCompositorSession.h
+++ b/gfx/ipc/RemoteCompositorSession.h
@@ -18,19 +18,21 @@ class RemoteCompositorSession final : pu
 public:
   RemoteCompositorSession(CompositorBridgeChild* aChild,
                           CompositorWidgetDelegate* aWidgetDelegate,
                           APZCTreeManagerChild* aAPZ,
                           const uint64_t& aRootLayerTreeId);
 
   CompositorBridgeParent* GetInProcessBridge() const override;
   void SetContentController(GeckoContentController* aController) override;
+  GeckoContentController* GetContentController();
   RefPtr<IAPZCTreeManager> GetAPZCTreeManager() const override;
   void Shutdown() override;
 
 private:
   RefPtr<APZCTreeManagerChild> mAPZ;
+  RefPtr<GeckoContentController> mContentController;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // include_mozilla_gfx_ipc_RemoteCompositorSession_h
--- a/gfx/layers/apz/util/ContentProcessController.cpp
+++ b/gfx/layers/apz/util/ContentProcessController.cpp
@@ -134,20 +134,18 @@ ContentProcessController::RequestContent
 void
 ContentProcessController::HandleTap(
                         TapType aType,
                         const LayoutDevicePoint& aPoint,
                         Modifiers aModifiers,
                         const ScrollableLayerGuid& aGuid,
                         uint64_t aInputBlockId)
 {
-  if (mBrowser) {
-    mBrowser->HandleTap(aType, aPoint - mBrowser->GetChromeDisplacement(), aModifiers, aGuid,
-        aInputBlockId);
-  }
+  // This should never get called
+  MOZ_ASSERT(false);
 }
 
 void
 ContentProcessController::NotifyAPZStateChange(
                                   const ScrollableLayerGuid& aGuid,
                                   APZStateChange aChange,
                                   int aArg)
 {
--- a/gfx/layers/ipc/APZCTreeManagerChild.cpp
+++ b/gfx/layers/ipc/APZCTreeManagerChild.cpp
@@ -2,20 +2,36 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=99: */
 /* 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/layers/APZCTreeManagerChild.h"
 
 #include "InputData.h"                  // for InputData
+#include "mozilla/dom/TabParent.h"      // for TabParent
+#include "mozilla/layers/RemoteCompositorSession.h" // for RemoteCompositorSession
 
 namespace mozilla {
 namespace layers {
 
+APZCTreeManagerChild::APZCTreeManagerChild()
+  : mCompositorSession(nullptr)
+{
+}
+
+void
+APZCTreeManagerChild::SetCompositorSession(RemoteCompositorSession* aSession)
+{
+  // Exactly one of mCompositorSession and aSession must be null (i.e. either
+  // we're setting mCompositorSession or we're clearing it).
+  MOZ_ASSERT(!mCompositorSession ^ !aSession);
+  mCompositorSession = aSession;
+}
+
 nsEventStatus
 APZCTreeManagerChild::ReceiveInputEvent(
     InputData& aEvent,
     ScrollableLayerGuid* aOutTargetGuid,
     uint64_t* aOutInputBlockId)
 {
   switch (aEvent.mInputType) {
   case MULTITOUCH_INPUT: {
@@ -198,16 +214,38 @@ APZCTreeManagerChild::UpdateWheelTransac
 
 void APZCTreeManagerChild::TransformEventRefPoint(
     LayoutDeviceIntPoint* aRefPoint,
     ScrollableLayerGuid* aOutTargetGuid)
 {
   SendTransformEventRefPoint(*aRefPoint, aRefPoint, aOutTargetGuid);
 }
 
+bool
+APZCTreeManagerChild::RecvHandleTap(const TapType& aType,
+                                    const LayoutDevicePoint& aPoint,
+                                    const Modifiers& aModifiers,
+                                    const ScrollableLayerGuid& aGuid,
+                                    const uint64_t& aInputBlockId)
+{
+  MOZ_ASSERT(XRE_IsParentProcess());
+  if (mCompositorSession &&
+      mCompositorSession->RootLayerTreeId() == aGuid.mLayersId &&
+      mCompositorSession->GetContentController()) {
+    mCompositorSession->GetContentController()->HandleTap(aType, aPoint,
+        aModifiers, aGuid, aInputBlockId);
+    return true;
+  }
+  dom::TabParent* tab = dom::TabParent::GetTabParentFromLayersId(aGuid.mLayersId);
+  if (tab) {
+    tab->SendHandleTap(aType, aPoint, aModifiers, aGuid, aInputBlockId);
+  }
+  return true;
+}
+
 void
 APZCTreeManagerChild::OnProcessingError(
         Result aCode,
         const char* aReason)
 {
   MOZ_RELEASE_ASSERT(aCode != MsgDropped);
 }
 
--- a/gfx/layers/ipc/APZCTreeManagerChild.h
+++ b/gfx/layers/ipc/APZCTreeManagerChild.h
@@ -8,23 +8,26 @@
 #define mozilla_layers_APZCTreeManagerChild_h
 
 #include "mozilla/layers/IAPZCTreeManager.h"
 #include "mozilla/layers/PAPZCTreeManagerChild.h"
 
 namespace mozilla {
 namespace layers {
 
+class RemoteCompositorSession;
 
 class APZCTreeManagerChild
   : public IAPZCTreeManager
   , public PAPZCTreeManagerChild
 {
 public:
-  APZCTreeManagerChild() { }
+  APZCTreeManagerChild();
+
+  void SetCompositorSession(RemoteCompositorSession* aSession);
 
   nsEventStatus
   ReceiveInputEvent(
           InputData& aEvent,
           ScrollableLayerGuid* aOutTargetGuid,
           uint64_t* aOutInputBlockId) override;
 
   void
@@ -84,17 +87,25 @@ public:
           EventMessage aEventMessage) override;
 
   void
   OnProcessingError(
           Result aCode,
           const char* aReason) override;
 
 protected:
+  bool RecvHandleTap(const TapType& aType,
+                     const LayoutDevicePoint& aPoint,
+                     const Modifiers& aModifiers,
+                     const ScrollableLayerGuid& aGuid,
+                     const uint64_t& aInputBlockId) override;
 
   virtual
   ~APZCTreeManagerChild() { }
+
+private:
+  MOZ_NON_OWNING_REF RemoteCompositorSession* mCompositorSession;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // mozilla_layers_APZCTreeManagerChild_h
--- a/gfx/layers/ipc/APZCTreeManagerParent.cpp
+++ b/gfx/layers/ipc/APZCTreeManagerParent.cpp
@@ -14,16 +14,20 @@ namespace layers {
 
 APZCTreeManagerParent::APZCTreeManagerParent(uint64_t aLayersId, RefPtr<APZCTreeManager> aAPZCTreeManager)
   : mLayersId(aLayersId)
   , mTreeManager(aAPZCTreeManager)
 {
   MOZ_ASSERT(aAPZCTreeManager != nullptr);
 }
 
+APZCTreeManagerParent::~APZCTreeManagerParent()
+{
+}
+
 void
 APZCTreeManagerParent::ChildAdopted(RefPtr<APZCTreeManager> aAPZCTreeManager)
 {
   MOZ_ASSERT(aAPZCTreeManager != nullptr);
   mTreeManager = aAPZCTreeManager;
 }
 
 bool
--- a/gfx/layers/ipc/APZCTreeManagerParent.h
+++ b/gfx/layers/ipc/APZCTreeManagerParent.h
@@ -15,17 +15,17 @@ namespace layers {
 class APZCTreeManager;
 
 class APZCTreeManagerParent
     : public PAPZCTreeManagerParent
 {
 public:
 
   explicit APZCTreeManagerParent(uint64_t aLayersId, RefPtr<APZCTreeManager> aAPZCTreeManager);
-  virtual ~APZCTreeManagerParent() { }
+  virtual ~APZCTreeManagerParent();
 
   uint64_t LayersId() const { return mLayersId; }
 
   /**
    * Called when the layer tree that this protocol is connected to
    * is adopted by another compositor, and we need to switch APZCTreeManagers.
    */
   void ChildAdopted(RefPtr<APZCTreeManager> aAPZCTreeManager);
--- a/gfx/layers/ipc/APZChild.cpp
+++ b/gfx/layers/ipc/APZChild.cpp
@@ -34,28 +34,16 @@ APZChild::RecvRequestContentRepaint(cons
 {
   MOZ_ASSERT(mController->IsRepaintThread());
 
   mController->RequestContentRepaint(aFrameMetrics);
   return true;
 }
 
 bool
-APZChild::RecvHandleTap(const TapType& aType,
-                        const LayoutDevicePoint& aPoint,
-                        const Modifiers& aModifiers,
-                        const ScrollableLayerGuid& aGuid,
-                        const uint64_t& aInputBlockId)
-{
-  mController->HandleTap(aType, aPoint, aModifiers, aGuid,
-      aInputBlockId);
-  return true;
-}
-
-bool
 APZChild::RecvUpdateOverscrollVelocity(const float& aX, const float& aY, const bool& aIsRootContent)
 {
   mController->UpdateOverscrollVelocity(aX, aY, aIsRootContent);
   return true;
 }
 
 bool
 APZChild::RecvUpdateOverscrollOffset(const float& aX, const float& aY, const bool& aIsRootContent)
--- a/gfx/layers/ipc/APZChild.h
+++ b/gfx/layers/ipc/APZChild.h
@@ -22,22 +22,16 @@ class GeckoContentController;
 class APZChild final : public PAPZChild
 {
 public:
   explicit APZChild(RefPtr<GeckoContentController> aController);
   ~APZChild();
 
   bool RecvRequestContentRepaint(const FrameMetrics& frame) override;
 
-  bool RecvHandleTap(const TapType& aType,
-                     const LayoutDevicePoint& aPoint,
-                     const Modifiers& aModifiers,
-                     const ScrollableLayerGuid& aGuid,
-                     const uint64_t& aInputBlockId) override;
-
   bool RecvUpdateOverscrollVelocity(const float& aX, const float& aY, const bool& aIsRootContent) override;
 
   bool RecvUpdateOverscrollOffset(const float& aX, const float& aY, const bool& aIsRootContent) override;
 
   bool RecvSetScrollingRootContent(const bool& aIsRootContent) override;
 
   bool RecvNotifyMozMouseScrollEvent(const ViewID& aScrollId,
                                      const nsString& aEvent) override;
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -2434,16 +2434,42 @@ CompositorBridgeParent::GetIndirectShado
   MonitorAutoLock lock(*sIndirectLayerTreesLock);
   LayerTreeMap::iterator cit = sIndirectLayerTrees.find(aId);
   if (sIndirectLayerTrees.end() == cit) {
     return nullptr;
   }
   return &cit->second;
 }
 
+/* static */ APZCTreeManagerParent*
+CompositorBridgeParent::GetApzcTreeManagerParentForRoot(uint64_t aContentLayersId)
+{
+  MonitorAutoLock lock(*sIndirectLayerTreesLock);
+
+  CompositorBridgeParent::LayerTreeState* state = nullptr;
+  LayerTreeMap::iterator itr = sIndirectLayerTrees.find(aContentLayersId);
+  if (sIndirectLayerTrees.end() != itr) {
+    state = &itr->second;
+  }
+
+  // |state| is the state for the content process, but we want the APZCTMParent
+  // for the parent process owning that content process. So we have to jump to
+  // the LayerTreeState for the root layer tree id for that layer tree, and use
+  // the mApzcTreeManagerParent from that. This should also work with nested
+  // content processes, because RootLayerTreeId() will bypass any intermediate
+  // processes' ids and go straight to the root.
+  if (state) {
+    uint64_t rootLayersId = state->mParent->RootLayerTreeId();
+    itr = sIndirectLayerTrees.find(rootLayersId);
+    state = (sIndirectLayerTrees.end() != itr) ? &itr->second : nullptr;
+  }
+
+  return state ? state->mApzcTreeManagerParent : nullptr;
+}
+
 PTextureParent*
 CompositorBridgeParent::AllocPTextureParent(const SurfaceDescriptor& aSharedData,
                                             const LayersBackend& aLayersBackend,
                                             const TextureFlags& aFlags,
                                             const uint64_t& aId,
                                             const uint64_t& aSerial)
 {
   return TextureHost::CreateIPDLActor(this, aSharedData, aLayersBackend, aFlags, aSerial);
--- a/gfx/layers/ipc/CompositorBridgeParent.h
+++ b/gfx/layers/ipc/CompositorBridgeParent.h
@@ -463,16 +463,28 @@ public:
 
   /**
    * Lookup the indirect shadow tree for |aId| and return it if it
    * exists.  Otherwise null is returned.  This must only be called on
    * the compositor thread.
    */
   static LayerTreeState* GetIndirectShadowTree(uint64_t aId);
 
+  /**
+   * Given the layers id for a content process, get the APZCTreeManagerParent
+   * for the corresponding *root* layers id. That is, the APZCTreeManagerParent,
+   * if one is found, will always be connected to the parent process rather
+   * than a content process. Note that unless the compositor process is
+   * separated this is expected to return null, because if the compositor is
+   * living in the gecko parent process then there is no APZCTreeManagerParent
+   * for the parent process.
+   */
+  static APZCTreeManagerParent* GetApzcTreeManagerParentForRoot(
+        uint64_t aContentLayersId);
+
 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
   /**
    * Calculates and requests the main thread update plugin positioning, clip,
    * and visibility via ipc.
    */
   bool UpdatePluginWindowState(uint64_t aId);
 
   /**
--- a/gfx/layers/ipc/PAPZ.ipdl
+++ b/gfx/layers/ipc/PAPZ.ipdl
@@ -4,29 +4,26 @@
 /* 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 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";
-using mozilla::layers::GeckoContentController::TapType from "mozilla/layers/GeckoContentController.h";
 using mozilla::layers::GeckoContentController::APZStateChange from "mozilla/layers/GeckoContentController.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 mozilla::Modifiers from "mozilla/EventForwards.h";
 using class nsRegion from "nsRegion.h";
 
 namespace mozilla {
 namespace layers {
 
 
 /**
  * PAPZ is a protocol for remoting a GeckoContentController. PAPZ lives on the
@@ -52,19 +49,16 @@ parent:
   async UpdateHitRegion(nsRegion aRegion);
 
   async __delete__();
 
 child:
 
   async RequestContentRepaint(FrameMetrics frame);
 
-  async HandleTap(TapType aType, LayoutDevicePoint point, Modifiers aModifiers,
-                  ScrollableLayerGuid aGuid, uint64_t aInputBlockId);
-
   async UpdateOverscrollVelocity(float aX, float aY, bool aIsRootContent);
 
   async UpdateOverscrollOffset(float aX, float aY, bool aIsRootContent);
 
   async SetScrollingRootContent(bool aIsRootContent);
 
   async NotifyMozMouseScrollEvent(ViewID aScrollId, nsString aEvent);
 
--- a/gfx/layers/ipc/PAPZCTreeManager.ipdl
+++ b/gfx/layers/ipc/PAPZCTreeManager.ipdl
@@ -5,24 +5,27 @@
 
 include "mozilla/GfxMessageUtils.h";
 include "ipc/nsGUIEventIPC.h";
 
 include protocol PCompositorBridge;
 
 using CSSRect from "Units.h";
 using LayoutDeviceIntPoint from "Units.h";
+using mozilla::LayoutDevicePoint from "Units.h";
 using ScreenPoint from "Units.h";
 using struct mozilla::layers::ScrollableLayerGuid from "FrameMetrics.h";
 using mozilla::layers::MaybeZoomConstraints from "FrameMetrics.h";
 using mozilla::layers::TouchBehaviorFlags from "mozilla/layers/APZUtils.h";
 using mozilla::layers::AsyncDragMetrics from "mozilla/layers/AsyncDragMetrics.h";
+using mozilla::layers::GeckoContentController::TapType from "mozilla/layers/GeckoContentController.h";
 
 using nsEventStatus from "mozilla/EventForwards.h";
 using EventMessage from "mozilla/EventForwards.h";
+using mozilla::Modifiers from "mozilla/EventForwards.h";
 using class mozilla::WidgetInputEvent from "mozilla/BasicEvents.h";
 using class mozilla::WidgetMouseEventBase from "mozilla/MouseEvents.h";
 using mozilla::WidgetMouseEvent::Reason from "mozilla/MouseEvents.h";
 using class mozilla::WidgetTouchEvent from "mozilla/TouchEvents.h";
 using class mozilla::WidgetWheelEvent from "mozilla/MouseEvents.h";
 using class mozilla::InputData from "InputData.h";
 using class mozilla::MultiTouchInput from "InputData.h";
 using class mozilla::MouseInput from "InputData.h";
@@ -115,12 +118,17 @@ parent:
 
   async UpdateWheelTransaction(LayoutDeviceIntPoint aRefPoint, EventMessage aEventMessage);
 
   sync TransformEventRefPoint(LayoutDeviceIntPoint aRefPoint)
     returns (LayoutDeviceIntPoint   aOutRefPoint,
              ScrollableLayerGuid    aOutTargetGuid);
 
   async __delete__();
+
+child:
+
+  async HandleTap(TapType aType, LayoutDevicePoint point, Modifiers aModifiers,
+                  ScrollableLayerGuid aGuid, uint64_t aInputBlockId);
 };
 
 } // namespace gfx
 } // namespace mozilla
--- a/gfx/layers/ipc/RemoteContentController.cpp
+++ b/gfx/layers/ipc/RemoteContentController.cpp
@@ -7,16 +7,17 @@
 
 #include "mozilla/layers/RemoteContentController.h"
 
 #include "base/message_loop.h"
 #include "base/task.h"
 #include "MainThreadUtils.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/TabParent.h"
+#include "mozilla/layers/APZCTreeManagerParent.h"  // for APZCTreeManagerParent
 #include "mozilla/layers/APZThreadUtils.h"
 #include "mozilla/layout/RenderFrameParent.h"
 #include "mozilla/gfx/GPUProcessManager.h"
 #include "mozilla/Unused.h"
 #include "Units.h"
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidBridge.h"
 #endif
@@ -49,29 +50,43 @@ RemoteContentController::RequestContentR
 
 void
 RemoteContentController::HandleTap(TapType aTapType,
                                    const LayoutDevicePoint& aPoint,
                                    Modifiers aModifiers,
                                    const ScrollableLayerGuid& aGuid,
                                    uint64_t aInputBlockId)
 {
-  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;
+  APZThreadUtils::AssertOnControllerThread();
+
+  if (XRE_GetProcessType() == GeckoProcessType_GPU) {
+    MOZ_ASSERT(MessageLoop::current() == mCompositorThread);
+
+    // The raw pointer to APZCTreeManagarParent is ok here because we are on the
+    // compositor thread.
+    APZCTreeManagerParent* apzctmp =
+        CompositorBridgeParent::GetApzcTreeManagerParentForRoot(aGuid.mLayersId);
+    if (apzctmp) {
+      Unused << apzctmp->SendHandleTap(aTapType, aPoint, aModifiers, aGuid, aInputBlockId);
+      return;
+    }
   }
 
-  if (mCanSend) {
-    Unused << SendHandleTap(aTapType, aPoint,
-            aModifiers, aGuid, aInputBlockId);
+  // If we get here we're probably in the parent process, but we might be in
+  // the GPU process in some shutdown phase where the LayerTreeState or
+  // APZCTreeManagerParent structures are torn down. In that case we'll just get
+  // a null TabParent.
+  dom::TabParent* tab = dom::TabParent::GetTabParentFromLayersId(aGuid.mLayersId);
+  if (tab) {
+    // If we got a TabParent we're definitely in the parent process, and the
+    // message is going to a child process. That means we're in an e10s
+    // environment, so we must be on the main thread.
+    MOZ_ASSERT(XRE_IsParentProcess());
+    MOZ_ASSERT(NS_IsMainThread());
+    tab->SendHandleTap(aTapType, aPoint, aModifiers, aGuid, aInputBlockId);
   }
 }
 
 void
 RemoteContentController::PostDelayedTask(already_AddRefed<Runnable> aTask, int aDelayMs)
 {
 #ifdef MOZ_WIDGET_ANDROID
   AndroidBridge::Bridge()->PostTaskToUiThread(Move(aTask), aDelayMs);