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
--- 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;