Bug 949445 - Part 2: Move Selection to WebIDL; r=bzbarsky
authorEhsan Akhgari <ehsan@mozilla.com>
Tue, 17 Dec 2013 09:12:33 -0500
changeset 160820 12aeb83eaee74f49cc92434a5791804b05cbcbc1
parent 160819 bd02651de80bd72c9ca7a8057c77c78024ac828d
child 160821 8f9955d5f6b1ed34a45951446b62b510214fa1d2
push id37713
push usereakhgari@mozilla.com
push dateTue, 17 Dec 2013 14:12:58 +0000
treeherdermozilla-inbound@8f9955d5f6b1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky
bugs949445
milestone29.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 949445 - Part 2: Move Selection to WebIDL; r=bzbarsky
accessible/src/base/SelectionManager.cpp
accessible/src/generic/HyperTextAccessible.cpp
content/base/public/nsISelectionPrivate.idl
content/base/src/nsContentUtils.cpp
content/html/document/src/nsHTMLDocument.cpp
content/html/document/src/nsHTMLDocument.h
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
dom/bindings/Bindings.conf
dom/imptests/failures/editing/selecttest/Makefile.in
dom/imptests/failures/editing/selecttest/test_interfaces.html.json
dom/webidl/HTMLDocument.webidl
dom/webidl/LegacyQueryInterface.webidl
dom/webidl/Selection.webidl
dom/webidl/moz.build
editor/libeditor/base/nsEditor.cpp
editor/libeditor/html/nsHTMLDataTransfer.cpp
editor/libeditor/html/nsHTMLEditor.cpp
layout/base/tests/chrome/chrome.ini
layout/base/tests/chrome/scroll_selection_into_view_window.html
layout/base/tests/chrome/test_scroll_selection_into_view.html
layout/base/tests/mochitest.ini
layout/base/tests/test_scroll_selection_into_view.html
layout/generic/Selection.h
layout/generic/nsSelection.cpp
layout/generic/test/chrome.ini
layout/generic/test/mochitest.ini
layout/generic/test/test_bug348681.html
--- a/accessible/src/base/SelectionManager.cpp
+++ b/accessible/src/base/SelectionManager.cpp
@@ -115,17 +115,17 @@ SelectionManager::ProcessTextSelChangeEv
 
   // Fire selection change event if it's not pure caret-move selection change.
   if (sel->GetRangeCount() != 1 || !sel->IsCollapsed())
     nsEventShell::FireEvent(aEvent);
 
   // Fire caret move event if there's a caret in the selection.
   nsINode* caretCntrNode =
     nsCoreUtils::GetDOMNodeFromDOMPoint(sel->GetFocusNode(),
-                                        sel->GetFocusOffset());
+                                        sel->FocusOffset());
   if (!caretCntrNode)
     return;
 
   HyperTextAccessible* caretCntr = nsAccUtils::GetTextContainer(caretCntrNode);
   NS_ASSERTION(caretCntr,
                "No text container for focus while there's one for common ancestor?!");
   if (!caretCntr)
     return;
--- a/accessible/src/generic/HyperTextAccessible.cpp
+++ b/accessible/src/generic/HyperTextAccessible.cpp
@@ -1154,17 +1154,17 @@ HyperTextAccessible::CaretOffset() const
     return -1;
 
   // Turn the focus node and offset of the selection into caret hypretext
   // offset.
   Selection* domSel = DOMSelection();
   NS_ENSURE_TRUE(domSel, -1);
 
   nsINode* focusNode = domSel->GetFocusNode();
