Bug 1454358, removes unneccessary implementation of ScrollBoxObject rr?enndeakin+6102 draft
authorEmma Malysz <emalysz@mozilla.com>
Mon, 25 Jun 2018 10:11:31 -0700
changeset 817507 de0dd0a4cdb1e718a9c59b6ac3d16775588fc98f
parent 817077 511395e98603e5260d584de94e6cc21ad2324792
push id116078
push userbmo:emalysz@mozilla.com
push dateThu, 12 Jul 2018 18:06:45 +0000
bugs1454358
milestone63.0a1
Bug 1454358, removes unneccessary implementation of ScrollBoxObject rr?enndeakin+6102 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/BindingUtils.cpp
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_mousescroll.xul
toolkit/content/tests/chrome/test_position.xul
toolkit/content/tests/chrome/test_richlist_direction.xul
toolkit/content/tests/chrome/window_largemenu.xul
toolkit/content/widgets/richlistbox.xml
toolkit/content/widgets/scrollbox.xml
--- a/browser/components/places/content/menu.xml
+++ b/browser/components/places/content/menu.xml
@@ -80,18 +80,17 @@
             // 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 eventY = aEvent.layerY + (scrollbox.boxObject.y - this.boxObject.y);
-            let scrollboxOffset = scrollbox.scrollBoxObject.y -
-                                  (scrollbox.boxObject.y - this.boxObject.y);
+            let scrollboxOffset = this.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)
@@ -429,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._scrollBox.scrollBoxObject;
+        let scrollbox = 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;
+          newMarginTop = elt ? elt.boxObject.screenY - scrollbox.screenY :
+                               scrollbox.height;
         } else if (scrollDir == 1)
-          newMarginTop = sbo.height;
+          newMarginTop = scrollbox.height;
 
         // Set the new marginTop based on arrowscrollbox.
-        newMarginTop += sbo.y - this._scrollBox.boxObject.y;
+        newMarginTop += scrollbox.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
@@ -590,16 +590,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;
 
@@ -1978,25 +1982,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();
 
