Bug 1367683 Optimize initializing nsRange r=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Tue, 30 May 2017 13:18:25 +0900
changeset 409408 6736d54ffd89b3fe3f28b3e59a8b558517894caf
parent 409407 ee035e1480b0c216099a39d491bf2a5974e54a02
child 409409 db2635a42c74dd3dede8de90b8ed2c250d63ec16
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1367683
milestone55.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 1367683 Optimize initializing nsRange r=smaug nsRange::DoSetRange() adds/remove its root to/from mutation observer, initializes common ancestor, registers itself to the common ancestor, unregisters itself from old common ancestor, and notifies selection listeners of selection change. However, those runtime cost is expensive but on the other hand, a lot of callers set both start and end of the range and that causes calling DoSetRange() twice. This patch renames Set() to SetStartAndEnd() for easier to understand the meaning and make it call DoSetRange() only once. MozReview-Commit-ID: FRV55tuBAgg
dom/base/nsDocument.cpp
dom/base/nsRange.cpp
dom/base/nsRange.h
dom/events/ContentEventHandler.cpp
editor/libeditor/HTMLEditRules.cpp
editor/libeditor/HTMLEditor.cpp
editor/libeditor/HTMLStyleEditor.cpp
editor/libeditor/SelectionState.cpp
editor/libeditor/WSRunObject.cpp
editor/txtsvc/nsTextServicesDocument.cpp
extensions/spellcheck/src/mozInlineSpellChecker.cpp
extensions/spellcheck/src/mozInlineSpellChecker.h
extensions/spellcheck/src/mozInlineSpellWordUtil.cpp
layout/forms/nsTextControlFrame.cpp
layout/generic/nsSelection.cpp
layout/printing/nsPrintEngine.cpp
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -6729,17 +6729,17 @@ nsDocument::CreateRange(nsIDOMRange** aR
   *aReturn = nsIDocument::CreateRange(rv).take();
   return rv.StealNSResult();
 }
 
 already_AddRefed<nsRange>
 nsIDocument::CreateRange(ErrorResult& rv)
 {
   RefPtr<nsRange> range = new nsRange(this);
-  nsresult res = range->Set(this, 0, this, 0);
+  nsresult res = range->CollapseTo(this, 0);
   if (NS_FAILED(res)) {
     rv.Throw(res);
     return nullptr;
   }
 
   return range.forget();
 }
 
--- a/dom/base/nsRange.cpp
+++ b/dom/base/nsRange.cpp
@@ -266,50 +266,38 @@ nsRange::nsRange(nsINode* aNode)
 }
 
 /* static */
 nsresult
 nsRange::CreateRange(nsINode* aStartParent, int32_t aStartOffset,
                      nsINode* aEndParent, int32_t aEndOffset,
                      nsRange** aRange)
 {
-  nsCOMPtr<nsIDOMNode> startDomNode = do_QueryInterface(aStartParent);
-  nsCOMPtr<nsIDOMNode> endDomNode = do_QueryInterface(aEndParent);
-
-  nsresult rv = CreateRange(startDomNode, aStartOffset, endDomNode, aEndOffset,
-                            aRange);
-
-  return rv;
-
+  MOZ_ASSERT(aRange);
+  *aRange = nullptr;
+
+  RefPtr<nsRange> range = new nsRange(aStartParent);
+  nsresult rv = range->SetStartAndEnd(aStartParent, aStartOffset,
+                                      aEndParent, aEndOffset);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  range.forget(aRange);
+  return NS_OK;
 }
 
 /* static */
 nsresult
 nsRange::CreateRange(nsIDOMNode* aStartParent, int32_t aStartOffset,
                      nsIDOMNode* aEndParent, int32_t aEndOffset,
                      nsRange** aRange)
 {
-  MOZ_ASSERT(aRange);
-  *aRange = nullptr;
-
   nsCOMPtr<nsINode> startParent = do_QueryInterface(aStartParent);
-  NS_ENSURE_ARG_POINTER(startParent);
-
-  RefPtr<nsRange> range = new nsRange(startParent);
-
-  // XXX this can be optimized by inlining SetStart/End and calling
-  // DoSetRange *once*.
-  nsresult rv = range->SetStart(startParent, aStartOffset);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = range->SetEnd(aEndParent, aEndOffset);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  range.forget(aRange);
-  return NS_OK;
+  nsCOMPtr<nsINode> endParent = do_QueryInterface(aEndParent);
+  return CreateRange(startParent, aStartOffset, endParent, aEndOffset, aRange);
 }
 
 /* static */
 nsresult
 nsRange::CreateRange(nsIDOMNode* aStartParent, int32_t aStartOffset,
                      nsIDOMNode* aEndParent, int32_t aEndOffset,
                      nsIDOMRange** aRange)
 {
@@ -1144,16 +1132,25 @@ nsRange::GetCommonAncestorContainer(nsID
     NS_ADDREF(*aCommonParent = commonAncestor->AsDOMNode());
   } else {
     *aCommonParent = nullptr;
   }
 
   return rv.StealNSResult();
 }
 
