Bug 1349828 Smooth scroller of <scrollbox> should not try to scroll to outside of the range r?mstange draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Mon, 10 Apr 2017 19:56:40 +0900
changeset 560141 b47ff808beef2d050a6a0ef62a3d45a46e4ae04b
parent 559365 45692c884fdd5136a64fb2f8a61a0c8183b69331
child 623622 3776c5644f1a1b53f40ea3817bd0c19c07098988
push id53341
push usermasayuki@d-toybox.com
push dateTue, 11 Apr 2017 06:43:03 +0000
reviewersmstange
bugs1349828
milestone55.0a1
Bug 1349828 Smooth scroller of <scrollbox> should not try to scroll to outside of the range r?mstange 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
@@ -335,34 +335,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;
           }
@@ -389,16 +394,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)