-  /**
-   * Get a scrollframe for the element, if any.  If aFrame is not null, the
-   * element's primary frame (after whatever flushing is needed) will be
-   * returned in *aFrame.
-   */
-  MOZ_CAN_RUN_SCRIPT
-  nsIScrollableFrame* GetScrollFrame(nsIFrame **aFrame = 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
@@ -251,17 +251,16 @@
 #include "mozilla/StyleSheetInlines.h"
 #include "mozilla/dom/SVGDocument.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"
 
@@ -6325,18 +6324,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/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -51,16 +51,17 @@
 #include "mozilla/dom/XULFrameElementBinding.h"
 #include "mozilla/dom/XULPopupElementBinding.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/ResolveSystemBinding.h"
 #include "mozilla/dom/WebIDLGlobalNameHash.h"
 #include "mozilla/dom/WorkerPrivate.h"
 #include "mozilla/dom/WorkerScope.h"
 #include "mozilla/dom/XrayExpandoClass.h"
+#include "mozilla/dom/XULScrollElementBinding.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
 #include "ipc/ErrorIPCUtils.h"
 #include "mozilla/UseCounter.h"
 #include "mozilla/dom/DocGroup.h"
 #include "nsXULElement.h"
 
 namespace mozilla {
 namespace dom {
@@ -3854,16 +3855,18 @@ HTMLConstructor(JSContext* aCx, unsigned
           definition->mLocalName == nsGkAtoms::popup ||
           definition->mLocalName == nsGkAtoms::panel ||
           definition->mLocalName == nsGkAtoms::tooltip) {
         cb = XULPopupElement_Binding::GetConstructorObject;
       } else if (definition->mLocalName == nsGkAtoms::iframe ||
                  definition->mLocalName == nsGkAtoms::browser ||
                  definition->mLocalName == nsGkAtoms::editor) {
         cb = XULFrameElement_Binding::GetConstructorObject;
+      } else if (definition->mLocalName == nsGkAtoms::scrollbox) {
+          cb = XULScrollElement_Binding::GetConstructorObject;
       } else {
         cb = XULElement_Binding::GetConstructorObject;
       }
     }
 
     if (!cb) {
       return ThrowErrorMessage(aCx, MSG_ILLEGAL_CONSTRUCTOR);
     }
rename from dom/webidl/ScrollBoxObject.webidl
rename to dom/chrome-webidl/XULScrollElement.webidl
--- a/dom/webidl/ScrollBoxObject.webidl
+++ b/dom/chrome-webidl/XULScrollElement.webidl
@@ -1,45 +1,15 @@
 /* -*- 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 scrollByIndex(long dindexes);
+[HTMLConstructor, Func="IsChromeOrXBL"]
+interface XULScrollElement : XULElement {
   [Throws]
   void scrollToElement(Element child);
-
-  /**
-   * 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;
-
+  [Throws]
+  void scrollByIndex(long aIndexes);
   [Throws]
   void ensureElementIsVisible(Element child);
 };
--- a/dom/chrome-webidl/moz.build
+++ b/dom/chrome-webidl/moz.build
@@ -40,16 +40,17 @@ WEBIDL_FILES = [
     'MozStorageAsyncStatementParams.webidl',
     'MozStorageStatementParams.webidl',
     'MozStorageStatementRow.webidl',
     'PrecompiledScript.webidl',
     'PromiseDebugging.webidl',
     'StructuredCloneHolder.webidl',
     'WebExtensionContentScript.webidl',
     'WebExtensionPolicy.webidl',
-    'XULFrameElement.webidl'
+    'XULFrameElement.webidl',
+    'XULScrollElement.webidl'
 ]
 
 if CONFIG['MOZ_PLACES']:
     WEBIDL_FILES += [
         'PlacesEvent.webidl',
         'PlacesObservers.webidl',
     ]
--- a/dom/events/test/test_bug602962.xul
+++ b/dom/events/test/test_bug602962.xul
@@ -13,73 +13,72 @@ https://bugzilla.mozilla.org/show_bug.cg
   <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=602962">Mozilla Bug 602962</a>
   <p id="display"></p>
 <div id="content" style="display: none">
 </div>
 </body>
 
 <script class="testbody" type="application/javascript"><![CDATA[
 /** Test for Bug 602962 **/
-var scrollbox, sbo, content;
+var scrollbox, content;
 var scrollX = 0, scrollY = 0;
 
 var oldWidth = 0, oldHeight = 0;
 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");
-  sbo = scrollbox.boxObject;
   content = win.document.getElementById("page-box");
   content.style.width = 400 + "px";
-  
+
   win.addEventListener("resize", function() {
     win.removeEventListener("resize", arguments.callee, false);
 
     setTimeout(function(){
-      sbo.scrollBy(200, 0);
+      scrollbox.scrollBy(200,0);
       resize();
     },0);
   }, false);
 
   oldWidth = win.outerWidth;
   oldHeight = win.outerHeight;
   win.resizeTo(200, 400);
 }
 
 function resize() {
-  scrollX = sbo.positionX;
-  scrollY = sbo.positionY;
+ 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);
 }
 
 function finish() {
   if (win.outerWidth != oldWidth ||
       win.outerHeight != oldHeight) {
     // We should eventually get back to the original size.
     setTimeout(finish, 0);
     return;
   }
-  sbo.scrollBy(scrollX, scrollY);
+  scrollbox.scrollBy(scrollX, scrollY);
 
-  is(sbo.positionX, 200, "Scroll X should have been restored to the value before the resize");
-  is(sbo.positionY, 0, "Scroll Y should have been restored to the value before the resize");
+  is(scrollbox.scrollLeft, 200, "Scroll Left should have been restored to the value before the resize");
+  is(scrollbox.scrollTop, 0, "Scroll Top should have been restored to the value before the resize");
 
   is(win.outerWidth, oldWidth, "Width should be resized");
   is(win.outerHeight, oldHeight, "Height should be resized");
   win.close();
   SimpleTest.finish();
 }
 
 SimpleTest.waitForExplicitFinish();
