Bug 1020199 - Make sure APZ works with nested oop iframe. r=kats, r=dvander.
authorPeter Van der Beken <peterv@propagandism.org>
Fri, 08 Jan 2016 20:17:39 +0100
changeset 320916 9e71a38057d1e37194c6a367d7df337e7088acca
parent 320915 5271840b178c83f3021833252c6595d600fcc6c8
child 320917 47eed1e76f6a4527e8ce787af863825fe9bbd450
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskats, dvander
bugs1020199
milestone47.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 1020199 - Make sure APZ works with nested oop iframe. r=kats, r=dvander.
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PBrowser.ipdl
dom/ipc/PContent.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
gfx/layers/apz/public/GeckoContentController.h
gfx/layers/ipc/APZChild.cpp
gfx/layers/ipc/APZChild.h
gfx/layers/ipc/CompositorParent.cpp
gfx/layers/ipc/CompositorParent.h
gfx/layers/ipc/PAPZ.ipdl
gfx/layers/ipc/PCompositor.ipdl
gfx/layers/ipc/RemoteContentController.cpp
gfx/layers/ipc/RemoteContentController.h
gfx/layers/ipc/ThreadSafeRefcountingWithMainThreadDestruction.h
gfx/layers/moz.build
layout/ipc/PRenderFrame.ipdl
layout/ipc/RenderFrameParent.cpp
layout/ipc/RenderFrameParent.h
widget/PuppetWidget.cpp
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -39,16 +39,17 @@
 #include "mozilla/psm/PSMContentListener.h"
 #include "mozilla/hal_sandbox/PHalChild.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/FileDescriptorSetChild.h"
 #include "mozilla/ipc/FileDescriptorUtils.h"
 #include "mozilla/ipc/GeckoChildProcessHost.h"
 #include "mozilla/ipc/TestShellChild.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
+#include "mozilla/layers/APZChild.h"
 #include "mozilla/layers/CompositorChild.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 #include "mozilla/layers/PCompositorChild.h"
 #include "mozilla/layers/SharedBufferManagerChild.h"
 #include "mozilla/layout/RenderFrameChild.h"
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/plugins/PluginInstanceParent.h"
 #include "mozilla/plugins/PluginModuleParent.h"
@@ -1255,16 +1256,29 @@ 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;
+}
+
 PCompositorChild*
 ContentChild::AllocPCompositorChild(mozilla::ipc::Transport* aTransport,
                                     base::ProcessId aOtherProcess)
 {
   return CompositorChild::Create(aTransport, aOtherProcess);
 }
 
 PSharedBufferManagerChild*
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -139,16 +139,21 @@ 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;
+
   PCompositorChild*
   AllocPCompositorChild(mozilla::ipc::Transport* aTransport,
                         base::ProcessId aOtherProcess) override;
 
   PSharedBufferManagerChild*
   AllocPSharedBufferManagerChild(mozilla::ipc::Transport* aTransport,
                                   base::ProcessId aOtherProcess) override;
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -78,16 +78,17 @@
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/BackgroundParent.h"
 #include "mozilla/ipc/FileDescriptorSetParent.h"
 #include "mozilla/ipc/FileDescriptorUtils.h"
 #include "mozilla/ipc/PFileDescriptorSetParent.h"
 #include "mozilla/ipc/TestShellParent.h"
 #include "mozilla/ipc/InputStreamUtils.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
+#include "mozilla/layers/PAPZParent.h"
 #include "mozilla/layers/CompositorParent.h"
 #include "mozilla/layers/ImageBridgeParent.h"
 #include "mozilla/layers/SharedBufferManagerParent.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/media/MediaParent.h"
 #include "mozilla/Move.h"
 #include "mozilla/net/NeckoParent.h"
 #include "mozilla/plugins/PluginBridge.h"
@@ -2023,21 +2024,71 @@ std::map<ContentParent*, std::set<uint64
 NestedBrowserLayerIds()
 {
   MOZ_ASSERT(NS_IsMainThread());
   static std::map<ContentParent*, std::set<uint64_t> > sNestedBrowserIds;
   return sNestedBrowserIds;
 }
 } // namespace
 
+/* static */
 bool
-ContentParent::RecvAllocateLayerTreeId(uint64_t* aId)
+ContentParent::AllocateLayerTreeId(TabParent* aTabParent, uint64_t* aId)
+{
+  return AllocateLayerTreeId(aTabParent->Manager()->AsContentParent(),
+                             aTabParent, aTabParent->GetTabId(), aId);
+}
+
+/* static */
+bool
+ContentParent::AllocateLayerTreeId(ContentParent* aContent,
+                                   TabParent* aTopLevel, const TabId& aTabId,
+                                   uint64_t* aId)
 {
   *aId = CompositorParent::AllocateLayerTreeId();
 
+  if (!gfxPlatform::AsyncPanZoomEnabled()) {
+    return true;
+  }
+
+  if (!aContent || !aTopLevel) {
+    return false;
+  }
+
+  return CompositorParent::UpdateRemoteContentController(*aId, aContent,
+                                                         aTabId, aTopLevel);
+}
+
+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
+  // child of it.
+  ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
+  if (ChildID() != aCpId) {
+    ContentParentId parent;
+    if (!cpm->GetParentProcessId(aCpId, &parent) ||
+        ChildID() != parent) {
+      return false;
+    }
+  }
+
+  // GetTopLevelTabParentByProcessAndTabId will make sure that aTabId
+  // lives in the process for aCpId.
+  RefPtr<ContentParent> contentParent = cpm->GetContentProcessById(aCpId);
+  RefPtr<TabParent> browserParent =
+    cpm->GetTopLevelTabParentByProcessAndTabId(aCpId, aTabId);
+  MOZ_ASSERT(contentParent && browserParent);
+
+  if (!AllocateLayerTreeId(contentParent, browserParent, aTabId, aId)) {
+    return false;
+  }
+
   auto iter = NestedBrowserLayerIds().find(this);
   if (iter == NestedBrowserLayerIds().end()) {
     std::set<uint64_t> ids;
     ids.insert(*aId);
     NestedBrowserLayerIds().insert(IDPair(this, ids));
   } else {
     iter->second.insert(*aId);
   }
@@ -3393,16 +3444,31 @@ 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;
+}
+
 PCompositorParent*
 ContentParent::AllocPCompositorParent(mozilla::ipc::Transport* aTransport,
                                       base::ProcessId aOtherProcess)
 {
   return CompositorParent::Create(aTransport, aOtherProcess);
 }
 
 gfx::PVRManagerParent*
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -501,16 +501,18 @@ public:
                                 const nsString& aName,
                                 const nsCString& aFeatures,
                                 const nsCString& aBaseURI,
                                 nsresult* aResult,
                                 bool* aWindowIsNew,
                                 InfallibleTArray<FrameScriptInfo>* aFrameScripts,
                                 nsCString* aURLToLoad) override;
 
+  static bool AllocateLayerTreeId(TabParent* aTabParent, uint64_t* aId);
+
 protected:
   void OnChannelConnected(int32_t pid) override;
 
   virtual void ActorDestroy(ActorDestroyReason why) override;
 
   void OnNuwaForkTimeout();
 
   bool ShouldContinueFromReplyTimeout() override;
@@ -645,20 +647,29 @@ private:
   // manager and null out mMessageManager.
   void ShutDownMessageManager();
 
   // Start the force-kill timer on shutdown.
   void StartForceKillTimer();
 
   static void ForceKillTimerCallback(nsITimer* aTimer, void* aClosure);
 
+  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;
+
   PCompositorParent*
   AllocPCompositorParent(mozilla::ipc::Transport* aTransport,
                          base::ProcessId aOtherProcess) override;
 
   PImageBridgeParent*
   AllocPImageBridgeParent(mozilla::ipc::Transport* aTransport,
                           base::ProcessId aOtherProcess) override;
 
@@ -999,17 +1010,19 @@ private:
 
   virtual bool RecvCopyFavicon(const URIParams& aOldURI,
                                const URIParams& aNewURI,
                                const IPC::Principal& aLoadingPrincipal,
                                const bool& aInPrivateBrowsing) override;
 
   virtual void ProcessingError(Result aCode, const char* aMsgName) override;
 
-  virtual bool RecvAllocateLayerTreeId(uint64_t* aId) override;
+  virtual bool RecvAllocateLayerTreeId(const ContentParentId& aCpId,
+                                       const TabId& aTabId,
+                                       uint64_t* aId) override;
 
   virtual bool RecvDeallocateLayerTreeId(const uint64_t& aId) override;
 
   virtual bool RecvGetGraphicsFeatureStatus(const int32_t& aFeature,
                                             int32_t* aStatus,
                                             bool* aSuccess) override;
 
   virtual bool
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -51,23 +51,19 @@ using class mozilla::WidgetWheelEvent fr
 using class mozilla::WidgetDragEvent from "ipc/nsGUIEventIPC.h";
 using struct nsRect from "nsRect.h";
 using class mozilla::WidgetSelectionEvent from "ipc/nsGUIEventIPC.h";
 using class mozilla::WidgetTouchEvent from "ipc/nsGUIEventIPC.h";
 using class mozilla::WidgetPluginEvent from "ipc/nsGUIEventIPC.h";
 using struct mozilla::dom::RemoteDOMEvent from "mozilla/dom/TabMessageUtils.h";
 using mozilla::dom::ScreenOrientationInternal from "mozilla/dom/ScreenOrientation.h";
 using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h";
-using mozilla::CSSPoint from "Units.h";
 using mozilla::CSSToScreenScale from "Units.h";
 using mozilla::CommandInt from "mozilla/EventForwards.h";
-using mozilla::Modifiers from "mozilla/EventForwards.h";
-using mozilla::layers::GeckoContentController::APZStateChange from "mozilla/layers/GeckoContentController.h";
 using mozilla::WritingMode from "mozilla/WritingModes.h";
-using mozilla::layers::AsyncDragMetrics from "mozilla/layers/AsyncDragMetrics.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::ipc::StructuredCloneData from "ipc/IPCMessageUtils.h";
 using mozilla::EventMessage from "mozilla/EventForwards.h";
 using nsEventStatus from "mozilla/EventForwards.h";
 using nsSizeMode from "nsIWidgetListener.h";
 using mozilla::widget::CandidateWindowPosition from "ipc/nsGUIEventIPC.h";
@@ -413,53 +409,16 @@ parent:
      *
      * @param opener the PBrowser whose content called window.open.
      */
     sync BrowserFrameOpenWindow(PBrowser opener, nsString aURL,
                                 nsString aName, nsString aFeatures)
       returns (bool windowOpened);
 
     /**
-     * Instructs the TabParent to forward a request to zoom to a rect given in
-     * CSS pixels. This rect is relative to the document.
-     */
-    async ZoomToRect(uint32_t aPresShellId, ViewID aViewId, CSSRect aRect, uint32_t aFlags);
-
-    /**
-     * We know for sure that content has either preventDefaulted or not
-     * preventDefaulted. This applies to an entire batch of touch events. It is
-     * expected that, if there are any DOM touch listeners, touch events will be
-     * batched and only processed for panning and zooming if content does not
-     * preventDefault.
-     */
-    async ContentReceivedInputBlock(ScrollableLayerGuid aGuid, uint64_t aInputBlockId, bool aPreventDefault);
-
-    /**
-     * Notifies the APZ code of the results of the gecko hit-test for a
-     * particular input block. Each target corresponds to one touch point in the
-     * touch event.
-     */
-    async SetTargetAPZC(uint64_t aInputBlockId, ScrollableLayerGuid[] aTargets);
-
-    /**
-     * Notifies the APZ code of the allowed touch-behaviours for a particular
-     * input block. Each item in the aFlags array corresponds to one touch point
-     * in the touch event.
-     */
-    async SetAllowedTouchBehavior(uint64_t aInputBlockId, TouchBehaviorFlags[] aFlags);
-
-    /**
-     * Updates the zoom constraints for a scrollable frame in this tab.
-     * The zoom controller code lives on the parent side and so this allows it to
-     * have up-to-date zoom constraints.
-     */
-    async UpdateZoomConstraints(uint32_t aPresShellId, ViewID aViewId,
-                                MaybeZoomConstraints aConstraints);
-
-    /**
      * Tells the containing widget whether the given input block results in a
      * swipe. Should be called in response to a WidgetWheelEvent that has
      * mFlags.mCanTriggerSwipe set on it.
      */
     async RespondStartSwipeEvent(uint64_t aInputBlockId, bool aStartSwipe);
 
     /**
      * Brings up the auth prompt dialog.
@@ -533,19 +492,16 @@ parent:
      * dimensions has been requested, likely through win.moveTo or resizeTo
      */
     async SetDimensions(uint32_t aFlags, int32_t aX, int32_t aY, int32_t aCx, int32_t aCy);
 
     prio(high) sync DispatchWheelEvent(WidgetWheelEvent event);
     prio(high) sync DispatchMouseEvent(WidgetMouseEvent event);
     prio(high) sync DispatchKeyboardEvent(WidgetKeyboardEvent event);
 
-    // Start an APZ drag on a scrollbar
-    async StartScrollbarDrag(AsyncDragMetrics aDragMetrics);
-
     async InvokeDragSession(IPCDataTransfer[] transfers, uint32_t action,
                             nsCString visualData, uint32_t width, uint32_t height,
                             uint32_t stride, uint8_t format,
                             int32_t dragAreaX, int32_t dragAreaY);
 
     async AudioChannelActivityNotification(uint32_t aAudioChannel,
                                            bool aActive);
 
@@ -571,30 +527,16 @@ child:
     async OpenURI(URIParams uri, uint32_t flags);
 
     async CacheFileDescriptor(nsString path, FileDescriptor fd);
 
     async UpdateDimensions(CSSRect rect, CSSSize size, nsSizeMode sizeMode,
                            ScreenOrientationInternal orientation,
                            LayoutDeviceIntPoint chromeDisp) compressall;
 
-    async UpdateFrame(FrameMetrics frame);
-
-    // The following methods correspond to functions on the GeckoContentController
-    // interface in gfx/layers/apz/public/GeckoContentController.h. Refer to documentation
-    // in that file for these functions.
-    async RequestFlingSnap(ViewID aScrollID, CSSPoint aDestination);
-    async AcknowledgeScrollUpdate(ViewID aScrollId, uint32_t aScrollGeneration);
-    async HandleDoubleTap(CSSPoint aPoint, Modifiers aModifiers, ScrollableLayerGuid aGuid);
-    async HandleSingleTap(CSSPoint aPoint, Modifiers aModifiers, ScrollableLayerGuid aGuid);
-    async HandleLongTap(CSSPoint point, Modifiers aModifiers, ScrollableLayerGuid aGuid, uint64_t aInputBlockId);
-    async NotifyAPZStateChange(ViewID aViewId, APZStateChange aChange, int aArg);
-    async NotifyFlushComplete();
-
-
     /**
      * Sending an activate message moves focus to the child.
      */
     async Activate();
 
     async Deactivate();
 
     async ParentActivated(bool aActivated);
@@ -656,17 +598,17 @@ child:
                    int32_t aKeyCode,
                    int32_t aCharCode,
                    int32_t aModifiers,
                    bool aPreventDefault);
 
     /**
      * APZ notification for mouse scroll testing events.
      */
