Bug 890932 - Make AsyncPanZoomController::mMonitor re-entrant to reduce code madness. r=BenWa
authorKartikaya Gupta <kgupta@mozilla.com>
Wed, 31 Jul 2013 08:53:16 -0400
changeset 153023 2bbb3a9505ab68bbe2614123230be499260b613e
parent 153022 7d9b658f6840c3dad704a68899a6c6018878ab19
child 153024 c2e61d3df70964d170e983b31b0e1972085eaa66
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersBenWa
bugs890932
milestone25.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 890932 - Make AsyncPanZoomController::mMonitor re-entrant to reduce code madness. r=BenWa
gfx/layers/ipc/AsyncPanZoomController.cpp
gfx/layers/ipc/AsyncPanZoomController.h
gfx/tests/gtest/TestAsyncPanZoomController.cpp
--- a/gfx/layers/ipc/AsyncPanZoomController.cpp
+++ b/gfx/layers/ipc/AsyncPanZoomController.cpp
@@ -164,23 +164,23 @@ AsyncPanZoomController::InitializeGlobal
 
 AsyncPanZoomController::AsyncPanZoomController(uint64_t aLayersId,
                                                GeckoContentController* aGeckoContentController,
                                                GestureBehavior aGestures)
   :  mLayersId(aLayersId),
      mPaintThrottler(GetFrameTime()),
      mGeckoContentController(aGeckoContentController),
      mRefPtrMonitor("RefPtrMonitor"),
+     mMonitor("AsyncPanZoomController"),
      mTouchListenerTimeoutTask(nullptr),
      mX(this),
      mY(this),
      mAllowZoom(true),
      mMinZoom(MIN_ZOOM),
      mMaxZoom(MAX_ZOOM),
-     mMonitor("AsyncPanZoomController"),
      mLastSampleTime(GetFrameTime()),
      mState(NOTHING),
      mLastAsyncScrollTime(GetFrameTime()),
      mLastAsyncScrollOffset(0, 0),
      mCurrentAsyncScrollOffset(0, 0),
      mAsyncScrollTimeoutTask(nullptr),
      mDPI(72),
      mDisableNextTouchBatch(false),
