Bug 1308627 - Ensure that two-fingered pans scroll the page even if the span between the fingers doesn't change. r?botond draft
authorKartikaya Gupta <kgupta@mozilla.com>
Fri, 07 Oct 2016 17:00:30 -0400
changeset 422563 ac42963be52f1cdf89a2b323786f422c81939ae3
parent 422256 49fe455cac957808ed4a5d1685c3a1938dac1d31
child 533308 3184bfd8a51c757f1f88c1e3fbb0a37c826fd260
push id31743
push userkgupta@mozilla.com
push dateFri, 07 Oct 2016 21:01:27 +0000
reviewersbotond
bugs1308627
milestone52.0a1
Bug 1308627 - Ensure that two-fingered pans scroll the page even if the span between the fingers doesn't change. r?botond MozReview-Commit-ID: 5jeqVtoIAO6
gfx/layers/apz/src/GestureEventListener.cpp
gfx/layers/apz/src/GestureEventListener.h
--- a/gfx/layers/apz/src/GestureEventListener.cpp
+++ b/gfx/layers/apz/src/GestureEventListener.cpp
@@ -23,20 +23,20 @@ namespace layers {
 /**
  * Maximum time for a touch on the screen and corresponding lift of the finger
  * to be considered a tap. This also applies to double taps, except that it is
  * used twice.
  */
 static const uint32_t MAX_TAP_TIME = 300;
 
 /**
- * Amount of change in span needed to take us from the GESTURE_WAITING_PINCH
- * state to the GESTURE_PINCH state. This is measured as a change in distance
- * between the fingers used to compute the span ratio. Note that it is a
- * distance, not a displacement.
+ * Amount of span or focus change needed to take us from the GESTURE_WAITING_PINCH
+ * state to the GESTURE_PINCH state. This is measured as either a change in distance
+ * between the fingers used to compute the span ratio, or the a change in
+ * position of the focus point between the two fingers.
  */
 static const float PINCH_START_THRESHOLD = 35.0f;
 
 static bool sLongTapEnabled = true;
 
 ParentLayerPoint GetCurrentFocus(const MultiTouchInput& aEvent)
 {
   const ParentLayerPoint& firstTouch = aEvent.mTouches[0].mLocalScreenPoint;
@@ -61,16 +61,17 @@ TapGestureInput CreateTapEvent(const Mul
                          aTouch.modifiers);
 }
 
 GestureEventListener::GestureEventListener(AsyncPanZoomController* aAsyncPanZoomController)
   : mAsyncPanZoomController(aAsyncPanZoomController),
     mState(GESTURE_NONE),
     mSpanChange(0.0f),
     mPreviousSpan(0.0f),
+    mFocusChange(0.0f),
     mLastTouchInput(MultiTouchInput::MULTITOUCH_START, 0, TimeStamp(), 0),
     mLastTapInput(MultiTouchInput::MULTITOUCH_START, 0, TimeStamp(), 0),
     mLongTapTimeoutTask(nullptr),
     mMaxTapTimeoutTask(nullptr)
 {
 }
 
 GestureEventListener::~GestureEventListener()
@@ -265,36 +266,40 @@ nsEventStatus GestureEventListener::Hand
 
   case GESTURE_MULTI_TOUCH_DOWN: {
     if (mLastTouchInput.mTouches.Length() < 2) {
       NS_WARNING("Wrong input: less than 2 moving points in GESTURE_MULTI_TOUCH_DOWN state");
       break;
     }
 
     ParentLayerCoord currentSpan = GetCurrentSpan(mLastTouchInput);
+    ParentLayerPoint currentFocus = GetCurrentFocus(mLastTouchInput);
 
     mSpanChange += fabsf(currentSpan - mPreviousSpan);
-    if (mSpanChange > PINCH_START_THRESHOLD) {
+    mFocusChange += (currentFocus - mPreviousFocus).Length();
+    if (mSpanChange > PINCH_START_THRESHOLD ||
+        mFocusChange > PINCH_START_THRESHOLD) {
       SetState(GESTURE_PINCH);
       PinchGestureInput pinchEvent(PinchGestureInput::PINCHGESTURE_START,
                                    mLastTouchInput.mTime,
                                    mLastTouchInput.mTimeStamp,
-                                   GetCurrentFocus(mLastTouchInput),
+                                   currentFocus,
                                    currentSpan,
                                    currentSpan,
                                    mLastTouchInput.modifiers);
 
       rv = mAsyncPanZoomController->HandleGestureEvent(pinchEvent);
     } else {
       // Prevent APZC::OnTouchMove from processing a move event when two
       // touches are active
       rv = nsEventStatus_eConsumeNoDefault;
     }
 
     mPreviousSpan = currentSpan;
+    mPreviousFocus = currentFocus;
     break;
   }
 
   case GESTURE_PINCH: {
     if (mLastTouchInput.mTouches.Length() < 2) {
       NS_WARNING("Wrong input: less than 2 moving points in GESTURE_PINCH state");
       // Prevent APZC::OnTouchMove() from handling this wrong input
       rv = nsEventStatus_eConsumeNoDefault;
@@ -477,18 +482,20 @@ void GestureEventListener::TriggerSingle
 
 void GestureEventListener::SetState(GestureState aState)
 {
   mState = aState;
 
   if (mState == GESTURE_NONE) {
     mSpanChange = 0.0f;
     mPreviousSpan = 0.0f;
+    mFocusChange = 0.0f;
   } else if (mState == GESTURE_MULTI_TOUCH_DOWN) {
     mPreviousSpan = GetCurrentSpan(mLastTouchInput);
+    mPreviousFocus = GetCurrentFocus(mLastTouchInput);
   }
 }
 
 void GestureEventListener::CancelLongTapTimeoutTask()
 {
   if (mState == GESTURE_SECOND_SINGLE_TOUCH_DOWN) {
     // being in this state means the task has been canceled already
     return;
--- a/gfx/layers/apz/src/GestureEventListener.h
+++ b/gfx/layers/apz/src/GestureEventListener.h
@@ -174,16 +174,20 @@ private:
   ParentLayerCoord mSpanChange;
 
   /**
    * Previous span calculated for the purposes of setting inside a
    * PinchGestureInput.
    */
   ParentLayerCoord mPreviousSpan;
 
+  /* Properties similar to mSpanChange and mPreviousSpan, but for the focus */
+  ParentLayerCoord mFocusChange;
+  ParentLayerPoint mPreviousFocus;
+
   /**
    * Cached copy of the last touch input.
    */
   MultiTouchInput mLastTouchInput;
 
   /**
    * Cached copy of the last tap gesture input.
    * In the situation when we have a tap followed by a pinch we lose info