Bug 1408125 - part 2: EditorBase::CreateTxnForInsertNode() and EditorBase::InsertNode() should take |const EditorRawDOMPoint&| as an argument specifying point to insert r?m_kato draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Wed, 22 Nov 2017 21:25:05 +0900
changeset 710425 6b0737fa9567365a2c680a52a72348b0dc38913c
parent 710424 c6a7a807fa6c2b370dd6e51cd2cb2d2694eb4cdf
child 710426 83fa9fd4c7b083941e6d01bbdc894556c5356563
push id92823
push usermasayuki@d-toybox.com
push dateSun, 10 Dec 2017 02:40:55 +0000
reviewersm_kato
bugs1408125
milestone59.0a1
Bug 1408125 - part 2: EditorBase::CreateTxnForInsertNode() and EditorBase::InsertNode() should take |const EditorRawDOMPoint&| as an argument specifying point to insert r?m_kato EditorBase::CreateTxnForInsertNode() and EditorBase::InsertNode() should take |const EditorRawDOMPoint&| as an argument specifying point to insert. MozReview-Commit-ID: KhK19xS7wXb
editor/libeditor/EditorBase.cpp
editor/libeditor/EditorBase.h
editor/libeditor/HTMLEditRules.cpp
editor/libeditor/HTMLEditor.cpp
editor/libeditor/HTMLEditorDataTransfer.cpp
editor/libeditor/HTMLTableEditor.cpp
editor/libeditor/TextEditRules.cpp
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -1464,52 +1464,67 @@ EditorBase::CreateNode(nsAtom* aTag,
                               GetAsDOMNode(ret), rv);
     }
   }
 
   return ret.forget();
 }
 
 NS_IMETHODIMP
