From 1a41b340db97e726616016686ea8f0dc6bee8413 Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Fri, 12 Sep 2014 11:39:56 -0400 Subject: [PATCH] Bug 1053766 - Add a StateChange notification blocker to APZC. r=botond --- gfx/layers/apz/src/AsyncPanZoomController.cpp | 50 +++++++++- gfx/layers/apz/src/AsyncPanZoomController.h | 99 ++++++++++++------- 2 files changed, 106 insertions(+), 43 deletions(-) diff --git a/gfx/layers/apz/src/AsyncPanZoomController.cpp b/gfx/layers/apz/src/AsyncPanZoomController.cpp index 4d0482f906ba..fb0d3005df66 100644 --- a/gfx/layers/apz/src/AsyncPanZoomController.cpp +++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp @@ -408,6 +408,32 @@ GetFrameTime() { return sFrameTime; } +class MOZ_STACK_CLASS StateChangeNotificationBlocker { +public: + StateChangeNotificationBlocker(AsyncPanZoomController* aApzc) + : mApzc(aApzc) + { + ReentrantMonitorAutoEnter lock(mApzc->mMonitor); + mInitialState = mApzc->mState; + mApzc->mNotificationBlockers++; + } + + ~StateChangeNotificationBlocker() + { + AsyncPanZoomController::PanZoomState newState; + { + ReentrantMonitorAutoEnter lock(mApzc->mMonitor); + mApzc->mNotificationBlockers--; + newState = mApzc->mState; + } + mApzc->DispatchStateChangeNotification(mInitialState, newState); + } + +private: + AsyncPanZoomController* mApzc; + AsyncPanZoomController::PanZoomState mInitialState; +}; + class FlingAnimation: public AsyncPanZoomAnimation { public: FlingAnimation(AsyncPanZoomController& aApzc, @@ -848,7 +874,6 @@ AsyncPanZoomController::AsyncPanZoomController(uint64_t aLayersId, mRefPtrMonitor("RefPtrMonitor"), mSharingFrameMetricsAcrossProcesses(false), mMonitor("AsyncPanZoomController"), - mState(NOTHING), mX(MOZ_THIS_IN_INITIALIZER_LIST()), mY(MOZ_THIS_IN_INITIALIZER_LIST()), mPanDirRestricted(false), @@ -858,6 +883,8 @@ AsyncPanZoomController::AsyncPanZoomController(uint64_t aLayersId, mLastAsyncScrollOffset(0, 0), mCurrentAsyncScrollOffset(0, 0), mAsyncScrollTimeoutTask(nullptr), + mState(NOTHING), + mNotificationBlockers(0), mTouchBlockBalance(0), mTreeManager(aTreeManager), mAPZCId(sAsyncPanZoomControllerCount++), @@ -2999,8 +3026,8 @@ AsyncPanZoomController::GetAllowedTouchBehavior(ScreenIntPoint& aPoint) { return AllowedTouchBehavior::UNKNOWN; } -void AsyncPanZoomController::SetState(PanZoomState aNewState) { - +void AsyncPanZoomController::SetState(PanZoomState aNewState) +{ PanZoomState oldState; // Intentional scoping for mutex @@ -3010,11 +3037,24 @@ void AsyncPanZoomController::SetState(PanZoomState aNewState) { mState = aNewState; } + DispatchStateChangeNotification(oldState, aNewState); +} + +void AsyncPanZoomController::DispatchStateChangeNotification(PanZoomState aOldState, + PanZoomState aNewState) +{ + { // scope the lock + ReentrantMonitorAutoEnter lock(mMonitor); + if (mNotificationBlockers > 0) { + return; + } + } + if (nsRefPtr controller = GetGeckoContentController()) { - if (!IsTransformingState(oldState) && IsTransformingState(aNewState)) { + if (!IsTransformingState(aOldState) && IsTransformingState(aNewState)) { controller->NotifyAPZStateChange( GetGuid(), APZStateChange::TransformBegin); - } else if (IsTransformingState(oldState) && !IsTransformingState(aNewState)) { + } else if (IsTransformingState(aOldState) && !IsTransformingState(aNewState)) { controller->NotifyAPZStateChange( GetGuid(), APZStateChange::TransformEnd); } diff --git a/gfx/layers/apz/src/AsyncPanZoomController.h b/gfx/layers/apz/src/AsyncPanZoomController.h index 0fa4c227db84..5d2e1b91a3f8 100644 --- a/gfx/layers/apz/src/AsyncPanZoomController.h +++ b/gfx/layers/apz/src/AsyncPanZoomController.h @@ -45,6 +45,7 @@ class FlingAnimation; class InputBlockState; class TouchBlockState; class OverscrollHandoffChain; +class StateChangeNotificationBlocker; /** * Controller for all panning and zooming logic. Any time a user input is @@ -350,27 +351,6 @@ public: const ScreenPoint& aAnchor) const; protected: - enum PanZoomState { - NOTHING, /* no touch-start events received */ - FLING, /* all touches removed, but we're still scrolling page */ - TOUCHING, /* one touch-start event received */ - - PANNING, /* panning the frame */ - PANNING_LOCKED_X, /* touch-start followed by move (i.e. panning with axis lock) X axis */ - PANNING_LOCKED_Y, /* as above for Y axis */ - - CROSS_SLIDING_X, /* Panning disabled while user does a horizontal gesture - on a vertically-scrollable view. This used for the - Windows Metro "cross-slide" gesture. */ - CROSS_SLIDING_Y, /* as above for Y axis */ - - PINCHING, /* nth touch-start, where n > 1. this mode allows pan and zoom */ - ANIMATING_ZOOM, /* animated zoom to a new rect */ - SNAP_BACK, /* snap-back animation to relieve overscroll */ - SMOOTH_SCROLL, /* Smooth scrolling to destination. Used by - CSSOM-View smooth scroll-behavior */ - }; - // Protected destructor, to discourage deletion outside of Release(): ~AsyncPanZoomController(); @@ -596,13 +576,6 @@ private: */ bool ArePointerEventsConsumable(TouchBlockState* aBlock, uint32_t aTouchPoints); - /** - * Helper to set the current state. Holds the monitor before actually setting - * it and fires content controller events based on state changes. Always set - * the state using this call, do not set it directly. - */ - void SetState(PanZoomState aState); - /** * Convert ScreenPoint relative to this APZC to CSSPoint relative * to the parent document. This excludes the transient compositor transform. @@ -611,12 +584,6 @@ private: */ bool ConvertToGecko(const ScreenPoint& aPoint, CSSPoint* aOut); - /** - * Internal helpers for checking general state of this apzc. - */ - static bool IsTransformingState(PanZoomState aState); - bool IsInPanningState() const; - /** * Return in |aTransform| a visual effect that reflects this apzc's * overscrolled state, if any. @@ -682,10 +649,6 @@ protected: // would significantly limit what methods could be 'const'. mutable ReentrantMonitor mMonitor; - // Stores the state of panning and zooming this frame. This is protected by - // |mMonitor|; that is, it should be held whenever this is updated. - PanZoomState mState; - private: // Metrics of the container layer corresponding to this APZC. This is // stored here so that it is accessible from the UI/controller thread. @@ -741,6 +704,66 @@ private: friend class Axis; + + + /* =================================================================== + * The functions and members in this section are used to manage + * the state that tracks what this APZC is doing with the input events. + */ +protected: + enum PanZoomState { + NOTHING, /* no touch-start events received */ + FLING, /* all touches removed, but we're still scrolling page */ + TOUCHING, /* one touch-start event received */ + + PANNING, /* panning the frame */ + PANNING_LOCKED_X, /* touch-start followed by move (i.e. panning with axis lock) X axis */ + PANNING_LOCKED_Y, /* as above for Y axis */ + + CROSS_SLIDING_X, /* Panning disabled while user does a horizontal gesture + on a vertically-scrollable view. This used for the + Windows Metro "cross-slide" gesture. */ + CROSS_SLIDING_Y, /* as above for Y axis */ + + PINCHING, /* nth touch-start, where n > 1. this mode allows pan and zoom */ + ANIMATING_ZOOM, /* animated zoom to a new rect */ + SNAP_BACK, /* snap-back animation to relieve overscroll */ + SMOOTH_SCROLL, /* Smooth scrolling to destination. Used by + CSSOM-View smooth scroll-behavior */ + }; + + // This is in theory protected by |mMonitor|; that is, it should be held whenever + // this is updated. In practice though... see bug 897017. + PanZoomState mState; + +private: + friend class StateChangeNotificationBlocker; + /** + * A counter of how many StateChangeNotificationBlockers are active. + * A non-zero count will prevent state change notifications from + * being dispatched. Only code that holds mMonitor should touch this. + */ + int mNotificationBlockers; + + /** + * Helper to set the current state. Holds the monitor before actually setting + * it and fires content controller events based on state changes. Always set + * the state using this call, do not set it directly. + */ + void SetState(PanZoomState aState); + /** + * Fire content controller notifications about state changes, assuming no + * StateChangeNotificationBlocker has been activated. + */ + void DispatchStateChangeNotification(PanZoomState aOldState, PanZoomState aNewState); + /** + * Internal helpers for checking general state of this apzc. + */ + static bool IsTransformingState(PanZoomState aState); + bool IsInPanningState() const; + + + /* =================================================================== * The functions and members in this section are used to manage * blocks of touch events and the state needed to deal with content