Bug 1349828 Smooth scroller of <scrollbox> should not try to scroll to outside of the range. r=mstange. a=gchang
authorMasayuki Nakano <masayuki@d-toybox.com>
Mon, 10 Apr 2017 19:56:40 +0900
changeset 375956 9ac3ed4401b5
parent 375955 8059a9af7490
child 375957 1388c6f3d0aa
push id11066
push userihsiao@mozilla.com
push date2017-04-18 08:21 +0000
treeherdermozilla-aurora@b7cdc8cfc61f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange, gchang
bugs1349828
milestone54.0a2
Bug 1349828 Smooth scroller of <scrollbox> should not try to scroll to outside of the range. r=mstange. a=gchang The scroll destination of the smooth scroller of <scrollbox> can be outside of the actual scrollable range. Therefore, it doesn't make scroll slower even when the end appears. This patch makes the destination always in the scrollable range. MozReview-Commit-ID: CfEGzhG7Jh7
toolkit/content/widgets/scrollbox.xml
--- a/toolkit/content/widgets/scrollbox.xml
+++ b/toolkit/content/widgets/scrollbox.xml
@@ -343,34 +343,39 @@
         // a part of continous scroll, for example, it's caused by turning mosue wheel.
         start: function scrollAnim_start(distance, isContinuousScroll) {
           // When it's a continous scroll and the scroll was started, this needs to
           // respect preceding scroll requests.  For example, 1.5px scroll occurs 2 times,
           // 3px should be scrolled.  So, fractional values shouldn't be discarded.
           if (isContinuousScroll && this.distance) {
             // |this.startPos| is integer due to cache of |.scrollPosition|.  Therefore,
             // we need to manage actual destination with |this.destination|.
-            this.destination += distance;
+            var oldDestination = this.destination;
+            this.destination = this._clampPosition(this.destination + distance);
+
+            // If scroll position has already reached the ends, we need to do nothing.
+            if (oldDestination == this.destination)
+              return;
 
             // If the integer part of the destination isn't changed, we need to do
             // nothing now, wait next event.
             if (Math.trunc(this.destination) == Math.trunc(this.destination - distance))
               return;
 
             // Let's restart animation from current position to the new destination.
             if (this.requestHandle) {
               this.stop();
               this.startPos = this.scrollbox.scrollPosition;
               // The call of |.stop()| causes clearing |this.distance| but let's recover it
               // for keeping continuous scroll.
               this.distance = this.destination - this.startPos;
             }
           } else {
             this.startPos = this.scrollbox.scrollPosition;
-            this.destination = this.startPos + distance;
+            this.destination = this._clampPosition(this.startPos + distance);
             this.distance = this.destination - this.startPos;
 
             // If absolute value of |this.distance| is less than 1px and this call is
             // start of a continous scroll, should wait to scroll until accumulated
             // scroll amount becomes 1px or greater.
             if (isContinuousScroll && Math.abs(this.distance) < 1)
               return;
           }
@@ -397,16 +402,27 @@
                       1 - Math.pow(1 - timePassed / this.duration, 4);
 
           this.scrollbox.scrollPosition = this.startPos + (this.distance * pos);
 
           if (pos == 1)
             this.scrollbox._stopSmoothScroll();
           else
             this.requestHandle = window.requestAnimationFrame(this.sample.bind(this));
+        },
+
+        _clampPosition: function scrollAnim_clampPosition(aScrollPosition) {
+          if (aScrollPosition < 0) {
+            return 0;
+          }
+          var maxPos = this.scrollbox.scrollSize - this.scrollbox.scrollClientSize;
+          if (aScrollPosition > maxPos) {
+            return maxPos;
+          }
+          return aScrollPosition;
         }
       })]]></field>
 
       <method name="scrollByIndex">
         <parameter name="index"/>
         <parameter name="aSmoothScroll"/>
         <body><![CDATA[
           if (index == 0)