Backed out changeset c0c635e938fa (bug 1368208) for eslint and reftest 508816-1-ref.xul failures
authorPhil Ringnalda <philringnalda@gmail.com>
Mon, 29 May 2017 12:34:16 -0700
changeset 361125 2d19d1d3f8aab615255a27338dc00258004ad0d7
parent 361124 84a99d06f8db2902ff4c6b41d9fd2c9f71a4d09d
child 361126 b76a023ad0c12b4e7f4992d0e915b4de354c1f3a
push id31917
push usercbook@mozilla.com
push dateTue, 30 May 2017 09:14:52 +0000
treeherdermozilla-central@0c712d76d598 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1368208, 508816
milestone55.0a1
backs outc0c635e938fa8e84cedec58bfe7b1543a67a7d8e
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
Backed out changeset c0c635e938fa (bug 1368208) for eslint and reftest 508816-1-ref.xul failures CLOSED TREE MozReview-Commit-ID: LcPpCIciePj
toolkit/content/widgets/scrollbox.xml
--- a/toolkit/content/widgets/scrollbox.xml
+++ b/toolkit/content/widgets/scrollbox.xml
@@ -180,68 +180,57 @@
           var innerRect = {};
           innerRect.left = outerRect.left - this._scrollbox.scrollLeft;
           innerRect.top = outerRect.top - this._scrollbox.scrollTop;
           innerRect.right = innerRect.left + this._scrollbox.scrollWidth;
           innerRect.bottom = innerRect.top + this._scrollbox.scrollHeight;
           return innerRect;
         ]]></getter>
       </property>
-      <field name="scrollboxPaddingStart"><![CDATA[
-        let paddingStart = this.orient == "vertical" ? "paddingTop" :
-              (this._isRTLScrollbox ? "paddingRight" : "paddingLeft");
-        parseFloat(window.getComputedStyle(this._scrollbox)[paddingStart]);
-      ]]></field>
-      <field name="scrollboxPaddingEnd"><![CDATA[{
-        let paddingEnd = this.orient == "vertical" ? "paddingBottom" :
-              (this._isRTLScrollbox ? "paddingLeft" : "paddingRight");
-        parseFloat(window.getComputedStyle(this._scrollbox)[paddingEnd]);
-      }]]></field>
+      <property name="scrollboxPaddingStart" readonly="true">
+        <getter><![CDATA[
+          var ltr = (window.getComputedStyle(this).direction == "ltr");
+          var paddingStartName = ltr ? "padding-left" : "padding-right";
+          var scrollboxStyle = window.getComputedStyle(this._scrollbox);
+          return parseFloat(scrollboxStyle.getPropertyValue(paddingStartName));
+        ]]></getter>
+      </property>
       <property name="scrollPosition">
         <getter><![CDATA[
           return this.orient == "vertical" ?
                  this._scrollbox.scrollTop :
                  this._scrollbox.scrollLeft;
         ]]></getter>
         <setter><![CDATA[
           if (this.orient == "vertical")
             this._scrollbox.scrollTop = val;
           else
             this._scrollbox.scrollLeft = val;
           return val;
         ]]></setter>
       </property>
 
-      <field name="_startEndProps"><![CDATA[
-        this.orient == "vertical" ?
-          ["top", "bottom"] : ["left", "right"];
-      ]]></field>
+      <property name="_startEndProps" readonly="true">
+        <getter><![CDATA[
+          return this.orient == "vertical" ?
+                 ["top", "bottom"] : ["left", "right"];
+        ]]></getter>
+      </property>
 
       <field name="_isRTLScrollbox"><![CDATA[
         this.orient != "vertical" &&
         document.defaultView.getComputedStyle(this._scrollbox).direction == "rtl";
       ]]></field>
 
       <field name="_scrollTarget">null</field>
 
       <method name="_canScrollToElement">
         <parameter name="element"/>
         <body><![CDATA[
-          if (element.hidden) {
-            return false;
-          }
-
-          // See if the element is hidden via CSS without the hidden attribute.
-          // If we get only zeros for the client rect, this means the element
-          // is hidden. As a performance optimization, we don't flush layout
-          // here which means that on the fly changes aren't fully supported.
-          let rect = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-                           .getInterface(Components.interfaces.nsIDOMWindowUtils)
-                           .getBoundsWithoutFlushing(element);
-          return !!(rect.top || rect.left || rect.width || rect.height);
+          return window.getComputedStyle(element).display != "none";
         ]]></body>
       </method>
 
       <method name="ensureElementIsVisible">
         <parameter name="element"/>
         <parameter name="aSmoothScroll"/>
         <body><![CDATA[
           if (!this._canScrollToElement(element))
@@ -617,86 +606,50 @@
           if (this._isScrolling) {
             this._scrollAnim.stop();
             this._isScrolling = 0;
             this._scrollTarget = null;
           }
         ]]></body>
       </method>
 
-      <field name="_scrollButtonUpdatePending">false</field>
       <method name="_updateScrollButtonsDisabledState">
