Bug 1105109 - Add a BeforeSample() method to AsyncPanZoomAnimation. r=kats draft
authorBotond Ballo <botond@mozilla.com>
Mon, 19 Jun 2017 18:07:31 -0400
changeset 614800 84f6aaa8bec3b3b88875bae087f54bfeb54be7bd
parent 614799 5e0abe9b23b37f8cbdf956cfcedb81aab5d40ae2
child 614801 5bdcefb056b5094e80fc1c173605d065b105ea14
push id70133
push userbballo@mozilla.com
push dateTue, 25 Jul 2017 02:09:09 +0000
reviewerskats
bugs1105109
milestone56.0a1
Bug 1105109 - Add a BeforeSample() method to AsyncPanZoomAnimation. r=kats This gives the animation a chance to perform work that requires the APZC lock not to be held. MozReview-Commit-ID: EygHf54Kax
gfx/layers/apz/src/AsyncPanZoomAnimation.h
gfx/layers/apz/src/AsyncPanZoomController.cpp
--- a/gfx/layers/apz/src/AsyncPanZoomAnimation.h
+++ b/gfx/layers/apz/src/AsyncPanZoomAnimation.h
@@ -60,16 +60,22 @@ public:
   virtual SmoothScrollAnimation* AsSmoothScrollAnimation() {
     return nullptr;
   }
 
   virtual bool WantsRepaints() {
     return true;
   }
 
+  // A function that APZC calls prior to calling DoSample(), before acquiring
+  // the APZC lock (which is held while DoSample() is called). This allows
+  // the animation to perform computation that requires the APZC lock not to
+  // be held (like accessing the tree manager).
+  virtual void BeforeSample() {}
+
 protected:
   // Protected destructor, to discourage deletion outside of Release():
   virtual ~AsyncPanZoomAnimation()
   { }
 
   /**
    * Tasks scheduled for execution after the APZC's mMonitor is released.
    * Derived classes can add tasks here in Sample(), and the APZC can call
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -3292,16 +3292,33 @@ bool AsyncPanZoomController::AdvanceAnim
 {
   APZThreadUtils::AssertOnCompositorThread();
 
   // Don't send any state-change notifications until the end of the function,
   // because we may go through some intermediate states while we finish
   // animations and start new ones.
   StateChangeNotificationBlocker blocker(this);
 
+  // If we have an animation, give it a chance to perform operations
+  // that require |mMonitor| not to be held.
+  {
+    // We still need to hold |mMonitor| while we acquire a ref to the
+    // animation, because otherwise the controller thread could get a
+    // timeslice between the null check and the BeforeSample() call,
+    // and call CancelAnimation().
+    RefPtr<AsyncPanZoomAnimation> animation;
+    {
+      ReentrantMonitorAutoEnter lock(mMonitor);
+      animation = mAnimation;
+    }
+    if (animation) {
+      animation->BeforeSample();
+    }
+  }
+
   // The eventual return value of this function. The compositor needs to know
   // whether or not to advance by a frame as soon as it can. For example, if a
   // fling is happening, it has to keep compositing so that the animation is
   // smooth. If an animation frame is requested, it is the compositor's
   // responsibility to schedule a composite.
   mAsyncTransformAppliedToContent = false;
   bool requestAnimationFrame = false;
   nsTArray<RefPtr<Runnable>> deferredTasks;