@@ -248,17 +248,17 @@ WidgetSpaceToCompensatedViewportSpace(co
 }
 
 nsEventStatus
 AsyncPanZoomController::ReceiveInputEvent(const nsInputEvent& aEvent,
                                           nsInputEvent* aOutEvent)
 {
   CSSToScreenScale currentResolution;
   {
-    MonitorAutoLock monitor(mMonitor);
+    ReentrantMonitorAutoEnter lock(mMonitor);
     currentResolution = mFrameMetrics.CalculateResolution();
   }
 
   nsEventStatus status;
   switch (aEvent.eventStructType) {
   case NS_TOUCH_EVENT: {
     MultiTouchInput event(static_cast<const nsTouchEvent&>(aEvent));
     status = ReceiveInputEvent(event);
@@ -411,17 +411,17 @@ nsEventStatus AsyncPanZoomController::On
 
   ScreenIntPoint point = touch.mScreenPoint;
 
   switch (mState) {
     case ANIMATING_ZOOM:
       // We just interrupted a double-tap animation, so force a redraw in case
       // this touchstart is just a tap that doesn't end up triggering a redraw.
       {
-        MonitorAutoLock monitor(mMonitor);
+        ReentrantMonitorAutoEnter lock(mMonitor);
         // Bring the resolution back in sync with the zoom.
         SetZoomAndResolution(mFrameMetrics.mZoom);
         RequestContentRepaint();
         ScheduleComposite();
       }
       // Fall through.
     case FLING:
       CancelAnimation();
@@ -490,17 +490,17 @@ nsEventStatus AsyncPanZoomController::On
 
 nsEventStatus AsyncPanZoomController::OnTouchEnd(const MultiTouchInput& aEvent) {
   if (mDisableNextTouchBatch) {
     mDisableNextTouchBatch = false;
     return nsEventStatus_eIgnore;
   }
 
   {
-    MonitorAutoLock monitor(mMonitor);
+    ReentrantMonitorAutoEnter lock(mMonitor);
     SendAsyncScrollEvent();
   }
 
   switch (mState) {
   case FLING:
     // Should never happen.
     NS_WARNING("Received impossible touch end in OnTouchEnd.");
     // Fall through.
@@ -511,17 +511,17 @@ nsEventStatus AsyncPanZoomController::On
     return nsEventStatus_eIgnore;
 
   case TOUCHING:
     SetState(NOTHING);
     return nsEventStatus_eIgnore;
 
   case PANNING:
     {
-      MonitorAutoLock monitor(mMonitor);
+      ReentrantMonitorAutoEnter lock(mMonitor);
       ScheduleComposite();
       RequestContentRepaint();
     }
     mX.EndTouch();
     mY.EndTouch();
     SetState(FLING);
     return nsEventStatus_eConsumeNoDefault;
 
@@ -564,17 +564,17 @@ nsEventStatus AsyncPanZoomController::On
   if (fabsf(prevSpan) <= EPSILON || fabsf(aEvent.mCurrentSpan) <= EPSILON) {
     // We're still handling it; we've just decided to throw this event away.
     return nsEventStatus_eConsumeNoDefault;
   }
 
   float spanRatio = aEvent.mCurrentSpan / aEvent.mPreviousSpan;
 
   {
-    MonitorAutoLock monitor(mMonitor);
+    ReentrantMonitorAutoEnter lock(mMonitor);
 
     CSSToScreenScale resolution = mFrameMetrics.CalculateResolution();
     gfxFloat userZoom = mFrameMetrics.mZoom.scale;
     ScreenPoint focusPoint = aEvent.mFocusPoint;
 
     CSSPoint focusChange = (mLastZoomFocus - focusPoint) / resolution;
     // If displacing by the change in focus point will take us off page bounds,
     // then reduce the displacement such that it doesn't.
@@ -655,58 +655,58 @@ nsEventStatus AsyncPanZoomController::On
   return nsEventStatus_eConsumeNoDefault;
 }
 
 nsEventStatus AsyncPanZoomController::OnScaleEnd(const PinchGestureInput& aEvent) {
   SetState(PANNING);
   mX.StartTouch(aEvent.mFocusPoint.x);
   mY.StartTouch(aEvent.mFocusPoint.y);
   {
-    MonitorAutoLock monitor(mMonitor);
+    ReentrantMonitorAutoEnter lock(mMonitor);
     ScheduleComposite();
     RequestContentRepaint();
   }
 
   return nsEventStatus_eConsumeNoDefault;
 }
 
 nsEventStatus AsyncPanZoomController::OnLongPress(const TapGestureInput& aEvent) {
   nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
   if (controller) {
-    MonitorAutoLock monitor(mMonitor);
+    ReentrantMonitorAutoEnter lock(mMonitor);
 
     CSSToScreenScale resolution = mFrameMetrics.CalculateResolution();
     CSSPoint point = WidgetSpaceToCompensatedViewportSpace(aEvent.mPoint, resolution);
     controller->HandleLongTap(gfx::RoundedToInt(point));
     return nsEventStatus_eConsumeNoDefault;
   }
   return nsEventStatus_eIgnore;
 }
 
 nsEventStatus AsyncPanZoomController::OnSingleTapUp(const TapGestureInput& aEvent) {
   return nsEventStatus_eIgnore;
 }
 
 nsEventStatus AsyncPanZoomController::OnSingleTapConfirmed(const TapGestureInput& aEvent) {
   nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
   if (controller) {
-    MonitorAutoLock monitor(mMonitor);
+    ReentrantMonitorAutoEnter lock(mMonitor);
 
     CSSToScreenScale resolution = mFrameMetrics.CalculateResolution();
     CSSPoint point = WidgetSpaceToCompensatedViewportSpace(aEvent.mPoint, resolution);
     controller->HandleSingleTap(gfx::RoundedToInt(point));
     return nsEventStatus_eConsumeNoDefault;
   }
   return nsEventStatus_eIgnore;
 }
 
 nsEventStatus AsyncPanZoomController::OnDoubleTap(const TapGestureInput& aEvent) {
   nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
   if (controller) {
-    MonitorAutoLock monitor(mMonitor);
+    ReentrantMonitorAutoEnter lock(mMonitor);
 
     if (mAllowZoom) {
       CSSToScreenScale resolution = mFrameMetrics.CalculateResolution();
       CSSPoint point = WidgetSpaceToCompensatedViewportSpace(aEvent.mPoint, resolution);
       controller->HandleDoubleTap(gfx::RoundedToInt(point));
     }
 
     return nsEventStatus_eConsumeNoDefault;
@@ -715,17 +715,17 @@ nsEventStatus AsyncPanZoomController::On
 }
 
 nsEventStatus AsyncPanZoomController::OnCancelTap(const TapGestureInput& aEvent) {
   // XXX: Implement this.
   return nsEventStatus_eIgnore;
 }
 
 float AsyncPanZoomController::PanDistance() {
-  MonitorAutoLock monitor(mMonitor);
+  ReentrantMonitorAutoEnter lock(mMonitor);
   return NS_hypot(mX.PanDistance(), mY.PanDistance());
 }
 
 const gfx::Point AsyncPanZoomController::GetVelocityVector() {
   return gfx::Point(mX.GetVelocity(), mY.GetVelocity());
 }
 
 const gfx::Point AsyncPanZoomController::GetAccelerationVector() {
@@ -762,17 +762,17 @@ void AsyncPanZoomController::TrackTouch(
   // Probably a duplicate event, just throw it away.
   if (timeDelta.ToMilliseconds() <= EPSILON) {
     return;
   }
 
   UpdateWithTouchAtDevicePoint(aEvent);
 
   {
-    MonitorAutoLock monitor(mMonitor);
+    ReentrantMonitorAutoEnter lock(mMonitor);
 
     // We want to inversely scale it because when you're zoomed further in, a
     // larger swipe should move you a shorter distance.
     ScreenToCSSScale inverseResolution = mFrameMetrics.CalculateResolution().Inverse();
 
     gfx::Point displacement(mX.GetDisplacementForDuration(inverseResolution.scale,
                                                           timeDelta),
                             mY.GetDisplacementForDuration(inverseResolution.scale,
@@ -825,17 +825,17 @@ bool AsyncPanZoomController::DoFling(con
   if (timePaintDelta.ToMilliseconds() > gFlingRepaintInterval) {
     RequestContentRepaint();
   }
 
   return true;
 }
 
 void AsyncPanZoomController::CancelAnimation() {
-  MonitorAutoLock monitor(mMonitor);
+  ReentrantMonitorAutoEnter lock(mMonitor);
   mState = NOTHING;
 }
 
 void AsyncPanZoomController::SetCompositorParent(CompositorParent* aCompositorParent) {
   mCompositorParent = aCompositorParent;
 }
 
 void AsyncPanZoomController::ScrollBy(const CSSPoint& aOffset) {
@@ -1047,34 +1047,34 @@ void AsyncPanZoomController::RequestCont
   // Set the zoom back to what it was for the purpose of logic control.
   mFrameMetrics.mZoom = actualZoom;
 }
 
 void
 AsyncPanZoomController::FireAsyncScrollOnTimeout()
 {
   if (mCurrentAsyncScrollOffset != mLastAsyncScrollOffset) {
-    MonitorAutoLock monitor(mMonitor);
+    ReentrantMonitorAutoEnter lock(mMonitor);
     SendAsyncScrollEvent();
   }
   mAsyncScrollTimeoutTask = nullptr;
 }
 
 bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSampleTime,
                                                             ViewTransform* aNewTransform,
                                                             ScreenPoint& aScrollOffset) {
   // 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.
   bool requestAnimationFrame = false;
 
   {
-    MonitorAutoLock mon(mMonitor);
+    ReentrantMonitorAutoEnter lock(mMonitor);
 
     switch (mState) {
     case FLING:
       // If a fling is currently happening, apply it now. We can pull
       // the updated metrics afterwards.
       requestAnimationFrame |= DoFling(aSampleTime - mLastSampleTime);
       break;
     case ANIMATING_ZOOM: {
@@ -1129,17 +1129,17 @@ bool AsyncPanZoomController::SampleConte
   // Fire the mozbrowserasyncscroll event immediately if it's been
   // sAsyncScrollThrottleTime ms since the last time we fired the event and the
   // current scroll offset is different than the mLastAsyncScrollOffset we sent
   // with the last event.
   // Otherwise, start a timer to fire the event sAsyncScrollTimeout ms from now.
   TimeDuration delta = aSampleTime - mLastAsyncScrollTime;
   if (delta.ToMilliseconds() > gAsyncScrollThrottleTime &&
       mCurrentAsyncScrollOffset != mLastAsyncScrollOffset) {
-    MonitorAutoLock monitor(mMonitor);
+    ReentrantMonitorAutoEnter lock(mMonitor);
     mLastAsyncScrollTime = aSampleTime;
     mLastAsyncScrollOffset = mCurrentAsyncScrollOffset;
     SendAsyncScrollEvent();
   }
   else {
     mAsyncScrollTimeoutTask =
       NewRunnableMethod(this, &AsyncPanZoomController::FireAsyncScrollOnTimeout);
     MessageLoop::current()->PostDelayedTask(FROM_HERE,
@@ -1148,32 +1148,32 @@ bool AsyncPanZoomController::SampleConte
   }
 
   mLastSampleTime = aSampleTime;
 
   return requestAnimationFrame;
 }
 
 ViewTransform AsyncPanZoomController::GetCurrentAsyncTransform() {
-  MonitorAutoLock mon(mMonitor);
+  ReentrantMonitorAutoEnter lock(mMonitor);
   return GetCurrentAsyncTransformInternal();
 }
 
 ViewTransform AsyncPanZoomController::GetCurrentAsyncTransformInternal() {
   LayerPoint metricsScrollOffset;
   if (mLastContentPaintMetrics.IsScrollable()) {
     metricsScrollOffset = mLastContentPaintMetrics.GetScrollOffsetInLayerPixels();
   }
   CSSToScreenScale localScale = mFrameMetrics.CalculateResolution();
   LayerPoint translation = mFrameMetrics.GetScrollOffsetInLayerPixels() - metricsScrollOffset;
   return ViewTransform(-translation, localScale / mLastContentPaintMetrics.mDevPixelsPerCSSPixel);
 }
 
 void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetrics, bool aIsFirstPaint) {
-  MonitorAutoLock monitor(mMonitor);
+  ReentrantMonitorAutoEnter lock(mMonitor);
 
   mLastContentPaintMetrics = aLayerMetrics;
 
   mFrameMetrics.mMayHaveTouchListeners = aLayerMetrics.mMayHaveTouchListeners;
 
   // TODO: Once a mechanism for calling UpdateScrollOffset() when content does
   //       a scrollTo() is implemented for B2G (bug 895905), this block can be removed.
 #ifndef MOZ_WIDGET_ANDROID
@@ -1229,22 +1229,22 @@ void AsyncPanZoomController::NotifyLayer
   }
 
   if (needContentRepaint) {
     RequestContentRepaint();
   }
 }
 
 const FrameMetrics& AsyncPanZoomController::GetFrameMetrics() {
-  mMonitor.AssertCurrentThreadOwns();
+  mMonitor.AssertCurrentThreadIn();
   return mFrameMetrics;
 }
 
 void AsyncPanZoomController::UpdateCompositionBounds(const ScreenIntRect& aCompositionBounds) {
-  MonitorAutoLock mon(mMonitor);
+  ReentrantMonitorAutoEnter lock(mMonitor);
 
   ScreenIntRect oldCompositionBounds = mFrameMetrics.mCompositionBounds;
   mFrameMetrics.mCompositionBounds = aCompositionBounds;
 
   // If the window had 0 dimensions before, or does now, we don't want to
   // repaint or update the zoom since we'll run into rendering issues and/or
   // divide-by-zero. This manifests itself as the screen flashing. If the page
   // has gone out of view, the buffer will be cleared elsewhere anyways.
@@ -1268,17 +1268,17 @@ void AsyncPanZoomController::CancelDefau
 void AsyncPanZoomController::DetectScrollableSubframe() {
   mDelayPanning = true;
 }
 
 void AsyncPanZoomController::ZoomToRect(CSSRect aRect) {
   SetState(ANIMATING_ZOOM);
 
   {
-    MonitorAutoLock mon(mMonitor);
+    ReentrantMonitorAutoEnter lock(mMonitor);
 
     ScreenIntRect compositionBounds = mFrameMetrics.mCompositionBounds;
     CSSRect cssPageRect = mFrameMetrics.mScrollableRect;
     CSSPoint scrollOffset = mFrameMetrics.mScrollOffset;
     float currentZoom = mFrameMetrics.mZoom.scale;
     float targetZoom;
     float intrinsicScale = mFrameMetrics.CalculateIntrinsicScale().scale;
 
@@ -1399,17 +1399,17 @@ void AsyncPanZoomController::ContentRece
 }
 
 void AsyncPanZoomController::SetState(PanZoomState aNewState) {
 
   PanZoomState oldState;
 
   // Intentional scoping for mutex
   {
-    MonitorAutoLock monitor(mMonitor);
+    ReentrantMonitorAutoEnter lock(mMonitor);
     oldState = mState;
     mState = aNewState;
   }
 
   if (mGeckoContentController) {
     if (oldState == PANNING && aNewState != PANNING) {
       mGeckoContentController->HandlePanEnd();
     } else if (oldState != PANNING && aNewState == PANNING) {
@@ -1419,17 +1419,17 @@ void AsyncPanZoomController::SetState(Pa
 }
 
 void AsyncPanZoomController::TimeoutTouchListeners() {
   mTouchListenerTimeoutTask = nullptr;
   ContentReceivedTouch(false);
 }
 
 void AsyncPanZoomController::SetZoomAndResolution(const ScreenToScreenScale& aZoom) {
-  mMonitor.AssertCurrentThreadOwns();
+  mMonitor.AssertCurrentThreadIn();
   mFrameMetrics.mZoom = aZoom;
   CSSToScreenScale resolution = mFrameMetrics.CalculateResolution();
   // We use ScreenToLayerScale(1) below in order to ask gecko to render
   // what's currently visible on the screen. This is effectively turning
   // the async zoom amount into the gecko zoom amount.
   mFrameMetrics.mResolution = resolution / mFrameMetrics.mDevPixelsPerCSSPixel * ScreenToLayerScale(1);
 }
 
@@ -1465,17 +1465,17 @@ void AsyncPanZoomController::SendAsyncSc
     contentRect.MoveTo(mCurrentAsyncScrollOffset);
   }
 
   controller->SendAsyncScrollDOMEvent(scrollId, contentRect, scrollableSize);
 }
 
 void AsyncPanZoomController::UpdateScrollOffset(const CSSPoint& aScrollOffset)
 {
-  MonitorAutoLock monitor(mMonitor);
+  ReentrantMonitorAutoEnter lock(mMonitor);
   mFrameMetrics.mScrollOffset = aScrollOffset;
 }
 
 bool AsyncPanZoomController::Matches(const ScrollableLayerGuid& aGuid)
 {
   // TODO: also check the presShellId and mScrollId, once those are
   // fully propagated everywhere in RenderFrameParent and AndroidJNI.
   return aGuid.mLayersId == mLayersId;
--- a/gfx/layers/ipc/AsyncPanZoomController.h
+++ b/gfx/layers/ipc/AsyncPanZoomController.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_layers_AsyncPanZoomController_h
 #define mozilla_layers_AsyncPanZoomController_h
 
 #include "GeckoContentController.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Monitor.h"
+#include "mozilla/ReentrantMonitor.h"
 #include "mozilla/RefPtr.h"
 #include "InputData.h"
 #include "Axis.h"
 #include "TaskThrottler.h"
 #include "mozilla/layers/APZCTreeManager.h"
 
 #include "base/message_loop.h"
 
@@ -530,17 +531,17 @@ protected:
   // Both |mFrameMetrics| and |mLastContentPaintMetrics| are protected by the
   // monitor. Do not read from or modify either of them without locking.
   FrameMetrics mFrameMetrics;
 
   // Protects |mFrameMetrics|, |mLastContentPaintMetrics|, and |mState|.
   // Before manipulating |mFrameMetrics| or |mLastContentPaintMetrics|, the
   // monitor should be held. When setting |mState|, either the SetState()
   // function can be used, or the monitor can be held and then |mState| updated.
-  Monitor mMonitor;
+  ReentrantMonitor mMonitor;
 
 private:
   // Metrics of the container layer corresponding to this APZC. This is
   // stored here so that it is accessible from the UI/controller thread.
   // These are the metrics at last content paint, the most recent
   // values we were notified of in NotifyLayersUpdate(). Since it represents
   // the Gecko state, it should be used as a basis for untransformation when
   // sending messages back to Gecko.
--- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp
+++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp
@@ -43,17 +43,17 @@ class TestAPZCContainerLayer : public Co
 
 class TestAsyncPanZoomController : public AsyncPanZoomController {
 public:
   TestAsyncPanZoomController(uint64_t aLayersId, MockContentController* mcc)
     : AsyncPanZoomController(aLayersId, mcc)
   {}
 
   void SetFrameMetrics(const FrameMetrics& metrics) {
-    MonitorAutoLock lock(mMonitor);
+    ReentrantMonitorAutoEnter lock(mMonitor);
     mFrameMetrics = metrics;
   }
 };
 
 class TestAPZCTreeManager : public APZCTreeManager {
 protected:
   void AssertOnCompositorThread() MOZ_OVERRIDE { /* no-op */ }
 };