Bug #1454358, removes unneccessary implementation of ScrollBoxObject rr?enndeakin+6102 r?bz draft
authorEmma Malysz <emalysz@mozilla.com>
Wed, 06 Jun 2018 16:02:04 -0700
changeset 809271 3687a9a2a048c961e198b5eb4b8f93a5c695e52f
parent 807449 8abb9c450e135976702a77dc9bcb82898496c66d
push id113611
push userbmo:emalysz@mozilla.com
push dateThu, 21 Jun 2018 17:25:07 +0000
reviewersbz
bugs1454358
milestone62.0a1
Bug #1454358, removes unneccessary implementation of ScrollBoxObject rr?enndeakin+6102 r?bz MozReview-Commit-ID: LBQ0RoS0ZVc
browser/components/places/content/menu.xml
devtools/client/shared/widgets/FastListWidget.js
devtools/client/shared/widgets/SideMenuWidget.jsm
devtools/client/shared/widgets/SimpleListWidget.jsm
devtools/client/shared/widgets/VariablesView.jsm
dom/base/Element.h
dom/base/nsDocument.cpp
dom/bindings/Bindings.conf
dom/chrome-webidl/XULScrollElement.webidl
dom/chrome-webidl/moz.build
dom/events/test/test_bug602962.xul
dom/tests/mochitest/general/test_interfaces.js
dom/webidl/ScrollBoxObject.webidl
dom/webidl/moz.build
dom/xul/XULScrollElement.cpp
dom/xul/XULScrollElement.h
dom/xul/moz.build
dom/xul/nsXULElement.cpp
layout/build/nsLayoutCID.h
layout/build/nsLayoutModule.cpp
layout/reftests/invalidation/540247-1-ref.xul
layout/reftests/invalidation/540247-1.xul
layout/xul/ScrollBoxObject.cpp
layout/xul/ScrollBoxObject.h
layout/xul/moz.build
testing/mochitest/browser-harness.xul
toolkit/content/tests/chrome/test_position.xul
toolkit/modules/SelectParentHelper.jsm
--- a/browser/components/places/content/menu.xml
+++ b/browser/components/places/content/menu.xml
@@ -78,19 +78,19 @@
             var dropPoint = { ip: null, folderElt: null };
 
             // The element we are dragging over
             let elt = aEvent.target;
             if (elt.localName == "menupopup")
               elt = elt.parentNode;
 
             // Calculate positions taking care of arrowscrollbox
-            let scrollbox = this._scrollbox;
+            let scrollbox = this._scrollBox;
             let eventY = aEvent.layerY + (scrollbox.boxObject.y - this.boxObject.y);
