Bug 1415445 - part 4: EditorBase::CreateNode() should take EditorRawDOMPoint as insertion point instead of a set of container, child and offset of the child in the container r=m_kato
authorMasayuki Nakano <masayuki@d-toybox.com>
Wed, 08 Nov 2017 20:23:10 +0900
changeset 435636 4be8afd896458fae76dc2eacf813a5eaa26db483
parent 435635 57ed7f0422124ea09e45dd8df7c14d4a0bc689f6
child 435637 c58e3a20c6f151a1f45c593bf0b342cd9262d98c
push id117
push userfmarier@mozilla.com
push dateTue, 28 Nov 2017 20:17:16 +0000
reviewersm_kato
bugs1415445
milestone58.0a1
Bug 1415445 - part 4: EditorBase::CreateNode() should take EditorRawDOMPoint as insertion point instead of a set of container, child and offset of the child in the container r=m_kato EditorBase::CreateNode() should take EditorRawDOMPoint as insertion point of the new element instead of a set of container, child and offset of the child in the container. This patch initializes EditorRawDOMPoint with original 3 arguments as far as possible. If the relation of them are broken, MOZ_ASSERT in RawRangeBoundary constructor detects existing bugs. MozReview-Commit-ID: 2N55S6pRv7k
dom/base/RangeBoundary.h
editor/libeditor/EditorBase.cpp
editor/libeditor/EditorBase.h
editor/libeditor/EditorDOMPoint.h
editor/libeditor/HTMLEditRules.cpp
editor/libeditor/HTMLEditor.cpp
editor/libeditor/TextEditor.cpp
--- a/dom/base/RangeBoundary.h
+++ b/dom/base/RangeBoundary.h
@@ -82,20 +82,21 @@ protected:
   RangeBoundaryBase(nsINode* aContainer, nsIContent* aRef, int32_t aOffset)
     : mParent(aContainer)
     , mRef(aRef)
     , mOffset(mozilla::Some(aOffset))
   {
     MOZ_RELEASE_ASSERT(aContainer,
       "This constructor shouldn't be used when pointing nowhere");
     if (!mRef) {
-      MOZ_ASSERT(mOffset.value() == 0);
+      MOZ_ASSERT(!mParent->IsContainerNode() || mOffset.value() == 0);
       return;
     }
     MOZ_ASSERT(mOffset.value() > 0);
+    MOZ_ASSERT(mParent == mRef->GetParentNode());
     MOZ_ASSERT(mParent->GetChildAt(mOffset.value() - 1) == mRef);
   }
 
 public:
   RangeBoundaryBase()
     : mParent(nullptr)
     , mRef(nullptr)
   {
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -1414,56 +1414,51 @@ EditorBase::SetSpellcheckUserOverride(bo
 {
   mSpellcheckCheckboxState = enable ? eTriTrue : eTriFalse;
 
   return SyncRealTimeSpell();
 }
 
 already_AddRefed<Element>
 EditorBase::CreateNode(nsAtom* aTag,
-                       nsINode* aParent,
-                       int32_t aPosition,
-                       nsIContent* aChildAtPosition)
-{
-  MOZ_ASSERT(aTag && aParent);
-
-  EditorRawDOMPoint pointToInsert;
-  if (aPosition == -1) {
-    pointToInsert.Set(aParent, aParent->Length());
-  } else if (aChildAtPosition) {
-    pointToInsert.Set(aChildAtPosition);
-  } else {
-    pointToInsert.Set(aParent, aPosition);
-  }
+                       EditorRawDOMPoint& aPointToInsert)
+{
+  MOZ_ASSERT(aTag);
+  MOZ_ASSERT(aPointToInsert.IsSetAndValid());
+
   // XXX We need to offset at new node to mRangeUpdater.  Therefore, we need
   //     to compute the offset now but this is expensive.  So, if it's possible,
   //     we need to redesign mRangeUpdater as avoiding using indices.
-  int32_t offset = static_cast<int32_t>(pointToInsert.Offset());
+  int32_t offset = static_cast<int32_t>(aPointToInsert.Offset());
 
   AutoRules beginRulesSniffing(this, EditAction::createNode, nsIEditor::eNext);
 
   {
     AutoActionListenerArray listeners(mActionListeners);
     for (auto& listener : listeners) {
       listener->WillCreateNode(nsDependentAtomString(aTag),
-                               GetAsDOMNode(pointToInsert.GetChildAtOffset()));
+                               GetAsDOMNode(aPointToInsert.GetChildAtOffset()));
     }
   }
 
   nsCOMPtr<Element> ret;
 
   RefPtr<CreateElementTransaction> transaction =
-    CreateTxnForCreateElement(*aTag, pointToInsert);
+    CreateTxnForCreateElement(*aTag, aPointToInsert);
   nsresult rv = DoTransaction(transaction);
   if (NS_SUCCEEDED(rv)) {
     ret = transaction->GetNewNode();
     MOZ_ASSERT(ret);
-  }
-
-  mRangeUpdater.SelAdjCreateNode(pointToInsert.Container(), offset);
+    // Now, aPointToInsert may be invalid.  I.e., ChildAtOffset() keeps
+    // referring the next sibling of new node but Offset() refers the
+    // new node.  Let's make refer the new node.
+    aPointToInsert.Set(ret);
+  }
+
+  mRangeUpdater.SelAdjCreateNode(aPointToInsert.Container(), offset);
 
   {
     AutoActionListenerArray listeners(mActionListeners);
     for (auto& listener : listeners) {
       listener->DidCreateNode(nsDependentAtomString(aTag),
                               GetAsDOMNode(ret), rv);
     }
   }
@@ -4221,26 +4216,39 @@ already_AddRefed<Element>
 EditorBase::DeleteSelectionAndCreateElement(nsAtom& aTag)
 {
   nsresult rv = DeleteSelectionAndPrepareToCreateNode();
   NS_ENSURE_SUCCESS(rv, nullptr);
 
   RefPtr<Selection> selection = GetSelection();
   NS_ENSURE_TRUE(selection, nullptr);
 
-  nsCOMPtr<nsINode> node = selection->GetAnchorNode();
-  uint32_t offset = selection->AnchorOffset();
-  nsIContent* child = selection->GetChildAtAnchorOffset();
-
-  nsCOMPtr<Element> newElement = CreateNode(&aTag, node, offset, child);
+  EditorRawDOMPoint pointToInsert(selection->GetChildAtAnchorOffset());
+  if (!pointToInsert.IsSet()) {
+    // Perhaps, the anchor point is in a text node.
+    pointToInsert.Set(selection->GetAnchorNode(), selection->AnchorOffset());
+    if (NS_WARN_IF(!pointToInsert.IsSet())) {
+      return nullptr;
+    }
+  }
+  RefPtr<Element> newElement = CreateNode(&aTag, pointToInsert);
 
   // We want the selection to be just after the new node
-  rv = selection->Collapse(node, offset + 1);
-  NS_ENSURE_SUCCESS(rv, nullptr);
-
+  DebugOnly<bool> advanced = pointToInsert.AdvanceOffset();
+  NS_WARNING_ASSERTION(advanced,
+                       "Failed to move offset next to the new element");
+  ErrorResult error;
+  selection->Collapse(pointToInsert, error);
+  if (NS_WARN_IF(error.Failed())) {
+    // XXX Even if it succeeded to create new element, this returns error
+    //     when Selection.Collapse() fails something.  This could occur with
+    //     mutation observer or mutation event listener.
+    error.SuppressException();
+    return nullptr;
+  }
   return newElement.forget();
 }
 
 TextComposition*
 EditorBase::GetComposition() const
 {
   return mComposition;
 }
--- a/editor/libeditor/EditorBase.h
+++ b/editor/libeditor/EditorBase.h
@@ -405,19 +405,33 @@ protected:
    *                        child node referred by this.
    * @return                A CreateElementTransaction which are initialized
    *                        with the arguments.
    */
   already_AddRefed<CreateElementTransaction>
     CreateTxnForCreateElement(nsAtom& aTag,
                               const EditorRawDOMPoint& aPointToInsert);
 
-  already_AddRefed<Element> CreateNode(nsAtom* aTag, nsINode* aParent,
-                                       int32_t aPosition,
-                                       nsIContent* aChildAtPosition = nullptr);
+  /**
+   * Create an element node whose name is aTag at before aPointToInsert.  When
+   * this succeed to create an element node, this sets aPointToInsert to the
+   * new element because the relation of child and offset may be broken.
+   * If the caller needs to collapse the selection to next to the new element
+   * node, it should call |aPointToInsert.AdvanceOffset()| after calling this.
+   *
+   * @param aTag            The element name to create.
+   * @param aPointToInsert  The insertion point of new element.  If this refers
+   *                        end of the container or after, the transaction
+   *                        will append the element to the container.
+   *                        Otherwise, will insert the element before the
+   *                        child node referred by this.
+   * @return                The created new element node.
+   */
+  already_AddRefed<Element> CreateNode(nsAtom* aTag,
+                                       EditorRawDOMPoint& aPointToInsert);
 
   /**
    * Create a transaction for inserting aNode as a child of aParent.
    */
   already_AddRefed<InsertNodeTransaction>
     CreateTxnForInsertNode(nsIContent& aNode, nsINode& aParent,
                            int32_t aOffset);
 
--- a/editor/libeditor/EditorDOMPoint.h
+++ b/editor/libeditor/EditorDOMPoint.h
@@ -54,43 +54,52 @@ public:
    * 0 - Length() - 1.  Otherwise, set nullptr, i.e., if offset is same as
    * Length().
    */
   explicit EditorDOMPointBase(nsINode* aPointedNode)
     : RangeBoundaryBase<ParentType, RefType>(
         aPointedNode && aPointedNode->IsContent() ?
           aPointedNode->GetParentNode() : nullptr,
         aPointedNode && aPointedNode->IsContent() ?
-          GetRef(aPointedNode->AsContent()) : nullptr)
+          GetRef(aPointedNode->GetParentNode(),
+                 aPointedNode->AsContent()) : nullptr)
   {
   }
 
