Bug 1423097 - part 2: Add overloads of nsRange::SetStart(), nsRange::SetEnd(), nsRange::IsPointInRange() and nsRange::ComparePoint() to use them with RawRangeBoundary r?smaug draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Tue, 05 Dec 2017 17:50:13 +0900
changeset 710242 f1a78f0266703368b6cc75416ef2ac4333e4927c
parent 709489 259db8743b7cbe245c4c641fe0a1237cf0f50737
child 710243 6ad6ff45e6464aa199451a1ea3c317ed8381b309
push id92792
push usermasayuki@d-toybox.com
push dateFri, 08 Dec 2017 23:53:41 +0000
reviewerssmaug
bugs1423097
milestone59.0a1
Bug 1423097 - part 2: Add overloads of nsRange::SetStart(), nsRange::SetEnd(), nsRange::IsPointInRange() and nsRange::ComparePoint() to use them with RawRangeBoundary r?smaug nsRange::SetStart(), nsRange::SetEnd(), nsRange::IsPointInRange() and nsRange::ComparePoint() take a set of container node and offset in it to specifying a DOM point. However, the caller may not have computed the offset but may know the child node at the point. In such case, they can avoid computing the offset with nsINode::IndexOf() if they have overloads which take RawRangeBoundary. Therefore, this patch implements the overloads and changes the callers in editor. MozReview-Commit-ID: E4DLbAgTTCI
dom/base/nsRange.cpp
dom/base/nsRange.h
editor/libeditor/HTMLEditRules.cpp
--- a/dom/base/nsRange.cpp
+++ b/dom/base/nsRange.cpp
@@ -280,17 +280,17 @@ nsRange::IsNodeSelected(nsINode* aNode, 
  * constructor/destructor
  ******************************************************/
 
 nsRange::~nsRange()
 {
   NS_ASSERTION(!IsInSelection(), "deleting nsRange that is in use");
 
   // we want the side effects (releases and list removals)
-  DoSetRange(nullptr, 0, nullptr, 0, nullptr);
+  DoSetRange(RawRangeBoundary(), RawRangeBoundary(), nullptr);
 }
 
 nsRange::nsRange(nsINode* aNode)
   : mRoot(nullptr)
   , mRegisteredCommonAncestor(nullptr)
   , mNextStartRef(nullptr)
   , mNextEndRef(nullptr)
   , mIsPositioned(false)
@@ -854,24 +854,24 @@ nsRange::IsPointInRange(nsIDOMNode* aCon
   if (!container) {
     return NS_ERROR_DOM_NOT_OBJECT_ERR;
   }
   if (NS_WARN_IF(!IsValidOffset(aOffset))) {
     return NS_ERROR_DOM_INDEX_SIZE_ERR;
   }
 
   ErrorResult rv;
-  *aResult = IsPointInRange(*container, aOffset, rv);
+  *aResult = IsPointInRange(RawRangeBoundary(container, aOffset), rv);
   return rv.StealNSResult();
 }
 
 bool
-nsRange::IsPointInRange(nsINode& aContainer, uint32_t aOffset, ErrorResult& aRv)
+nsRange::IsPointInRange(const RawRangeBoundary& aPoint, ErrorResult& aRv)
 {
-  uint16_t compareResult = ComparePoint(aContainer, aOffset, aRv);
+  uint16_t compareResult = ComparePoint(aPoint, aRv);
   // If the node isn't in the range's document, it clearly isn't in the range.
   if (aRv.ErrorCodeIs(NS_ERROR_DOM_WRONG_DOCUMENT_ERR)) {
     aRv.SuppressException();
     return false;
   }
 
   return compareResult == 0;
 }
@@ -881,52 +881,56 @@ nsRange::IsPointInRange(nsINode& aContai
 NS_IMETHODIMP
 nsRange::ComparePoint(nsIDOMNode* aContainer, uint32_t aOffset,
                       int16_t* aResult)
 {
   nsCOMPtr<nsINode> container = do_QueryInterface(aContainer);
   NS_ENSURE_TRUE(container, NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
 
   ErrorResult rv;
-  *aResult = ComparePoint(*container, aOffset, rv);
+  *aResult = ComparePoint(RawRangeBoundary(container, aOffset), rv);
   return rv.StealNSResult();
 }
 
 int16_t
-nsRange::ComparePoint(nsINode& aContainer, uint32_t aOffset, ErrorResult& aRv)
+nsRange::ComparePoint(const RawRangeBoundary& aPoint, ErrorResult& aRv)
 {
+  if (NS_WARN_IF(!aPoint.IsSet())) {
+    // FYI: Shouldn't reach this case if it's called by JS.  Therefore, it's
+    //      okay to warn.
+    aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
+    return 0;
+  }
+
   // our range is in a good state?
   if (!mIsPositioned) {
     aRv.Throw(NS_ERROR_NOT_INITIALIZED);
     return 0;
   }
 
-  if (!nsContentUtils::ContentIsDescendantOf(&aContainer, mRoot)) {
+  if (!nsContentUtils::ContentIsDescendantOf(aPoint.Container(), mRoot)) {
     aRv.Throw(NS_ERROR_DOM_WRONG_DOCUMENT_ERR);
     return 0;
   }
 
-  if (aContainer.NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE) {
+  if (aPoint.Container()->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE) {
     aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
     return 0;
   }
 
-  if (aOffset > aContainer.Length()) {
+  if (aPoint.Offset() > aPoint.Container()->Length()) {
     aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     return 0;
   }
 
-  int32_t cmp = nsContentUtils::ComparePoints(&aContainer, aOffset,
-                                              mStart.Container(),
-                                              mStart.Offset());
+  int32_t cmp = nsContentUtils::ComparePoints(aPoint, mStart.AsRaw());
   if (cmp <= 0) {
     return cmp;
   }
-  if (nsContentUtils::ComparePoints(mEnd.Container(), mEnd.Offset(),
-                                    &aContainer, aOffset) == -1) {
+  if (nsContentUtils::ComparePoints(mEnd.AsRaw(), aPoint) == -1) {
     return 1;
   }
 
   return 0;
 }
 
 NS_IMETHODIMP
 nsRange::IntersectsNode(nsIDOMNode* aNode, bool* aResult)
@@ -1373,59 +1377,55 @@ nsRange::SetStart(nsINode& aNode, uint32
 {
  if (!nsContentUtils::LegacyIsCallerNativeCode() &&
      !nsContentUtils::CanCallerAccess(&aNode)) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return;
   }
 
   AutoInvalidateSelection atEndOfBlock(this);
-  aRv = SetStart(&aNode, aOffset);
+  SetStart(RawRangeBoundary(&aNode, aOffset), aRv);
 }
 
 NS_IMETHODIMP
 nsRange::SetStart(nsIDOMNode* aContainer, uint32_t aOffset)
 {
   nsCOMPtr<nsINode> container = do_QueryInterface(aContainer);
   if (!container) {
     return NS_ERROR_DOM_NOT_OBJECT_ERR;
   }
 
   ErrorResult rv;
   SetStart(*container, aOffset, rv);
   return rv.StealNSResult();
 }
 
-/* virtual */ nsresult
-nsRange::SetStart(nsINode* aContainer, uint32_t aOffset)
+void
+nsRange::SetStart(const RawRangeBoundary& aPoint, ErrorResult& aRv)
 {
-  nsINode* newRoot = IsValidBoundary(aContainer);
+  nsINode* newRoot = IsValidBoundary(aPoint.Container());
   if (!newRoot) {
-    return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
+    aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
+    return;
   }
 
-  if (!IsValidOffset(aContainer, aOffset)) {
-    return NS_ERROR_DOM_INDEX_SIZE_ERR;
+  if (!aPoint.IsSetAndValid()) {
+    aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
+    return;
   }
 
   // Collapse if not positioned yet, if positioned in another doc or
   // if the new start is after end.
   if (!mIsPositioned || newRoot != mRoot ||
-      nsContentUtils::ComparePoints(aContainer,
-                                    static_cast<int32_t>(aOffset),
-                                    mEnd.Container(), mEnd.Offset()) == 1) {
-    DoSetRange(aContainer, aOffset, aContainer, aOffset, newRoot);
-
-    return NS_OK;
+      nsContentUtils::ComparePoints(aPoint, mEnd.AsRaw()) == 1) {
+    DoSetRange(aPoint, aPoint, newRoot);
+    return;
   }
 
-  RawRangeBoundary newStart(aContainer, aOffset);
-  DoSetRange(newStart, mEnd.AsRaw(), mRoot);
-
-  return NS_OK;
+  DoSetRange(aPoint, mEnd.AsRaw(), mRoot);
 }
 
 void
 nsRange::SetStartBeforeJS(nsINode& aNode, ErrorResult& aErr)
 {
   AutoCalledByJSRestore calledByJSRestorer(*this);
   mCalledByJS = true;
   SetStartBefore(aNode, aErr);
@@ -1513,60 +1513,55 @@ void
 nsRange::SetEnd(nsINode& aNode, uint32_t aOffset, ErrorResult& aRv)
 {
  if (!nsContentUtils::LegacyIsCallerNativeCode() &&
      !nsContentUtils::CanCallerAccess(&aNode)) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return;
   }
   AutoInvalidateSelection atEndOfBlock(this);
-  aRv = SetEnd(&aNode, aOffset);
+  SetEnd(RawRangeBoundary(&aNode, aOffset), aRv);
 }
 
 NS_IMETHODIMP
 nsRange::SetEnd(nsIDOMNode* aContainer, uint32_t aOffset)
 {
   nsCOMPtr<nsINode> container = do_QueryInterface(aContainer);
   if (!container) {
     return NS_ERROR_DOM_NOT_OBJECT_ERR;
   }
 
   ErrorResult rv;
   SetEnd(*container, aOffset, rv);
   return rv.StealNSResult();
 }
 
-/* virtual */ nsresult
-nsRange::SetEnd(nsINode* aContainer, uint32_t aOffset)
+void
+nsRange::SetEnd(const RawRangeBoundary& aPoint, ErrorResult& aRv)
 {
-  nsINode* newRoot = IsValidBoundary(aContainer);
+  nsINode* newRoot = IsValidBoundary(aPoint.Container());
   if (!newRoot) {
-    return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
+    aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
+    return;
   }
 
-  if (!IsValidOffset(aContainer, aOffset)) {
-    return NS_ERROR_DOM_INDEX_SIZE_ERR;
+  if (!aPoint.IsSetAndValid()) {
+    aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
+    return;
   }
 
   // Collapse if not positioned yet, if positioned in another doc or
   // if the new end is before start.
   if (!mIsPositioned || newRoot != mRoot ||
-      nsContentUtils::ComparePoints(mStart.Container(),
-                                    static_cast<int32_t>(mStart.Offset()),
-                                    aContainer,
-                                    static_cast<int32_t>(aOffset)) == 1) {
-    DoSetRange(aContainer, aOffset, aContainer, aOffset, newRoot);
-
-    return NS_OK;
+      nsContentUtils::ComparePoints(mStart.AsRaw(), aPoint) == 1) {
+    DoSetRange(aPoint, aPoint, newRoot);
+    return;
   }
 
-  RawRangeBoundary newEnd(aContainer, aOffset);
-  DoSetRange(mStart.AsRaw(), newEnd, mRoot);
-
-  return NS_OK;
+  DoSetRange(mStart.AsRaw(), aPoint, mRoot);
 }
 
 void
 nsRange::SelectNodesInContainer(nsINode* aContainer,
                                 nsIContent* aStartContent,
                                 nsIContent* aEndContent)
 {
   MOZ_ASSERT(aContainer);
@@ -1637,28 +1632,16 @@ nsRange::SetStartAndEnd(const RawRangeBo
     return NS_OK;
   }
 
   // Otherwise, set the range as specified.
   DoSetRange(aStart, aEnd, newStartRoot);
   return NS_OK;
 }
 
-nsresult
-nsRange::SetStartAndEnd(nsINode* aStartContainer, uint32_t aStartOffset,
-                        nsINode* aEndContainer, uint32_t aEndOffset)
-{
-  if (NS_WARN_IF(!aStartContainer) || NS_WARN_IF(!aEndContainer)) {
-    return NS_ERROR_INVALID_ARG;
-  }
-
-  return SetStartAndEnd(RawRangeBoundary(aStartContainer, aStartOffset),
-                        RawRangeBoundary(aEndContainer, aEndOffset));
-}
-
 void
 nsRange::SetEndBeforeJS(nsINode& aNode, ErrorResult& aErr)
 {
   AutoCalledByJSRestore calledByJSRestorer(*this);
   mCalledByJS = true;
   SetEndBefore(aNode, aErr);
 }
 
@@ -1799,17 +1782,18 @@ nsRange::SelectNode(nsINode& aNode, Erro
   if (NS_WARN_IF(index < 0) ||
       !IsValidOffset(static_cast<uint32_t>(index)) ||
       !IsValidOffset(static_cast<uint32_t>(index) + 1)) {
     aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
     return;
   }
 
   AutoInvalidateSelection atEndOfBlock(this);
-  DoSetRange(container, index, container, index + 1, newRoot);
+  DoSetRange(RawRangeBoundary(container, index),
+             RawRangeBoundary(container, index + 1), newRoot);
 }
 
 NS_IMETHODIMP
 nsRange::SelectNodeContents(nsIDOMNode* aN)
 {
   nsCOMPtr<nsINode> node = do_QueryInterface(aN);
   NS_ENSURE_TRUE(node, NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
 
@@ -1837,17 +1821,18 @@ nsRange::SelectNodeContents(nsINode& aNo
 
   nsINode* newRoot = IsValidBoundary(&aNode);
   if (!newRoot) {
     aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
     return;
   }
 
   AutoInvalidateSelection atEndOfBlock(this);
-  DoSetRange(&aNode, 0, &aNode, aNode.Length(), newRoot);
+  DoSetRange(RawRangeBoundary(&aNode, 0),
+             RawRangeBoundary(&aNode, aNode.Length()), newRoot);
 }
 
 // The Subtree Content Iterator only returns subtrees that are
 // completely within a given range. It doesn't return a CharacterData
 // node that contains either the start or end point of the range.,
 // nor does it return element nodes when nothing in the element is selected.
 // We need an iterator that will also include these start/end points
 // so that our methods/algorithms aren't cluttered with special
--- a/dom/base/nsRange.h
+++ b/dom/base/nsRange.h
@@ -177,31 +177,45 @@ public:
   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* aContainer, uint32_t aOffset);
-  nsresult SetEnd(nsINode* aContainer, uint32_t aOffset);
+  nsresult SetStart(nsINode* aContainer, uint32_t aOffset)
+  {
+    ErrorResult error;
+    SetStart(RawRangeBoundary(aContainer, aOffset), error);
+    return error.StealNSResult();
+  }
+  nsresult SetEnd(nsINode* aContainer, uint32_t aOffset)
+  {
+    ErrorResult error;
+    SetEnd(RawRangeBoundary(aContainer, aOffset), error);
+    return error.StealNSResult();
+  }
 
   already_AddRefed<nsRange> CloneRange() const;
 
   /**
    * 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* aStartContainer, uint32_t aStartOffset,
-                          nsINode* aEndContainer, uint32_t aEndOffset);
+                          nsINode* aEndContainer, uint32_t aEndOffset)
+  {
+    return SetStartAndEnd(RawRangeBoundary(aStartContainer, aStartOffset),
+                          RawRangeBoundary(aEndContainer, aEndOffset));
+  }
   nsresult SetStartAndEnd(const RawRangeBoundary& aStart,
                           const RawRangeBoundary& aEnd);
 
   /**
    * Adds all nodes between |aStartContent| and |aEndContent| to the range.
    * The start offset will be set before |aStartContent|,
    * while the end offset will be set immediately after |aEndContent|.
    *
@@ -285,28 +299,36 @@ public:
   }
   already_AddRefed<mozilla::dom::DocumentFragment>
   CreateContextualFragment(const nsAString& aString, ErrorResult& aError);
   already_AddRefed<mozilla::dom::DocumentFragment>
   CloneContents(ErrorResult& aErr);
   int16_t CompareBoundaryPoints(uint16_t aHow, nsRange& aOther,
                                 ErrorResult& aErr);
   int16_t ComparePoint(nsINode& aContainer, uint32_t aOffset,
-                       ErrorResult& aErr);
+                       ErrorResult& aErr)
+  {
+    return ComparePoint(RawRangeBoundary(&aContainer, aOffset), aErr);
+  }
+  int16_t ComparePoint(const RawRangeBoundary& aPoint, ErrorResult& aErr);
   void DeleteContents(ErrorResult& aRv);
   already_AddRefed<mozilla::dom::DocumentFragment>
     ExtractContents(ErrorResult& aErr);
   nsINode* GetCommonAncestorContainer(ErrorResult& aRv) const;
   nsINode* GetStartContainer(ErrorResult& aRv) const;
   uint32_t GetStartOffset(ErrorResult& aRv) const;
   nsINode* GetEndContainer(ErrorResult& aRv) const;
   uint32_t GetEndOffset(ErrorResult& aRv) const;
   void InsertNode(nsINode& aNode, ErrorResult& aErr);
   bool IntersectsNode(nsINode& aNode, ErrorResult& aRv);
-  bool IsPointInRange(nsINode& aContainer, uint32_t aOffset, ErrorResult& aErr);
+  bool IsPointInRange(nsINode& aContainer, uint32_t aOffset, ErrorResult& aErr)
+  {
+    return IsPointInRange(RawRangeBoundary(&aContainer, aOffset), aErr);
+  }
+  bool IsPointInRange(const RawRangeBoundary& aPoint, ErrorResult& aErr);
 
   // *JS() methods are mapped to Range.*() of DOM.
   // They may move focus only when the range represents normal selection.
   // These methods shouldn't be used from internal.
   void CollapseJS(bool aToStart);
   void SelectNodeJS(nsINode& aNode, ErrorResult& aErr);
   void SelectNodeContentsJS(nsINode& aNode, ErrorResult& aErr);
   void SetEndJS(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr);
@@ -324,19 +346,21 @@ public:
   void GetClientRectsAndTexts(
     mozilla::dom::ClientRectsAndTexts& aResult,
     ErrorResult& aErr);
 
   // Following methods should be used for internal use instead of *JS().
   void SelectNode(nsINode& aNode, ErrorResult& aErr);
   void SelectNodeContents(nsINode& aNode, ErrorResult& aErr);
   void SetEnd(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr);
+  void SetEnd(const RawRangeBoundary& aPoint, ErrorResult& aErr);
   void SetEndAfter(nsINode& aNode, ErrorResult& aErr);
   void SetEndBefore(nsINode& aNode, ErrorResult& aErr);
   void SetStart(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr);
+  void SetStart(const RawRangeBoundary& aPoint, ErrorResult& aErr);
   void SetStartAfter(nsINode& aNode, ErrorResult& aErr);
   void SetStartBefore(nsINode& aNode, ErrorResult& aErr);
 
   static void GetInnerTextNoFlush(mozilla::dom::DOMString& aValue,
                                   mozilla::ErrorResult& aError,
                                   nsIContent* aStartContainer,
                                   uint32_t aStartOffset,
                                   nsIContent* aEndContainer,
@@ -464,26 +488,16 @@ protected:
   // 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(const RawRangeBoundary& lowerBound,
                   const RawRangeBoundary& upperBound,
                   nsINode* aRoot, bool aNotInsertedYet = false);
 
-  void DoSetRange(nsINode* aStartContainer, uint32_t aStartOffset,
-                  nsINode* aEndContainer, uint32_t aEndOffset,
-                  nsINode* aRoot, bool aNotInsertedYet = false)
-  {
-    RawRangeBoundary start(aStartContainer, aStartOffset);
-    RawRangeBoundary end(aEndContainer, aEndOffset);
-
-    DoSetRange(start, end, aRoot, aNotInsertedYet);
-  }
-
   /**
    * For a range for which IsInSelection() is true, return the common ancestor
    * for the range, which we had to compute when the common ancestor changed or
    * IsInSelection became true, so we could register with it.  That is, it's a
    * faster version of GetCommonAncestor that only works for ranges in a
    * Selection.  The method will assert and the behavior is undefined if called
    * on a range where IsInSelection() is false.
    */
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -6111,18 +6111,20 @@ HTMLEditRules::GetNodesForOperation(
         if (NS_WARN_IF(error.Failed())) {
           return error.StealNSResult();
         }
 
         // Correct the range.
         // The new end parent becomes the parent node of the text.
         // XXX We want nsRange::SetEnd(const RawRangeBoundary&)
         EditorRawDOMPoint atContainerOfSplitNode(atEnd.Container());
-        range->SetEnd(atContainerOfSplitNode.Container(),
-                      atContainerOfSplitNode.Offset());
+        range->SetEnd(atContainerOfSplitNode, error);
+        if (NS_WARN_IF(error.Failed())) {
+          error.SuppressException();
+        }
       }
     }
   }
 
   // Bust up any inlines that cross our range endpoints, but only if we are
   // allowed to touch content.
 
   if (aTouchContent == TouchContent::yes) {
@@ -6609,18 +6611,21 @@ HTMLEditRules::GetNodesFromPoint(
                  EditAction aOperation,
                  nsTArray<OwningNonNull<nsINode>>& outArrayOfNodes,
                  TouchContent aTouchContent)
 {
   if (NS_WARN_IF(!aPoint.IsSet())) {
     return NS_ERROR_INVALID_ARG;
   }
   RefPtr<nsRange> range = new nsRange(aPoint.Container());
-  DebugOnly<nsresult> rv = range->SetStart(aPoint.Container(), aPoint.Offset());
-  MOZ_ASSERT(NS_SUCCEEDED(rv));
+  IgnoredErrorResult error;
+  range->SetStart(aPoint, error);
+  if (NS_WARN_IF(error.Failed())) {
+    MOZ_ASSERT(!error.Failed());
+  }
 
   // Expand the range to include adjacent inlines
   PromoteRange(*range, aOperation);
 
   // Make array of ranges
   nsTArray<RefPtr<nsRange>> arrayOfRanges;
 
   // Stuff new opRange into array
@@ -8635,26 +8640,29 @@ HTMLEditRules::ConfirmSelectionInBody()
   }
 
   return NS_OK;
 }
 
 nsresult
 HTMLEditRules::UpdateDocChangeRange(nsRange* aRange)
 {
+  if (NS_WARN_IF(!mHTMLEditor)) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
   // first make sure aRange is in the document.  It might not be if
   // portions of our editting action involved manipulating nodes
   // prior to placing them in the document (e.g., populating a list item
   // before placing it in its list)
-  nsCOMPtr<nsINode> startNode = aRange->GetStartContainer();
-  if (NS_WARN_IF(!startNode)) {
+  const RangeBoundary& atStart = aRange->StartRef();
+  if (NS_WARN_IF(!atStart.IsSet())) {
     return NS_ERROR_FAILURE;
   }
-  NS_ENSURE_STATE(mHTMLEditor);
-  if (!mHTMLEditor->IsDescendantOfRoot(startNode)) {
+  if (!mHTMLEditor->IsDescendantOfRoot(atStart.Container())) {
     // just return - we don't need to adjust mDocChangeRange in this case
     return NS_OK;
   }
 
   if (!mDocChangeRange) {
     // clone aRange.
     mDocChangeRange = aRange->CloneRange();
   } else {
@@ -8670,32 +8678,38 @@ HTMLEditRules::UpdateDocChangeRange(nsRa
       // The same test won't be needed further down since after we've set
       // the start the range will be collapsed to that point.
       result = 1;
       rv = NS_OK;
     }
     NS_ENSURE_SUCCESS(rv, rv);
     // Positive result means mDocChangeRange start is after aRange start.
     if (result > 0) {
-      rv = mDocChangeRange->SetStart(startNode, aRange->StartOffset());
-      NS_ENSURE_SUCCESS(rv, rv);
+      ErrorResult error;
+      mDocChangeRange->SetStart(atStart.AsRaw(), error);
+      if (NS_WARN_IF(error.Failed())) {
+        return error.StealNSResult();
+      }
     }
 
     // compare ends of ranges
     rv = mDocChangeRange->CompareBoundaryPoints(nsIDOMRange::END_TO_END,
                                                 aRange, &result);
     NS_ENSURE_SUCCESS(rv, rv);
     // Negative result means mDocChangeRange end is before aRange end.
     if (result < 0) {
-      nsINode* endNode = aRange->GetEndContainer();
-      if (NS_WARN_IF(!endNode)) {
+      const RangeBoundary& atEnd = aRange->EndRef();
+      if (NS_WARN_IF(!atEnd.IsSet())) {
         return NS_ERROR_FAILURE;
       }
-      rv = mDocChangeRange->SetEnd(endNode, aRange->EndOffset());
-      NS_ENSURE_SUCCESS(rv, rv);
+      ErrorResult error;
+      mDocChangeRange->SetEnd(atEnd.AsRaw(), error);
+      if (NS_WARN_IF(error.Failed())) {
+        return error.StealNSResult();
+      }
     }
   }
   return NS_OK;
 }
 
 nsresult
 HTMLEditRules::InsertBRIfNeededInternal(nsINode& aNode,
                                         bool aInsertMozBR)