Bug 586621 - Use animation-scheduling API for smooth scrollbox scrolling. r=enn a=joe
authorDão Gottwald <dao@mozilla.com>
Sat, 21 Aug 2010 07:16:33 +0200
changeset 51161 5c5c3bf8dfeb14ee91516997172dfe0f8e10af21
parent 51160 8f2e9f567713fb4ad50ce5d6716c3a02e48e70d3
child 51162 2cfcf5515e1b38d6cbaa0e6f901bbd9dabe18cdf
push id15228
push userdgottwald@mozilla.com
push dateSat, 21 Aug 2010 08:53:57 +0000
treeherdermozilla-central@5c5c3bf8dfeb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersenn, joe
bugs586621
milestone2.0b5pre
first release with
nightly linux32
5c5c3bf8dfeb / 4.0b5pre / 20100821031041 / files
nightly linux64
5c5c3bf8dfeb / 4.0b5pre / 20100821030729 / files
nightly mac
5c5c3bf8dfeb / 4.0b5pre / 20100821031035 / files
nightly win32
5c5c3bf8dfeb / 4.0b5pre / 20100821040844 / files
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
Bug 586621 - Use animation-scheduling API for smooth scrollbox scrolling. r=enn a=joe
toolkit/content/widgets/scrollbox.xml
--- a/toolkit/content/widgets/scrollbox.xml
+++ b/toolkit/content/widgets/scrollbox.xml
@@ -220,59 +220,50 @@
         <parameter name="amountToScroll"/>
         <body><![CDATA[
           if (amountToScroll == 0)
             return;
 
           this._stopSmoothScroll();
 
           // Positive amountToScroll makes us scroll right (elements fly left), negative scrolls left.
-          var round;
-          if (amountToScroll < 0) {
-            this._isScrolling = -1;
-            round = Math.floor;
-          } else {
-            this._isScrolling = 1;
-            round = Math.ceil;
-          }
-
-          const FRAME_LENGTH = 60;
-
-          function processFrame(self, scrollAmounts, off) {
-            var distance = scrollAmounts.shift();
-
-            // Skip frames if we aren't getting the desired frame rate.
-            if (off > 0) {
-              for (var i = Math.round(off / FRAME_LENGTH); i > 0; i--)
-                distance += scrollAmounts.shift() || 0;
-            }
+          this._isScrolling = amountToScroll < 0 ? -1 : 1;
 
-            self.scrollByPixels(distance);
-            if (!scrollAmounts.length)
-              self._stopSmoothScroll();
-          }
-
-          // amountToScroll: total distance to scroll
-          // scrollAmount: distance to move during the particular effect frame (60ms)
-          var scrollAmount, scrollAmounts = [];
-          if (amountToScroll > 2 || amountToScroll < -2) {
-            scrollAmount = round(amountToScroll * 0.2);
-            scrollAmounts.push(scrollAmount, scrollAmount, scrollAmount);
-            amountToScroll -= 3 * scrollAmount;
-          }
-          while (this._isScrolling < 0 && amountToScroll < 0 ||
-                 this._isScrolling > 0 && amountToScroll > 0) {
-            amountToScroll -= (scrollAmount = round(amountToScroll * 0.5));
-            scrollAmounts.push(scrollAmount);
-          }
-          this._smoothScrollTimer = setInterval(processFrame, FRAME_LENGTH, this, scrollAmounts);
-          processFrame(this, scrollAmounts, 0);
+          this._scrollAnim.start(amountToScroll);
         ]]></body>
       </method>
 
+      <field name="_scrollAnim"><![CDATA[({
+        scrollbox: this,
+        start: function scrollAnim_start(distance) {
+          this.distance = distance;
+          this.startPos = this.scrollbox.scrollPosition;
+          this.duration = Math.min(1000, Math.round(50 * Math.sqrt(Math.abs(distance))));
+          this.startTime = window.mozAnimationStartTime;
+
+          window.addEventListener("MozBeforePaint", this, false);
+          window.mozRequestAnimationFrame();
+        },
+        stop: function scrollAnim_stop() {
+          window.removeEventListener("MozBeforePaint", this, false);
+        },
+        handleEvent: function scrollAnim_handleEvent(event) {
+          const timePassed = event.timeStamp - this.startTime;
+          const pos = timePassed >= this.duration ? 1 :
+                      1 - Math.pow(1 - timePassed / this.duration, 2);
+
+          this.scrollbox.scrollPosition = this.startPos + (this.distance * pos);
+
+          if (pos == 1)
+            this.scrollbox._stopSmoothScroll();
+          else
+            window.mozRequestAnimationFrame();
+        }
+      })]]></field>
+
       <method name="scrollByIndex">
         <parameter name="index"/>
         <parameter name="aSmoothScroll"/>
         <body><![CDATA[
           if (index == 0)
             return;
 
           // Each scrollByIndex call is expected to scroll the given number of
@@ -388,23 +379,22 @@
           this.scrollPosition += px;
         ]]></body>
       </method>
 
       <!-- 0: idle
            1: scrolling right
           -1: scrolling left -->
       <field name="_isScrolling">0</field>
-      <field name="_smoothScrollTimer">0</field>
       <field name="_prevMouseScrolls">[null, null]</field>
 
       <method name="_stopSmoothScroll">
         <body><![CDATA[
           if (this._isScrolling) {
-            clearInterval(this._smoothScrollTimer);
+            this._scrollAnim.stop();
             this._isScrolling = 0;
             this._scrollTarget = null;
           }
         ]]></body>
       </method>
 
       <method name="_updateScrollButtonsDisabledState">
         <body><![CDATA[