Bug 587814 - Smoother panning using mozAnimationFrame [r=mfinkle]
authorBenjamin Stover <bstover@mozilla.com>
Mon, 16 Aug 2010 20:58:26 -0700
changeset 66443 fbf4a8bf612cd8c4ba42f8c3f990a17f74139917
parent 66442 3d135a627fa4fd02700d45207868de9004cbb91f
child 66444 4ab11d2060b33ca6a3f2533cfa285944d1db199c
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)
reviewersmfinkle
bugs587814
Bug 587814 - Smoother panning using mozAnimationFrame [r=mfinkle]
mobile/chrome/content/InputHandler.js
--- a/mobile/chrome/content/InputHandler.js
+++ b/mobile/chrome/content/InputHandler.js
@@ -957,17 +957,16 @@ DragData.prototype = {
  * object was panned, false if there was no movement.
  *
  * There are two complicated things done here.  One is calculating the
  * initial velocity of the movement based on user input.  Two is
  * calculating the distance to move every frame.
  */
 function KineticController(aPanBy, aEndCallback) {
   this._panBy = aPanBy;
-  this._timer = null;
   this._beforeEnd = aEndCallback;
 
   // These are used to calculate the position of the scroll panes during kinetic panning. Think of
   // these points as vectors that are added together and multiplied by scalars.
   this._position = new Point(0, 0);
   this._velocity = new Point(0, 0);
   this._acceleration = new Point(0, 0);
   this._time = 0;
@@ -1030,29 +1029,28 @@ KineticController.prototype = {
 
     let lastx = this._position;  // track last position vector because pan takes differences
     let v0 = this._velocity;  // initial velocity
     let a = this._acceleration;  // acceleration
 
     // Temporary "bins" so that we don't create new objects during pan.
     let aBin = new Point(0, 0);
     let v0Bin = new Point(0, 0);
+    let self = this;
 
     let callback = {
-      _self: this,
-      notify: function kineticTimerCallback(timer) {
-        let self = this._self;
+      handleEvent: function kineticHandleEvent(event) {
 
         if (!self.isActive())  // someone called end() on us between timer intervals
           return;
 
         // To make animation end fast enough but to keep smoothness, average the ideal
         // time frame (smooth animation) with the actual time lapse (end fast enough).
         // Animation will never take longer than 2 times the ideal length of time.
-        let realt = Date.now() - self._initialTime;
+        let realt = event.timeStamp - self._initialTime;
         self._time += self._updateInterval;
         let t = (self._time + realt) / 2;
 
         // Calculate new position using x(t) formula.
         let x = v0Bin.set(v0).scale(t).add(aBin.set(a).scale(0.5 * t * t));
         let dx = x.x - lastx.x;
         let dy = x.y - lastx.y;
         lastx.set(x);
@@ -1074,24 +1072,24 @@ KineticController.prototype = {
           v0.y = 0;
           a.y = 0;
         }
 
         let panned = false;
         try { panned = self._panBy(Math.round(-dx), Math.round(-dy)); } catch (e) {}
         if (!panned)
           self.end();
+        else
+          mozRequestAnimationFrame();
       }
     };
 
-    this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
-    //initialize our timer with updateInterval
-    this._timer.initWithCallback(callback,
-                                 this._updateInterval,
-                                 this._timer.TYPE_REPEATING_SLACK);
+    this._callback = callback;
+    addEventListener("MozBeforePaint", callback, false);
+    mozRequestAnimationFrame();
   },
 
   start: function start() {
     function sign(x) {
       return x ? ((x > 0) ? 1 : -1) : 0;
     }
 
     let mb = this.momentumBuffer;
@@ -1115,17 +1113,17 @@ KineticController.prototype = {
     // Only allow kinetic scrolling to speed up if kinetic scrolling is active.
     this._velocity.x = (distanceX < 0 ? Math.min : Math.max)((distanceX / swipeLength) * this._speedSensitivity, this._velocity.x);
     this._velocity.y = (distanceY < 0 ? Math.min : Math.max)((distanceY / swipeLength) * this._speedSensitivity, this._velocity.y);
 
     // Set acceleration vector to opposite signs of velocity
     this._acceleration.set(this._velocity.clone().map(sign).scale(-this._decelerationRate));
 
     this._position.set(0, 0);
-    this._initialTime = Date.now();
+    this._initialTime = mozAnimationStartTime;
     this._time = 0;
     this.momentumBuffer = [];
 
     if (!this.isActive())
       this._startTimer();
 
     return true;
   },