Bug 625985 Panning gestures during kinetic panning are ignored r=mbrubeck
authorBenjamin Stover <bstover@mozilla.com>
Tue, 18 Jan 2011 14:02:34 -0800
changeset 67274 e6b27a2b978b630580b11f90ee35c4c40eee30a4
parent 67273 30dc032402ebc8fb949893124171f06f8639a4f7
child 67275 23eaec40c9407a47c545a0a7a1f156c8c0a09312
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmbrubeck
bugs625985
Bug 625985 Panning gestures during kinetic panning are ignored r=mbrubeck
mobile/chrome/content/input.js
--- a/mobile/chrome/content/input.js
+++ b/mobile/chrome/content/input.js
@@ -181,20 +181,21 @@ MouseModule.prototype = {
     this._cleanClickBuffer();
   },
 
   /** Begin possible pan and send tap down event. */
   _onMouseDown: function _onMouseDown(aEvent) {
     let dragData = this._dragData;
     if (dragData.dragging) {
       // Somehow a mouse up was missed.
-      let [sX, sY] = dragData.panPosition();
       this._doDragStop();
     }
     dragData.reset();
+    this.dX = 0;
+    this.dY = 0;
 
     // walk up the DOM tree in search of nearest scrollable ancestor.  nulls are
     // returned if none found.
     let [targetScrollbox, targetScrollInterface, dragger]
       = ScrollUtils.getScrollboxFromElement(aEvent.target);
 
     // stop kinetic panning if targetScrollbox has changed
     if (this._kinetic.isActive() && this._dragger != dragger)
@@ -241,16 +242,19 @@ MouseModule.prototype = {
   /** Send tap up event and any necessary full taps. */
   _onMouseUp: function _onMouseUp(aEvent) {
     if (this._suppressNextMouseUp) {
       this._suppressNextMouseUp = false;
       aEvent.stopPropagation();
       aEvent.preventDefault();
     }
 
+    // onMouseMove will not record the delta change if we are waiting for a
+    // paint. Since this is the last input for this drag, we override the flag.
+    this._waitingForPaint = false;
     this._onMouseMove(aEvent);
 
     let dragData = this._dragData;
     this._doDragStop();
 
     // Do tap
     if (this._target) {
       let event = document.createEvent("Events");
@@ -295,23 +299,41 @@ MouseModule.prototype = {
   },
 
   /**
    * If we're in a drag, do what we have to do to drag on.
    */
   _onMouseMove: function _onMouseMove(aEvent) {
     let dragData = this._dragData;
 
-    if (dragData.dragging && !this._waitingForPaint) {
+    if (dragData.dragging) {
       let oldIsPan = dragData.isPan();
       dragData.setDragPosition(aEvent.screenX, aEvent.screenY);
+
+      // Kinetic panning is sensitive to time. It is more stable if it receives
+      // the mousemove events as they come. For dragging though, we only want
+      // to call _dragBy if we aren't waiting for a paint (so we don't spam the
+      // main browser loop with a bunch of redundant paints).
+      //
+      // Here, we feed kinetic panning drag differences for mouse events as
+      // come; for dragging, we build up a drag buffer in this.dX/this.dY and
+      // release it when we are ready to paint.
+      //
+      let [sX, sY] = dragData.panPosition();
+      this.dX += dragData.prevPanX - sX;
+      this.dY += dragData.prevPanY - sY;
+
       if (dragData.isPan()) {
         // Only pan when mouse event isn't part of a click. Prevent jittering on tap.
-        let [sX, sY] = dragData.panPosition();
-        this._doDragMove();
+        this._kinetic.addData(sX - dragData.prevPanX, sY - dragData.prevPanY);
+        if (!this._waitingForPaint) {
+          this._dragBy(this.dX, this.dY);
+          this.dX = 0;
+          this.dY = 0;
+        }
 
         // Let everyone know when mousemove begins a pan
         if (!oldIsPan && dragData.isPan()) {
           this._mouseOverTimeout.clear();
           this._longClickTimeout.clear();
 
           let event = document.createEvent("Events");
           event.initEvent("PanBegin", true, false);
@@ -352,39 +374,23 @@ MouseModule.prototype = {
     // want the kinetic panner to tell our drag interface to stop.
 
     if (!dragData.isPan() && !this._kinetic.isActive()) {
       // There was no pan and no kinetic scrolling, so just stop dragger.
       this._dragger.dragStop(0, 0, this._targetScrollInterface);
       this._dragger = null;
     } else if (dragData.isPan()) {
       // Start kinetic pan.
-      let [sX, sY] = dragData.panPosition();
-      let dX = dragData.prevPanX - sX;
-      let dY = dragData.prevPanY - sY;
-      this._kinetic.addData(-dX, -dY);
       this._kinetic.start();
     }
   },
 
   /**
-   * Update kinetic with new data and drag.
-   */
-  _doDragMove: function _doDragMove() {
-    let dragData = this._dragData;
-    let [sX, sY] = dragData.panPosition();
-    let dX = dragData.prevPanX - sX;
-    let dY = dragData.prevPanY - sY;
-    this._kinetic.addData(-dX, -dY);
-    this._dragBy(dX, dY);
-  },
-
-  /**
-   * Used by _doDragMove() above and by KineticController's timer to do the
-   * actual dragMove signalling to the dragger.  We'd put this in _doDragMove()
+   * Used by _onMouseMove() above and by KineticController's timer to do the
+   * actual dragMove signalling to the dragger.  We'd put this in _onMouseMove()
    * but then KineticController would be adding to its own data as it signals
    * the dragger of dragMove()s.
    */
   _dragBy: function _dragBy(dX, dY) {
     let dragData = this._dragData;
     let dragged = this._dragger.dragMove(dX, dY, this._targetScrollInterface);
     if (dragged && !this._waitingForPaint) {
       this._waitingForPaint = true;
@@ -706,23 +712,23 @@ DragData.prototype = {
 
         if (absX > 2.5 * absY)
           this.lockedY = sY;
         else if (absY > absX)
           this.lockedX = sX;
 
         this.locked = true;
       }
+    }
 
-      // After pan lock, figure out previous panning position. Base it on last drag
-      // position so there isn't a jump in panning.
-      let [prevX, prevY] = this._lockAxis(this.sX, this.sY);
-      this.prevPanX = prevX;
-      this.prevPanY = prevY;
-    }
+    // After pan lock, figure out previous panning position. Base it on last drag
+    // position so there isn't a jump in panning.
+    let [prevX, prevY] = this._lockAxis(this.sX, this.sY);
+    this.prevPanX = prevX;
+    this.prevPanY = prevY;
 
     this.sX = sX;
     this.sY = sY;
   },
 
   setDragStart: function setDragStart(screenX, screenY, aDraggable) {
     this.sX = this._originX = screenX;
     this.sY = this._originY = screenY;