Bug 1075253 - Consecutive taps should only emit one gesture. r=yzen
☠☠ backed out by 5ce2fc3939da ☠ ☠
authorEitan Isaacson <eitan@monotonous.org>
Wed, 15 Oct 2014 14:55:30 -0700
changeset 237060 a940b5a1f2f6c3e982befdd3eeed39ec4e065c69
parent 237059 b39cff5628dfb2460cc464e3424de9c1f2230e0f
child 237061 e655fbbc6e9fab9fa942d5d5769f7dba8f53592b
push id660
push userraliiev@mozilla.com
push dateWed, 18 Feb 2015 20:30:48 +0000
treeherdermozilla-release@49e493494178 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersyzen
bugs1075253
milestone36.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 1075253 - Consecutive taps should only emit one gesture. r=yzen
accessible/jsat/Gestures.jsm
accessible/tests/mochitest/jsat/dom_helper.js
accessible/tests/mochitest/jsat/gestures.json
--- a/accessible/jsat/Gestures.jsm
+++ b/accessible/jsat/Gestures.jsm
@@ -2,25 +2,25 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* global Components, GestureSettings, XPCOMUtils, Utils, Promise, Logger */
 /* exported GestureSettings, GestureTracker */
 
 /******************************************************************************
   All gestures have the following pathways when being resolved(v)/rejected(x):
-               Tap -> DoubleTap        (v)
+               Tap -> DoubleTap        (x)
                    -> Dwell            (x)
                    -> Swipe            (x)
 
-        AndroidTap -> TripleTap        (v)
+        AndroidTap -> TripleTap        (x)
                    -> TapHold          (x)
                    -> Swipe            (x)
 
-         DoubleTap -> TripleTap        (v)
+         DoubleTap -> TripleTap        (x)
                    -> TapHold          (x)
                    -> Explore          (x)
 
          TripleTap -> DoubleTapHold    (x)
                    -> Explore          (x)
 
              Dwell -> DwellEnd         (v)
 
@@ -355,29 +355,32 @@ Gesture.prototype = {
     // reject this gesture promise.
     return GestureSettings.maxConsecutiveGestureDelay;
   },
 
   /**
    * Clear the existing timer.
    */
   clearTimer: function Gesture_clearTimer() {
+    Logger.gesture('clearTimeout', this.type);
     clearTimeout(this._timer);
     delete this._timer;
   },
 
   /**
    * Start the timer for gesture timeout.
    * @param {Number} aTimeStamp An original pointer event's timeStamp that
    * started the gesture resolution sequence.
    */
   startTimer: function Gesture_startTimer(aTimeStamp) {
+    Logger.gesture('startTimer', this.type);
     this.clearTimer();
     let delay = this._getDelay(aTimeStamp);
     let handler = () => {
+      Logger.gesture('timer handler');
       delete this._timer;
       if (!this._inProgress) {
         this._deferred.reject();
       } else if (this._rejectToOnWait) {
         this._deferred.reject(this._rejectToOnWait);
       }
     };
     if (delay <= 0) {
@@ -667,69 +670,95 @@ DoubleTapHoldEnd.prototype = Object.crea
 DoubleTapHoldEnd.prototype.type = 'doubletapholdend';
 
 /**
  * A common tap gesture object.
  * @param {Number} aTimeStamp An original pointer event's timeStamp that started
  * the gesture resolution sequence.
  * @param {Object} aPoints An existing set of points (from previous events).
  * @param {?String} aLastEvent Last pointer event type.
- * @param {Function} aRejectTo A constructor for the next gesture to reject to
- * in case no pointermove or pointerup happens within the
+ * @param {Function} aRejectToOnWait A constructor for the next gesture to
+ * reject to in case no pointermove or pointerup happens within the
  * GestureSettings.dwellThreshold.
+ * @param {Function} aRejectToOnPointerDown A constructor for the gesture to
+ * reject to if a finger comes down immediately after the tap.
  * @param {Function} aTravelTo An optional constuctor for the next gesture to
  * reject to in case the the TravelGesture test fails.
  */
-function TapGesture(aTimeStamp, aPoints, aLastEvent, aRejectTo, aTravelTo) {
-  this._rejectToOnWait = aRejectTo;
+function TapGesture(aTimeStamp, aPoints, aLastEvent, aRejectToOnWait, aTravelTo, aRejectToOnPointerDown) {
+  this._rejectToOnWait = aRejectToOnWait;
+  this._rejectToOnPointerDown = aRejectToOnPointerDown;
   // If the pointer travels, reject to aTravelTo.
   TravelGesture.call(this, aTimeStamp, aPoints, aLastEvent, aTravelTo,
     TAP_MAX_RADIUS);
 }
 
 TapGesture.prototype = Object.create(TravelGesture.prototype);
 TapGesture.prototype._getDelay = function TapGesture__getDelay() {
   // If, for TapGesture, no pointermove or pointerup happens within the
   // GestureSettings.dwellThreshold, reject.
   // Note: the original pointer event's timeStamp is irrelevant here.
   return GestureSettings.dwellThreshold;
 };
 
+TapGesture.prototype.pointerup = function TapGesture_pointerup(aPoints) {
+    if (this._rejectToOnPointerDown) {
+      let complete = this._update(aPoints, 'pointerup', false, true);
+      if (complete) {
+        this.clearTimer();
+        this._pointerUpTimer = setTimeout(() => {
+          delete this._pointerUpTimer;
+          this._deferred.resolve();
+        }, GestureSettings.maxConsecutiveGestureDelay);
+      }
+    } else {
+      TravelGesture.prototype.pointerup.call(this, aPoints);
+    }
+};
+
+TapGesture.prototype.pointerdown = function TapGesture_pointerdown(aPoints, aTimeStamp) {
+  TravelGesture.prototype.pointerdown.call(this, aPoints, aTimeStamp);
+  if (this._pointerUpTimer) {
+    clearTimeout(this._pointerUpTimer);
+    delete this._pointerUpTimer;
+    this._deferred.reject(this._rejectToOnPointerDown);
+  }
+};
+
+
 /**
  * Tap gesture.
  * @param {Number} aTimeStamp An original pointer event's timeStamp that started
  * the gesture resolution sequence.
  * @param {Object} aPoints An existing set of points (from previous events).
  * @param {?String} aLastEvent Last pointer event type.
  */
 function Tap(aTimeStamp, aPoints, aLastEvent) {
   // If the pointer travels, reject to Swipe.
-  TapGesture.call(this, aTimeStamp, aPoints, aLastEvent, Dwell, Swipe);
+  TapGesture.call(this, aTimeStamp, aPoints, aLastEvent, Dwell, Swipe, DoubleTap);
 }
 
 Tap.prototype = Object.create(TapGesture.prototype);
 Tap.prototype.type = 'tap';
-Tap.prototype.resolveTo = DoubleTap;
 
 /**
  * Tap (multi) gesture on Android.
  * @param {Number} aTimeStamp An original pointer event's timeStamp that started
  * the gesture resolution sequence.
  * @param {Object} aPoints An existing set of points (from previous events).
  * @param {?String} aLastEvent Last pointer event type.
  */
 function AndroidTap(aTimeStamp, aPoints, aLastEvent) {
   // If the pointer travels, reject to Swipe. On dwell threshold reject to
   // TapHold.
-  TapGesture.call(this, aTimeStamp, aPoints, aLastEvent, TapHold, Swipe);
+  TapGesture.call(this, aTimeStamp, aPoints, aLastEvent, TapHold, Swipe, TripleTap);
 }
 AndroidTap.prototype = Object.create(TapGesture.prototype);
 // Android double taps are translated to single taps.
 AndroidTap.prototype.type = 'doubletap';
-AndroidTap.prototype.resolveTo = TripleTap;
 
 /**
  * Clear the pointerup handler timer in case of the 3 pointer swipe.
  */
 AndroidTap.prototype.clearThreeFingerSwipeTimer = function AndroidTap_clearThreeFingerSwipeTimer() {
   clearTimeout(this._threeFingerSwipeTimer);
   delete this._threeFingerSwipeTimer;
 };
@@ -762,31 +791,32 @@ AndroidTap.prototype.pointerup = functio
 /**
  * Double Tap gesture.
  * @param {Number} aTimeStamp An original pointer event's timeStamp that started
  * the gesture resolution sequence.
  * @param {Object} aPoints An existing set of points (from previous events).
  * @param {?String} aLastEvent Last pointer event type.
  */
 function DoubleTap(aTimeStamp, aPoints, aLastEvent) {
-  TapGesture.call(this, aTimeStamp, aPoints, aLastEvent, TapHold);
+  this._inProgress = true;
+  TapGesture.call(this, aTimeStamp, aPoints, aLastEvent, TapHold, null, TripleTap);
 }
 
 DoubleTap.prototype = Object.create(TapGesture.prototype);
 DoubleTap.prototype.type = 'doubletap';
-DoubleTap.prototype.resolveTo = TripleTap;
 
 /**
  * Triple Tap gesture.
  * @param {Number} aTimeStamp An original pointer event's timeStamp that started
  * the gesture resolution sequence.
  * @param {Object} aPoints An existing set of points (from previous events).
  * @param {?String} aLastEvent Last pointer event type.
  */
 function TripleTap(aTimeStamp, aPoints, aLastEvent) {
+  this._inProgress = true;
   TapGesture.call(this, aTimeStamp, aPoints, aLastEvent, DoubleTapHold);
 }
 
 TripleTap.prototype = Object.create(TapGesture.prototype);
 TripleTap.prototype.type = 'tripletap';
 
 /**
  * Common base object for gestures that are created as resolved.
--- a/accessible/tests/mochitest/jsat/dom_helper.js
+++ b/accessible/tests/mochitest/jsat/dom_helper.js
@@ -112,17 +112,17 @@ var originalSwipeMaxDuration = GestureSe
 function testMozAccessFuGesture(aExpectedGestures) {
   var types = aExpectedGestures;
   function handleGesture(aEvent) {
     if (aEvent.detail.type !== types[0].type) {
       // The is not the event of interest.
       return;
     }
     is(!!aEvent.detail.edge, !!types[0].edge);
-    ok(true, 'Received correct mozAccessFuGesture: ' + types.shift() + '.');
+    ok(true, 'Received correct mozAccessFuGesture: ' + JSON.stringify(types.shift()) + '.');
     if (types.length === 0) {
       win.removeEventListener('mozAccessFuGesture', handleGesture);
       if (AccessFuTest.sequenceCleanup) {
         AccessFuTest.sequenceCleanup();
       }
       AccessFuTest.nextTest();
     }
   }
--- a/accessible/tests/mochitest/jsat/gestures.json
+++ b/accessible/tests/mochitest/jsat/gestures.json
@@ -31,52 +31,51 @@
       {"type": "pointerup",
         "points": [{"x": 1.03, "y": 1.02, "identifier": 1}]},
       {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointermove",
         "points": [{"x": 0.97, "y": 1.01, "identifier": 1}]},
       {"type": "pointerup",
         "points": [{"x": 0.97, "y": 1.01, "identifier": 1}]}
     ],
-    "expectedGestures": [{ "type": "tap" }, { "type": "doubletap" }]
+    "expectedGestures": [{ "type": "doubletap" }]
   },
   {
     "events": [
       {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]}
     ],
-    "expectedGestures": [{ "type": "tap" }, { "type": "doubletap" }, { "type": "tripletap" }]
+    "expectedGestures": [{ "type": "tripletap" }]
   },
   {
     "events": [
       {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}],
         "removeDwellThreshold": true},
       {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]}
     ],
-    "expectedGestures": [{ "type": "tap" }, { "type": "doubletap" },
-      { "type": "doubletaphold" }, { "type": "doubletapholdend" }]
+    "expectedGestures": [{ "type": "doubletaphold" },
+      { "type": "doubletapholdend" }]
   },
   {
     "events": [
       {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}],
         "removeDwellThreshold": true},
       {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]}
     ],
-    "expectedGestures": [{ "type": "tap" }, { "type": "taphold" },
-      { "type": "tapholdend" }]
+    "expectedGestures": [{ "type": "taphold" }, { "type": "tapholdend" }]
   },
   {
     "events": [
       {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointermove", "points": [{"x": 1.5, "y": 1, "identifier": 1}]},
       {"type": "pointerup", "points": [{"x": 1.5, "y": 1, "identifier": 1}]}
     ],
     "expectedGestures": [{ "type": "swiperight" }]