Bug 1449982 - Maintain a map from WrWindowId to APZUpdater. r?botond draft
authorKartikaya Gupta <kgupta@mozilla.com>
Tue, 10 Apr 2018 12:29:55 -0400
changeset 779784 45fb83f5aeef7ca53a21c81f97d5ebb88eee6c10
parent 779783 a6b61075aee25fe0ac443039b3f9ea6395317a60
child 779785 fd3d72afcc7dfa2c333c65bca436650654c4add5
push id105878
push userkgupta@mozilla.com
push dateTue, 10 Apr 2018 16:32:25 +0000
reviewersbotond
bugs1449982
milestone61.0a1
Bug 1449982 - Maintain a map from WrWindowId to APZUpdater. r?botond This will allow callbacks from rust code to get a handle to the necessary APZUpdater instance on which to invoke functions. MozReview-Commit-ID: 13XdzZrrtI5
gfx/layers/apz/public/APZUpdater.h
gfx/layers/apz/src/APZUpdater.cpp
gfx/layers/ipc/CompositorBridgeParent.cpp
--- a/gfx/layers/apz/public/APZUpdater.h
+++ b/gfx/layers/apz/public/APZUpdater.h
@@ -2,22 +2,30 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_layers_APZUpdater_h
 #define mozilla_layers_APZUpdater_h
 
+#include <unordered_map>
+
 #include "LayersTypes.h"
 #include "mozilla/layers/APZTestData.h"
