Bug 716673 - Fix up the advanceFling() step. r=pcwalton
authorKartikaya Gupta <kgupta@mozilla.com>
Tue, 10 Jan 2012 10:05:57 -0500
changeset 84217 72528d442842fa2de3dc42fe3ebdc43f6c906972
parent 84216 82efff89bd7669b71987f5695076b9343c9e5a11
child 84218 ee48470bdaf3457e19cfdaa92069a8e60f946a1f
push id21832
push userbmo@edmorley.co.uk
push dateWed, 11 Jan 2012 17:04:15 +0000
treeherdermozilla-central@40c9f9ff9fd5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspcwalton
bugs716673
milestone12.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 716673 - Fix up the advanceFling() step. r=pcwalton - Refactor the code a little to ensure we don't do any flinging if the panning is being overridden. - Collapse duplicated/inconsistent code in the fling-termination conditions so that it makes sense now.
mobile/android/base/ui/PanZoomController.java
--- a/mobile/android/base/ui/PanZoomController.java
+++ b/mobile/android/base/ui/PanZoomController.java
@@ -496,16 +496,22 @@ public class PanZoomController
             mAnimationTimer = null;
         }
         if (mAnimationRunnable != null) {
             mAnimationRunnable.terminate();
             mAnimationRunnable = null;
         }
     }
 