-  EditorDOMPointBase(nsINode* aConatiner,
+  EditorDOMPointBase(nsINode* aContainer,
                      nsIContent* aPointedNode,
                      int32_t aOffset)
-    : RangeBoundaryBase<ParentType, RefType>(aConatiner,
-                                             GetRef(aPointedNode),
+    : RangeBoundaryBase<ParentType, RefType>(aContainer,
+                                             GetRef(aContainer, aPointedNode),
                                              aOffset)
   {
   }
 
   template<typename PT, typename RT>
   explicit EditorDOMPointBase(const RangeBoundaryBase<PT, RT>& aOther)
     : RangeBoundaryBase<ParentType, RefType>(aOther)
   {
   }
 
   explicit EditorDOMPointBase(const RawRangeBoundary& aRawRangeBoundary)
     : RangeBoundaryBase<ParentType, RefType>(aRawRangeBoundary)
   {
   }
 
 private:
-  static nsIContent* GetRef(nsIContent* aPointedNode)
+  static nsIContent* GetRef(nsINode* aContainerNode, nsIContent* aPointedNode)
   {
-    MOZ_ASSERT(aPointedNode);
-    return aPointedNode ? aPointedNode->GetPreviousSibling() : nullptr;
+    // If referring one of a child of the container, the 'ref' should be the
+    // previous sibling of the referring child.
+    if (aPointedNode) {
+      return aPointedNode->GetPreviousSibling();
+    }
+    // If referring after the last child, the 'ref' should be the last child.
+    if (aContainerNode && aContainerNode->IsContainerNode()) {
+      return aContainerNode->GetLastChild();
+    }
+    return nullptr;
   }
 };
 
 } // namespace mozilla
 
 #endif // #ifndef mozilla_EditorDOMPoint_h
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -3391,33 +3391,39 @@ HTMLEditRules::WillMakeList(Selection* a
     if (!mHTMLEditor->CanContainTag(*container, listType)) {
       *aCancel = true;
       return NS_OK;
     }
     rv = SplitAsNeeded(listType, container, offset,
                        address_of(child));
     NS_ENSURE_SUCCESS(rv, rv);
     NS_ENSURE_STATE(mHTMLEditor);
-    nsCOMPtr<Element> theList =
-      mHTMLEditor->CreateNode(listType, container, offset, child);
+    EditorRawDOMPoint atListItemToInsertBefore(container, child, offset);
+    RefPtr<Element> theList =
+      mHTMLEditor->CreateNode(listType, atListItemToInsertBefore);
     NS_ENSURE_STATE(theList);
 
     NS_ENSURE_STATE(mHTMLEditor);
-    nsCOMPtr<Element> theListItem =
-      mHTMLEditor->CreateNode(itemType, theList, 0, theList->GetFirstChild());
+    EditorRawDOMPoint atFirstListItemToInsertBefore(theList, 0);
+    RefPtr<Element> theListItem =
+      mHTMLEditor->CreateNode(itemType, atFirstListItemToInsertBefore);
     NS_ENSURE_STATE(theListItem);
 
     // remember our new block for postprocessing
     mNewBlock = theListItem;
     // put selection in new list item
     *aHandled = true;
-    rv = aSelection->Collapse(theListItem, 0);
+    ErrorResult error;
+    aSelection->Collapse(EditorRawDOMPoint(theListItem, 0), error);
     // Don't restore the selection
     selectionRestorer.Abort();
-    return rv;
+    if (NS_WARN_IF(!error.Failed())) {
+      return error.StealNSResult();
+    }
+    return NS_OK;
   }
 
   // if there is only one node in the array, and it is a list, div, or
   // blockquote, then look inside of it until we find inner list or content.
 
   LookInsideDivBQandList(arrayOfNodes);
 
   // Ok, now go through all the nodes and put then in the list,