+        <parameter name="aScrolling"/>
         <body><![CDATA[
-          if (this._scrollButtonUpdatePending) {
-            return;
-          }
-          this._scrollButtonUpdatePending = true;
+          let scrolledToStart;
+          let scrolledToEnd;
 
+          // Avoid flushing layout when not overflowing or when scrolling.
           if (this.hasAttribute("notoverflowing")) {
-            // Invalidate layout lazily before painting the next frame.
-            window.requestAnimationFrame(() => {
-              this._scrollButtonUpdatePending = false;
-
-              this.setAttribute("scrolledtoend", "true");
-              this.setAttribute("scrolledtostart", "true");
-            });
-            return;
+            scrolledToStart = true;
+            scrolledToEnd = true;
+          } else if (aScrolling) {
+            scrolledToStart = false;
+            scrolledToEnd = false;
+          } else if (this.scrollPosition == 0) {
+            // In the RTL case, this means the _last_ element in the
+            // scrollbox is visible
+            scrolledToEnd = this._isRTLScrollbox;
+            scrolledToStart = !this._isRTLScrollbox;
+          } else if (this.scrollClientSize + this.scrollPosition == this.scrollSize) {
+            // In the RTL case, this means the _first_ element in the
+            // scrollbox is visible
+            scrolledToStart = this._isRTLScrollbox;
+            scrolledToEnd = !this._isRTLScrollbox;
           }
 
-          // Wait until after the next paint to get current layout data from
-          // getBoundsWithoutFlushing.
-          window.requestAnimationFrame(() => {
-            window.requestAnimationFrame(() => {
-              this._scrollButtonUpdatePending = false;
-
-              let scrolledToStart = false;
-              let scrolledToEnd = false;
-
-              if (this.hasAttribute("notoverflowing")) {
-                scrolledToStart = true;
-                scrolledToEnd = true;
-              } else {
-                let scrollboxPaddingStart = Math.round(this.scrollboxPaddingStart);
-                let scrollboxPaddingEnd = Math.round(this.scrollboxPaddingEnd);
-                let [start, end] = this._startEndProps;
-                if (this._isRTLScrollbox) {
-                  [start, end] = [end, start];
-                  scrollboxPaddingStart = -scrollboxPaddingStart;
-                  scrollboxPaddingEnd = -scrollboxPaddingEnd;
-                }
+          if (scrolledToEnd)
+            this.setAttribute("scrolledtoend", "true");
+          else
+            this.removeAttribute("scrolledtoend");
 
-                let windowUtils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-                                        .getInterface(Components.interfaces.nsIDOMWindowUtils);
-                let rect = ele => windowUtils.getBoundsWithoutFlushing(ele);
-                let scrollboxRect = rect(this._scrollbox);
-                let elements = this._getScrollableElements();
-                let [firstElement, lastElement] = [elements[0], elements[elements.length - 1]];
-
-                if (firstElement &&
-                    rect(firstElement)[start] - scrollboxPaddingStart == scrollboxRect[start]) {
-                  scrolledToStart = true;
-                } else if (lastElement &&
-                           rect(lastElement)[end] + scrollboxPaddingEnd == scrollboxRect[end]) {
-                  scrolledToEnd = true;
-                }
-              }
-
-              if (scrolledToEnd) {
-                this.setAttribute("scrolledtoend", "true");
-              } else {
-                this.removeAttribute("scrolledtoend");
-              }
-
-              if (scrolledToStart) {
-                this.setAttribute("scrolledtostart", "true");
-              } else {
-                this.removeAttribute("scrolledtostart");
-              }
-            });
-          });
+          if (scrolledToStart)
+            this.setAttribute("scrolledtostart", "true");
+          else
+            this.removeAttribute("scrolledtostart");
         ]]></body>
       </method>
     </implementation>
 
     <handlers>
       <handler event="wheel"><![CDATA[
         let doScroll = false;
         let useSmoothScroll = event.deltaMode != event.DOM_DELTA_PIXEL && this.smoothScroll;
@@ -839,17 +792,37 @@
           // as the whole overflow event should not be happening in that case.
           this._updateScrollButtonsDisabledState();
         } catch (e) {
           this.setAttribute("notoverflowing", "true");
         }
       ]]></handler>
 
       <handler event="scroll"><![CDATA[
-        this._updateScrollButtonsDisabledState();
+        if (!this._delayedUpdateScrollButtonsTimer) {
+          // This is the beginning of a scrolling animation. We need to update
+          // scroll buttons now in case we were scrolled to the start or to the
+          // end before we started scrolling.
+          this._updateScrollButtonsDisabledState(true);
+        } else {
+          // We're in the middle of the scrolling animation. We'll restart the
+          // delayed update request so that we only update the scroll buttons
+          // a second time once we're done scrolling.
+          window.clearTimeout(this._delayedUpdateScrollButtonsTimer);
+        }
+
+        // Try to detect the end of the scrolling animation to update the
+        // scroll buttons again. To avoid false positives, this timeout needs
+        // to be big enough to account for intermediate frames that don't move
+        // the scroll position in case we're scrolling slowly.
+        this._delayedUpdateScrollButtonsTimer = setTimeout(() => {
+          // Scrolling animation has finished.
+          this._delayedUpdateScrollButtonsTimer = 0;
+          this._updateScrollButtonsDisabledState();
+        }, 200);
       ]]></handler>
     </handlers>
   </binding>
 
   <binding id="autorepeatbutton" extends="chrome://global/content/bindings/scrollbox.xml#scrollbox-base">
     <content repeat="hover">
       <xul:image class="autorepeatbutton-icon"/>
     </content>