Bug 1351783 part 10 - Create and sync the current FocusTarget on each layer transaction. r=kats,botond
authorRyan Hunt <rhunt@eqrion.net>
Tue, 13 Jun 2017 02:00:49 -0400
changeset 600758 8d3d222b4761f2c6cfe27c92ba0ae1dcf3c44430
parent 600757 965a72722c0165313b4da4a9063896103645a827
child 600759 36bfbfdfa4a187ceea3aa8013963f0153b0317f3
push id65868
push userbmo:rail@mozilla.com
push dateTue, 27 Jun 2017 20:33:55 +0000
reviewerskats, botond
bugs1351783
milestone56.0a1
Bug 1351783 part 10 - Create and sync the current FocusTarget on each layer transaction. r=kats,botond This commit modifies PresShell and nsDisplayList to send a FocusTarget update on every layer transaction. Ideally we would like to send updates as often as possible, but this seems like it works well. This can be iterated on later, if necessary. MozReview-Commit-ID: 8PFqIOhzH77
gfx/layers/Layers.h
gfx/layers/apz/src/FocusTarget.cpp
gfx/layers/apz/src/FocusTarget.h
gfx/layers/client/ClientLayerManager.cpp
gfx/layers/client/ClientLayerManager.h
gfx/layers/ipc/CompositorBridgeParent.cpp
gfx/layers/ipc/CompositorBridgeParent.h
gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
gfx/layers/ipc/LayersMessageUtils.h
gfx/layers/ipc/LayersMessages.ipdlh
gfx/layers/ipc/ShadowLayers.cpp
gfx/layers/ipc/ShadowLayers.h
layout/base/PresShell.cpp
layout/base/nsIPresShell.h
layout/painting/nsDisplayList.cpp
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -92,16 +92,17 @@ class CompositorAnimations;
 class CompositorBridgeChild;
 class TextLayer;
 class CanvasLayer;
 class BorderLayer;
 class ReadbackLayer;
 class ReadbackProcessor;
 class RefLayer;
 class HostLayer;
+class FocusTarget;
 class KnowsCompositor;
 class ShadowableLayer;
 class ShadowLayerForwarder;
 class LayerManagerComposite;
 class SpecificLayerAttributes;
 class TransactionIdAllocator;
 class Compositor;
 class FrameUniformityData;
@@ -595,16 +596,21 @@ public:
   virtual void ClearCachedResources(Layer* aSubtree = nullptr) {}
 
   /**
    * Flag the next paint as the first for a document.
    */
   virtual void SetIsFirstPaint() {}
 
   /**
+   * Set the current focus target to be sent with the next paint.
+   */
+  virtual void SetFocusTarget(const FocusTarget& aFocusTarget) {}
+
+  /**
    * Make sure that the previous transaction has been entirely
    * completed.
    *
    * Note: This may sychronously wait on a remote compositor
    * to complete rendering.
    */
   virtual void FlushRendering() { }
 
--- a/gfx/layers/apz/src/FocusTarget.cpp
+++ b/gfx/layers/apz/src/FocusTarget.cpp
@@ -124,10 +124,27 @@ FocusTarget::FocusTarget(nsIPresShell* a
   // the horizontal and vertical scroll targets of this element.
   mType = FocusTarget::eScrollLayer;
   mData.mScrollTargets.mHorizontal =
     nsLayoutUtils::FindIDForScrollableFrame(horizontal);
   mData.mScrollTargets.mVertical =
     nsLayoutUtils::FindIDForScrollableFrame(vertical);
 }
 
+bool
+FocusTarget::operator==(const FocusTarget& aRhs) const
+{
+  if (mFocusHasKeyEventListeners != aRhs.mFocusHasKeyEventListeners ||
+      mType != aRhs.mType) {
+    return false;
+  }
+
+  if (mType == FocusTarget::eRefLayer) {
+      return mData.mRefLayerId == aRhs.mData.mRefLayerId;
+  } else if (mType == FocusTarget::eScrollLayer) {
+      return mData.mScrollTargets.mHorizontal == aRhs.mData.mScrollTargets.mHorizontal &&
+             mData.mScrollTargets.mVertical == aRhs.mData.mScrollTargets.mVertical;
+  }
+  return true;
+}
+
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/apz/src/FocusTarget.h
+++ b/gfx/layers/apz/src/FocusTarget.h
@@ -47,16 +47,18 @@ public:
 
   FocusTarget();
 
   /**
    * Construct a focus target for the specified top level PresShell
    */
   FocusTarget(nsIPresShell* aRootPresShell);
 