+/* static */
+bool
+nsRange::IsValidOffset(nsINode* aNode, int32_t aOffset)
+{
+  return aNode &&
+         aOffset >= 0 &&
+         static_cast<size_t>(aOffset) <= aNode->Length();
+}
+
 nsINode*
 nsRange::IsValidBoundary(nsINode* aNode)
 {
   if (!aNode) {
     return nullptr;
   }
 
   if (aNode->IsNodeOfType(nsINode::eCONTENT)) {
@@ -1232,17 +1229,17 @@ nsRange::SetStart(nsIDOMNode* aParent, i
 /* virtual */ nsresult
 nsRange::SetStart(nsINode* aParent, int32_t aOffset)
 {
   nsINode* newRoot = IsValidBoundary(aParent);
   if (!newRoot) {
     return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
   }
 
-  if (aOffset < 0 || uint32_t(aOffset) > aParent->Length()) {
+  if (!IsValidOffset(aParent, aOffset)) {
     return NS_ERROR_DOM_INDEX_SIZE_ERR;
   }
 
   // Collapse if not positioned yet, if positioned in another doc or
   // if the new start is after end.
   if (!mIsPositioned || newRoot != mRoot ||
       nsContentUtils::ComparePoints(aParent, aOffset,
                                     mEndParent, mEndOffset) == 1) {
@@ -1269,17 +1266,19 @@ nsRange::SetStartBefore(nsINode& aNode, 
 {
   if (!nsContentUtils::LegacyIsCallerNativeCode() &&
       !nsContentUtils::CanCallerAccess(&aNode)) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return;
   }
 
   AutoInvalidateSelection atEndOfBlock(this);
-  aRv = SetStart(aNode.GetParentNode(), IndexOf(&aNode));
+  int32_t offset = -1;
+  nsINode* parent = GetParentAndOffsetBefore(&aNode, &offset);
+  aRv = SetStart(parent, offset);
 }
 
 NS_IMETHODIMP
 nsRange::SetStartBefore(nsIDOMNode* aSibling)
 {
   nsCOMPtr<nsINode> sibling = do_QueryInterface(aSibling);
   if (!sibling) {
     return NS_ERROR_DOM_NOT_OBJECT_ERR;
@@ -1303,17 +1302,19 @@ nsRange::SetStartAfter(nsINode& aNode, E
 {
   if (!nsContentUtils::LegacyIsCallerNativeCode() &&
       !nsContentUtils::CanCallerAccess(&aNode)) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return;
   }
 
   AutoInvalidateSelection atEndOfBlock(this);
-  aRv = SetStart(aNode.GetParentNode(), IndexOf(&aNode) + 1);
+  int32_t offset = -1;
+  nsINode* parent = GetParentAndOffsetAfter(&aNode, &offset);
+  aRv = SetStart(parent, offset);
 }
 
 NS_IMETHODIMP
 nsRange::SetStartAfter(nsIDOMNode* aSibling)
 {
   nsCOMPtr<nsINode> sibling = do_QueryInterface(aSibling);
   if (!sibling) {
     return NS_ERROR_DOM_NOT_OBJECT_ERR;
@@ -1360,17 +1361,17 @@ nsRange::SetEnd(nsIDOMNode* aParent, int
 /* virtual */ nsresult
 nsRange::SetEnd(nsINode* aParent, int32_t aOffset)
 {
   nsINode* newRoot = IsValidBoundary(aParent);
   if (!newRoot) {
     return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
   }
 
-  if (aOffset < 0 || uint32_t(aOffset) > aParent->Length()) {
+  if (!IsValidOffset(aParent, aOffset)) {
     return NS_ERROR_DOM_INDEX_SIZE_ERR;
   }
 
   // Collapse if not positioned yet, if positioned in another doc or
   // if the new end is before start.
   if (!mIsPositioned || newRoot != mRoot ||
       nsContentUtils::ComparePoints(mStartParent, mStartOffset,
                                     aParent, aOffset) == 1) {
@@ -1379,16 +1380,74 @@ nsRange::SetEnd(nsINode* aParent, int32_
     return NS_OK;
   }
 
   DoSetRange(mStartParent, mStartOffset, aParent, aOffset, mRoot);
 
   return NS_OK;
 }
 
+nsresult
+nsRange::SetStartAndEnd(nsINode* aStartParent, int32_t aStartOffset,
+                        nsINode* aEndParent, int32_t aEndOffset)
+{
+  if (NS_WARN_IF(!aStartParent) || NS_WARN_IF(!aEndParent)) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  nsINode* newStartRoot = IsValidBoundary(aStartParent);
+  if (!newStartRoot) {
+    return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
+  }
+  if (!IsValidOffset(aStartParent, aStartOffset)) {
+    return NS_ERROR_DOM_INDEX_SIZE_ERR;
+  }
+
+  if (aStartParent == aEndParent) {
+    if (!IsValidOffset(aEndParent, aEndOffset)) {
+      return NS_ERROR_DOM_INDEX_SIZE_ERR;
+    }
+    // If the end offset is less than the start offset, this should be
+    // collapsed at the end offset.
+    if (aStartOffset > aEndOffset) {
+      DoSetRange(aEndParent, aEndOffset, aEndParent, aEndOffset, newStartRoot);
+    } else {
+      DoSetRange(aStartParent, aStartOffset,
+                 aEndParent, aEndOffset, newStartRoot);
+    }
+    return NS_OK;
+  }
+
+  nsINode* newEndRoot = IsValidBoundary(aEndParent);
+  if (!newEndRoot) {
+    return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
+  }
+  if (!IsValidOffset(aEndParent, aEndOffset)) {
+    return NS_ERROR_DOM_INDEX_SIZE_ERR;
+  }
+
+  // If they have different root, this should be collapsed at the end point.
+  if (newStartRoot != newEndRoot) {
+    DoSetRange(aEndParent, aEndOffset, aEndParent, aEndOffset, newEndRoot);
+    return NS_OK;
+  }
+
+  // If the end point is before the start point, this should be collapsed at
+  // the end point.
+  if (nsContentUtils::ComparePoints(aStartParent, aStartOffset,
+                                    aEndParent, aEndOffset) == 1) {
+    DoSetRange(aEndParent, aEndOffset, aEndParent, aEndOffset, newEndRoot);
+    return NS_OK;
+  }
+
+  // Otherwise, set the range as specified.
+  DoSetRange(aStartParent, aStartOffset, aEndParent, aEndOffset, newStartRoot);
+  return NS_OK;
+}
+
 void
 nsRange::SetEndBeforeJS(nsINode& aNode, ErrorResult& aErr)
 {
   AutoCalledByJSRestore calledByJSRestorer(*this);
   mCalledByJS = true;
   SetEndBefore(aNode, aErr);
 }
 
@@ -1397,17 +1456,19 @@ nsRange::SetEndBefore(nsINode& aNode, Er
 {
   if (!nsContentUtils::LegacyIsCallerNativeCode() &&
       !nsContentUtils::CanCallerAccess(&aNode)) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return;
   }
 
   AutoInvalidateSelection atEndOfBlock(this);
-  aRv = SetEnd(aNode.GetParentNode(), IndexOf(&aNode));
+  int32_t offset = -1;
+  nsINode* parent = GetParentAndOffsetBefore(&aNode, &offset);
+  aRv = SetEnd(parent, offset);
 }
 
 NS_IMETHODIMP
 nsRange::SetEndBefore(nsIDOMNode* aSibling)
 {
   nsCOMPtr<nsINode> sibling = do_QueryInterface(aSibling);
   if (!sibling) {
     return NS_ERROR_DOM_NOT_OBJECT_ERR;
@@ -1431,17 +1492,19 @@ nsRange::SetEndAfter(nsINode& aNode, Err
 {
   if (!nsContentUtils::LegacyIsCallerNativeCode() &&
       !nsContentUtils::CanCallerAccess(&aNode)) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return;
   }
 
   AutoInvalidateSelection atEndOfBlock(this);
-  aRv = SetEnd(aNode.GetParentNode(), IndexOf(&aNode) + 1);
+  int32_t offset = -1;
+  nsINode* parent = GetParentAndOffsetAfter(&aNode, &offset);
+  aRv = SetEnd(parent, offset);
 }
 
 NS_IMETHODIMP
 nsRange::SetEndAfter(nsIDOMNode* aSibling)
 {
   nsCOMPtr<nsINode> sibling = do_QueryInterface(aSibling);
   if (!sibling) {
     return NS_ERROR_DOM_NOT_OBJECT_ERR;
--- a/dom/base/nsRange.h
+++ b/dom/base/nsRange.h
@@ -144,29 +144,71 @@ public:
    */
   void SetIsGenerated(bool aIsGenerated)
   {
     mIsGenerated = aIsGenerated;
   }
 
   nsINode* GetCommonAncestor() const;
   void Reset();
+
+  /**
+   * SetStart() and SetEnd() sets start point or end point separately.
+   * However, this is expensive especially when it's a range of Selection.
+   * When you set both start and end of a range, you should use
+   * SetStartAndEnd() instead.
+   */
   nsresult SetStart(nsINode* aParent, int32_t aOffset);
   nsresult SetEnd(nsINode* aParent, int32_t aOffset);
+
   already_AddRefed<nsRange> CloneRange() const;
 
-  nsresult Set(nsINode* aStartParent, int32_t aStartOffset,
-               nsINode* aEndParent, int32_t aEndOffset)
+  /**
+   * SetStartAndEnd() works similar to call both SetStart() and SetEnd().
+   * Different from calls them separately, this does nothing if either
+   * the start point or the end point is invalid point.
+   * If the specified start point is after the end point, the range will be
+   * collapsed at the end point.  Similarly, if they are in different root,
+   * the range will be collapsed at the end point.
+   */
+  nsresult SetStartAndEnd(nsINode* aStartParent, int32_t aStartOffset,
+                          nsINode* aEndParent, int32_t aEndOffset);
+
+  /**
+   * CollapseTo() works similar to call both SetStart() and SetEnd() with
+   * same node and offset.  This just calls SetStartAndParent() to set
+   * collapsed range at aParent and aOffset.
+   */
+  nsresult CollapseTo(nsINode* aParent, int32_t aOffset)
   {
-    // If this starts being hot, we may be able to optimize this a bit,
-    // but for now just set start and end separately.
-    nsresult rv = SetStart(aStartParent, aStartOffset);
-    NS_ENSURE_SUCCESS(rv, rv);
+    return SetStartAndEnd(aParent, aOffset, aParent, aOffset);
+  }
 
-    return SetEnd(aEndParent, aEndOffset);
+  /**
+   * Retrieves node and offset for setting start or end of a range to
+   * before or after aNode.
+   */
+  static nsINode* GetParentAndOffsetAfter(nsINode* aNode, int32_t* aOffset)
+  {
+    MOZ_ASSERT(aNode);
+    MOZ_ASSERT(aOffset);
+    nsINode* parentNode = aNode->GetParentNode();
+    *aOffset = parentNode ? parentNode->IndexOf(aNode) : -1;
+    if (*aOffset >= 0) {
+      (*aOffset)++;
+    }
+    return parentNode;
+  }
+  static nsINode* GetParentAndOffsetBefore(nsINode* aNode, int32_t* aOffset)
+  {
+    MOZ_ASSERT(aNode);
+    MOZ_ASSERT(aOffset);
+    nsINode* parentNode = aNode->GetParentNode();
+    *aOffset = parentNode ? parentNode->IndexOf(aNode) : -1;
+    return parentNode;
   }
 
   NS_IMETHOD GetUsedFontFaces(nsIDOMFontFaceList** aResult);
 
   // nsIMutationObserver methods
   NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
@@ -309,16 +351,17 @@ public:
    */
   void ExcludeNonSelectableNodes(nsTArray<RefPtr<nsRange>>* aOutRanges);
 
   typedef nsTHashtable<nsPtrHashKey<nsRange> > RangeHashTable;
 protected:
   void RegisterCommonAncestor(nsINode* aNode);
   void UnregisterCommonAncestor(nsINode* aNode);
   nsINode* IsValidBoundary(nsINode* aNode);
+  static bool IsValidOffset(nsINode* aNode, int32_t aOffset);
 
   // CharacterDataChanged set aNotInsertedYet to true to disable an assertion
   // and suppress re-registering a range common ancestor node since
   // the new text node of a splitText hasn't been inserted yet.
   // CharacterDataChanged does the re-registering when needed.
   void DoSetRange(nsINode* aStartN, int32_t aStartOffset,
                   nsINode* aEndN, int32_t aEndOffset,
                   nsINode* aRoot, bool aNotInsertedYet = false);
--- a/dom/events/ContentEventHandler.cpp
+++ b/dom/events/ContentEventHandler.cpp
@@ -980,21 +980,17 @@ ContentEventHandler::SetRangeFromFlatTex
     *aNewOffset = aOffset;
   }
   if (aLastTextNode) {
     *aLastTextNode = nullptr;
   }
 
   // Special case like <br contenteditable>
   if (!mRootContent->HasChildren()) {
-    nsresult rv = aRange->SetStart(mRootContent, 0);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-    rv = aRange->SetEnd(mRootContent, 0);
+    nsresult rv = aRange->CollapseTo(mRootContent, 0);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
   nsCOMPtr<nsIContentIterator> iter = NS_NewPreContentIterator();
   nsresult rv = iter->Init(mRootContent);
   if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -2878,18 +2874,17 @@ ContentEventHandler::AdjustCollapsedRang
   }
 
   // But if the found node isn't a text node, we cannot modify the range.
   if (!childNode || !childNode->IsNodeOfType(nsINode::eTEXT) ||
       NS_WARN_IF(offsetInChildNode < 0)) {
     return NS_OK;
   }
 
-  nsresult rv = aRange->Set(childNode, offsetInChildNode,
-                            childNode, offsetInChildNode);
+  nsresult rv = aRange->CollapseTo(childNode, offsetInChildNode);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
   return NS_OK;
 }
 
 nsresult
 ContentEventHandler::GetStartFrameAndOffset(const nsRange* aRange,
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -1440,26 +1440,25 @@ HTMLEditRules::WillInsertText(EditAction
     }
     aSelection->SetInterlinePosition(false);
     if (curNode) aSelection->Collapse(curNode, curOffset);
     // manually update the doc changed range so that AfterEdit will clean up
     // the correct portion of the document.
     if (!mDocChangeRange) {
       mDocChangeRange = new nsRange(selNode);
     }
-    rv = mDocChangeRange->SetStart(selNode, selOffset);
-    NS_ENSURE_SUCCESS(rv, rv);
 
     if (curNode) {
-      rv = mDocChangeRange->SetEnd(curNode, curOffset);
+      rv = mDocChangeRange->SetStartAndEnd(selNode, selOffset,
+                                           curNode, curOffset);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
     } else {
-      rv = mDocChangeRange->SetEnd(selNode, selOffset);
+      rv = mDocChangeRange->CollapseTo(selNode, selOffset);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
     }
   }
   return NS_OK;
 }
 
@@ -5245,20 +5244,21 @@ HTMLEditRules::ExpandSelectionForDeletio
   bool doEndExpansion = true;
   if (firstBRParent) {
     // Find block node containing br
     nsCOMPtr<Element> brBlock = HTMLEditor::GetBlock(*firstBRParent);
     bool nodeBefore = false, nodeAfter = false;
 
     // Create a range that represents expanded selection
     RefPtr<nsRange> range = new nsRange(selStartNode);
-    nsresult rv = range->SetStart(selStartNode, selStartOffset);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = range->SetEnd(selEndNode, selEndOffset);
-    NS_ENSURE_SUCCESS(rv, rv);
+    nsresult rv = range->SetStartAndEnd(selStartNode, selStartOffset,
+                                        selEndNode, selEndOffset);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
 
     // Check if block is entirely inside range
     if (brBlock) {
       nsRange::CompareNodeToRange(brBlock, range, &nodeBefore, &nodeAfter);
     }
 
     // If block isn't contained, forgo grabbing the br in expanded selection
     if (nodeBefore || nodeAfter) {
@@ -5709,36 +5709,37 @@ HTMLEditRules::PromoteRange(nsRange& aRa
       }
     }
   }
 
   // Make a new adjusted range to represent the appropriate block content.
   // This is tricky.  The basic idea is to push out the range endpoints to
   // truly enclose the blocks that we will affect.
 
-  nsCOMPtr<nsIDOMNode> opStartNode;
-  nsCOMPtr<nsIDOMNode> opEndNode;
+  nsCOMPtr<nsIDOMNode> opDOMStartNode;
+  nsCOMPtr<nsIDOMNode> opDOMEndNode;
   int32_t opStartOffset, opEndOffset;
 
   GetPromotedPoint(kStart, GetAsDOMNode(startNode), startOffset,
-                   aOperationType, address_of(opStartNode), &opStartOffset);
+                   aOperationType, address_of(opDOMStartNode), &opStartOffset);
   GetPromotedPoint(kEnd, GetAsDOMNode(endNode), endOffset, aOperationType,
-                   address_of(opEndNode), &opEndOffset);
+                   address_of(opDOMEndNode), &opEndOffset);
 
   // Make sure that the new range ends up to be in the editable section.
   if (!htmlEditor->IsDescendantOfEditorRoot(
-        EditorBase::GetNodeAtRangeOffsetPoint(opStartNode, opStartOffset)) ||
+        EditorBase::GetNodeAtRangeOffsetPoint(opDOMStartNode, opStartOffset)) ||
       !htmlEditor->IsDescendantOfEditorRoot(
-        EditorBase::GetNodeAtRangeOffsetPoint(opEndNode, opEndOffset - 1))) {
+        EditorBase::GetNodeAtRangeOffsetPoint(opDOMEndNode, opEndOffset - 1))) {
     return;
   }
 
-  DebugOnly<nsresult> rv = aRange.SetStart(opStartNode, opStartOffset);
-  MOZ_ASSERT(NS_SUCCEEDED(rv));
-  rv = aRange.SetEnd(opEndNode, opEndOffset);
+  nsCOMPtr<nsINode> opStartNode = do_QueryInterface(opDOMStartNode);
+  nsCOMPtr<nsINode> opEndNode = do_QueryInterface(opDOMEndNode);
+  DebugOnly<nsresult> rv =
+    aRange.SetStartAndEnd(opStartNode, opStartOffset, opEndNode, opEndOffset);
   MOZ_ASSERT(NS_SUCCEEDED(rv));
 }
 
 class UniqueFunctor final : public BoolDomIterFunctor
 {
 public:
   explicit UniqueFunctor(nsTArray<OwningNonNull<nsINode>>& aArray)
     : mArray(aArray)
@@ -7395,20 +7396,20 @@ HTMLEditRules::PinSelectionToNewBlock(Se
     EditorBase::GetStartNodeAndOffset(aSelection,
                                       getter_AddRefs(selNode), &selOffset);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // use ranges and sRangeHelper to compare sel point to new block
   nsCOMPtr<nsINode> node = do_QueryInterface(selNode);
   NS_ENSURE_STATE(node);
   RefPtr<nsRange> range = new nsRange(node);
-  rv = range->SetStart(selNode, selOffset);
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = range->SetEnd(selNode, selOffset);
-  NS_ENSURE_SUCCESS(rv, rv);
+  rv = range->CollapseTo(node, selOffset);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
   bool nodeBefore, nodeAfter;
   rv = nsRange::CompareNodeToRange(mNewBlock, range, &nodeBefore, &nodeAfter);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (nodeBefore && nodeAfter) {
     return NS_OK;  // selection is inside block
   } else if (nodeBefore) {
     // selection is after block.  put at end of block.
@@ -8293,20 +8294,23 @@ NS_IMETHODIMP
 HTMLEditRules::DidSplitNode(nsIDOMNode* aExistingRightNode,
                             int32_t aOffset,
                             nsIDOMNode* aNewLeftNode,
                             nsresult aResult)
 {
   if (!mListenerEnabled) {
     return NS_OK;
   }
-  nsresult rv = mUtilRange->SetStart(aNewLeftNode, 0);
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = mUtilRange->SetEnd(aExistingRightNode, 0);
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsCOMPtr<nsINode> newLeftNode = do_QueryInterface(aNewLeftNode);
+  nsCOMPtr<nsINode> existingRightNode = do_QueryInterface(aExistingRightNode);
+  nsresult rv = mUtilRange->SetStartAndEnd(newLeftNode, 0,
+                                           existingRightNode, 0);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
   return UpdateDocChangeRange(mUtilRange);
 }
 
 NS_IMETHODIMP
 HTMLEditRules::WillJoinNodes(nsIDOMNode* aLeftNode,
                              nsIDOMNode* aRightNode,
                              nsIDOMNode* aParent)
 {
@@ -8321,21 +8325,22 @@ NS_IMETHODIMP
 HTMLEditRules::DidJoinNodes(nsIDOMNode* aLeftNode,
                             nsIDOMNode* aRightNode,
                             nsIDOMNode* aParent,
                             nsresult aResult)
 {
   if (!mListenerEnabled) {
     return NS_OK;
   }
+  nsCOMPtr<nsINode> rightNode = do_QueryInterface(aRightNode);
   // assumption that Join keeps the righthand node
-  nsresult rv = mUtilRange->SetStart(aRightNode, mJoinOffset);
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = mUtilRange->SetEnd(aRightNode, mJoinOffset);
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsresult rv = mUtilRange->CollapseTo(rightNode, mJoinOffset);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
   return UpdateDocChangeRange(mUtilRange);
 }
 
 NS_IMETHODIMP
 HTMLEditRules::WillInsertText(nsIDOMCharacterData* aTextNode,
                               int32_t aOffset,
                               const nsAString& aString)
 {
@@ -8347,21 +8352,22 @@ HTMLEditRules::DidInsertText(nsIDOMChara
                              int32_t aOffset,
                              const nsAString& aString,
                              nsresult aResult)
 {
   if (!mListenerEnabled) {
     return NS_OK;
   }
   int32_t length = aString.Length();
-  nsCOMPtr<nsIDOMNode> theNode = do_QueryInterface(aTextNode);
-  nsresult rv = mUtilRange->SetStart(theNode, aOffset);
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = mUtilRange->SetEnd(theNode, aOffset+length);
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsCOMPtr<nsINode> theNode = do_QueryInterface(aTextNode);
+  nsresult rv = mUtilRange->SetStartAndEnd(theNode, aOffset,
+                                           theNode, aOffset + length);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
   return UpdateDocChangeRange(mUtilRange);
 }
 
 NS_IMETHODIMP
 HTMLEditRules::WillDeleteText(nsIDOMCharacterData* aTextNode,
                               int32_t aOffset,
                               int32_t aLength)
 {
@@ -8372,49 +8378,54 @@ NS_IMETHODIMP
 HTMLEditRules::DidDeleteText(nsIDOMCharacterData* aTextNode,
                              int32_t aOffset,
                              int32_t aLength,
                              nsresult aResult)
 {
   if (!mListenerEnabled) {
     return NS_OK;
   }
-  nsCOMPtr<nsIDOMNode> theNode = do_QueryInterface(aTextNode);
-  nsresult rv = mUtilRange->SetStart(theNode, aOffset);
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = mUtilRange->SetEnd(theNode, aOffset);
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsCOMPtr<nsINode> theNode = do_QueryInterface(aTextNode);
+  nsresult rv = mUtilRange->CollapseTo(theNode, aOffset);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
   return UpdateDocChangeRange(mUtilRange);
 }
 
 NS_IMETHODIMP
 HTMLEditRules::WillDeleteSelection(nsISelection* aSelection)
 {
   if (!mListenerEnabled) {
     return NS_OK;
   }
   if (NS_WARN_IF(!aSelection)) {
     return NS_ERROR_INVALID_ARG;
   }
   RefPtr<Selection> selection = aSelection->AsSelection();
   // get the (collapsed) selection location
-  nsCOMPtr<nsIDOMNode> selNode;
-  int32_t selOffset;
-
+  nsCOMPtr<nsINode> startNode;
+  int32_t startOffset;
   nsresult rv =
     EditorBase::GetStartNodeAndOffset(selection,
-                                      getter_AddRefs(selNode), &selOffset);
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = mUtilRange->SetStart(selNode, selOffset);
-  NS_ENSURE_SUCCESS(rv, rv);
+                                      getter_AddRefs(startNode), &startOffset);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  nsCOMPtr<nsINode> endNode;
+  int32_t endOffset;
   rv = EditorBase::GetEndNodeAndOffset(selection,
-                                       getter_AddRefs(selNode), &selOffset);
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = mUtilRange->SetEnd(selNode, selOffset);
-  NS_ENSURE_SUCCESS(rv, rv);
+                                       getter_AddRefs(endNode), &endOffset);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  rv = mUtilRange->SetStartAndEnd(startNode, startOffset, endNode, endOffset);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
   return UpdateDocChangeRange(mUtilRange);
 }
 
 NS_IMETHODIMP
 HTMLEditRules::DidDeleteSelection(nsISelection *aSelection)
 {
   return NS_OK;
 }
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -3282,18 +3282,18 @@ HTMLEditor::DoContentInserted(nsIDocumen
       if (aInsertedOrAppended == eAppended) {
         // Count all the appended nodes
         nsIContent* sibling = aChild->GetNextSibling();
         while (sibling) {
           endIndex++;
           sibling = sibling->GetNextSibling();
         }
       }
-      nsresult rv = range->Set(aContainer, aIndexInContainer,
-                               aContainer, endIndex);
+      nsresult rv = range->SetStartAndEnd(aContainer, aIndexInContainer,
+                                          aContainer, endIndex);
       if (NS_SUCCEEDED(rv)) {
         mInlineSpellChecker->SpellCheckRange(range);
       }
     }
   }
 }
 
 void
--- a/editor/libeditor/HTMLStyleEditor.cpp
+++ b/editor/libeditor/HTMLStyleEditor.cpp
@@ -531,19 +531,21 @@ HTMLEditor::SplitStyleAboveRange(nsRange
 
   // second verse, same as the first...
   nsresult rv =
     SplitStyleAbovePoint(address_of(endNode), &endOffset, aProperty,
                          aAttribute);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // reset the range
-  rv = inRange->SetStart(startNode, startOffset);
-  NS_ENSURE_SUCCESS(rv, rv);
-  return inRange->SetEnd(endNode, endOffset);
+  rv = inRange->SetStartAndEnd(startNode, startOffset, endNode, endOffset);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  return NS_OK;
 }
 
 nsresult
 HTMLEditor::SplitStyleAbovePoint(nsCOMPtr<nsINode>* aNode,
                                  int32_t* aOffset,
                                  // null here means we split all properties
                                  nsIAtom* aProperty,
                                  const nsAString* aAttribute,
@@ -878,20 +880,21 @@ HTMLEditor::PromoteRangeIfStartsOrEndsIn
   }
   NS_ENSURE_TRUE(parent, NS_ERROR_NULL_POINTER);
 
   if (HTMLEditUtils::IsNamedAnchor(parent)) {
     endNode = parent->GetParentNode();
     endOffset = endNode ? endNode->IndexOf(parent) + 1 : 0;
   }
 
-  nsresult rv = aRange.SetStart(startNode, startOffset);
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = aRange.SetEnd(endNode, endOffset);
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsresult rv = aRange.SetStartAndEnd(startNode, startOffset,
+                                      endNode, endOffset);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
 
   return NS_OK;
 }
 
 nsresult
 HTMLEditor::PromoteInlineRange(nsRange& aRange)
 {
   nsCOMPtr<nsINode> startNode = aRange.GetStartParent();
@@ -911,20 +914,21 @@ HTMLEditor::PromoteInlineRange(nsRange& 
          IsEditable(endNode) && IsAtEndOfNode(*endNode, endOffset)) {
     nsCOMPtr<nsINode> parent = endNode->GetParentNode();
     NS_ENSURE_TRUE(parent, NS_ERROR_NULL_POINTER);
     // We are AFTER this node
     endOffset = 1 + parent->IndexOf(endNode);
     endNode = parent;
   }
 
-  nsresult rv = aRange.SetStart(startNode, startOffset);
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = aRange.SetEnd(endNode, endOffset);
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsresult rv = aRange.SetStartAndEnd(startNode, startOffset,
+                                      endNode, endOffset);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
 
   return NS_OK;
 }
 
 bool
 HTMLEditor::IsAtFrontOfNode(nsINode& aNode,
                             int32_t aOffset)
 {
--- a/editor/libeditor/SelectionState.cpp
+++ b/editor/libeditor/SelectionState.cpp
@@ -681,15 +681,16 @@ RangeItem::StoreRange(nsRange* aRange)
   endNode = aRange->GetEndParent();
   endOffset = aRange->EndOffset();
 }
 
 already_AddRefed<nsRange>
 RangeItem::GetRange()
 {
   RefPtr<nsRange> range = new nsRange(startNode);
-  if (NS_FAILED(range->Set(startNode, startOffset, endNode, endOffset))) {
+  if (NS_FAILED(range->SetStartAndEnd(startNode, startOffset,
+                                      endNode, endOffset))) {
     return nullptr;
   }
   return range.forget();
 }
 
 } // namespace mozilla
--- a/editor/libeditor/WSRunObject.cpp
+++ b/editor/libeditor/WSRunObject.cpp
@@ -1291,17 +1291,17 @@ WSRunObject::DeleteChars(nsINode* aStart
           mHTMLEditor->DeleteText(*node, 0, AssertedCast<uint32_t>(aEndOffset));
         NS_ENSURE_SUCCESS(rv, rv);
       }
       break;
     } else {
       if (!range) {
         range = new nsRange(aStartNode);
         nsresult rv =
-          range->Set(aStartNode, aStartOffset, aEndNode, aEndOffset);
+          range->SetStartAndEnd(aStartNode, aStartOffset, aEndNode, aEndOffset);
         NS_ENSURE_SUCCESS(rv, rv);
       }
       bool nodeBefore, nodeAfter;
       nsresult rv =
         nsRange::CompareNodeToRange(node, range, &nodeBefore, &nodeAfter);
       NS_ENSURE_SUCCESS(rv, rv);
       if (nodeAfter) {
         break;
--- a/editor/txtsvc/nsTextServicesDocument.cpp
+++ b/editor/txtsvc/nsTextServicesDocument.cpp
@@ -401,21 +401,23 @@ nsTextServicesDocument::ExpandRangeToWor
       rngEndOffset != wordStartOffset ||
       (rngEndNode == rngStartNode && rngEndOffset == rngStartOffset)) {
     rngEndNode = wordEndNode;
     rngEndOffset = wordEndOffset;
   }
 
   // Now adjust the range so that it uses our new
   // end points.
-
-  rv = range->SetEnd(rngEndNode, rngEndOffset);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return range->SetStart(rngStartNode, rngStartOffset);
+  nsCOMPtr<nsINode> startNode = do_QueryInterface(rngStartNode);
+  nsCOMPtr<nsINode> endNode = do_QueryInterface(rngEndNode);
+  rv = range->SetStartAndEnd(startNode, rngStartOffset, endNode, rngEndOffset);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsTextServicesDocument::SetFilter(nsITextServicesFilter *aFilter)
 {
   // Hang on to the filter so we can set it into the filtered iterator.
   mTxtSvcFilter = aFilter;
 
--- a/extensions/spellcheck/src/mozInlineSpellChecker.cpp
+++ b/extensions/spellcheck/src/mozInlineSpellChecker.cpp
@@ -159,26 +159,33 @@ mozInlineSpellStatus::InitForEditorChang
   mRange = new nsRange(prevNode);
 
   // ...we need to put the start and end in the correct order
   int16_t cmpResult;
   rv = mAnchorRange->ComparePoint(aPreviousNode, aPreviousOffset, &cmpResult);
   NS_ENSURE_SUCCESS(rv, rv);
   if (cmpResult < 0) {
     // previous anchor node is before the current anchor
-    rv = mRange->SetStart(aPreviousNode, aPreviousOffset);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = mRange->SetEnd(aAnchorNode, aAnchorOffset);
+    nsCOMPtr<nsINode> previousNode = do_QueryInterface(aPreviousNode);
+    nsCOMPtr<nsINode> anchorNode = do_QueryInterface(aAnchorNode);
+    rv = mRange->SetStartAndEnd(previousNode, aPreviousOffset,
+                                anchorNode, aAnchorOffset);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
   } else {
     // previous anchor node is after (or the same as) the current anchor
-    rv = mRange->SetStart(aAnchorNode, aAnchorOffset);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = mRange->SetEnd(aPreviousNode, aPreviousOffset);
+    nsCOMPtr<nsINode> previousNode = do_QueryInterface(aPreviousNode);
+    nsCOMPtr<nsINode> anchorNode = do_QueryInterface(aAnchorNode);
+    rv = mRange->SetStartAndEnd(anchorNode, aAnchorOffset,
+                                previousNode, aPreviousOffset);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
   }
-  NS_ENSURE_SUCCESS(rv, rv);
 
   // On insert save this range: DoSpellCheck optimizes things in this range.
   // Otherwise, just leave this nullptr.
   if (aAction == EditAction::insertText)
     mCreatedRange = mRange;
 
   // if we were given a range, we need to expand our range to encompass it
   if (aStartNode && aEndNode) {
@@ -449,27 +456,29 @@ mozInlineSpellStatus::GetDocument(nsIDOM
 // mozInlineSpellStatus::PositionToCollapsedRange
 //
 //    Converts a given DOM position to a collapsed range covering that
 //    position. We use ranges to store DOM positions becuase they stay
 //    updated as the DOM is changed.
 
 nsresult
 mozInlineSpellStatus::PositionToCollapsedRange(nsIDOMDocument* aDocument,
-    nsIDOMNode* aNode, int32_t aOffset, nsIDOMRange** aRange)
+                                               nsIDOMNode* aNode,
+                                               int32_t aOffset,
+                                               nsRange** aRange)
 {
   *aRange = nullptr;
-  nsCOMPtr<nsIDOMRange> range;
-  nsresult rv = aDocument->CreateRange(getter_AddRefs(range));
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsCOMPtr<nsINode> documentNode = do_QueryInterface(aDocument);
+  RefPtr<nsRange> range = new nsRange(documentNode);
 
-  rv = range->SetStart(aNode, aOffset);
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = range->SetEnd(aNode, aOffset);
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
+  nsresult rv = range->CollapseTo(node, aOffset);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
 
   range.swap(*aRange);
   return NS_OK;
 }
 
 // mozInlineSpellResume
 
 class mozInlineSpellResume : public Runnable
@@ -1162,19 +1171,18 @@ mozInlineSpellChecker::MakeSpellCheckRan
   nsCOMPtr<nsIEditor> editor (do_QueryReferent(mEditor));
   NS_ENSURE_TRUE(editor, NS_ERROR_NULL_POINTER);
 
   nsCOMPtr<nsIDOMDocument> doc;
   rv = editor->GetDocument(getter_AddRefs(doc));
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
 
-  nsCOMPtr<nsIDOMRange> range;
-  rv = doc->CreateRange(getter_AddRefs(range));
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsCOMPtr<nsINode> documentNode = do_QueryInterface(doc);
+  RefPtr<nsRange> range = new nsRange(documentNode);
 
   // possibly use full range of the editor
   nsCOMPtr<nsIDOMElement> rootElem;
   if (! aStartNode || ! aEndNode) {
     rv = editor->GetRootElement(getter_AddRefs(rootElem));
     NS_ENSURE_SUCCESS(rv, rv);
 
     aStartNode = rootElem;
@@ -1196,25 +1204,33 @@ mozInlineSpellChecker::MakeSpellCheckRan
     aEndOffset = childCount;
   }
 
   // sometimes we are are requested to check an empty range (possibly an empty
   // document). This will result in assertions later.
   if (aStartNode == aEndNode && aStartOffset == aEndOffset)
     return NS_OK;
 
-  rv = range->SetStart(aStartNode, aStartOffset);
-  NS_ENSURE_SUCCESS(rv, rv);
-  if (aEndOffset)
-    rv = range->SetEnd(aEndNode, aEndOffset);
-  else
-    rv = range->SetEndAfter(aEndNode);
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsCOMPtr<nsINode> startNode = do_QueryInterface(aStartNode);
+  nsCOMPtr<nsINode> endNode = do_QueryInterface(aEndNode);
+  if (aEndOffset) {
+    rv = range->SetStartAndEnd(startNode, aStartOffset, endNode, aEndOffset);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  } else {
+    int32_t endOffset = -1;
+    endNode = nsRange::GetParentAndOffsetAfter(endNode, &endOffset);
+    rv = range->SetStartAndEnd(startNode, aStartOffset, endNode, endOffset);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
 
-  *aRange = static_cast<nsRange*>(range.forget().take());
+  range.swap(*aRange);
   return NS_OK;
 }
 
 nsresult
 mozInlineSpellChecker::SpellCheckBetweenNodes(nsIDOMNode *aStartNode,
                                               int32_t aStartOffset,
                                               nsIDOMNode *aEndNode,
                                               int32_t aEndOffset)
--- a/extensions/spellcheck/src/mozInlineSpellChecker.h
+++ b/extensions/spellcheck/src/mozInlineSpellChecker.h
@@ -80,25 +80,25 @@ public:
   // Contains the range computed for the current word. Can be nullptr.
   RefPtr<nsRange> mNoCheckRange;
 
   // Indicates the position of the cursor for the event (so we can compute
   // mNoCheckRange). It can be nullptr if we don't care about the cursor position
   // (such as for the intial check of everything).
   //
   // For mOp == eOpNavigation, this is the NEW position of the cursor
-  nsCOMPtr<nsIDOMRange> mAnchorRange;
+  RefPtr<nsRange> mAnchorRange;
 
   // -----
   // The following members are only for navigation events and are only
   // stored for FinishNavigationEvent to initialize the other members.
   // -----
 
   // this is the OLD position of the cursor
-  nsCOMPtr<nsIDOMRange> mOldNavigationAnchorRange;
+  RefPtr<nsRange> mOldNavigationAnchorRange;
 
   // Set when we should force checking the current word. See
   // mozInlineSpellChecker::HandleNavigationEvent for a description of why we
   // have this.
   bool mForceNavigationWordCheck;
 
   // Contains the offset passed in to HandleNavigationEvent
   int32_t mNewNavigationPositionOffset;
@@ -106,17 +106,17 @@ public:
 protected:
   nsresult FinishNavigationEvent(mozInlineSpellWordUtil& aWordUtil);
 
   nsresult FillNoCheckRangeFromAnchor(mozInlineSpellWordUtil& aWordUtil);
 
   nsresult GetDocument(nsIDOMDocument** aDocument);
   nsresult PositionToCollapsedRange(nsIDOMDocument* aDocument,
                                     nsIDOMNode* aNode, int32_t aOffset,
-                                    nsIDOMRange** aRange);
+                                    nsRange** aRange);
 };
 
 class mozInlineSpellChecker final : public nsIInlineSpellChecker,
                                     public nsIEditActionListener,
                                     public nsIDOMEventListener,
                                     public nsSupportsWeakReference
 {
 private:
--- a/extensions/spellcheck/src/mozInlineSpellWordUtil.cpp
+++ b/extensions/spellcheck/src/mozInlineSpellWordUtil.cpp
@@ -330,19 +330,21 @@ nsresult
 mozInlineSpellWordUtil::MakeRange(NodeOffset aBegin, NodeOffset aEnd,
                                   nsRange** aRange)
 {
   NS_ENSURE_ARG_POINTER(aBegin.mNode);
   if (!mDOMDocument)
     return NS_ERROR_NOT_INITIALIZED;
 
   RefPtr<nsRange> range = new nsRange(aBegin.mNode);
-  nsresult rv = range->Set(aBegin.mNode, aBegin.mOffset,
-                           aEnd.mNode, aEnd.mOffset);
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsresult rv = range->SetStartAndEnd(aBegin.mNode, aBegin.mOffset,
+                                      aEnd.mNode, aEnd.mOffset);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
   range.forget(aRange);
 
   return NS_OK;
 }
 
 /*********** DOM text extraction ************/
 
 // IsDOMWordSeparator
--- a/layout/forms/nsTextControlFrame.cpp
+++ b/layout/forms/nsTextControlFrame.cpp
@@ -750,22 +750,22 @@ nsTextControlFrame::SetSelectionInternal
   // Note that we use a new range to avoid having to do
   // isIncreasing checks to avoid possible errors.
 
   RefPtr<nsRange> range = new nsRange(mContent);
   // Be careful to use internal nsRange methods which do not check to make sure
   // we have access to the node.
   nsCOMPtr<nsINode> start = do_QueryInterface(aStartNode);
   nsCOMPtr<nsINode> end = do_QueryInterface(aEndNode);
-  // XXXbz nsRange::Set takes int32_t (and ranges generally work on int32_t),
-  // but we're passing uint32_t.  The good news is that at this point our
-  // endpoints should really be within our length, so not really that big.  And
-  // if they _are_ that big, Set() will simply error out, which is not too bad
-  // for a case we don't expect to happen.
-  nsresult rv = range->Set(start, aStartOffset, end, aEndOffset);
+  // XXXbz nsRange::SetStartAndEnd takes int32_t (and ranges generally work on
+  // int32_t), but we're passing uint32_t.  The good news is that at this point
+  // our endpoints should really be within our length, so not really that big.
+  // And if they _are_ that big, SetStartAndEnd() will simply error out, which
+  // is not too bad for a case we don't expect to happen.
+  nsresult rv = range->SetStartAndEnd(start, aStartOffset, end, aEndOffset);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Get the selection, clear it and add the new range to it!
   nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
   NS_ASSERTION(txtCtrl, "Content not a text control element");
   nsISelectionController* selCon = txtCtrl->GetSelectionController();
   NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE);
 
--- a/layout/generic/nsSelection.cpp
+++ b/layout/generic/nsSelection.cpp
@@ -1790,18 +1790,17 @@ nsFrameSelection::TakeFocus(nsIContent* 
 
     if (aMultipleSelection) {
       // Remove existing collapsed ranges as there's no point in having 
       // non-anchor/focus collapsed ranges.
       mDomSelections[index]->RemoveCollapsedRanges();
 
       RefPtr<nsRange> newRange = new nsRange(aNewFocus);
 
-      newRange->SetStart(aNewFocus, aContentOffset);
-      newRange->SetEnd(aNewFocus, aContentOffset);
+      newRange->CollapseTo(aNewFocus, aContentOffset);
       mDomSelections[index]->AddRange(newRange);
       mBatching = batching;
       mChangesDuringBatching = changes;
     } else {
       bool oldDesiredPosSet = mDesiredPosSet; //need to keep old desired position if it was set.
       mDomSelections[index]->Collapse(aNewFocus, aContentOffset);
       mDesiredPosSet = oldDesiredPosSet; //now reset desired pos back.
       mBatching = batching;
@@ -3363,21 +3362,22 @@ Selection::GetTableSelectionType(nsIDOMR
 nsresult
 nsFrameSelection::CreateAndAddRange(nsINode *aParentNode, int32_t aOffset)
 {
   if (!aParentNode) return NS_ERROR_NULL_POINTER;
 
   RefPtr<nsRange> range = new nsRange(aParentNode);
 
   // Set range around child at given offset
-  nsresult result = range->SetStart(aParentNode, aOffset);
-  if (NS_FAILED(result)) return result;
-  result = range->SetEnd(aParentNode, aOffset+1);
-  if (NS_FAILED(result)) return result;
-  
+  nsresult rv = range->SetStartAndEnd(aParentNode, aOffset,
+                                      aParentNode, aOffset + 1);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
   int8_t index = GetIndexFromSelectionType(SelectionType::eNormal);
   if (!mDomSelections[index])
     return NS_ERROR_NULL_POINTER;
 
   return mDomSelections[index]->AddRange(range);
 }
 
 // End of Table Selection
@@ -3795,42 +3795,39 @@ Selection::SubtractRange(RangeData* aRan
   // cmp < 0, and cmp2 < 0
   // If it right overlaps the new range then cmp > 0 and cmp2 > 0
   // If it fully contains the new range, then cmp < 0 and cmp2 > 0
 
   if (cmp2 > 0) {
     // We need to add a new RangeData to the output, running from
     // the end of aSubtract to the end of range
     RefPtr<nsRange> postOverlap = new nsRange(aSubtract->GetEndParent());
-
-    rv =
-      postOverlap->SetStart(aSubtract->GetEndParent(), aSubtract->EndOffset());
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv =
-     postOverlap->SetEnd(range->GetEndParent(), range->EndOffset());
-    NS_ENSURE_SUCCESS(rv, rv);
+    rv = postOverlap->SetStartAndEnd(
+                        aSubtract->GetEndParent(), aSubtract->EndOffset(),
+                        range->GetEndParent(), range->EndOffset());
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
     if (!postOverlap->Collapsed()) {
       if (!aOutput->InsertElementAt(0, RangeData(postOverlap)))
         return NS_ERROR_OUT_OF_MEMORY;
       (*aOutput)[0].mTextRangeStyle = aRange->mTextRangeStyle;
     }
   }
 
   if (cmp < 0) {
     // We need to add a new RangeData to the output, running from
     // the start of the range to the start of aSubtract
     RefPtr<nsRange> preOverlap = new nsRange(range->GetStartParent());
-
-    nsresult rv =
-     preOverlap->SetStart(range->GetStartParent(), range->StartOffset());
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv =
-     preOverlap->SetEnd(aSubtract->GetStartParent(), aSubtract->StartOffset());
-    NS_ENSURE_SUCCESS(rv, rv);
-    
+    rv = preOverlap->SetStartAndEnd(
+                       range->GetStartParent(), range->StartOffset(),
+                       aSubtract->GetStartParent(), aSubtract->StartOffset());
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
     if (!preOverlap->Collapsed()) {
       if (!aOutput->InsertElementAt(0, RangeData(preOverlap)))
         return NS_ERROR_OUT_OF_MEMORY;
       (*aOutput)[0].mTextRangeStyle = aRange->mTextRangeStyle;
     }
   }
 
   return NS_OK;
@@ -5272,22 +5269,17 @@ Selection::Collapse(nsINode& aParentNode
           (parentNode == f->GetContent()->GetParentNode() &&
            parentNode->IndexOf(f->GetContent()) + 1 == int32_t(aOffset))) {
         frameSelection->SetHint(CARET_ASSOCIATE_AFTER);
       }
     }
   }
 
   RefPtr<nsRange> range = new nsRange(parentNode);
-  result = range->SetEnd(parentNode, aOffset);
-  if (NS_FAILED(result)) {
-    aRv.Throw(result);
-    return;
-  }
-  result = range->SetStart(parentNode, aOffset);
+  result = range->CollapseTo(parentNode, aOffset);
   if (NS_FAILED(result)) {
     aRv.Throw(result);
     return;
   }
 
 #ifdef DEBUG_SELECTION
   nsCOMPtr<nsIContent> content = do_QueryInterface(parentNode);
   nsCOMPtr<nsIDocument> doc = do_QueryInterface(parentNode);
@@ -5680,21 +5672,18 @@ Selection::Extend(nsINode& aParentNode, 
   RefPtr<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
     range->SetEnd(aParentNode, aOffset, aRv);
     if (aRv.Failed()) {
       return;
     }
     SetDirection(eDirNext);
-    res = difRange->SetEnd(range->GetEndParent(), range->EndOffset());
-    nsresult tmp = difRange->SetStart(focusNode, focusOffset);
-    if (NS_FAILED(tmp)) {
-      res = tmp;
-    }
+    res = difRange->SetStartAndEnd(focusNode, focusOffset,
+                                   range->GetEndParent(), range->EndOffset());
     if (NS_FAILED(res)) {
       aRv.Throw(res);
       return;
     }
     SelectFrames(presContext, difRange , true);
     res = SetAnchorFocusToRange(range);
     if (NS_FAILED(res)) {
       aRv.Throw(res);
@@ -5712,21 +5701,18 @@ Selection::Extend(nsINode& aParentNode, 
     res = SetAnchorFocusToRange(range);
     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);
-    difRange->SetStart(aParentNode, aOffset, aRv);
-    if (aRv.Failed()) {
-      return;
-    }
+    res = difRange->SetStartAndEnd(&aParentNode, aOffset,
+                                   focusNode, focusOffset);
     if (NS_FAILED(res)) {
       aRv.Throw(res);
       return;
     }
 
     range->SetEnd(aParentNode, aOffset, aRv);
     if (aRv.Failed()) {
       return;
@@ -5780,21 +5766,18 @@ Selection::Extend(nsINode& aParentNode, 
         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
-    difRange->SetEnd(aParentNode, aOffset, aRv);
-    res = difRange->SetStart(focusNode, focusOffset);
-    if (aRv.Failed()) {
-      return;
-    }
+    res = difRange->SetStartAndEnd(focusNode, focusOffset,
+                                   &aParentNode, aOffset);
     if (NS_FAILED(res)) {
       aRv.Throw(res);
       return;
     }
     SetDirection(eDirPrevious);
     range->SetStart(aParentNode, aOffset, aRv);
     if (aRv.Failed()) {
       return;
@@ -5815,22 +5798,19 @@ Selection::Extend(nsINode& aParentNode, 
     }
     SetDirection(eDirPrevious);
     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);
+      res = difRange->SetStartAndEnd(anchorNode, anchorOffset,
+                                     focusNode, focusOffset);
+      nsresult tmp = SetAnchorFocusToRange(range);
       if (NS_FAILED(tmp)) {
         res = tmp;
       }
       if (NS_FAILED(res)) {
         aRv.Throw(res);
         return;
       }
       SelectFrames(presContext, difRange, false);
@@ -5848,21 +5828,19 @@ Selection::Extend(nsINode& aParentNode, 
   }
   else if (result2 >= 0 && result1 >= 0) {//2,1,a or 21,a or 2,1a or 21a
     //select from 2 to 1
     range->SetStart(aParentNode, aOffset, aRv);
     if (aRv.Failed()) {
       return;
     }
     SetDirection(eDirPrevious);
-    res = difRange->SetEnd(focusNode, focusOffset);
-    nsresult tmp = difRange->SetStart(range->GetStartParent(), range->StartOffset());
-    if (NS_FAILED(tmp)) {
-      res = tmp;
-    }
+    res = difRange->SetStartAndEnd(
+                      range->GetStartParent(), range->StartOffset(),
+                      focusNode, focusOffset);
     if (NS_FAILED(res)) {
       aRv.Throw(res);
       return;
     }
 
     SelectFrames(presContext, difRange, true);
     res = SetAnchorFocusToRange(range);
     if (NS_FAILED(res)) {
--- a/layout/printing/nsPrintEngine.cpp
+++ b/layout/printing/nsPrintEngine.cpp
@@ -2446,23 +2446,27 @@ CloneRangeToSelection(nsRange* aRange, n
   int32_t endOffset = aRange->EndOffset();
   NS_ENSURE_TRUE_VOID(startContainer && endContainer);
 
   nsCOMPtr<nsIDOMNode> newStart = GetEqualNodeInCloneTree(startContainer, aDoc);
   nsCOMPtr<nsIDOMNode> newEnd = GetEqualNodeInCloneTree(endContainer, aDoc);
   NS_ENSURE_TRUE_VOID(newStart && newEnd);
 
   nsCOMPtr<nsINode> newStartNode = do_QueryInterface(newStart);
-  NS_ENSURE_TRUE_VOID(newStartNode);
+  nsCOMPtr<nsINode> newEndNode = do_QueryInterface(newEnd);
+  if (NS_WARN_IF(!newStartNode) || NS_WARN_IF(!newEndNode)) {
+    return;
+  }
 
   RefPtr<nsRange> range = new nsRange(newStartNode);
-  nsresult rv = range->SetStart(newStartNode, startOffset);
-  NS_ENSURE_SUCCESS_VOID(rv);
-  rv = range->SetEnd(newEnd, endOffset);
-  NS_ENSURE_SUCCESS_VOID(rv);
+  nsresult rv =
+    range->SetStartAndEnd(newStartNode, startOffset, newEndNode, endOffset);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return;
+  }
 
   aSelection->AddRange(range);
 }
 
 static nsresult CloneSelection(nsIDocument* aOrigDoc, nsIDocument* aDoc)
 {
   nsIPresShell* origShell = aOrigDoc->GetShell();
   nsIPresShell* shell = aDoc->GetShell();