-EditorBase::InsertNode(nsIDOMNode* aNode,
-                       nsIDOMNode* aParent,
-                       int32_t aPosition)
-{
-  nsCOMPtr<nsIContent> node = do_QueryInterface(aNode);
-  nsCOMPtr<nsINode> parent = do_QueryInterface(aParent);
-  NS_ENSURE_TRUE(node && parent, NS_ERROR_NULL_POINTER);
-
-  return InsertNode(*node, *parent, aPosition);
+EditorBase::InsertNode(nsIDOMNode* aNodeToInsert,
+                       nsIDOMNode* aContainer,
+                       int32_t aOffset)
+{
+  nsCOMPtr<nsIContent> contentToInsert = do_QueryInterface(aNodeToInsert);
+  if (NS_WARN_IF(!contentToInsert)) {
+    return NS_ERROR_NULL_POINTER;
+  }
+  nsCOMPtr<nsINode> container = do_QueryInterface(aContainer);
+  if (NS_WARN_IF(!container)) {
+    return NS_ERROR_NULL_POINTER;
+  }
+  int32_t offset =
+    aOffset < 0 ? static_cast<int32_t>(container->Length()) :
+                  std::min(aOffset, static_cast<int32_t>(container->Length()));
+  return InsertNode(*contentToInsert, EditorRawDOMPoint(container, offset));
 }
 
 nsresult
-EditorBase::InsertNode(nsIContent& aNode,
-                       nsINode& aParent,
-                       int32_t aPosition)
-{
+EditorBase::InsertNode(nsIContent& aContentToInsert,
+                       const EditorRawDOMPoint& aPointToInsert)
+{
+  if (NS_WARN_IF(!aPointToInsert.IsSet())) {
+    return NS_ERROR_INVALID_ARG;
+  }
+  MOZ_ASSERT(aPointToInsert.IsSetAndValid());
+
   AutoRules beginRulesSniffing(this, EditAction::insertNode, nsIEditor::eNext);
 
   {
     AutoActionListenerArray listeners(mActionListeners);
     for (auto& listener : listeners) {
-      listener->WillInsertNode(aNode.AsDOMNode(), aParent.AsDOMNode(),
-                               aPosition);
+      listener->WillInsertNode(aContentToInsert.AsDOMNode(),
+                               aPointToInsert.Container()->AsDOMNode(),
+                               aPointToInsert.Offset());
     }
   }
 
   RefPtr<InsertNodeTransaction> transaction =
-    CreateTxnForInsertNode(aNode, aParent, aPosition);
+    CreateTxnForInsertNode(aContentToInsert, aPointToInsert);
   nsresult rv = DoTransaction(transaction);
 
-  mRangeUpdater.SelAdjInsertNode(&aParent, aPosition);
+  mRangeUpdater.SelAdjInsertNode(aPointToInsert.Container(),
+                                 aPointToInsert.Offset());
 
   {
     AutoActionListenerArray listeners(mActionListeners);
     for (auto& listener : listeners) {
-      listener->DidInsertNode(aNode.AsDOMNode(), aParent.AsDOMNode(), aPosition,
+      listener->DidInsertNode(aContentToInsert.AsDOMNode(),
+                              aPointToInsert.Container()->AsDOMNode(),
+                              aPointToInsert.Offset(),
                               rv);
     }
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
@@ -1689,91 +1704,115 @@ already_AddRefed<Element>
 EditorBase::ReplaceContainer(Element* aOldContainer,
                              nsAtom* aNodeType,
                              nsAtom* aAttribute,
                              const nsAString* aValue,
                              ECloneAttributes aCloneAttributes)
 {
   MOZ_ASSERT(aOldContainer && aNodeType);
 
-  nsCOMPtr<nsIContent> parent = aOldContainer->GetParent();
-  NS_ENSURE_TRUE(parent, nullptr);
-
-  int32_t offset = parent->IndexOf(aOldContainer);
-
-  // create new container
-  nsCOMPtr<Element> ret = CreateHTMLContent(aNodeType);
-  NS_ENSURE_TRUE(ret, nullptr);
-
-  // set attribute if needed
+  EditorDOMPoint atOldContainer(aOldContainer);
+  if (NS_WARN_IF(!atOldContainer.IsSet())) {
+    return nullptr;
+  }
+
+  RefPtr<Element> newContainer = CreateHTMLContent(aNodeType);
+  if (NS_WARN_IF(!newContainer)) {
+    return nullptr;
+  }
+
+  // Set attribute if needed.
   if (aAttribute && aValue && aAttribute != nsGkAtoms::_empty) {
-    nsresult rv = ret->SetAttr(kNameSpaceID_None, aAttribute, *aValue, true);
-    NS_ENSURE_SUCCESS(rv, nullptr);
+    nsresult rv =
+      newContainer->SetAttr(kNameSpaceID_None, aAttribute, *aValue, true);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return nullptr;
+    }
   }
   if (aCloneAttributes == eCloneAttributes) {
-    CloneAttributes(ret, aOldContainer);
-  }
-
-  // notify our internal selection state listener
-  // (Note: An AutoSelectionRestorer object must be created
-  //  before calling this to initialize mRangeUpdater)
+    CloneAttributes(newContainer, aOldContainer);
+  }
+
+  // Notify our internal selection state listener.
+  // Note: An AutoSelectionRestorer object must be created before calling this
+  // to initialize mRangeUpdater.
   AutoReplaceContainerSelNotify selStateNotify(mRangeUpdater, aOldContainer,
-                                               ret);
+                                               newContainer);
   {
     AutoTransactionsConserveSelection conserveSelection(this);
+    // Move all children from the old container to the new container.
     while (aOldContainer->HasChildren()) {
       nsCOMPtr<nsIContent> child = aOldContainer->GetFirstChild();
 
       nsresult rv = DeleteNode(child);
-      NS_ENSURE_SUCCESS(rv, nullptr);
-
-      rv = InsertNode(*child, *ret, -1);
-      NS_ENSURE_SUCCESS(rv, nullptr);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return nullptr;
+      }
+
+      rv = InsertNode(*child, EditorRawDOMPoint(newContainer,
+                                                newContainer->Length()));
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return nullptr;
+      }
     }
   }
 
-  // insert new container into tree
-  nsresult rv = InsertNode(*ret, *parent, offset);
-  NS_ENSURE_SUCCESS(rv, nullptr);
-
-  // delete old container
+  // Insert new container into tree.
+  NS_WARNING_ASSERTION(atOldContainer.IsSetAndValid(),
+    "The old container might be moved by mutation observer");
+  nsresult rv = InsertNode(*newContainer, atOldContainer.AsRaw());
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return nullptr;
+  }
+
+  // Delete old container.
   rv = DeleteNode(aOldContainer);