-    async MouseScrollTestEvent(ViewID aScrollId, nsString aEvent);
+    async MouseScrollTestEvent(uint64_t aLayersId, ViewID aScrollId, nsString aEvent);
 
     async CompositionEvent(WidgetCompositionEvent event);
 
     async SelectionEvent(WidgetSelectionEvent event);
 
     /**
      * Activate event forwarding from client to parent.
      */
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -1,14 +1,15 @@
 /* -*- 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 PCompositor;
 include protocol PContentBridge;
 include protocol PContentPermissionRequest;
@@ -460,16 +461,17 @@ prio(normal upto urgent) sync protocol P
     parent opens PCompositor;
     parent opens PProcessHangMonitor;
     parent opens PSharedBufferManager;
     parent opens PImageBridge;
     parent opens PGMPService;
     parent opens PVRManager;
     child opens PBackground;
 
+    manages PAPZ;
     manages PBlob;
     manages PBluetooth;
     manages PBrowser;
     manages PCellBroadcast;
     manages PContentPermissionRequest;
     manages PCrashReporter;
     manages PCycleCollectWithLogs;
     manages PDeviceStorageRequest;
@@ -570,16 +572,18 @@ 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 SetOffline(bool offline);
     async SetConnectivity(bool connectivity);
 
     async NotifyVisited(URIParams uri);
@@ -988,17 +992,17 @@ parent:
     sync KeywordToURI(nsCString keyword)
         returns (nsString providerName, OptionalInputStreamParams postData, OptionalURIParams uri);
 
     sync NotifyKeywordSearchLoading(nsString providerName, nsString keyword);
 
     async CopyFavicon(URIParams oldURI, URIParams newURI, Principal aLoadingPrincipal, bool isPrivate);
 
     // Tell the compositor to allocate a layer tree id for nested remote mozbrowsers.
-    sync AllocateLayerTreeId()
+    sync AllocateLayerTreeId(ContentParentId cpId, TabId tabId)
         returns (uint64_t id);
     async DeallocateLayerTreeId(uint64_t id);
 
     sync SpeakerManagerForceSpeaker(bool aEnable);
 
     sync SpeakerManagerGetSpeakerStatus()
         returns (bool value);
 
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -11,37 +11,40 @@
 #include "gfxPrefs.h"
 #ifdef ACCESSIBILITY
 #include "mozilla/a11y/DocAccessibleChild.h"
 #endif
 #include "Layers.h"
 #include "ContentChild.h"
 #include "TabParent.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/BrowserElementParent.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/dom/workers/ServiceWorkerManager.h"
 #include "mozilla/dom/indexedDB/PIndexedDBPermissionRequestChild.h"
 #include "mozilla/plugins/PluginWidgetChild.h"
 #include "mozilla/IMEStateManager.h"
 #include "mozilla/ipc/DocumentRendererChild.h"
 #include "mozilla/ipc/URIUtils.h"
 #ifdef MOZ_NUWA_PROCESS
 #include "ipc/Nuwa.h"
 #endif
 #include "mozilla/ipc/FileDescriptorUtils.h"
+#include "mozilla/layers/APZChild.h"
 #include "mozilla/layers/APZCCallbackHelper.h"
 #include "mozilla/layers/APZCTreeManager.h"
 #include "mozilla/layers/APZEventState.h"
 #include "mozilla/layers/CompositorChild.h"
 #include "mozilla/layers/DoubleTapToZoom.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 #include "mozilla/layers/InputAPZContext.h"
 #include "mozilla/layers/ShadowLayers.h"
 #include "mozilla/layout/RenderFrameChild.h"
+#include "mozilla/layout/RenderFrameParent.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/Move.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/TouchEvents.h"
 #include "mozilla/unused.h"
@@ -584,30 +587,31 @@ TabChild::TabChild(nsIContentChild* aMan
   , mHasValidInnerSize(false)
   , mDestroyed(false)
   , mUniqueId(aTabId)
   , mDPI(0)
   , mDefaultScale(0)
   , mIPCOpen(true)
   , mParentIsActive(false)
   , mDidSetRealShowInfo(false)
+  , mAPZChild(nullptr)
 {
   // In the general case having the TabParent tell us if APZ is enabled or not
   // doesn't really work because the TabParent itself may not have a reference
   // to the owning widget during initialization. Instead we assume that this
   // TabChild corresponds to a widget type that would have APZ enabled, and just
   // check the other conditions necessary for enabling APZ.
   mAsyncPanZoomEnabled = gfxPlatform::AsyncPanZoomEnabled();
 
   nsWeakPtr weakPtrThis(do_GetWeakReference(static_cast<nsITabChild*>(this)));  // for capture by the lambda
   mSetAllowedTouchBehaviorCallback = [weakPtrThis](uint64_t aInputBlockId,
                                                    const nsTArray<TouchBehaviorFlags>& aFlags)
   {
     if (nsCOMPtr<nsITabChild> tabChild = do_QueryReferent(weakPtrThis)) {
-      static_cast<TabChild*>(tabChild.get())->SendSetAllowedTouchBehavior(aInputBlockId, aFlags);
+      static_cast<TabChild*>(tabChild.get())->SetAllowedTouchBehavior(aInputBlockId, aFlags);
     }
   };
 
   // preloaded TabChild should not be added to child map
   if (mUniqueId) {
     MOZ_ASSERT(NestedTabChildMap().find(mUniqueId) == NestedTabChildMap().end());
     NestedTabChildMap()[mUniqueId] = this;
   }
@@ -705,31 +709,63 @@ TabChild::Observe(nsISupports *aSubject,
       mAudioChannelsActive[audioChannel] = active;
       Unused << SendAudioChannelActivityNotification(audioChannel, active);
     }
   }
 
   return NS_OK;
 }
 
+void
+TabChild::ContentReceivedInputBlock(const ScrollableLayerGuid& aGuid,
+                                    uint64_t aInputBlockId,
+                                    bool aPreventDefault) const
+{
+  if (mAPZChild) {
+    mAPZChild->SendContentReceivedInputBlock(aGuid, aInputBlockId,
+                                             aPreventDefault);
+  }
+}
+
+void
+TabChild::SetTargetAPZC(uint64_t aInputBlockId,
+                        const nsTArray<ScrollableLayerGuid>& aTargets) const
+{
+  if (mAPZChild) {
+    mAPZChild->SendSetTargetAPZC(aInputBlockId, aTargets);
+  }
+}
+
+void
+TabChild::SetAllowedTouchBehavior(uint64_t aInputBlockId,
+                                  const nsTArray<TouchBehaviorFlags>& aTargets) const
+{
+  if (mAPZChild) {
+    mAPZChild->SendSetAllowedTouchBehavior(aInputBlockId, aTargets);
+  }
+}
+
 bool
 TabChild::DoUpdateZoomConstraints(const uint32_t& aPresShellId,
                                   const ViewID& aViewId,
                                   const Maybe<ZoomConstraints>& aConstraints)
 {
   if (sPreallocatedTab == this) {
     // If we're the preallocated tab, bail out because doing IPC will crash.
     // Once we get used for something we'll get another zoom constraints update
     // and all will be well.
     return true;
   }
 
-  return SendUpdateZoomConstraints(aPresShellId,
-                                   aViewId,
-                                   aConstraints);
+  if (!mAPZChild) {
+    return false;
+  }
+
+  return mAPZChild->SendUpdateZoomConstraints(aPresShellId, aViewId,
+                                              aConstraints);
 }
 
 nsresult
 TabChild::Init()
 {
   nsCOMPtr<nsIWebBrowser> webBrowser = do_CreateInstance(NS_WEBBROWSER_CONTRACTID);
   if (!webBrowser) {
     NS_ERROR("Couldn't create a nsWebBrowser?");
@@ -806,17 +842,17 @@ TabChild::Init()
 
   nsWeakPtr weakPtrThis = do_GetWeakReference(static_cast<nsITabChild*>(this));  // for capture by the lambda
   ContentReceivedInputBlockCallback callback(
       [weakPtrThis](const ScrollableLayerGuid& aGuid,
                     uint64_t aInputBlockId,
                     bool aPreventDefault)
       {
         if (nsCOMPtr<nsITabChild> tabChild = do_QueryReferent(weakPtrThis)) {
-          static_cast<TabChild*>(tabChild.get())->SendContentReceivedInputBlock(aGuid, aInputBlockId, aPreventDefault);
+          static_cast<TabChild*>(tabChild.get())->ContentReceivedInputBlock(aGuid, aInputBlockId, aPreventDefault);
         }
       });
   mAPZEventState = new APZEventState(mPuppetWidget, Move(callback));
 
   return NS_OK;
 }
 
 void
@@ -1628,17 +1664,17 @@ TabChild::RecvUpdateDimensions(const CSS
     mPuppetWidget->Resize(screenRect.x + chromeDisp.x,
                           screenRect.y + chromeDisp.y,
                           screenSize.width, screenSize.height, true);
 
     return true;
 }
 
 bool
-TabChild::RecvUpdateFrame(const FrameMetrics& aFrameMetrics)
+TabChild::UpdateFrame(const FrameMetrics& aFrameMetrics)
 {
   return TabChildBase::UpdateFrameHandler(aFrameMetrics);
 }
 
 bool
 TabChild::RecvSuppressDisplayport(const bool& aEnabled)
 {
   if (aEnabled) {
@@ -1647,101 +1683,104 @@ TabChild::RecvSuppressDisplayport(const 
     mActiveSuppressDisplayport--;
   }
 
   MOZ_ASSERT(mActiveSuppressDisplayport >= 0);
   APZCCallbackHelper::SuppressDisplayport(aEnabled);
   return true;
 }
 
-bool
-TabChild::RecvRequestFlingSnap(const FrameMetrics::ViewID& aScrollId,
-                               const mozilla::CSSPoint& aDestination)
-{
-  APZCCallbackHelper::RequestFlingSnap(aScrollId, aDestination);
-  return true;
-}
-
-bool
-TabChild::RecvAcknowledgeScrollUpdate(const ViewID& aScrollId,
-                                      const uint32_t& aScrollGeneration)
-{
-  APZCCallbackHelper::AcknowledgeScrollUpdate(aScrollId, aScrollGeneration);
-  return true;
-}
-
-bool
-TabChild::RecvHandleDoubleTap(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid)
+void
+TabChild::HandleDoubleTap(const CSSPoint& aPoint, const Modifiers& aModifiers,
+                          const ScrollableLayerGuid& aGuid)
 {
-    TABC_LOG("Handling double tap at %s with %p %p\n",
-      Stringify(aPoint).c_str(), mGlobal.get(), mTabChildGlobal.get());
-
-    if (!mGlobal || !mTabChildGlobal) {
-        return true;
-    }
-
-    // Note: there is nothing to do with the modifiers here, as we are not
-    // synthesizing any sort of mouse event.
-    CSSPoint point = APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid);
-    nsCOMPtr<nsIDocument> document = GetDocument();
-    CSSRect zoomToRect = CalculateRectToZoomTo(document, point);
-    // The double-tap can be dispatched by any scroll frame (so |aGuid| could be
-    // the guid of any scroll frame), but the zoom-to-rect operation must be
-    // performed by the root content scroll frame, so query its identifiers
-    // for the SendZoomToRect() call rather than using the ones from |aGuid|.
-    uint32_t presShellId;
-    ViewID viewId;
-    if (APZCCallbackHelper::GetOrCreateScrollIdentifiers(
-        document->GetDocumentElement(), &presShellId, &viewId)) {
-      SendZoomToRect(presShellId, viewId, zoomToRect, DEFAULT_BEHAVIOR);
-    }
-
-    return true;
+  TABC_LOG("Handling double tap at %s with %p %p\n",
+    Stringify(aPoint).c_str(), mGlobal.get(), mTabChildGlobal.get());
+
+  if (!mGlobal || !mTabChildGlobal) {
+    return;
+  }
+
+  // Note: there is nothing to do with the modifiers here, as we are not
+  // synthesizing any sort of mouse event.
+  CSSPoint point = APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid);
+  nsCOMPtr<nsIDocument> document = GetDocument();
+  CSSRect zoomToRect = CalculateRectToZoomTo(document, point);
+  // The double-tap can be dispatched by any scroll frame (so |aGuid| could be
+  // the guid of any scroll frame), but the zoom-to-rect operation must be
+  // performed by the root content scroll frame, so query its identifiers
+  // for the SendZoomToRect() call rather than using the ones from |aGuid|.
+  uint32_t presShellId;
+  ViewID viewId;
+  if (APZCCallbackHelper::GetOrCreateScrollIdentifiers(
+      document->GetDocumentElement(), &presShellId, &viewId) &&
+      mAPZChild) {
+    mAPZChild->SendZoomToRect(presShellId, viewId, zoomToRect,
+                              DEFAULT_BEHAVIOR);
+  }
 }
 
-bool
-TabChild::RecvHandleSingleTap(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid)
+void
+TabChild::HandleSingleTap(const CSSPoint& aPoint,
+                          const Modifiers& aModifiers,
+                          const ScrollableLayerGuid& aGuid,
+                          bool aCallTakeFocusForClickFromTap)
 {
+  if (aCallTakeFocusForClickFromTap && mRemoteFrame) {
+    mRemoteFrame->SendTakeFocusForClickFromTap();
+  }
   if (mGlobal && mTabChildGlobal) {
     mAPZEventState->ProcessSingleTap(aPoint, aModifiers, aGuid);
   }
-  return true;
 }
 
-bool
-TabChild::RecvHandleLongTap(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId)
+void
+TabChild::HandleLongTap(const CSSPoint& aPoint, const Modifiers& aModifiers,
+                        const ScrollableLayerGuid& aGuid,
+                        const uint64_t& aInputBlockId)
 {
   if (mGlobal && mTabChildGlobal) {
     mAPZEventState->ProcessLongTap(GetPresShell(), aPoint, aModifiers, aGuid,
         aInputBlockId);
   }
-  return true;
 }
 
 bool
-TabChild::RecvNotifyAPZStateChange(const ViewID& aViewId,
-                                   const APZStateChange& aChange,
-                                   const int& aArg)
+TabChild::NotifyAPZStateChange(const ViewID& aViewId,
+                               const layers::GeckoContentController::APZStateChange& aChange,
+                               const int& aArg)
 {
   mAPZEventState->ProcessAPZStateChange(GetDocument(), aViewId, aChange, aArg);
-  if (aChange == APZStateChange::TransformEnd) {
+  if (aChange == layers::GeckoContentController::APZStateChange::TransformEnd) {
     // This is used by tests to determine when the APZ is done doing whatever
     // it's doing. XXX generify this as needed when writing additional tests.
     DispatchMessageManagerMessage(
       NS_LITERAL_STRING("APZ:TransformEnd"),
       NS_LITERAL_STRING("{}"));
   }
   return true;
 }
 
-bool
-TabChild::RecvNotifyFlushComplete()
+void
+TabChild::StartScrollbarDrag(const layers::AsyncDragMetrics& aDragMetrics)
 {
-  APZCCallbackHelper::NotifyFlushComplete();
-  return true;
+  if (mAPZChild) {
+    mAPZChild->SendStartScrollbarDrag(aDragMetrics);
+  }
+}
+
+void
+TabChild::ZoomToRect(const uint32_t& aPresShellId,
+                     const FrameMetrics::ViewID& aViewId,
+                     const CSSRect& aRect,
+                     const uint32_t& aFlags)
+{
+  if (mAPZChild) {
+    mAPZChild->SendZoomToRect(aPresShellId, aViewId, aRect, aFlags);
+  }
 }
 
 bool
 TabChild::RecvActivate()
 {
   nsCOMPtr<nsIWebBrowserFocus> browser = do_QueryInterface(WebNavigation());
   browser->Activate();
   return true;
@@ -1849,18 +1888,31 @@ TabChild::RecvMouseWheelEvent(const Widg
 
   if (aEvent.mFlags.mHandledByAPZ) {
     mAPZEventState->ProcessWheelEvent(event, aGuid, aInputBlockId);
   }
   return true;
 }
 
 bool
-TabChild::RecvMouseScrollTestEvent(const FrameMetrics::ViewID& aScrollId, const nsString& aEvent)
+TabChild::RecvMouseScrollTestEvent(const uint64_t& aLayersId,
+                                   const FrameMetrics::ViewID& aScrollId, const nsString& aEvent)
 {
+  if (aLayersId != mLayersId) {
+    RefPtr<TabParent> browser = TabParent::GetTabParentFromLayersId(aLayersId);
+    if (!browser) {
+      return false;
+    }
+    NS_DispatchToMainThread(NS_NewRunnableFunction(
+      [aLayersId, browser, aScrollId, aEvent] () -> void {
+        Unused << browser->SendMouseScrollTestEvent(aLayersId, aScrollId, aEvent);
+      }));
+    return true;
+  }
+
   APZCCallbackHelper::NotifyMozMouseScrollEvent(aScrollId, aEvent);
   return true;
 }
 
 bool
 TabChild::RecvRealTouchEvent(const WidgetTouchEvent& aEvent,
                              const ScrollableLayerGuid& aGuid,
                              const uint64_t& aInputBlockId,
@@ -2617,17 +2669,20 @@ TabChild::MakeHidden()
   if (mPuppetWidget) {
     mPuppetWidget->Show(false);
   }
 }
 
 void
 TabChild::UpdateHitRegion(const nsRegion& aRegion)
 {
-    mRemoteFrame->SendUpdateHitRegion(aRegion);
+  mRemoteFrame->SendUpdateHitRegion(aRegion);
+  if (mAPZChild) {
+    mAPZChild->SendUpdateHitRegion(aRegion);
+  }
 }
 
 NS_IMETHODIMP
 TabChild::GetMessageManager(nsIContentFrameMessageManager** aResult)
 {
   if (mTabChildGlobal) {
     NS_ADDREF(*aResult = mTabChildGlobal);
     return NS_OK;
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -32,27 +32,30 @@
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventForwards.h"
 #include "mozilla/layers/CompositorTypes.h"
 #include "mozilla/layers/APZCCallbackHelper.h"
 #include "nsIWebBrowserChrome3.h"
 #include "mozilla/dom/ipc/IdType.h"
 #include "AudioChannelService.h"
 #include "PuppetWidget.h"
+#include "mozilla/layers/GeckoContentController.h"
 
 class nsICachedFileDescriptorListener;
 class nsIDOMWindowUtils;
 
 namespace mozilla {
 namespace layout {
 class RenderFrameChild;
 } // namespace layout
 
 namespace layers {
+class APZChild;
 class APZEventState;
+class AsyncDragMetrics;
 class ImageCompositeNotification;
 } // namespace layers
 
 namespace widget {
 struct AutoCacheNativeKeyCommands;
 } // namespace widget
 
 namespace plugins {
@@ -327,49 +330,16 @@ public:
 
   virtual bool
   RecvUpdateDimensions(const CSSRect& aRect,
                        const CSSSize& aSize,
                        const nsSizeMode& aSizeMode,
                        const ScreenOrientationInternal& aOrientation,
                        const LayoutDeviceIntPoint& aChromeDisp) override;
 
-  virtual bool
-  RecvUpdateFrame(const layers::FrameMetrics& aFrameMetrics) override;
-
-  virtual bool
-  RecvRequestFlingSnap(const ViewID& aScrollId,
-                       const CSSPoint& aDestination) override;
-
-  virtual bool
-  RecvAcknowledgeScrollUpdate(const ViewID& aScrollId,
-                              const uint32_t& aScrollGeneration) override;
-
-  virtual bool
-  RecvHandleDoubleTap(const CSSPoint& aPoint,
-                      const Modifiers& aModifiers,
-                      const mozilla::layers::ScrollableLayerGuid& aGuid) override;
-
-  virtual bool
-  RecvHandleSingleTap(const CSSPoint& aPoint,
-                      const Modifiers& aModifiers,
-                      const mozilla::layers::ScrollableLayerGuid& aGuid) override;
-
-  virtual bool
-  RecvHandleLongTap(const CSSPoint& aPoint,
-                    const Modifiers& aModifiers,
-                    const mozilla::layers::ScrollableLayerGuid& aGuid,
-                    const uint64_t& aInputBlockId) override;
-
-  virtual bool RecvNotifyAPZStateChange(const ViewID& aViewId,
-                                        const APZStateChange& aChange,
-                                        const int& aArg) override;
-
-  virtual bool RecvNotifyFlushComplete() override;
-
   virtual bool RecvActivate() override;
 
   virtual bool RecvDeactivate() override;
 
   virtual bool RecvMouseEvent(const nsString& aType,
                               const float& aX,
                               const float& aY,
                               const int32_t& aButton,
@@ -413,17 +383,18 @@ public:
                          const nsEventStatus& aApzResponse) override;
 
   virtual bool RecvKeyEvent(const nsString& aType,
                             const int32_t& aKeyCode,
                             const int32_t& aCharCode,
                             const int32_t& aModifiers,
                             const bool& aPreventDefault) override;
 
-  virtual bool RecvMouseScrollTestEvent(const FrameMetrics::ViewID& aScrollId,
+  virtual bool RecvMouseScrollTestEvent(const uint64_t& aLayersId,
+                                        const FrameMetrics::ViewID& aScrollId,
                                         const nsString& aEvent) override;
 
   virtual bool RecvNativeSynthesisResponse(const uint64_t& aObserverId,
                                            const nsCString& aResponse) override;
 
   virtual bool RecvPluginEvent(const WidgetPluginEvent& aEvent) override;
 
   virtual bool
@@ -617,16 +588,50 @@ public:
   virtual ScreenIntSize GetInnerSize() override;
 
   // Call RecvShow(nsIntSize(0, 0)) and block future calls to RecvShow().
   void DoFakeShow(const TextureFactoryIdentifier& aTextureFactoryIdentifier,
                   const uint64_t& aLayersId,
                   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 HandleDoubleTap(const CSSPoint& aPoint,
+                       const Modifiers& aModifiers,
+                       const mozilla::layers::ScrollableLayerGuid& aGuid);
+  void HandleSingleTap(const CSSPoint& aPoint,
+                       const Modifiers& aModifiers,
+                       const mozilla::layers::ScrollableLayerGuid& aGuid,
+                       bool aCallTakeFocusForClickFromTap);
+  void HandleLongTap(const CSSPoint& aPoint,
+                     const Modifiers& aModifiers,
+                     const mozilla::layers::ScrollableLayerGuid& aGuid,
+                     const uint64_t& aInputBlockId);
+  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);
+  void ZoomToRect(const uint32_t& aPresShellId,
+                  const FrameMetrics::ViewID& aViewId,
+                  const CSSRect& aRect,
+                  const uint32_t& aFlags);
+
+  void SetAPZChild(layers::APZChild* aAPZChild)
+  {
+      mAPZChild = aAPZChild;
+  }
+
 protected:
   virtual ~TabChild();
 
   virtual PRenderFrameChild* AllocPRenderFrameChild() override;
 
   virtual bool DeallocPRenderFrameChild(PRenderFrameChild* aFrame) override;
 
   virtual bool RecvDestroy() override;
@@ -731,15 +736,19 @@ private:
   bool mIPCOpen;
   bool mParentIsActive;
   bool mAsyncPanZoomEnabled;
   CSSSize mUnscaledInnerSize;
   bool mDidSetRealShowInfo;
 
   AutoTArray<bool, NUMBER_OF_AUDIO_CHANNELS> mAudioChannelsActive;
 
+  // APZChild clears this pointer from its destructor, so it shouldn't be a
+  // dangling pointer.
+  layers::APZChild* mAPZChild;
+
   DISALLOW_EVIL_CONSTRUCTORS(TabChild);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_TabChild_h
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -991,24 +991,16 @@ TabParent::UpdateDimensions(const nsIntR
     CSSSize unscaledSize = devicePixelSize / widgetScale;
     Unused << SendUpdateDimensions(unscaledRect, unscaledSize,
                                    widget->SizeMode(),
                                    orientation, chromeOffset);
   }
 }
 
 void
-TabParent::UpdateFrame(const FrameMetrics& aFrameMetrics)
-{
-  if (!mIsDestroyed) {
-    Unused << SendUpdateFrame(aFrameMetrics);
-  }
-}
-
-void
 TabParent::UIResolutionChanged()
 {
   if (!mIsDestroyed) {
     // TryCacheDPIAndScale()'s cache is keyed off of
     // mDPI being greater than 0, so this invalidates it.
     mDPI = -1;
     TryCacheDPIAndScale();
     // If mDPI was set to -1 to invalidate it and then TryCacheDPIAndScale
@@ -1038,86 +1030,16 @@ TabParent::HandleAccessKey(nsTArray<uint
                            const int32_t& aModifierMask)
 {
   if (!mIsDestroyed) {
     Unused << SendHandleAccessKey(aCharCodes, aIsTrusted, aModifierMask);
   }
 }
 
 void
-TabParent::RequestFlingSnap(const FrameMetrics::ViewID& aScrollId,
-                            const mozilla::CSSPoint& aDestination)
-{
-  if (!mIsDestroyed) {
-    Unused << SendRequestFlingSnap(aScrollId, aDestination);
-  }
-}
-
-void
-TabParent::AcknowledgeScrollUpdate(const ViewID& aScrollId, const uint32_t& aScrollGeneration)
-{
-  if (!mIsDestroyed) {
-    Unused << SendAcknowledgeScrollUpdate(aScrollId, aScrollGeneration);
-  }
-}
-
-void TabParent::HandleDoubleTap(const CSSPoint& aPoint,
-                                Modifiers aModifiers,
-                                const ScrollableLayerGuid &aGuid)
-{
-  if (!mIsDestroyed) {
-    Unused << SendHandleDoubleTap(aPoint, aModifiers, aGuid);
-  }
-}
-
-void TabParent::HandleSingleTap(const CSSPoint& aPoint,
-                                Modifiers aModifiers,
-                                const ScrollableLayerGuid &aGuid)
-{
-  if (!mIsDestroyed) {
-    Unused << SendHandleSingleTap(aPoint, aModifiers, aGuid);
-  }
-}
-
-void TabParent::HandleLongTap(const CSSPoint& aPoint,
-                              Modifiers aModifiers,
-                              const ScrollableLayerGuid &aGuid,
-                              uint64_t aInputBlockId)
-{
-  if (!mIsDestroyed) {
-    Unused << SendHandleLongTap(aPoint, aModifiers, aGuid, aInputBlockId);
-  }
-}
-
-void TabParent::NotifyAPZStateChange(ViewID aViewId,
-                                     APZStateChange aChange,
-                                     int aArg)
-{
-  if (!mIsDestroyed) {
-    Unused << SendNotifyAPZStateChange(aViewId, aChange, aArg);
-  }
-}
-
-void
-TabParent::NotifyMouseScrollTestEvent(const ViewID& aScrollId, const nsString& aEvent)
-{
-  if (!mIsDestroyed) {
-    Unused << SendMouseScrollTestEvent(aScrollId, aEvent);
-  }
-}
-
-void
-TabParent::NotifyFlushComplete()
-{
-  if (!mIsDestroyed) {
-    Unused << SendNotifyFlushComplete();
-  }
-}
-
-void
 TabParent::Activate()
 {
   if (!mIsDestroyed) {
     Unused << SendActivate();
   }
 }
 
 void
@@ -1395,43 +1317,16 @@ TabParent::SendRealDragEvent(WidgetDragE
   return PBrowserParent::SendRealDragEvent(event, aDragAction, aDropEffect);
 }
 
 CSSPoint TabParent::AdjustTapToChildWidget(const CSSPoint& aPoint)
 {
   return aPoint + (LayoutDevicePoint(GetChildProcessOffset()) * GetLayoutDeviceToCSSScale());
 }
 
-bool TabParent::SendHandleSingleTap(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid)
-{
-  if (mIsDestroyed) {
-    return false;
-  }
-
-  return PBrowserParent::SendHandleSingleTap(AdjustTapToChildWidget(aPoint), aModifiers, aGuid);
-}
-
-bool TabParent::SendHandleLongTap(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId)
-{
-  if (mIsDestroyed) {
-    return false;
-  }
-
-  return PBrowserParent::SendHandleLongTap(AdjustTapToChildWidget(aPoint), aModifiers, aGuid, aInputBlockId);
-}
-
-bool TabParent::SendHandleDoubleTap(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid)
-{
-  if (mIsDestroyed) {
-    return false;
-  }
-
-  return PBrowserParent::SendHandleDoubleTap(AdjustTapToChildWidget(aPoint), aModifiers, aGuid);
-}
-
 bool TabParent::SendMouseWheelEvent(WidgetWheelEvent& event)
 {
   if (mIsDestroyed) {
     return false;
   }
 
   ScrollableLayerGuid guid;
   uint64_t blockId;
@@ -2792,88 +2687,25 @@ TabParent::RecvBrowserFrameOpenWindow(PB
   BrowserElementParent::OpenWindowResult opened =
     BrowserElementParent::OpenWindowOOP(TabParent::GetFrom(aOpener),
                                         this, aURL, aName, aFeatures);
   *aOutWindowOpened = (opened == BrowserElementParent::OPEN_WINDOW_ADDED);
   return true;
 }
 
 bool
-TabParent::RecvZoomToRect(const uint32_t& aPresShellId,
-                          const ViewID& aViewId,
-                          const CSSRect& aRect,
-                          const uint32_t& aFlags)
-{
-  if (RenderFrameParent* rfp = GetRenderFrame()) {
-    rfp->ZoomToRect(aPresShellId, aViewId, aRect, aFlags);
-  }
-  return true;
-}
-
-bool
-TabParent::RecvUpdateZoomConstraints(const uint32_t& aPresShellId,
-                                     const ViewID& aViewId,
-                                     const MaybeZoomConstraints& aConstraints)
-{
-  if (RenderFrameParent* rfp = GetRenderFrame()) {
-    rfp->UpdateZoomConstraints(aPresShellId, aViewId, aConstraints);
-  }
-  return true;
-}
-
-bool
 TabParent::RecvRespondStartSwipeEvent(const uint64_t& aInputBlockId,
                                       const bool& aStartSwipe)
 {
   if (nsCOMPtr<nsIWidget> widget = GetWidget()) {
     widget->ReportSwipeStarted(aInputBlockId, aStartSwipe);
   }
   return true;
 }
 
-bool
-TabParent::RecvContentReceivedInputBlock(const ScrollableLayerGuid& aGuid,
-                                         const uint64_t& aInputBlockId,
-                                         const bool& aPreventDefault)
-{
-  if (RenderFrameParent* rfp = GetRenderFrame()) {
-    rfp->ContentReceivedInputBlock(aGuid, aInputBlockId, aPreventDefault);
-  }
-  return true;
-}
-
-bool
-TabParent::RecvSetTargetAPZC(const uint64_t& aInputBlockId,
-                             nsTArray<ScrollableLayerGuid>&& aTargets)
-{
-  if (RenderFrameParent* rfp = GetRenderFrame()) {
-    rfp->SetTargetAPZC(aInputBlockId, aTargets);
-  }
-  return true;
-}
-
-bool
-TabParent::RecvStartScrollbarDrag(const AsyncDragMetrics& aDragMetrics)
-{
-  if (RenderFrameParent* rfp = GetRenderFrame()) {
-    rfp->StartScrollbarDrag(aDragMetrics);
-  }
-  return true;
-}
-
-bool
-TabParent::RecvSetAllowedTouchBehavior(const uint64_t& aInputBlockId,
-                                       nsTArray<TouchBehaviorFlags>&& aFlags)
-{
-  if (RenderFrameParent* rfp = GetRenderFrame()) {
-    rfp->SetAllowedTouchBehavior(aInputBlockId, aFlags);
-  }
-  return true;
-}
-
 already_AddRefed<nsILoadContext>
 TabParent::GetLoadContext()
 {
   nsCOMPtr<nsILoadContext> loadContext;
   if (mLoadContext) {
     loadContext = mLoadContext;
   } else {
     loadContext = new LoadContext(GetOwnerElement(),
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -45,18 +45,16 @@ namespace a11y {
 class DocAccessibleParent;
 }
 
 namespace jsipc {
 class CpowHolder;
 } // namespace jsipc
 
 namespace layers {
-class AsyncDragMetrics;
-struct FrameMetrics;
 struct TextureFactoryIdentifier;
 } // namespace layers
 
 namespace layout {
 class RenderFrameParent;
 } // namespace layout
 
 namespace widget {
@@ -85,17 +83,16 @@ class TabParent final : public PBrowserP
                       , public nsIAuthPromptProvider
                       , public nsISecureBrowserUI
                       , public nsSupportsWeakReference
                       , public TabContext
                       , public nsAPostRefreshObserver
                       , public nsIWebBrowserPersistable
 {
   typedef mozilla::dom::ClonedMessageData ClonedMessageData;
-  typedef mozilla::layers::AsyncDragMetrics AsyncDragMetrics;
 
   virtual ~TabParent();
 
 public:
   // Helper class for ContentParent::RecvCreateWindow.
   struct AutoUseNewTab;
 
   // nsITabParent
@@ -292,53 +289,28 @@ public:
   virtual bool RecvGetMaxTouchPoints(uint32_t* aTouchPoints) override;
 
   virtual bool RecvGetWidgetNativeData(WindowsHandle* aValue) override;
 
   virtual bool RecvSetNativeChildOfShareableWindow(const uintptr_t& childWindow) override;
 
   virtual bool RecvDispatchFocusToTopLevelWindow() override;
 
-  virtual bool RecvZoomToRect(const uint32_t& aPresShellId,
-                              const ViewID& aViewId,
-                              const CSSRect& aRect,
-                              const uint32_t& aFlags) override;
-
-  virtual bool
-  RecvUpdateZoomConstraints(const uint32_t& aPresShellId,
-                            const ViewID& aViewId,
-                            const MaybeZoomConstraints& aConstraints) override;
-
   virtual bool RecvRespondStartSwipeEvent(const uint64_t& aInputBlockId,
                                           const bool& aStartSwipe) override;
 
   virtual bool
-  RecvContentReceivedInputBlock(const ScrollableLayerGuid& aGuid,
-                                const uint64_t& aInputBlockId,
-                                const bool& aPreventDefault) override;
-
-  virtual bool RecvSetTargetAPZC(const uint64_t& aInputBlockId,
-                                 nsTArray<ScrollableLayerGuid>&& aTargets) override;
-
-  virtual bool
-  RecvSetAllowedTouchBehavior(const uint64_t& aInputBlockId,
-                              nsTArray<TouchBehaviorFlags>&& aTargets) override;
-
-  virtual bool
   RecvDispatchWheelEvent(const mozilla::WidgetWheelEvent& aEvent) override;
 
   virtual bool
   RecvDispatchMouseEvent(const mozilla::WidgetMouseEvent& aEvent) override;
 
   virtual bool
   RecvDispatchKeyboardEvent(const mozilla::WidgetKeyboardEvent& aEvent) override;
 
-  virtual bool
-  RecvStartScrollbarDrag(const AsyncDragMetrics& aDragMetrics) override;
-
   virtual PColorPickerParent*
   AllocPColorPickerParent(const nsString& aTitle,
                           const nsString& aInitialColor) override;
 
   virtual bool
   DeallocPColorPickerParent(PColorPickerParent* aColorPicker) override;
 
   virtual PDocAccessibleParent*
@@ -360,54 +332,24 @@ public:
 
   // XXX/cjones: it's not clear what we gain by hiding these
   // message-sending functions under a layer of indirection and
   // eating the return values
   void Show(const ScreenIntSize& aSize, bool aParentIsActive);
 
   void UpdateDimensions(const nsIntRect& aRect, const ScreenIntSize& aSize);
 
-  void UpdateFrame(const layers::FrameMetrics& aFrameMetrics);
-
   void UIResolutionChanged();
 
   void ThemeChanged();
 
   void HandleAccessKey(nsTArray<uint32_t>& aCharCodes,
                        const bool& aIsTrusted,
                        const int32_t& aModifierMask);
 
-  void RequestFlingSnap(const FrameMetrics::ViewID& aScrollId,
-                        const mozilla::CSSPoint& aDestination);
-
-  void AcknowledgeScrollUpdate(const ViewID& aScrollId,
-                               const uint32_t& aScrollGeneration);
-
-  void HandleDoubleTap(const CSSPoint& aPoint,
-                       Modifiers aModifiers,
-                       const ScrollableLayerGuid& aGuid);
-
-  void HandleSingleTap(const CSSPoint& aPoint,
-                       Modifiers aModifiers,
-                       const ScrollableLayerGuid& aGuid);
-
-  void HandleLongTap(const CSSPoint& aPoint,
-                     Modifiers aModifiers,
-                     const ScrollableLayerGuid& aGuid,
-                     uint64_t aInputBlockId);
-
-  void NotifyAPZStateChange(ViewID aViewId,
-                            APZStateChange aChange,
-                            int aArg);
-
-  void NotifyMouseScrollTestEvent(const ViewID& aScrollId,
-                                  const nsString& aEvent);
-
-  void NotifyFlushComplete();
-
   void Activate();
 
   void Deactivate();
 
   bool MapEventCoordinatesForChildProcess(mozilla::WidgetEvent* aEvent);
 
   void MapEventCoordinatesForChildProcess(const LayoutDeviceIntPoint& aOffset,
                                           mozilla::WidgetEvent* aEvent);
@@ -477,29 +419,16 @@ public:
                          uint32_t aDropEffect);
 
   bool SendMouseWheelEvent(mozilla::WidgetWheelEvent& event);
 
   bool SendRealKeyEvent(mozilla::WidgetKeyboardEvent& event);
 
   bool SendRealTouchEvent(WidgetTouchEvent& event);
 
-  bool SendHandleSingleTap(const CSSPoint& aPoint,
-                           const Modifiers& aModifiers,
-                           const ScrollableLayerGuid& aGuid);
-
-  bool SendHandleLongTap(const CSSPoint& aPoint,
-                         const Modifiers& aModifiers,
-                         const ScrollableLayerGuid& aGuid,
-                         const uint64_t& aInputBlockId);
-
-  bool SendHandleDoubleTap(const CSSPoint& aPoint,
-                           const Modifiers& aModifiers,
-                           const ScrollableLayerGuid& aGuid);
-
   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/layers/apz/public/GeckoContentController.h
+++ b/gfx/layers/apz/public/GeckoContentController.h
@@ -7,26 +7,32 @@
 #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"
 
 class Task;
 
 namespace mozilla {
 namespace layers {
 
 class GeckoContentController
 {
 public:
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GeckoContentController)
+  /**
+   * 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)
 
   /**
    * 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;
 
@@ -83,16 +89,17 @@ public:
 
   /**
    * 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
    * APZ can then get the correct touch-sensitive region for each frame
    * directly from the layer.
    */
   virtual bool GetTouchSensitiveRegion(CSSRect* aOutRegion)
   {
     return false;
   }