-            let scrollboxOffset = this.boxObject.y;
+            let scrollboxOffset = scrollbox.boxObject.y;
             let eltY = elt.boxObject.y - scrollboxOffset;
             let eltHeight = elt.boxObject.height;
 
             if (!elt._placesNode) {
               // If we are dragging over a non places node drop at the end.
               dropPoint.ip = new PlacesInsertionPoint({
                 parentId: PlacesUtils.getConcreteItemId(resultNode),
                 parentGuid: PlacesUtils.getConcreteItemGuid(resultNode)
@@ -428,30 +428,30 @@
         if (dropPoint.folderElt || this._hideDropIndicator(event)) {
           this._indicatorBar.hidden = true;
           event.preventDefault();
           event.stopPropagation();
           return;
         }
 
         // We should display the drop indicator relative to the arrowscrollbox.
-        let sbo = this.boxObject;
+        let sbo = this._scrollBox.boxObject;
         let newMarginTop = 0;
         if (scrollDir == 0) {
           let elt = this.firstChild;
           while (elt && event.screenY > elt.boxObject.screenY +
                                         elt.boxObject.height / 2)
             elt = elt.nextSibling;
           newMarginTop = elt ? elt.boxObject.screenY - sbo.screenY :
                                sbo.height;
         } else if (scrollDir == 1)
           newMarginTop = sbo.height;
 
         // Set the new marginTop based on arrowscrollbox.
-        newMarginTop += sbo.y - this.boxObject.y;
+        newMarginTop += sbo.y - this._scrollBox.boxObject.y;
         this._indicatorBar.firstChild.style.marginTop = newMarginTop + "px";
         this._indicatorBar.hidden = false;
 
         event.preventDefault();
         event.stopPropagation();
       ]]></handler>
 
       <handler event="dragexit"><![CDATA[
--- a/devtools/client/shared/widgets/FastListWidget.js
+++ b/devtools/client/shared/widgets/FastListWidget.js
@@ -188,19 +188,19 @@ FastListWidget.prototype = {
    *        The element to make visible.
    */
   ensureElementIsVisible: function(element) {
     if (!element) {
       return;
     }
 
     // Ensure the element is visible but not scrolled horizontally.
-    const boxObject = this._list.boxObject;
-    boxObject.ensureElementIsVisible(element);
-    boxObject.scrollBy(-this._list.clientWidth, 0);
+    const scrollbox = this._list;
+    scrollbox.ensureElementIsVisible(element);
+    scrollbox.scrollBy(-this._list.clientWidth, 0);
   },
 
   /**
    * Sets the text displayed in this container when empty.
    * @param string aValue
    */
   set _textWhenEmpty(value) {
     if (this._emptyTextNode) {
--- a/devtools/client/shared/widgets/SideMenuWidget.jsm
+++ b/devtools/client/shared/widgets/SideMenuWidget.jsm
@@ -222,19 +222,19 @@ SideMenuWidget.prototype = {
    *        The element to make visible.
    */
   ensureElementIsVisible: function(aElement) {
     if (!aElement) {
       return;
     }
 
     // Ensure the element is visible but not scrolled horizontally.
-    const boxObject = this._list.boxObject;
-    boxObject.ensureElementIsVisible(aElement);
-    boxObject.scrollBy(-this._list.clientWidth, 0);
+    const scrollbox = this._list;
+    scrollbox.ensureElementIsVisible(aElement);
+    scrollbox.scrollBy(-this._list.clientWidth, 0);
   },
 
   /**
    * Shows all the groups, even the ones with no visible children.
    */
   showEmptyGroups: function() {
     for (const group of this._orderedGroupElementsArray) {
       group.hidden = false;
--- a/devtools/client/shared/widgets/SimpleListWidget.jsm
+++ b/devtools/client/shared/widgets/SimpleListWidget.jsm
@@ -165,19 +165,19 @@ SimpleListWidget.prototype = {
    *        The element to make visible.
    */
   ensureElementIsVisible: function(aElement) {
     if (!aElement) {
       return;
     }
 
     // Ensure the element is visible but not scrolled horizontally.
-    const boxObject = this._list.boxObject;
-    boxObject.ensureElementIsVisible(aElement);
-    boxObject.scrollBy(-this._list.clientWidth, 0);
+    const scrollbox = this._list;
+    scrollbox.ensureElementIsVisible(aElement);
+    scrollbox.scrollBy(-this._list.clientWidth, 0);
   },
 
   /**
    * Sets the text displayed permanently in this container as a header.
    * @param string aValue
    */
   set _textAsHeader(aValue) {
     if (this._headerTextNode) {
--- a/devtools/client/shared/widgets/VariablesView.jsm
+++ b/devtools/client/shared/widgets/VariablesView.jsm
@@ -786,17 +786,17 @@ VariablesView.prototype = {
   _focusItem: function(aItem, aCollapseFlag) {
     if (!aItem.focusable) {
       return false;
     }
     if (aCollapseFlag) {
       aItem.collapse();
     }
     aItem._target.focus();
-    this.boxObject.ensureElementIsVisible(aItem._arrow);
+    this._list.ensureElementIsVisible(aItem._arrow);
     return true;
   },
 
   /**
    * Listener handling a key down event on the view.
    */
   _onViewKeyDown: function(e) {
     const item = this.getFocusedItem();
@@ -3970,17 +3970,17 @@ Editable.prototype = {
     // element's specified label location.
     const input = this._input = this._variable.document.createElement("textbox");
     input.className = "plain " + this.className;
     input.setAttribute("value", initialString);
     input.setAttribute("flex", "1");
 
     // Replace the specified label with a textbox input element.
     label.parentNode.replaceChild(input, label);
-    this._variable._variablesView.boxObject.ensureElementIsVisible(input);
+    this._variable._variablesView._list.ensureElementIsVisible(input);
     input.select();
 
     // When the value is a string (displayed as "value"), then we probably want
     // to change it to another string in the textbox, so to avoid typing the ""
     // again, tackle with the selection bounds just a bit.
     if (initialString.match(/^".+"$/)) {
       input.selectionEnd--;
       input.selectionStart++;
@@ -4004,18 +4004,18 @@ Editable.prototype = {
    * state.
    */
   deactivate: function() {
     this._input.removeEventListener("keydown", this._onKeydown);
     this._input.removeEventListener("blur", this.deactivate);
     this._input.parentNode.replaceChild(this.label, this._input);
     this._input = null;
 
-    const { boxObject } = this._variable._variablesView;
-    boxObject.scrollBy(-this._variable._target, 0);
+    const scrollbox = this._variable._variablesView._list;
+    scrollbox.scrollBy(-this._variable._target, 0);
     this._variable.locked = false;
     this._variable.twisty = this._prevExpandable;
     this._variable.expanded = this._prevExpanded;
     this._variable.editing = false;
     this._onCleanup && this._onCleanup();
   },
 
   /**
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -572,16 +572,20 @@ protected:
   void RemoveStatesSilently(EventStates aStates)
   {
     mState &= ~aStates;
   }
 
   already_AddRefed<ShadowRoot> AttachShadowInternal(
     ShadowRootMode, ErrorResult& aError);
 
+  MOZ_CAN_RUN_SCRIPT
+  nsIScrollableFrame* GetScrollFrame(nsIFrame **aStyledFrame = nullptr,
+                                     FlushType aFlushType = FlushType::Layout);
+
 private:
   // Need to allow the ESM, nsGlobalWindow, and the focus manager to
   // set our state
   friend class mozilla::EventStateManager;
   friend class ::nsGlobalWindowInner;
   friend class ::nsGlobalWindowOuter;
   friend class ::nsFocusManager;
 
@@ -1956,20 +1960,16 @@ private:
   const nsAttrValue* GetSVGAnimatedClass() const;
 
   /**
    * Get this element's client area rect in app units.
    * @return the frame's client area
    */
   MOZ_CAN_RUN_SCRIPT nsRect GetClientAreaRect();
 
-  MOZ_CAN_RUN_SCRIPT
-  nsIScrollableFrame* GetScrollFrame(nsIFrame **aStyledFrame = nullptr,
-                                     FlushType aFlushType = FlushType::Layout);
-
   // Prevent people from doing pointless checks/casts on Element instances.
   void IsElement() = delete;
   void AsElement() = delete;
 
   // Data members
   EventStates mState;
   // Per-node data managed by Servo.
   //
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -249,17 +249,16 @@
 #include "mozilla/StyleSheet.h"
 #include "mozilla/StyleSheetInlines.h"
 #include "mozilla/dom/SVGSVGElement.h"
 #include "mozilla/dom/DocGroup.h"
 #include "mozilla/dom/TabGroup.h"
 #ifdef MOZ_XUL
 #include "mozilla/dom/ListBoxObject.h"
 #include "mozilla/dom/MenuBoxObject.h"
-#include "mozilla/dom/ScrollBoxObject.h"
 #include "mozilla/dom/TreeBoxObject.h"
 #include "nsIXULWindow.h"
 #include "nsIDocShellTreeOwner.h"
 #endif
 #include "nsIPresShellInlines.h"
 
 #include "mozilla/DocLoadingTimelineMarker.h"
 
@@ -6434,18 +6433,16 @@ nsIDocument::GetBoxObjectFor(Element* aE
 #ifdef MOZ_XUL
   if (namespaceID == kNameSpaceID_XUL) {
     if (tag == nsGkAtoms::menu) {
       boxObject = new MenuBoxObject();
     } else if (tag == nsGkAtoms::tree) {
       boxObject = new TreeBoxObject();
     } else if (tag == nsGkAtoms::listbox) {
       boxObject = new ListBoxObject();
-    } else if (tag == nsGkAtoms::scrollbox) {
-      boxObject = new ScrollBoxObject();
     } else {
       boxObject = new BoxObject();
     }
   } else
 #endif // MOZ_XUL
   {
     boxObject = new BoxObject();
   }
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -1371,17 +1371,17 @@ DOMInterfaces = {
     'nativeType': 'txMozillaXSLTProcessor',
 },
 
 'XULDocument': {
     'headerFile': 'XULDocument.h'
 },
 
 'XULElement': {
-    'nativeType': 'nsXULElement',
+    'nativeType': 'nsXULElement'
 },
 
 'XULTemplateBuilder': {
     'nativeType': 'nsXULTemplateBuilder',
 },
 
 'XULTreeBuilder': {
     'nativeType': 'nsXULTreeBuilder',
new file mode 100644
--- /dev/null
+++ b/dom/chrome-webidl/XULScrollElement.webidl
@@ -0,0 +1,14 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+[HTMLConstructor, Func="IsChromeOrXBL"]
+interface XULScrollElement : XULElement {
+
+  [Throws]
+  void scrollByIndex(long aIndexes);
+  [Throws]
+  void ensureElementIsVisible(Element child);
+};
--- a/dom/chrome-webidl/moz.build
+++ b/dom/chrome-webidl/moz.build
@@ -40,9 +40,10 @@ WEBIDL_FILES = [
     'MozStorageAsyncStatementParams.webidl',
     'MozStorageStatementParams.webidl',
     'MozStorageStatementRow.webidl',
     'PrecompiledScript.webidl',
     'PromiseDebugging.webidl',
     'StructuredCloneHolder.webidl',
     'WebExtensionContentScript.webidl',
     'WebExtensionPolicy.webidl',
+    'XULScrollElement.webidl',
 ]
--- a/dom/events/test/test_bug602962.xul
+++ b/dom/events/test/test_bug602962.xul
@@ -27,17 +27,17 @@ var win = null;
 function openWindow() {
   win = window.open("chrome://mochitests/content/chrome/dom/events/test/bug602962.xul", "_blank", "width=600,height=600");
 }
 
 function doTest() {
   scrollbox = win.document.getElementById("page-scrollbox");
   content = win.document.getElementById("page-box");
   content.style.width = 400 + "px";
-  
+
   win.addEventListener("resize", function() {
     win.removeEventListener("resize", arguments.callee, false);
 
     setTimeout(function(){
       scrollbox.scrollBy(200,0);
       resize();
     },0);
   }, false);
@@ -49,17 +49,17 @@ function doTest() {
 
 function resize() {
  scrollX = scrollbox.scrollLeft;
  scrollY = scrollbox.scrollTop;
 
   win.addEventListener("resize", function() {
     content.style.width = (oldWidth + 400) + "px";
     win.removeEventListener("resize", arguments.callee, true);
-    
+
     setTimeout(function() {
       finish();
     }, 0);
   }, true);
 
   win.resizeTo(oldWidth, oldHeight);
 }
 
--- a/dom/tests/mochitest/general/test_interfaces.js
+++ b/dom/tests/mochitest/general/test_interfaces.js
@@ -1248,16 +1248,18 @@ var interfaceNamesInGlobalScope =
     {name: "XULCommandEvent", insecureContext: true, xbl: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "XULDocument", insecureContext: true, xbl: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "XULElement", insecureContext: true, xbl: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "XULPopupElement", insecureContext: true, xbl: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "XULScrollElement", insecureContext: true, xbl: true},
+// IMPORTANT: Do not change this list without review from a DOM peer!
   ];
 // IMPORTANT: Do not change the list above without review from a DOM peer!
 
 function createInterfaceMap(isXBLScope) {
   var interfaceMap = {};
 
   function addInterfaces(interfaces)
   {
deleted file mode 100644
--- a/dom/webidl/ScrollBoxObject.webidl
+++ /dev/null
@@ -1,70 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-[NoInterfaceObject]
-interface ScrollBoxObject : BoxObject {
-
-  /**
-   * Scroll to the given coordinates, in css pixels.
-   * (0,0) will put the top left corner of the scrolled element's padding-box
-   * at the top left corner of the scrollport (which is its inner-border-box).
-   * Values will be clamped to legal values.
-   */
-  [Throws]
-  void scrollTo(long x, long y);
-
-  /**
-   * Scroll the given amount of device pixels to the right and down.
-   * Values will be clamped to make the resuling position legal.
-   */
-  [Throws]
-  void scrollBy(long dx, long dy);
-  [Throws]
-  void scrollByLine(long dlines);
-  [Throws]
-  void scrollByIndex(long dindexes);
-  [Throws]
-  void scrollToLine(long line);
-  [Throws]
-  void scrollToElement(Element child);
-  [Throws]
-  void scrollToIndex(long index);
-
-  /**
-   * Get the current scroll position in css pixels.
-   * @see scrollTo for the definition of x and y.
-   */
-  [Pure, Throws]
-  readonly attribute long positionX;
-  [Pure, Throws]
-  readonly attribute long positionY;
-  [Pure, Throws]
-  readonly attribute long scrolledWidth;
-  [Pure, Throws]
-  readonly attribute long scrolledHeight;
-
-  /**
-   * DEPRECATED: Please use positionX and positionY
-   *
-   * Get the current scroll position in css pixels.
-   * @see scrollTo for the definition of x and y.
-   */
-  [Throws]
-  void getPosition(object x, object y);
-
-  /**
-   * DEPRECATED: Please use scrolledWidth and scrolledHeight
-   */
-  [Throws]
-  void getScrolledSize(object width, object height);
-
-  [Throws]
-  void ensureElementIsVisible(Element child);
-  [Throws]
-  void ensureIndexIsVisible(long index);
-  [Throws]
-  void ensureLineIsVisible(long line);
-};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -737,17 +737,16 @@ WEBIDL_FILES = [
     'Range.webidl',
     'Request.webidl',
     'Response.webidl',
     'RTCStatsReport.webidl',
     'Screen.webidl',
     'ScreenOrientation.webidl',
     'ScriptProcessorNode.webidl',
     'ScrollAreaEvent.webidl',
-    'ScrollBoxObject.webidl',
     'Selection.webidl',
     'ServiceWorker.webidl',
     'ServiceWorkerContainer.webidl',
     'ServiceWorkerGlobalScope.webidl',
     'ServiceWorkerRegistration.webidl',
     'ShadowRoot.webidl',
     'SharedWorker.webidl',
     'SharedWorkerGlobalScope.webidl',
new file mode 100644
--- /dev/null
+++ b/dom/xul/XULScrollElement.cpp
@@ -0,0 +1,178 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/Element.h"
+#include "mozilla/dom/ToJSValue.h"
+#include "nsCOMPtr.h"
+#include "nsIPresShell.h"
+#include "nsIContent.h"
+#include "nsPresContext.h"
+#include "nsBox.h"
+#include "nsIScrollableFrame.h"
+#include "mozilla/dom/XULScrollElement.h"
+#include "mozilla/dom/XULScrollElementBinding.h"
+
+namespace mozilla {
+namespace dom {
+
+nsXULElement*
+NS_NewXULScrollElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
+{
+  return new XULScrollElement(aNodeInfo);
+}
+
+JSObject*
+XULScrollElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
+{
+  return XULScrollElementBinding::Wrap(aCx, this, aGivenProto);
+}
+
+void
+XULScrollElement::ScrollByIndex(int32_t aIndex, ErrorResult& aRv)
+{
+    nsIScrollableFrame* sf = GetScrollFrame();
+    if (!sf) {
+      aRv.Throw(NS_ERROR_FAILURE);
+      return;
+    }
+
+    nsIFrame* scrolledFrame = sf->GetScrolledFrame();
+    scrolledFrame = nsBox::GetChildXULBox(scrolledFrame);
+    if (!scrolledFrame){
+      aRv.Throw(NS_ERROR_FAILURE);
+      return;
+    }
+
+    nsRect rect;
+
+    // now get the element's first child 
+    nsIFrame* child = nsBox::GetChildXULBox(scrolledFrame);
+
+    bool horiz = scrolledFrame->IsXULHorizontal();
+    nsPoint cp = sf->GetScrollPosition();
+    nscoord diff = 0;
+    int32_t curIndex = 0;
+    bool isLTR = scrolledFrame->IsXULNormalDirection();
+
+    int32_t frameWidth = 0;
+    if (!isLTR && horiz) {
+      nsCOMPtr<nsIDocument> doc = GetUncomposedDoc();
+      if (!doc) {
+        return;
+      }
+
+      nsCOMPtr<nsIPresShell> shell = doc->GetShell();
+      if (!shell) {
+        aRv.Throw(NS_ERROR_UNEXPECTED);
+        return;
+      }
+      frameWidth = nsPresContext::CSSPixelsToAppUnits(frameWidth);
+    }
+
+    // first find out what index we are currently at
+    while(child) {
+      rect = child->GetRect();
+      if (horiz) {
+        // In the left-to-right case we break from the loop when the center of
+        // the current child rect is greater than the scrolled position of
+        // the left edge of the scrollbox
+        // In the right-to-left case we break when the center of the current
+        // child rect is less than the scrolled position of the right edge of
+        // the scrollbox.
+        diff = rect.x + rect.width/2; // use the center, to avoid rounding errors
+        if ((isLTR && diff > cp.x) ||
+            (!isLTR && diff < cp.x + frameWidth)) {
+          break;
+        }
+      } else {
+        diff = rect.y + rect.height/2;// use the center, to avoid rounding errors
+        if (diff > cp.y) {
+          break;
+        }
+      }
+      child = nsBox::GetNextXULBox(child);
+      curIndex++;
+    }
+
+    int32_t count = 0;
+
+    if (aIndex == 0)
+      return;
+
+    if (aIndex > 0) {
+      while(child) {
+        child = nsBox::GetNextXULBox(child);
+        if (child) {
+          rect = child->GetRect();
+        }
+        count++;
+        if (count >= aIndex) {
+          break;
+        }
+      }
+
+    } else if (aIndex < 0) {
+      child = nsBox::GetChildXULBox(scrolledFrame);
+      while(child) {
+        rect = child->GetRect();
+        if (count >= curIndex + aIndex) {
+          break;
+        }
+        count++;
+        child = nsBox::GetNextXULBox(child);
+
+      }
+   }
+
+   nscoord csspixel = nsPresContext::CSSPixelsToAppUnits(1);
+   if (horiz) {
+       // In the left-to-right case we scroll so that the left edge of the
+       // selected child is scrolled to the left edge of the scrollbox.
+       // In the right-to-left case we scroll so that the right edge of the
+       // selected child is scrolled to the right edge of the scrollbox.
+
+       nsPoint pt(isLTR ? rect.x : rect.x + rect.width - frameWidth,
+                  cp.y);
+
+       // Use a destination range that ensures the left edge (or right edge,
+       // for RTL) will indeed be visible. Also ensure that the top edge
+       // is visible.
+       nsRect range(pt.x, pt.y, csspixel, 0);
+       if (isLTR) {
+         range.x -= csspixel;
+       }
+       sf->ScrollTo(pt, nsIScrollableFrame::INSTANT, &range);
+   } else {
+       // Use a destination range that ensures the top edge will be visible.
+       nsRect range(cp.x, rect.y - csspixel, 0, csspixel);
+       sf->ScrollTo(nsPoint(cp.x, rect.y), nsIScrollableFrame::INSTANT, &range);
+   }
+}
+
+
+void
+XULScrollElement::EnsureElementIsVisible(Element& aChild, ErrorResult& aRv)
+{
+    nsCOMPtr<nsIDocument> doc = GetUncomposedDoc();
+    if (!doc) {
+      return;
+    }
+
+    nsCOMPtr<nsIPresShell> shell = doc->GetShell();
+    if (!shell) {
+      aRv.Throw(NS_ERROR_UNEXPECTED);
+      return;
+    }
+
+    shell->ScrollContentIntoView(&aChild,
+                                 nsIPresShell::ScrollAxis(),
+                                 nsIPresShell::ScrollAxis(),
+                                 nsIPresShell::SCROLL_FIRST_ANCESTOR_ONLY |
+                                 nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/xul/XULScrollElement.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef XULScrollElement_h__
+#define XULScrollElement_h__
+
+#include "nsXULElement.h"
+#include "Units.h"
+
+class nsIScrollableFrame;
+struct nsRect;
+
+namespace mozilla {
+namespace dom {
+
+
+nsXULElement* 
+NS_NewXULScrollElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
+
+class XULScrollElement final : public nsXULElement
+{
+public:
+  explicit XULScrollElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo): nsXULElement(aNodeInfo)
+  {
+  }
+
+  MOZ_CAN_RUN_SCRIPT void ScrollByIndex(int32_t aIndex, ErrorResult& aRv);
+  void EnsureElementIsVisible(Element& aChild, ErrorResult& aRv);
+
+protected:
+  virtual ~XULScrollElement() {}
+  virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // XULScrollElement_h
--- a/dom/xul/moz.build
+++ b/dom/xul/moz.build
@@ -20,29 +20,31 @@ if CONFIG['MOZ_XUL']:
     ]
 
     EXPORTS += [
         'nsXULElement.h',
     ]
 
     EXPORTS.mozilla.dom += [
         'XULPopupElement.h',
+        'XULScrollElement.h',
     ]
 
     UNIFIED_SOURCES += [
         'nsXULCommandDispatcher.cpp',
         'nsXULContentSink.cpp',
         'nsXULContentUtils.cpp',
         'nsXULElement.cpp',
         'nsXULPopupListener.cpp',
         'nsXULPrototypeCache.cpp',
         'nsXULPrototypeDocument.cpp',
         'nsXULSortService.cpp',
         'XULDocument.cpp',
         'XULPopupElement.cpp',
+        'XULScrollElement.cpp',
     ]
 
 XPIDL_SOURCES += [
     'nsIController.idl',
     'nsIControllers.idl',
     'nsIXULSortService.idl',
 ]
 
--- a/dom/xul/nsXULElement.cpp
+++ b/dom/xul/nsXULElement.cpp
@@ -70,16 +70,17 @@
 #include "nsXBLBinding.h"
 #include "nsXULTooltipListener.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozAutoDocUpdate.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsICSSDeclaration.h"
 #include "nsLayoutUtils.h"
 #include "XULPopupElement.h"
+#include "XULScrollElement.h"
 
 #include "mozilla/dom/XULElementBinding.h"
 #include "mozilla/dom/BoxObject.h"
 #include "mozilla/dom/HTMLIFrameElement.h"
 #include "mozilla/dom/MouseEventBinding.h"
 #include "mozilla/dom/MutationEventBinding.h"
 #include "mozilla/dom/XULCommandEvent.h"
 
@@ -173,16 +174,20 @@ nsXULElement* nsXULElement::Construct(al
   RefPtr<mozilla::dom::NodeInfo> nodeInfo = aNodeInfo;
   if (nodeInfo->Equals(nsGkAtoms::menupopup) ||
       nodeInfo->Equals(nsGkAtoms::popup) ||
       nodeInfo->Equals(nsGkAtoms::panel) ||
       nodeInfo->Equals(nsGkAtoms::tooltip)) {
     return NS_NewXULPopupElement(nodeInfo.forget());
   }
 
+  if (nodeInfo->Equals(nsGkAtoms::scrollbox)){
+    return NS_NewXULScrollElement(nodeInfo.forget());
+  }
+
   return NS_NewBasicXULElement(nodeInfo.forget());
 }
 
 /* static */
 already_AddRefed<nsXULElement>
 nsXULElement::CreateFromPrototype(nsXULPrototypeElement* aPrototype,
                                   mozilla::dom::NodeInfo *aNodeInfo,
                                   bool aIsScriptable,
--- a/layout/build/nsLayoutCID.h
+++ b/layout/build/nsLayoutCID.h
@@ -18,20 +18,16 @@
 // {D750A964-2D14-484c-B3AA-8ED7823B5C7B}
 #define NS_BOXOBJECT_CID \
 { 0xd750a964, 0x2d14, 0x484c, { 0xb3, 0xaa, 0x8e, 0xd7, 0x82, 0x3b, 0x5c, 0x7b } }
 
 // {C2710D40-6F4D-4b7f-9778-76AE5166648C}
 #define NS_LISTBOXOBJECT_CID \
 { 0xc2710d40, 0x6f4d, 0x4b7f, { 0x97, 0x78, 0x76, 0xae, 0x51, 0x66, 0x64, 0x8c } }
 
-// {56E2ADA8-4631-11d4-BA11-001083023C1E}
-#define NS_SCROLLBOXOBJECT_CID \
-{ 0x56e2ada8, 0x4631, 0x11d4, { 0xba, 0x11, 0x0, 0x10, 0x83, 0x2, 0x3c, 0x1e } }
-
 // {AA40253B-4C42-4056-8132-37BCD07862FD}
 #define NS_MENUBOXOBJECT_CID \
 { 0xaa40253b, 0x4c42, 0x4056, { 0x81, 0x32, 0x37, 0xbc, 0xd0, 0x78, 0x62, 0xfd } }
 
 // {3B581FD4-3497-426c-8F61-3658B971CB80}
 #define NS_TREEBOXOBJECT_CID \
 { 0x3b581fd4, 0x3497, 0x426c, { 0x8f, 0x61, 0x36, 0x58, 0xb9, 0x71, 0xcb, 0x80 } }
 
--- a/layout/build/nsLayoutModule.cpp
+++ b/layout/build/nsLayoutModule.cpp
@@ -296,17 +296,16 @@ Shutdown()
 #ifdef DEBUG
 nsresult NS_NewLayoutDebugger(nsILayoutDebugger** aResult);
 #endif
 
 nsresult NS_NewBoxObject(nsIBoxObject** aResult);
 
 #ifdef MOZ_XUL
 nsresult NS_NewListBoxObject(nsIBoxObject** aResult);
-nsresult NS_NewScrollBoxObject(nsIBoxObject** aResult);
 nsresult NS_NewMenuBoxObject(nsIBoxObject** aResult);
 nsresult NS_NewTreeBoxObject(nsIBoxObject** aResult);
 #endif
 
 nsresult NS_CreateFrameTraversal(nsIFrameTraversal** aResult);
 
 already_AddRefed<nsIContentViewer> NS_NewContentViewer();
 nsresult NS_NewContentDocumentLoaderFactory(nsIDocumentLoaderFactory** aResult);
@@ -359,17 +358,16 @@ MAKE_CTOR(CreateNewLayoutDebugger,      
 #endif
 
 MAKE_CTOR(CreateNewFrameTraversal,      nsIFrameTraversal,      NS_CreateFrameTraversal)
 MAKE_CTOR(CreateNewBoxObject,           nsIBoxObject,           NS_NewBoxObject)
 
 #ifdef MOZ_XUL
 MAKE_CTOR(CreateNewListBoxObject,       nsIBoxObject,           NS_NewListBoxObject)
 MAKE_CTOR(CreateNewMenuBoxObject,       nsIBoxObject,           NS_NewMenuBoxObject)
-MAKE_CTOR(CreateNewScrollBoxObject,     nsIBoxObject,           NS_NewScrollBoxObject)
 MAKE_CTOR(CreateNewTreeBoxObject,       nsIBoxObject,           NS_NewTreeBoxObject)
 #endif // MOZ_XUL
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(inDeepTreeWalker)
 
 MAKE_CTOR2(CreateContentViewer,           nsIContentViewer,            NS_NewContentViewer)
 MAKE_CTOR(CreateHTMLDocument,             nsIDocument,                 NS_NewHTMLDocument)
 MAKE_CTOR(CreateXMLDocument,              nsIDocument,                 NS_NewXMLDocument)
@@ -502,17 +500,16 @@ Construct_nsIScriptSecurityManager(nsISu
 #ifdef DEBUG
 NS_DEFINE_NAMED_CID(NS_LAYOUT_DEBUGGER_CID);
 #endif
 NS_DEFINE_NAMED_CID(NS_FRAMETRAVERSAL_CID);
 NS_DEFINE_NAMED_CID(NS_BOXOBJECT_CID);
 #ifdef MOZ_XUL
 NS_DEFINE_NAMED_CID(NS_LISTBOXOBJECT_CID);
 NS_DEFINE_NAMED_CID(NS_MENUBOXOBJECT_CID);
-NS_DEFINE_NAMED_CID(NS_SCROLLBOXOBJECT_CID);
 NS_DEFINE_NAMED_CID(NS_TREEBOXOBJECT_CID);
 #endif // MOZ_XUL
 NS_DEFINE_NAMED_CID(IN_DEEPTREEWALKER_CID);
 NS_DEFINE_NAMED_CID(NS_CONTENT_VIEWER_CID);
 NS_DEFINE_NAMED_CID(NS_HTMLDOCUMENT_CID);
 NS_DEFINE_NAMED_CID(NS_XMLDOCUMENT_CID);
 NS_DEFINE_NAMED_CID(NS_SVGDOCUMENT_CID);
 NS_DEFINE_NAMED_CID(NS_IMAGEDOCUMENT_CID);
@@ -744,17 +741,16 @@ static const mozilla::Module::CIDEntry k
 #ifdef DEBUG
   { &kNS_LAYOUT_DEBUGGER_CID, false, nullptr, CreateNewLayoutDebugger },
 #endif
   { &kNS_FRAMETRAVERSAL_CID, false, nullptr, CreateNewFrameTraversal },
   { &kNS_BOXOBJECT_CID, false, nullptr, CreateNewBoxObject },
 #ifdef MOZ_XUL
   { &kNS_LISTBOXOBJECT_CID, false, nullptr, CreateNewListBoxObject },
   { &kNS_MENUBOXOBJECT_CID, false, nullptr, CreateNewMenuBoxObject },
-  { &kNS_SCROLLBOXOBJECT_CID, false, nullptr, CreateNewScrollBoxObject },
   { &kNS_TREEBOXOBJECT_CID, false, nullptr, CreateNewTreeBoxObject },
 #endif // MOZ_XUL
   { &kIN_DEEPTREEWALKER_CID, false, nullptr, inDeepTreeWalkerConstructor },
   { &kNS_CONTENT_VIEWER_CID, false, nullptr, CreateContentViewer },
   { &kNS_HTMLDOCUMENT_CID, false, nullptr, CreateHTMLDocument },
   { &kNS_XMLDOCUMENT_CID, false, nullptr, CreateXMLDocument },
   { &kNS_SVGDOCUMENT_CID, false, nullptr, CreateSVGDocument },
   { &kNS_IMAGEDOCUMENT_CID, false, nullptr, CreateImageDocument },
@@ -852,17 +848,16 @@ static const mozilla::Module::CIDEntry k
 };
 
 static const mozilla::Module::ContractIDEntry kLayoutContracts[] = {
   XPCONNECT_CONTRACTS
   { "@mozilla.org/layout/xul-boxobject;1", &kNS_BOXOBJECT_CID },
 #ifdef MOZ_XUL
   { "@mozilla.org/layout/xul-boxobject-listbox;1", &kNS_LISTBOXOBJECT_CID },
   { "@mozilla.org/layout/xul-boxobject-menu;1", &kNS_MENUBOXOBJECT_CID },
-  { "@mozilla.org/layout/xul-boxobject-scrollbox;1", &kNS_SCROLLBOXOBJECT_CID },
   { "@mozilla.org/layout/xul-boxobject-tree;1", &kNS_TREEBOXOBJECT_CID },
 #endif // MOZ_XUL
   { "@mozilla.org/inspector/deep-tree-walker;1", &kIN_DEEPTREEWALKER_CID },
   { "@mozilla.org/xml/xml-document;1", &kNS_XMLDOCUMENT_CID },
   { "@mozilla.org/svg/svg-document;1", &kNS_SVGDOCUMENT_CID },
   { "@mozilla.org/content/post-content-iterator;1", &kNS_CONTENTITERATOR_CID },
   { "@mozilla.org/content/pre-content-iterator;1", &kNS_PRECONTENTITERATOR_CID },
   { "@mozilla.org/content/subtree-content-iterator;1", &kNS_SUBTREEITERATOR_CID },
--- a/layout/reftests/invalidation/540247-1-ref.xul
+++ b/layout/reftests/invalidation/540247-1-ref.xul
@@ -4,17 +4,17 @@
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
 <script><![CDATA[
 document.addEventListener("MozReftestInvalidate", runtest, false);
 
 function runtest() {
   document.getElementById('b').height = '100';
 
-  var sbo = document.getElementById('s').boxObject;
+  var sbo = document.getElementById('s');
   sbo.scrollTo(0, 1000);
 
   document.documentElement.className = "";
 }
 ]]>
 </script>
 
   <scrollbox id="s" height="200" style="overflow: scroll;">
--- a/layout/reftests/invalidation/540247-1.xul
+++ b/layout/reftests/invalidation/540247-1.xul
@@ -5,17 +5,17 @@
 
 <script><![CDATA[
 document.addEventListener("MozReftestInvalidate", runtest, false);
 
 function runtest() {
   // Make sure that the effects of the scroll are painted to the screen before
   // shrinking the size of the scrolled frame.
   window.addEventListener("MozAfterPaint", finish, false);
-  var sbo = document.getElementById('s').boxObject;
+  var sbo = document.getElementById('s');
   sbo.scrollTo(0, 1000);
 }
 
 function finish() {
   document.getElementById('b').height = '100';
   document.documentElement.className = "";
 }
 ]]>
deleted file mode 100644
--- a/layout/xul/ScrollBoxObject.cpp
+++ /dev/null
@@ -1,384 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "mozilla/dom/ScrollBoxObject.h"
-#include "mozilla/dom/ScrollBoxObjectBinding.h"
-#include "mozilla/dom/Element.h"
-#include "mozilla/dom/ToJSValue.h"
-#include "nsCOMPtr.h"
-#include "nsIPresShell.h"
-#include "nsIContent.h"
-#include "nsPresContext.h"
-#include "nsBox.h"
-#include "nsIScrollableFrame.h"
-
-namespace mozilla {
-namespace dom {
-
-ScrollBoxObject::ScrollBoxObject()
-{
-}
-
-ScrollBoxObject::~ScrollBoxObject()
-{
-}
-
-JSObject* ScrollBoxObject::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
-{
-  return ScrollBoxObjectBinding::Wrap(aCx, this, aGivenProto);
-}
-
-nsIScrollableFrame* ScrollBoxObject::GetScrollFrame()
-{
-  return do_QueryFrame(GetFrame(false));
-}
-
-void ScrollBoxObject::ScrollTo(int32_t x, int32_t y, ErrorResult& aRv)
-{
-  nsIScrollableFrame* sf = GetScrollFrame();
-  if (!sf) {
-    aRv.Throw(NS_ERROR_FAILURE);
-    return;
-  }
-
-  sf->ScrollToCSSPixels(CSSIntPoint(x, y));
-}
-
-void ScrollBoxObject::ScrollBy(int32_t dx, int32_t dy, ErrorResult& aRv)
-{
-  CSSIntPoint pt;
-  GetPosition(pt, aRv);
-
-  if (aRv.Failed()) {
-    return;
-  }
-
-  ScrollTo(pt.x + dx, pt.y + dy, aRv);
-}
-
-void ScrollBoxObject::ScrollByLine(int32_t dlines, ErrorResult& aRv)
-{
-  nsIScrollableFrame* sf = GetScrollFrame();
-  if (!sf) {
-    aRv.Throw(NS_ERROR_FAILURE);
-    return;
-  }
-
-  sf->ScrollBy(nsIntPoint(0, dlines), nsIScrollableFrame::LINES,
-               nsIScrollableFrame::SMOOTH);
-}
-
-// XUL <scrollbox> elements have a single box child element.
-// Get a pointer to that box.
-// Note that now that the <scrollbox> is just a regular box
-// with 'overflow:hidden', the boxobject's frame is an nsXULScrollFrame,
-// the <scrollbox>'s box frame is the scrollframe's "scrolled frame", and
-// the <scrollbox>'s child box is a child of that.
-static nsIFrame* GetScrolledBox(BoxObject* aScrollBox) {
-  nsIFrame* frame = aScrollBox->GetFrame(false);
-  if (!frame) {
-    return nullptr;
-  }
-
-  nsIScrollableFrame* scrollFrame = do_QueryFrame(frame);
-  if (!scrollFrame) {
-    NS_WARNING("ScrollBoxObject attached to something that's not a scroll frame!");
-    return nullptr;
-  }
-
-  nsIFrame* scrolledFrame = scrollFrame->GetScrolledFrame();
-  if (!scrolledFrame)
-    return nullptr;
-  return nsBox::GetChildXULBox(scrolledFrame);
-}
-
-void ScrollBoxObject::ScrollByIndex(int32_t dindexes, ErrorResult& aRv)
-{
-    nsIScrollableFrame* sf = GetScrollFrame();
-    if (!sf) {
-      aRv.Throw(NS_ERROR_FAILURE);
-      return;
-    }
-
-    nsIFrame* scrolledBox = GetScrolledBox(this);
-    if (!scrolledBox) {
-      aRv.Throw(NS_ERROR_FAILURE);
-      return;
-    }
-
-    nsRect rect;
-
-    // now get the scrolled boxes first child.
-    nsIFrame* child = nsBox::GetChildXULBox(scrolledBox);
-
-    bool horiz = scrolledBox->IsXULHorizontal();
-    nsPoint cp = sf->GetScrollPosition();
-    nscoord diff = 0;
-    int32_t curIndex = 0;
-    bool isLTR = scrolledBox->IsXULNormalDirection();
-
-    int32_t frameWidth = 0;
-    if (!isLTR && horiz) {
-      GetWidth(&frameWidth);
-      nsCOMPtr<nsIPresShell> shell = GetPresShell(false);
-      if (!shell) {
-        aRv.Throw(NS_ERROR_UNEXPECTED);
-        return;
-      }
-      frameWidth = nsPresContext::CSSPixelsToAppUnits(frameWidth);
-    }
-
-    // first find out what index we are currently at
-    while(child) {
-      rect = child->GetRect();
-      if (horiz) {
-        // In the left-to-right case we break from the loop when the center of
-        // the current child rect is greater than the scrolled position of
-        // the left edge of the scrollbox
-        // In the right-to-left case we break when the center of the current
-        // child rect is less than the scrolled position of the right edge of
-        // the scrollbox.
-        diff = rect.x + rect.width/2; // use the center, to avoid rounding errors
-        if ((isLTR && diff > cp.x) ||
-            (!isLTR && diff < cp.x + frameWidth)) {
-          break;
-        }
-      } else {
-        diff = rect.y + rect.height/2;// use the center, to avoid rounding errors
-        if (diff > cp.y) {
-          break;
-        }
-      }
-      child = nsBox::GetNextXULBox(child);
-      curIndex++;
-    }
-
-    int32_t count = 0;
-
-    if (dindexes == 0)
-      return;
-
-    if (dindexes > 0) {
-      while(child) {
-        child = nsBox::GetNextXULBox(child);
-        if (child) {
-          rect = child->GetRect();
-        }
-        count++;
-        if (count >= dindexes) {
-          break;
-        }
-      }
-
-   } else if (dindexes < 0) {
-      child = nsBox::GetChildXULBox(scrolledBox);
-      while(child) {
-        rect = child->GetRect();
-        if (count >= curIndex + dindexes) {
-          break;
-        }
-
-        count++;
-        child = nsBox::GetNextXULBox(child);
-
-      }
-   }
-
-   nscoord csspixel = nsPresContext::CSSPixelsToAppUnits(1);
-   if (horiz) {
-       // In the left-to-right case we scroll so that the left edge of the
-       // selected child is scrolled to the left edge of the scrollbox.
-       // In the right-to-left case we scroll so that the right edge of the
-       // selected child is scrolled to the right edge of the scrollbox.
-
-       nsPoint pt(isLTR ? rect.x : rect.x + rect.width - frameWidth,
-                  cp.y);
-
-       // Use a destination range that ensures the left edge (or right edge,
-       // for RTL) will indeed be visible. Also ensure that the top edge
-       // is visible.
-       nsRect range(pt.x, pt.y, csspixel, 0);
-       if (isLTR) {
-         range.x -= csspixel;
-       }
-       sf->ScrollTo(pt, nsIScrollableFrame::INSTANT, &range);
-   } else {
-       // Use a destination range that ensures the top edge will be visible.
-       nsRect range(cp.x, rect.y - csspixel, 0, csspixel);
-       sf->ScrollTo(nsPoint(cp.x, rect.y), nsIScrollableFrame::INSTANT, &range);
-   }
-}
-
-void ScrollBoxObject::ScrollToLine(int32_t line, ErrorResult& aRv)
-{
-  nsIScrollableFrame* sf = GetScrollFrame();
-  if (!sf) {
-    aRv.Throw(NS_ERROR_FAILURE);
-    return;
-  }
-
-  nscoord y = sf->GetLineScrollAmount().height * line;
-  nsRect range(0, y - nsPresContext::CSSPixelsToAppUnits(1),
-               0, nsPresContext::CSSPixelsToAppUnits(1));
-  sf->ScrollTo(nsPoint(0, y), nsIScrollableFrame::INSTANT, &range);
-}
-
-void ScrollBoxObject::ScrollToElement(Element& child, ErrorResult& aRv)
-{
-  nsCOMPtr<nsIPresShell> shell = GetPresShell(false);
-  if (!shell) {
-    aRv.Throw(NS_ERROR_UNEXPECTED);
-    return;
-  }
-
-  shell->ScrollContentIntoView(&child,
-                               nsIPresShell::ScrollAxis(
-                                 nsIPresShell::SCROLL_TOP,
-                                 nsIPresShell::SCROLL_ALWAYS),
-                               nsIPresShell::ScrollAxis(
-                                 nsIPresShell::SCROLL_LEFT,
-                                 nsIPresShell::SCROLL_ALWAYS),
-                               nsIPresShell::SCROLL_FIRST_ANCESTOR_ONLY |
-                               nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
-}
-
-void ScrollBoxObject::ScrollToIndex(int32_t index, ErrorResult& aRv)
-{
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
-}
-
-int32_t ScrollBoxObject::GetPositionX(ErrorResult& aRv)
-{
-  CSSIntPoint pt;
-  GetPosition(pt, aRv);
-  return pt.x;
-}
-
-int32_t ScrollBoxObject::GetPositionY(ErrorResult& aRv)
-{
-  CSSIntPoint pt;
-  GetPosition(pt, aRv);
-  return pt.y;
-}
-
-int32_t ScrollBoxObject::GetScrolledWidth(ErrorResult& aRv)
-{
-  nsRect scrollRect;
-  GetScrolledSize(scrollRect, aRv);
-  return scrollRect.width;
-}
-
-int32_t ScrollBoxObject::GetScrolledHeight(ErrorResult& aRv)
-{
-  nsRect scrollRect;
-  GetScrolledSize(scrollRect, aRv);
-  return scrollRect.height;
-}
-
-/* private helper */
-void ScrollBoxObject::GetPosition(CSSIntPoint& aPos, ErrorResult& aRv)
-{
-  nsIScrollableFrame* sf = GetScrollFrame();
-  if (!sf) {
-    aRv.Throw(NS_ERROR_FAILURE);
-    return;
-  }
-
-  aPos = sf->GetScrollPositionCSSPixels();
-}
-
-/* private helper */
-void ScrollBoxObject::GetScrolledSize(nsRect& aRect, ErrorResult& aRv)
-{
-    nsIFrame* scrolledBox = GetScrolledBox(this);
-    if (!scrolledBox) {
-      aRv.Throw(NS_ERROR_FAILURE);
-      return;
-    }
-
-    aRect = scrolledBox->GetRect();
-    aRect.width  = nsPresContext::AppUnitsToIntCSSPixels(aRect.width);
-    aRect.height = nsPresContext::AppUnitsToIntCSSPixels(aRect.height);
-}
-
-void ScrollBoxObject::GetPosition(JSContext* cx,
-                                  JS::Handle<JSObject*> x,
-                                  JS::Handle<JSObject*> y,
-                                  ErrorResult& aRv)
-{
-  CSSIntPoint pt;
-  GetPosition(pt, aRv);
-  JS::Rooted<JS::Value> v(cx);
-  if (!ToJSValue(cx, pt.x, &v) ||
-      !JS_SetProperty(cx, x, "value", v)) {
-    aRv.Throw(NS_ERROR_XPC_CANT_SET_OUT_VAL);
-    return;
-  }
-  if (!ToJSValue(cx, pt.y, &v) ||
-      !JS_SetProperty(cx, y, "value", v)) {
-    aRv.Throw(NS_ERROR_XPC_CANT_SET_OUT_VAL);
-    return;
-  }
-}
-
-void ScrollBoxObject::GetScrolledSize(JSContext* cx,
-                                      JS::Handle<JSObject*> width,
-                                      JS::Handle<JSObject*> height,
-                                      ErrorResult& aRv)
-{
-  nsRect rect;
-  GetScrolledSize(rect, aRv);
-  JS::Rooted<JS::Value> v(cx);
-  if (!ToJSValue(cx, rect.width, &v) ||
-      !JS_SetProperty(cx, width, "value", v)) {
-    aRv.Throw(NS_ERROR_XPC_CANT_SET_OUT_VAL);
-    return;
-  }
-  if (!ToJSValue(cx, rect.height, &v) ||
-      !JS_SetProperty(cx, height, "value", v)) {
-    aRv.Throw(NS_ERROR_XPC_CANT_SET_OUT_VAL);
-    return;
-  }
-}
-
-void ScrollBoxObject::EnsureElementIsVisible(Element& child, ErrorResult& aRv)
-{
-    nsCOMPtr<nsIPresShell> shell = GetPresShell(false);
-    if (!shell) {
-      aRv.Throw(NS_ERROR_UNEXPECTED);
-      return;
-    }
-
-    shell->ScrollContentIntoView(&child,
-                                 nsIPresShell::ScrollAxis(),
-                                 nsIPresShell::ScrollAxis(),
-                                 nsIPresShell::SCROLL_FIRST_ANCESTOR_ONLY |
-                                 nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
-}
-
-void ScrollBoxObject::EnsureIndexIsVisible(int32_t index, ErrorResult& aRv)
-{
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
-}
-
-void ScrollBoxObject::EnsureLineIsVisible(int32_t line, ErrorResult& aRv)
-{
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
-}
-
-} // namespace dom
-} // namespace mozilla
-
-// Creation Routine ///////////////////////////////////////////////////////////////////////
-
-using namespace mozilla::dom;
-
-nsresult
-NS_NewScrollBoxObject(nsIBoxObject** aResult)
-{
-  NS_ADDREF(*aResult = new ScrollBoxObject());
-  return NS_OK;
-}
deleted file mode 100644
--- a/layout/xul/ScrollBoxObject.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_ScrollBoxObject_h
-#define mozilla_dom_ScrollBoxObject_h
-
-#include "mozilla/dom/BoxObject.h"
-#include "Units.h"
-
-class nsIScrollableFrame;
-struct nsRect;
-
-namespace mozilla {
-namespace dom {
-
-class ScrollBoxObject final : public BoxObject
-{
-public:
-  ScrollBoxObject();
-
-  virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
-
-  virtual nsIScrollableFrame* GetScrollFrame();
-
-  void ScrollTo(int32_t x, int32_t y, ErrorResult& aRv);
-  void ScrollBy(int32_t dx, int32_t dy, ErrorResult& aRv);
-  void ScrollByLine(int32_t dlines, ErrorResult& aRv);
-  void ScrollByIndex(int32_t dindexes, ErrorResult& aRv);
-  void ScrollToLine(int32_t line, ErrorResult& aRv);
-  void ScrollToElement(Element& child, ErrorResult& aRv);
-  void ScrollToIndex(int32_t index, ErrorResult& aRv);
-  int32_t GetPositionX(ErrorResult& aRv);
-  int32_t GetPositionY(ErrorResult& aRv);
-  int32_t GetScrolledWidth(ErrorResult& aRv);
-  int32_t GetScrolledHeight(ErrorResult& aRv);
-  void EnsureElementIsVisible(Element& child, ErrorResult& aRv);
-  void EnsureIndexIsVisible(int32_t index, ErrorResult& aRv);
-  void EnsureLineIsVisible(int32_t line, ErrorResult& aRv);
-
-  // Deprecated APIs from old IDL
-  void GetPosition(JSContext* cx,
-                   JS::Handle<JSObject*> x,
-                   JS::Handle<JSObject*> y,
-                   ErrorResult& aRv);
-
-  void GetScrolledSize(JSContext* cx,
-                       JS::Handle<JSObject*> width,
-                       JS::Handle<JSObject*> height,
-                       ErrorResult& aRv);
-
-protected:
-  void GetScrolledSize(nsRect& aRect, ErrorResult& aRv);
-  void GetPosition(CSSIntPoint& aPos, ErrorResult& aRv);
-
-private:
-  ~ScrollBoxObject();
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_ScrollBoxObject_h
--- a/layout/xul/moz.build
+++ b/layout/xul/moz.build
@@ -30,17 +30,16 @@ EXPORTS += [
     'nsPIListBoxObject.h',
     'nsXULPopupManager.h',
 ]
 
 EXPORTS.mozilla.dom += [
     'BoxObject.h',
     'ListBoxObject.h',
     'MenuBoxObject.h',
-    'ScrollBoxObject.h',
 ]
 
 UNIFIED_SOURCES += [
     'BoxObject.cpp',
     'nsBox.cpp',
     'nsBoxFrame.cpp',
     'nsBoxLayout.cpp',
     'nsBoxLayoutState.cpp',
@@ -75,17 +74,16 @@ if CONFIG['MOZ_XUL']:
         'nsPopupSetFrame.cpp',
         'nsProgressMeterFrame.cpp',
         'nsResizerFrame.cpp',
         'nsSplitterFrame.cpp',
         'nsTextBoxFrame.cpp',
         'nsTitleBarFrame.cpp',
         'nsXULLabelFrame.cpp',
         'nsXULPopupManager.cpp',
-        'ScrollBoxObject.cpp',
     ]
 
 if CONFIG['MOZ_XUL']:
     DIRS += ['tree', 'grid']
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
--- a/testing/mochitest/browser-harness.xul
+++ b/testing/mochitest/browser-harness.xul
@@ -319,18 +319,18 @@
       setStatus("Done.");
     }
 
     function scrollTo(id) {
       var line = document.getElementById(id);
       if (!line)
         return;
 
-      var scrollbox = document.getElementById("results").parentNode._scrollbox;
-      line.scrollIntoView(); 
+      var scrollbox = document.getElementById("results").parentNode;
+      line.scrollIntoView();
     }
   ]]></script>
   <button id="runTestsButton" oncommand="runTests();" label="Run All Tests"/>
   <label id="status"/>
   <scrollbox flex="1" style="overflow: auto" align="stretch">
     <div id="results" xmlns="http://www.w3.org/1999/xhtml" flex="1"/>
   </scrollbox>
 </window>
--- a/toolkit/content/tests/chrome/test_position.xul
+++ b/toolkit/content/tests/chrome/test_position.xul
@@ -70,25 +70,23 @@ function runTest()
 
   var box2 = $("box2");
   checkPosition("box2", box2, 2, 46, winwidth, 96);
 
   // height is height(box1) = 46 + margin-top(box3) = 1 + margin-top(button1) = 5
   var button1 = $("button1");
   checkPosition("button1", button1, 9, 53, 99, 88);
 
-  var sbo = box2.boxObject;
-  sbo.scrollTo(7, 16);
+  box2.scrollTo(7, 16);
 
   // clientRect height is offset from root so is 16 pixels vertically less
   checkPosition("button1 scrolled", button1, 9, 37, 99, 72);
 
   var box3 = $("box3");
-  sbo = box3.boxObject;
-  sbo.scrollTo(1, 2);
+  box3.scrollTo(1, 2);
 
   checkPosition("button1 scrolled", button1, 9, 35, 99, 70);
 
   $("menu").open = true;
 }
 
 function menuOpened()
 {
--- a/toolkit/modules/SelectParentHelper.jsm
+++ b/toolkit/modules/SelectParentHelper.jsm
@@ -242,35 +242,35 @@ var SelectParentHelper = {
 
     if (msg.name == "Forms:UpdateDropDown") {
       // Sanity check - we'd better know what the currently
       // opened menulist is, and what browser it belongs to...
       if (!currentMenulist) {
         return;
       }
 
-      let scrollbox = currentMenulist.menupopup._scrollbox;
-      let scrollTop = scrollbox.scrollTop;
+      let scrollBox = currentMenulist.menupopup.scrollBox;
+      let scrollTop = scrollBox.scrollTop;
 
       let options = msg.data.options;
       let selectedIndex = msg.data.selectedIndex;
       let uaBackgroundColor = msg.data.uaBackgroundColor;
       let uaColor = msg.data.uaColor;
       let uaSelectBackgroundColor = msg.data.uaSelectBackgroundColor;
       let uaSelectColor = msg.data.uaSelectColor;
       let selectBackgroundColor = msg.data.selectBackgroundColor;
       let selectColor = msg.data.selectColor;
       let selectTextShadow = msg.data.selectTextShadow;
       this.populate(currentMenulist, options, selectedIndex,
                     currentZoom, uaBackgroundColor, uaColor,
                     uaSelectBackgroundColor, uaSelectColor,
                     selectBackgroundColor, selectColor, selectTextShadow);
 
       // Restore scroll position to what it was prior to the update.
-      scrollbox.scrollTop = scrollTop;
+      scrollBox.scrollTop = scrollTop;
     } else if (msg.name == "Forms:BlurDropDown-Ping") {
       currentBrowser.messageManager.sendAsyncMessage("Forms:BlurDropDown-Pong", {});
     }
   },
 
   _registerListeners(browser, popup) {
     popup.addEventListener("command", this);
     popup.addEventListener("popuphidden", this);