-  NS_ENSURE_SUCCESS(rv, nullptr);
-
-  return ret.forget();
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return nullptr;
+  }
+
+  return newContainer.forget();
 }
 
 /**
  * RemoveContainer() removes inNode, reparenting its children (if any) into the
  * parent of inNode.
  */
 nsresult
 EditorBase::RemoveContainer(nsIContent* aNode)
 {
   MOZ_ASSERT(aNode);
 
-  nsCOMPtr<nsINode> parent = aNode->GetParentNode();
-  NS_ENSURE_STATE(parent);
-
-  int32_t offset = parent->IndexOf(aNode);
-
-  // Loop through the children of inNode and promote them into inNode's parent
-  uint32_t nodeOrigLen = aNode->GetChildCount();
-
-  // notify our internal selection state listener
-  AutoRemoveContainerSelNotify selNotify(mRangeUpdater, aNode, parent,
-                                         offset, nodeOrigLen);
-
+  EditorDOMPoint pointToInsertChildren(aNode);
+  if (NS_WARN_IF(!pointToInsertChildren.IsSet())) {
+    return NS_ERROR_FAILURE;
+  }
+
+  // Notify our internal selection state listener.
+  AutoRemoveContainerSelNotify selNotify(mRangeUpdater, aNode,
+                                         pointToInsertChildren.Container(),
+                                         pointToInsertChildren.Offset(),
+                                         aNode->GetChildCount());
+
+  // Move all children from aNode to its parent.
   while (aNode->HasChildren()) {
     nsCOMPtr<nsIContent> child = aNode->GetLastChild();
     nsresult rv = DeleteNode(child);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = InsertNode(*child, *parent, offset);
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    // Insert the last child before the previous last child.  So, we need to
+    // use offset here because previous child might have been moved to
+    // container.
+    rv = InsertNode(*child, EditorRawDOMPoint(pointToInsertChildren.Container(),
+                                              pointToInsertChildren.Offset()));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
   }
 
   return DeleteNode(aNode);
 }
 
 /**
  * InsertContainerAbove() inserts a new parent for inNode, which is contructed
  * to be of type aNodeType.  outNode becomes a child of inNode's earlier
@@ -1783,49 +1822,66 @@ EditorBase::RemoveContainer(nsIContent* 
 already_AddRefed<Element>
 EditorBase::InsertContainerAbove(nsIContent* aNode,
                                  nsAtom* aNodeType,
                                  nsAtom* aAttribute,
                                  const nsAString* aValue)
 {
   MOZ_ASSERT(aNode && aNodeType);
 
-  nsCOMPtr<nsIContent> parent = aNode->GetParent();
-  NS_ENSURE_TRUE(parent, nullptr);
-  int32_t offset = parent->IndexOf(aNode);
+  EditorDOMPoint pointToInsertNewContainer(aNode);
+  if (NS_WARN_IF(!pointToInsertNewContainer.IsSet())) {
+    return nullptr;
+  }
+  // aNode will be moved to the new container before inserting the new
+  // container.  So, when we insert the container, the insertion point
+  // is before the next sibling of aNode.
+  DebugOnly<bool> advanced = pointToInsertNewContainer.AdvanceOffset();
+  NS_WARNING_ASSERTION(advanced,
+    "Failed to advance offset to after aNode");
 
   // Create new container
-  nsCOMPtr<Element> newContent = CreateHTMLContent(aNodeType);
-  NS_ENSURE_TRUE(newContent, nullptr);
+  RefPtr<Element> newContainer = CreateHTMLContent(aNodeType);
+  if (NS_WARN_IF(!newContainer)) {
+    return nullptr;
+  }
 
   // Set attribute if needed
   if (aAttribute && aValue && aAttribute != nsGkAtoms::_empty) {
     nsresult rv =
-      newContent->SetAttr(kNameSpaceID_None, aAttribute, *aValue, true);
-    NS_ENSURE_SUCCESS(rv, nullptr);
+      newContainer->SetAttr(kNameSpaceID_None, aAttribute, *aValue, true);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return nullptr;
+    }
   }
 
   // Notify our internal selection state listener
   AutoInsertContainerSelNotify selNotify(mRangeUpdater);
 
-  // Put inNode in new parent, outNode
+  // Put aNode in the new container, first.
   nsresult rv = DeleteNode(aNode);
-  NS_ENSURE_SUCCESS(rv, nullptr);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return nullptr;
+  }
 
   {
     AutoTransactionsConserveSelection conserveSelection(this);
-    rv = InsertNode(*aNode, *newContent, 0);
-    NS_ENSURE_SUCCESS(rv, nullptr);
-  }
-
-  // Put new parent in doc
-  rv = InsertNode(*newContent, *parent, offset);
-  NS_ENSURE_SUCCESS(rv, nullptr);
-
-  return newContent.forget();
+    rv = InsertNode(*aNode, EditorRawDOMPoint(newContainer, 0));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return nullptr;
+    }
+  }
+
+  // Put the new container where aNode was.
+  rv = InsertNode(*newContainer, pointToInsertNewContainer.AsRaw());
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return nullptr;
+  }
+
+  return newContainer.forget();
 }
 
 /**
  * MoveNode() moves aNode to {aParent,aOffset}.
  */
 nsresult
 EditorBase::MoveNode(nsIContent* aNode,
                      nsINode* aParent,
@@ -1859,19 +1915,25 @@ EditorBase::MoveNode(nsIContent* aNode,
     // When we delete aNode, it will make the offsets after it off by one
     aOffset--;
   }
 
   // Hold a reference so aNode doesn't go away when we remove it (bug 772282)
   nsCOMPtr<nsINode> kungFuDeathGrip = aNode;
 
   nsresult rv = DeleteNode(aNode);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return InsertNode(*aNode, *aParent, aOffset);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = InsertNode(*aNode, EditorRawDOMPoint(aParent, aOffset));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  return NS_OK;
 }
 
 void
 EditorBase::MoveAllChildren(nsINode& aContainer,
                             const EditorRawDOMPoint& aPointToInsert,
                             ErrorResult& aError)
 {
   if (!aContainer.HasChildren()) {
@@ -2660,18 +2722,17 @@ EditorBase::InsertTextImpl(nsIDocument& 
 
   if (ShouldHandleIMEComposition()) {
     CheckedInt<int32_t> newOffset;
     if (!pointToInsert.Container()->IsNodeOfType(nsINode::eTEXT)) {
       // create a text node
       RefPtr<nsTextNode> newNode =
         EditorBase::CreateTextNode(aDocument, EmptyString());
       // then we insert it into the dom tree
-      nsresult rv = InsertNode(*newNode, *pointToInsert.Container(),
-                               pointToInsert.Offset());
+      nsresult rv = InsertNode(*newNode, pointToInsert);
       NS_ENSURE_SUCCESS(rv, rv);
       pointToInsert.Set(newNode, 0);
       newOffset = lengthToInsert;
     } else {
       newOffset = lengthToInsert + pointToInsert.Offset();
       NS_ENSURE_TRUE(newOffset.isValid(), NS_ERROR_FAILURE);
     }
     nsresult rv =
@@ -2702,18 +2763,17 @@ EditorBase::InsertTextImpl(nsIDocument& 
     return NS_OK;
   }
 
   // we are inserting text into a non-text node.  first we have to create a
   // textnode (this also populates it with the text)
   RefPtr<nsTextNode> newNode =
     EditorBase::CreateTextNode(aDocument, aStringToInsert);
   // then we insert it into the dom tree
-  nsresult rv = InsertNode(*newNode, *pointToInsert.Container(),
-                           pointToInsert.Offset());
+  nsresult rv = InsertNode(*newNode, pointToInsert);
   NS_ENSURE_SUCCESS(rv, rv);
   if (aPointAfterInsertedString) {
     aPointAfterInsertedString->Set(newNode, lengthToInsert.value());
   }
   return NS_OK;
 }
 
 nsresult
@@ -4617,25 +4677,20 @@ EditorBase::CreateTxnForCreateElement(ns
     new CreateElementTransaction(*this, aTag, aPointToInsert);
 
   return transaction.forget();
 }
 
 
 already_AddRefed<InsertNodeTransaction>
 EditorBase::CreateTxnForInsertNode(nsIContent& aNode,
-                                   nsINode& aParent,
-                                   int32_t aPosition)
-{
-  int32_t offset =
-    aPosition < 0 ? static_cast<int32_t>(aParent.Length()) :
-                    std::min(aPosition, static_cast<int32_t>(aParent.Length()));
+                                   const EditorRawDOMPoint& aPointToInsert)
+{
   RefPtr<InsertNodeTransaction> transaction =
-    new InsertNodeTransaction(*this, aNode,
-                              EditorRawDOMPoint(&aParent, offset));
+    new InsertNodeTransaction(*this, aNode, aPointToInsert);
   return transaction.forget();
 }
 
 already_AddRefed<DeleteNodeTransaction>
 EditorBase::CreateTxnForDeleteNode(nsINode* aNode)
 {
   if (NS_WARN_IF(!aNode)) {
     return nullptr;
--- a/editor/libeditor/EditorBase.h
+++ b/editor/libeditor/EditorBase.h
@@ -341,17 +341,31 @@ public:
                                  EStripWrappers aStripWrappers);
 
   already_AddRefed<Element> DeleteSelectionAndCreateElement(nsAtom& aTag);
 
   /**
    * Helper routines for node/parent manipulations.
    */
   nsresult DeleteNode(nsINode* aNode);
-  nsresult InsertNode(nsIContent& aNode, nsINode& aParent, int32_t aPosition);
+
+  /**
+   * InsertNode() inserts aContentToInsert before the child specified by
+   * aPointToInsert.
+   *
+   * @param aContentToInsert    The node to be inserted.
+   * @param aPointToInsert      The insertion point of aContentToInsert.
+   *                            If this refers end of the container, the
+   *                            transaction will append the node to the
+   *                            container.  Otherwise, will insert the node
+   *                            before child node referred by this.
+   */
+  nsresult InsertNode(nsIContent& aContentToInsert,
+                      const EditorRawDOMPoint& aPointToInsert);
+
   enum ECloneAttributes { eDontCloneAttributes, eCloneAttributes };
   already_AddRefed<Element> ReplaceContainer(Element* aOldContainer,
                                              nsAtom* aNodeType,
                                              nsAtom* aAttribute = nullptr,
                                              const nsAString* aValue = nullptr,
                                              ECloneAttributes aCloneAttributes
                                              = eDontCloneAttributes);
   void CloneAttributes(Element* aDest, Element* aSource);
@@ -507,17 +521,17 @@ protected:
    * aPointToInsert of type aTag.
    *
    * @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                A CreateElementTransaction which are initialized
+   * @return                A CreateElementTransaction which was initialized
    *                        with the arguments.
    */
   already_AddRefed<CreateElementTransaction>
     CreateTxnForCreateElement(nsAtom& aTag,
                               const EditorRawDOMPoint& aPointToInsert);
 
   /**
    * Create an element node whose name is aTag at before aPointToInsert.  When
@@ -533,21 +547,31 @@ protected:
    *                        Otherwise, will insert the element before the
    *                        child node referred by this.
    * @return                The created new element node.
    */
   already_AddRefed<Element> CreateNode(nsAtom* aTag,
                                        const EditorRawDOMPoint& aPointToInsert);
 
   /**
-   * Create a transaction for inserting aNode as a child of aParent.
+   * Create a transaction for inserting aContentToInsert before the child
+   * at aPointToInsert.
+   *
+   * @param aContentToInsert    The node to be inserted.
+   * @param aPointToInsert      The insertion point of aContentToInsert.
+   *                            If this refers end of the container, the
+   *                            transaction will append the node to the
+   *                            container.  Otherwise, will insert the node
+   *                            before child node referred by this.
+   * @return                    A InsertNodeTranaction which was initialized
+   *                            with the arguments.
    */
   already_AddRefed<InsertNodeTransaction>
-    CreateTxnForInsertNode(nsIContent& aNode, nsINode& aParent,
-                           int32_t aOffset);
+    CreateTxnForInsertNode(nsIContent& aContentToInsert,
+                           const EditorRawDOMPoint& aPointToInsert);
 
   /**
    * Create a transaction for removing aNode from its parent.
    */
   already_AddRefed<DeleteNodeTransaction>
     CreateTxnForDeleteNode(nsINode* aNode);
 
   /**
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -4859,16 +4859,18 @@ HTMLEditRules::CreateStyleForInsertText(
   nsCOMPtr<Element> rootElement = aDoc.GetRootElement();
   NS_ENSURE_STATE(rootElement);
 
   // process clearing any styles first
   UniquePtr<PropItem> item =
     Move(mHTMLEditor->mTypeInState->TakeClearProperty());
   while (item && node != rootElement) {
     NS_ENSURE_STATE(mHTMLEditor);
+    // XXX If we redesign ClearStyle(), we can use EditorDOMPoint in this
+    //     method.
     nsresult rv =
       mHTMLEditor->ClearStyle(address_of(node), &offset,
                               item->tag, &item->attr);
     NS_ENSURE_SUCCESS(rv, rv);
     item = Move(mHTMLEditor->mTypeInState->TakeClearProperty());
     weDidSomething = true;
   }
 
@@ -4895,17 +4897,18 @@ HTMLEditRules::CreateStyleForInsertText(
       offset = splitPoint.Offset();
     }
     if (!mHTMLEditor->IsContainer(node)) {
       return NS_OK;
     }
     OwningNonNull<Text> newNode =
       EditorBase::CreateTextNode(aDoc, EmptyString());
     NS_ENSURE_STATE(mHTMLEditor);
-    nsresult rv = mHTMLEditor->InsertNode(*newNode, *node, offset);
+    nsresult rv =
+      mHTMLEditor->InsertNode(*newNode, EditorRawDOMPoint(node, offset));
     NS_ENSURE_SUCCESS(rv, rv);
     node = newNode;
     offset = 0;
     weDidSomething = true;
 
     if (relFontSize) {
       // dir indicated bigger versus smaller.  1 = bigger, -1 = smaller
       HTMLEditor::FontSize dir = relFontSize > 0 ?
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -1162,18 +1162,21 @@ HTMLEditor::ReplaceHeadContentsWithHTML(
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // Now insert the new nodes
   int32_t offsetOfNewNode = 0;
 
   // Loop over the contents of the fragment and move into the document
   while (nsCOMPtr<nsIContent> child = docfrag->GetFirstChild()) {
-    nsresult rv = InsertNode(*child, *headNode, offsetOfNewNode++);
-    NS_ENSURE_SUCCESS(rv, rv);
+    nsresult rv =
+      InsertNode(*child, EditorRawDOMPoint(headNode, offsetOfNewNode++));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HTMLEditor::RebuildDocumentFromSource(const nsAString& aSourceString)
 {
@@ -1607,17 +1610,17 @@ HTMLEditor::InsertNodeAtPoint(nsIDOMNode
     EditorRawDOMPoint splitPoint(splitNodeResult.SplitPoint());
     *ioParent = GetAsDOMNode(splitPoint.Container());
     *ioOffset = splitPoint.Offset();
     if (ioChildAtOffset) {
       *ioChildAtOffset = GetAsDOMNode(splitPoint.GetChildAtOffset());
     }
   }
   // Now we can insert the new node
-  nsresult rv = InsertNode(*node, *parent, *ioOffset);
+  nsresult rv = InsertNode(*node, EditorRawDOMPoint(parent, *ioOffset));
   if (isDocumentFragment) {
     *ioChildAtOffset = do_QueryInterface(parent->GetChildAt(*ioOffset));
   }
   return rv;
 }
 
 NS_IMETHODIMP
 HTMLEditor::SelectElement(nsIDOMElement* aElement)
--- a/editor/libeditor/HTMLEditorDataTransfer.cpp
+++ b/editor/libeditor/HTMLEditorDataTransfer.cpp
@@ -119,32 +119,50 @@ HTMLEditor::LoadHTML(const nsAString& aI
       rv = DeleteSelection(eNone, eStrip);
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     // Get the first range in the selection, for context:
     RefPtr<nsRange> range = selection->GetRangeAt(0);
     NS_ENSURE_TRUE(range, NS_ERROR_NULL_POINTER);
 
-    // create fragment for pasted html
-    nsCOMPtr<nsIDOMDocumentFragment> docfrag;
-    rv = range->CreateContextualFragment(aInputString, getter_AddRefs(docfrag));
-    NS_ENSURE_SUCCESS(rv, rv);
-    // put the fragment into the document
-    nsCOMPtr<nsINode> parent = range->GetStartContainer();
-    NS_ENSURE_TRUE(parent, NS_ERROR_NULL_POINTER);
-    uint32_t childOffset = range->StartOffset();
+    // Create fragment for pasted HTML.
+    ErrorResult error;
+    RefPtr<DocumentFragment> documentFragment =
+      range->CreateContextualFragment(aInputString, error);
+    if (NS_WARN_IF(error.Failed())) {
+      return error.StealNSResult();
+    }
 
-    nsCOMPtr<nsIDOMNode> nodeToInsert;
-    docfrag->GetFirstChild(getter_AddRefs(nodeToInsert));
-    while (nodeToInsert) {
-      rv = InsertNode(nodeToInsert, GetAsDOMNode(parent),
-                      static_cast<int32_t>(childOffset++));
-      NS_ENSURE_SUCCESS(rv, rv);
-      docfrag->GetFirstChild(getter_AddRefs(nodeToInsert));
+    // Put the fragment into the document at start of selection.
+    EditorDOMPoint pointToInsert(range->StartRef());
+    // XXX We need to make pointToInsert store offset for keeping traditional
+    //     behavior since using only child node to pointing insertion point
+    //     changes the behavior when inserted child is moved by mutation
+    //     observer.  We need to investigate what we should do here.
+    Unused << pointToInsert.Offset();
+    for (nsCOMPtr<nsIContent> contentToInsert =
+           documentFragment->GetFirstChild();
+         contentToInsert;
+         contentToInsert = documentFragment->GetFirstChild()) {
+      rv = InsertNode(*contentToInsert, pointToInsert.AsRaw());
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+      // XXX If the inserted node has been moved by mutation observer,
+      //     incrementing offset will cause odd result.  Next new node
+      //     will be inserted after existing node and the offset will be
+      //     overflown from the container node.
+      pointToInsert.Set(pointToInsert.Container(), pointToInsert.Offset() + 1);
+      if (NS_WARN_IF(!pointToInsert.Offset())) {
+        // Append the remaining children to the container if offset is
+        // overflown.
+        pointToInsert.Set(pointToInsert.Container(),
+                          pointToInsert.Container()->Length());
+      }
     }
   }
 
   return rules->DidDoAction(selection, &ruleInfo, rv);
 }
 
 NS_IMETHODIMP
 HTMLEditor::InsertHTML(const nsAString& aInString)
--- a/editor/libeditor/HTMLTableEditor.cpp
+++ b/editor/libeditor/HTMLTableEditor.cpp
@@ -82,72 +82,80 @@ public:
   void CancelSetCaret()
   {
     mHTMLEditor = nullptr;
     mTable = nullptr;
   }
 };
 
 NS_IMETHODIMP
-HTMLEditor::InsertCell(nsIDOMElement* aCell,
+HTMLEditor::InsertCell(nsIDOMElement* aDOMCell,
                        int32_t aRowSpan,
                        int32_t aColSpan,
                        bool aAfter,
                        bool aIsHeader,
-                       nsIDOMElement** aNewCell)
+                       nsIDOMElement** aNewDOMCell)
 {
-  NS_ENSURE_TRUE(aCell, NS_ERROR_NULL_POINTER);
-  if (aNewCell) {
-    *aNewCell = nullptr;
+  if (aNewDOMCell) {
+    *aNewDOMCell = nullptr;
+  }
+
+  if (NS_WARN_IF(!aDOMCell)) {
+    return NS_ERROR_NULL_POINTER;
   }
 
   // And the parent and offsets needed to do an insert
-  nsCOMPtr<nsIDOMNode> cellParent;
-  nsresult rv = aCell->GetParentNode(getter_AddRefs(cellParent));
-  NS_ENSURE_SUCCESS(rv, rv);
-  NS_ENSURE_TRUE(cellParent, NS_ERROR_NULL_POINTER);
-
-  int32_t cellOffset = GetChildOffset(aCell, cellParent);
-
-  nsCOMPtr<nsIDOMElement> newCell;
-  rv = CreateElementWithDefaults(aIsHeader ? NS_LITERAL_STRING("th") :
-                                             NS_LITERAL_STRING("tb"),
-                                 getter_AddRefs(newCell));
-  if (NS_FAILED(rv)) {
+  nsCOMPtr<nsIContent> cell = do_QueryInterface(aDOMCell);
+  if (NS_WARN_IF(!cell)) {
+    return NS_ERROR_INVALID_ARG;
+  }
+  EditorDOMPoint pointToInsert(cell);
+  if (NS_WARN_IF(!pointToInsert.IsSet())) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  nsCOMPtr<nsIDOMElement> newDOMCell;
+  nsresult rv =
+    CreateElementWithDefaults(aIsHeader ? NS_LITERAL_STRING("th") :
+                                          NS_LITERAL_STRING("tb"),
+                              getter_AddRefs(newDOMCell));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
-  if (!newCell) {
+  nsCOMPtr<Element> newCell = do_QueryInterface(newDOMCell);
+  if (NS_WARN_IF(!newCell)) {
     return NS_ERROR_FAILURE;
   }
 
   //Optional: return new cell created
-  if (aNewCell) {
-    *aNewCell = newCell.get();
-    NS_ADDREF(*aNewCell);
+  if (aNewDOMCell) {
+    newDOMCell.forget(aNewDOMCell);
   }
 
   if (aRowSpan > 1) {
     // Note: Do NOT use editor transaction for this
     nsAutoString newRowSpan;
     newRowSpan.AppendInt(aRowSpan, 10);
-    newCell->SetAttribute(NS_LITERAL_STRING("rowspan"), newRowSpan);
+    newCell->SetAttr(kNameSpaceID_None, nsGkAtoms::rowspan, newRowSpan, true);
   }
   if (aColSpan > 1) {
     // Note: Do NOT use editor transaction for this
     nsAutoString newColSpan;
     newColSpan.AppendInt(aColSpan, 10);
-    newCell->SetAttribute(NS_LITERAL_STRING("colspan"), newColSpan);
+    newCell->SetAttr(kNameSpaceID_None, nsGkAtoms::colspan, newColSpan, true);
   }
   if (aAfter) {
-    cellOffset++;
+    DebugOnly<bool> advanced = pointToInsert.AdvanceOffset();
+    NS_WARNING_ASSERTION(advanced,
+      "Failed to advance offset to after the old cell");
   }
 
-  //Don't let Rules System change the selection
+  // Don't let Rules System change the selection.
   AutoTransactionsConserveSelection dontChangeSelection(this);
-  return InsertNode(newCell, cellParent, cellOffset);
+  return InsertNode(*newCell, pointToInsert.AsRaw());
 }
 
 NS_IMETHODIMP
 HTMLEditor::SetColSpan(nsIDOMElement* aCell,
                        int32_t aColSpan)
 {
   NS_ENSURE_TRUE(aCell, NS_ERROR_NULL_POINTER);
   nsAutoString newSpan;
@@ -202,17 +210,21 @@ HTMLEditor::InsertTableCell(int32_t aNum
   for (int32_t i = 0; i < aNumber; i++) {
     nsCOMPtr<nsIDOMElement> newCell;
     rv = CreateElementWithDefaults(NS_LITERAL_STRING("td"),
                                    getter_AddRefs(newCell));
     if (NS_SUCCEEDED(rv) && newCell) {
       if (aAfter) {
         cellOffset++;
       }
-      rv = InsertNode(newCell, cellParent, cellOffset);
+      nsCOMPtr<nsIContent> cell = do_QueryInterface(newCell);
+      if (NS_WARN_IF(!cell)) {
+        return NS_ERROR_FAILURE;
+      }
+      rv = InsertNode(*cell, EditorRawDOMPoint(cellParent, cellOffset));
       if (NS_FAILED(rv)) {
         break;
       }
     }
   }
   // XXX This is perhaps the result of the last call of InsertNode() or
   //     CreateElementWithDefaults().
   return rv;
@@ -682,17 +694,17 @@ HTMLEditor::InsertTableRow(int32_t aNumb
         newRow->AppendChild(*newCell, result);
         if (NS_WARN_IF(result.Failed())) {
           return result.StealNSResult();
         }
       }
 
       // Use transaction system to insert the entire row+cells
       // (Note that rows are inserted at same childoffset each time)
-      rv = InsertNode(*newRow, *parentOfRow, newRowOffset);
+      rv = InsertNode(*newRow, EditorRawDOMPoint(parentOfRow, newRowOffset));
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
   // SetSelectionAfterTableEdit from AutoSelectionSetterAfterTableEdit will
   // access frame selection, so we need reframe.
   // Because GetCellAt depends on frame.
   nsCOMPtr<nsIPresShell> ps = GetPresShell();
@@ -2323,21 +2335,22 @@ HTMLEditor::MergeCells(nsCOMPtr<nsIDOMEl
       NS_ENSURE_SUCCESS(rv, rv);
       insertIndex = 0;
     } else {
       insertIndex = (int32_t)len;
     }
 
     // Move the contents
     while (cellToMerge->HasChildren()) {
-      nsCOMPtr<nsIDOMNode> cellChild = cellToMerge->GetLastChild()->AsDOMNode();
-      nsresult rv = DeleteNode(cellChild);
+      nsCOMPtr<nsIContent> cellChild = cellToMerge->GetLastChild();
+      // XXX We need HTMLEditor::DeleteNode(nsINode&).
+      nsresult rv = DeleteNode(cellChild->AsDOMNode());
       NS_ENSURE_SUCCESS(rv, rv);
 
-      rv = InsertNode(cellChild, aTargetCell, insertIndex);
+      rv = InsertNode(*cellChild, EditorRawDOMPoint(aTargetCell, insertIndex));
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
   // Delete cells whose contents were moved
   if (aDeleteCellToMerge) {
     return DeleteNode(aCellToMerge);
   }
--- a/editor/libeditor/TextEditRules.cpp
+++ b/editor/libeditor/TextEditRules.cpp
@@ -866,17 +866,18 @@ TextEditRules::WillSetText(Selection& aS
     RefPtr<nsIDocument> doc = textEditor->GetDocument();
     if (NS_WARN_IF(!doc)) {
       return NS_OK;
     }
     RefPtr<nsTextNode> newNode = EditorBase::CreateTextNode(*doc, tString);
     if (NS_WARN_IF(!newNode)) {
       return NS_OK;
     }
-    nsresult rv = textEditor->InsertNode(*newNode, *rootElement, 0);
+    nsresult rv =
+      textEditor->InsertNode(*newNode, EditorRawDOMPoint(rootElement, 0));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
     *aHandled = true;
 
     ASSERT_PASSWORD_LENGTHS_EQUAL();
 
     return NS_OK;
@@ -1443,21 +1444,28 @@ TextEditRules::CreateBogusNodeIfNeeded(S
   // set mBogusNode to be the newly created <br>
   mBogusNode = newContent;
 
   // Give it a special attribute.
   newContent->SetAttr(kNameSpaceID_None, kMOZEditorBogusNodeAttrAtom,
                       kMOZEditorBogusNodeValue, false);
 
   // Put the node in the document.
-  nsresult rv = mTextEditor->InsertNode(*mBogusNode, *body, 0);
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsresult rv =
+    mTextEditor->InsertNode(*mBogusNode, EditorRawDOMPoint(body, 0));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
 
   // Set selection.
-  aSelection->Collapse(body, 0);
+  ErrorResult error;
+  aSelection->Collapse(EditorRawDOMPoint(body, 0), error);
+  if (NS_WARN_IF(error.Failed())) {
+    error.SuppressException();
+  }
   return NS_OK;
 }
 
 
 nsresult
 TextEditRules::TruncateInsertionIfNeeded(Selection* aSelection,
                                          const nsAString* aInString,
                                          nsAString* aOutString,