-  int32_t focusOffset = domSel->GetFocusOffset();
+  uint32_t focusOffset = domSel->FocusOffset();
 
   // No caret if this DOM node is inside of focused node but the selection's
   // focus point is not inside of this DOM node.
   if (focusDisp == FocusManager::eContainedByFocus) {
     nsINode* resultNode =
       nsCoreUtils::GetDOMNodeFromDOMPoint(focusNode, focusOffset);
 
     nsINode* thisNode = GetNode();
@@ -1196,17 +1196,17 @@ HyperTextAccessible::CaretLineNumber()
   if (!caretNode || !caretNode->IsContent())
     return -1;
 
   nsIContent* caretContent = caretNode->AsContent();
   if (!nsCoreUtils::IsAncestorOf(GetNode(), caretContent))
     return -1;
 
   int32_t returnOffsetUnused;
-  int32_t caretOffset = domSel->GetFocusOffset();
+  uint32_t caretOffset = domSel->FocusOffset();
   nsFrameSelection::HINT hint = frameSelection->GetHint();
   nsIFrame *caretFrame = frameSelection->GetFrameForNodeOffset(caretContent, caretOffset,
                                                                hint, &returnOffsetUnused);
   NS_ENSURE_TRUE(caretFrame, -1);
 
   int32_t lineNumber = 1;
   nsAutoLineIterator lineIterForCaret;
   nsIContent *hyperTextContent = IsContent() ? mContent.get() : nullptr;
--- a/content/base/public/nsISelectionPrivate.idl
+++ b/content/base/public/nsISelectionPrivate.idl
@@ -23,56 +23,56 @@ template<class T> class nsTArray;
 
 [ptr] native nsIFrame(nsIFrame);
 [ptr] native RangeArray(nsTArray<nsRange*>);
 [ref] native constTextRangeStyleRef(const mozilla::TextRangeStyle);
 [ref] native nsPointRef(nsPoint);
 native nsDirection(nsDirection);
 native ScrollAxis(nsIPresShell::ScrollAxis);
 
-[scriptable, builtinclass, uuid(fb883d4c-9ddc-423c-b3e2-bb8b93a271cd)]
+[scriptable, builtinclass, uuid(52629837-7b3f-4434-940d-a14de7ef9b7a)]
 interface nsISelectionPrivate : nsISelection
  {
     const short ENDOFPRECEDINGLINE=0;
     const short STARTOFNEXTLINE=1;
-    
+
     attribute boolean interlinePosition;
 
     /* startBatchChanges
        match this up with endbatchChanges. will stop ui updates while multiple selection methods are called
     */
-    void  startBatchChanges();
-    
+    [noscript] void  startBatchChanges();
+
     /* endBatchChanges
        match this up with startBatchChanges
     */
-    void  endBatchChanges();
-		
+    [noscript] void  endBatchChanges();
+
     DOMString  toStringWithFormat(in string formatType, in unsigned long flags, in int32_t wrapColumn);
     void  addSelectionListener(in nsISelectionListener newListener);
     void  removeSelectionListener(in nsISelectionListener listenerToRemove);
 
     /* Table selection stuff
        We should probably move this and table-related 
        items in nsFrameSelection  to a
        new nsITableSelection interface
     */
-    const long TABLESELECTION_NONE     = 0; 
-    const long TABLESELECTION_CELL     = 1; 
-    const long TABLESELECTION_ROW      = 2; 
-    const long TABLESELECTION_COLUMN   = 3; 
-    const long TABLESELECTION_TABLE    = 4; 
+    const long TABLESELECTION_NONE     = 0;
+    const long TABLESELECTION_CELL     = 1;
+    const long TABLESELECTION_ROW      = 2;
+    const long TABLESELECTION_COLUMN   = 3;
+    const long TABLESELECTION_TABLE    = 4;
     const long TABLESELECTION_ALLCELLS = 5;
 
     /** Test if supplied range points to a single table element:
       *    Result is one of above constants. "None" means
       *    a table element isn't selected.
       */
-    long getTableSelectionType(in nsIDOMRange range);
-    
+    [noscript] long getTableSelectionType(in nsIDOMRange range);
+
     /* canCacheFrameOffset
      * Frame Offset cache can be used just during calling nsEditor::EndPlaceHolderTransaction.
      * EndPlaceHolderTransaction will give rise to reflow/refreshing view/scroll, and call times
      * of nsTextFrame::GetPointFromOffset whose return value is to be cached.
      * see bugs 35296 and 199412
      */
     [noscript] attribute boolean canCacheFrameOffset;
 
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -6455,19 +6455,19 @@ nsContentUtils::GetSelectionInTextContro
 
   if (!aSelection->GetRangeCount()) {
     // Nothing selected
     aOutStartOffset = aOutEndOffset = 0;
     return;
   }
 
   nsCOMPtr<nsINode> anchorNode = aSelection->GetAnchorNode();
-  int32_t anchorOffset = aSelection->GetAnchorOffset();
+  uint32_t anchorOffset = aSelection->AnchorOffset();
   nsCOMPtr<nsINode> focusNode = aSelection->GetFocusNode();
-  int32_t focusOffset = aSelection->GetFocusOffset();
+  uint32_t focusOffset = aSelection->FocusOffset();
 
   // We have at most two children, consisting of an optional text node followed
   // by an optional <br>.
   NS_ASSERTION(aRoot->GetChildCount() <= 2, "Unexpected children");
   nsCOMPtr<nsIContent> firstChild = aRoot->GetFirstChild();
 #ifdef DEBUG
   nsCOMPtr<nsIContent> lastChild = aRoot->GetLastChild();
   NS_ASSERTION(anchorNode == aRoot || anchorNode == firstChild ||
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -2091,33 +2091,34 @@ nsHTMLDocument::Embeds()
 NS_IMETHODIMP
 nsHTMLDocument::GetSelection(nsISelection** aReturn)
 {
   ErrorResult rv;
   *aReturn = GetSelection(rv).get();
   return rv.ErrorCode();
 }
 
-already_AddRefed<nsISelection>
+already_AddRefed<Selection>
 nsHTMLDocument::GetSelection(ErrorResult& rv)
 {
   nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(GetScopeObject());
   nsCOMPtr<nsPIDOMWindow> pwin = do_QueryInterface(window);
   if (!pwin) {
     return nullptr;
   }
   NS_ASSERTION(pwin->IsInnerWindow(), "Should have inner window here!");
   if (!pwin->GetOuterWindow() ||
       pwin->GetOuterWindow()->GetCurrentInnerWindow() != pwin) {
     return nullptr;
   }
 
   nsCOMPtr<nsISelection> sel;
   rv = window->GetSelection(getter_AddRefs(sel));
-  return sel.forget();
+  nsRefPtr<Selection> selection = static_cast<Selection*>(sel.get());
+  return selection.forget();
 }
 
 NS_IMETHODIMP
 nsHTMLDocument::CaptureEvents(int32_t aEventFlags)
 {
   WarnOnceAbout(nsIDocument::eUseOfCaptureEvents);
   return NS_OK;
 }
--- a/content/html/document/src/nsHTMLDocument.h
+++ b/content/html/document/src/nsHTMLDocument.h
@@ -234,17 +234,17 @@ public:
   // The XPCOM Get/SetALinkColor work OK for us, since they never throw.
   // The XPCOM Get/SetBgColor work OK for us, since they never throw.
   nsIHTMLCollection* Anchors();
   nsIHTMLCollection* Applets();
   void Clear() const
   {
     // Deprecated
   }
-  already_AddRefed<nsISelection> GetSelection(mozilla::ErrorResult& rv);
+  already_AddRefed<mozilla::Selection> GetSelection(mozilla::ErrorResult& rv);
   // The XPCOM CaptureEvents works fine for us.
   // The XPCOM ReleaseEvents works fine for us.
   // We're picking up GetLocation from Document
   already_AddRefed<nsIDOMLocation> GetLocation() const {
     return nsIDocument::GetLocation();
   }
 
   virtual nsHTMLDocument* AsHTMLDocument() MOZ_OVERRIDE { return this; }
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -8814,31 +8814,31 @@ nsGlobalWindow::UpdateCommands(const nsA
       nsContentUtils::AddScriptRunner(new CommandDispatcher(xulCommandDispatcher,
                                                             anAction));
     }
   }
 
   return NS_OK;
 }
 
-nsISelection*
+Selection*
 nsGlobalWindow::GetSelection(ErrorResult& aError)
 {
   FORWARD_TO_OUTER_OR_THROW(GetSelection, (aError), aError, nullptr);
 
   if (!mDocShell) {
     return nullptr;
   }
 
   nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
   if (!presShell) {
     return nullptr;
   }
-    
-  return presShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
+
+  return static_cast<Selection*>(presShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL));
 }
 
 NS_IMETHODIMP
 nsGlobalWindow::GetSelection(nsISelection** aSelection)
 {
   ErrorResult rv;
   nsCOMPtr<nsISelection> selection = GetSelection(rv);
   selection.forget(aSelection);
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -99,16 +99,17 @@ class nsDOMEventTargetHelper;
 class nsDOMWindowUtils;
 class nsIIdleService;
 struct nsIntSize;
 struct nsRect;
 
 class nsWindowSizes;
 
 namespace mozilla {
+class Selection;
 namespace dom {
 class BarProp;
 class Function;
 class Gamepad;
 class MediaQueryList;
 class Navigator;
 class SpeechSynthesis;
 namespace indexedDB {
@@ -841,17 +842,17 @@ public:
                       mozilla::ErrorResult& aError);
   void ClearInterval(int32_t aHandle, mozilla::ErrorResult& aError);
   void Atob(const nsAString& aAsciiBase64String, nsAString& aBinaryData,
             mozilla::ErrorResult& aError);
   void Btoa(const nsAString& aBinaryData, nsAString& aAsciiBase64String,
             mozilla::ErrorResult& aError);
   nsIDOMStorage* GetSessionStorage(mozilla::ErrorResult& aError);
   nsIDOMStorage* GetLocalStorage(mozilla::ErrorResult& aError);
-  nsISelection* GetSelection(mozilla::ErrorResult& aError);
+  mozilla::Selection* GetSelection(mozilla::ErrorResult& aError);
   mozilla::dom::indexedDB::IDBFactory* GetIndexedDB(mozilla::ErrorResult& aError);
   already_AddRefed<nsICSSDeclaration>
     GetComputedStyle(mozilla::dom::Element& aElt, const nsAString& aPseudoElt,
                      mozilla::ErrorResult& aError);
   already_AddRefed<mozilla::dom::MediaQueryList> MatchMedia(const nsAString& aQuery,
                                                             mozilla::ErrorResult& aError);
   nsScreen* GetScreen(mozilla::ErrorResult& aError);
   void MoveTo(int32_t aXPos, int32_t aYPos, mozilla::ErrorResult& aError);
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -960,16 +960,21 @@ DOMInterfaces = {
 'Screen': {
     'nativeType': 'nsScreen',
 },
 
 'ScrollAreaEvent': {
     'nativeType': 'nsDOMScrollAreaEvent',
 },
 
+'Selection': {
+    'nativeType': 'mozilla::Selection',
+    'resultNotAddRefed': [ 'anchorNode', 'focusNode', 'getRangeAt' ],
+},
+
 'ShadowRoot': {
     'resultNotAddRefed': [
         'styleSheets'
     ]
 },
 
 'SharedWorker': {
     'nativeType': 'mozilla::dom::workers::SharedWorker',
@@ -1886,27 +1891,27 @@ addExternalIface('MozVoicemailStatus')
 addExternalIface('MozWakeLock', headerFile='nsIDOMWakeLock.h')
 addExternalIface('MozWakeLockListener', headerFile='nsIDOMWakeLockListener.h')
 addExternalIface('MozXULTemplateBuilder', nativeType='nsIXULTemplateBuilder')
 addExternalIface('nsIControllers', nativeType='nsIControllers')
 addExternalIface('nsIDOMCrypto', nativeType='nsIDOMCrypto',
                  headerFile='Crypto.h')
 addExternalIface('nsIInputStreamCallback', nativeType='nsIInputStreamCallback',
                  headerFile='nsIAsyncInputStream.h')
+addExternalIface('nsISelectionListener', nativeType='nsISelectionListener')
 addExternalIface('nsIStreamListener', nativeType='nsIStreamListener', notflattened=True)
 addExternalIface('nsISupports', nativeType='nsISupports')
 addExternalIface('nsIDocShell', nativeType='nsIDocShell', notflattened=True)
 addExternalIface('nsIEditor', nativeType='nsIEditor', notflattened=True)
 addExternalIface('nsIVariant', nativeType='nsIVariant', notflattened=True)
 addExternalIface('OutputStream', nativeType='nsIOutputStream',
                  notflattened=True)
 addExternalIface('Pkcs11')
 addExternalIface('Principal', nativeType='nsIPrincipal',
                  headerFile='nsIPrincipal.h', notflattened=True)
-addExternalIface('Selection', nativeType='nsISelection')
 addExternalIface('StackFrame', nativeType='nsIStackFrame',
                  headerFile='nsIException.h', notflattened=True)
 addExternalIface('StyleSheetList')
 addExternalIface('SVGLength')
 addExternalIface('SVGNumber')
 addExternalIface('URI', nativeType='nsIURI', headerFile='nsIURI.h',
                  notflattened=True)
 addExternalIface('UserDataHandler')
--- a/dom/imptests/failures/editing/selecttest/Makefile.in
+++ b/dom/imptests/failures/editing/selecttest/Makefile.in
@@ -2,12 +2,11 @@
 
 MOCHITEST_FILES := \
   test_Document-open.html.json \
   test_addRange.html.json \
   test_collapse.html.json \
   test_collapseToStartEnd.html.json \
   test_extend.html.json \
   test_getSelection.html.json \
-  test_interfaces.html.json \
   test_removeAllRanges.html.json \
   test_selectAllChildren.html.json \
   $(NULL)
deleted file mode 100644
--- a/dom/imptests/failures/editing/selecttest/test_interfaces.html.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-  "Selection interface: existence and properties of interface object":true,
-  "Selection interface: existence and properties of interface prototype object":true,
-  "Selection interface object length":true,
-  "Selection interface: existence and properties of interface prototype object's \"constructor\" property":true,
-  "Selection interface: attribute anchorNode":true,
-  "Selection interface: attribute anchorOffset":true,
-  "Selection interface: attribute focusNode":true,
-  "Selection interface: attribute focusOffset":true,
-  "Selection interface: attribute isCollapsed":true,
-  "Selection interface: attribute rangeCount":true,
-  "Selection interface: calling collapse(Node,unsigned long) on getSelection() with too few arguments must throw TypeError":true,
-  "Selection interface: calling extend(Node,unsigned long) on getSelection() with too few arguments must throw TypeError":true,
-  "Selection interface: calling selectAllChildren(Node) on getSelection() with too few arguments must throw TypeError":true,
-  "Selection interface: calling getRangeAt(unsigned long) on getSelection() with too few arguments must throw TypeError":true,
-  "Selection interface: calling addRange(Range) on getSelection() with too few arguments must throw TypeError":true,
-  "Selection interface: calling removeRange(Range) on getSelection() with too few arguments must throw TypeError":true
-}
--- a/dom/webidl/HTMLDocument.webidl
+++ b/dom/webidl/HTMLDocument.webidl
@@ -1,16 +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/.
  */
 
-interface Selection;
-
 [OverrideBuiltins]
 interface HTMLDocument : Document {
            [Throws]
            attribute DOMString? domain;
            [Throws]
            attribute DOMString cookie;
   // DOM tree accessors
   [Throws]
@@ -74,16 +72,16 @@ interface HTMLDocument : Document {
 
   void clear();
 
   [Throws]
   readonly attribute object all;
 
   // https://dvcs.w3.org/hg/editing/raw-file/tip/editing.html#selections
   [Throws]
-  Selection getSelection();
+  Selection? getSelection();
 
   // @deprecated These are old Netscape 4 methods. Do not use,
   //             the implementation is no-op.
   // XXXbz do we actually need these anymore?
   void                      captureEvents(long eventFlags);
   void                      releaseEvents(long eventFlags);
 };
--- a/dom/webidl/LegacyQueryInterface.webidl
+++ b/dom/webidl/LegacyQueryInterface.webidl
@@ -57,16 +57,17 @@ OfflineResourceList implements LegacyQue
 PaintRequest implements LegacyQueryInterface;
 PaintRequestList implements LegacyQueryInterface;
 Performance implements LegacyQueryInterface;
 Plugin implements LegacyQueryInterface;
 PluginArray implements LegacyQueryInterface;
 ProcessingInstruction implements LegacyQueryInterface;
 Range implements LegacyQueryInterface;
 Rect implements LegacyQueryInterface;
+Selection implements LegacyQueryInterface;
 SVGAnimatedEnumeration implements LegacyQueryInterface;
 SVGAnimatedInteger implements LegacyQueryInterface;
 SVGAnimatedNumber implements LegacyQueryInterface;
 SVGAnimatedNumberList implements LegacyQueryInterface;
 SVGAnimatedPreserveAspectRatio implements LegacyQueryInterface;
 SVGAnimatedString implements LegacyQueryInterface;
 SVGLengthList implements LegacyQueryInterface;
 SVGNumberList implements LegacyQueryInterface;
new file mode 100644
--- /dev/null
+++ b/dom/webidl/Selection.webidl
@@ -0,0 +1,85 @@
+/* -*- 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/.
+ *
+ * The origin of this IDL file is
+ * https://dvcs.w3.org/hg/editing/raw-file/tip/editing.html#concept-selection
+ *
+ * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+interface Selection {
+  readonly attribute Node? anchorNode;
+  readonly attribute unsigned long anchorOffset;
+  readonly attribute Node? focusNode;
+  readonly attribute unsigned long focusOffset;
+
+  readonly attribute boolean isCollapsed;
+  [Throws]
+  void               collapse(Node node, unsigned long offset);
+  [Throws]
+  void               collapseToStart();
+  [Throws]
+  void               collapseToEnd();
+
+  [Throws]
+  void               extend(Node node, unsigned long offset);
+
+  [Throws]
+  void               selectAllChildren(Node node);
+  [Throws]
+  void               deleteFromDocument();
+
+  readonly attribute unsigned long rangeCount;
+  [Throws]
+  Range              getRangeAt(unsigned long index);
+  [Throws]
+  void               addRange(Range range);
+  [Throws]
+  void               removeRange(Range range);
+  [Throws]
+  void               removeAllRanges();
+
+  stringifier;
+};
+
+// Additional methods not currently in the spec
+partial interface Selection {
+  [Throws]
+  boolean containsNode(Node? node, boolean partlyContained);
+
+  [Throws]
+  void modify(DOMString alter, DOMString direction,
+              DOMString granularity);
+};
+
+// Additional chrome-only methods from nsISelectionPrivate
+interface nsISelectionListener;
+partial interface Selection {
+  [ChromeOnly]
+  const short ENDOFPRECEDINGLINE = 0;
+  [ChromeOnly]
+  const short STARTOFNEXTLINE = 1;
+
+  [ChromeOnly,Throws]
+  attribute boolean interlinePosition;
+
+  [ChromeOnly,Throws]
+  DOMString  toStringWithFormat(DOMString formatType, unsigned long flags, long wrapColumn);
+  [ChromeOnly,Throws]
+  void  addSelectionListener(nsISelectionListener newListener);
+  [ChromeOnly,Throws]
+  void  removeSelectionListener(nsISelectionListener listenerToRemove);
+
+  [ChromeOnly]
+  readonly attribute short type;
+
+  [ChromeOnly,Throws,Pref="dom.testing.selection.GetRangesForInterval"]
+  sequence<Range> GetRangesForInterval(Node beginNode, long beginOffset, Node endNode, long endOffset,
+                                       boolean allowAdjacent);
+
+  [ChromeOnly,Throws]
+  void scrollIntoView(short aRegion, boolean aIsSynchronous, short aVPercent, short aHPercent);
+};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -269,16 +269,17 @@ WEBIDL_FILES = [
     'RTCConfiguration.webidl',
     'RTCIceCandidate.webidl',
     'RTCPeerConnection.webidl',
     'RTCSessionDescription.webidl',
     'RTCStatsReport.webidl',
     'Screen.webidl',
     'ScriptProcessorNode.webidl',
     'ScrollAreaEvent.webidl',
+    'Selection.webidl',
     'SettingsManager.webidl',
     'ShadowRoot.webidl',
     'SharedWorker.webidl',
     'SharedWorkerGlobalScope.webidl',
     'SimpleGestureEvent.webidl',
     'SourceBuffer.webidl',
     'SourceBufferList.webidl',
     'StorageType.webidl',
--- a/editor/libeditor/base/nsEditor.cpp
+++ b/editor/libeditor/base/nsEditor.cpp
@@ -4157,17 +4157,17 @@ nsEditor::DeleteSelectionAndCreateNode(c
 {
   nsresult result = DeleteSelectionAndPrepareToCreateNode();
   NS_ENSURE_SUCCESS(result, result);
 
   nsRefPtr<Selection> selection = GetSelection();
   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
 
   nsCOMPtr<nsINode> node = selection->GetAnchorNode();
-  int32_t offset = selection->GetAnchorOffset();
+  uint32_t offset = selection->AnchorOffset();
 
   nsCOMPtr<nsIDOMNode> newNode;
   result = CreateNode(aTag, node->AsDOMNode(), offset,
                       getter_AddRefs(newNode));
   // XXX: ERROR_HANDLING  check result, and make sure aNewNode is set correctly
   // in success/failure cases
   *aNewNode = newNode;
   NS_IF_ADDREF(*aNewNode);
@@ -4243,24 +4243,24 @@ nsEditor::DeleteSelectionAndPrepareToCre
   MOZ_ASSERT(node, "Selection has no ranges in it");
 
   if (node && node->IsNodeOfType(nsINode::eDATA_NODE)) {
     NS_ASSERTION(node->GetParentNode(),
                  "It's impossible to insert into chardata with no parent -- "
                  "fix the caller");
     NS_ENSURE_STATE(node->GetParentNode());
 
-    int32_t offset = selection->GetAnchorOffset();
+    uint32_t offset = selection->AnchorOffset();
 
     if (offset == 0) {
       res = selection->Collapse(node->GetParentNode(),
                                 node->GetParentNode()->IndexOf(node));
       MOZ_ASSERT(NS_SUCCEEDED(res));
       NS_ENSURE_SUCCESS(res, res);
-    } else if (offset == (int32_t)node->Length()) {
+    } else if (offset == node->Length()) {
       res = selection->Collapse(node->GetParentNode(),
                                 node->GetParentNode()->IndexOf(node) + 1);
       MOZ_ASSERT(NS_SUCCEEDED(res));
       NS_ENSURE_SUCCESS(res, res);
     } else {
       nsCOMPtr<nsIDOMNode> tmp;
       res = SplitNode(node->AsDOMNode(), offset, getter_AddRefs(tmp));
       NS_ENSURE_SUCCESS(res, res);
--- a/editor/libeditor/html/nsHTMLDataTransfer.cpp
+++ b/editor/libeditor/html/nsHTMLDataTransfer.cpp
@@ -364,17 +364,17 @@ nsHTMLEditor::DoInsertHTMLWithContext(co
   {
     rv = DeleteSelectionAndPrepareToCreateNode();
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (aClearStyle) {
       // pasting does not inherit local inline styles
       nsCOMPtr<nsIDOMNode> tmpNode =
         do_QueryInterface(selection->GetAnchorNode());
-      int32_t tmpOffset = selection->GetAnchorOffset();
+      int32_t tmpOffset = static_cast<int32_t>(selection->AnchorOffset());
       rv = ClearStyle(address_of(tmpNode), &tmpOffset, nullptr, nullptr);
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
   else
   {
     // delete whole cells: we will replace with new table content
     { // Braces for artificial block to scope nsAutoSelectionReset.
--- a/editor/libeditor/html/nsHTMLEditor.cpp
+++ b/editor/libeditor/html/nsHTMLEditor.cpp
@@ -2283,17 +2283,17 @@ nsHTMLEditor::GetElementOrParentByTagNam
     nsRefPtr<Selection> selection = GetSelection();
     NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
 
     nsCOMPtr<nsINode> anchorNode = selection->GetAnchorNode();
     NS_ENSURE_TRUE(anchorNode, NS_ERROR_FAILURE);
 
     // Try to get the actual selected node
     if (anchorNode->HasChildNodes() && anchorNode->IsContent()) {
-      int32_t offset = selection->GetAnchorOffset();
+      uint32_t offset = selection->AnchorOffset();
       current = anchorNode->GetChildAt(offset);
     }
     // anchor node is probably a text node - just use that
     if (!current) {
       current = anchorNode;
     }
   }
 
--- a/layout/base/tests/chrome/chrome.ini
+++ b/layout/base/tests/chrome/chrome.ini
@@ -37,12 +37,14 @@ support-files =
 [test_leaf_layers_partition_browser_window.xul]
 skip-if = (!debug) || (toolkit == "cocoa") # Disabled on Mac because of Bug 748219
 [test_no_clip_iframe.xul]
 [test_passpointerevents.html]
 [test_prerendered_transforms.html]
 [test_printpreview.xul]
 [test_printpreview_bug396024.xul]
 [test_printpreview_bug482976.xul]
+[test_scroll_selection_into_view.html]
+support-files=scroll_selection_into_view_window.html
 [test_scrolling_repaints.html]
 [test_transformed_scrolling_repaints.html]
 [test_transformed_scrolling_repaints_2.html]
 [test_transformed_scrolling_repaints_3.html]
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/chrome/scroll_selection_into_view_window.html
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for scrolling selection into view</title>
+</head>
+<body onload="opener.doTest();">
+
+<div id="c1" style="overflow-y:scroll; width:200px; height:200px; position:absolute; top:200px; left:0;">
+  <div style="height:400px;"></div>
+  <div><span id="target1"
+        style="display:inline-block; vertical-align:top; height:20px;">target</span>
+  </div>
+  <div style="height:400px;"></div>
+</div>
+<div id="c2" style="overflow:hidden; width:200px; height:200px; position:absolute; top:200px; left:200px;">
+  <div style="height:400px;"></div>
+  <div><span id="target2"
+        style="display:inline-block; vertical-align:top; height:20px;">target2</span>
+  </div>
+  <div style="height:400px;"></div>
+</div>
+<div id="c3" style="overflow-y:scroll; width:200px; height:200px; position:absolute; top:200px; left:400px;">
+  <div style="height:400px;"></div>
+  <div><span id="target3"
+        style="display:inline-block; vertical-align:top; height:300px;">target3</span>
+  </div>
+  <div style="height:400px;"></div>
+</div>
+<div id="c4" style="overflow-y:scroll; width:200px; height:200px; position:absolute; top:200px; left:600px;">
+  <iframe id="target4" style="border:none; width:100%; height:1100px; display:block;"
+          src="data:text/html,
+               <body style='margin:0; overflow:hidden;'>
+                 <div style='height:400px;'></div>
+                 <div><span id='target4'
+                            style='display:inline-block; vertical-align:top; height:300px;'>target4</span>
+                 </div>
+                 <div style='height:400px;'></div>">
+  </iframe>
+</div>
+<div id="c5" style="overflow-y:scroll; width:200px; height:200px; position:absolute; top:400px; left:0;">
+  <div style="-moz-transform:translateY(400px); transform:translateY(400px)">
+    <span id="target5" style="display:inline-block; vertical-align:top; height:20px;">target</span>
+  </div>
+  <div style="height:800px;"></div>
+</div>
+<div id="c6" style="overflow-y:scroll; width:200px; height:200px; position:absolute; top:400px; left:200px;">
+  <div style="height:200px"></div>
+  <div style="height:100px; -moz-transform:scale(2); transform:scale(2)">
+    <span id="target6" style="display:inline-block; vertical-align:top; height:20px;">target</span>
+  </div>
+  <div style="height:800px;"></div>
+</div>
+<div id="c7" style="overflow-y:scroll; width:200px; height:200px; position:absolute; top:400px; left:400px;">
+  <div style="overflow:auto; height:200px; -moz-transform:translateY(400px); transform:translateY(400px)">
+    <div style="height:200px;"></div>
+    <div>
+      <span id="target7" style="display:inline-block; vertical-align:top; height:20px;">target</span>
+    </div>
+    <div style="height:800px;"></div>
+  </div>
+  <div style="height:800px;"></div>
+</div>
+
+</body>
+
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/chrome/test_scroll_selection_into_view.html
@@ -0,0 +1,97 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for scrolling selection into view</title>
+  <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var ANCHOR = 0;
+var FOCUS = 1;
+var win;
+
+function testCollapsed(id, vPercent, startAt, expected) {
+  var selection = win.getSelection().QueryInterface(SpecialPowers.Ci.nsISelectionPrivate);
+
+  var c = win.document.getElementById("c" + id);
+  var target = win.document.getElementById("target" + id);
+  if (target.contentDocument) {
+    selection = target.contentWindow.getSelection().QueryInterface(SpecialPowers.Ci.nsISelectionPrivate);
+    target = target.contentDocument.getElementById("target" + id);
+  }
+  selection.collapse(target.parentNode, 0);
+  c.scrollTop = startAt;
+  selection.scrollIntoView(FOCUS, true, vPercent, 0);
+  is(c.scrollTop, expected, "Scrolling " + target.id +
+     " into view with vPercent " + vPercent + ", starting at " + startAt);
+}
+
+function doTest() {
+  // Test scrolling an element smaller than the scrollport
+  testCollapsed("1", 0, 0, 400);
+  testCollapsed("1", 100, 0, 220);
+  testCollapsed("1", -1, 0, 220);
+  testCollapsed("1", 0, 500, 400);
+  testCollapsed("1", 100, 500, 220);
+  testCollapsed("1", -1, 500, 400);
+
+  // overflow:hidden elements should not be scrolled by selection
+  // scrolling-into-view
+  testCollapsed("2", 0, 0, 0);
+  testCollapsed("2", 100, 0, 0);
+  testCollapsed("2", -1, 0, 0);
+  testCollapsed("2", 0, 500, 500);
+  testCollapsed("2", 100, 500, 500);
+  testCollapsed("2", -1, 500, 500);
+
+  // Test scrolling an element larger than the scrollport
+  testCollapsed("3", 0, 0, 400);
+  testCollapsed("3", 100, 0, 500);
+  testCollapsed("3", -1, 0, 400);
+  testCollapsed("3", 0, 1000, 400);
+  testCollapsed("3", 100, 1000, 500);
+  // If the element can't be completely visible, we make the top edge
+  // visible.
+  testCollapsed("3", -1, 1000, 400);
+
+  // Test scrolling an element larger than the scrollport
+  testCollapsed("4", 0, 0, 400);
+  testCollapsed("4", 100, 0, 500);
+  testCollapsed("4", -1, 0, 400);
+  testCollapsed("4", 0, 1000, 400);
+  testCollapsed("4", 100, 1000, 500);
+  // If the element can't be completely visible, we make the top edge
+  // visible.
+  testCollapsed("4", -1, 1000, 400);
+
+  // Test that scrolling a translated element into view takes
+  // account of the transform.
+  testCollapsed("5", 0, 0, 400);
+
+  // Test that scrolling a scaled element into view takes
+  // account of the transform.
+  testCollapsed("6", 0, 0, 150);
+
+  // Test that scrolling an element with a translated, scrolling container
+  // into view takes account of the transform.
+  testCollapsed("7", 0, 0, 400);
+
+  win.close();
+  SimpleTest.finish();
+}
+
+function openWindow() {
+  win = open("scroll_selection_into_view_window.html", "_blank", "width=500,height=350");
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(openWindow);
+</script>
+</pre>
+</body>
+
+</html>
--- a/layout/base/tests/mochitest.ini
+++ b/layout/base/tests/mochitest.ini
@@ -158,17 +158,16 @@ support-files = file_bug607529.html
 [test_bug667512.html]
 [test_bug677878.html]
 [test_bug696020.html]
 [test_event_target_radius.html]
 [test_event_target_iframe_oop.html]
 support-files = bug921928_event_target_iframe_apps_oop.html
 [test_mozPaintCount.html]
 [test_scroll_event_ordering.html]
-[test_scroll_selection_into_view.html]
 [test_bug583889.html]
 support-files = bug583889_inner1.html bug583889_inner2.html
 [test_bug582771.html]
 [test_bug603550.html]
 [test_bug629838.html]
 [test_bug646757.html]
 [test_bug718809.html]
 [test_bug725426.html]
deleted file mode 100644
--- a/layout/base/tests/test_scroll_selection_into_view.html
+++ /dev/null
@@ -1,148 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <title>Test for scrolling selection into view</title>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body>
-
-<p id="display"></p>
-<div id="c1" style="overflow-y:scroll; width:200px; height:200px; position:absolute; top:200px; left:0;">
-  <div style="height:400px;"></div>
-  <div><span id="target1"
-        style="display:inline-block; vertical-align:top; height:20px;">target</span>
-  </div>
-  <div style="height:400px;"></div>
-</div>
-<div id="c2" style="overflow:hidden; width:200px; height:200px; position:absolute; top:200px; left:200px;">
-  <div style="height:400px;"></div>
-  <div><span id="target2"
-        style="display:inline-block; vertical-align:top; height:20px;">target2</span>
-  </div>
-  <div style="height:400px;"></div>
-</div>
-<div id="c3" style="overflow-y:scroll; width:200px; height:200px; position:absolute; top:200px; left:400px;">
-  <div style="height:400px;"></div>
-  <div><span id="target3"
-        style="display:inline-block; vertical-align:top; height:300px;">target3</span>
-  </div>
-  <div style="height:400px;"></div>
-</div>
-<div id="c4" style="overflow-y:scroll; width:200px; height:200px; position:absolute; top:200px; left:600px;">
-  <iframe id="target4" style="border:none; width:100%; height:1100px; display:block;"
-          src="data:text/html,
-               <body style='margin:0; overflow:hidden;'>
-                 <div style='height:400px;'></div>
-                 <div><span id='target4'
-                            style='display:inline-block; vertical-align:top; height:300px;'>target4</span>
-                 </div>
-                 <div style='height:400px;'></div>">
-  </iframe>
-</div>
-<div id="c5" style="overflow-y:scroll; width:200px; height:200px; position:absolute; top:400px; left:0;">
-  <div style="-moz-transform:translateY(400px); transform:translateY(400px)">
-    <span id="target5" style="display:inline-block; vertical-align:top; height:20px;">target</span>
-  </div>
-  <div style="height:800px;"></div>
-</div>
-<div id="c6" style="overflow-y:scroll; width:200px; height:200px; position:absolute; top:400px; left:200px;">
-  <div style="height:200px"></div>
-  <div style="height:100px; -moz-transform:scale(2); transform:scale(2)">
-    <span id="target6" style="display:inline-block; vertical-align:top; height:20px;">target</span>
-  </div>
-  <div style="height:800px;"></div>
-</div>
-<div id="c7" style="overflow-y:scroll; width:200px; height:200px; position:absolute; top:400px; left:400px;">
-  <div style="overflow:auto; height:200px; -moz-transform:translateY(400px); transform:translateY(400px)">
-    <div style="height:200px;"></div>
-    <div>
-      <span id="target7" style="display:inline-block; vertical-align:top; height:20px;">target</span>
-    </div>
-    <div style="height:800px;"></div>
-  </div>
-  <div style="height:800px;"></div>
-</div>
-
-<pre id="test">
-<script class="testbody" type="text/javascript">
-
-var ANCHOR = 0;
-var FOCUS = 1;
-
-function testCollapsed(id, vPercent, startAt, expected) {
-  var selection = window.getSelection().QueryInterface(SpecialPowers.Ci.nsISelectionPrivate);
-
-  var c = document.getElementById("c" + id);
-  var target = document.getElementById("target" + id);
-  if (target.contentDocument) {
-    selection = target.contentWindow.getSelection().QueryInterface(SpecialPowers.Ci.nsISelectionPrivate);
-    target = target.contentDocument.getElementById("target" + id);
-  }
-  selection.collapse(target.parentNode, 0);
-  c.scrollTop = startAt;
-  selection.scrollIntoView(FOCUS, true, vPercent, 0);
-  is(c.scrollTop, expected, "Scrolling " + target.id +
-     " into view with vPercent " + vPercent + ", starting at " + startAt);
-}
-
-function doTest() {
-  // Test scrolling an element smaller than the scrollport
-  testCollapsed("1", 0, 0, 400);
-  testCollapsed("1", 100, 0, 220);
-  testCollapsed("1", -1, 0, 220);
-  testCollapsed("1", 0, 500, 400);
-  testCollapsed("1", 100, 500, 220);
-  testCollapsed("1", -1, 500, 400);
-
-  // overflow:hidden elements should not be scrolled by selection
-  // scrolling-into-view
-  testCollapsed("2", 0, 0, 0);
-  testCollapsed("2", 100, 0, 0);
-  testCollapsed("2", -1, 0, 0);
-  testCollapsed("2", 0, 500, 500);
-  testCollapsed("2", 100, 500, 500);
-  testCollapsed("2", -1, 500, 500);
-
-  // Test scrolling an element larger than the scrollport
-  testCollapsed("3", 0, 0, 400);
-  testCollapsed("3", 100, 0, 500);
-  testCollapsed("3", -1, 0, 400);
-  testCollapsed("3", 0, 1000, 400);
-  testCollapsed("3", 100, 1000, 500);
-  // If the element can't be completely visible, we make the top edge
-  // visible.
-  testCollapsed("3", -1, 1000, 400);
-
-  // Test scrolling an element larger than the scrollport
-  testCollapsed("4", 0, 0, 400);
-  testCollapsed("4", 100, 0, 500);
-  testCollapsed("4", -1, 0, 400);
-  testCollapsed("4", 0, 1000, 400);
-  testCollapsed("4", 100, 1000, 500);
-  // If the element can't be completely visible, we make the top edge
-  // visible.
-  testCollapsed("4", -1, 1000, 400);
-
-  // Test that scrolling a translated element into view takes
-  // account of the transform.
-  testCollapsed("5", 0, 0, 400);
-
-  // Test that scrolling a scaled element into view takes
-  // account of the transform.
-  testCollapsed("6", 0, 0, 150);
-
-  // Test that scrolling an element with a translated, scrolling container
-  // into view takes account of the transform.
-  testCollapsed("7", 0, 0, 400);
-
-  SimpleTest.finish();
-}
-
-SimpleTest.waitForExplicitFinish();
-addLoadEvent(doTest);
-</script>
-</pre>
-</body>
-
-</html>
--- a/layout/generic/Selection.h
+++ b/layout/generic/Selection.h
@@ -10,24 +10,29 @@
 #include "nsIWeakReference.h"
 
 #include "nsISelection.h"
 #include "nsISelectionController.h"
 #include "nsISelectionPrivate.h"
 #include "nsRange.h"
 #include "nsThreadUtils.h"
 #include "mozilla/TextRange.h"
+#include "nsWrapperCache.h"
 
 struct CachedOffsetForFrame;
 class nsAutoScrollTimer;
 class nsIContentIterator;
 class nsIFrame;
 class nsFrameSelection;
 struct SelectionDetails;
 
+namespace mozilla {
+class ErrorResult;
+}
+
 struct RangeData
 {
   RangeData(nsRange* aRange)
     : mRange(aRange)
   {}
 
   nsRefPtr<nsRange> mRange;
   mozilla::TextRangeStyle mTextRangeStyle;
@@ -36,28 +41,31 @@ struct RangeData
 // Note, the ownership of mozilla::Selection depends on which way the object is
 // created. When nsFrameSelection has created Selection, addreffing/releasing
 // the Selection object is aggregated to nsFrameSelection. Otherwise normal
 // addref/release is used.  This ensures that nsFrameSelection is never deleted
 // before its Selections.
 namespace mozilla {
 
 class Selection : public nsISelectionPrivate,
+                  public nsWrapperCache,
                   public nsSupportsWeakReference
 {
 public:
   Selection();
   Selection(nsFrameSelection *aList);
   virtual ~Selection();
-  
+
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(Selection, nsISelectionPrivate)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(Selection, nsISelectionPrivate)
   NS_DECL_NSISELECTION
   NS_DECL_NSISELECTIONPRIVATE
 
+  nsIDocument* GetParentObject() const;
+
   // utility methods for scrolling the selection into view
   nsPresContext* GetPresContext() const;
   nsIPresShell* GetPresShell() const;
   nsFrameSelection* GetFrameSelection() const { return mFrameSelection; }
   // Returns a rect containing the selection region, and frame that that
   // position is relative to. For SELECTION_ANCHOR_REGION or
   // SELECTION_FOCUS_REGION the rect is a zero-width rectangle. For
   // SELECTION_WHOLE_SELECTION the rect contains both the anchor and focus
@@ -93,25 +101,16 @@ public:
   nsresult      RemoveItem(nsRange *aRange);
   nsresult      RemoveCollapsedRanges();
   nsresult      Clear(nsPresContext* aPresContext);
   nsresult      Collapse(nsINode* aParentNode, int32_t aOffset);
   nsresult      Extend(nsINode* aParentNode, int32_t aOffset);
   nsRange*      GetRangeAt(int32_t aIndex);
   int32_t GetRangeCount() { return mRanges.Length(); }
 
-  // methods for convenience. Note, these don't addref
-  nsINode*     GetAnchorNode();
-  int32_t      GetAnchorOffset();
-
-  nsINode*     GetFocusNode();
-  int32_t      GetFocusOffset();
-
-  bool IsCollapsed();
-
   // Get the anchor-to-focus range if we don't care which end is
   // anchor and which end is focus.
   const nsRange* GetAnchorFocusRange() const {
     return mAnchorFocusRange;
   }
 
   nsDirection  GetDirection(){return mDirection;}
   void         SetDirection(nsDirection aDir){mDirection = aDir;}
@@ -127,16 +126,75 @@ public:
 
   // Note: StartAutoScrollTimer might destroy arbitrary frames etc.
   nsresult     StartAutoScrollTimer(nsIFrame *aFrame,
                                     nsPoint& aPoint,
                                     uint32_t aDelay);
 
   nsresult     StopAutoScrollTimer();
 
+  JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
+
+  // WebIDL methods
+  nsINode*     GetAnchorNode();
+  uint32_t     AnchorOffset();
+  nsINode*     GetFocusNode();
+  uint32_t     FocusOffset();
+
+  bool IsCollapsed();
+  void Collapse(nsINode& aNode, uint32_t aOffset, mozilla::ErrorResult& aRv);
+  void CollapseToStart(mozilla::ErrorResult& aRv);
+  void CollapseToEnd(mozilla::ErrorResult& aRv);
+
+  void Extend(nsINode& aNode, uint32_t aOffset, mozilla::ErrorResult& aRv);
+
+  void SelectAllChildren(nsINode& aNode, mozilla::ErrorResult& aRv);
+  void DeleteFromDocument(mozilla::ErrorResult& aRv);
+
+  uint32_t RangeCount() const
+  {
+    return mRanges.Length();
+  }
+  nsRange* GetRangeAt(uint32_t aIndex, mozilla::ErrorResult& aRv);
+  void AddRange(nsRange& aRange, mozilla::ErrorResult& aRv);
+  void RemoveRange(nsRange& aRange, mozilla::ErrorResult& aRv);
+  void RemoveAllRanges(mozilla::ErrorResult& aRv);
+
+  void Stringify(nsAString& aResult);
+
+  bool ContainsNode(nsINode* aNode, bool aPartlyContained, mozilla::ErrorResult& aRv);
+
+  void Modify(const nsAString& aAlter, const nsAString& aDirection,
+              const nsAString& aGranularity, mozilla::ErrorResult& aRv);
+
+  bool GetInterlinePosition(mozilla::ErrorResult& aRv);
+  void SetInterlinePosition(bool aValue, mozilla::ErrorResult& aRv);
+
+  void ToStringWithFormat(const nsAString& aFormatType,
+                          uint32_t aFlags,
+                          int32_t aWrapColumn,
+                          nsAString& aReturn,
+                          mozilla::ErrorResult& aRv);
+  void AddSelectionListener(nsISelectionListener* aListener,
+                            mozilla::ErrorResult& aRv);
+  void RemoveSelectionListener(nsISelectionListener* aListener,
+                               mozilla::ErrorResult& aRv);
+
+  int16_t Type() const { return mType; }
+
+  void GetRangesForInterval(nsINode& aBeginNode, int32_t aBeginOffset,
+                            nsINode& aEndNode, int32_t aEndOffset,
+                            bool aAllowAdjacent,
+                            nsTArray<nsRefPtr<nsRange>>& aReturn,
+                            mozilla::ErrorResult& aRv);
+
+  void ScrollIntoView(int16_t aRegion, bool aIsSynchronous,
+                      int16_t aVPercent, int16_t aHPercent,
+                      mozilla::ErrorResult& aRv);
+
 private:
   friend class ::nsAutoScrollTimer;
 
   // Note: DoAutoScroll might destroy arbitrary frames etc.
   nsresult DoAutoScroll(nsIFrame *aFrame, nsPoint& aPoint);
 
 public:
   SelectionType GetType(){return mType;}
--- a/layout/generic/nsSelection.cpp
+++ b/layout/generic/nsSelection.cpp
@@ -71,16 +71,18 @@ static NS_DEFINE_CID(kFrameTraversalCID,
 
 #ifdef IBMBIDI
 #include "nsIBidiKeyboard.h"
 #endif // IBMBIDI
 
 #include "nsError.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/ShadowRoot.h"
+#include "mozilla/ErrorResult.h"
+#include "mozilla/dom/SelectionBinding.h"
 
 using namespace mozilla;
 
 //#define DEBUG_TABLE 1
 
 static bool IsValidSelectionPoint(nsFrameSelection *aFrameSel, nsINode *aNode);
 
 static nsIAtom *GetTag(nsINode *aNode);
@@ -921,17 +923,17 @@ nsFrameSelection::MoveCaret(uint32_t    
     }
     result = TakeFocus(pos.mResultContent, pos.mContentOffset, pos.mContentOffset,
                        tHint, aContinueSelection, false);
   } else if (aKeycode == nsIDOMKeyEvent::DOM_VK_RIGHT && !aContinueSelection) {
     // Collapse selection if PeekOffset failed, we either
     //  1. bumped into the BRFrame, bug 207623
     //  2. had select-all in a text input (DIV range), bug 352759.
     bool isBRFrame = frame->GetType() == nsGkAtoms::brFrame;
-    sel->Collapse(sel->GetFocusNode(), sel->GetFocusOffset());
+    sel->Collapse(sel->GetFocusNode(), sel->FocusOffset());
     // Note: 'frame' might be dead here.
     if (!isBRFrame) {
       mHint = HINTLEFT; // We're now at the end of the frame to the left.
     }
     result = NS_OK;
   }
   if (NS_SUCCEEDED(result))
   {
@@ -963,75 +965,129 @@ Selection::ToString(nsAString& aReturn)
   }
   shell->FlushPendingNotifications(Flush_Style);
 
   return ToStringWithFormat("text/plain",
                             nsIDocumentEncoder::SkipInvisibleContent,
                             0, aReturn);
 }
 
+void
+Selection::Stringify(nsAString& aResult)
+{
+  // Eat the error code
+  ToString(aResult);
+}
+
 NS_IMETHODIMP
 Selection::ToStringWithFormat(const char* aFormatType, uint32_t aFlags,
                               int32_t aWrapCol, nsAString& aReturn)
 {
+  ErrorResult result;
+  NS_ConvertUTF8toUTF16 format(aFormatType);
+  ToStringWithFormat(format, aFlags, aWrapCol, aReturn, result);
+  if (result.Failed()) {
+    return result.ErrorCode();
+  }
+  return NS_OK;
+}
+
+void
+Selection::ToStringWithFormat(const nsAString& aFormatType, uint32_t aFlags,
+                              int32_t aWrapCol, nsAString& aReturn,
+                              ErrorResult& aRv)
+{
   nsresult rv = NS_OK;
-  nsAutoCString formatType( NS_DOC_ENCODER_CONTRACTID_BASE );
+  NS_ConvertUTF8toUTF16 formatType( NS_DOC_ENCODER_CONTRACTID_BASE );
   formatType.Append(aFormatType);
   nsCOMPtr<nsIDocumentEncoder> encoder =
-           do_CreateInstance(formatType.get(), &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
+           do_CreateInstance(NS_ConvertUTF16toUTF8(formatType).get(), &rv);
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+    return;
+  }
 
   nsIPresShell* shell = GetPresShell();
   if (!shell) {
-    return NS_ERROR_FAILURE;
+    aRv.Throw(NS_ERROR_FAILURE);
+    return;
   }
 
   nsIDocument *doc = shell->GetDocument();
 
   nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(doc);
   NS_ASSERTION(domDoc, "Need a document");
 
   // Flags should always include OutputSelectionOnly if we're coming from here:
   aFlags |= nsIDocumentEncoder::OutputSelectionOnly;
   nsAutoString readstring;
-  readstring.AssignASCII(aFormatType);
+  readstring.Assign(aFormatType);
   rv = encoder->Init(domDoc, readstring, aFlags);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+    return;
+  }
 
   encoder->SetSelection(this);
   if (aWrapCol != 0)
     encoder->SetWrapColumn(aWrapCol);
 
-  return encoder->EncodeToString(aReturn);
+  rv = encoder->EncodeToString(aReturn);
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+  }
 }
 
 NS_IMETHODIMP
 Selection::SetInterlinePosition(bool aHintRight)
 {
-  if (!mFrameSelection)
-    return NS_ERROR_NOT_INITIALIZED; // Can't do selection
+  ErrorResult result;
+  SetInterlinePosition(aHintRight, result);
+  if (result.Failed()) {
+    return result.ErrorCode();
+  }
+  return NS_OK;
+}
+
+void
+Selection::SetInterlinePosition(bool aHintRight, ErrorResult& aRv)
+{
+  if (!mFrameSelection) {
+    aRv.Throw(NS_ERROR_NOT_INITIALIZED); // Can't do selection
+    return;
+  }
   nsFrameSelection::HINT hint;
   if (aHintRight)
     hint = nsFrameSelection::HINTRIGHT;
   else
     hint = nsFrameSelection::HINTLEFT;
   mFrameSelection->SetHint(hint);
-  
-  return NS_OK;
 }
 
 NS_IMETHODIMP
 Selection::GetInterlinePosition(bool* aHintRight)
 {
-  if (!mFrameSelection)
-    return NS_ERROR_NOT_INITIALIZED; // Can't do selection
-  *aHintRight = (mFrameSelection->GetHint() == nsFrameSelection::HINTRIGHT);
+  ErrorResult result;
+  *aHintRight = GetInterlinePosition(result);
+  if (result.Failed()) {
+    return result.ErrorCode();
+  }
   return NS_OK;
 }
 
+bool
+Selection::GetInterlinePosition(ErrorResult& aRv)
+{
+  if (!mFrameSelection) {
+    aRv.Throw(NS_ERROR_NOT_INITIALIZED); // Can't do selection
+    return false;
+  }
+  return (mFrameSelection->GetHint() == nsFrameSelection::HINTRIGHT);
+}
+
 nsPrevNextBidiLevels
 nsFrameSelection::GetPrevNextBidiLevels(nsIContent *aNode,
                                         uint32_t    aContentOffset,
                                         bool        aJumpLines) const
 {
   return GetPrevNextBidiLevels(aNode, aContentOffset, mHint, aJumpLines);
 }
 
@@ -2933,19 +2989,19 @@ nsFrameSelection::DeleteFromDocument()
     if (NS_FAILED(res))
       return res;
   }
 
   // Collapse to the new location.
   // If we deleted one character, then we move back one element.
   // FIXME  We don't know how to do this past frame boundaries yet.
   if (isCollapsed)
-    mDomSelections[index]->Collapse(mDomSelections[index]->GetAnchorNode(), mDomSelections[index]->GetAnchorOffset()-1);
-  else if (mDomSelections[index]->GetAnchorOffset() > 0)
-    mDomSelections[index]->Collapse(mDomSelections[index]->GetAnchorNode(), mDomSelections[index]->GetAnchorOffset());
+    mDomSelections[index]->Collapse(mDomSelections[index]->GetAnchorNode(), mDomSelections[index]->AnchorOffset()-1);
+  else if (mDomSelections[index]->AnchorOffset() > 0)
+    mDomSelections[index]->Collapse(mDomSelections[index]->GetAnchorNode(), mDomSelections[index]->AnchorOffset());
 #ifdef DEBUG
   else
     printf("Don't know how to set selection back past frame boundary\n");
 #endif
 
   return NS_OK;
 }
 
@@ -2981,24 +3037,26 @@ nsFrameSelection::DisconnectFromPresShel
 
 // note: this can return a nil anchor node
 
 Selection::Selection()
   : mCachedOffsetForFrame(nullptr)
   , mDirection(eDirNext)
   , mType(nsISelectionController::SELECTION_NORMAL)
 {
+  SetIsDOMBinding();
 }
 
 Selection::Selection(nsFrameSelection* aList)
   : mFrameSelection(aList)
   , mCachedOffsetForFrame(nullptr)
   , mDirection(eDirNext)
   , mType(nsISelectionController::SELECTION_NORMAL)
 {
+  SetIsDOMBinding();
 }
 
 Selection::~Selection()
 {
   setAnchorFocusRange(-1);
 
   uint32_t count = mRanges.Length();
   for (uint32_t i = 0; i < count; ++i) {
@@ -3013,48 +3071,60 @@ Selection::~Selection()
   mScrollEvent.Revoke();
 
   if (mCachedOffsetForFrame) {
     delete mCachedOffsetForFrame;
     mCachedOffsetForFrame = nullptr;
   }
 }
 
+nsIDocument*
+Selection::GetParentObject() const
+{
+  nsIPresShell* shell = GetPresShell();
+  if (shell) {
+    return shell->GetDocument();
+  }
+  return nullptr;
+}
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(Selection)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Selection)
   // Unlink the selection listeners *before* we do RemoveAllRanges since
   // we don't want to notify the listeners during JS GC (they could be
   // in JS!).
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSelectionListeners)
   tmp->RemoveAllRanges();
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameSelection)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Selection)
   {
     uint32_t i, count = tmp->mRanges.Length();
     for (i = 0; i < count; ++i) {
       NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRanges[i].mRange)
     }
   }
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnchorFocusRange)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameSelection)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSelectionListeners)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(Selection)
 
 DOMCI_DATA(Selection, Selection)
 
 // QueryInterface implementation for Selection
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Selection)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISelection)
   NS_INTERFACE_MAP_ENTRY(nsISelectionPrivate)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISelection)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Selection)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Selection)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(Selection)
 
 
 NS_IMETHODIMP
 Selection::GetAnchorNode(nsIDOMNode** aAnchorNode)
@@ -3079,17 +3149,17 @@ Selection::GetAnchorNode()
   }
 
   return mAnchorFocusRange->GetEndParent();
 }
 
 NS_IMETHODIMP
 Selection::GetAnchorOffset(int32_t* aAnchorOffset)
 {
-  *aAnchorOffset = GetAnchorOffset();
+  *aAnchorOffset = static_cast<int32_t>(AnchorOffset());
   return NS_OK;
 }
 
 // note: this can return a nil focus node
 NS_IMETHODIMP
 Selection::GetFocusNode(nsIDOMNode** aFocusNode)
 {
   nsINode* focusNode = GetFocusNode();
@@ -3112,17 +3182,17 @@ Selection::GetFocusNode()
   }
 
   return mAnchorFocusRange->GetStartParent();
 }
 
 NS_IMETHODIMP
 Selection::GetFocusOffset(int32_t* aFocusOffset)
 {
-  *aFocusOffset = GetFocusOffset();
+  *aFocusOffset = static_cast<int32_t>(FocusOffset());
   return NS_OK;
 }
 
 void
 Selection::setAnchorFocusRange(int32_t indx)
 {
   if (indx >= (int32_t)mRanges.Length())
     return;
@@ -3130,31 +3200,31 @@ Selection::setAnchorFocusRange(int32_t i
   {
     mAnchorFocusRange = nullptr;
   }
   else{
     mAnchorFocusRange = mRanges[indx].mRange;
   }
 }
 
-int32_t
-Selection::GetAnchorOffset()
+uint32_t
+Selection::AnchorOffset()
 {
   if (!mAnchorFocusRange)
     return 0;
 
   if (GetDirection() == eDirNext){
     return mAnchorFocusRange->StartOffset();
   }
 
   return mAnchorFocusRange->EndOffset();
 }
 
-int32_t
-Selection::GetFocusOffset()
+uint32_t
+Selection::FocusOffset()
 {
   if (!mAnchorFocusRange)
     return 0;
 
   if (GetDirection() == eDirNext){
     return mAnchorFocusRange->EndOffset();
   }
 
@@ -3488,17 +3558,17 @@ Selection::Clear(nsPresContext* aPresCon
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 Selection::GetType(int16_t* aType)
 {
   NS_ENSURE_ARG_POINTER(aType);
-  *aType = mType;
+  *aType = Type();
 
   return NS_OK;
 }
 
 // RangeMatches*Point
 //
 //    Compares the range beginning or ending point, and returns true if it
 //    exactly matches the given DOM point.
@@ -3545,39 +3615,65 @@ Selection::GetRangesForInterval(nsIDOMNo
                                 uint32_t* aResultCount,
                                 nsIDOMRange*** aResults)
 {
   if (!aBeginNode || ! aEndNode || ! aResultCount || ! aResults)
     return NS_ERROR_NULL_POINTER;
 
   *aResultCount = 0;
   *aResults = nullptr;
-  
+
+  nsTArray<nsRefPtr<nsRange>> results;
+  ErrorResult result;
   nsCOMPtr<nsINode> beginNode = do_QueryInterface(aBeginNode);
   nsCOMPtr<nsINode> endNode = do_QueryInterface(aEndNode);
-
-  nsTArray<nsRange*> results;
-  nsresult rv = GetRangesForIntervalArray(beginNode, aBeginOffset,
-                                          endNode, aEndOffset,
-                                          aAllowAdjacent, &results);
-  NS_ENSURE_SUCCESS(rv, rv);
+  NS_ENSURE_TRUE(beginNode && endNode, NS_ERROR_NULL_POINTER);
+  GetRangesForInterval(*beginNode, aBeginOffset, *endNode, aEndOffset,
+                       aAllowAdjacent, results, result);
+  if (result.Failed()) {
+    return result.ErrorCode();
+  }
   *aResultCount = results.Length();
   if (*aResultCount == 0) {
     return NS_OK;
   }
 
   *aResults = static_cast<nsIDOMRange**>
                          (nsMemory::Alloc(sizeof(nsIDOMRange*) * *aResultCount));
   NS_ENSURE_TRUE(*aResults, NS_ERROR_OUT_OF_MEMORY);
 
-  for (uint32_t i = 0; i < *aResultCount; i++)
-    NS_ADDREF((*aResults)[i] = results[i]);
+  for (uint32_t i = 0; i < *aResultCount; i++) {
+    (*aResults)[i] = results[i].forget().get(); // Already AddRefed
+  }
   return NS_OK;
 }
 
+
+void
+Selection::GetRangesForInterval(nsINode& aBeginNode, int32_t aBeginOffset,
+                                nsINode& aEndNode, int32_t aEndOffset,
+                                bool aAllowAdjacent,
+                                nsTArray<nsRefPtr<nsRange>>& aReturn,
+                                mozilla::ErrorResult& aRv)
+{
+  nsTArray<nsRange*> results;
+  nsresult rv = GetRangesForIntervalArray(&aBeginNode, aBeginOffset,
+                                          &aEndNode, aEndOffset,
+                                          aAllowAdjacent, &results);
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+    return;
+  }
+
+  aReturn.SetLength(results.Length());
+  for (uint32_t i = 0; i < results.Length(); ++i) {
+    aReturn[i] = results[i]; // AddRefs
+  }
+}
+
 // Selection::GetRangesForIntervalArray
 //
 //    Fills a nsTArray with the ranges overlapping the range specified by
 //    the given endpoints. Ranges in the selection exactly adjacent to the
 //    input range are not returned unless aAllowAdjacent is set.
 //
 //    For example, if the following ranges were in the selection
 //    (assume everything is within the same node)
@@ -3756,17 +3852,17 @@ Selection::GetPrimaryFrameForAnchorNode(
     return NS_ERROR_NULL_POINTER;
   
   int32_t frameOffset = 0;
   *aReturnFrame = 0;
   nsCOMPtr<nsIContent> content = do_QueryInterface(GetAnchorNode());
   if (content && mFrameSelection)
   {
     *aReturnFrame = mFrameSelection->
-      GetFrameForNodeOffset(content, GetAnchorOffset(),
+      GetFrameForNodeOffset(content, AnchorOffset(),
                             mFrameSelection->GetHint(), &frameOffset);
     if (*aReturnFrame)
       return NS_OK;
   }
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
@@ -3792,22 +3888,22 @@ Selection::GetPrimaryFrameForFocusNode(n
 
   if (aVisual) {
     nsRefPtr<nsCaret> caret = presShell->GetCaret();
     if (!caret)
       return NS_ERROR_FAILURE;
     
     uint8_t caretBidiLevel = mFrameSelection->GetCaretBidiLevel();
 
-    return caret->GetCaretFrameForNodeOffset(content, GetFocusOffset(),
+    return caret->GetCaretFrameForNodeOffset(content, FocusOffset(),
       hint, caretBidiLevel, aReturnFrame, aOffsetUsed);
   }
   
   *aReturnFrame = mFrameSelection->
-    GetFrameForNodeOffset(content, GetFocusOffset(),
+    GetFrameForNodeOffset(content, FocusOffset(),
                           hint, aOffsetUsed);
   if (!*aReturnFrame)
     return NS_ERROR_FAILURE;
 
   return NS_OK;
 }
 
 //select all content children of aContent
@@ -4222,69 +4318,98 @@ Selection::DoAutoScroll(nsIFrame* aFrame
 }
 
 
 /** RemoveAllRanges zeroes the selection
  */
 NS_IMETHODIMP
 Selection::RemoveAllRanges()
 {
+  ErrorResult result;
+  RemoveAllRanges(result);
+  return result.ErrorCode();
+}
+
+void
+Selection::RemoveAllRanges(ErrorResult& aRv)
+{
   if (!mFrameSelection)
-    return NS_OK;//nothing to do
+    return; // nothing to do
   nsRefPtr<nsPresContext>  presContext = GetPresContext();
   nsresult  result = Clear(presContext);
-  if (NS_FAILED(result))
-    return result;
-  
+  if (NS_FAILED(result)) {
+    aRv.Throw(result);
+    return;
+  }
+
   // Turn off signal for table selection
   mFrameSelection->ClearTableCellSelection();
 
-  return mFrameSelection->NotifySelectionListeners(GetType());
+  result = mFrameSelection->NotifySelectionListeners(GetType());
   // Also need to notify the frames!
   // PresShell::CharacterDataChanged should do that on DocumentChanged
+  if (NS_FAILED(result)) {
+    aRv.Throw(result);
+  }
 }
 
 /** AddRange adds the specified range to the selection
  *  @param aRange is the range to be added
  */
 NS_IMETHODIMP
 Selection::AddRange(nsIDOMRange* aDOMRange)
 {
   if (!aDOMRange) {
     return NS_ERROR_NULL_POINTER;
   }
   nsRange* range = static_cast<nsRange*>(aDOMRange);
-
+  ErrorResult result;
+  AddRange(*range, result);
+  return result.ErrorCode();
+}
+
+void
+Selection::AddRange(nsRange& aRange, ErrorResult& aRv)
+{
   // This inserts a table cell range in proper document order
   // and returns NS_OK if range doesn't contain just one table cell
   bool didAddRange;
   int32_t rangeIndex;
-  nsresult result = addTableCellRange(range, &didAddRange, &rangeIndex);
-  if (NS_FAILED(result)) return result;
+  nsresult result = addTableCellRange(&aRange, &didAddRange, &rangeIndex);
+  if (NS_FAILED(result)) {
+    aRv.Throw(result);
+    return;
+  }
 
   if (!didAddRange)
   {
-    result = AddItem(range, &rangeIndex);
-    if (NS_FAILED(result)) return result;
+    result = AddItem(&aRange, &rangeIndex);
+    if (NS_FAILED(result)) {
+      aRv.Throw(result);
+      return;
+    }
   }
 
   NS_ASSERTION(rangeIndex >= 0, "Range index not returned");
   setAnchorFocusRange(rangeIndex);
   
   // Make sure the caret appears on the next line, if at a newline
   if (mType == nsISelectionController::SELECTION_NORMAL)
     SetInterlinePosition(true);
 
   nsRefPtr<nsPresContext>  presContext = GetPresContext();
-  selectFrames(presContext, range, true);
+  selectFrames(presContext, &aRange, true);
 
   if (!mFrameSelection)
-    return NS_OK;//nothing to do
-
-  return mFrameSelection->NotifySelectionListeners(GetType());
+    return;//nothing to do
+
+  result = mFrameSelection->NotifySelectionListeners(GetType());
+  if (NS_FAILED(result)) {
+    aRv.Throw(result);
+  }
 }
 
 // Selection::RemoveRange
 //
 //    Removes the given range from the selection. The tricky part is updating
 //    the flags on the frames that indicate whether they have a selection or
 //    not. There could be several selection ranges on the frame, and clearing
 //    the bit would cause the selection to not be drawn, even when there is
@@ -4295,74 +4420,89 @@ Selection::AddRange(nsIDOMRange* aDOMRan
 //    selected frames after we've cleared the bit from ours.
 
 nsresult
 Selection::RemoveRange(nsIDOMRange* aDOMRange)
 {
   if (!aDOMRange) {
     return NS_ERROR_INVALID_ARG;
   }
-  nsRefPtr<nsRange> range = static_cast<nsRange*>(aDOMRange);
-  
-  nsresult rv = RemoveItem(range);
-  if (NS_FAILED(rv))
-    return rv;
-
-  nsINode* beginNode = range->GetStartParent();
-  nsINode* endNode = range->GetEndParent();
+  nsRange* range = static_cast<nsRange*>(aDOMRange);
+  ErrorResult result;
+  RemoveRange(*range, result);
+  return result.ErrorCode();
+}
+
+void
+Selection::RemoveRange(nsRange& aRange, ErrorResult& aRv)
+{
+  nsresult rv = RemoveItem(&aRange);
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+    return;
+  }
+
+  nsINode* beginNode = aRange.GetStartParent();
+  nsINode* endNode = aRange.GetEndParent();
 
   if (!beginNode || !endNode) {
     // Detached range; nothing else to do here.
-    return NS_OK;
+    return;
   }
   
   // find out the length of the end node, so we can select all of it
   int32_t beginOffset, endOffset;
   if (endNode->IsNodeOfType(nsINode::eTEXT)) {
     // Get the length of the text. We can't just use the offset because
     // another range could be touching this text node but not intersect our
     // range.
     beginOffset = 0;
     endOffset = static_cast<nsIContent*>(endNode)->TextLength();
   } else {
     // For non-text nodes, the given offsets should be sufficient.
-    beginOffset = range->StartOffset();
-    endOffset = range->EndOffset();
+    beginOffset = aRange.StartOffset();
+    endOffset = aRange.EndOffset();
   }
 
   // clear the selected bit from the removed range's frames
   nsRefPtr<nsPresContext>  presContext = GetPresContext();
-  selectFrames(presContext, range, false);
+  selectFrames(presContext, &aRange, false);
 
   // add back the selected bit for each range touching our nodes
   nsTArray<nsRange*> affectedRanges;
   rv = GetRangesForIntervalArray(beginNode, beginOffset,
                                  endNode, endOffset,
                                  true, &affectedRanges);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+    return;
+  }
   for (uint32_t i = 0; i < affectedRanges.Length(); i++) {
     selectFrames(presContext, affectedRanges[i], true);
   }
 
   int32_t cnt = mRanges.Length();
-  if (range == mAnchorFocusRange) {
+  if (&aRange == mAnchorFocusRange) {
     // Reset anchor to LAST range or clear it if there are no ranges.
     setAnchorFocusRange(cnt - 1);
 
     // When the selection is user-created it makes sense to scroll the range
     // into view. The spell-check selection, however, is created and destroyed
     // in the background. We don't want to scroll in this case or the view
     // might appear to be moving randomly (bug 337871).
     if (mType != nsISelectionController::SELECTION_SPELLCHECK && cnt > 0)
       ScrollIntoView(nsISelectionController::SELECTION_FOCUS_REGION);
   }
 
   if (!mFrameSelection)
-    return NS_OK;//nothing to do
-  return mFrameSelection->NotifySelectionListeners(GetType());
+    return;//nothing to do
+  rv = mFrameSelection->NotifySelectionListeners(GetType());
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+  }
 }
 
 
 
 /*
  * Collapse sets the whole selection to be one point.
  */
 NS_IMETHODIMP
@@ -4378,110 +4518,166 @@ Selection::CollapseNative(nsINode* aPare
   return Collapse(aParentNode, aOffset);
 }
 
 nsresult
 Selection::Collapse(nsINode* aParentNode, int32_t aOffset)
 {
   if (!aParentNode)
     return NS_ERROR_INVALID_ARG;
-  if (!mFrameSelection)
-    return NS_ERROR_NOT_INITIALIZED; // Can't do selection
-
-  nsCOMPtr<nsINode> kungfuDeathGrip = aParentNode;
+
+  ErrorResult result;
+  Collapse(*aParentNode, static_cast<uint32_t>(aOffset), result);
+  return result.ErrorCode();
+}
+
+void
+Selection::Collapse(nsINode& aParentNode, uint32_t aOffset, ErrorResult& aRv)
+{
+  if (!mFrameSelection) {
+    aRv.Throw(NS_ERROR_NOT_INITIALIZED); // Can't do selection
+    return;
+  }
+
+  nsCOMPtr<nsINode> kungfuDeathGrip = &aParentNode;
 
   mFrameSelection->InvalidateDesiredX();
-  if (!IsValidSelectionPoint(mFrameSelection, aParentNode))
-    return NS_ERROR_FAILURE;
+  if (!IsValidSelectionPoint(mFrameSelection, &aParentNode)) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return;
+  }
   nsresult result;
 
   nsRefPtr<nsPresContext> presContext = GetPresContext();
-  if (!presContext || presContext->Document() != aParentNode->OwnerDoc())
-    return NS_ERROR_FAILURE;
+  if (!presContext || presContext->Document() != aParentNode.OwnerDoc()) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return;
+  }
 
   // Delete all of the current ranges
   Clear(presContext);
 
   // Turn off signal for table selection
   mFrameSelection->ClearTableCellSelection();
 
-  nsRefPtr<nsRange> range = new nsRange(aParentNode);
-  result = range->SetEnd(aParentNode, aOffset);
-  if (NS_FAILED(result))
-    return result;
-  result = range->SetStart(aParentNode, aOffset);
-  if (NS_FAILED(result))
-    return result;
+  nsRefPtr<nsRange> range = new nsRange(&aParentNode);
+  result = range->SetEnd(&aParentNode, aOffset);
+  if (NS_FAILED(result)) {
+    aRv.Throw(result);
+    return;
+  }
+  result = range->SetStart(&aParentNode, aOffset);
+  if (NS_FAILED(result)) {
+    aRv.Throw(result);
+    return;
+  }
 
 #ifdef DEBUG_SELECTION
-  if (aParentNode) {
-    nsCOMPtr<nsIContent> content = do_QueryInterface(aParentNode);
-    nsCOMPtr<nsIDocument> doc = do_QueryInterface(aParentNode);
-    printf ("Sel. Collapse to %p %s %d\n", aParentNode,
-            content ? nsAtomCString(content->Tag()).get()
-                    : (doc ? "DOCUMENT" : "???"),
-            aOffset);
-  }
+  nsCOMPtr<nsIContent> content = do_QueryInterface(&aParentNode);
+  nsCOMPtr<nsIDocument> doc = do_QueryInterface(&aParentNode);
+  printf ("Sel. Collapse to %p %s %d\n", &aParentNode,
+          content ? nsAtomCString(content->Tag()).get()
+                  : (doc ? "DOCUMENT" : "???"),
+          aOffset);
 #endif
 
   int32_t rangeIndex = -1;
   result = AddItem(range, &rangeIndex);
-  if (NS_FAILED(result))
-    return result;
+  if (NS_FAILED(result)) {
+    aRv.Throw(result);
+    return;
+  }
   setAnchorFocusRange(0);
   selectFrames(presContext, range, true);
-  return mFrameSelection->NotifySelectionListeners(GetType());
+  result = mFrameSelection->NotifySelectionListeners(GetType());
+  if (NS_FAILED(result)) {
+    aRv.Throw(result);
+  }
 }
 
 /*
  * Sets the whole selection to be one point
  * at the start of the current selection
  */
 NS_IMETHODIMP
 Selection::CollapseToStart()
 {
+  ErrorResult result;
+  CollapseToStart(result);
+  return result.ErrorCode();
+}
+
+void
+Selection::CollapseToStart(ErrorResult& aRv)
+{
   int32_t cnt;
   nsresult rv = GetRangeCount(&cnt);
-  if (NS_FAILED(rv) || cnt <= 0)
-    return NS_ERROR_DOM_INVALID_STATE_ERR;
+  if (NS_FAILED(rv) || cnt <= 0) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return;
+  }
 
   // Get the first range
   nsRange* firstRange = mRanges[0].mRange;
-  if (!firstRange)
-    return NS_ERROR_FAILURE;
+  if (!firstRange) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return;
+  }
 
   if (mFrameSelection) {
     int16_t reason = mFrameSelection->PopReason() | nsISelectionListener::COLLAPSETOSTART_REASON;
     mFrameSelection->PostReason(reason);
   }
-  return Collapse(firstRange->GetStartParent(), firstRange->StartOffset());
+  nsINode* parent = firstRange->GetStartParent();
+  if (!parent) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return;
+  }
+  Collapse(*parent, firstRange->StartOffset(), aRv);
 }
 
 /*
  * Sets the whole selection to be one point
  * at the end of the current selection
  */
 NS_IMETHODIMP
 Selection::CollapseToEnd()
 {
+  ErrorResult result;
+  CollapseToEnd(result);
+  return result.ErrorCode();
+}
+
+void
+Selection::CollapseToEnd(ErrorResult& aRv)
+{
   int32_t cnt;
   nsresult rv = GetRangeCount(&cnt);
-  if (NS_FAILED(rv) || cnt <= 0)
-    return NS_ERROR_DOM_INVALID_STATE_ERR;
+  if (NS_FAILED(rv) || cnt <= 0) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return;
+  }
 
   // Get the last range
   nsRange* lastRange = mRanges[cnt - 1].mRange;