@@ -3493,23 +3499,19 @@ HTMLEditRules::WillMakeList(Selection* a
         if (!curList || EditorUtils::IsDescendantOf(*curNode, *curList)) {
           NS_ENSURE_STATE(mHTMLEditor);
           NS_ENSURE_STATE(curParent->IsContent());
           ErrorResult rv;
           nsCOMPtr<nsIContent> splitNode =
             mHTMLEditor->SplitNode(*curParent->AsContent(), offset, rv);
           NS_ENSURE_TRUE(!rv.Failed(), rv.StealNSResult());
           newBlock = splitNode ? splitNode->AsElement() : nullptr;
-          int32_t offset;
-          nsCOMPtr<nsINode> parent = EditorBase::GetNodeLocation(curParent,
-                                                                 &offset);
           NS_ENSURE_STATE(mHTMLEditor);
-          curList = mHTMLEditor->CreateNode(listType, parent, offset,
-                                            curParent ? curParent->AsContent()
-                                                      : nullptr);
+          EditorRawDOMPoint atCurParent(curParent);
+          curList = mHTMLEditor->CreateNode(listType, atCurParent);
           NS_ENSURE_STATE(curList);
         }
         // move list item to new list
         NS_ENSURE_STATE(mHTMLEditor);
         rv = mHTMLEditor->MoveNode(curNode, curList, -1);
         NS_ENSURE_SUCCESS(rv, rv);
         // convert list item type if needed
         NS_ENSURE_STATE(mHTMLEditor);
@@ -3570,18 +3572,18 @@ HTMLEditRules::WillMakeList(Selection* a
 
     // need to make a list to put things in if we haven't already,
     if (!curList) {
       nsCOMPtr<nsIContent> curChild(curNode);
       rv = SplitAsNeeded(listType, curParent, offset,
                          address_of(curChild));
       NS_ENSURE_SUCCESS(rv, rv);
       NS_ENSURE_STATE(mHTMLEditor);
-      curList = mHTMLEditor->CreateNode(listType, curParent, offset,
-                                        curChild);
+      EditorRawDOMPoint atCurChild(curParent, curChild, offset);
+      curList = mHTMLEditor->CreateNode(listType, atCurChild);
       // remember our new block for postprocessing
       mNewBlock = curList;
       // curList is now the correct thing to put curNode in
       prevListItem = nullptr;
     }
 
     // if curNode isn't a list item, we must wrap it in one
     nsCOMPtr<Element> listItem;
@@ -3776,23 +3778,25 @@ HTMLEditRules::MakeBasicBlock(Selection&
       // We are making a block.  Consume a br, if needed.
       nsCOMPtr<nsIContent> brNode =
         htmlEditor->GetNextHTMLNode(container, offset, child, true);
       if (brNode && brNode->IsHTMLElement(nsGkAtoms::br)) {
         rv = htmlEditor->DeleteNode(brNode);
         NS_ENSURE_SUCCESS(rv, rv);
         // We don't need to act on this node any more
         arrayOfNodes.RemoveElement(brNode);
-        child = nullptr;
+        // XXX We need to recompute child here because SplitAsNeeded() and
+        //     EditorBase::SplitNodeDeep() don't compute child in some cases.
+        child = container->GetChildAt(offset);
       }
       // Make sure we can put a block here
       rv = SplitAsNeeded(blockType, container, offset, address_of(child));
       NS_ENSURE_SUCCESS(rv, rv);
-      nsCOMPtr<Element> block =
-        htmlEditor->CreateNode(&blockType, container, offset, child);
+      EditorRawDOMPoint atChild(container, child, offset);
+      RefPtr<Element> block = htmlEditor->CreateNode(&blockType, atChild);
       NS_ENSURE_STATE(block);
       // Remember our new block for postprocessing
       mNewBlock = block;
       // Delete anything that was in the list of nodes
       while (!arrayOfNodes.IsEmpty()) {
         OwningNonNull<nsINode> curNode = arrayOfNodes[0];
         rv = htmlEditor->DeleteNode(curNode);
         NS_ENSURE_SUCCESS(rv, rv);
@@ -3923,37 +3927,42 @@ HTMLEditRules::WillCSSIndent(Selection* 
     NS_ENSURE_STATE(container);
     nsCOMPtr<nsIContent> child =
       aSelection->GetRangeAt(0)->GetChildAtStartOffset();
 
     // make sure we can put a block here
     rv = SplitAsNeeded(*nsGkAtoms::div, container, offset, address_of(child));
     NS_ENSURE_SUCCESS(rv, rv);
     NS_ENSURE_STATE(mHTMLEditor);
-    nsCOMPtr<Element> theBlock = mHTMLEditor->CreateNode(nsGkAtoms::div,
-                                                         container, offset,
-                                                         child);
+    EditorRawDOMPoint atChild(container, child, offset);
+    RefPtr<Element> theBlock =
+      mHTMLEditor->CreateNode(nsGkAtoms::div, atChild);
     NS_ENSURE_STATE(theBlock);
     // remember our new block for postprocessing
     mNewBlock = theBlock;
     ChangeIndentation(*theBlock, Change::plus);
     // delete anything that was in the list of nodes
     while (!arrayOfNodes.IsEmpty()) {
       OwningNonNull<nsINode> curNode = arrayOfNodes[0];
       NS_ENSURE_STATE(mHTMLEditor);
       rv = mHTMLEditor->DeleteNode(curNode);
       NS_ENSURE_SUCCESS(rv, rv);
       arrayOfNodes.RemoveElementAt(0);
     }
     // put selection in new block
     *aHandled = true;
-    rv = aSelection->Collapse(theBlock, 0);
+    EditorRawDOMPoint atStartOfTheBlock(theBlock, 0);
+    ErrorResult error;
+    aSelection->Collapse(atStartOfTheBlock, error);
     // Don't restore the selection
     selectionRestorer.Abort();
-    return rv;
+    if (NS_WARN_IF(!error.Failed())) {
+      return error.StealNSResult();
+    }
+    return NS_OK;
   }
 
   // Ok, now go through all the nodes and put them in a blockquote,
   // or whatever is appropriate.  Wohoo!
   nsCOMPtr<Element> curList, curQuote;
   nsCOMPtr<nsIContent> sibling;
   int32_t listCount = arrayOfNodes.Length();
   for (int32_t i = 0; i < listCount; i++) {
@@ -4020,18 +4029,19 @@ HTMLEditRules::WillCSSIndent(Selection* 
       if (!curList || (sibling && sibling != curList)) {
         // create a new nested list of correct type
         nsCOMPtr<nsIContent> curChild(curNode);
         rv =
           SplitAsNeeded(*curParent->NodeInfo()->NameAtom(), curParent, offset,
                         address_of(curChild));
         NS_ENSURE_SUCCESS(rv, rv);
         NS_ENSURE_STATE(mHTMLEditor);
+        EditorRawDOMPoint atCurChild(curParent, curChild, offset);
         curList = mHTMLEditor->CreateNode(curParent->NodeInfo()->NameAtom(),
-                                          curParent, offset, curChild);
+                                          atCurChild);
         NS_ENSURE_STATE(curList);
         // curList is now the correct thing to put curNode in
         // remember our new block for postprocessing
         mNewBlock = curList;
       }
       // tuck the node into the end of the active list
       uint32_t listLen = curList->Length();
       NS_ENSURE_STATE(mHTMLEditor);
@@ -4053,18 +4063,18 @@ HTMLEditRules::WillCSSIndent(Selection* 
             return NS_OK; // cancelled
           }
 
           nsCOMPtr<nsIContent> curChild(curNode);
           rv = SplitAsNeeded(*nsGkAtoms::div, curParent, offset,
                              address_of(curChild));
           NS_ENSURE_SUCCESS(rv, rv);
           NS_ENSURE_STATE(mHTMLEditor);
-          curQuote = mHTMLEditor->CreateNode(nsGkAtoms::div, curParent,
-                                             offset, curChild);
+          EditorRawDOMPoint atCurChild(curParent, curChild, offset);
+          curQuote = mHTMLEditor->CreateNode(nsGkAtoms::div, atCurChild);
           NS_ENSURE_STATE(curQuote);
           ChangeIndentation(*curQuote, Change::plus);
           // remember our new block for postprocessing
           mNewBlock = curQuote;
           // curQuote is now the correct thing to put curNode in
         }
 
         // tuck the node into the end of the active blockquote
@@ -4122,36 +4132,41 @@ HTMLEditRules::WillHTMLIndent(Selection*
     nsCOMPtr<nsIContent> child =
       aSelection->GetRangeAt(0)->GetChildAtStartOffset();
 
     // make sure we can put a block here
     rv = SplitAsNeeded(*nsGkAtoms::blockquote, container, offset,
                        address_of(child));
     NS_ENSURE_SUCCESS(rv, rv);
     NS_ENSURE_STATE(mHTMLEditor);
-    nsCOMPtr<Element> theBlock = mHTMLEditor->CreateNode(nsGkAtoms::blockquote,
-                                                         container, offset,
-                                                         child);
+    EditorRawDOMPoint atChild(container, child, offset);
+    RefPtr<Element> theBlock =
+      mHTMLEditor->CreateNode(nsGkAtoms::blockquote, atChild);
     NS_ENSURE_STATE(theBlock);
     // remember our new block for postprocessing
     mNewBlock = theBlock;
     // delete anything that was in the list of nodes
     while (!arrayOfNodes.IsEmpty()) {
       OwningNonNull<nsINode> curNode = arrayOfNodes[0];
       NS_ENSURE_STATE(mHTMLEditor);
       rv = mHTMLEditor->DeleteNode(curNode);
       NS_ENSURE_SUCCESS(rv, rv);
       arrayOfNodes.RemoveElementAt(0);
     }
     // put selection in new block
     *aHandled = true;
-    rv = aSelection->Collapse(theBlock, 0);
+    EditorRawDOMPoint atStartOfTheBlock(theBlock, 0);
+    ErrorResult error;
+    aSelection->Collapse(atStartOfTheBlock, error);
     // Don't restore the selection
     selectionRestorer.Abort();
-    return rv;
+    if (NS_WARN_IF(!error.Failed())) {
+      return error.StealNSResult();
+    }
+    return NS_OK;
   }
 
   // Ok, now go through all the nodes and put them in a blockquote,
   // or whatever is appropriate.  Wohoo!
   nsCOMPtr<nsIContent> sibling;
   nsCOMPtr<Element> curList, curQuote, indentedLI;
   int32_t listCount = arrayOfNodes.Length();
   for (int32_t i = 0; i < listCount; i++) {
@@ -4219,18 +4234,19 @@ HTMLEditRules::WillHTMLIndent(Selection*
       if (!curList || (sibling && sibling != curList)) {
         // create a new nested list of correct type
         nsCOMPtr<nsIContent> curChild(curNode);
         rv =
           SplitAsNeeded(*curParent->NodeInfo()->NameAtom(), curParent, offset,
                         address_of(curChild));
         NS_ENSURE_SUCCESS(rv, rv);
         NS_ENSURE_STATE(mHTMLEditor);
+        EditorRawDOMPoint atCurChild(curParent, curChild, offset);
         curList = mHTMLEditor->CreateNode(curParent->NodeInfo()->NameAtom(),
-                                          curParent, offset, curChild);
+                                          atCurChild);
         NS_ENSURE_STATE(curList);
         // curList is now the correct thing to put curNode in
         // remember our new block for postprocessing
         mNewBlock = curList;
       }
       // tuck the node into the end of the active list
       NS_ENSURE_STATE(mHTMLEditor);
       rv = mHTMLEditor->MoveNode(curNode, curList, -1);
@@ -4264,18 +4280,19 @@ HTMLEditRules::WillHTMLIndent(Selection*
 
         if (!curList || (sibling && sibling != curList)) {
           // create a new nested list of correct type
           nsCOMPtr<nsIContent> curChild(listItem);
           rv = SplitAsNeeded(*curParent->NodeInfo()->NameAtom(), curParent,
                              offset, address_of(curChild));
           NS_ENSURE_SUCCESS(rv, rv);
           NS_ENSURE_STATE(mHTMLEditor);
+          EditorRawDOMPoint atCurChild(curParent, curChild, offset);
           curList = mHTMLEditor->CreateNode(curParent->NodeInfo()->NameAtom(),
-                                            curParent, offset, curChild);
+                                            atCurChild);
           NS_ENSURE_STATE(curList);
         }
         NS_ENSURE_STATE(mHTMLEditor);
         rv = mHTMLEditor->MoveNode(listItem, curList, -1);
         NS_ENSURE_SUCCESS(rv, rv);
         // remember we indented this li
         indentedLI = listItem;
       } else {
@@ -4296,18 +4313,18 @@ HTMLEditRules::WillHTMLIndent(Selection*
             return NS_OK; // cancelled
           }
 
           nsCOMPtr<nsIContent> curChild(curNode);
           rv = SplitAsNeeded(*nsGkAtoms::blockquote, curParent, offset,
                              address_of(curChild));
           NS_ENSURE_SUCCESS(rv, rv);
           NS_ENSURE_STATE(mHTMLEditor);
-          curQuote = mHTMLEditor->CreateNode(nsGkAtoms::blockquote, curParent,
-                                             offset, curChild);
+          EditorRawDOMPoint atCurChild(curParent, curChild, offset);
+          curQuote = mHTMLEditor->CreateNode(nsGkAtoms::blockquote, atCurChild);
           NS_ENSURE_STATE(curQuote);
           // remember our new block for postprocessing
           mNewBlock = curQuote;
           // curQuote is now the correct thing to put curNode in
         }
 
         // tuck the node into the end of the active blockquote
         NS_ENSURE_STATE(mHTMLEditor);
@@ -4911,32 +4928,36 @@ HTMLEditRules::WillAlign(Selection& aSel
       if (child) {
         sibling = htmlEditor->GetNextHTMLSibling(child);
       }
       if (sibling && !IsBlockNode(*sibling)) {
         rv = htmlEditor->DeleteNode(brContent);
         NS_ENSURE_SUCCESS(rv, rv);
       }
     }
-    nsCOMPtr<Element> div = htmlEditor->CreateNode(nsGkAtoms::div, parent,
-                                                   offset, child);
+    EditorRawDOMPoint atChild(parent, child, offset);
+    RefPtr<Element> div = htmlEditor->CreateNode(nsGkAtoms::div, atChild);
     NS_ENSURE_STATE(div);
     // Remember our new block for postprocessing
     mNewBlock = div;
     // Set up the alignment on the div, using HTML or CSS
     rv = AlignBlock(*div, aAlignType, ContentsOnly::yes);
     NS_ENSURE_SUCCESS(rv, rv);
     *aHandled = true;
     // Put in a moz-br so that it won't get deleted
     rv = CreateMozBR(div->AsDOMNode(), 0);
     NS_ENSURE_SUCCESS(rv, rv);
-    rv = aSelection.Collapse(div, 0);
+    EditorRawDOMPoint atStartOfDiv(div, 0);
+    ErrorResult error;
+    aSelection.Collapse(atStartOfDiv, error);
     // Don't restore the selection
     selectionRestorer.Abort();
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (NS_WARN_IF(error.Failed())) {
+      return error.StealNSResult();
+    }
     return NS_OK;
   }
 
   // Next we detect all the transitions in the array, where a transition
   // means that adjacent nodes in the array don't have the same parent.
 
   nsTArray<bool> transitionList;
   MakeTransitionList(nodeArray, transitionList);
@@ -5017,18 +5038,18 @@ HTMLEditRules::WillAlign(Selection& aSel
         // Cancelled
         return NS_OK;
       }
 
       nsCOMPtr<nsIContent> curChild(curNode->AsContent());
       rv = SplitAsNeeded(*nsGkAtoms::div, curParent, offset,
                          address_of(curChild));
       NS_ENSURE_SUCCESS(rv, rv);
-      curDiv = htmlEditor->CreateNode(nsGkAtoms::div, curParent, offset,
-                                      curChild);
+      EditorRawDOMPoint atCurChild(curParent, curChild, offset);
+      curDiv = htmlEditor->CreateNode(nsGkAtoms::div, atCurChild);
       NS_ENSURE_STATE(curDiv);
       // Remember our new block for postprocessing
       mNewBlock = curDiv;
       // Set up the alignment on the div
       rv = AlignBlock(*curDiv, aAlignType, ContentsOnly::yes);
     }
 
     NS_ENSURE_STATE(curNode->IsContent());
@@ -5094,18 +5115,19 @@ HTMLEditRules::AlignBlockContents(nsIDOM
                                                         nsGkAtoms::align,
                                                         *alignType, false);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   } else {
     // else we need to put in a div, set the alignment, and toss in all the children
     NS_ENSURE_STATE(mHTMLEditor);
-    RefPtr<Element> divElem = mHTMLEditor->CreateNode(nsGkAtoms::div, node, 0,
-                                                      node->GetFirstChild());
+    EditorRawDOMPoint atStartOfNode(node, 0);
+    RefPtr<Element> divElem =
+      mHTMLEditor->CreateNode(nsGkAtoms::div, atStartOfNode);
     NS_ENSURE_STATE(divElem);
     // set up the alignment on the div
     NS_ENSURE_STATE(mHTMLEditor);
     nsresult rv =
       mHTMLEditor->SetAttributeOrEquivalent(divElem, nsGkAtoms::align,
                                             *alignType, false);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
@@ -6613,20 +6635,21 @@ HTMLEditRules::ReturnInHeader(Selection&
     }
     if (!sibling || !sibling->IsHTMLElement(nsGkAtoms::br)) {
       ClearCachedStyles();
       htmlEditor->mTypeInState->ClearAllProps();
 
       // Create a paragraph
       nsAtom& paraAtom = DefaultParagraphSeparator();
       // We want a wrapper element even if we separate with <br>
-      nsCOMPtr<Element> pNode =
-        htmlEditor->CreateNode(&paraAtom == nsGkAtoms::br ? nsGkAtoms::p
-                                                           : &paraAtom,
-                                headerParent, offset + 1);
+      EditorRawDOMPoint nextToHeader(headerParent, offset + 1);
+      RefPtr<Element> pNode =
+        htmlEditor->CreateNode(&paraAtom == nsGkAtoms::br ?
+                                 nsGkAtoms::p : &paraAtom,
+                               nextToHeader);
       NS_ENSURE_STATE(pNode);
 
       // Append a <br> to it
       nsCOMPtr<Element> brNode = htmlEditor->CreateBR(pNode, 0);
       NS_ENSURE_STATE(brNode);
 
       // Set selection to before the break
       rv = aSelection.Collapse(pNode, 0);
@@ -6894,20 +6917,21 @@ HTMLEditRules::ReturnInListItem(Selectio
     } else {
       // Otherwise kill this item
       rv = htmlEditor->DeleteNode(&aListItem);
       NS_ENSURE_SUCCESS(rv, rv);
 
       // Time to insert a paragraph
       nsAtom& paraAtom = DefaultParagraphSeparator();
       // We want a wrapper even if we separate with <br>
-      nsCOMPtr<Element> pNode =
-        htmlEditor->CreateNode(&paraAtom == nsGkAtoms::br ? nsGkAtoms::p
-                                                           : &paraAtom,
-                                listParent, offset + 1);
+      EditorRawDOMPoint atNextListItem(listParent, offset + 1);
+      RefPtr<Element> pNode =
+        htmlEditor->CreateNode(&paraAtom == nsGkAtoms::br ?
+                                 nsGkAtoms::p : &paraAtom,
+                               atNextListItem);
       NS_ENSURE_STATE(pNode);
 
       // Append a <br> to it
       nsCOMPtr<Element> brNode = htmlEditor->CreateBR(pNode, 0);
       NS_ENSURE_STATE(brNode);
 
       // Set selection to before the break
       rv = aSelection.Collapse(pNode, 0);
@@ -6943,19 +6967,21 @@ HTMLEditRules::ReturnInListItem(Selectio
       if (isEmptyNode) {
         RefPtr<nsAtom> nodeAtom = aListItem.NodeInfo()->NameAtom();
         if (nodeAtom == nsGkAtoms::dd || nodeAtom == nsGkAtoms::dt) {
           nsCOMPtr<nsINode> list = aListItem.GetParentNode();
           int32_t itemOffset = list ? list->IndexOf(&aListItem) : -1;
 
           nsAtom* listAtom = nodeAtom == nsGkAtoms::dt ? nsGkAtoms::dd
                                                         : nsGkAtoms::dt;
-          nsCOMPtr<Element> newListItem =
-            htmlEditor->CreateNode(listAtom, list, itemOffset + 1,
-                                   aListItem.GetNextSibling());
+          MOZ_DIAGNOSTIC_ASSERT(itemOffset != -1);
+          EditorRawDOMPoint atNextListItem(list, aListItem.GetNextSibling(),
+                                           itemOffset + 1);
+          RefPtr<Element> newListItem =
+            htmlEditor->CreateNode(listAtom, atNextListItem);
           NS_ENSURE_STATE(newListItem);
           rv = htmlEditor->DeleteNode(&aListItem);
           NS_ENSURE_SUCCESS(rv, rv);
           rv = aSelection.Collapse(newListItem, 0);
           NS_ENSURE_SUCCESS(rv, rv);
 
           return NS_OK;
         }
@@ -7048,18 +7074,18 @@ HTMLEditRules::MakeBlockquote(nsTArray<O
     if (!curBlock) {
       nsCOMPtr<nsINode> curParent = curNode->GetParentNode();
       int32_t offset = curParent ? curParent->IndexOf(curNode) : -1;
       nsCOMPtr<nsIContent> curChild(curNode->AsContent());
       nsresult rv = SplitAsNeeded(*nsGkAtoms::blockquote, curParent, offset,
                                   address_of(curChild));
       NS_ENSURE_SUCCESS(rv, rv);
       NS_ENSURE_STATE(mHTMLEditor);
-      curBlock = mHTMLEditor->CreateNode(nsGkAtoms::blockquote, curParent,
-                                         offset, curChild);
+      EditorRawDOMPoint atCurChild(curParent, curChild, offset);
+      curBlock = mHTMLEditor->CreateNode(nsGkAtoms::blockquote, atCurChild);
       NS_ENSURE_STATE(curBlock);
       // remember our new block for postprocessing
       mNewBlock = curBlock;
       // note: doesn't matter if we set mNewBlock multiple times.
     }
 
     NS_ENSURE_STATE(mHTMLEditor);
     nsresult rv = mHTMLEditor->MoveNode(curNode->AsContent(), curBlock, -1);
@@ -7218,19 +7244,19 @@ HTMLEditRules::ApplyBlockStyle(nsTArray<
         nsresult rv = ApplyBlockStyle(childArray, aBlockTag);
         NS_ENSURE_SUCCESS(rv, rv);
       } else {
         // Make sure we can put a block here
         nsCOMPtr<nsIContent> curChild(curNode->AsContent());
         nsresult rv = SplitAsNeeded(aBlockTag, curParent, offset,
                                     address_of(curChild));
         NS_ENSURE_SUCCESS(rv, rv);
-        nsCOMPtr<Element> theBlock =
-          htmlEditor->CreateNode(&aBlockTag, curParent, offset,
-                                 curChild);
+        EditorRawDOMPoint atCurChild(curParent, curChild, offset);
+        RefPtr<Element> theBlock =
+          htmlEditor->CreateNode(&aBlockTag, atCurChild);
         NS_ENSURE_STATE(theBlock);
         // Remember our new block for postprocessing
         mNewBlock = theBlock;
       }
     } else if (curNode->IsHTMLElement(nsGkAtoms::br)) {
       // If the node is a break, we honor it by putting further nodes in a new
       // parent
       if (curBlock) {
@@ -7240,18 +7266,18 @@ HTMLEditRules::ApplyBlockStyle(nsTArray<
         NS_ENSURE_SUCCESS(rv, rv);
       } else {
         // The break is the first (or even only) node we encountered.  Create a
         // block for it.
         nsCOMPtr<nsIContent> curChild(curNode->AsContent());
         nsresult rv = SplitAsNeeded(aBlockTag, curParent, offset,
                                     address_of(curChild));
         NS_ENSURE_SUCCESS(rv, rv);
-        curBlock = htmlEditor->CreateNode(&aBlockTag, curParent, offset,
-                                          curChild);
+        EditorRawDOMPoint atCurChild(curParent, curChild, offset);
+        curBlock = htmlEditor->CreateNode(&aBlockTag, atCurChild);
         NS_ENSURE_STATE(curBlock);
         // Remember our new block for postprocessing
         mNewBlock = curBlock;
         // Note: doesn't matter if we set mNewBlock multiple times.
         rv = htmlEditor->MoveNode(curNode->AsContent(), curBlock, -1);
         NS_ENSURE_SUCCESS(rv, rv);
       }
     } else if (IsInlineNode(curNode)) {
@@ -7268,18 +7294,18 @@ HTMLEditRules::ApplyBlockStyle(nsTArray<
       }
 
       // If no curBlock, make one
       if (!curBlock) {
         nsCOMPtr<nsIContent> curChild(curNode->AsContent());
         nsresult rv = SplitAsNeeded(aBlockTag, curParent, offset,
                                     address_of(curChild));
         NS_ENSURE_SUCCESS(rv, rv);
-        curBlock = htmlEditor->CreateNode(&aBlockTag, curParent, offset,
-                                          curChild);
+        EditorRawDOMPoint atCurChild(curParent, curChild, offset);
+        curBlock = htmlEditor->CreateNode(&aBlockTag, atCurChild);
         NS_ENSURE_STATE(curBlock);
         // Remember our new block for postprocessing
         mNewBlock = curBlock;
         // Note: doesn't matter if we set mNewBlock multiple times.
       }
 
       if (NS_WARN_IF(!curNode->GetParentNode())) {
         // This is possible due to mutation events, let's not assert
@@ -9020,18 +9046,19 @@ HTMLEditRules::WillAbsolutePosition(Sele
     int32_t offset = aSelection.GetRangeAt(0)->StartOffset();
     nsCOMPtr<nsIContent> child =
       aSelection.GetRangeAt(0)->GetChildAtStartOffset();
 
     // Make sure we can put a block here
     rv = SplitAsNeeded(*nsGkAtoms::div, parent, offset,
                        address_of(child));
     NS_ENSURE_SUCCESS(rv, rv);
-    nsCOMPtr<Element> positionedDiv =
-      htmlEditor->CreateNode(nsGkAtoms::div, parent, offset, child);
+    EditorRawDOMPoint atChild(parent, child, offset);
+    RefPtr<Element> positionedDiv =
+      htmlEditor->CreateNode(nsGkAtoms::div, atChild);
     NS_ENSURE_STATE(positionedDiv);
     // Remember our new block for postprocessing
     mNewBlock = positionedDiv;
     // Delete anything that was in the list of nodes
     while (!arrayOfNodes.IsEmpty()) {
       OwningNonNull<nsINode> curNode = arrayOfNodes[0];
       rv = htmlEditor->DeleteNode(curNode);
       NS_ENSURE_SUCCESS(rv, rv);
@@ -9076,26 +9103,25 @@ HTMLEditRules::WillAbsolutePosition(Sele
       }
 
       if (!curList || (sibling && sibling != curList)) {
         // Create a new nested list of correct type
         rv =
           SplitAsNeeded(*curParent->NodeInfo()->NameAtom(), curParent, offset);
         NS_ENSURE_SUCCESS(rv, rv);
         if (!curPositionedDiv) {
-          nsCOMPtr<nsINode> curParentParent = curParent->GetParentNode();
-          int32_t parentOffset = curParentParent
-            ? curParentParent->IndexOf(curParent) : -1;
-          curPositionedDiv = htmlEditor->CreateNode(nsGkAtoms::div, curParentParent,
-                                                    parentOffset);
+          EditorRawDOMPoint atCurParent(curParent);
+          curPositionedDiv =
+            htmlEditor->CreateNode(nsGkAtoms::div, atCurParent);
           mNewBlock = curPositionedDiv;
         }
+        EditorRawDOMPoint atEndOfCurPositionedDiv(curPositionedDiv,
+                                                  curPositionedDiv->Length());
         curList = htmlEditor->CreateNode(curParent->NodeInfo()->NameAtom(),
-                                         curPositionedDiv, -1,
-                                         curPositionedDiv->GetLastChild());
+                                         atEndOfCurPositionedDiv);
         NS_ENSURE_STATE(curList);
         // curList is now the correct thing to put curNode in.  Remember our
         // new block for postprocessing.
       }
       // Tuck the node into the end of the active list
       rv = htmlEditor->MoveNode(curNode, curList, -1);
       NS_ENSURE_SUCCESS(rv, rv);
     } else {
@@ -9120,28 +9146,25 @@ HTMLEditRules::WillAbsolutePosition(Sele
         }
 
         if (!curList || (sibling && sibling != curList)) {
           // Create a new nested list of correct type
           rv = SplitAsNeeded(*curParent->NodeInfo()->NameAtom(), curParent,
                              offset);
           NS_ENSURE_SUCCESS(rv, rv);
           if (!curPositionedDiv) {
-            nsCOMPtr<nsINode> curParentParent = curParent->GetParentNode();
-            int32_t parentOffset = curParentParent ?
-              curParentParent->IndexOf(curParent) : -1;
-            curPositionedDiv = htmlEditor->CreateNode(nsGkAtoms::div,
-                                                      curParentParent,
-                                                      parentOffset,
-                                                      curParent->AsContent());
+            EditorRawDOMPoint atCurParent(curParent);
+            curPositionedDiv =
+              htmlEditor->CreateNode(nsGkAtoms::div, atCurParent);
             mNewBlock = curPositionedDiv;
           }
+          EditorRawDOMPoint atEndOfCurPositionedDiv(curPositionedDiv,
+                                                    curPositionedDiv->Length());
           curList = htmlEditor->CreateNode(curParent->NodeInfo()->NameAtom(),
-                                           curPositionedDiv, -1,
-                                           curPositionedDiv->GetLastChild());
+                                           atEndOfCurPositionedDiv);
           NS_ENSURE_STATE(curList);
         }
         rv = htmlEditor->MoveNode(listItem, curList, -1);
         NS_ENSURE_SUCCESS(rv, rv);
         // Remember we indented this li
         indentedLI = listItem;
       } else {
         // Need to make a div to put things in if we haven't already
@@ -9152,18 +9175,18 @@ HTMLEditRules::WillAbsolutePosition(Sele
             mNewBlock = curPositionedDiv;
             curList = nullptr;
             continue;
           }
           nsCOMPtr<nsIContent> curChild(curNode);
           rv = SplitAsNeeded(*nsGkAtoms::div, curParent, offset,
                              address_of(curChild));
           NS_ENSURE_SUCCESS(rv, rv);
-          curPositionedDiv = htmlEditor->CreateNode(nsGkAtoms::div, curParent,
-                                                    offset, curChild);
+          EditorRawDOMPoint atCurChild(curParent, curChild, offset);
+          curPositionedDiv = htmlEditor->CreateNode(nsGkAtoms::div, atCurChild);
           NS_ENSURE_STATE(curPositionedDiv);
           // Remember our new block for postprocessing
           mNewBlock = curPositionedDiv;
           // curPositionedDiv is now the correct thing to put curNode in
         }
 
         // Tuck the node into the end of the active blockquote
         rv = htmlEditor->MoveNode(curNode, curPositionedDiv, -1);
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; 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/. */
 
 #include "mozilla/HTMLEditor.h"
 
 #include "mozilla/DebugOnly.h"
+#include "mozilla/EditorDOMPoint.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/TextEvents.h"
 
 #include "nsCRT.h"
 
 #include "nsUnicharUtils.h"
 
 #include "HTMLEditorEventListener.h"
@@ -2016,21 +2017,23 @@ HTMLEditor::MakeOrChangeList(const nsASt
         // we need to split up to the child of parent
         offset = SplitNodeDeep(*topChild, *node, offset,
                                EmptyContainers::yes, nullptr, nullptr,
                                address_of(child));
         NS_ENSURE_STATE(offset != -1);
       }
 
       // make a list
-      nsCOMPtr<Element> newList = CreateNode(listAtom, parent, offset, child);
+      MOZ_DIAGNOSTIC_ASSERT(child);
+      EditorRawDOMPoint atChild(parent, child, offset);
+      RefPtr<Element> newList = CreateNode(listAtom, atChild);
       NS_ENSURE_STATE(newList);
       // make a list item
-      nsCOMPtr<Element> newItem = CreateNode(nsGkAtoms::li, newList, 0,
-                                             newList->GetFirstChild());
+      EditorRawDOMPoint atStartOfNewList(newList, 0);
+      RefPtr<Element> newItem = CreateNode(nsGkAtoms::li, atStartOfNewList);
       NS_ENSURE_STATE(newItem);
       rv = selection->Collapse(newItem, 0);
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
   return rules->DidDoAction(selection, &ruleInfo, rv);
 }
@@ -2159,17 +2162,19 @@ HTMLEditor::InsertBasicBlock(const nsASt
         // we need to split up to the child of parent
         offset = SplitNodeDeep(*topChild, *node, offset,
                                EmptyContainers::yes, nullptr, nullptr,
                                address_of(child));
         NS_ENSURE_STATE(offset != -1);
       }
 
       // make a block
-      nsCOMPtr<Element> newBlock = CreateNode(blockAtom, parent, offset, child);
+      MOZ_DIAGNOSTIC_ASSERT(child);
+      EditorRawDOMPoint atChild(parent, child, offset);
+      RefPtr<Element> newBlock = CreateNode(blockAtom, atChild);
       NS_ENSURE_STATE(newBlock);
 
       // reposition selection to inside the block
       rv = selection->Collapse(newBlock, 0);
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
@@ -2233,18 +2238,19 @@ HTMLEditor::Indent(const nsAString& aInd
           // we need to split up to the child of parent
           offset = SplitNodeDeep(*topChild, *node, offset,
                                  EmptyContainers::yes, nullptr, nullptr,
                                  address_of(child));
           NS_ENSURE_STATE(offset != -1);
         }
 
         // make a blockquote
-        nsCOMPtr<Element> newBQ =
-          CreateNode(nsGkAtoms::blockquote, parent, offset, child);
+        MOZ_DIAGNOSTIC_ASSERT(child);
+        EditorRawDOMPoint atChild(parent, child, offset);
+        RefPtr<Element> newBQ = CreateNode(nsGkAtoms::blockquote, atChild);
         NS_ENSURE_STATE(newBQ);
         // put a space in it so layout will draw the list item
         rv = selection->Collapse(newBQ, 0);
         NS_ENSURE_SUCCESS(rv, rv);
         rv = InsertText(NS_LITERAL_STRING(" "));
         NS_ENSURE_SUCCESS(rv, rv);
         // reposition selection to before the space character
         NS_ENSURE_STATE(selection->GetRangeAt(0));
@@ -4527,19 +4533,19 @@ HTMLEditor::CopyLastEditableChildStyles(
   while (childElement && (childElement != aPreviousBlock)) {
     if (HTMLEditUtils::IsInlineStyle(childElement) ||
         childElement->IsHTMLElement(nsGkAtoms::span)) {
       if (newStyles) {
         newStyles = InsertContainerAbove(newStyles,
                                          childElement->NodeInfo()->NameAtom());
         NS_ENSURE_STATE(newStyles);
       } else {
+        EditorRawDOMPoint atStartOfNewBlock(newBlock, 0);
         deepestStyle = newStyles =
-          CreateNode(childElement->NodeInfo()->NameAtom(), newBlock, 0,
-                     newBlock->GetFirstChild());
+          CreateNode(childElement->NodeInfo()->NameAtom(), atStartOfNewBlock);
         NS_ENSURE_STATE(newStyles);
       }
       CloneAttributes(newStyles, childElement);
     }
     childElement = childElement->GetParentElement();
   }
   if (deepestStyle) {
     RefPtr<Element> retVal = CreateBR(deepestStyle, 0);
--- a/editor/libeditor/TextEditor.cpp
+++ b/editor/libeditor/TextEditor.cpp
@@ -237,17 +237,18 @@ TextEditor::SetDocumentCharacterSet(cons
   }
 
   nsCOMPtr<nsIContent> headNode = headList->Item(0);
   if (NS_WARN_IF(!headNode)) {
     return NS_OK;
   }
 
   // Create a new meta charset tag
-  RefPtr<Element> metaElement = CreateNode(nsGkAtoms::meta, headNode, 0);
+  EditorRawDOMPoint atStartOfHeadNode(headNode, 0);
+  RefPtr<Element> metaElement = CreateNode(nsGkAtoms::meta, atStartOfHeadNode);
   if (NS_WARN_IF(!metaElement)) {
     return NS_OK;
   }
 
   // Set attributes to the created element
   if (characterSet.IsEmpty()) {
     return NS_OK;
   }
@@ -438,42 +439,45 @@ TextEditor::CreateBRImpl(nsCOMPtr<nsIDOM
   NS_ENSURE_TRUE(aInOutParent && *aInOutParent && aInOutOffset && outBRNode, NS_ERROR_NULL_POINTER);
   *outBRNode = nullptr;
 
   // we need to insert a br.  unfortunately, we may have to split a text node to do it.
   nsCOMPtr<nsINode> node = do_QueryInterface(*aInOutParent);
   int32_t theOffset = *aInOutOffset;
   RefPtr<Element> brNode;
   if (IsTextNode(node)) {
-    int32_t offset;
-    nsCOMPtr<nsINode> tmp = GetNodeLocation(node, &offset);
-    NS_ENSURE_TRUE(tmp, NS_ERROR_FAILURE);
+    EditorRawDOMPoint atNode(node);
+    if (NS_WARN_IF(!atNode.IsSetAndValid())) {
+      return NS_ERROR_FAILURE;
+    }
     if (!theOffset) {
       // we are already set to go
     } else if (theOffset == static_cast<int32_t>(node->Length())) {
       // update offset to point AFTER the text node
-      offset++;
+      atNode.AdvanceOffset();
     } else {
       // split the text node
       ErrorResult rv;
       SplitNode(*node->AsContent(), theOffset, rv);
       if (NS_WARN_IF(rv.Failed())) {
         return rv.StealNSResult();
       }
-      tmp = GetNodeLocation(node, &offset);
+      atNode.Clear();
+      atNode.Set(node);
     }
     // create br
-    brNode = CreateNode(nsGkAtoms::br, tmp, offset);
+    brNode = CreateNode(nsGkAtoms::br, atNode);
     if (NS_WARN_IF(!brNode)) {
       return NS_ERROR_FAILURE;
     }
-    *aInOutParent = GetAsDOMNode(tmp);
-    *aInOutOffset = offset+1;
+    *aInOutParent = GetAsDOMNode(atNode.Container());
+    *aInOutOffset = atNode.Offset() + 1;
   } else {
-    brNode = CreateNode(nsGkAtoms::br, node, theOffset);
+    EditorRawDOMPoint atTheOffset(node, theOffset);
+    brNode = CreateNode(nsGkAtoms::br, atTheOffset);
     if (NS_WARN_IF(!brNode)) {
       return NS_ERROR_FAILURE;
     }
     (*aInOutOffset)++;
   }
 
   *outBRNode = GetAsDOMNode(brNode);
   if (*outBRNode && (aSelect != eNone)) {