@@ -143,16 +150,20 @@ public:
    * Notify content that the repaint requests have been flushed.
    */
   virtual void NotifyFlushComplete() = 0;
 
   virtual void UpdateOverscrollVelocity(const float aX, const float aY) {}
   virtual void UpdateOverscrollOffset(const float aX,const  float aY) {}
 
   GeckoContentController() {}
+  virtual void ChildAdopted() {}
+  /**
+   * Needs to be called on the main thread.
+   */
   virtual void Destroy() {}
 
 protected:
   // Protected destructor, to discourage deletion outside of Release():
   virtual ~GeckoContentController() {}
 };
 
 } // namespace layers
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/APZChild.cpp
@@ -0,0 +1,179 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=4 ts=8 et 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/. */
+
+#include "mozilla/layers/APZChild.h"
+
+#include "mozilla/dom/TabChild.h"
+#include "mozilla/layers/APZCCallbackHelper.h"
+
+namespace mozilla {
+namespace layers {
+
+/**
+ * There are cases where we try to create the APZChild before the corresponding
+ * TabChild has been created, we use an observer for the "tab-child-created"
+ * topic to set the TabChild in the APZChild when it has been created.
+ */
+class TabChildCreatedObserver : public nsIObserver
+{
+public:
+  TabChildCreatedObserver(APZChild* aAPZChild, const dom::TabId& aTabId)
+    : mAPZChild(aAPZChild),
+      mTabId(aTabId)
+  {}
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIOBSERVER
+
+private:
+  virtual ~TabChildCreatedObserver()
+  {}
+
+  // TabChildCreatedObserver is owned by mAPZChild, and mAPZChild outlives its
+  // TabChildCreatedObserver, so the raw pointer is fine.
+  APZChild* mAPZChild;
+  dom::TabId mTabId;
+};
+
+NS_IMPL_ISUPPORTS(TabChildCreatedObserver, nsIObserver)
+
+NS_IMETHODIMP
+TabChildCreatedObserver::Observe(nsISupports* aSubject,
+                                 const char* aTopic,
+                                 const char16_t* aData)
+{
+  MOZ_ASSERT(strcmp(aTopic, "tab-child-created") == 0);
+
+  nsCOMPtr<nsITabChild> tabChild(do_QueryInterface(aSubject));
+  NS_ENSURE_TRUE(tabChild, NS_ERROR_FAILURE);
+
+  dom::TabChild* browser = static_cast<dom::TabChild*>(tabChild.get());
+  if (browser->GetTabId() == mTabId) {
+    mAPZChild->SetBrowser(browser);
+  }
+  return NS_OK;
+}
+
+APZChild*
+APZChild::Create(const dom::TabId& aTabId)
+{
+  RefPtr<dom::TabChild> browser = dom::TabChild::FindTabChild(aTabId);
+  nsAutoPtr<APZChild> apz(new APZChild);
+  if (browser) {
+    apz->SetBrowser(browser);
+  } else {
+    RefPtr<TabChildCreatedObserver> observer =
+      new TabChildCreatedObserver(apz, aTabId);
+    nsCOMPtr<nsIObserverService> os = services::GetObserverService();
+    if (!os ||
+        NS_FAILED(os->AddObserver(observer, "tab-child-created", false))) {
+      return nullptr;
+    }
+    apz->SetObserver(observer);
+  }
+
+  return apz.forget();
+}
+
+APZChild::~APZChild()
+{
+  if (mObserver) {
+    nsCOMPtr<nsIObserverService> os = services::GetObserverService();
+    os->RemoveObserver(mObserver, "tab-child-created");
+  } else {
+    mBrowser->SetAPZChild(nullptr);
+  }
+}
+
+bool
+APZChild::RecvUpdateFrame(const FrameMetrics& aFrameMetrics)
+{
+  return mBrowser->UpdateFrame(aFrameMetrics);
+}
+
+bool
+APZChild::RecvRequestFlingSnap(const FrameMetrics::ViewID& aScrollId,
+                               const mozilla::CSSPoint& aDestination)
+{
+  APZCCallbackHelper::RequestFlingSnap(aScrollId, aDestination);
+  return true;
+}
+
+bool
+APZChild::RecvAcknowledgeScrollUpdate(const ViewID& aScrollId,
+                                      const uint32_t& aScrollGeneration)
+{
+  APZCCallbackHelper::AcknowledgeScrollUpdate(aScrollId, aScrollGeneration);
+  return true;
+}
+
+bool
+APZChild::RecvHandleDoubleTap(const CSSPoint& aPoint,
+                              const Modifiers& aModifiers,
+                              const ScrollableLayerGuid& aGuid)
+{
+  mBrowser->HandleDoubleTap(aPoint, aModifiers, aGuid);
+  return true;
+}
+
+bool
+APZChild::RecvHandleSingleTap(const CSSPoint& aPoint,
+                              const Modifiers& aModifiers,
+                              const ScrollableLayerGuid& aGuid,
+                              const bool& aCallTakeFocusForClickFromTap)
+{
+  mBrowser->HandleSingleTap(aPoint, aModifiers, aGuid,
+                            aCallTakeFocusForClickFromTap);
+  return true;
+}
+
+bool
+APZChild::RecvHandleLongTap(const CSSPoint& aPoint,
+                            const Modifiers& aModifiers,
+                            const ScrollableLayerGuid& aGuid,
+                            const uint64_t& aInputBlockId)
+{
+  mBrowser->HandleLongTap(aPoint, aModifiers, aGuid, aInputBlockId);
+  return true;
+}
+
+bool
+APZChild::RecvNotifyAPZStateChange(const ViewID& aViewId,
+                                   const APZStateChange& aChange,
+                                   const int& aArg)
+{
+  return mBrowser->NotifyAPZStateChange(aViewId, aChange, aArg);
+}
+
+bool
+APZChild::RecvNotifyFlushComplete()
+{
+  APZCCallbackHelper::NotifyFlushComplete();
+  return true;
+}
+
+void
+APZChild::SetObserver(nsIObserver* aObserver)
+{
+  MOZ_ASSERT(!mBrowser);
+  mObserver = aObserver;
+}
+
+void
+APZChild::SetBrowser(dom::TabChild* aBrowser)
+{
+  MOZ_ASSERT(!mBrowser);
+  if (mObserver) {
+    nsCOMPtr<nsIObserverService> os = services::GetObserverService();
+    os->RemoveObserver(mObserver, "tab-child-created");
+    mObserver = nullptr;
+  }
+  mBrowser = aBrowser;
+  mBrowser->SetAPZChild(this);
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/APZChild.h
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=4 ts=8 et 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_APZChild_h
+#define mozilla_layers_APZChild_h
+
+#include "mozilla/layers/PAPZChild.h"
+
+class nsIObserver;
+
+namespace mozilla {
+
+namespace dom {
+class TabChild;
+} // namespace dom
+
+namespace layers {
+
+class APZChild final : public PAPZChild
+{
+public:
+  static APZChild* Create(const dom::TabId& aTabId);
+
+  ~APZChild();
+
+  virtual bool RecvUpdateFrame(const FrameMetrics& frame) override;
+
+  virtual bool RecvRequestFlingSnap(const ViewID& aScrollID,
+                                    const CSSPoint& aDestination) override;
+
+  virtual bool RecvAcknowledgeScrollUpdate(const ViewID& aScrollId,
+                                           const uint32_t& aScrollGeneration) override;
+
+  virtual bool RecvHandleDoubleTap(const CSSPoint& aPoint,
+                                   const Modifiers& aModifiers,
+                                   const ScrollableLayerGuid& aGuid) override;
+
+  virtual bool RecvHandleSingleTap(const CSSPoint& aPoint,
+                                   const Modifiers& aModifiers,
+                                   const ScrollableLayerGuid& aGuid,
+                                   const bool& aCallTakeFocusForClickFromTap) override;
+
+  virtual bool RecvHandleLongTap(const CSSPoint& aPoint,
+                                 const Modifiers& aModifiers,
+                                 const ScrollableLayerGuid& aGuid,
+                                 const uint64_t& aInputBlockId) override;
+
+  virtual bool RecvNotifyAPZStateChange(const ViewID& aViewId,
+                                        const APZStateChange& aChange,
+                                        const int& aArg) override;
+
+  virtual bool RecvNotifyFlushComplete() override;
+
+  void SetBrowser(dom::TabChild* aBrowser);
+
+private:
+  APZChild() {};
+
+  void SetObserver(nsIObserver* aObserver);
+
+  RefPtr<dom::TabChild> mBrowser;
+  RefPtr<nsIObserver> mObserver;
+};
+
+} // namespace layers
+
+} // namespace mozilla
+
+#endif // mozilla_layers_APZChild_h
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -20,16 +20,17 @@
 #include "gfxPlatform.h"                // for gfxPlatform
 #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/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/APZThreadUtils.h"  // for APZCTreeManager
 #include "mozilla/layers/AsyncCompositionManager.h"
@@ -38,17 +39,19 @@
 #include "mozilla/layers/CompositorLRU.h"  // for CompositorLRU
 #include "mozilla/layers/CompositorOGL.h"  // for CompositorOGL
 #include "mozilla/layers/CompositorTypes.h"
 #include "mozilla/layers/FrameUniformityData.h"
 #include "mozilla/layers/ImageBridgeParent.h"
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "mozilla/layers/LayersTypes.h"
 #include "mozilla/layers/PLayerTransactionParent.h"
+#include "mozilla/layers/RemoteContentController.h"
 #include "mozilla/layers/ShadowLayersManager.h" // for ShadowLayersManager
+#include "mozilla/layout/RenderFrameParent.h"
 #include "mozilla/media/MediaSystemResourceService.h" // for MediaSystemResourceService
 #include "mozilla/mozalloc.h"           // for operator new, etc
 #include "mozilla/Telemetry.h"
 #ifdef MOZ_WIDGET_GTK
 #include "basic/X11BasicCompositor.h" // for X11BasicCompositor
 #endif
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_ASSERTION, etc
@@ -73,16 +76,20 @@
 #endif
 #include "mozilla/VsyncDispatcher.h"
 
 #ifdef MOZ_WIDGET_GONK
 #include "GeckoTouchDispatcher.h"
 #include "nsScreenManagerGonk.h"
 #endif
 
+#ifdef MOZ_ANDROID_APZ
+#include "AndroidBridge.h"
+#endif
+
 #include "LayerScope.h"
 
 namespace mozilla {
 
 namespace gfx {
 // See VRManagerChild.cpp
 void ReleaseVRManagerParentSingleton();
 } // namespace gfx
@@ -1649,33 +1656,67 @@ bool
 CompositorParent::RecvNotifyChildCreated(const uint64_t& child)
 {
   MonitorAutoLock lock(*sIndirectLayerTreesLock);
   NotifyChildCreated(child);
   return true;
 }
 
 void
-CompositorParent::NotifyChildCreated(const uint64_t& aChild)
+CompositorParent::NotifyChildCreated(uint64_t aChild)
 {
   sIndirectLayerTreesLock->AssertCurrentThreadOwns();
   sIndirectLayerTrees[aChild].mParent = this;
   sIndirectLayerTrees[aChild].mLayerManager = mLayerManager;
 }
 
+/* static */ bool
+CompositorParent::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
 CompositorParent::RecvAdoptChild(const uint64_t& child)
 {
-  MonitorAutoLock lock(*sIndirectLayerTreesLock);
-  NotifyChildCreated(child);
-  if (sIndirectLayerTrees[child].mLayerTree) {
-    sIndirectLayerTrees[child].mLayerTree->mLayerManager = mLayerManager;
+  RefPtr<GeckoContentController> controller;
+  {
+    MonitorAutoLock lock(*sIndirectLayerTreesLock);
+    NotifyChildCreated(child);
+    if (sIndirectLayerTrees[child].mLayerTree) {
+      sIndirectLayerTrees[child].mLayerTree->mLayerManager = mLayerManager;
+    }
+    if (sIndirectLayerTrees[child].mRoot) {
+      sIndirectLayerTrees[child].mRoot->AsLayerComposite()->SetLayerManager(mLayerManager);
+    }
+    controller = sIndirectLayerTrees[child].mController;
   }
-  if (sIndirectLayerTrees[child].mRoot) {
-    sIndirectLayerTrees[child].mRoot->AsLayerComposite()->SetLayerManager(mLayerManager);
+
+  // Calling ChildAdopted on controller will acquire a lock, to avoid a
+  // potential deadlock between that lock and sIndirectLayerTreesLock we
+  // release sIndirectLayerTreesLock first before calling ChildAdopted.
+  if (mApzcTreeManager && controller) {
+    controller->ChildAdopted();
   }
   return true;
 }
 
 /*static*/ uint64_t
 CompositorParent::AllocateLayerTreeId()
 {
   MOZ_ASSERT(CompositorLoop());
--- a/gfx/layers/ipc/CompositorParent.h
+++ b/gfx/layers/ipc/CompositorParent.h
@@ -20,16 +20,17 @@
 #include "base/basictypes.h"            // for DISALLOW_EVIL_CONSTRUCTORS
 #include "base/platform_thread.h"       // for PlatformThreadId
 #include "base/thread.h"                // for Thread
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT_HELPER2
 #include "mozilla/Attributes.h"         // for override
 #include "mozilla/Monitor.h"            // for Monitor
 #include "mozilla/RefPtr.h"             // for RefPtr
 #include "mozilla/TimeStamp.h"          // for TimeStamp
+#include "mozilla/dom/ipc/IdType.h"
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/ipc/ProtocolUtils.h"
 #include "mozilla/layers/GeckoContentController.h"
 #include "mozilla/layers/LayersMessages.h"  // for TargetConfig
 #include "mozilla/layers/PCompositorParent.h"
 #include "mozilla/layers/ShadowLayersManager.h" // for ShadowLayersManager
 #include "mozilla/layers/APZTestData.h"
 #include "nsAutoPtr.h"                  // for nsRefPtr
@@ -49,16 +50,17 @@ class DrawTarget;
 namespace layers {
 
 class APZCTreeManager;
 class AsyncCompositionManager;
 class Compositor;
 class CompositorParent;
 class LayerManagerComposite;
 class LayerTransactionParent;
+class PAPZParent;
 
 struct ScopedLayerTreeRegistration
 {
   ScopedLayerTreeRegistration(APZCTreeManager* aApzctm,
                               uint64_t aLayersId,
                               Layer* aRoot,
                               GeckoContentController* aController);
   ~ScopedLayerTreeRegistration();
@@ -278,17 +280,17 @@ public:
    * The information refresh happens because the compositor will call
    * SetFirstPaintViewport on the next frame of composition.
    */
   void ForceIsFirstPaint();
   void Destroy();
 
   static void SetShadowProperties(Layer* aLayer);
 
-  void NotifyChildCreated(const uint64_t& aChild);
+  void NotifyChildCreated(uint64_t aChild);
 
   void AsyncRender();
 
   // Can be called from any thread
   void ScheduleRenderOnCompositorThread();
   void SchedulePauseOnCompositorThread();
   void InvalidateOnCompositorThread();
   /**
@@ -442,16 +444,30 @@ public:
    * Returns true if the calling thread is the compositor thread.
    */
   static bool IsInCompositorThread();
 
   nsIWidget* GetWidget() { return mWidget; }
 
   void ForceComposeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr);
 
+  /**
+   * 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 ~CompositorParent();
 
   void DeferredDestroy();
 
   virtual PLayerTransactionParent*
     AllocPLayerTransactionParent(const nsTArray<LayersBackend>& aBackendHints,
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/PAPZ.ipdl
@@ -0,0 +1,104 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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;
+
+using mozilla::CSSPoint 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::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 {
+
+
+/**
+ * If APZ is enabled then one PAPZ will be opened per PBrowser between the
+ * process where the PBrowser child actor lives and the main process (the
+ * 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;
+
+parent:
+  async UpdateHitRegion(nsRegion aRegion);
+
+  /**
+   * Instructs the TabParent to forward a request to zoom to a rect given in
+   * CSS pixels. This rect is relative to the document.
+   */
+  async ZoomToRect(uint32_t aPresShellId, ViewID aViewId, CSSRect aRect, uint32_t aFlags);
+
+  /**
+   * We know for sure that content has either preventDefaulted or not
+   * preventDefaulted. This applies to an entire batch of touch events. It is
+   * expected that, if there are any DOM touch listeners, touch events will be
+   * batched and only processed for panning and zooming if content does not
+   * preventDefault.
+   */
+  async ContentReceivedInputBlock(ScrollableLayerGuid aGuid, uint64_t aInputBlockId, bool aPreventDefault);
+
+  /**
+   * Notifies the APZ code of the results of the gecko hit-test for a
+   * particular input block. Each target corresponds to one touch point in the
+   * touch event.
+   */
+  async SetTargetAPZC(uint64_t aInputBlockId, ScrollableLayerGuid[] aTargets);
+
+  // Start an APZ drag on a scrollbar
+  async StartScrollbarDrag(AsyncDragMetrics aDragMetrics);
+
+  /**
+   * Notifies the APZ code of the allowed touch-behaviours for a particular
+   * input block. Each item in the aFlags array corresponds to one touch point
+   * in the touch event.
+   */
+  async SetAllowedTouchBehavior(uint64_t aInputBlockId, TouchBehaviorFlags[] aFlags);
+
+  /**
+   * Updates the zoom constraints for a scrollable frame in this tab.
+   * The zoom controller code lives on the parent side and so this allows it to
+   * have up-to-date zoom constraints.
+   */
+  async UpdateZoomConstraints(uint32_t aPresShellId, ViewID aViewId,
+                              MaybeZoomConstraints aConstraints);
+
+child:
+  async UpdateFrame(FrameMetrics frame);
+
+  // The following methods correspond to functions on the GeckoContentController
+  // interface in gfx/layers/apz/public/GeckoContentController.h. Refer to documentation
+  // in that file for these functions.
+  async RequestFlingSnap(ViewID aScrollID, CSSPoint aDestination);
+  async AcknowledgeScrollUpdate(ViewID aScrollId, uint32_t aScrollGeneration);
+  async HandleDoubleTap(CSSPoint aPoint, Modifiers aModifiers, ScrollableLayerGuid aGuid);
+  async HandleSingleTap(CSSPoint aPoint, Modifiers aModifiers, ScrollableLayerGuid aGuid, bool aCallTakeFocusForClickFromTap);
+  async HandleLongTap(CSSPoint point, Modifiers aModifiers, ScrollableLayerGuid aGuid, uint64_t aInputBlockId);
+  async NotifyAPZStateChange(ViewID aViewId, APZStateChange aChange, int aArg);
+  async NotifyFlushComplete();
+
+  async __delete__();
+};
+
+} // layers
+} // mozilla
--- a/gfx/layers/ipc/PCompositor.ipdl
+++ b/gfx/layers/ipc/PCompositor.ipdl
@@ -2,26 +2,28 @@
  * 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 LayersSurfaces;
 include LayersMessages;
+include protocol PBrowser;
 include protocol PLayer;
 include protocol PLayerTransaction;
 include "mozilla/GfxMessageUtils.h";
-include "nsRegion.h";
 
 using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
 using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h";
 using struct mozilla::layers::FrameMetrics from "FrameMetrics.h";
 using mozilla::layers::FrameMetrics::ViewID from "FrameMetrics.h";
+using mozilla::layers::MaybeZoomConstraints from "FrameMetrics.h";
 using mozilla::layers::LayersBackend from "mozilla/layers/LayersTypes.h";
+using mozilla::layers::TouchBehaviorFlags from "mozilla/layers/APZUtils.h";
 using mozilla::CrossProcessMutexHandle from "mozilla/ipc/CrossProcessMutex.h";
 using mozilla::ipc::SharedMemoryBasic::Handle from "mozilla/ipc/SharedMemoryBasic.h";
 using mozilla::LayoutDeviceIntPoint from "Units.h";
 using mozilla::LayoutDeviceIntRegion from "Units.h";
 using class mozilla::TimeStamp from "mozilla/TimeStamp.h";
 using class mozilla::layers::FrameUniformityData from "mozilla/layers/FrameUniformityData.h";
 
 namespace mozilla {
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/RemoteContentController.cpp
@@ -0,0 +1,384 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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/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/APZCTreeManager.h"
+#include "mozilla/layers/APZThreadUtils.h"
+#include "mozilla/layers/CompositorParent.h"
+#include "mozilla/layout/RenderFrameParent.h"
+#include "mozilla/unused.h"
+#include "Units.h"
+#ifdef MOZ_WIDGET_ANDROID
+#include "AndroidBridge.h"
+#endif
+
+namespace mozilla {
+namespace layers {
+
+RemoteContentController::RemoteContentController(uint64_t aLayersId,
+                                                 dom::TabParent* aBrowserParent)
+  : mUILoop(MessageLoop::current())
+  , mLayersId(aLayersId)
+  , mBrowserParent(aBrowserParent)
+  , mMutex("RemoteContentController")
+{
+  MOZ_ASSERT(NS_IsMainThread());
+}
+
+RemoteContentController::~RemoteContentController()
+{
+  if (mBrowserParent) {
+    Unused << PAPZParent::Send__delete__(this);
+  }
+}
+
+void
+RemoteContentController::RequestContentRepaint(const FrameMetrics& aFrameMetrics)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  if (CanSend()) {
+    Unused << SendUpdateFrame(aFrameMetrics);
+  }
+}
+
+void
+RemoteContentController::RequestFlingSnap(const FrameMetrics::ViewID& aScrollId,
+                                          const mozilla::CSSPoint& aDestination)
+{
+  if (MessageLoop::current() != mUILoop) {
+    // We have to send this message from the "UI thread" (main
+    // thread).
+    mUILoop->PostTask(
+      FROM_HERE,
+      NewRunnableMethod(this, &RemoteContentController::RequestFlingSnap,
+                        aScrollId, aDestination));
+    return;
+  }
+  if (CanSend()) {
+    Unused << SendRequestFlingSnap(aScrollId, aDestination);
+  }
+}
+
+void
+RemoteContentController::AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
+                                                 const uint32_t& aScrollGeneration)
+{
+  if (MessageLoop::current() != mUILoop) {
+    // We have to send this message from the "UI thread" (main
+    // thread).
+    mUILoop->PostTask(
+      FROM_HERE,
+      NewRunnableMethod(this, &RemoteContentController::AcknowledgeScrollUpdate,
+                        aScrollId, aScrollGeneration));
+    return;
+  }
+  if (CanSend()) {
+    Unused << SendAcknowledgeScrollUpdate(aScrollId, aScrollGeneration);
+  }
+}
+
+void
+RemoteContentController::HandleDoubleTap(const CSSPoint& aPoint,
+                                         Modifiers aModifiers,
+                                         const ScrollableLayerGuid& aGuid)
+{
+  if (MessageLoop::current() != mUILoop) {
+    // We have to send this message from the "UI thread" (main
+    // thread).
+    mUILoop->PostTask(
+      FROM_HERE,
+      NewRunnableMethod(this, &RemoteContentController::HandleDoubleTap,
+                        aPoint, aModifiers, aGuid));
+    return;
+  }
+  if (CanSend()) {
+    Unused << SendHandleDoubleTap(aPoint, aModifiers, aGuid);
+  }
+}
+
+void
+RemoteContentController::HandleSingleTap(const CSSPoint& aPoint,
+                                         Modifiers aModifiers,
+                                         const ScrollableLayerGuid& aGuid)
+{
+  if (MessageLoop::current() != mUILoop) {
+    // We have to send this message from the "UI thread" (main
+    // thread).
+    mUILoop->PostTask(
+      FROM_HERE,
+      NewRunnableMethod(this, &RemoteContentController::HandleSingleTap,
+                        aPoint, aModifiers, aGuid));
+    return;
+  }
+
+  bool callTakeFocusForClickFromTap;
+  layout::RenderFrameParent* frame;
+  if (mBrowserParent && (frame = mBrowserParent->GetRenderFrame()) &&
+      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;
+  } else {
+    callTakeFocusForClickFromTap = true;
+  }
+
+  if (CanSend()) {
+    Unused << SendHandleSingleTap(aPoint, aModifiers, aGuid,
+                                  callTakeFocusForClickFromTap);
+  }
+}
+
+void
+RemoteContentController::HandleLongTap(const CSSPoint& 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(
+      FROM_HERE,
+      NewRunnableMethod(this, &RemoteContentController::HandleLongTap,
+                        aPoint, aModifiers, aGuid, aInputBlockId));
+    return;
+  }
+  if (CanSend()) {
+    Unused << SendHandleLongTap(aPoint, aModifiers, aGuid, aInputBlockId);
+  }
+}
+
+void
+RemoteContentController::PostDelayedTask(Task* aTask, int aDelayMs)
+{
+#ifdef MOZ_ANDROID_APZ
+  AndroidBridge::Bridge()->PostTaskToUiThread(aTask, aDelayMs);
+#else
+  (MessageLoop::current() ? MessageLoop::current() : mUILoop)->
+     PostDelayedTask(FROM_HERE, aTask, aDelayMs);
+#endif
+}
+
+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(
+      FROM_HERE,
+      NewRunnableMethod(this, &RemoteContentController::NotifyAPZStateChange,
+                        aGuid, aChange, aArg));
+    return;
+  }
+  if (CanSend()) {
+    Unused << SendNotifyAPZStateChange(aGuid.mScrollId, aChange, aArg);
+  }
+}
+
+void
+RemoteContentController::NotifyMozMouseScrollEvent(const FrameMetrics::ViewID& aScrollId,
+                                                   const nsString& aEvent)
+{
+  if (MessageLoop::current() != mUILoop) {
+    mUILoop->PostTask(
+      FROM_HERE,
+      NewRunnableMethod(this, &RemoteContentController::NotifyMozMouseScrollEvent,
+                        aScrollId, aEvent));
+    return;
+  }
+
+  if (mBrowserParent) {
+    Unused << mBrowserParent->SendMouseScrollTestEvent(mLayersId, aScrollId, aEvent);
+  }
+}
+
+void
+RemoteContentController::NotifyFlushComplete()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  if (CanSend()) {
+    Unused << SendNotifyFlushComplete();
+  }
+}
+
+bool
+RemoteContentController::RecvUpdateHitRegion(const nsRegion& aRegion)
+{
+  MutexAutoLock lock(mMutex);
+  mTouchSensitiveRegion = aRegion;
+  return true;
+}
+
+bool
+RemoteContentController::RecvZoomToRect(const uint32_t& aPresShellId,
+                                        const ViewID& aViewId,
+                                        const CSSRect& aRect,
+                                        const uint32_t& aFlags)
+{
+  if (RefPtr<APZCTreeManager> apzcTreeManager = GetApzcTreeManager()) {
+    apzcTreeManager->ZoomToRect(ScrollableLayerGuid(mLayersId, aPresShellId, aViewId),
+                                aRect, aFlags);
+  }
+  return true;
+}
+
+bool
+RemoteContentController::RecvContentReceivedInputBlock(const ScrollableLayerGuid& aGuid,
+                                                       const uint64_t& aInputBlockId,
+                                                       const bool& aPreventDefault)
+{
+  if (aGuid.mLayersId != mLayersId) {
+    // Guard against bad data from hijacked child processes
+    NS_ERROR("Unexpected layers id in RecvContentReceivedInputBlock; dropping message...");
+    return false;
+  }
+  if (RefPtr<APZCTreeManager> apzcTreeManager = GetApzcTreeManager()) {
+    APZThreadUtils::RunOnControllerThread(NewRunnableMethod(
+        apzcTreeManager.get(), &APZCTreeManager::ContentReceivedInputBlock,
+        aInputBlockId, aPreventDefault));
+  }
+  return true;
+}
+
+bool
+RemoteContentController::RecvStartScrollbarDrag(const AsyncDragMetrics& aDragMetrics)
+{
+  if (RefPtr<APZCTreeManager> apzcTreeManager = GetApzcTreeManager()) {
+    ScrollableLayerGuid guid(mLayersId, aDragMetrics.mPresShellId,
+                             aDragMetrics.mViewId);
+
+    APZThreadUtils::RunOnControllerThread(
+      NewRunnableMethod(apzcTreeManager.get(),
+                        &APZCTreeManager::StartScrollbarDrag,
+                        guid, aDragMetrics));
+  }
+  return true;
+}
+
+bool
+RemoteContentController::RecvSetTargetAPZC(const uint64_t& aInputBlockId,
+                                           nsTArray<ScrollableLayerGuid>&& aTargets)
+{
+  for (size_t i = 0; i < aTargets.Length(); i++) {
+    if (aTargets[i].mLayersId != mLayersId) {
+      // Guard against bad data from hijacked child processes
+      NS_ERROR("Unexpected layers id in SetTargetAPZC; dropping message...");
+      return false;
+    }
+  }
+  if (RefPtr<APZCTreeManager> apzcTreeManager = GetApzcTreeManager()) {
+    // need a local var to disambiguate between the SetTargetAPZC overloads.
+    void (APZCTreeManager::*setTargetApzcFunc)(uint64_t, const nsTArray<ScrollableLayerGuid>&)
+        = &APZCTreeManager::SetTargetAPZC;
+    APZThreadUtils::RunOnControllerThread(NewRunnableMethod(
+        apzcTreeManager.get(), setTargetApzcFunc,
+        aInputBlockId, aTargets));
+  }
+  return true;
+}
+
+bool
+RemoteContentController::RecvSetAllowedTouchBehavior(const uint64_t& aInputBlockId,
+                                                     nsTArray<TouchBehaviorFlags>&& aFlags)
+{
+  if (RefPtr<APZCTreeManager> apzcTreeManager = GetApzcTreeManager()) {
+    APZThreadUtils::RunOnControllerThread(NewRunnableMethod(
+        apzcTreeManager.get(), &APZCTreeManager::SetAllowedTouchBehavior,
+        aInputBlockId, Move(aFlags)));
+  }
+  return true;
+}
+
+bool
+RemoteContentController::RecvUpdateZoomConstraints(const uint32_t& aPresShellId,
+                                                   const ViewID& aViewId,
+                                                   const MaybeZoomConstraints& aConstraints)
+{
+  if (RefPtr<APZCTreeManager> apzcTreeManager = GetApzcTreeManager()) {
+    apzcTreeManager->UpdateZoomConstraints(ScrollableLayerGuid(mLayersId, aPresShellId, aViewId),
+                                           aConstraints);
+  }
+  return true;
+}
+
+void
+RemoteContentController::ActorDestroy(ActorDestroyReason aWhy)
+{
+  {
+    MutexAutoLock lock(mMutex);
+    mApzcTreeManager = nullptr;
+  }
+  mBrowserParent = nullptr;
+}
+
+// TODO: Remove once upgraded to GCC 4.8+ on linux. Calling a static member
+//       function (like PAPZParent::Send__delete__) in a lambda leads to a bogus
+//       error: "'this' was not captured for this lambda function".
+//
+//       (see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51494)
+static void
+DeletePAPZParent(PAPZParent* aPAPZ)
+{
+  Unused << PAPZParent::Send__delete__(aPAPZ);
+}
+
+void
+RemoteContentController::Destroy()
+{
+  RefPtr<RemoteContentController> controller = this;
+  NS_DispatchToMainThread(NS_NewRunnableFunction([controller] {
+    if (controller->CanSend()) {
+      DeletePAPZParent(controller);
+    }
+  }));
+}
+
+void
+RemoteContentController::ChildAdopted()
+{
+  // Clear the cached APZCTreeManager.
+  MutexAutoLock lock(mMutex);
+  mApzcTreeManager = nullptr;
+}
+
+already_AddRefed<APZCTreeManager>
+RemoteContentController::GetApzcTreeManager()
+{
+  // We can't get a ref to the APZCTreeManager until after the child is
+  // created and the static getter knows which CompositorParent is
+  // instantiated with this layers ID. That's why try to fetch it when
+  // we first need it and cache the result.
+  MutexAutoLock lock(mMutex);
+  if (!mApzcTreeManager) {
+    mApzcTreeManager = CompositorParent::GetAPZCTreeManager(mLayersId);
+  }
+  RefPtr<APZCTreeManager> apzcTreeManager(mApzcTreeManager);
+  return apzcTreeManager.forget();
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/RemoteContentController.h
@@ -0,0 +1,130 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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/. */
+
+#ifndef mozilla_layers_RemoteContentController_h
+#define mozilla_layers_RemoteContentController_h
+
+#include "mozilla/layers/GeckoContentController.h"
+#include "mozilla/layers/PAPZParent.h"
+
+namespace mozilla {
+
+namespace dom {
+class TabParent;
+}
+
+namespace layers {
+
+class APZCTreeManager;
+
+/**
+ * RemoteContentController uses the PAPZ protocol to implement a
+ * GeckoContentController for a browser living in a remote process.
+ * Most of the member functions can be called on any thread, exceptions are
+ * annotated in comments. The PAPZ protocol runs on the main thread (so all the
+ * Recv* member functions do too).
+ */
+class RemoteContentController : public GeckoContentController
+                              , public PAPZParent
+{
+  using GeckoContentController::APZStateChange;
+
+public:
+  explicit RemoteContentController(uint64_t aLayersId,
+                                   dom::TabParent* aBrowserParent);
+
+  virtual ~RemoteContentController();
+
+  // Needs to be called on the main thread.
+  virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) override;
+
+  virtual void RequestFlingSnap(const FrameMetrics::ViewID& aScrollId,
+                                const mozilla::CSSPoint& aDestination) override;
+
+  virtual void AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
+                                       const uint32_t& aScrollGeneration) override;
+
+  virtual void HandleDoubleTap(const CSSPoint& aPoint,
+                               Modifiers aModifiers,
+                               const ScrollableLayerGuid& aGuid) override;
+
+  virtual void HandleSingleTap(const CSSPoint& aPoint,
+                               Modifiers aModifiers,
+                               const ScrollableLayerGuid& aGuid) override;
+
+  virtual void HandleLongTap(const CSSPoint& aPoint,
+                             Modifiers aModifiers,
+                             const ScrollableLayerGuid& aGuid,
+                             uint64_t aInputBlockId) override;
+
+  virtual void PostDelayedTask(Task* aTask, int aDelayMs) 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 bool RecvZoomToRect(const uint32_t& aPresShellId,
+                              const ViewID& aViewId,
+                              const CSSRect& aRect,
+                              const uint32_t& aFlags) override;
+
+  virtual bool RecvContentReceivedInputBlock(const ScrollableLayerGuid& aGuid,
+                                             const uint64_t& aInputBlockId,
+                                             const bool& aPreventDefault) override;
+
+  virtual bool RecvStartScrollbarDrag(const AsyncDragMetrics& aDragMetrics) override;
+
+  virtual bool RecvSetTargetAPZC(const uint64_t& aInputBlockId,
+                                 nsTArray<ScrollableLayerGuid>&& aTargets) override;
+
+  virtual bool RecvSetAllowedTouchBehavior(const uint64_t& aInputBlockId,
+                                           nsTArray<TouchBehaviorFlags>&& aFlags) override;
+
+  virtual bool RecvUpdateZoomConstraints(const uint32_t& aPresShellId,
+                                         const ViewID& aViewId,
+                                         const MaybeZoomConstraints& aConstraints) override;
+
+  virtual void ActorDestroy(ActorDestroyReason aWhy) override;
+
+  virtual void Destroy() override;
+
+  virtual void ChildAdopted() override;
+
+private:
+  bool CanSend()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+    return !!mBrowserParent;
+  }
+  already_AddRefed<APZCTreeManager> GetApzcTreeManager();
+
+  MessageLoop* mUILoop;
+  uint64_t mLayersId;
+  RefPtr<dom::TabParent> mBrowserParent;
+
+  // Mutex protecting members below accessed from multiple threads.
+  mozilla::Mutex mMutex;
+
+  RefPtr<APZCTreeManager> mApzcTreeManager;
+  nsRegion mTouchSensitiveRegion;
+};
+
+} // namespace layers
+
+} // namespace mozilla
+
+#endif // mozilla_layers_RemoteContentController_h
--- a/gfx/layers/ipc/ThreadSafeRefcountingWithMainThreadDestruction.h
+++ b/gfx/layers/ipc/ThreadSafeRefcountingWithMainThreadDestruction.h
@@ -1,15 +1,16 @@
 /* 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 THREADSAFEREFCOUNTINGWITHMAINTHREADDESTRUCTION_H_
 #define THREADSAFEREFCOUNTINGWITHMAINTHREADDESTRUCTION_H_
 
+#include "base/message_loop.h"
 #include "MainThreadUtils.h"
 #include "nsThreadUtils.h"
 
 namespace mozilla {
 namespace layers {
 
 inline MessageLoop* GetMainLoopAssertingMainThread()
 {
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -146,32 +146,34 @@ EXPORTS.mozilla.layers += [
     'composite/TextureHost.h',
     'composite/TiledContentHost.h',
     'Compositor.h',
     'CompositorTypes.h',
     'D3D11ShareHandleImage.h',
     'D3D9SurfaceImage.h',
     'Effects.h',
     'ImageDataSerializer.h',
+    'ipc/APZChild.h',
     'ipc/AsyncTransactionTracker.h',
     'ipc/CompositableForwarder.h',
     'ipc/CompositableTransactionParent.h',
     'ipc/CompositorChild.h',
     'ipc/CompositorLRU.h',
     'ipc/CompositorParent.h',
     'ipc/FenceUtils.h',
     'ipc/GonkNativeHandle.h',
     'ipc/GonkNativeHandleUtils.h',
     'ipc/ImageBridgeChild.h',
     'ipc/ImageBridgeParent.h',
     'ipc/ImageContainerParent.h',
     'ipc/ISurfaceAllocator.h',
     'ipc/LayerAnimationUtils.h',
     'ipc/LayerTransactionChild.h',
     'ipc/LayerTransactionParent.h',
+    'ipc/RemoteContentController.h',
     'ipc/ShadowLayerChild.h',
     'ipc/ShadowLayers.h',
     'ipc/ShadowLayersManager.h',
     'ipc/SharedBufferManagerChild.h',
     'ipc/SharedBufferManagerParent.h',
     'ipc/SharedPlanarYCbCrImage.h',
     'ipc/SharedRGBImage.h',
     'LayerMetricsWrapper.h',
@@ -323,30 +325,32 @@ UNIFIED_SOURCES += [
     'composite/TiledContentHost.cpp',
     'Compositor.cpp',
     'CopyableCanvasLayer.cpp',
     'Effects.cpp',
     'FrameMetrics.cpp',
     'GLImages.cpp',
     'ImageDataSerializer.cpp',
     'ImageLayers.cpp',
+    'ipc/APZChild.cpp',
     'ipc/AsyncTransactionTracker.cpp',
     'ipc/CompositableTransactionParent.cpp',
     'ipc/CompositorBench.cpp',
     'ipc/CompositorChild.cpp',
     'ipc/CompositorLRU.cpp',
     'ipc/CompositorParent.cpp',
     'ipc/FenceUtils.cpp',
     'ipc/ImageBridgeChild.cpp',
     'ipc/ImageBridgeParent.cpp',
     'ipc/ImageContainerParent.cpp',
     'ipc/ISurfaceAllocator.cpp',
     'ipc/LayerAnimationUtils.cpp',
     'ipc/LayerTransactionChild.cpp',
     'ipc/LayerTransactionParent.cpp',
+    'ipc/RemoteContentController.cpp',
     'ipc/ShadowLayerChild.cpp',
     'ipc/ShadowLayerParent.cpp',
     'ipc/ShadowLayers.cpp',
     'ipc/SharedBufferManagerChild.cpp',
     'ipc/SharedBufferManagerParent.cpp',
     'ipc/SharedPlanarYCbCrImage.cpp',
     'ipc/SharedRGBImage.cpp',
     'LayerScope.cpp',
@@ -392,16 +396,17 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'coco
         'basic/MacIOSurfaceTextureHostBasic.cpp',
         'opengl/MacIOSurfaceTextureClientOGL.cpp',
         'opengl/MacIOSurfaceTextureHostOGL.cpp',
     ]
 
 IPDL_SOURCES = [
     'ipc/LayersMessages.ipdlh',
     'ipc/LayersSurfaces.ipdlh',
+    'ipc/PAPZ.ipdl',
     'ipc/PCompositable.ipdl',
     'ipc/PCompositor.ipdl',
     'ipc/PImageBridge.ipdl',
     'ipc/PImageContainer.ipdl',
     'ipc/PLayer.ipdl',
     'ipc/PLayerTransaction.ipdl',
     'ipc/PSharedBufferManager.ipdl',
     'ipc/PTexture.ipdl',
--- a/layout/ipc/PRenderFrame.ipdl
+++ b/layout/ipc/PRenderFrame.ipdl
@@ -27,13 +27,15 @@ sync protocol PRenderFrame
 {
     manager PBrowser;
 
 parent:
     async NotifyCompositorTransaction();
 
     async UpdateHitRegion(nsRegion aRegion);
 
+    sync TakeFocusForClickFromTap();
+
     async __delete__();
 };
 
 } // namespace layout
 } // namespace mozilla
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -10,16 +10,18 @@
 #include "BasicLayers.h"
 #include "gfxPrefs.h"
 #ifdef MOZ_ENABLE_D3D9_LAYER
 # include "LayerManagerD3D9.h"
 #endif //MOZ_ENABLE_D3D9_LAYER
 #include "mozilla/BrowserElementParent.h"
 #include "mozilla/EventForwards.h"  // for Modifiers
 #include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/ContentParent.h"
+#include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/layers/APZCTreeManager.h"
 #include "mozilla/layers/APZThreadUtils.h"
 #include "mozilla/layers/CompositorParent.h"
 #include "mozilla/layers/LayerTransactionParent.h"
 #include "nsContentUtils.h"
 #include "nsFocusManager.h"
 #include "nsFrameLoader.h"
@@ -29,20 +31,16 @@
 #include "nsView.h"
 #include "nsViewportFrame.h"
 #include "RenderFrameParent.h"
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "mozilla/layers/CompositorChild.h"
 #include "ClientLayerManager.h"
 #include "FrameLayerBuilder.h"
 
-#ifdef MOZ_ANDROID_APZ
-#include "AndroidBridge.h"
-#endif
-
 using namespace mozilla::dom;
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 
 namespace mozilla {
 namespace layout {
 
 typedef FrameMetrics::ViewID ViewID;
@@ -83,200 +81,16 @@ GetFrom(nsFrameLoader* aFrameLoader)
 {
   nsIDocument* doc = aFrameLoader->GetOwnerDoc();
   if (!doc) {
     return nullptr;
   }
   return nsContentUtils::LayerManagerForDocument(doc);
 }
 
-class RemoteContentController : public GeckoContentController {
-public:
-  explicit RemoteContentController(RenderFrameParent* aRenderFrame)
-    : mUILoop(MessageLoop::current())
-    , mRenderFrame(aRenderFrame)
-  { }
-
-  virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) override
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-    if (mRenderFrame) {
-      TabParent* browser = TabParent::GetFrom(mRenderFrame->Manager());
-      browser->UpdateFrame(aFrameMetrics);
-    }
-  }
-
-  virtual void RequestFlingSnap(const FrameMetrics::ViewID& aScrollId,
-                                const mozilla::CSSPoint& aDestination) override
-  {
-    if (MessageLoop::current() != mUILoop) {
-      // We have to send this message from the "UI thread" (main
-      // thread).
-      mUILoop->PostTask(
-        FROM_HERE,
-        NewRunnableMethod(this, &RemoteContentController::RequestFlingSnap,
-                          aScrollId, aDestination));
-      return;
-    }
-    if (mRenderFrame) {
-      TabParent* browser = TabParent::GetFrom(mRenderFrame->Manager());
-      browser->RequestFlingSnap(aScrollId, aDestination);
-    }
-  }
-
-  virtual void AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
-                                       const uint32_t& aScrollGeneration) override
-  {
-    if (MessageLoop::current() != mUILoop) {
-      // We have to send this message from the "UI thread" (main
-      // thread).
-      mUILoop->PostTask(
-        FROM_HERE,
-        NewRunnableMethod(this, &RemoteContentController::AcknowledgeScrollUpdate,
-                          aScrollId, aScrollGeneration));
-      return;
-    }
-    if (mRenderFrame) {
-      TabParent* browser = TabParent::GetFrom(mRenderFrame->Manager());
-      browser->AcknowledgeScrollUpdate(aScrollId, aScrollGeneration);
-    }
-  }
-
-  virtual void HandleDoubleTap(const CSSPoint& aPoint,
-                               Modifiers aModifiers,
-                               const ScrollableLayerGuid& aGuid) override
-  {
-    if (MessageLoop::current() != mUILoop) {
-      // We have to send this message from the "UI thread" (main
-      // thread).
-      mUILoop->PostTask(
-        FROM_HERE,
-        NewRunnableMethod(this, &RemoteContentController::HandleDoubleTap,
-                          aPoint, aModifiers, aGuid));
-      return;
-    }
-    if (mRenderFrame) {
-      TabParent* browser = TabParent::GetFrom(mRenderFrame->Manager());
-      browser->HandleDoubleTap(aPoint, aModifiers, aGuid);
-    }
-  }
-
-  virtual void HandleSingleTap(const CSSPoint& aPoint,
-                               Modifiers aModifiers,
-                               const ScrollableLayerGuid& aGuid) override
-  {
-    if (MessageLoop::current() != mUILoop) {
-      // We have to send this message from the "UI thread" (main
-      // thread).
-      mUILoop->PostTask(
-        FROM_HERE,
-        NewRunnableMethod(this, &RemoteContentController::HandleSingleTap,
-                          aPoint, aModifiers, aGuid));
-      return;
-    }
-    if (mRenderFrame) {
-      mRenderFrame->TakeFocusForClickFromTap();
-      TabParent* browser = TabParent::GetFrom(mRenderFrame->Manager());
-      browser->HandleSingleTap(aPoint, aModifiers, aGuid);
-    }
-  }
-
-  virtual void HandleLongTap(const CSSPoint& aPoint,
-                             Modifiers aModifiers,
-                             const ScrollableLayerGuid& aGuid,
-                             uint64_t aInputBlockId) override
-  {
-    if (MessageLoop::current() != mUILoop) {
-      // We have to send this message from the "UI thread" (main
-      // thread).
-      mUILoop->PostTask(
-        FROM_HERE,
-        NewRunnableMethod(this, &RemoteContentController::HandleLongTap,
-                          aPoint, aModifiers, aGuid, aInputBlockId));
-      return;
-    }
-    if (mRenderFrame) {
-      TabParent* browser = TabParent::GetFrom(mRenderFrame->Manager());
-      browser->HandleLongTap(aPoint, aModifiers, aGuid, aInputBlockId);
-    }
-  }
-
-  void ClearRenderFrame() { mRenderFrame = nullptr; }
-
-  virtual void PostDelayedTask(Task* aTask, int aDelayMs) override
-  {
-#ifdef MOZ_ANDROID_APZ
-    AndroidBridge::Bridge()->PostTaskToUiThread(aTask, aDelayMs);
-#else
-    (MessageLoop::current() ? MessageLoop::current() : mUILoop)->
-       PostDelayedTask(FROM_HERE, aTask, aDelayMs);
-#endif
-  }
-
-  virtual bool GetTouchSensitiveRegion(CSSRect* aOutRegion) override
-  {
-    if (mTouchSensitiveRegion.IsEmpty())
-      return false;
-
-    *aOutRegion = CSSRect::FromAppUnits(mTouchSensitiveRegion.GetBounds());
-    return true;
-  }
-
-  virtual void NotifyAPZStateChange(const ScrollableLayerGuid& aGuid,
-                                    APZStateChange aChange,
-                                    int aArg) override
-  {
-    if (MessageLoop::current() != mUILoop) {
-      mUILoop->PostTask(
-        FROM_HERE,
-        NewRunnableMethod(this, &RemoteContentController::NotifyAPZStateChange,
-                          aGuid, aChange, aArg));
-      return;
-    }
-    if (mRenderFrame) {
-      TabParent* browser = TabParent::GetFrom(mRenderFrame->Manager());
-      browser->NotifyAPZStateChange(aGuid.mScrollId, aChange, aArg);
-    }
-  }
-
-  void NotifyMozMouseScrollEvent(const FrameMetrics::ViewID& aScrollId, const nsString& aEvent) override {
-    if (MessageLoop::current() != mUILoop) {
-      mUILoop->PostTask(
-        FROM_HERE,
-        NewRunnableMethod(this, &RemoteContentController::NotifyMozMouseScrollEvent, aScrollId, aEvent));
-      return;
-    }
-
-    if (mRenderFrame) {
-      TabParent* browser = TabParent::GetFrom(mRenderFrame->Manager());
-      browser->NotifyMouseScrollTestEvent(aScrollId, aEvent);
-    }
-  }
-
-  void NotifyFlushComplete() override {
-    MOZ_ASSERT(NS_IsMainThread());
-    if (mRenderFrame) {
-      TabParent* browser = TabParent::GetFrom(mRenderFrame->Manager());
-      browser->NotifyFlushComplete();
-    }
-  }
-
-  // Methods used by RenderFrameParent to set fields stored here.
-
-  void SetTouchSensitiveRegion(const nsRegion& aRegion)
-  {
-    mTouchSensitiveRegion = aRegion;
-  }
-private:
-  MessageLoop* mUILoop;
-  RenderFrameParent* mRenderFrame;
-
-  nsRegion mTouchSensitiveRegion;
-};
-
 RenderFrameParent::RenderFrameParent(nsFrameLoader* aFrameLoader,
                                      TextureFactoryIdentifier* aTextureFactoryIdentifier,
                                      uint64_t* aId,
                                      bool* aSuccess)
   : mLayersId(0)
   , mFrameLoader(aFrameLoader)
   , mFrameLoaderDestroyed(false)
   , mAsyncPanZoomEnabled(false)
@@ -294,54 +108,35 @@ RenderFrameParent::RenderFrameParent(nsF
   // Perhaps the document containing this frame currently has no presentation?
   if (lm && lm->GetBackendType() == LayersBackend::LAYERS_CLIENT) {
     *aTextureFactoryIdentifier =
       static_cast<ClientLayerManager*>(lm.get())->GetTextureFactoryIdentifier();
   } else {
     *aTextureFactoryIdentifier = TextureFactoryIdentifier();
   }
 
+  TabParent* browser = TabParent::GetFrom(mFrameLoader);
   if (XRE_IsParentProcess()) {
     // Our remote frame will push layers updates to the compositor,
     // and we'll keep an indirect reference to that tree.
-    *aId = mLayersId = CompositorParent::AllocateLayerTreeId();
+    browser->Manager()->AsContentParent()->AllocateLayerTreeId(browser, aId);
+    mLayersId = *aId;
     if (lm && lm->GetBackendType() == LayersBackend::LAYERS_CLIENT) {
       ClientLayerManager *clientManager =
         static_cast<ClientLayerManager*>(lm.get());
       clientManager->GetRemoteRenderer()->SendNotifyChildCreated(mLayersId);
     }
-    if (mAsyncPanZoomEnabled) {
-      mContentController = new RemoteContentController(this);
-      CompositorParent::SetControllerForLayerTree(mLayersId, mContentController);
-    }
   } else if (XRE_IsContentProcess()) {
-    ContentChild::GetSingleton()->SendAllocateLayerTreeId(aId);
+    ContentChild::GetSingleton()->SendAllocateLayerTreeId(browser->Manager()->ChildID(), browser->GetTabId(), aId);
     mLayersId = *aId;
     CompositorChild::Get()->SendNotifyChildCreated(mLayersId);
   }
   *aSuccess = true;
 }
 
-APZCTreeManager*
-RenderFrameParent::GetApzcTreeManager()
-{
-  // We can't get a ref to the APZCTreeManager until after the child is
-  // created and the static getter knows which CompositorParent is
-  // instantiated with this layers ID. That's why try to fetch it when
-  // we first need it and cache the result.
-  // Note: the IsParentProcess check is to deal with nested content process
-  // scenarios, since in those cases we can have RenderFrameParent instances
-  // in a child process, but the APZC machinery is not in that process. Bug
-  // 1020199 should fix this more comprehensively.
-  if (!mApzcTreeManager && mAsyncPanZoomEnabled && XRE_IsParentProcess()) {
-    mApzcTreeManager = CompositorParent::GetAPZCTreeManager(mLayersId);
-  }
-  return mApzcTreeManager.get();
-}
-
 RenderFrameParent::~RenderFrameParent()
 {}
 
 void
 RenderFrameParent::Destroy()
 {
   mFrameLoaderDestroyed = true;
 }
@@ -413,59 +208,43 @@ RenderFrameParent::OwnerContentChanged(n
 
   RefPtr<LayerManager> lm = mFrameLoader ? GetFrom(mFrameLoader) : nullptr;
   // Perhaps the document containing this frame currently has no presentation?
   if (lm && lm->GetBackendType() == LayersBackend::LAYERS_CLIENT) {
     ClientLayerManager *clientManager =
       static_cast<ClientLayerManager*>(lm.get());
     clientManager->GetRemoteRenderer()->SendAdoptChild(mLayersId);
   }
-  // The APZCTreeManager associated with this RenderFrameParent may have changed
-  // so reset it and let GetApzcTreeManager() pick it up again.
-  mApzcTreeManager = nullptr;
 }
 
 void
 RenderFrameParent::ActorDestroy(ActorDestroyReason why)
 {
   if (mLayersId != 0) {
     if (XRE_IsContentProcess()) {
       ContentChild::GetSingleton()->SendDeallocateLayerTreeId(mLayersId);
     } else {
       CompositorParent::DeallocateLayerTreeId(mLayersId);
     }
-    if (mContentController) {
-      // Stop our content controller from requesting repaints of our
-      // content.
-      mContentController->ClearRenderFrame();
-      // TODO: notify the compositor?
-    }
   }
 
   mFrameLoader = nullptr;
 }
 
 bool
 RenderFrameParent::RecvNotifyCompositorTransaction()
 {
   TriggerRepaint();
   return true;
 }
 
 bool
 RenderFrameParent::RecvUpdateHitRegion(const nsRegion& aRegion)
 {
   mTouchRegion = aRegion;
-  if (mContentController) {
-    // Tell the content controller about the touch-sensitive region, so
-    // that it can provide it to APZ. This is required for APZ to do
-    // correct hit testing for a remote 'mozpasspointerevents' iframe
-    // until bug 928833 is fixed.
-    mContentController->SetTouchSensitiveRegion(aRegion);
-  }
   return true;
 }
 
 void
 RenderFrameParent::TriggerRepaint()
 {
   nsIFrame* docFrame = mFrameLoader->GetPrimaryFrameOfOwningContent();
   if (!docFrame) {
@@ -499,109 +278,23 @@ RenderFrameParent::BuildDisplayList(nsDi
   nsPoint offset = aBuilder->ToReferenceFrame(aFrame);
   nsRect bounds = aFrame->EnsureInnerView()->GetBounds() + offset;
   clipState.ClipContentDescendants(bounds);
 
   aLists.Content()->AppendToTop(
     new (aBuilder) nsDisplayRemote(aBuilder, aFrame, this));
 }
 
-void
-RenderFrameParent::ZoomToRect(uint32_t aPresShellId, ViewID aViewId,
-                              const CSSRect& aRect,
-                              const uint32_t aFlags)
-{
-  if (GetApzcTreeManager()) {
-    GetApzcTreeManager()->ZoomToRect(ScrollableLayerGuid(mLayersId, aPresShellId, aViewId),
-                                     aRect, aFlags);
-  }
-}
-
-void
-RenderFrameParent::ContentReceivedInputBlock(const ScrollableLayerGuid& aGuid,
-                                             uint64_t aInputBlockId,
-                                             bool aPreventDefault)
-{
-  if (aGuid.mLayersId != mLayersId) {
-    // Guard against bad data from hijacked child processes
-    NS_ERROR("Unexpected layers id in ContentReceivedInputBlock; dropping message...");
-    return;
-  }
-  if (GetApzcTreeManager()) {
-    APZThreadUtils::RunOnControllerThread(NewRunnableMethod(
-        GetApzcTreeManager(), &APZCTreeManager::ContentReceivedInputBlock,
-        aInputBlockId, aPreventDefault));
-  }
-}
-
-void
-RenderFrameParent::SetTargetAPZC(uint64_t aInputBlockId,
-                                 const nsTArray<ScrollableLayerGuid>& aTargets)
-{
-  for (size_t i = 0; i < aTargets.Length(); i++) {
-    if (aTargets[i].mLayersId != mLayersId) {
-      // Guard against bad data from hijacked child processes
-      NS_ERROR("Unexpected layers id in SetTargetAPZC; dropping message...");
-      return;
-    }
-  }
-  if (GetApzcTreeManager()) {
-    // need a local var to disambiguate between the SetTargetAPZC overloads.
-    void (APZCTreeManager::*setTargetApzcFunc)(uint64_t, const nsTArray<ScrollableLayerGuid>&)
-        = &APZCTreeManager::SetTargetAPZC;
-    APZThreadUtils::RunOnControllerThread(NewRunnableMethod(
-        GetApzcTreeManager(), setTargetApzcFunc,
-        aInputBlockId, aTargets));
-  }
-}
-
-void
-RenderFrameParent::SetAllowedTouchBehavior(uint64_t aInputBlockId,
-                                           const nsTArray<TouchBehaviorFlags>& aFlags)
-{
-  if (GetApzcTreeManager()) {
-    APZThreadUtils::RunOnControllerThread(NewRunnableMethod(
-        GetApzcTreeManager(), &APZCTreeManager::SetAllowedTouchBehavior,
-        aInputBlockId, aFlags));
-  }
-}
-
-void
-RenderFrameParent::UpdateZoomConstraints(uint32_t aPresShellId,
-                                         ViewID aViewId,
-                                         const Maybe<ZoomConstraints>& aConstraints)
-{
-  if (GetApzcTreeManager()) {
-    GetApzcTreeManager()->UpdateZoomConstraints(ScrollableLayerGuid(mLayersId, aPresShellId, aViewId),
-                                                aConstraints);
-  }
-}
-
 bool
 RenderFrameParent::HitTest(const nsRect& aRect)
 {
   return mTouchRegion.Contains(aRect);
 }
 
 void
-RenderFrameParent::StartScrollbarDrag(const AsyncDragMetrics& aDragMetrics)
-{
-  if (GetApzcTreeManager()) {
-    uint64_t layersId = GetLayersId();
-    ScrollableLayerGuid guid(layersId, aDragMetrics.mPresShellId,
-                             aDragMetrics.mViewId);
-
-    APZThreadUtils::RunOnControllerThread(
-      NewRunnableMethod(GetApzcTreeManager(),
-                        &APZCTreeManager::StartScrollbarDrag,
-                        guid, aDragMetrics));
-  }
-}
-
-void
 RenderFrameParent::GetTextureFactoryIdentifier(TextureFactoryIdentifier* aTextureFactoryIdentifier)
 {
   RefPtr<LayerManager> lm = mFrameLoader ? GetFrom(mFrameLoader) : nullptr;
   // Perhaps the document containing this frame currently has no presentation?
   if (lm && lm->GetBackendType() == LayersBackend::LAYERS_CLIENT) {
     *aTextureFactoryIdentifier =
       static_cast<ClientLayerManager*>(lm.get())->GetTextureFactoryIdentifier();
   } else {
@@ -624,16 +317,23 @@ RenderFrameParent::TakeFocusForClickFrom
   if (!element) {
     return;
   }
   fm->SetFocus(element, nsIFocusManager::FLAG_BYMOUSE |
                         nsIFocusManager::FLAG_BYTOUCH |
                         nsIFocusManager::FLAG_NOSCROLL);
 }
 
+bool
+RenderFrameParent::RecvTakeFocusForClickFromTap()
+{
+  TakeFocusForClickFromTap();
+  return true;
+}
+
 } // namespace layout
 } // namespace mozilla
 
 nsDisplayRemote::nsDisplayRemote(nsDisplayListBuilder* aBuilder,
                                  nsSubDocumentFrame* aFrame,
                                  RenderFrameParent* aRemoteFrame)
   : nsDisplayItem(aBuilder, aFrame)
   , mRemoteFrame(aRemoteFrame)
--- a/layout/ipc/RenderFrameParent.h
+++ b/layout/ipc/RenderFrameParent.h
@@ -28,18 +28,16 @@ class APZCTreeManager;
 class AsyncDragMetrics;
 class TargetConfig;
 struct TextureFactoryIdentifier;
 struct ScrollableLayerGuid;
 } // namespace layers
 
 namespace layout {
 
-class RemoteContentController;
-
 class RenderFrameParent : public PRenderFrameParent
 {
   typedef mozilla::layers::AsyncDragMetrics AsyncDragMetrics;
   typedef mozilla::layers::FrameMetrics FrameMetrics;
   typedef mozilla::layers::ContainerLayer ContainerLayer;
   typedef mozilla::layers::Layer Layer;
   typedef mozilla::layers::LayerManager LayerManager;
   typedef mozilla::layers::TargetConfig TargetConfig;
@@ -74,67 +72,46 @@ public:
                                      nsIFrame* aFrame,
                                      LayerManager* aManager,
                                      const nsIntRect& aVisibleRect,
                                      nsDisplayItem* aItem,
                                      const ContainerLayerParameters& aContainerParameters);
 
   void OwnerContentChanged(nsIContent* aContent);
 
-  void ZoomToRect(uint32_t aPresShellId, ViewID aViewId, const CSSRect& aRect, const uint32_t aFlags);
-
-  void ContentReceivedInputBlock(const ScrollableLayerGuid& aGuid,
-                                 uint64_t aInputBlockId,
-                                 bool aPreventDefault);
-  void SetTargetAPZC(uint64_t aInputBlockId,
-                     const nsTArray<ScrollableLayerGuid>& aTargets);
-  void SetAllowedTouchBehavior(uint64_t aInputBlockId,
-                               const nsTArray<TouchBehaviorFlags>& aFlags);
-
-  void UpdateZoomConstraints(uint32_t aPresShellId,
-                             ViewID aViewId,
-                             const Maybe<ZoomConstraints>& aConstraints);
-
   bool HitTest(const nsRect& aRect);
 
-  void StartScrollbarDrag(const AsyncDragMetrics& aDragMetrics);
-
   void GetTextureFactoryIdentifier(TextureFactoryIdentifier* aTextureFactoryIdentifier);
 
   inline uint64_t GetLayersId() { return mLayersId; }
 
   void TakeFocusForClickFromTap();
 
 protected:
   void ActorDestroy(ActorDestroyReason why) override;
 
   virtual bool RecvNotifyCompositorTransaction() override;
 
   virtual bool RecvUpdateHitRegion(const nsRegion& aRegion) override;
 
+  virtual bool RecvTakeFocusForClickFromTap() override;
+
 private:
   void TriggerRepaint();
   void DispatchEventForPanZoomController(const InputEvent& aEvent);
 
   uint64_t GetLayerTreeId() const;
 
   // When our child frame is pushing transactions directly to the
   // compositor, this is the ID of its layer tree in the compositor's
   // context.
   uint64_t mLayersId;
 
   RefPtr<nsFrameLoader> mFrameLoader;
   RefPtr<ContainerLayer> mContainer;
-  // When our scrolling behavior is ASYNC_PAN_ZOOM, we have a nonnull
-  // APZCTreeManager. It's used to manipulate the shadow layer tree
-  // on the compositor thread.
-  RefPtr<layers::APZCTreeManager> mApzcTreeManager;
-  RefPtr<RemoteContentController> mContentController;
-
-  layers::APZCTreeManager* GetApzcTreeManager();
 
   // True after Destroy() has been called, which is triggered
   // originally by nsFrameLoader::Destroy().  After this point, we can
   // no longer safely ask the frame loader to find its nearest layer
   // manager, because it may have been disconnected from the DOM.
   // It's still OK to *tell* the frame loader that we've painted after
   // it's destroyed; it'll just ignore us, and we won't be able to
   // find an nsIFrame to invalidate.  See ShadowLayersUpdated().
--- a/widget/PuppetWidget.cpp
+++ b/widget/PuppetWidget.cpp
@@ -7,17 +7,17 @@
 
 #include "base/basictypes.h"
 
 #include "ClientLayerManager.h"
 #include "gfxPlatform.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/Hal.h"
 #include "mozilla/IMEStateManager.h"
-#include "mozilla/layers/CompositorChild.h"
+#include "mozilla/layers/APZChild.h"
 #include "mozilla/layers/PLayerTransactionChild.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/TextComposition.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/unused.h"
 #include "PuppetWidget.h"
 #include "nsContentUtils.h"
 #include "nsIWidgetListener.h"
@@ -507,17 +507,17 @@ PuppetWidget::ClearNativeTouchSequence(n
   return NS_OK;
 }
  
 void
 PuppetWidget::SetConfirmedTargetAPZC(uint64_t aInputBlockId,
                                      const nsTArray<ScrollableLayerGuid>& aTargets) const
 {
   if (mTabChild) {
-    mTabChild->SendSetTargetAPZC(aInputBlockId, aTargets);
+    mTabChild->SetTargetAPZC(aInputBlockId, aTargets);
   }
 }
 
 void
 PuppetWidget::UpdateZoomConstraints(const uint32_t& aPresShellId,
                                     const FrameMetrics::ViewID& aViewId,
                                     const Maybe<ZoomConstraints>& aConstraints)
 {
@@ -1256,17 +1256,17 @@ uint32_t PuppetWidget::GetMaxTouchPoints
     sIsInitialized = true;
   }
   return sTouchPoints;
 }
 
 void
 PuppetWidget::StartAsyncScrollbarDrag(const AsyncDragMetrics& aDragMetrics)
 {
-  mTabChild->SendStartScrollbarDrag(aDragMetrics);
+  mTabChild->StartScrollbarDrag(aDragMetrics);
 }
 
 PuppetScreen::PuppetScreen(void *nativeScreen)
 {
 }
 
 PuppetScreen::~PuppetScreen()
 {
@@ -1429,13 +1429,13 @@ PuppetWidget::ZoomToRect(const uint32_t&
                          const FrameMetrics::ViewID& aViewId,
                          const CSSRect& aRect,
                          const uint32_t& aFlags)
 {
   if (!mTabChild) {
     return;
   }
 
-  mTabChild->SendZoomToRect(aPresShellId, aViewId, aRect, aFlags);
+  mTabChild->ZoomToRect(aPresShellId, aViewId, aRect, aFlags);
 }
 
 } // namespace widget
 } // namespace mozilla