-  if (!lastRange)
-    return NS_ERROR_FAILURE;
+  if (!lastRange) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return;
+  }
 
   if (mFrameSelection) {
     int16_t reason = mFrameSelection->PopReason() | nsISelectionListener::COLLAPSETOEND_REASON;
     mFrameSelection->PostReason(reason);
   }
-  return Collapse(lastRange->GetEndParent(), lastRange->EndOffset());
+  nsINode* parent = lastRange->GetEndParent();
+  if (!parent) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return;
+  }
+  Collapse(*parent, lastRange->EndOffset(), aRv);
 }
 
 /*
  * IsCollapsed -- is the whole selection just one point, or unset?
  */
 bool
 Selection::IsCollapsed()
 {
@@ -4511,33 +4707,40 @@ Selection::GetIsCollapsed(bool* aIsColla
 
   *aIsCollapsed = IsCollapsed();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 Selection::GetRangeCount(int32_t* aRangeCount)
 {
-  *aRangeCount = (int32_t)mRanges.Length();
+  *aRangeCount = (int32_t)RangeCount();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 Selection::GetRangeAt(int32_t aIndex, nsIDOMRange** aReturn)
 {
-  RangeData empty(nullptr);
-  *aReturn = mRanges.SafeElementAt(aIndex, empty).mRange;
-  if (!*aReturn) {
-    return NS_ERROR_DOM_INDEX_SIZE_ERR;
-  }
-
-  NS_ADDREF(*aReturn);
-
-  return NS_OK;
+  ErrorResult result;
+  *aReturn = GetRangeAt(aIndex, result);
+  NS_IF_ADDREF(*aReturn);
+  return result.ErrorCode();
+}
+
+nsRange*
+Selection::GetRangeAt(uint32_t aIndex, ErrorResult& aRv)
+{
+  nsRange* range = GetRangeAt(aIndex);
+  if (!range) {
+    aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
+    return nullptr;
+  }
+
+  return range;
 }
 
 nsRange*
 Selection::GetRangeAt(int32_t aIndex)
 {
   RangeData empty(nullptr);
   return mRanges.SafeElementAt(aIndex, empty).mRange;
 }
@@ -4618,37 +4821,53 @@ Selection::ExtendNative(nsINode* aParent
 }
 
 nsresult
 Selection::Extend(nsINode* aParentNode, int32_t aOffset)
 {
   if (!aParentNode)
     return NS_ERROR_INVALID_ARG;
 
+  ErrorResult result;
+  Extend(*aParentNode, static_cast<uint32_t>(aOffset), result);
+  return result.ErrorCode();
+}
+
+void
+Selection::Extend(nsINode& aParentNode, uint32_t aOffset, ErrorResult& aRv)
+{
   // First, find the range containing the old focus point:
-  if (!mAnchorFocusRange)
-    return NS_ERROR_DOM_INVALID_STATE_ERR;
-
-  if (!mFrameSelection)
-    return NS_ERROR_NOT_INITIALIZED; // Can't do selection
+  if (!mAnchorFocusRange) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return;
+  }
+
+  if (!mFrameSelection) {
+    aRv.Throw(NS_ERROR_NOT_INITIALIZED); // Can't do selection
+    return;
+  }
 
   nsresult res;
-  if (!IsValidSelectionPoint(mFrameSelection, aParentNode))
-    return NS_ERROR_FAILURE;
+  if (!IsValidSelectionPoint(mFrameSelection, &aParentNode)) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return;
+  }
 
   nsRefPtr<nsPresContext> presContext = GetPresContext();
-  if (!presContext || presContext->Document() != aParentNode->OwnerDoc())
-    return NS_ERROR_FAILURE;
+  if (!presContext || presContext->Document() != aParentNode.OwnerDoc()) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return;
+  }
 
   //mFrameSelection->InvalidateDesiredX();
 
   nsINode* anchorNode = GetAnchorNode();
   nsINode* focusNode = GetFocusNode();
-  int32_t anchorOffset = GetAnchorOffset();
-  int32_t focusOffset = GetFocusOffset();
+  uint32_t anchorOffset = AnchorOffset();
+  uint32_t focusOffset = FocusOffset();
 
   nsRefPtr<nsRange> range = mAnchorFocusRange->CloneRange();
 
   nsINode* startNode = range->GetStartParent();
   nsINode* endNode = range->GetEndParent();
   int32_t startOffset = range->StartOffset();
   int32_t endOffset = range->EndOffset();
 
@@ -4666,286 +4885,336 @@ Selection::Extend(nsINode* aParentNode, 
   bool disconnected = false;
   bool shouldClearRange = false;
   int32_t result1 = nsContentUtils::ComparePoints(anchorNode, anchorOffset,
                                                   focusNode, focusOffset,
                                                   &disconnected);
   //compare old cursor to new cursor
   shouldClearRange |= disconnected;
   int32_t result2 = nsContentUtils::ComparePoints(focusNode, focusOffset,
-                                                  aParentNode, aOffset,
+                                                  &aParentNode, aOffset,
                                                   &disconnected);
   //compare anchor to new cursor
   shouldClearRange |= disconnected;
   int32_t result3 = nsContentUtils::ComparePoints(anchorNode, anchorOffset,
-                                                  aParentNode, aOffset,
+                                                  &aParentNode, aOffset,
                                                   &disconnected);
 
   // If the points are disconnected, the range will be collapsed below,
   // resulting in a range that selects nothing.
   if (shouldClearRange) {
     // Repaint the current range with the selection removed.
     selectFrames(presContext, range, false);
   }
 
-  nsRefPtr<nsRange> difRange = new nsRange(aParentNode);
+  nsRefPtr<nsRange> difRange = new nsRange(&aParentNode);
   if ((result1 == 0 && result3 < 0) || (result1 <= 0 && result2 < 0)){//a1,2  a,1,2
     //select from 1 to 2 unless they are collapsed
-    res = range->SetEnd(aParentNode, aOffset);
-    if (NS_FAILED(res))
-      return res;
+    range->SetEnd(aParentNode, aOffset, aRv);
+    if (aRv.Failed()) {
+      return;
+    }
     dir = eDirNext;
     res = difRange->SetEnd(range->GetEndParent(), range->EndOffset());
     nsresult tmp = difRange->SetStart(focusNode, focusOffset);
     if (NS_FAILED(tmp)) {
       res = tmp;
     }
-    if (NS_FAILED(res))
-      return res;
+    if (NS_FAILED(res)) {
+      aRv.Throw(res);
+      return;
+    }
     selectFrames(presContext, difRange , true);
     res = SetAnchorFocusToRange(range);
-    if (NS_FAILED(res))
-      return res;
+    if (NS_FAILED(res)) {
+      aRv.Throw(res);
+      return;
+    }
   }
   else if (result1 == 0 && result3 > 0){//2, a1
     //select from 2 to 1a
     dir = eDirPrevious;
-    res = range->SetStart(aParentNode, aOffset);
-    if (NS_FAILED(res))
-      return res;
+    range->SetStart(aParentNode, aOffset, aRv);
+    if (aRv.Failed()) {
+      return;
+    }
     selectFrames(presContext, range, true);
     res = SetAnchorFocusToRange(range);
-    if (NS_FAILED(res))
-      return res;
+    if (NS_FAILED(res)) {
+      aRv.Throw(res);
+      return;
+    }
   }
   else if (result3 <= 0 && result2 >= 0) {//a,2,1 or a2,1 or a,21 or a21
     //deselect from 2 to 1
     res = difRange->SetEnd(focusNode, focusOffset);
-    nsresult tmp = difRange->SetStart(aParentNode, aOffset);
-    if (NS_FAILED(tmp)) {
-      res = tmp;
+    difRange->SetStart(aParentNode, aOffset, aRv);
+    if (aRv.Failed()) {
+      return;
+    }
+    if (NS_FAILED(res)) {
+      aRv.Throw(res);
+      return;
     }
-    if (NS_FAILED(res))
-      return res;
-
-    res = range->SetEnd(aParentNode, aOffset);
-    if (NS_FAILED(res))
-      return res;
+
+    range->SetEnd(aParentNode, aOffset, aRv);
+    if (aRv.Failed()) {
+      return;
+    }
     res = SetAnchorFocusToRange(range);
-    if (NS_FAILED(res))
-      return res;
+    if (NS_FAILED(res)) {
+      aRv.Throw(res);
+      return;
+    }
     selectFrames(presContext, difRange, false); // deselect now
     difRange->SetEnd(range->GetEndParent(), range->EndOffset());
     selectFrames(presContext, difRange, true); // must reselect last node maybe more
   }
   else if (result1 >= 0 && result3 <= 0) {//1,a,2 or 1a,2 or 1,a2 or 1a2
     if (GetDirection() == eDirPrevious){
       res = range->SetStart(endNode, endOffset);
-      if (NS_FAILED(res))
-        return res;
+      if (NS_FAILED(res)) {
+        aRv.Throw(res);
+        return;
+      }
     }
     dir = eDirNext;
-    res = range->SetEnd(aParentNode, aOffset);
-    if (NS_FAILED(res))
-      return res;
+    range->SetEnd(aParentNode, aOffset, aRv);
+    if (aRv.Failed()) {
+      return;
+    }
     if (focusNode != anchorNode || focusOffset != anchorOffset) {//if collapsed diff dont do anything
       res = difRange->SetStart(focusNode, focusOffset);
       nsresult tmp = difRange->SetEnd(anchorNode, anchorOffset);
       if (NS_FAILED(tmp)) {
         res = tmp;
       }
-      if (NS_FAILED(res))
-        return res;
+      if (NS_FAILED(res)) {
+        aRv.Throw(res);
+        return;
+      }
       res = SetAnchorFocusToRange(range);
-      if (NS_FAILED(res))
-        return res;
+      if (NS_FAILED(res)) {
+        aRv.Throw(res);
+        return;
+      }
       //deselect from 1 to a
       selectFrames(presContext, difRange , false);
     }
     else
     {
       res = SetAnchorFocusToRange(range);
-      if (NS_FAILED(res))
-        return res;
+      if (NS_FAILED(res)) {
+        aRv.Throw(res);
+        return;
+      }
     }
     //select from a to 2
     selectFrames(presContext, range , true);
   }
   else if (result2 <= 0 && result3 >= 0) {//1,2,a or 12,a or 1,2a or 12a
     //deselect from 1 to 2
-    res = difRange->SetEnd(aParentNode, aOffset);
-    nsresult tmp = difRange->SetStart(focusNode, focusOffset);
-    if (NS_FAILED(tmp)) {
-      res = tmp;
+    difRange->SetEnd(aParentNode, aOffset, aRv);
+    res = difRange->SetStart(focusNode, focusOffset);
+    if (aRv.Failed()) {
+      return;
     }
-    if (NS_FAILED(res))
-      return res;
+    if (NS_FAILED(res)) {
+      aRv.Throw(res);
+      return;
+    }
     dir = eDirPrevious;
-    res = range->SetStart(aParentNode, aOffset);
-    if (NS_FAILED(res))
-      return res;
+    range->SetStart(aParentNode, aOffset, aRv);
+    if (aRv.Failed()) {
+      return;
+    }
 
     res = SetAnchorFocusToRange(range);
-    if (NS_FAILED(res))
-      return res;
+    if (NS_FAILED(res)) {
+      aRv.Throw(res);
+      return;
+    }
     selectFrames(presContext, difRange , false);
     difRange->SetStart(range->GetStartParent(), range->StartOffset());
     selectFrames(presContext, difRange, true);//must reselect last node
   }
   else if (result3 >= 0 && result1 <= 0) {//2,a,1 or 2a,1 or 2,a1 or 2a1
     if (GetDirection() == eDirNext){
       range->SetEnd(startNode, startOffset);
     }
     dir = eDirPrevious;
-    res = range->SetStart(aParentNode, aOffset);
-    if (NS_FAILED(res))
-      return res;
+    range->SetStart(aParentNode, aOffset, aRv);
+    if (aRv.Failed()) {
+      return;
+    }
     //deselect from a to 1
     if (focusNode != anchorNode || focusOffset!= anchorOffset) {//if collapsed diff dont do anything
       res = difRange->SetStart(anchorNode, anchorOffset);
       nsresult tmp = difRange->SetEnd(focusNode, focusOffset);
       if (NS_FAILED(tmp)) {
         res = tmp;
       }
       tmp = SetAnchorFocusToRange(range);
       if (NS_FAILED(tmp)) {
         res = tmp;
       }
-      if (NS_FAILED(res))
-        return res;
+      if (NS_FAILED(res)) {
+        aRv.Throw(res);
+        return;
+      }
       selectFrames(presContext, difRange, false);
     }
     else
     {
       res = SetAnchorFocusToRange(range);
-      if (NS_FAILED(res))
-        return res;
+      if (NS_FAILED(res)) {
+        aRv.Throw(res);
+        return;
+      }
     }
     //select from 2 to a
     selectFrames(presContext, range , true);
   }
   else if (result2 >= 0 && result1 >= 0) {//2,1,a or 21,a or 2,1a or 21a
     //select from 2 to 1
-    res = range->SetStart(aParentNode, aOffset);
-    if (NS_FAILED(res))
-      return res;
+    range->SetStart(aParentNode, aOffset, aRv);
+    if (aRv.Failed()) {
+      return;
+    }
     dir = eDirPrevious;
     res = difRange->SetEnd(focusNode, focusOffset);
     nsresult tmp = difRange->SetStart(range->GetStartParent(), range->StartOffset());
     if (NS_FAILED(tmp)) {
       res = tmp;
     }
-    if (NS_FAILED(res))
-      return res;
+    if (NS_FAILED(res)) {
+      aRv.Throw(res);
+      return;
+    }
 
     selectFrames(presContext, difRange, true);
     res = SetAnchorFocusToRange(range);
-    if (NS_FAILED(res))
-      return res;
+    if (NS_FAILED(res)) {
+      aRv.Throw(res);
+      return;
+    }
   }
 
   DEBUG_OUT_RANGE(range);
 #ifdef DEBUG_SELECTION
   if (eDirNext == mDirection)
     printf("    direction = 1  LEFT TO RIGHT\n");
   else
     printf("    direction = 0  RIGHT TO LEFT\n");
 #endif
   SetDirection(dir);
 #ifdef DEBUG_SELECTION
-  if (aParentNode)
-  {
-    nsCOMPtr<nsIContent>content;
-    content = do_QueryInterface(aParentNode);
-
-    printf ("Sel. Extend to %p %s %d\n", content.get(),
-            nsAtomCString(content->Tag()).get(), aOffset);
-  }
-  else {
-    printf ("Sel. Extend set to null parent.\n");
-  }
+  nsCOMPtr<nsIContent>content;
+  content = do_QueryInterface(aParentNode);
+
+  printf ("Sel. Extend to %p %s %d\n", content.get(),
+          nsAtomCString(content->Tag()).get(), aOffset);
 #endif
-  return mFrameSelection->NotifySelectionListeners(GetType());
+  res = mFrameSelection->NotifySelectionListeners(GetType());
+  if (NS_FAILED(res)) {
+    aRv.Throw(res);
+  }
 }
 
 NS_IMETHODIMP
 Selection::SelectAllChildren(nsIDOMNode* aParentNode)
 {
-  NS_ENSURE_ARG_POINTER(aParentNode);
+  ErrorResult result;
   nsCOMPtr<nsINode> node = do_QueryInterface(aParentNode);
+  NS_ENSURE_TRUE(node, NS_ERROR_INVALID_ARG);
+  SelectAllChildren(*node, result);
+  return result.ErrorCode();
+}
+
+void
+Selection::SelectAllChildren(nsINode& aNode, ErrorResult& aRv)
+{
+  if (mFrameSelection)
+  {
+    mFrameSelection->PostReason(nsISelectionListener::SELECTALL_REASON);
+  }
+  Collapse(aNode, 0, aRv);
+  if (aRv.Failed()) {
+    return;
+  }
 
   if (mFrameSelection)
   {
     mFrameSelection->PostReason(nsISelectionListener::SELECTALL_REASON);
   }
-  nsresult result = Collapse(node, 0);
-  if (NS_FAILED(result))
-    return result;
-
-  if (mFrameSelection)
-  {
-    mFrameSelection->PostReason(nsISelectionListener::SELECTALL_REASON);
-  }
-  return Extend(node, node->GetChildCount());
+  Extend(aNode, aNode.GetChildCount(), aRv);
 }
 
 NS_IMETHODIMP
 Selection::ContainsNode(nsIDOMNode* aNode, bool aAllowPartial, bool* aYes)
 {
-  nsresult rv;
   if (!aYes)
     return NS_ERROR_NULL_POINTER;
   *aYes = false;
 
   nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
-  if (mRanges.Length() == 0 || !node)
-    return NS_OK;
+  ErrorResult result;
+  *aYes = ContainsNode(node, aAllowPartial, result);
+  return result.ErrorCode();
+}
+
+bool
+Selection::ContainsNode(nsINode* aNode, bool aAllowPartial, ErrorResult& aRv)
+{
+  nsresult rv;
+  if (mRanges.Length() == 0 || !aNode)
+    return false;
 
   // XXXbz this duplicates the GetNodeLength code in nsRange.cpp
   uint32_t nodeLength;
-  bool isData = node->IsNodeOfType(nsINode::eDATA_NODE);
+  bool isData = aNode->IsNodeOfType(nsINode::eDATA_NODE);
   if (isData) {
-    nodeLength = static_cast<nsIContent*>(node.get())->TextLength();
+    nodeLength = static_cast<nsIContent*>(aNode)->TextLength();
   } else {
-    nodeLength = node->GetChildCount();
+    nodeLength = aNode->GetChildCount();
   }
 
   nsTArray<nsRange*> overlappingRanges;
-  rv = GetRangesForIntervalArray(node, 0, node, nodeLength,
+  rv = GetRangesForIntervalArray(aNode, 0, aNode, nodeLength,
                                  false, &overlappingRanges);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+    return false;
+  }
   if (overlappingRanges.Length() == 0)
-    return NS_OK; // no ranges overlap
-  
+    return false; // no ranges overlap
+
   // if the caller said partial intersections are OK, we're done
   if (aAllowPartial) {
-    *aYes = true;
-    return NS_OK;
+    return true;
   }
 
   // text nodes always count as inside
   if (isData) {
-    *aYes = true;
-    return NS_OK;
+    return true;
   }
 
   // The caller wants to know if the node is entirely within the given range,
   // so we have to check all intersecting ranges.
   for (uint32_t i = 0; i < overlappingRanges.Length(); i++) {
     bool nodeStartsBeforeRange, nodeEndsAfterRange;
-    if (NS_SUCCEEDED(nsRange::CompareNodeToRange(node, overlappingRanges[i],
+    if (NS_SUCCEEDED(nsRange::CompareNodeToRange(aNode, overlappingRanges[i],
                                                  &nodeStartsBeforeRange,
                                                  &nodeEndsAfterRange))) {
       if (!nodeStartsBeforeRange && !nodeEndsAfterRange) {
-        *aYes = true;
-        return NS_OK;
+        return true;
       }
     }
   }
-  return NS_OK;
+  return false;
 }
 
 
 nsPresContext*
 Selection::GetPresContext() const
 {
   nsIPresShell *shell = GetPresShell();
   if (!shell) {
@@ -5015,27 +5284,27 @@ Selection::GetSelectionEndPointGeometry(
   if (!mFrameSelection)
     return nullptr;  // nothing to do
 
   NS_ENSURE_TRUE(aRect, nullptr);
 
   aRect->SetRect(0, 0, 0, 0);
 
   nsINode    *node       = nullptr;
-  int32_t     nodeOffset = 0;
+  uint32_t    nodeOffset = 0;
   nsIFrame   *frame      = nullptr;
 
   switch (aRegion) {
     case nsISelectionController::SELECTION_ANCHOR_REGION:
       node       = GetAnchorNode();
-      nodeOffset = GetAnchorOffset();
+      nodeOffset = AnchorOffset();
       break;
     case nsISelectionController::SELECTION_FOCUS_REGION:
       node       = GetFocusNode();
-      nodeOffset = GetFocusOffset();
+      nodeOffset = FocusOffset();
       break;
     default:
       return nullptr;
   }
 
   if (!node)
     return nullptr;
 
@@ -5122,20 +5391,35 @@ Selection::PostScrollSelectionIntoViewEv
   mScrollEvent = ev;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 Selection::ScrollIntoView(SelectionRegion aRegion, bool aIsSynchronous,
                           int16_t aVPercent, int16_t aHPercent)
 {
-  return ScrollIntoViewInternal(aRegion,
-                                aIsSynchronous,
-                                nsIPresShell::ScrollAxis(aVPercent),
-                                nsIPresShell::ScrollAxis(aHPercent));
+  ErrorResult result;
+  ScrollIntoView(aRegion, aIsSynchronous, aVPercent, aHPercent, result);
+  if (result.Failed()) {
+    return result.ErrorCode();
+  }
+  return NS_OK;
+}
+
+void
+Selection::ScrollIntoView(int16_t aRegion, bool aIsSynchronous,
+                          int16_t aVPercent, int16_t aHPercent,
+                          ErrorResult& aRv)
+{
+  nsresult rv = ScrollIntoViewInternal(aRegion, aIsSynchronous,
+                                       nsIPresShell::ScrollAxis(aVPercent),
+                                       nsIPresShell::ScrollAxis(aHPercent));
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+  }
 }
 
 NS_IMETHODIMP
 Selection::ScrollIntoViewInternal(SelectionRegion aRegion, bool aIsSynchronous,
                                   nsIPresShell::ScrollAxis aVertical,
                                   nsIPresShell::ScrollAxis aHorizontal)
 {
   return ScrollIntoView(aRegion, aVertical, aHorizontal,
@@ -5198,36 +5482,61 @@ Selection::ScrollIntoView(SelectionRegio
     flags |= nsIPresShell::SCROLL_OVERFLOW_HIDDEN;
   }
 
   presShell->ScrollFrameRectIntoView(frame, rect, aVertical, aHorizontal,
     flags);
   return NS_OK;
 }
 
-
-
 NS_IMETHODIMP
 Selection::AddSelectionListener(nsISelectionListener* aNewListener)
 {
   if (!aNewListener)
     return NS_ERROR_NULL_POINTER;
-  return mSelectionListeners.AppendObject(aNewListener) ? NS_OK : NS_ERROR_FAILURE;      // addrefs
-}
-
-
+  ErrorResult result;
+  AddSelectionListener(aNewListener, result);
+  if (result.Failed()) {
+    return result.ErrorCode();
+  }
+  return NS_OK;
+}
+
+void
+Selection::AddSelectionListener(nsISelectionListener* aNewListener,
+                                ErrorResult& aRv)
+{
+  bool result = mSelectionListeners.AppendObject(aNewListener); // AddRefs
+  if (!result) {
+    aRv.Throw(NS_ERROR_FAILURE);
+  }
+}
 
 NS_IMETHODIMP
 Selection::RemoveSelectionListener(nsISelectionListener* aListenerToRemove)
 {
-  if (!aListenerToRemove )
+  if (!aListenerToRemove)
     return NS_ERROR_NULL_POINTER;
-  return mSelectionListeners.RemoveObject(aListenerToRemove) ? NS_OK : NS_ERROR_FAILURE; // releases
-}
-
+  ErrorResult result;
+  RemoveSelectionListener(aListenerToRemove, result);
+  if (result.Failed()) {
+    return result.ErrorCode();
+  }
+  return NS_OK;
+}
+
+void
+Selection::RemoveSelectionListener(nsISelectionListener* aListenerToRemove,
+                                   ErrorResult& aRv)
+{
+  bool result = mSelectionListeners.RemoveObject(aListenerToRemove); // Releases
+  if (!result) {
+    aRv.Throw(NS_ERROR_FAILURE);
+  }
+}
 
 nsresult
 Selection::NotifySelectionListeners()
 {
   if (!mFrameSelection)
     return NS_OK;//nothing to do
  
   if (mFrameSelection->GetBatching()) {
@@ -5273,40 +5582,62 @@ Selection::EndBatchChanges()
   return NS_OK;
 }
 
 
 
 NS_IMETHODIMP
 Selection::DeleteFromDocument()
 {
+  ErrorResult result;
+  DeleteFromDocument(result);
+  return result.ErrorCode();
+}
+
+void
+Selection::DeleteFromDocument(ErrorResult& aRv)
+{
   if (!mFrameSelection)
-    return NS_OK;//nothing to do
-  return mFrameSelection->DeleteFromDocument();
+    return;//nothing to do
+  nsresult rv = mFrameSelection->DeleteFromDocument();
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+  }
 }
 
 NS_IMETHODIMP
 Selection::Modify(const nsAString& aAlter, const nsAString& aDirection,
                   const nsAString& aGranularity)
 {
+  ErrorResult result;
+  Modify(aAlter, aDirection, aGranularity, result);
+  return result.ErrorCode();
+}
+
+void
+Selection::Modify(const nsAString& aAlter, const nsAString& aDirection,
+                  const nsAString& aGranularity, ErrorResult& aRv)
+{
   // Silently exit if there's no selection or no focus node.
   if (!mFrameSelection || !GetAnchorFocusRange() || !GetFocusNode()) {
-    return NS_OK;
+    return;
   }
 
   if (!aAlter.LowerCaseEqualsLiteral("move") &&
       !aAlter.LowerCaseEqualsLiteral("extend")) {
-    return NS_ERROR_INVALID_ARG;
+    aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
+    return;
   }
 
   if (!aDirection.LowerCaseEqualsLiteral("forward") &&
       !aDirection.LowerCaseEqualsLiteral("backward") &&
       !aDirection.LowerCaseEqualsLiteral("left") &&
       !aDirection.LowerCaseEqualsLiteral("right")) {
-    return NS_ERROR_INVALID_ARG;
+    aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
+    return;
   }
 
   // Line moves are always visual.
   bool visual  = aDirection.LowerCaseEqualsLiteral("left") ||
                    aDirection.LowerCaseEqualsLiteral("right") ||
                    aGranularity.LowerCaseEqualsLiteral("line");
 
   bool forward = aDirection.LowerCaseEqualsLiteral("forward") ||
@@ -5337,31 +5668,35 @@ Selection::Modify(const nsAString& aAlte
     keycode = forward ? (uint32_t) nsIDOMKeyEvent::DOM_VK_END :
                         (uint32_t) nsIDOMKeyEvent::DOM_VK_HOME;
   }
   else if (aGranularity.LowerCaseEqualsLiteral("sentence") ||
            aGranularity.LowerCaseEqualsLiteral("sentenceboundary") ||
            aGranularity.LowerCaseEqualsLiteral("paragraph") ||
            aGranularity.LowerCaseEqualsLiteral("paragraphboundary") ||
            aGranularity.LowerCaseEqualsLiteral("documentboundary")) {
-    return NS_ERROR_NOT_IMPLEMENTED;
+    aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
   }
   else {
-    return NS_ERROR_INVALID_ARG;
+    aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
+    return;
   }
 
   // If the anchor doesn't equal the focus and we try to move without first
   // collapsing the selection, MoveCaret will collapse the selection and quit.
   // To avoid this, we need to collapse the selection first.
   nsresult rv = NS_OK;
   if (!extend) {
     nsINode* focusNode = GetFocusNode();
     // We should have checked earlier that there was a focus node.
-    NS_ENSURE_TRUE(focusNode, NS_ERROR_UNEXPECTED);
-    int32_t focusOffset = GetFocusOffset();
+    if (!focusNode) {
+      aRv.Throw(NS_ERROR_UNEXPECTED);
+      return;
+    }
+    uint32_t focusOffset = FocusOffset();
     Collapse(focusNode, focusOffset);
   }
 
   // If the base level of the focused frame is odd, we may have to swap the
   // direction of the keycode.
   nsIFrame *frame;
   int32_t offset;
   rv = GetPrimaryFrameForFocusNode(&frame, &offset, visual);
@@ -5389,20 +5724,19 @@ Selection::Modify(const nsAString& aAlte
   // case we call nsISelectionController::CompleteMove to move the cursor to
   // the beginning/end of the line.
   rv = mFrameSelection->MoveCaret(keycode, extend, amount, visual);
 
   if (aGranularity.LowerCaseEqualsLiteral("line") && NS_FAILED(rv)) {
     nsCOMPtr<nsISelectionController> shell =
       do_QueryInterface(mFrameSelection->GetShell());
     if (!shell)
-      return NS_OK;
+      return;
     shell->CompleteMove(forward, extend);
   }
-  return NS_OK;
 }
 
 /** SelectionLanguageChange modifies the cursor Bidi level after a change in keyboard direction
  *  @param aLangRTL is true if the new language is right-to-left or false if the new language is left-to-right
  */
 NS_IMETHODIMP
 Selection::SelectionLanguageChange(bool aLangRTL)
 {
@@ -5423,17 +5757,17 @@ Selection::SelectionLanguageChange(bool 
   focusFrame->GetOffsets(frameStart, frameEnd);
   nsRefPtr<nsPresContext> context = GetPresContext();
   uint8_t levelBefore, levelAfter;
   if (!context) {
     return NS_ERROR_FAILURE;
   }
 
   uint8_t level = NS_GET_EMBEDDING_LEVEL(focusFrame);
-  int32_t focusOffset = GetFocusOffset();
+  int32_t focusOffset = static_cast<int32_t>(FocusOffset());
   if ((focusOffset != frameStart) && (focusOffset != frameEnd))
     // the cursor is not at a frame boundary, so the level of both the characters (logically) before and after the cursor
     //  is equal to the frame level
     levelBefore = levelAfter = level;
   else {
     // the cursor is at a frame boundary, so use GetPrevNextBidiLevels to find the level of the characters
     //  before and after the cursor
     nsCOMPtr<nsIContent> focusContent = do_QueryInterface(GetFocusNode());
@@ -5489,16 +5823,21 @@ Selection::GetSelectionDirection() {
   return mDirection;
 }
 
 NS_IMETHODIMP_(void)
 Selection::SetSelectionDirection(nsDirection aDirection) {
   mDirection = aDirection;
 }
 
+JSObject*
+Selection::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
+{
+  return mozilla::dom::SelectionBinding::Wrap(aCx, aScope, this);
+}
 
 // nsAutoCopyListener
 
 nsAutoCopyListener* nsAutoCopyListener::sInstance = nullptr;
 
 NS_IMPL_ISUPPORTS1(nsAutoCopyListener, nsISelectionListener)
 
 /*
--- a/layout/generic/test/chrome.ini
+++ b/layout/generic/test/chrome.ini
@@ -1,15 +1,16 @@
 [DEFAULT]
 support-files =
   file_bug514732_window.xul
   frame_selection_underline-ref.xhtml
   frame_selection_underline.css
   frame_selection_underline.xhtml
 
 [test_backspace_delete.xul]
+[test_bug348681.html]
 [test_bug469613.xul]
 [test_bug469774.xul]
 [test_bug508115.xul]
 [test_bug514732-2.xul]
 [test_bug632379.xul]
 [test_selection_preventDefault.html]
 [test_selection_underline.html]
--- a/layout/generic/test/mochitest.ini
+++ b/layout/generic/test/mochitest.ini
@@ -13,17 +13,16 @@ support-files =
 
 [test_bug240933.html]
 [test_bug263683.html]
 [test_bug288789.html]
 [test_bug290397.html]
 [test_bug323656.html]
 [test_bug344830.html]
 support-files = bug344830_testembed.svg
-[test_bug348681.html]
 [test_bug382429.html]
 [test_bug384527.html]
 [test_bug385751.html]
 [test_bug389630.html]
 [test_bug391747.html]
 [test_bug392746.html]
 [test_bug392923.html]
 [test_bug394173.html]
--- a/layout/generic/test/test_bug348681.html
+++ b/layout/generic/test/test_bug348681.html
@@ -4,35 +4,39 @@
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <html>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=348681
 -->
 
 <head>
   <title>Test for Bug 348681</title>
-  <script type="application/javascript" src="/MochiKit/MochiKit.js"></script>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>  
+  <script type="application/javascript" src="chrome://mochikit/content/MochiKit/MochiKit.js"></script>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+  <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>  
 </head>
 
-<body onload="doTest();">
+<body onload="loaded()">
   <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=348681">Mozilla Bug 348681</a>
   <p id="display"></p>
   <div id="content" style="display: none">
   </div>
 
   <pre id="test">
     <script type="application/javascript">
 
       /** Test for Bug 348681 **/
-    
+
       SimpleTest.waitForExplicitFinish();
 
+      function loaded() {
+        SpecialPowers.pushPrefEnv({"set": [["dom.testing.selection.GetRangesForInterval", true]]}, doTest);
+      }
+
       var rangeChecker = {
         ranges: [],
 
         reset: function() {
           this.ranges = [];
         },
 
         check: function(testID, selection) {
@@ -296,202 +300,183 @@ https://bugzilla.mozilla.org/show_bug.cg
        var range8 = document.createRange();
        range8.setStart(testNode, 10);
        range8.setEnd(testNode, 12);
        selection.addRange(range8);
        intervalChecker.reset();
        intervalChecker.addExpected(testNode, 8, 10);
        var privSel = selection.QueryInterface(SpecialPowers.Ci.nsISelectionPrivate);
        ok(privSel, "Test 17 - QIed to instance of nsISelection2 interface");
-       var numResults = {};
        var results = privSel.GetRangesForInterval(testNode, 8, testNode, 10,
-                                                  false, numResults);
+                                                  false);
        intervalChecker.check(17, results);
 
        // Test 18. Check GetRangesForInterval returns correct results.
        // Part 2 - Test interval matches a range, adjacent ranges allowed.
        intervalChecker.addExpected(testNode, 6, 8);
        intervalChecker.addExpected(testNode, 10, 12);
-       numResults = {};
        results = privSel.GetRangesForInterval(testNode, 8, testNode, 10,
-                                              true, numResults);
+                                              true);
        intervalChecker.check(18, results);
 
        // Test 19. Check GetRangesForInterval returns correct results.
        // Part 3 - Test interval not selected.
        intervalChecker.reset();
-       numResults = {};
        results = privSel.GetRangesForInterval(testNode, 14, testNode, 16,
-                                              true, numResults);
+                                              true);
        intervalChecker.check(19, results);
 
        // Test 20. Check GetRangesForInterval returns correct results.
        // Part 4 - Test interval is not equal to, and entirely contained in
        //          an existing range.
        selection.removeAllRanges();
        selection.addRange(range6);
        intervalChecker.reset();
        intervalChecker.addExpected(testNode, 0, 10);
-       numResults = {};
        results = privSel.GetRangesForInterval(testNode, 5, testNode, 7,
-                                              true, numResults);
+                                              true);
        intervalChecker.check(20, results);
 
        // Test 21. Check GetRangesForInterval returns correct results.
        // Part 5 - Test interval is not equal to, and entirely contains an
        //          existing range.
        selection.removeAllRanges();
        selection.addRange(range3);
        intervalChecker.reset();
        intervalChecker.addExpected(testNode, 6, 8);
-       numResults = {};
        results = privSel.GetRangesForInterval(testNode, 5, testNode, 9,
-                                              true, numResults);
+                                              true);
        intervalChecker.check(21, results);
 
        // Test 22. Check GetRangesForInterval returns correct results.
        // Part 6 - Test interval is end-adjacent to range at position 0 in
        //          the range array, and adjacencies permitted.
        selection.removeAllRanges();
        selection.addRange(range2);
        intervalChecker.reset();
        intervalChecker.addExpected(testNode, 8, 10);
-       numResults = {};
        results = privSel.GetRangesForInterval(testNode, 6, testNode, 8,
-                                              true, numResults);
+                                              true);
        intervalChecker.check(22, results);
 
        // Test 23. Check GetRangesForInterval returns correct results.
        // Part 7 - Test interval is end-adjacent to range at position 0 in
        //          the range array, and adjacencies not permitted.
        intervalChecker.reset();
-       numResults = {};
        results = privSel.GetRangesForInterval(testNode, 6, testNode, 8,
-                                              false, numResults);
+                                              false);
        intervalChecker.check(23, results);
 
        // Test 24. Check GetRangesForInterval returns correct results.
        // Part 8 - Test interval is start-adjacent to last range in array,
        //          and adjacencies permitted.
        intervalChecker.addExpected(testNode, 8, 10);
-       numResults = {};
        results = privSel.GetRangesForInterval(testNode, 10, testNode, 12,
-                                              true, numResults);
+                                              true);
        intervalChecker.check(24, results);
 
        // Test 25. Check GetRangesForInterval returns correct results.
        // Part 9 - Test interval is start-adjacent to last range in array,
        //          and adjacencies not permitted.
        intervalChecker.reset();
-       numResults = {};
        results = privSel.GetRangesForInterval(testNode, 10, testNode, 12,
-                                              false, numResults);
+                                              false);
        intervalChecker.check(25, results);
 
        // Test 26.  Check GetRangesForInterval returns correct results.
        // Part 10 - Test interval is equal to a collapsed range at position 0
        //           in the range array, and adjacencies permitted.
        selection.removeAllRanges();
        selection.addRange(range4);
        intervalChecker.addExpected(testNode, 11, 11);
-       numResults = {};
        results = privSel.GetRangesForInterval(testNode, 11, testNode, 11,
-                                              true, numResults);
+                                              true);
        intervalChecker.check(26, results);
 
        // Test 27.  Check GetRangesForInterval returns correct results.
        // Part 11 - Test interval is equal to a collapsed range at position 0
        //           in the range array, and adjacencies not permitted.
-       numResults = {};
        results = privSel.GetRangesForInterval(testNode, 11, testNode, 11,
-                                              false, numResults);
+                                              false);
        intervalChecker.check(27, results);
 
        // Test 28.  Check GetRangesForInterval returns correct results.
        // Part 12 - Test interval is equal to a collapsed range at end of the
        //           range array, and adjacencies permitted.
        selection.removeAllRanges();
        selection.addRange(range2);
        selection.addRange(range4);
-       numResults = {};
        results = privSel.GetRangesForInterval(testNode, 11, testNode, 11,
-                                              true, numResults);
+                                              true);
        intervalChecker.check(28, results);
 
        // Test 29.  Check GetRangesForInterval returns correct results.
        // Part 13 - Test interval is equal to a collapsed range at end of the
        //           range array, and adjacencies not permitted.
-       numResults = {};
        results = privSel.GetRangesForInterval(testNode, 11, testNode, 11,
-                                              false, numResults);
+                                              false);
        intervalChecker.check(29, results);
 
        // Test 30.  Check GetRangesForInterval returns correct results.
        // Part 14 - Test interval is a collapsed range contained in an
        //           existing range.
        selection.removeAllRanges();
        selection.addRange(range3);
        intervalChecker.reset();
        intervalChecker.addExpected(testNode, 6, 8);
