Bug 521108: Improve pan axis locking [r=vingtetung]
authorBenjamin Stover <bstover@mozilla.com>
Tue, 03 Nov 2009 13:50:01 -0500
changeset 65750 a14b030b52bd2aa5f0ebfcd1bd27f2b0da25a8bb
parent 65749 4651482bda1de61aa85025deb54950360133069a
child 65751 f986a1fa285db5fcab62ee4b7ea447cc660e726e
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)
reviewersvingtetung
bugs521108
Bug 521108: Improve pan axis locking [r=vingtetung]
mobile/chrome/content/BrowserView.js
mobile/chrome/content/InputHandler.js
--- a/mobile/chrome/content/BrowserView.js
+++ b/mobile/chrome/content/BrowserView.js
@@ -307,31 +307,28 @@ BrowserView.prototype = {
     this._viewportChanged(sizeChanged, sizeChanged && !!causedByZoom);
   },
 
   /**
    * @return [width, height]
    */
   getViewportDimensions: function getViewportDimensions() {
     let bvs = this._browserViewportState;
-
     if (!bvs)
       throw "Cannot get viewport dimensions when no browser is set";
 
     return [bvs.viewportRect.right, bvs.viewportRect.bottom];
   },
 
   setZoomLevel: function setZoomLevel(zoomLevel) {
     let bvs = this._browserViewportState;
-
     if (!bvs)
       return;
 
     let newZoomLevel = BrowserView.Util.clampZoomLevel(zoomLevel);
-
     if (newZoomLevel != bvs.zoomLevel) {
       let browserW = this.viewportToBrowser(bvs.viewportRect.right);
       let browserH = this.viewportToBrowser(bvs.viewportRect.bottom);
       bvs.zoomLevel = newZoomLevel; // side-effect: now scale factor in transformations is newZoomLevel
       this.setViewportDimensions(this.browserToViewport(browserW),
                                  this.browserToViewport(browserH),
                                  true);
       bvs.zoomChanged = true;
@@ -461,17 +458,16 @@ BrowserView.prototype = {
    * Swap out the current browser and browser viewport state with a new pair.
    */
   setBrowser: function setBrowser(browser, browserViewportState, doZoom) {
     if (browser && !browserViewportState) {
       throw "Cannot set non-null browser with null BrowserViewportState";
     }
 
     let oldBrowser = this._browser;
-
     let browserChanged = (oldBrowser !== browser);
 
     if (oldBrowser) {
       oldBrowser.removeEventListener("MozAfterPaint", this.handleMozAfterPaint, false);
       oldBrowser.removeEventListener("scroll", this.handlePageScroll, false);
       oldBrowser.removeEventListener("MozScrolledAreaChanged", this.handleMozScrolledAreaChanged, false);
 
       oldBrowser.setAttribute("type", "content");
--- a/mobile/chrome/content/InputHandler.js
+++ b/mobile/chrome/content/InputHandler.js
@@ -44,17 +44,17 @@
 
 // how many msecs elapse before two taps are not a double tap
 const kDoubleClickInterval = 400;
 
 // milliseconds between mouse down and drag direction determined
 const kMsUntilLock = 50;
 
 // threshold in pixels for sensing a tap as opposed to a pan
-const kTapRadius = 15;
+const kTapRadius = 25;
 
 // how many milliseconds between each kinetic pan update
 const kKineticUpdateInterval = 25;
 
 // How much speed is removed every update
 const kDecelerationRate = .10;
 
 // How sensitive kinetic scroll is to mouse movement
@@ -596,26 +596,21 @@ MouseModule.prototype = {
         return true;
 
       target = target.parentNode;
     }
     return false;
   },
 
   /**
-   * Inform our dragger of a dragStart and update kinetic with new data.
+   * Inform our dragger of a dragStart.
    */
   _doDragStart: function _doDragStart(event) {
     let dragData = this._dragData;
-
-    // addData must be called before setDragStart. Otherwise addData may end kinetic panning and
-    // thus accidentally end the drag we've just begun.
-    this._kinetic.addData(event.screenX, event.screenY);
     dragData.setDragStart(event.screenX, event.screenY);
-
     this._dragger.dragStart(event.clientX, event.clientY, event.target, this._targetScrollInterface);
   },
 
   /**
    * Finish a drag.  The third parameter is a secret one used to distinguish
    * between the supposed end of drag caused by a mouseup and the real end
    * of drag which happens when KineticController::end() is called.
    */
@@ -881,51 +876,58 @@ DragData.prototype = {
     // Check if drag is now a pan.
     if (!this._isPan) {
       let distanceSquared = (Math.pow(sX - this._originX, 2) + Math.pow(sY - this._originY, 2));
       this._isPan = (distanceSquared > Math.pow(this._dragRadius, 2));
     }
 
     // If now a pan, mark previous position where panning was.
     if (this._isPan) {
+      let absX = Math.abs(this._originX - sX);
+      let absY = Math.abs(this._originY - sY);
+
+      // After the first lock, see if locking decision should be reverted.
+      if (this.lockedX && absX > 3 * absY)
+        this.lockedX = null;
+      else if (this.lockedY && absY > 3 * absX)
+        this.lockedY = null;
+
+      if (!this.locked) {
+        // look at difference from origin coord to lock movement, but only
+        // do it if initial movement is sufficient to detect intent
+
+        // divide possibilty space into eight parts.  Diagonals will allow
+        // free movement, while moving towards a cardinal will lock that
+        // axis.  We pick a direction if you move more than twice as far
+        // on one axis than another, which should be an angle of about 30
+        // degrees from the axis
+
+        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;
-      this.sX = sX;
-      this.sY = sY;
     }
 
-    // Check if axes should be locked.
-    if (!this.locked && Date.now() - this._dragStartTime >= kMsUntilLock) {
-      // look at difference from origin coord to lock movement, but only
-      // do it if initial movement is sufficient to detect intent
-
-      // divide possibilty space into eight parts.  Diagonals will allow
-      // free movement, while moving towards a cardinal will lock that
-      // axis.  We pick a direction if you move more than twice as far
-      // on one axis than another, which should be an angle of about 30
-      // degrees from the axis
-
-      let absX = Math.abs(this._originX - sX);
-      let absY = Math.abs(this._originY - sY);
-
-      if (absX > 2 * absY)
-        this.lockedY = this._originY;
-      else if (absY > 2 * absX)
-        this.lockedX = this._originX;
-
-      this.locked = true;
-    }
+    this.sX = sX;
+    this.sY = sY;
   },
 
   setDragStart: function setDragStart(screenX, screenY) {
     this.sX = this._originX = screenX;
     this.sY = this._originY = screenY;
     this.dragging = true;
-    this._dragStartTime = Date.now();
     this.locked = false;
   },
 
   endDrag: function endDrag() {
     this.dragging = false;
   },
 
   /** Returns true if drag should pan scrollboxes.*/