+    private float getVelocity() {
+        float xvel = mX.getRealVelocity();
+        float yvel = mY.getRealVelocity();
+        return FloatMath.sqrt(xvel * xvel + yvel * yvel);
+    }
+
     private boolean stopped() {
         float absVelocity = (float)Math.sqrt(mX.velocity * mX.velocity +
                                              mY.velocity * mY.velocity);
         return absVelocity < STOPPED_THRESHOLD;
     }
 
     private void updatePosition() {
         if (mOverridePanning) {
@@ -630,47 +636,47 @@ public class PanZoomController
              * out.
              */
             if (mState != PanZoomState.FLING) {
                 finishAnimation();
                 return;
             }
 
             /* Advance flings, if necessary. */
-            boolean flingingX = mX.getFlingState() == Axis.FlingStates.FLINGING;
-            boolean flingingY = mY.getFlingState() == Axis.FlingStates.FLINGING;
-            if (flingingX)
-                mX.advanceFling();
-            if (flingingY)
-                mY.advanceFling();
+            boolean flingingX = mX.advanceFling();
+            boolean flingingY = mY.advanceFling();
+
+            boolean overscrolled = ((mX.overscrolled() || mY.overscrolled()) && !mOverridePanning);
 
             /* If we're still flinging in any direction, update the origin. */
             if (flingingX || flingingY) {
                 mX.displace(mOverridePanning); mY.displace(mOverridePanning);
                 updatePosition();
 
                 /*
-                 * If we're still flinging with an appreciable velocity, stop here. The threshold is
+                 * Check to see if we're still flinging with an appreciable velocity. The threshold is
                  * higher in the case of overscroll, so we bounce back eagerly when overscrolling but
-                 * coast smoothly to a stop when not.
+                 * coast smoothly to a stop when not. In other words, require a greater velocity to
+                 * maintain the fling once we enter overscroll.
                  */
-                float excess = PointUtils.distance(new PointF(mX.getExcess(), mY.getExcess()));
-                PointF velocityVector = new PointF(mX.getRealVelocity(), mY.getRealVelocity());
-                float threshold = (excess >= 1.0f) ? STOPPED_THRESHOLD : FLING_STOPPED_THRESHOLD;
-                if (PointUtils.distance(velocityVector) >= threshold)
+                float threshold = (overscrolled ? STOPPED_THRESHOLD : FLING_STOPPED_THRESHOLD);
+                if (getVelocity() >= threshold) {
+                    // we're still flinging
                     return;
+                }
+
+                mX.stopFling();
+                mY.stopFling();
             }
 
             /*
              * Perform a bounce-back animation if overscrolled, unless panning is being overridden
              * (which happens e.g. when the user is panning an iframe).
              */
-            boolean overscrolledX = mX.getOverscroll() != Axis.Overscroll.NONE;
-            boolean overscrolledY = mY.getOverscroll() != Axis.Overscroll.NONE;
-            if (!mOverridePanning && (overscrolledX || overscrolledY)) {
+            if (overscrolled) {
                 bounce();
             } else {
                 finishAnimation();
                 mState = PanZoomState.NOTHING;
             }
         }
     }
 
@@ -686,17 +692,17 @@ public class PanZoomController
     // Physics information for one axis (X or Y).
     private abstract static class Axis {
         public enum FlingStates {
             STOPPED,
             PANNING,
             FLINGING,
         }
 
-        public enum Overscroll {
+        private enum Overscroll {
             NONE,
             MINUS,      // Overscrolled in the negative direction
             PLUS,       // Overscrolled in the positive direction
             BOTH,       // Overscrolled in both directions (page is zoomed to smaller than screen)
         }
 
         private float firstTouchPos;            /* Position of the first touch event on the current drag. */
         private float touchPos;                 /* Position of the most recent touch event on the current drag. */
@@ -750,32 +756,36 @@ public class PanZoomController
             } else {
                 float maxChange = Math.abs(velocity * timeDelta * MAX_EVENT_ACCELERATION);
                 velocity = Math.min(velocity + maxChange, Math.max(velocity - maxChange, newVelocity));
             }
 
             touchPos = pos;
         }
 
-        public Overscroll getOverscroll() {
+        boolean overscrolled() {
+            return getOverscroll() != Overscroll.NONE;
+        }
+
+        private Overscroll getOverscroll() {
             boolean minus = (getOrigin() < 0.0f);
             boolean plus = (getViewportEnd() > getPageLength());
             if (minus && plus)
                 return Overscroll.BOTH;
             else if (minus)
                 return Overscroll.MINUS;
             else if (plus)
                 return Overscroll.PLUS;
             else
                 return Overscroll.NONE;
         }
 
         // Returns the amount that the page has been overscrolled. If the page hasn't been
         // overscrolled on this axis, returns 0.
-        public float getExcess() {
+        private float getExcess() {
             switch (getOverscroll()) {
             case MINUS:     return -getOrigin();
             case PLUS:      return getViewportEnd() - getPageLength();
             case BOTH:      return getViewportEnd() - getPageLength() - getOrigin();
             default:        return 0.0f;
             }
         }
 
@@ -805,45 +815,44 @@ public class PanZoomController
             if (stopped) {
                 setFlingState(FlingStates.STOPPED);
             } else {
                 setFlingState(FlingStates.FLINGING);
             }
         }
 
         /* Advances a fling animation by one step. */
-        public void advanceFling() {
-            // If we aren't overscrolled, just apply friction.
+        public boolean advanceFling() {
+            if (mFlingState != FlingStates.FLINGING) {
+                return false;
+            }
+
             float excess = getExcess();
             if (disableSnap || FloatUtils.fuzzyEquals(excess, 0.0f)) {
+                // If we aren't overscrolled, just apply friction.
                 if (Math.abs(velocity) >= VELOCITY_THRESHOLD) {
                     velocity *= FRICTION_FAST;
                 } else {
                     float t = velocity / VELOCITY_THRESHOLD;
                     velocity *= FloatUtils.interpolate(FRICTION_SLOW, FRICTION_FAST, t);
                 }
-
-                if (Math.abs(velocity) < FLING_STOPPED_THRESHOLD) {
-                    velocity = 0.0f;
-                    setFlingState(FlingStates.STOPPED);
-                }
-                return;
+            } else {
+                // Otherwise, decrease the velocity linearly.
+                float elasticity = 1.0f - excess / (getViewportLength() * SNAP_LIMIT);
+                if (getOverscroll() == Overscroll.MINUS)
+                    velocity = Math.min((velocity + OVERSCROLL_DECEL_RATE) * elasticity, 0.0f);
+                else // must be Overscroll.PLUS
+                    velocity = Math.max((velocity - OVERSCROLL_DECEL_RATE) * elasticity, 0.0f);
             }
+            return true;
+        }
 
-            // Otherwise, decrease the velocity linearly.
-            float elasticity = 1.0f - excess / (getViewportLength() * SNAP_LIMIT);
-            if (getOverscroll() == Overscroll.MINUS)
-                velocity = Math.min((velocity + OVERSCROLL_DECEL_RATE) * elasticity, 0.0f);
-            else // must be Overscroll.PLUS
-                velocity = Math.max((velocity - OVERSCROLL_DECEL_RATE) * elasticity, 0.0f);
-
-            if (Math.abs(velocity) < 0.3f) {
-                velocity = 0.0f;
-                setFlingState(FlingStates.STOPPED);
-            }
+        void stopFling() {
+            velocity = 0.0f;
+            setFlingState(FlingStates.STOPPED);
         }
 
         // Performs displacement of the viewport position according to the current velocity.
         public void displace(boolean panningOverridden) {
             if (!panningOverridden && (locked || !scrollable()))
                 return;
 
             if (mFlingState == FlingStates.PANNING)