-       numResults = {};
        results = privSel.GetRangesForInterval(testNode, 7, testNode, 7,
-                                              true, numResults);
+                                              true);
        intervalChecker.check(30, results);
 
        // Test 31.  Check GetRangesForInterval returns correct results.
        // Part 15 - Test interval equals a collapsed range which is not stored
        //           at either endpoint of the selection's range array,
        //           adjacencies not allowed.
        selection.removeAllRanges();
        range3.collapse(false);
        selection.addRange(range5);
        selection.addRange(range3);
        selection.addRange(range8);
        intervalChecker.reset();
        intervalChecker.addExpected(testNode, 8, 8);
-       numResults = {};
        results = privSel.GetRangesForInterval(testNode, 8, testNode, 8,
-                                              false, numResults);
+                                              false);
        intervalChecker.check(31, results);
 
        // Test 32.  Check GetRangesForInterval returns correct results.
        // Part 16 - Test interval equals a collapsed range which is not stored
        //           at either endpoint of the selection's range array,
        //           adjacencies allowed.
-       numResults = {};
        results = privSel.GetRangesForInterval(testNode, 8, testNode, 8,
-                                              true, numResults);
+                                              true);
        intervalChecker.check(32, results);
 
        // Test 33.  Check GetRangesForInterval returns correct results.
        // Part 17 - Test interval contains a collapsed range which is not
        //           stored at either endpoint of the selection's range array.
-       numResults = {};
        results = privSel.GetRangesForInterval(testNode, 7, testNode, 9,
-                                              false, numResults);
+                                              false);
        intervalChecker.check(33, results);
 
        // Test 34.  Check GetRangesForInterval returns correct results.
        // Part 18 - Test interval left-ovelaps an existing range.
        intervalChecker.reset();
        intervalChecker.addExpected(testNode, 5, 7);
-       numResults = {};
        results = privSel.GetRangesForInterval(testNode, 2, testNode, 6,
-                                              true, numResults);
+                                              true);
        intervalChecker.check(34, results);
 
        // Test 35.  Check GetRangesForInterval returns correct results.
        // Part 19 - Test interval right-ovelaps an existing range.
        selection.removeAllRanges();
        selection.addRange(range8);
        intervalChecker.reset();
        intervalChecker.addExpected(testNode, 10, 12);
-       numResults = {};
        results = privSel.GetRangesForInterval(testNode, 11, testNode, 13,
-                                              true, numResults);
+                                              true);
        intervalChecker.check(35, results);
 
        SimpleTest.finish();
      }
    </script>
   </pre>
 
   <p id="testparagraph">