+#include "mozilla/StaticMutex.h"
 #include "nsThreadUtils.h"
 #include "Units.h"
 
 namespace mozilla {
+
+namespace wr {
+struct WrWindowId;
+} // namespace wr
+
 namespace layers {
 
 class APZCTreeManager;
 class FocusTarget;
 class Layer;
 class WebRenderScrollData;
 
 /**
@@ -29,16 +37,17 @@ class WebRenderScrollData;
  */
 class APZUpdater {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(APZUpdater)
 
 public:
   explicit APZUpdater(const RefPtr<APZCTreeManager>& aApz);
 
   bool HasTreeManager(const RefPtr<APZCTreeManager>& aApz);
+  void SetWebRenderWindowId(const wr::WindowId& aWindowId);
 
   void ClearTree();
   void UpdateFocusState(LayersId aRootLayerTreeId,
                         LayersId aOriginatingLayersId,
                         const FocusTarget& aFocusTarget);
   void UpdateHitTestingTree(LayersId aRootLayerTreeId,
                             Layer* aRoot,
                             bool aIsFirstPaint,
@@ -92,14 +101,21 @@ public:
    */
   void RunOnControllerThread(already_AddRefed<Runnable> aTask);
 
 protected:
   virtual ~APZUpdater();
 
 private:
   RefPtr<APZCTreeManager> mApz;
+
+  // Used to manage the mapping from a WR window id to APZUpdater. These are only
+  // used if WebRender is enabled. Both sWindowIdMap and mWindowId should only
+  // be used while holding the sWindowIdLock.
+  static StaticMutex sWindowIdLock;
+  static std::unordered_map<uint64_t, APZUpdater*> sWindowIdMap;
+  Maybe<wr::WrWindowId> mWindowId;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // mozilla_layers_APZUpdater_h
--- a/gfx/layers/apz/src/APZUpdater.cpp
+++ b/gfx/layers/apz/src/APZUpdater.cpp
@@ -8,46 +8,78 @@
 
 #include "APZCTreeManager.h"
 #include "AsyncPanZoomController.h"
 #include "base/task.h"
 #include "mozilla/layers/APZThreadUtils.h"
 #include "mozilla/layers/CompositorThread.h"
 #include "mozilla/layers/SynchronousTask.h"
 #include "mozilla/layers/WebRenderScrollData.h"
+#include "mozilla/webrender/WebRenderTypes.h"
 
 namespace mozilla {
 namespace layers {
 
+StaticMutex APZUpdater::sWindowIdLock;
+std::unordered_map<uint64_t, APZUpdater*> APZUpdater::sWindowIdMap;
+
+
 APZUpdater::APZUpdater(const RefPtr<APZCTreeManager>& aApz)
   : mApz(aApz)
 {
   MOZ_ASSERT(aApz);
   mApz->SetUpdater(this);
 }
 
 APZUpdater::~APZUpdater()
 {
   mApz->SetUpdater(nullptr);
+
+  StaticMutexAutoLock lock(sWindowIdLock);
+  if (mWindowId) {
+    // Ensure that ClearTree was called and the task got run
+    MOZ_ASSERT(sWindowIdMap.find(wr::AsUint64(*mWindowId)) == sWindowIdMap.end());
+  }
 }
 
 bool
 APZUpdater::HasTreeManager(const RefPtr<APZCTreeManager>& aApz)
 {
   return aApz.get() == mApz.get();
 }
 
 void
+APZUpdater::SetWebRenderWindowId(const wr::WindowId& aWindowId)
+{
+  StaticMutexAutoLock lock(sWindowIdLock);
+  MOZ_ASSERT(!mWindowId);
+  mWindowId = Some(aWindowId);
+  sWindowIdMap[wr::AsUint64(aWindowId)] = this;
+}
+
+void
 APZUpdater::ClearTree()
 {
   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
-  RunOnUpdaterThread(NewRunnableMethod(
-      "APZUpdater::ClearTree",
-      mApz,
-      &APZCTreeManager::ClearTree));
+  RefPtr<APZUpdater> self = this;
+  RunOnUpdaterThread(NS_NewRunnableFunction(
+    "APZUpdater::ClearTree",
+    [=]() {
+      self->mApz->ClearTree();
+
+      // Once ClearTree is called on the APZCTreeManager, we are in a shutdown
+      // phase. After this point it's ok if WebRender cannot get a hold of the
+      // updater via the window id, and it's a good point to remove the mapping
+      // and avoid leaving a dangling pointer to this object.
+      StaticMutexAutoLock lock(sWindowIdLock);
+      if (self->mWindowId) {
+        sWindowIdMap.erase(wr::AsUint64(*(self->mWindowId)));
+      }
+    }
+  ));
 }
 
 void
 APZUpdater::UpdateFocusState(LayersId aRootLayerTreeId,
                              LayersId aOriginatingLayersId,
                              const FocusTarget& aFocusTarget)
 {
   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -1762,16 +1762,22 @@ CompositorBridgeParent::AllocPWebRenderB
   MOZ_ASSERT(wr::AsLayersId(aPipelineId) == mRootLayerTreeID);
   MOZ_ASSERT(!mWrBridge);
   MOZ_ASSERT(!mCompositor);
   MOZ_ASSERT(!mCompositorScheduler);
   MOZ_ASSERT(mWidget);
 
   RefPtr<widget::CompositorWidget> widget = mWidget;
   wr::WrWindowId windowId = wr::NewWindowId();
+  if (mApzUpdater) {
+    // If APZ is enabled, we need to register the APZ updater with the window id
+    // before the updater thread is created in WebRenderAPI::Create, so
+    // that the callback from the updater thread can find the right APZUpdater.
+    mApzUpdater->SetWebRenderWindowId(windowId);
+  }
   RefPtr<wr::WebRenderAPI> api = wr::WebRenderAPI::Create(this, Move(widget), windowId, aSize);
   if (!api) {
     mWrBridge = WebRenderBridgeParent::CreateDestroyed(aPipelineId);
     mWrBridge.get()->AddRef(); // IPDL reference
     *aIdNamespace = mWrBridge->GetIdNamespace();
     *aTextureFactoryIdentifier = TextureFactoryIdentifier(LayersBackend::LAYERS_NONE);
     return mWrBridge;
   }