--- a/dom/tests/mochitest/general/test_interfaces.js
+++ b/dom/tests/mochitest/general/test_interfaces.js
@@ -1252,16 +1252,18 @@ var interfaceNamesInGlobalScope =
     {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: "XULFrameElement", 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)
   {
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -745,17 +745,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',
rename from layout/xul/ScrollBoxObject.cpp
rename to dom/xul/XULScrollElement.cpp
--- a/layout/xul/ScrollBoxObject.cpp
+++ b/dom/xul/XULScrollElement.cpp
@@ -1,300 +1,202 @@
 /* -*- 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"
+#include "mozilla/dom/XULScrollElement.h"
+#include "mozilla/dom/XULScrollElementBinding.h"
 
 namespace mozilla {
 namespace dom {
 
-ScrollBoxObject::ScrollBoxObject()
+JSObject*
+XULScrollElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
 {
-}
-
-ScrollBoxObject::~ScrollBoxObject()
-{
+  return XULScrollElement_Binding::Wrap(aCx, this, aGivenProto);
 }
 
-JSObject* ScrollBoxObject::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
-{
-  return ScrollBoxObject_Binding::Wrap(aCx, this, aGivenProto);
-}
-
-nsIScrollableFrame* ScrollBoxObject::GetScrollFrame()
-{
-  return do_QueryFrame(GetFrame(false));
-}
-
-void ScrollBoxObject::ScrollTo(int32_t x, int32_t y, ErrorResult& aRv)
+void
+XULScrollElement::ScrollByIndex(int32_t aIndex, ErrorResult& aRv)
 {
   nsIScrollableFrame* sf = GetScrollFrame();
   if (!sf) {
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
 
-  sf->ScrollToCSSPixels(CSSIntPoint(x, y));
-}
+  nsIFrame* scrolledFrame = sf->GetScrolledFrame();
+  if (!scrolledFrame){
+    aRv.Throw(NS_ERROR_FAILURE);
+    return;
+  }
 
-void ScrollBoxObject::ScrollBy(int32_t dx, int32_t dy, ErrorResult& aRv)
-{
-  CSSIntPoint pt;
-  GetPosition(pt, aRv);
-
-  if (aRv.Failed()) {
+  nsIFrame* scrolledBox = nsBox::GetChildXULBox(scrolledFrame);
+  if (!scrolledBox){
+    aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
 
-  ScrollTo(pt.x + dx, pt.y + dy, aRv);
-}
+  nsRect rect;
+
+  // now get the element's 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();
 
-// 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;
-  }
+  nscoord frameWidth = 0;
+  if (!isLTR && horiz) {
+    nsCOMPtr<nsIDocument> doc = GetComposedDoc();
 
-  nsIScrollableFrame* scrollFrame = do_QueryFrame(frame);
-  if (!scrollFrame) {
-    NS_WARNING("ScrollBoxObject attached to something that's not a scroll frame!");
-    return nullptr;
+    nsCOMPtr<nsIPresShell> shell = doc->GetShell();
+    if (!shell) {
+      aRv.Throw(NS_ERROR_UNEXPECTED);
+      return;
+    }
+    nsRect rcFrame = nsLayoutUtils::GetAllInFlowRectsUnion(GetPrimaryFrame(), shell->GetRootFrame());
+    frameWidth = rcFrame.width;
   }
 
-  nsIFrame* scrolledFrame = scrollFrame->GetScrolledFrame();
-  if (!scrolledFrame)
-    return nullptr;
-  return nsBox::GetChildXULBox(scrolledFrame);
-}
+  // 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 scrollelement.
+      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++;
+  }
 
-void ScrollBoxObject::ScrollByIndex(int32_t dindexes, ErrorResult& aRv)
-{
-    nsIScrollableFrame* sf = GetScrollFrame();
-    if (!sf) {
-      aRv.Throw(NS_ERROR_FAILURE);
-      return;
-    }
+  int32_t count = 0;
+
+  if (aIndex == 0)
+    return;
 
-    nsIFrame* scrolledBox = GetScrolledBox(this);
-    if (!scrolledBox) {
-      aRv.Throw(NS_ERROR_FAILURE);
-      return;
+  if (aIndex > 0) {
+    while(child) {
+      child = nsBox::GetNextXULBox(child);
+      if (child) {
+        rect = child->GetRect();
+      }
+      count++;
+      if (count >= aIndex) {
+        break;
+      }
     }
 
-    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
+  } else if (aIndex < 0) {
+    child = nsBox::GetChildXULBox(scrolledBox);
     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;
-        }
+      if (count >= curIndex + aIndex) {
+        break;
       }
+      count++;
+      child = nsBox::GetNextXULBox(child);
 
-   } 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.
 
-   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);
+    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);
-   }
+    // 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::ScrollToElement(Element& child, ErrorResult& aRv)
+void
+XULScrollElement::ScrollToElement(Element& child, ErrorResult& aRv)
 {
-  nsCOMPtr<nsIPresShell> shell = GetPresShell(false);
+  nsCOMPtr<nsIDocument> doc = GetComposedDoc();
+  if (!doc){
+    aRv.Throw(NS_ERROR_FAILURE);
+    return;
+  }
+
+  nsCOMPtr<nsIPresShell> shell = doc->GetShell();
   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);
 }
 
-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)
+void
+XULScrollElement::EnsureElementIsVisible(Element& aChild, 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) {
+  nsCOMPtr<nsIDocument> doc = GetComposedDoc();
+  if (!doc){
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
 
-  aPos = sf->GetScrollPositionCSSPixels();
-}
+  nsCOMPtr<nsIPresShell> shell = doc->GetShell();
+  if (!shell) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return;
+  }
 
-/* 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);
+  shell->ScrollContentIntoView(&aChild,
+                               nsIPresShell::ScrollAxis(),
+                               nsIPresShell::ScrollAxis(),
+                               nsIPresShell::SCROLL_FIRST_ANCESTOR_ONLY |
+                               nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
 }
 
-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);
-}
 } // namespace dom
 } // namespace mozilla
-
-using namespace mozilla::dom;
-
-nsresult
-NS_NewScrollBoxObject(nsIBoxObject** aResult)
-{
-    NS_ADDREF(*aResult = new ScrollBoxObject());
-    return NS_OK;
-}
rename from layout/xul/ScrollBoxObject.h
rename to dom/xul/XULScrollElement.h
--- a/layout/xul/ScrollBoxObject.h
+++ b/dom/xul/XULScrollElement.h
@@ -1,50 +1,36 @@
 /* -*- 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
+#ifndef XULScrollElement_h__
+#define XULScrollElement_h__
 
-#include "mozilla/dom/BoxObject.h"
+#include "nsXULElement.h"
 #include "Units.h"
 
-class nsIScrollableFrame;
-struct nsRect;
-
 namespace mozilla {
 namespace dom {
 
-class ScrollBoxObject final : public BoxObject
+
+class XULScrollElement final : public nsXULElement
 {
 public:
-  ScrollBoxObject();
-
-  virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
-
-  virtual nsIScrollableFrame* GetScrollFrame();
+  explicit XULScrollElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo): nsXULElement(aNodeInfo)
+  {
+  }
 
-  void ScrollTo(int32_t x, int32_t y, ErrorResult& aRv);
-  void ScrollBy(int32_t dx, int32_t dy, ErrorResult& aRv);
-  void ScrollByIndex(int32_t dindexes, ErrorResult& aRv);
-  void ScrollToElement(Element& child, 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);
-
+  MOZ_CAN_RUN_SCRIPT void ScrollByIndex(int32_t aIndex, ErrorResult& aRv);
+  MOZ_CAN_RUN_SCRIPT void EnsureElementIsVisible(Element& aChild, ErrorResult& aRv);
+  MOZ_CAN_RUN_SCRIPT void ScrollToElement(Element& child, ErrorResult& aRv);
 
 protected:
-  void GetScrolledSize(nsRect& aRect, ErrorResult& aRv);
-  void GetPosition(CSSIntPoint& aPos, ErrorResult& aRv);
-
-private:
-  ~ScrollBoxObject();
+  virtual ~XULScrollElement() {}
+  JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) final;
 };
 
 } // namespace dom
 } // namespace mozilla
 
-#endif // mozilla_dom_ScrollBoxObject_h
+#endif // XULScrollElement_h
--- a/dom/xul/moz.build
+++ b/dom/xul/moz.build
@@ -17,30 +17,32 @@ MOCHITEST_CHROME_MANIFESTS += ['test/chr
 if CONFIG['MOZ_XUL']:
     EXPORTS += [
         'nsXULElement.h',
     ]
 
     EXPORTS.mozilla.dom += [
         'XULFrameElement.h',
         'XULPopupElement.h',
+        'XULScrollElement.h',
     ]
 
     UNIFIED_SOURCES += [
         'nsXULCommandDispatcher.cpp',
         'nsXULContentSink.cpp',
         'nsXULContentUtils.cpp',
         'nsXULElement.cpp',
         'nsXULPopupListener.cpp',
         'nsXULPrototypeCache.cpp',
         'nsXULPrototypeDocument.cpp',
         'nsXULSortService.cpp',
         'XULDocument.cpp',
         'XULFrameElement.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 "nsXULTooltipListener.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozAutoDocUpdate.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsICSSDeclaration.h"
 #include "nsLayoutUtils.h"
 #include "XULFrameElement.h"
 #include "XULPopupElement.h"
+#include "XULScrollElement.h"
 
 #include "mozilla/dom/XULElementBinding.h"
 #include "mozilla/dom/BoxObject.h"
 #include "mozilla/dom/MouseEventBinding.h"
 #include "mozilla/dom/MutationEventBinding.h"
 #include "mozilla/dom/XULCommandEvent.h"
 
 using namespace mozilla;
@@ -152,16 +153,21 @@ nsXULElement* nsXULElement::Construct(al
 
   if (nodeInfo->Equals(nsGkAtoms::iframe) ||
       nodeInfo->Equals(nsGkAtoms::browser) ||
       nodeInfo->Equals(nsGkAtoms::editor)) {
     already_AddRefed<mozilla::dom::NodeInfo> frameni = nodeInfo.forget();
     return new XULFrameElement(frameni);
   }
 
+  if (nodeInfo->Equals(nsGkAtoms::scrollbox)) {
+    already_AddRefed<mozilla::dom::NodeInfo> scrollni = nodeInfo.forget();
+    return new XULScrollElement(scrollni);
+  }
+
   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,18 +4,18 @@
         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;
-  sbo.scrollTo(0, 1000);
+  var scrollbox = document.getElementById('s');
+  scrollbox.scrollTo(0, 1000);
 
   document.documentElement.className = "";
 }
 ]]>
 </script>
 
   <scrollbox id="s" height="200" style="overflow: scroll;">
     <vbox>
--- a/layout/reftests/invalidation/540247-1.xul
+++ b/layout/reftests/invalidation/540247-1.xul
@@ -5,18 +5,18 @@
 
 <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;
-  sbo.scrollTo(0, 1000);
+  var scrollbox = document.getElementById('s');
+  scrollbox.scrollTo(0, 1000);
 }
 
 function finish() {
   document.getElementById('b').height = '100';
   document.documentElement.className = "";
 }
 ]]>
 </script>
--- a/layout/xul/moz.build
+++ b/layout/xul/moz.build
@@ -29,17 +29,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',
@@ -74,17 +73,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,17 @@
       setStatus("Done.");
     }
 
     function scrollTo(id) {
       var line = document.getElementById(id);
       if (!line)
         return;
 
-      var boxObject = document.getElementById("results").parentNode.boxObject;
-      boxObject.scrollToElement(line);
+      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_mousescroll.xul
+++ b/toolkit/content/tests/chrome/test_mousescroll.xul
@@ -200,34 +200,33 @@ function* testRichListbox(id)
     yield* helper(5, -delta,  0, deltaModes[i]);
     yield* helper(5,  delta,  1, deltaModes[i]);
     yield* helper(5,  delta,  0, deltaModes[i]);
   }
 }
 
 function* testArrowScrollbox(id)
 {
-  var scrollbox = document.getElementById(id);
-  var scrollBoxObject = scrollbox.scrollBoxObject;
+  var scrollbox = document.getElementById(id)._scrollbox;
   var orient = scrollbox.getAttribute("orient");
 
   function* helper(aStart, aDelta, aDeltaMode, aExpected)
   {
     var lineOrPageDelta = (aDeltaMode == WheelEvent.DOM_DELTA_PIXEL) ? aDelta / 10 : aDelta;
     var orientIsHorizontal = (orient == "horizontal");
 
-    scrollBoxObject.scrollTo(aStart, aStart);
+    scrollbox.scrollTo(aStart, aStart);
     for (var i = orientIsHorizontal ? 2 : 0; i >= 0; i--) {
       // Note, vertical mouse scrolling is allowed to scroll horizontal
       // arrowscrollboxes, because many users have no horizontal mouse scroll
       // capability
       let expected = !i ? aExpected : aStart;
       let getPos = ()=>{
-        return orientIsHorizontal ? scrollBoxObject.positionX :
-                                    scrollBoxObject.positionY;
+        return orientIsHorizontal ? scrollbox.scrollLeft :
+                                    scrollbox.scrollTop;
       };
       let oldPos = -1;
       let retry = 0;
       yield sendWheelAndWait(scrollbox, 5, 5,
                              { deltaMode: aDeltaMode, deltaY: aDelta,
                                lineOrPageDeltaY: lineOrPageDelta },
                              ()=>{
                                 if (getPos() == expected) {
@@ -260,24 +259,24 @@ function* testArrowScrollbox(id)
       } else {
         is(getPos(), expected,
            "testArrowScrollbox(" + id +  "): vertical, starting " + aStart +
              " delta " + aDelta + " lineOrPageDelta " + lineOrPageDelta +
              " aDeltaMode " + aDeltaMode);
       }
     }
 
-    scrollBoxObject.scrollTo(aStart, aStart);
+    scrollbox.scrollTo(aStart, aStart);
     for (var i = orientIsHorizontal ? 2 : 0; i >= 0; i--) {
       // horizontal mouse scrolling is never allowed to scroll vertical
       // arrowscrollboxes
       let expected = (!i && orientIsHorizontal) ? aExpected : aStart;
       let getPos = ()=>{
-        return orientIsHorizontal ? scrollBoxObject.positionX :
-                                    scrollBoxObject.positionY;
+        return orientIsHorizontal ? scrollbox.scrollLeft :
+                                    scrollbox.scrollTop;
       };
       let oldPos = -1;
       let retry = 0;
       yield sendWheelAndWait(scrollbox, 5, 5,
                              { deltaMode: aDeltaMode, deltaX: aDelta,
                                lineOrPageDeltaX: lineOrPageDelta },
                              ()=>{
                                 if (getPos() == expected) {
@@ -311,20 +310,20 @@ function* testArrowScrollbox(id)
         is(getPos(), expected,
            "testArrowScrollbox(" + id +  "): horizontal, starting " + aStart +
              " delta " + aDelta + " lineOrPageDelta " + lineOrPageDelta +
              " aDeltaMode " + aDeltaMode);
       }
     }
   }
 
-  var scrolledWidth = scrollBoxObject.scrolledWidth;
-  var scrolledHeight = scrollBoxObject.scrolledHeight;
-  var scrollMaxX = scrolledWidth - scrollBoxObject.width;
-  var scrollMaxY = scrolledHeight - scrollBoxObject.height;
+  var scrolledWidth = scrollbox.scrollWidth;
+  var scrolledHeight = scrollbox.scrollHeight;
+  var scrollMaxX = scrolledWidth - scrollbox.boxObject.width;
+  var scrollMaxY = scrolledHeight - scrollbox.boxObject.height;
   var scrollMax = orient == "horizontal" ? scrollMaxX : scrollMaxY;
 
   for (let i = 0; i < deltaModes.length; i++) {
     yield* helper(50, -1000, deltaModes[i], 0);
     yield* helper(50,  1000, deltaModes[i], scrollMax);
   }
 }
 
--- 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/content/tests/chrome/test_richlist_direction.xul
+++ b/toolkit/content/tests/chrome/test_richlist_direction.xul
@@ -26,18 +26,18 @@ var richListBox = document.getElementByI
 
 function getScrollIndexAmount(aDirection) {
   return (4 * aDirection + richListBox.currentIndex);
 }
 
 function test_richlistbox()
 {
   richListBox.minHeight = richListBox.maxHeight = richListBox.height =
-    80 + (80 - richListBox.scrollBoxObject.height);
-  var height = richListBox.scrollBoxObject.height;
+    80 + (80 - richListBox._scrollbox.clientHeight);
+  var height = richListBox._scrollbox.clientHeight;
   var item;
   do {
     item = richListBox.appendItem("Test", "");
     item.height = item.minHeight = item.maxHeight = Math.floor(height / 4);
   } while (item.getBoundingClientRect().bottom < (height * 2))
   richListBox.appendItem("Test", "");
   richListBox.firstChild.nextSibling.id = "list-box-first";
   richListBox.lastChild.previousSibling.id = "list-box-last";
--- a/toolkit/content/tests/chrome/window_largemenu.xul
+++ b/toolkit/content/tests/chrome/window_largemenu.xul
@@ -98,17 +98,17 @@ function popupShown()
   if (gTests[gTestIndex] == "menu movement")
     return testPopupMovement();
 
   if (gContextMenuTests)
     return contextMenuPopupShown();
 
   var popup = document.getElementById("popup");
   var rect = popup.getBoundingClientRect();
-  var sbo = document.getAnonymousNodes(popup)[0].scrollBoxObject;
+  var scrollbox = document.getAnonymousNodes(popup)[0]._scrollbox;
   var expectedScrollPos = 0;
 
   if (gTestIndex == 0) {
     // the popup should be in the center of the screen
     // note that if the height is odd, the y-offset will have been rounded
     // down when we pass the fractional value to openPopupAtScreen above.
     is(Math.round(rect.top) + gScreenY, Math.floor(screen.height / 2),
                               gTests[gTestIndex] + " top");
@@ -136,33 +136,33 @@ function popupShown()
     }
   }
   else if (gTestIndex == 2) {
     // the popup is too large so ensure that it is on screen
     ok(Math.round(rect.top) + gScreenY >= screen.top, gTests[gTestIndex] + " top");
     ok(Math.round(rect.bottom) + gScreenY <= screen.height, gTests[gTestIndex] + " bottom");
     ok(gOverflowed && !gUnderflowed, gTests[gTestIndex] + " overflow")
 
-    sbo.scrollTo(0, 40);
+    scrollbox.scrollTo(0, 40);
     expectedScrollPos = 40;
   }
   else if (gTestIndex == 3) {
     expectedScrollPos = 40;
   }
   else if (gTestIndex == 4) {
     // note that if the height is odd, the y-offset will have been rounded
     // down when we pass the fractional value to openPopupAtScreen above.
     is(Math.round(rect.top) + gScreenY, Math.floor(screen.height / 2),
                               gTests[gTestIndex] + " top");
     ok(Math.round(rect.bottom) + gScreenY < screen.height,
                                 gTests[gTestIndex] + " bottom");
     ok(!gOverflowed && gUnderflowed, gTests[gTestIndex] + " overflow");
   }
 
-  is(sbo.positionY, expectedScrollPos, "menu scroll position");
+  is(scrollbox.scrollTop, expectedScrollPos, "menu scroll position")
 
   hidePopup();
 }
 
 function is(l, r, n) { window.opener.wrappedJSObject.SimpleTest.is(l,r,n); }
 function ok(v, n) { window.opener.wrappedJSObject.SimpleTest.ok(v,n); }
 
 var oldx, oldy, waitSteps = 0;
--- a/toolkit/content/widgets/richlistbox.xml
+++ b/toolkit/content/widgets/richlistbox.xml
@@ -18,19 +18,16 @@
         <children/>
       </xul:scrollbox>
     </content>
 
     <implementation>
       <field name="_scrollbox">
         document.getAnonymousElementByAttribute(this, "anonid", "main-box");
       </field>
-      <field name="scrollBoxObject">
-        this._scrollbox.boxObject;
-      </field>
       <constructor>
         <![CDATA[
           // add a template build listener
           if (this.builder)
             this.builder.addListener(this._builderListener);
           else
             this._refreshSelection();
         ]]>
@@ -94,17 +91,18 @@
                 Ci.nsIDOMXULSelectControlItemElement &&
                 (!this._userSelecting || this._canUserSelect(aStartItem))) {
               --aDelta;
               if (aDelta == 0)
                 return aStartItem;
             }
           }
           return null;
-        ]]></body>
+        ]]>
+        </body>
       </method>
 
       <method name="getPreviousItem">
         <parameter name="aStartItem"/>
         <parameter name="aDelta"/>
         <body>
         <![CDATA[
           var prop = this.dir == "reverse" && this._mayReverse ?
@@ -175,17 +173,16 @@
           ]]>
         </body>
       </method>
 
       <method name="ensureIndexIsVisible">
         <parameter name="aIndex"/>
         <body>
           <![CDATA[
-            // work around missing implementation in scrollBoxObject
             return this.ensureElementIsVisible(this.getItemAtIndex(aIndex));
           ]]>
         </body>
       </method>
 
       <method name="ensureElementIsVisible">
         <parameter name="aElement"/>
         <body>
@@ -208,17 +205,17 @@
       </method>
 
       <method name="scrollToIndex">
         <parameter name="aIndex"/>
         <body>
           <![CDATA[
             var item = this.getItemAtIndex(aIndex);
             if (item)
-              this.scrollBoxObject.scrollToElement(item);
+              this._scrollbox.scrollToElement(item);
           ]]>
         </body>
       </method>
 
       <method name="getNumberOfVisibleRows">
         <!-- returns the number of currently visible rows                -->
         <!-- don't rely on this function, if the items' height can vary! -->
         <body>
@@ -268,22 +265,22 @@
             // at the extreme we're moving away from
             if (!this.currentItem)
               return aDirection == -1 ? children.length : 0;
 
             // If the current item is visible, scroll by one page so that
             // the new current item is at approximately the same position as
             // the existing current item.
             if (this._isItemVisible(this.currentItem))
-              this.scrollBoxObject.scrollBy(0, this.scrollBoxObject.height * aDirection);
+              this._scrollbox.scrollBy(0, this._scrollbox.boxObject.height * aDirection);
 
             // Figure out, how many items fully fit into the view port
             // (including the currently selected one), and determine
             // the index of the first one lying (partially) outside
-            var height = this.scrollBoxObject.height;
+            var height = this._scrollbox.boxObject.height;
             var startBorder = this.currentItem.boxObject.y;
             if (aDirection == -1)
               startBorder += this.currentItem.boxObject.height;
 
             var index = this.currentIndex;
             for (var ix = index; 0 <= ix && ix < children.length; ix += aDirection) {
               var boxObject = children[ix].boxObject;
               if (boxObject.height == 0)
@@ -352,17 +349,17 @@
               if (!currentItem && this._currentIndex)
                 currentItem = this.getItemAtIndex(Math.min(
                   this._currentIndex - 1, this.getRowCount()));
               if (currentItem) {
                 this.currentItem = currentItem;
                 if (this.selType != "multiple" && this.selectedCount == 0)
                   this.selectedItem = currentItem;
 
-                if (this.scrollBoxObject.height) {
+                if (this._scrollbox.boxObject.height) {
                   this.ensureElementIsVisible(currentItem);
                 } else {
                   // XXX hack around a bug in ensureElementIsVisible as it will
                   // scroll beyond the last element, bug 493645.
                   var previousElement = this.dir == "reverse" ? currentItem.nextSibling :
                                                                 currentItem.previousSibling;
                   this.ensureElementIsVisible(previousElement);
                 }
@@ -417,21 +414,21 @@
 
       <method name="_isItemVisible">
         <parameter name="aItem"/>
         <body>
           <![CDATA[
             if (!aItem)
               return false;
 
-            var y = this.scrollBoxObject.positionY + this.scrollBoxObject.y;
+            var y = this._scrollbox.scrollTop + this._scrollbox.boxObject.y;
 
             // Partially visible items are also considered visible
             return (aItem.boxObject.y + aItem.boxObject.height > y) &&
-                   (aItem.boxObject.y < y + this.scrollBoxObject.height);
+                   (aItem.boxObject.y < y + this._scrollbox.boxObject.height);
           ]]>
         </body>
       </method>
 
       <field name="_currentIndex">null</field>
 
       <!-- For backwards-compatibility and for convenience.
         Use getIndexOfItem instead. -->
--- a/toolkit/content/widgets/scrollbox.xml
+++ b/toolkit/content/widgets/scrollbox.xml
@@ -10,25 +10,16 @@
    xmlns:xbl="http://www.mozilla.org/xbl">
 
   <binding id="scrollbox" extends="chrome://global/content/bindings/general.xml#basecontrol">
     <content>
       <xul:box class="box-inherit scrollbox-innerbox" xbl:inherits="orient,align,pack,dir" flex="1">
         <children/>
       </xul:box>
     </content>
-
-    <implementation>
-      <method name="scrollByIndex">
-        <parameter name="index"/>
-        <body>
-          this.boxObject.scrollByIndex(index);
-        </body>
-      </method>
-    </implementation>
   </binding>
 
   <binding id="arrowscrollbox" extends="chrome://global/content/bindings/general.xml#basecontrol">
     <resources>
       <stylesheet src="chrome://global/skin/scrollbox.css"/>
     </resources>
 
     <content>
@@ -110,26 +101,16 @@
           return this.getAttribute("smoothscroll") == "true";
         ]]></getter>
         <setter><![CDATA[
           this.setAttribute("smoothscroll", !!val);
           return val;
         ]]></setter>
       </property>
 
-      <field name="_scrollBoxObject">null</field>
-      <property name="scrollBoxObject" readonly="true">
-        <getter><![CDATA[
-          if (!this._scrollBoxObject) {
-            this._scrollBoxObject = this._scrollbox.boxObject;
-          }
-          return this._scrollBoxObject;
-        ]]></getter>
-      </property>
-
       <property name="scrollClientRect" readonly="true">
         <getter><![CDATA[
           return this._scrollbox.getBoundingClientRect();
         ]]></getter>
       </property>
 
       <property name="scrollClientSize" readonly="true">
         <getter><![CDATA[