+  bool operator==(const FocusTarget& aRhs) const;
+
 public:
   // Whether there are keydown, keypress, or keyup event listeners
   // in the event target chain of the focused element
   bool mFocusHasKeyEventListeners;
 
   FocusTargetType mType;
   FocusTargetData mData;
 };
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -807,16 +807,22 @@ ClientLayerManager::SupportsBackdropCopy
 
 void
 ClientLayerManager::SetIsFirstPaint()
 {
   mForwarder->SetIsFirstPaint();
 }
 
 void
+ClientLayerManager::SetFocusTarget(const FocusTarget& aFocusTarget)
+{
+  mForwarder->SetFocusTarget(aFocusTarget);
+}
+
+void
 ClientLayerManager::ClearCachedResources(Layer* aSubtree)
 {
   if (mDestroyed) {
     // ClearCachedResource was already called by ClientLayerManager::Destroy
     return;
   }
   MOZ_ASSERT(!HasShadowManager() || !aSubtree);
   mForwarder->ClearCachedResources();
--- a/gfx/layers/client/ClientLayerManager.h
+++ b/gfx/layers/client/ClientLayerManager.h
@@ -9,16 +9,17 @@
 #include <stdint.h>                     // for int32_t
 #include "Layers.h"
 #include "gfxContext.h"                 // for gfxContext
 #include "mozilla/Attributes.h"         // for override
 #include "mozilla/LinkedList.h"         // For LinkedList
 #include "mozilla/WidgetUtils.h"        // for ScreenRotation
 #include "mozilla/gfx/Rect.h"           // for Rect
 #include "mozilla/layers/CompositorTypes.h"
+#include "mozilla/layers/FocusTarget.h"  // for FocusTarget
 #include "mozilla/layers/LayersTypes.h"  // for BufferMode, LayersBackend, etc
 #include "mozilla/layers/ShadowLayers.h"  // for ShadowLayerForwarder, etc
 #include "mozilla/layers/APZTestData.h" // for APZTestData
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsIObserver.h"                // for nsIObserver
 #include "nsISupportsImpl.h"            // for Layer::Release, etc
 #include "nsRect.h"                     // for mozilla::gfx::IntRect
 #include "nsTArray.h"                   // for nsTArray
@@ -128,16 +129,18 @@ public:
 
   bool HasShadowManager() const { return mForwarder->HasShadowManager(); }
 
   virtual bool IsCompositingCheap() override;
   virtual bool HasShadowManagerInternal() const override { return HasShadowManager(); }
 
   virtual void SetIsFirstPaint() override;
 
+  virtual void SetFocusTarget(const FocusTarget& aFocusTarget) override;
+
   /**
    * Pass through call to the forwarder for nsPresContext's
    * CollectPluginGeometryUpdates. Passes widget configuration information
    * to the compositor for transmission to the chrome process. This
    * configuration gets set when the window paints.
    */
   void StorePluginWidgetConfigurations(const nsTArray<nsIWidget::Configuration>&
                                        aConfigurations) override;
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -854,16 +854,17 @@ CompositorBridgeParent::UpdatePaintTime(
     return;
   }
 
   mLayerManager->SetPaintTime(aPaintTime);
 }
 
 void
 CompositorBridgeParent::NotifyShadowTreeTransaction(uint64_t aId, bool aIsFirstPaint,
+    const FocusTarget& aFocusTarget,
     bool aScheduleComposite, uint32_t aPaintSequenceNumber,
     bool aIsRepeatTransaction, bool aHitTestUpdate)
 {
   if (!aIsRepeatTransaction &&
       mLayerManager &&
       mLayerManager->GetRoot()) {
     // Process plugin data here to give time for them to update before the next
     // composition.
@@ -874,19 +875,23 @@ CompositorBridgeParent::NotifyShadowTree
 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
     // If plugins haven't been updated, stop waiting.
     if (!pluginsUpdatedFlag) {
       mWaitForPluginsUntil = TimeStamp();
       mHaveBlockedForPlugins = false;
     }
 #endif
 
-    if (mApzcTreeManager && aHitTestUpdate) {
-      mApzcTreeManager->UpdateHitTestingTree(mRootLayerTreeID,
-          mLayerManager->GetRoot(), aIsFirstPaint, aId, aPaintSequenceNumber);
+    if (mApzcTreeManager) {
+      mApzcTreeManager->UpdateFocusState(mRootLayerTreeID, aId,
+                                         aFocusTarget);
+      if (aHitTestUpdate) {
+        mApzcTreeManager->UpdateHitTestingTree(mRootLayerTreeID,
+            mLayerManager->GetRoot(), aIsFirstPaint, aId, aPaintSequenceNumber);
+      }
     }
 
     mLayerManager->NotifyShadowTreeTransaction();
   }
   if (aScheduleComposite) {
     ScheduleComposition();
   }
 }
@@ -1227,22 +1232,28 @@ CompositorBridgeParent::ShadowLayersUpda
   if (mLayerManager->GetCompositor()) {
     mLayerManager->GetCompositor()->SetScreenRotation(targetConfig.rotation());
   }
 
   mCompositionManager->Updated(aInfo.isFirstPaint(), targetConfig);
   Layer* root = aLayerTree->GetRoot();
   mLayerManager->SetRoot(root);
 
-  if (mApzcTreeManager && !aInfo.isRepeatTransaction() && aHitTestUpdate) {
-    AutoResolveRefLayers resolve(mCompositionManager);
+  if (mApzcTreeManager && !aInfo.isRepeatTransaction()) {
+    mApzcTreeManager->UpdateFocusState(mRootLayerTreeID,
+                                       mRootLayerTreeID,
+                                       aInfo.focusTarget());
 
-    mApzcTreeManager->UpdateHitTestingTree(
-      mRootLayerTreeID, root, aInfo.isFirstPaint(),
-      mRootLayerTreeID, aInfo.paintSequenceNumber());
+    if (aHitTestUpdate) {
+      AutoResolveRefLayers resolve(mCompositionManager);
+
+      mApzcTreeManager->UpdateHitTestingTree(
+        mRootLayerTreeID, root, aInfo.isFirstPaint(),
+        mRootLayerTreeID, aInfo.paintSequenceNumber());
+    }
   }
 
   // The transaction ID might get reset to 1 if the page gets reloaded, see
   // https://bugzilla.mozilla.org/show_bug.cgi?id=1145295#c41
   // Otherwise, it should be continually increasing.
   MOZ_ASSERT(aInfo.id() == 1 || aInfo.id() > mPendingTransaction);
   mPendingTransaction = aInfo.id();
 
--- a/gfx/layers/ipc/CompositorBridgeParent.h
+++ b/gfx/layers/ipc/CompositorBridgeParent.h
@@ -25,16 +25,17 @@
 #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/ipc/SharedMemory.h"
 #include "mozilla/layers/CompositorController.h"
 #include "mozilla/layers/CompositorOptions.h"
 #include "mozilla/layers/CompositorVsyncSchedulerOwner.h"
+#include "mozilla/layers/FocusState.h"
 #include "mozilla/layers/GeckoContentController.h"
 #include "mozilla/layers/ISurfaceAllocator.h" // for ShmemAllocator
 #include "mozilla/layers/LayersMessages.h"  // for TargetConfig
 #include "mozilla/layers/MetricsSharingController.h"
 #include "mozilla/layers/PCompositorBridgeParent.h"
 #include "mozilla/layers/APZTestData.h"
 #include "mozilla/webrender/WebRenderTypes.h"
 #include "mozilla/widget/CompositorWidget.h"
@@ -298,16 +299,17 @@ public:
    * Returns true if a surface was obtained and the resume succeeded; false
    * otherwise.
    */
   bool ScheduleResumeOnCompositorThread();
   bool ScheduleResumeOnCompositorThread(int width, int height);
 
   virtual void ScheduleComposition();
   void NotifyShadowTreeTransaction(uint64_t aId, bool aIsFirstPaint,
+      const FocusTarget& aFocusTarget,
       bool aScheduleComposite, uint32_t aPaintSequenceNumber,
       bool aIsRepeatTransaction, bool aHitTestUpdate);
 
   void UpdatePaintTime(LayerTransactionParent* aLayerTree,
                        const TimeDuration& aPaintTime) override;
 
   /**
    * Check rotation info and schedule a rendering task if needed.
--- a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
@@ -294,16 +294,17 @@ CrossProcessCompositorBridgeParent::Shad
 
   // Cache the plugin data for this remote layer tree
   state->mPluginData = aInfo.plugins();
   state->mUpdatedPluginDataAvailable = true;
 
   state->mParent->NotifyShadowTreeTransaction(
     id,
     aInfo.isFirstPaint(),
+    aInfo.focusTarget(),
     aInfo.scheduleComposite(),
     aInfo.paintSequenceNumber(),
     aInfo.isRepeatTransaction(),
     aHitTestUpdate);
 
   // Send the 'remote paint ready' message to the content thread if it has already asked.
   if(mNotifyAfterRemotePaint)  {
     Unused << SendRemotePaintIsReady();
--- a/gfx/layers/ipc/LayersMessageUtils.h
+++ b/gfx/layers/ipc/LayersMessageUtils.h
@@ -12,16 +12,17 @@
 #include "chrome/common/ipc_message_utils.h"
 #include "gfxTelemetry.h"
 #include "ipc/IPCMessageUtils.h"
 #include "ipc/nsGUIEventIPC.h"
 #include "mozilla/GfxMessageUtils.h"
 #include "mozilla/layers/AsyncDragMetrics.h"
 #include "mozilla/layers/CompositorOptions.h"
 #include "mozilla/layers/CompositorTypes.h"
+#include "mozilla/layers/FocusTarget.h"
 #include "mozilla/layers/GeckoContentController.h"
 #include "mozilla/layers/Keyboard.h"
 #include "mozilla/layers/LayerAttributes.h"
 #include "mozilla/layers/LayersTypes.h"
 #include "mozilla/Move.h"
 
 #include <stdint.h>
 
@@ -416,16 +417,75 @@ struct ParamTraits<mozilla::layers::Even
             ReadParam(aMsg, aIter, &aResult->mDispatchToContentHitRegion) &&
             ReadParam(aMsg, aIter, &aResult->mNoActionRegion) &&
             ReadParam(aMsg, aIter, &aResult->mHorizontalPanRegion) &&
             ReadParam(aMsg, aIter, &aResult->mVerticalPanRegion));
   }
 };
 
 template <>
+struct ParamTraits<mozilla::layers::FocusTarget::ScrollTargets>
+{
+  typedef mozilla::layers::FocusTarget::ScrollTargets paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    WriteParam(aMsg, aParam.mHorizontal);
+    WriteParam(aMsg, aParam.mVertical);
+  }
+
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+  {
+    return ReadParam(aMsg, aIter, &aResult->mHorizontal) &&
+           ReadParam(aMsg, aIter, &aResult->mVertical);
+  }
+};
+
+template <>
+struct ParamTraits<mozilla::layers::FocusTarget::FocusTargetType>
+  : public ContiguousEnumSerializer<
+             mozilla::layers::FocusTarget::FocusTargetType,
+             mozilla::layers::FocusTarget::eNone,
+             mozilla::layers::FocusTarget::eSentinel>
+{};
+
+template <>
+struct ParamTraits<mozilla::layers::FocusTarget>
+{
+  typedef mozilla::layers::FocusTarget paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    WriteParam(aMsg, aParam.mFocusHasKeyEventListeners);
+    WriteParam(aMsg, aParam.mType);
+    if (aParam.mType == mozilla::layers::FocusTarget::eRefLayer) {
+      WriteParam(aMsg, aParam.mData.mRefLayerId);
+    } else if (aParam.mType == mozilla::layers::FocusTarget::eScrollLayer) {
+      WriteParam(aMsg, aParam.mData.mScrollTargets);
+    }
+  }
+
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+  {
+    if (!ReadParam(aMsg, aIter, &aResult->mFocusHasKeyEventListeners) ||
+        !ReadParam(aMsg, aIter, &aResult->mType)) {
+      return false;
+    }
+
+    if (aResult->mType == mozilla::layers::FocusTarget::eRefLayer) {
+      return ReadParam(aMsg, aIter, &aResult->mData.mRefLayerId);
+    } else if (aResult->mType == mozilla::layers::FocusTarget::eScrollLayer) {
+      return ReadParam(aMsg, aIter, &aResult->mData.mScrollTargets);
+    }
+
+    return true;
+  }
+};
+
+template <>
 struct ParamTraits<mozilla::layers::KeyboardScrollAction::KeyboardScrollActionType>
   : public ContiguousEnumSerializer<
              mozilla::layers::KeyboardScrollAction::KeyboardScrollActionType,
              mozilla::layers::KeyboardScrollAction::KeyboardScrollActionType::eScrollCharacter,
              mozilla::layers::KeyboardScrollAction::KeyboardScrollActionType::eSentinel>
 {};
 
 template <>
--- a/gfx/layers/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -35,16 +35,17 @@ using mozilla::LayerSize from "Units.h";
 using mozilla::LayerRect from "Units.h";
 using mozilla::LayerIntRegion from "Units.h";
 using mozilla::ParentLayerIntRect from "Units.h";
 using mozilla::LayoutDeviceIntRect from "Units.h";
 using mozilla::layers::ScaleMode from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::EventRegions from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::EventRegionsOverride from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::DiagnosticTypes from "mozilla/layers/CompositorTypes.h";
+using mozilla::layers::FocusTarget from "mozilla/layers/FocusTarget.h";
 using struct mozilla::layers::ScrollMetadata from "FrameMetrics.h";
 using mozilla::layers::FrameMetrics::ViewID from "FrameMetrics.h";
 using mozilla::layers::LayersBackend from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::MaybeLayerClip from "FrameMetrics.h";
 using mozilla::gfx::Glyph from "Layers.h";
 using mozilla::layers::BorderColors from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::BorderCorners from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::BorderWidths from "mozilla/layers/LayersTypes.h";
@@ -564,16 +565,17 @@ struct TransactionInfo
   OpSetLayerAttributes[] setAttrs;
   CompositableOperation[] paints;
   OpDestroy[] toDestroy;
   uint64_t fwdTransactionId;
   uint64_t id;
   TargetConfig targetConfig;
   PluginWindowData[] plugins;
   bool isFirstPaint;
+  FocusTarget focusTarget;
   bool scheduleComposite;
   uint32_t paintSequenceNumber;
   bool isRepeatTransaction;
   TimeStamp transactionStart;
 };
 
 } // namespace
 } // namespace
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -728,16 +728,17 @@ ShadowLayerForwarder::EndTransaction(con
   info.setSimpleAttrs() = Move(setSimpleAttrs);
   info.setAttrs() = Move(setAttrs);
   info.paints() = Move(mTxn->mPaints);
   info.toDestroy() = mTxn->mDestroyedActors;
   info.fwdTransactionId() = GetFwdTransactionId();
   info.id() = aId;
   info.plugins() = mPluginWindowData;
   info.isFirstPaint() = mIsFirstPaint;
+  info.focusTarget() = mFocusTarget;
   info.scheduleComposite() = aScheduleComposite;
   info.paintSequenceNumber() = aPaintSequenceNumber;
   info.isRepeatTransaction() = aIsRepeatTransaction;
   info.transactionStart() = aTransactionStart;
 
   TargetConfig targetConfig(mTxn->mTargetBounds,
                             mTxn->mTargetRotation,
                             mTxn->mTargetOrientation,
@@ -772,16 +773,17 @@ ShadowLayerForwarder::EndTransaction(con
 
   if (startTime) {
     mPaintTiming.sendMs() = (TimeStamp::Now() - startTime.value()).ToMilliseconds();
     mShadowManager->SendRecordPaintTimes(mPaintTiming);
   }
 
   *aSent = true;
   mIsFirstPaint = false;
+  mFocusTarget = FocusTarget();
   MOZ_LAYERS_LOG(("[LayersForwarder] ... done"));
   return true;
 }
 
 RefPtr<CompositableClient>
 ShadowLayerForwarder::FindCompositable(const CompositableHandle& aHandle)
 {
   CompositableClient* client = nullptr;
--- a/gfx/layers/ipc/ShadowLayers.h
+++ b/gfx/layers/ipc/ShadowLayers.h
@@ -12,16 +12,17 @@
 #include <stdint.h>                     // for uint64_t
 #include "gfxTypes.h"
 #include "mozilla/Attributes.h"         // for override
 #include "mozilla/gfx/Rect.h"
 #include "mozilla/WidgetUtils.h"        // for ScreenRotation
 #include "mozilla/dom/ScreenOrientation.h"  // for ScreenOrientation
 #include "mozilla/ipc/SharedMemory.h"   // for SharedMemory, etc
 #include "mozilla/layers/CompositableForwarder.h"
+#include "mozilla/layers/FocusTarget.h"
 #include "mozilla/layers/LayersTypes.h"
 #include "mozilla/layers/TextureForwarder.h"
 #include "mozilla/layers/CompositorTypes.h"  // for OpenMode, etc
 #include "mozilla/layers/CompositorBridgeChild.h"
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsRegion.h"                   // for nsIntRegion
 #include "nsTArrayForwardDeclare.h"     // for InfallibleTArray
 #include "nsIWidget.h"
@@ -366,16 +367,21 @@ public:
    */
   LayerHandle ConstructShadowFor(ShadowableLayer* aLayer);
 
   /**
    * Flag the next paint as the first for a document.
    */
   void SetIsFirstPaint() { mIsFirstPaint = true; }
 
+  /**
+   * Set the current focus target to be sent with the next paint.
+   */
+  void SetFocusTarget(const FocusTarget& aFocusTarget) { mFocusTarget = aFocusTarget; }
+
   void SetLayerObserverEpoch(uint64_t aLayerObserverEpoch);
 
   static void PlatformSyncBeforeUpdate();
 
   virtual bool AllocSurfaceDescriptor(const gfx::IntSize& aSize,
                                       gfxContentType aContent,
                                       SurfaceDescriptor* aBuffer) override;
 
@@ -443,16 +449,17 @@ protected:
 
 private:
 
   ClientLayerManager* mClientLayerManager;
   Transaction* mTxn;
   MessageLoop* mMessageLoop;
   DiagnosticTypes mDiagnosticTypes;
   bool mIsFirstPaint;
+  FocusTarget mFocusTarget;
   bool mWindowOverlayChanged;
   InfallibleTArray<PluginWindowData> mPluginWindowData;
   UniquePtr<ActiveResourceTracker> mActiveResourceTracker;
   uint64_t mNextLayerHandle;
   nsDataHashtable<nsUint64HashKey, CompositableClient*> mCompositables;
   PaintTiming mPaintTiming;
   /**
    * ShadowLayerForwarder might dispatch tasks to main while puppet widget and
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -186,16 +186,17 @@
 #include "nsIDragSession.h"
 #include "nsIFrameInlines.h"
 #include "mozilla/gfx/2D.h"
 #include "nsSubDocumentFrame.h"
 #include "nsQueryObject.h"
 #include "nsLayoutStylesheetCache.h"
 #include "mozilla/layers/InputAPZContext.h"
 #include "mozilla/layers/ScrollInputMethods.h"
+#include "mozilla/layers/FocusTarget.h"
 #include "nsStyleSet.h"
 #include "mozilla/StyleSetHandle.h"
 #include "mozilla/StyleSetHandleInlines.h"
 #include "mozilla/StyleSheet.h"
 #include "mozilla/StyleSheetInlines.h"
 #include "mozilla/dom/ImageTracker.h"
 #include "nsIDocShellTreeOwner.h"
 
@@ -6331,16 +6332,21 @@ PresShell::Paint(nsView*         aViewTo
   NS_ASSERTION(aViewToPaint, "null view");
 
   MOZ_ASSERT(!mApproximateFrameVisibilityVisited, "Should have been cleared");
 
   if (!mIsActive) {
     return;
   }
 
+  // Update the focus target for async keyboard scrolling. This will be forwarded
+  // to APZ by nsDisplayList::PaintRoot. We need to to do this before we enter
+  // the paint phase because dispatching eVoid events can cause layout to happen.
+  mAPZFocusTarget = FocusTarget(this);
+
   nsPresContext* presContext = GetPresContext();
   AUTO_LAYOUT_PHASE_ENTRY_POINT(presContext, Paint);
 
   nsIFrame* frame = aViewToPaint->GetFrame();
 
   LayerManager* layerManager =
     aViewToPaint->GetWidget()->GetLayerManager();
   NS_ASSERTION(layerManager, "Must be in paint event");
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -18,16 +18,17 @@
 /* a presentation of a document, part 2 */
 
 #ifndef nsIPresShell_h___
 #define nsIPresShell_h___
 
 #include "mozilla/ArenaObjectID.h"
 #include "mozilla/EventForwards.h"
 #include "mozilla/FlushType.h"
+#include "mozilla/layers/FocusTarget.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/StyleSetHandle.h"
 #include "mozilla/StyleSheet.h"
 #include "mozilla/WeakPtr.h"
 #include "gfxPoint.h"
 #include "nsTHashtable.h"
 #include "nsHashKeys.h"
@@ -175,16 +176,17 @@ enum nsRectVisibility {
  */
 
 class nsIPresShell : public nsISupports
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IPRESSHELL_IID)
 
 protected:
+  typedef mozilla::layers::FocusTarget FocusTarget;
   typedef mozilla::layers::LayerManager LayerManager;
   typedef mozilla::gfx::SourceSurface SourceSurface;
 
   enum eRenderFlag {
     STATE_IGNORING_VIEWPORT_SCROLLING = 0x1,
     STATE_DRAWWINDOW_NOT_FLUSHING = 0x2
   };
   typedef uint8_t RenderFlags; // for storing the above flags
@@ -1522,16 +1524,21 @@ public:
   /**
    * Get the isFirstPaint flag.
    */
   bool GetIsFirstPaint() const { return mIsFirstPaint; }
 
   uint32_t GetPresShellId() { return mPresShellId; }
 
   /**
+   * Get the APZ FocusTarget used for async keyboard scrolling.
+   */
+  const FocusTarget& GetAPZFocusTarget() const { return mAPZFocusTarget; }
+
+  /**
    * Dispatch a mouse move event based on the most recent mouse position if
    * this PresShell is visible. This is used when the contents of the page
    * moved (aFromScroll is false) or scrolled (aFromScroll is true).
    */
   virtual void SynthesizeMouseMove(bool aFromScroll) = 0;
 
   enum PaintFlags {
     /* Update the layer tree and paint PaintedLayers. If this is not specified,
@@ -1831,17 +1838,16 @@ protected:
 #ifdef DEBUG
   nsIFrame*                 mDrawEventTargetFrame;
 
   // We track allocated pointers in a debug-only hashtable to assert against
   // missing/double frees.
   nsTHashtable<nsPtrHashKey<void>> mAllocatedPointers;
 #endif
 
-
   // Count of the number of times this presshell has been painted to a window.
   uint64_t                  mPaintCount;
 
   nsSize                    mScrollPositionClampingScrollPortSize;
 
   // A list of stack weak frames. This is a pointer to the last item in the list.
   AutoWeakFrame*            mAutoWeakFrames;
 
@@ -1894,16 +1900,19 @@ protected:
   bool mObservingLayoutFlushes: 1;
 
   // True if there are throttled animations that would be processed when
   // performing a flush with mFlushAnimations == true.
   bool mNeedThrottledAnimationFlush : 1;
 
   uint32_t                  mPresShellId;
 
+  // The focus information needed for async keyboard scrolling
+  FocusTarget               mAPZFocusTarget;
+
   static nsIContent*        gKeyDownTarget;
 
   // Cached font inflation values. This is done to prevent changing of font
   // inflation until a page is reloaded.
   uint32_t mFontSizeInflationEmPerLine;
   uint32_t mFontSizeInflationMinTwips;
   uint32_t mFontSizeInflationLineThreshold;
   bool mFontSizeInflationForceEnabled;
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -2201,17 +2201,16 @@ already_AddRefed<LayerManager> nsDisplay
     } else {
       // If there is no root scroll frame, pick the document element instead.
       // The only case we don't want to do this is in non-APZ fennec, where
       // we want the root xul document to get a null scroll id so that the root
       // content document gets the first non-null scroll id.
       content = document->GetDocumentElement();
     }
 
-
     if (ensureMetricsForRootId && content) {
       ViewID scrollId = nsLayoutUtils::FindOrCreateIDFor(content);
       if (nsLayoutUtils::ContainsMetricsWithId(root, scrollId)) {
         ensureMetricsForRootId = false;
       }
     }
 
     if (addMetrics || ensureMetricsForRootId) {
@@ -2222,16 +2221,19 @@ already_AddRefed<LayerManager> nsDisplay
       root->SetScrollMetadata(
         nsLayoutUtils::ComputeScrollMetadata(frame,
                            rootScrollFrame, content,
                            aBuilder->FindReferenceFrameFor(frame),
                            root, FrameMetrics::NULL_SCROLL_ID, viewport, Nothing(),
                            isRootContent, containerParameters));
     }
 
+    // Send an updated focus target with this transaction
+    layerManager->SetFocusTarget(presShell->GetAPZFocusTarget());
+
     // NS_WARNING is debug-only, so don't even bother checking the conditions in
     // a release build.
 #ifdef DEBUG
     bool usingDisplayport = false;
     if (nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame()) {
       nsIContent* content = rootScrollFrame->GetContent();
       if (content) {
         usingDisplayport = nsLayoutUtils::HasDisplayPort(content);