Bug 1451672 - part 7: Rename EditorBase::DeleteNode() to EditorBase::DeleteNodeWithTransaction() r=m_kato
authorMasayuki Nakano <masayuki@d-toybox.com>
Tue, 10 Apr 2018 16:23:54 +0900
changeset 468360 81a8389b9daaf8049ab3934904849de7dc527232
parent 468359 28422b0eee9a95a153980bcd741d5ac7b094cb0c
child 468361 5e8f25ef1174d4af6ac4c16c02effa8c49c432ed
push id9165
push userasasaki@mozilla.com
push dateThu, 26 Apr 2018 21:04:54 +0000
treeherdermozilla-beta@064c3804de2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersm_kato
bugs1451672
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1451672 - part 7: Rename EditorBase::DeleteNode() to EditorBase::DeleteNodeWithTransaction() r=m_kato MozReview-Commit-ID: AQVVTjfXJv
editor/libeditor/EditorBase.cpp
editor/libeditor/EditorBase.h
editor/libeditor/HTMLEditRules.cpp
editor/libeditor/HTMLEditor.cpp
editor/libeditor/HTMLEditor.h
editor/libeditor/HTMLEditorDataTransfer.cpp
editor/libeditor/HTMLStyleEditor.cpp
editor/libeditor/HTMLTableEditor.cpp
editor/libeditor/TextEditRules.cpp
editor/libeditor/WSRunObject.cpp
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -1604,49 +1604,49 @@ EditorBase::JoinNodesWithTransaction(nsI
 
   return rv;
 }
 
 NS_IMETHODIMP
 EditorBase::DeleteNode(nsIDOMNode* aNode)
 {
   nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
-  NS_ENSURE_STATE(node);
-  return DeleteNode(node);
+  if (NS_WARN_IF(!node)) {
+    return NS_ERROR_INVALID_ARG;
+  }
+  return DeleteNodeWithTransaction(*node);
 }
 
 nsresult
-EditorBase::DeleteNode(nsINode* aNode)
-{
-  if (NS_WARN_IF(!aNode)) {
-    return NS_ERROR_INVALID_ARG;
-  }
-
+EditorBase::DeleteNodeWithTransaction(nsINode& aNode)
+{
   AutoRules beginRulesSniffing(this, EditAction::createNode,
                                nsIEditor::ePrevious);
 
   if (mRules && mRules->AsHTMLEditRules()) {
     RefPtr<HTMLEditRules> htmlEditRules = mRules->AsHTMLEditRules();
-    htmlEditRules->WillDeleteNode(aNode);
-  }
-
+    htmlEditRules->WillDeleteNode(&aNode);
+  }
+
+  // FYI: DeleteNodeTransaction grabs aNode while it's alive.  So, it's safe
+  //      to refer aNode even after calling DoTransaction().
   RefPtr<DeleteNodeTransaction> deleteNodeTransaction =
-    DeleteNodeTransaction::MaybeCreate(*this, *aNode);
+    DeleteNodeTransaction::MaybeCreate(*this, aNode);
   nsresult rv = deleteNodeTransaction ? DoTransaction(deleteNodeTransaction) :
                                         NS_ERROR_FAILURE;
 
   if (mTextServicesDocument && NS_SUCCEEDED(rv)) {
     RefPtr<TextServicesDocument> textServicesDocument = mTextServicesDocument;
-    textServicesDocument->DidDeleteNode(aNode);
+    textServicesDocument->DidDeleteNode(&aNode);
   }
 
   if (!mActionListeners.IsEmpty()) {
     AutoActionListenerArray listeners(mActionListeners);
     for (auto& listener : listeners) {
-      listener->DidDeleteNode(aNode->AsDOMNode(), rv);
+      listener->DidDeleteNode(aNode.AsDOMNode(), rv);
     }
   }
 
   NS_ENSURE_SUCCESS(rv, rv);
   return NS_OK;
 }
 
 /**
@@ -1690,18 +1690,20 @@ EditorBase::ReplaceContainer(Element* aO
   // to initialize mRangeUpdater.
   AutoReplaceContainerSelNotify selStateNotify(mRangeUpdater, aOldContainer,
                                                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);
+      if (NS_WARN_IF(!child)) {
+        return nullptr;
+      }
+      nsresult rv = DeleteNodeWithTransaction(*child);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return nullptr;
       }
 
       rv = InsertNodeWithTransaction(*child,
                                      EditorRawDOMPoint(newContainer,
                                                        newContainer->Length()));
       if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -1714,17 +1716,17 @@ EditorBase::ReplaceContainer(Element* aO
   NS_WARNING_ASSERTION(atOldContainer.IsSetAndValid(),
     "The old container might be moved by mutation observer");
   nsresult rv = InsertNodeWithTransaction(*newContainer, atOldContainer);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return nullptr;
   }
 
   // Delete old container.
-  rv = DeleteNode(aOldContainer);
+  rv = DeleteNodeWithTransaction(*aOldContainer);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return nullptr;
   }
 
   return newContainer.forget();
 }
 
 /**
@@ -1745,34 +1747,41 @@ EditorBase::RemoveContainer(nsIContent* 
   AutoRemoveContainerSelNotify selNotify(mRangeUpdater, aNode,
                                          pointToInsertChildren.GetContainer(),
                                          pointToInsertChildren.Offset(),
                                          aNode->GetChildCount());
 
   // Move all children from aNode to its parent.
   while (aNode->HasChildren()) {
     nsCOMPtr<nsIContent> child = aNode->GetLastChild();
-    nsresult rv = DeleteNode(child);
+    if (NS_WARN_IF(!child)) {
+      return NS_ERROR_FAILURE;
+    }
+    nsresult rv = DeleteNodeWithTransaction(*child);
     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 = InsertNodeWithTransaction(*child,
                                    EditorRawDOMPoint(
                                      pointToInsertChildren.GetContainer(),
                                      pointToInsertChildren.Offset()));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
-  return DeleteNode(aNode);
+  nsresult rv = DeleteNodeWithTransaction(*aNode);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  return NS_OK;
 }
 
 /**
  * InsertContainerAbove() inserts a new parent for inNode, which is contructed
  * to be of type aNodeType.  outNode becomes a child of inNode's earlier
  * parent.  Caller's responsibility to make sure inNode's can be child of
  * outNode, and outNode can be child of old parent.
  */
@@ -1809,17 +1818,17 @@ EditorBase::InsertContainerAbove(nsICont
       return nullptr;
     }
   }
 
   // Notify our internal selection state listener
   AutoInsertContainerSelNotify selNotify(mRangeUpdater);
 
   // Put aNode in the new container, first.
-  nsresult rv = DeleteNode(aNode);
+  nsresult rv = DeleteNodeWithTransaction(*aNode);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return nullptr;
   }
 
   {
     AutoTransactionsConserveSelection conserveSelection(this);
     rv = InsertNodeWithTransaction(*aNode, EditorRawDOMPoint(newContainer, 0));
     if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -1872,24 +1881,24 @@ EditorBase::MoveNode(nsIContent* aNode,
 
   // Need to adjust aOffset if we're moving aNode later in its current parent
   if (aParent == oldParent && oldOffset < aOffset) {
     // 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);
+  nsCOMPtr<nsIContent> nodeToBeMoved(aNode);
+  nsresult rv = DeleteNodeWithTransaction(*nodeToBeMoved);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
-  rv = InsertNodeWithTransaction(*aNode, EditorRawDOMPoint(aParent, aOffset));
+  rv = InsertNodeWithTransaction(*nodeToBeMoved,
+                                 EditorRawDOMPoint(aParent, aOffset));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
   return NS_OK;
 }
 
 void
 EditorBase::MoveAllChildren(nsINode& aContainer,
@@ -2870,17 +2879,17 @@ EditorBase::InsertTextIntoTextNodeImpl(c
   // longer in the document.  This does not break undo/redo, because all these
   // txns are wrapped in a parent PlaceHolder txn, and placeholder txns are
   // already savvy to having multiple ime txns inside them.
 
   // Delete empty IME text node if there is one
   if (isIMETransaction && mComposition) {
     Text* textNode = mComposition->GetContainerTextNode();
     if (textNode && !textNode->Length()) {
-      DeleteNode(textNode);
+      DeleteNodeWithTransaction(*textNode);
       mComposition->OnTextNodeRemoved();
       static_cast<CompositionTransaction*>(transaction.get())->MarkFixed();
     }
   }
 
   return rv;
 }
 
--- a/editor/libeditor/EditorBase.h
+++ b/editor/libeditor/EditorBase.h
@@ -330,19 +330,21 @@ public:
                        Text& aTextNode);
 
   NS_IMETHOD DeleteSelectionImpl(EDirection aAction,
                                  EStripWrappers aStripWrappers);
 
   already_AddRefed<Element> DeleteSelectionAndCreateElement(nsAtom& aTag);
 
   /**
-   * Helper routines for node/parent manipulations.
+   * DeleteNodeWithTransaction() removes aNode from the DOM tree.
+   *
+   * @param aNode       The node which will be removed form the DOM tree.
    */
-  nsresult DeleteNode(nsINode* aNode);
+  nsresult DeleteNodeWithTransaction(nsINode& aNode);
 
   /**
    * InsertNodeWithTransaction() 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
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -1569,17 +1569,20 @@ HTMLEditRules::WillLoadHTML(Selection* a
 
   // Delete mBogusNode if it exists. If we really need one,
   // it will be added during post-processing in AfterEditInner().
 
   if (mBogusNode) {
     if (NS_WARN_IF(!mHTMLEditor)) {
       return NS_ERROR_UNEXPECTED;
     }
-    mHTMLEditor->DeleteNode(mBogusNode);
+    RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
+    DebugOnly<nsresult> rv = htmlEditor->DeleteNodeWithTransaction(*mBogusNode);
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+      "Failed to remove the bogus node");
     mBogusNode = nullptr;
   }
 
   return NS_OK;
 }
 
 bool
 HTMLEditRules::CanContainParagraph(Element& aElement) const
@@ -2127,30 +2130,30 @@ HTMLEditRules::SplitMailCites(Selection*
   if (previousNodeOfSplitPoint) {
     nsresult rv =
       htmlEditor->IsEmptyNode(previousNodeOfSplitPoint, &bEmptyCite,
                               true, false);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
     if (bEmptyCite) {
-      rv = htmlEditor->DeleteNode(previousNodeOfSplitPoint);
+      rv = htmlEditor->DeleteNodeWithTransaction(*previousNodeOfSplitPoint);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
     }
   }
 
   if (citeNode) {
     nsresult rv = htmlEditor->IsEmptyNode(citeNode, &bEmptyCite, true, false);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
     if (bEmptyCite) {
-      rv = htmlEditor->DeleteNode(citeNode);
+      rv = htmlEditor->DeleteNodeWithTransaction(*citeNode);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
     }
   }
 
   *aHandled = true;
   return NS_OK;
@@ -2362,19 +2365,24 @@ HTMLEditRules::WillDeleteSelection(Selec
       return NS_OK;
     }
 
     if (wsType == WSType::special || wsType == WSType::br ||
         visNode->IsHTMLElement(nsGkAtoms::hr)) {
       // Short circuit for invisible breaks.  delete them and recurse.
       if (visNode->IsHTMLElement(nsGkAtoms::br) &&
           (!mHTMLEditor || !mHTMLEditor->IsVisibleBRElement(visNode))) {
-        NS_ENSURE_STATE(mHTMLEditor);
-        rv = mHTMLEditor->DeleteNode(visNode);
-        NS_ENSURE_SUCCESS(rv, rv);
+        if (NS_WARN_IF(!mHTMLEditor)) {
+          return NS_ERROR_FAILURE;
+        }
+        RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
+        rv = htmlEditor->DeleteNodeWithTransaction(*visNode);
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return rv;
+        }
         return WillDeleteSelection(aSelection, aAction, aStripWrappers,
                                    aCancel, aHandled);
       }
 
       // Special handling for backspace when positioned after <hr>
       if (aAction == nsIEditor::ePrevious &&
           visNode->IsHTMLElement(nsGkAtoms::hr)) {
         // Only if the caret is positioned at the end-of-hr-line position, we
@@ -2425,50 +2433,60 @@ HTMLEditRules::WillDeleteSelection(Selec
           int32_t otherOffset;
 
           wsObj.NextVisibleNode(EditorRawDOMPoint(startNode, startOffset),
                                 address_of(otherNode),
                                 &otherOffset, &otherWSType);
 
           if (otherWSType == WSType::br) {
             // Delete the <br>
-
-            NS_ENSURE_STATE(mHTMLEditor);
-            nsCOMPtr<nsIContent> otherContent(do_QueryInterface(otherNode));
-            rv = WSRunObject::PrepareToDeleteNode(mHTMLEditor, otherContent);
-            NS_ENSURE_SUCCESS(rv, rv);
-            NS_ENSURE_STATE(mHTMLEditor);
-            rv = mHTMLEditor->DeleteNode(otherNode);
-            NS_ENSURE_SUCCESS(rv, rv);
+            if (NS_WARN_IF(!mHTMLEditor) ||
+                NS_WARN_IF(!otherNode->IsContent())) {
+              return NS_ERROR_FAILURE;
+            }
+            nsIContent* otherContent = otherNode->AsContent();
+            RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
+            rv = WSRunObject::PrepareToDeleteNode(htmlEditor, otherContent);
+            if (NS_WARN_IF(NS_FAILED(rv))) {
+              return rv;
+            }
+            rv = htmlEditor->DeleteNodeWithTransaction(*otherContent);
+            if (NS_WARN_IF(NS_FAILED(rv))) {
+              return rv;
+            }
           }
 
           return NS_OK;
         }
         // Else continue with normal delete code
       }
 
+      if (NS_WARN_IF(!mHTMLEditor) ||
+          NS_WARN_IF(!visNode->IsContent())) {
+        return NS_ERROR_FAILURE;
+      }
+      RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
       // Found break or image, or hr.
-      NS_ENSURE_STATE(mHTMLEditor);
-      NS_ENSURE_STATE(visNode->IsContent());
-      rv = WSRunObject::PrepareToDeleteNode(mHTMLEditor, visNode->AsContent());
-      NS_ENSURE_SUCCESS(rv, rv);
+      rv = WSRunObject::PrepareToDeleteNode(htmlEditor, visNode->AsContent());
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
       // Remember sibling to visnode, if any
-      NS_ENSURE_STATE(mHTMLEditor);
-      nsCOMPtr<nsIContent> sibling = mHTMLEditor->GetPriorHTMLSibling(visNode);
+      nsCOMPtr<nsIContent> sibling = htmlEditor->GetPriorHTMLSibling(visNode);
       // Delete the node, and join like nodes if appropriate
-      NS_ENSURE_STATE(mHTMLEditor);
-      rv = mHTMLEditor->DeleteNode(visNode);
-      NS_ENSURE_SUCCESS(rv, rv);
+      rv = htmlEditor->DeleteNodeWithTransaction(*visNode);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
       // We did something, so let's say so.
       *aHandled = true;
       // Is there a prior node and are they siblings?
       nsCOMPtr<nsINode> stepbrother;
       if (sibling) {
-        NS_ENSURE_STATE(mHTMLEditor);
-        stepbrother = mHTMLEditor->GetNextHTMLSibling(sibling);
+        stepbrother = htmlEditor->GetNextHTMLSibling(sibling);
       }
       // Are they both text nodes?  If so, join them!
       if (startNode == stepbrother && startNode->GetAsText() &&
           sibling->GetAsText()) {
         EditorDOMPoint pt =
           JoinNearestEditableNodesWithTransaction(*sibling,
                                                   *startNode->AsContent());
         if (NS_WARN_IF(!pt.IsSet())) {
@@ -2524,19 +2542,24 @@ HTMLEditRules::WillDeleteSelection(Selec
       } else {
         NS_ENSURE_STATE(mHTMLEditor);
         leafNode = mHTMLEditor->GetFirstEditableLeaf(*visNode);
         leftNode = startNode;
         rightNode = leafNode;
       }
 
       if (otherNode->IsHTMLElement(nsGkAtoms::br)) {
-        NS_ENSURE_STATE(mHTMLEditor);
-        rv = mHTMLEditor->DeleteNode(otherNode);
-        NS_ENSURE_SUCCESS(rv, rv);
+        if (NS_WARN_IF(!mHTMLEditor)) {
+          return NS_ERROR_FAILURE;
+        }
+        RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
+        rv = htmlEditor->DeleteNodeWithTransaction(*otherNode);
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return rv;
+        }
         // XXX Only in this case, setting "handled" to true only when it
         //     succeeds?
         *aHandled = true;
         bDeletedBR = true;
       }
 
       // Don't cross table boundaries
       if (leftNode && rightNode &&
@@ -2880,17 +2903,18 @@ HTMLEditRules::DeleteNodeIfCollapsedText
   }
 
   if (NS_WARN_IF(!mHTMLEditor)) {
     return;
   }
 
   if (!mHTMLEditor->IsVisibleTextNode(*text)) {
     RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
-    htmlEditor->DeleteNode(&aNode);
+    DebugOnly<nsresult> rv = htmlEditor->DeleteNodeWithTransaction(aNode);
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to remove aNode");
   }
 }
 
 
 /**
  * InsertBRIfNeeded() determines if a br is needed for current selection to not
  * be spastic.  If so, it inserts one.  Callers responsibility to only call
  * with collapsed selection.
@@ -3104,17 +3128,17 @@ HTMLEditRules::TryToJoinBlocksWithTransa
         if (NS_WARN_IF(!atRightBlockChild.GetContainer()->GetParentElement())) {
           return EditActionIgnored(NS_ERROR_UNEXPECTED);
         }
         rightBlock = atRightBlockChild.GetContainer()->GetParentElement();
       }
     }
 
     // Do br adjustment.
-    nsCOMPtr<Element> brNode =
+    RefPtr<Element> brNode =
       CheckForInvisibleBR(*leftBlock, BRLocation::blockEnd);
     EditActionResult ret(NS_OK);
     if (NS_WARN_IF(mergeLists)) {
       // Since 2002, here was the following comment:
       // > The idea here is to take all children in rightList that are past
       // > offset, and pull them into leftlist.
       // However, this has never been performed because we are here only when
       // neither left list nor right list is a descendant of the other but
@@ -3136,17 +3160,18 @@ HTMLEditRules::TryToJoinBlocksWithTransa
                   -1, atRightBlockChild.Offset());
       if (retMoveBlock.Handled()) {
         ret.MarkAsHandled();
       }
       // Now, all children of rightBlock were moved to leftBlock.  So,
       // atRightBlockChild is now invalid.
       atRightBlockChild.Clear();
     }
-    if (brNode && NS_SUCCEEDED(htmlEditor->DeleteNode(brNode))) {
+    if (brNode &&
+        NS_SUCCEEDED(htmlEditor->DeleteNodeWithTransaction(*brNode))) {
       ret.MarkAsHandled();
     }
     return ret;
   }
 
   MOZ_DIAGNOSTIC_ASSERT(!atRightBlockChild.IsSet());
 
   // Offset below is where you find yourself in leftBlock when you traverse
@@ -3180,17 +3205,17 @@ HTMLEditRules::TryToJoinBlocksWithTransa
       } else {
         if (NS_WARN_IF(!leftBlockChild.GetContainer()->GetParentElement())) {
           return EditActionIgnored(NS_ERROR_UNEXPECTED);
         }
         leftBlock = leftBlockChild.GetContainer()->GetParentElement();
       }
     }
     // Do br adjustment.
-    nsCOMPtr<Element> brNode =
+    RefPtr<Element> brNode =
       CheckForInvisibleBR(*leftBlock, BRLocation::beforeBlock,
                           leftBlockChild.Offset());
     EditActionResult ret(NS_OK);
     if (mergeLists) {
       // XXX Why do we ignore the result of MoveContents()?
       int32_t offset = leftBlockChild.Offset();
       EditActionResult retMoveContents =
         MoveContents(*rightList, *leftList, &offset);
@@ -3256,17 +3281,18 @@ HTMLEditRules::TryToJoinBlocksWithTransa
       }
 
       ret |= MoveBlock(*previousContent.GetContainerAsElement(), *rightBlock,
                        previousContent.Offset(), 0);
       if (NS_WARN_IF(ret.Failed())) {
         return ret;
       }
     }
-    if (brNode && NS_SUCCEEDED(htmlEditor->DeleteNode(brNode))) {
+    if (brNode &&
+        NS_SUCCEEDED(htmlEditor->DeleteNodeWithTransaction(*brNode))) {
       ret.MarkAsHandled();
     }
     return ret;
   }
 
   MOZ_DIAGNOSTIC_ASSERT(!atRightBlockChild.IsSet());
   MOZ_DIAGNOSTIC_ASSERT(!leftBlockChild.IsSet());
 
@@ -3298,19 +3324,20 @@ HTMLEditRules::TryToJoinBlocksWithTransa
   } else {
     // Nodes are dissimilar types.
     ret |= MoveBlock(*leftBlock, *rightBlock, -1, 0);
     if (NS_WARN_IF(ret.Failed())) {
       return ret;
     }
   }
   if (brNode) {
-    rv = htmlEditor->DeleteNode(brNode);
-    // XXX In other top level if blocks, the result of DeleteNode()
-    //     is ignored.  Why does only this result is respected?
+    rv = htmlEditor->DeleteNodeWithTransaction(*brNode);
+    // XXX In other top level if blocks, the result of
+    //     DeleteNodeWithTransaction() is ignored.  Why does only this result
+    //     is respected?
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return ret.SetResult(rv);
     }
     ret.MarkAsHandled();
   }
   return ret;
 }
 
@@ -3324,30 +3351,36 @@ HTMLEditRules::MoveBlock(Element& aLeftB
   // GetNodesFromPoint is the workhorse that figures out what we wnat to move.
   nsresult rv = GetNodesFromPoint(EditorDOMPoint(&aRightBlock, aRightOffset),
                                   EditAction::makeList, arrayOfNodes,
                                   TouchContent::yes);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return EditActionIgnored(rv);
   }
 
+  if (NS_WARN_IF(!mHTMLEditor)) {
+    return EditActionIgnored(NS_ERROR_NOT_AVAILABLE);
+  }
+  RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
   EditActionResult ret(NS_OK);
   for (uint32_t i = 0; i < arrayOfNodes.Length(); i++) {
     // get the node to act on
     if (IsBlockNode(arrayOfNodes[i])) {
       // For block nodes, move their contents only, then delete block.
       ret |=
         MoveContents(*arrayOfNodes[i]->AsElement(), aLeftBlock, &aLeftOffset);
       if (NS_WARN_IF(ret.Failed())) {
         return ret;
       }
       if (NS_WARN_IF(!mHTMLEditor)) {
         return ret.SetResult(NS_ERROR_UNEXPECTED);
       }
-      rv = mHTMLEditor->DeleteNode(arrayOfNodes[i]);
+      rv = htmlEditor->DeleteNodeWithTransaction(*arrayOfNodes[i]);
+      NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+        "Failed to remove a block node");
       ret.MarkAsHandled();
     } else {
       // Otherwise move the content as is, checking against the DTD.
       ret |=
         MoveNodeSmart(*arrayOfNodes[i]->AsContent(), aLeftBlock, &aLeftOffset);
     }
   }
 
@@ -3391,17 +3424,17 @@ HTMLEditRules::MoveNodeSmart(nsIContent&
   EditActionResult ret(NS_OK);
   if (aNode.IsElement()) {
     ret = MoveContents(*aNode.AsElement(), aDestElement, aInOutDestOffset);
     if (NS_WARN_IF(ret.Failed())) {
       return ret;
     }
   }
 
-  nsresult rv = htmlEditor->DeleteNode(&aNode);
+  nsresult rv = htmlEditor->DeleteNodeWithTransaction(aNode);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return ret.SetResult(rv);
   }
   return ret.MarkAsHandled();
 }
 
 EditActionResult
 HTMLEditRules::MoveContents(Element& aElement,
@@ -3426,18 +3459,25 @@ HTMLEditRules::MoveContents(Element& aEl
 }
 
 
 nsresult
 HTMLEditRules::DeleteNonTableElements(nsINode* aNode)
 {
   MOZ_ASSERT(aNode);
   if (!HTMLEditUtils::IsTableElementButNotTable(aNode)) {
-    NS_ENSURE_STATE(mHTMLEditor);
-    return mHTMLEditor->DeleteNode(aNode);
+    if (NS_WARN_IF(!mHTMLEditor)) {
+      return NS_ERROR_NOT_AVAILABLE;
+    }
+    RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
+    nsresult rv = htmlEditor->DeleteNodeWithTransaction(*aNode);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+    return NS_OK;
   }
 
   AutoTArray<nsCOMPtr<nsIContent>, 10> childList;
   for (nsIContent* child = aNode->GetFirstChild();
        child; child = child->GetNextSibling()) {
     childList.AppendElement(child);
   }
 
@@ -3464,27 +3504,27 @@ HTMLEditRules::DidDeleteSelection(Select
 
   // find where we are
   EditorDOMPoint atStartOfSelection(EditorBase::GetStartPoint(aSelection));
   if (NS_WARN_IF(!atStartOfSelection.IsSet())) {
     return NS_ERROR_FAILURE;
   }
 
   // find any enclosing mailcite
-  nsCOMPtr<Element> citeNode =
+  RefPtr<Element> citeNode =
     GetTopEnclosingMailCite(*atStartOfSelection.GetContainer());
   if (citeNode) {
     bool isEmpty = true, seenBR = false;
     htmlEditor->IsEmptyNodeImpl(citeNode, &isEmpty, true, true, false,
                                 &seenBR);
     if (isEmpty) {
       EditorDOMPoint atCiteNode(citeNode);
       {
         AutoEditorDOMPointChildInvalidator lockOffset(atCiteNode);
-        nsresult rv = htmlEditor->DeleteNode(citeNode);
+        nsresult rv = htmlEditor->DeleteNodeWithTransaction(*citeNode);
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return rv;
         }
       }
       if (atCiteNode.IsSet() && seenBR) {
         RefPtr<Element> brNode = htmlEditor->CreateBR(atCiteNode);
         if (NS_WARN_IF(!brNode)) {
           return NS_ERROR_FAILURE;
@@ -3567,18 +3607,20 @@ HTMLEditRules::WillMakeList(Selection* a
   }
 
   // if no nodes, we make empty list.  Ditto if the user tried to make a list
   // of some # of breaks.
   if (arrayOfNodes.IsEmpty() || bOnlyBreaks) {
     // if only breaks, delete them
     if (bOnlyBreaks) {
       for (auto& node : arrayOfNodes) {
-        rv = htmlEditor->DeleteNode(node);
-        NS_ENSURE_SUCCESS(rv, rv);
+        rv = htmlEditor->DeleteNodeWithTransaction(*node);
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return rv;
+        }
       }
     }
 
     nsRange* firstRange = aSelection->GetRangeAt(0);
     if (NS_WARN_IF(!firstRange)) {
       return NS_ERROR_FAILURE;
     }
 
@@ -3652,17 +3694,17 @@ HTMLEditRules::WillMakeList(Selection* a
       curList = nullptr;
     }
 
     // If curNode is a break, delete it, and quit remembering prev list item.
     // If an empty inline container, delete it, but still remember the previous
     // item.
     if (htmlEditor->IsEditable(curNode) && (TextEditUtils::IsBreak(curNode) ||
                                             IsEmptyInline(curNode))) {
-      rv = htmlEditor->DeleteNode(curNode);
+      rv = htmlEditor->DeleteNodeWithTransaction(*curNode);
       NS_ENSURE_SUCCESS(rv, rv);
       if (TextEditUtils::IsBreak(curNode)) {
         prevListItem = nullptr;
       }
       continue;
     }
 
     if (HTMLEditUtils::IsList(curNode)) {
@@ -3960,18 +4002,20 @@ HTMLEditRules::MakeBasicBlock(Selection&
 
       // If the first editable node after selection is a br, consume it.
       // Otherwise it gets pushed into a following block after the split,
       // which is visually bad.
       nsCOMPtr<nsIContent> brNode =
         htmlEditor->GetNextEditableHTMLNode(pointToInsertBlock);
       if (brNode && brNode->IsHTMLElement(nsGkAtoms::br)) {
         AutoEditorDOMPointChildInvalidator lockOffset(pointToInsertBlock);
-        rv = htmlEditor->DeleteNode(brNode);
-        NS_ENSURE_SUCCESS(rv, rv);
+        rv = htmlEditor->DeleteNodeWithTransaction(*brNode);
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return rv;
+        }
       }
       // Do the splits!
       SplitNodeResult splitNodeResult =
         htmlEditor->SplitNodeDeepWithTransaction(
                       *curBlock, pointToInsertBlock,
                       SplitAtEdges::eDoNotCreateEmptyContainer);
       if (NS_WARN_IF(splitNodeResult.Failed())) {
         return splitNodeResult.Rv();
@@ -3992,18 +4036,20 @@ HTMLEditRules::MakeBasicBlock(Selection&
       return NS_OK;
     }
 
     // We are making a block.  Consume a br, if needed.
     nsCOMPtr<nsIContent> brNode =
       htmlEditor->GetNextEditableHTMLNodeInBlock(pointToInsertBlock);
     if (brNode && brNode->IsHTMLElement(nsGkAtoms::br)) {
       AutoEditorDOMPointChildInvalidator lockOffset(pointToInsertBlock);
-      rv = htmlEditor->DeleteNode(brNode);
-      NS_ENSURE_SUCCESS(rv, rv);
+      rv = htmlEditor->DeleteNodeWithTransaction(*brNode);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
       // We don't need to act on this node any more
       arrayOfNodes.RemoveElement(brNode);
     }
     // Make sure we can put a block here.
     SplitNodeResult splitNodeResult =
       MaybeSplitAncestorsForInsertWithTransaction(blockType,
                                                   pointToInsertBlock);
     if (NS_WARN_IF(splitNodeResult.Failed())) {
@@ -4015,18 +4061,20 @@ HTMLEditRules::MakeBasicBlock(Selection&
     if (NS_WARN_IF(!block)) {
       return NS_ERROR_FAILURE;
     }
     // 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);
+      rv = htmlEditor->DeleteNodeWithTransaction(*curNode);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
       arrayOfNodes.RemoveElementAt(0);
     }
     // Put selection in new block
     rv = aSelection.Collapse(block, 0);
     // Don't restore the selection
     selectionRestorer.Abort();
     NS_ENSURE_SUCCESS(rv, rv);
     return NS_OK;
@@ -4169,18 +4217,20 @@ HTMLEditRules::WillCSSIndent(Selection* 
       return NS_ERROR_FAILURE;
     }
     // 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];
-      rv = htmlEditor->DeleteNode(curNode);
-      NS_ENSURE_SUCCESS(rv, rv);
+      rv = htmlEditor->DeleteNodeWithTransaction(*curNode);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
       arrayOfNodes.RemoveElementAt(0);
     }
     // put selection in new block
     *aHandled = true;
     EditorRawDOMPoint atStartOfTheBlock(theBlock, 0);
     ErrorResult error;
     aSelection->Collapse(atStartOfTheBlock, error);
     // Don't restore the selection
@@ -4376,18 +4426,20 @@ HTMLEditRules::WillHTMLIndent(Selection*
     if (NS_WARN_IF(!theBlock)) {
       return NS_ERROR_FAILURE;
     }
     // 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];
-      rv = htmlEditor->DeleteNode(curNode);
-      NS_ENSURE_SUCCESS(rv, rv);
+      rv = htmlEditor->DeleteNodeWithTransaction(*curNode);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
       arrayOfNodes.RemoveElementAt(0);
     }
     // put selection in new block
     *aHandled = true;
     EditorRawDOMPoint atStartOfTheBlock(theBlock, 0);
     ErrorResult error;
     aSelection->Collapse(atStartOfTheBlock, error);
     // Don't restore the selection
@@ -4754,18 +4806,20 @@ HTMLEditRules::WillOutdent(Selection& aS
               // We have an embedded list, so move it out from under the parent
               // list. Be sure to put it after the parent list because this
               // loop iterates backwards through the parent's list of children.
 
               rv = htmlEditor->MoveNode(child, curParent, offset + 1);
               NS_ENSURE_SUCCESS(rv, rv);
             } else {
               // Delete any non-list items for now
-              rv = htmlEditor->DeleteNode(child);
-              NS_ENSURE_SUCCESS(rv, rv);
+              rv = htmlEditor->DeleteNodeWithTransaction(*child);
+              if (NS_WARN_IF(NS_FAILED(rv))) {
+                return rv;
+              }
             }
             child = curNode->GetLastChild();
           }
           // Delete the now-empty list
           rv = htmlEditor->RemoveBlockContainer(curNode);
           NS_ENSURE_SUCCESS(rv, rv);
         } else if (useCSS) {
           nsCOMPtr<Element> element;
@@ -5180,18 +5234,20 @@ HTMLEditRules::WillAlign(Selection& aSel
       // putting our div is not a block, then the br we found is in same block
       // we are, so it's safe to consume it.
       nsCOMPtr<nsIContent> sibling;
       if (pointToInsertDiv.GetChild()) {
         sibling = htmlEditor->GetNextHTMLSibling(pointToInsertDiv.GetChild());
       }
       if (sibling && !IsBlockNode(*sibling)) {
         AutoEditorDOMPointChildInvalidator lockOffset(pointToInsertDiv);
-        rv = htmlEditor->DeleteNode(brContent);
-        NS_ENSURE_SUCCESS(rv, rv);
+        rv = htmlEditor->DeleteNodeWithTransaction(*brContent);
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return rv;
+        }
       }
     }
     RefPtr<Element> div =
       htmlEditor->CreateNodeWithTransaction(*nsGkAtoms::div, pointToInsertDiv);
     if (NS_WARN_IF(!div)) {
       return NS_ERROR_FAILURE;
     }
     // Remember our new block for postprocessing
@@ -5422,19 +5478,19 @@ HTMLEditRules::CheckForEmptyBlock(nsINod
 
   if (NS_WARN_IF(!mHTMLEditor)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
   RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
 
   // If we are inside an empty block, delete it.  Note: do NOT delete table
   // elements this way.
-  nsCOMPtr<Element> block = htmlEditor->GetBlock(*aStartNode);
+  RefPtr<Element> block = htmlEditor->GetBlock(*aStartNode);
   bool bIsEmptyNode;
-  nsCOMPtr<Element> emptyBlock;
+  RefPtr<Element> emptyBlock;
   if (block && block != aBodyNode) {
     // Efficiency hack, avoiding IsEmptyNode() call when in body
     nsresult rv = htmlEditor->IsEmptyNode(block, &bIsEmptyNode, true, false);
     NS_ENSURE_SUCCESS(rv, rv);
     while (block && bIsEmptyNode && !HTMLEditUtils::IsTableElement(block) &&
            block != aBodyNode) {
       emptyBlock = block;
       block = htmlEditor->GetBlockNodeParent(emptyBlock);
@@ -5521,18 +5577,20 @@ HTMLEditRules::CheckForEmptyBlock(nsINod
           nsresult rv = aSelection->Collapse(afterEmptyBlock);
           NS_ENSURE_SUCCESS(rv, rv);
         }
       } else if (aAction != nsIEditor::eNone) {
         MOZ_CRASH("CheckForEmptyBlock doesn't support this action yet");
       }
     }
     *aHandled = true;
-    nsresult rv = htmlEditor->DeleteNode(emptyBlock);
-    NS_ENSURE_SUCCESS(rv, rv);
+    nsresult rv = htmlEditor->DeleteNodeWithTransaction(*emptyBlock);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
   }
   return NS_OK;
 }
 
 Element*
 HTMLEditRules::CheckForInvisibleBR(Element& aBlock,
                                    BRLocation aWhere,
                                    int32_t aOffset)
@@ -6919,18 +6977,20 @@ HTMLEditRules::ReturnInHeader(Selection&
       if (NS_WARN_IF(!brElement)) {
         return NS_ERROR_FAILURE;
       }
     }
   }
 
   // If the new (righthand) header node is empty, delete it
   if (IsEmptyBlockElement(aHeader, IgnoreSingleBR::eYes)) {
-    rv = htmlEditor->DeleteNode(&aHeader);
-    NS_ENSURE_SUCCESS(rv, rv);
+    rv = htmlEditor->DeleteNodeWithTransaction(aHeader);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
     // Layout tells the caret to blink in a weird place if we don't place a
     // break after the header.
     nsCOMPtr<nsIContent> sibling;
     if (aHeader.GetNextSibling()) {
       sibling = htmlEditor->GetNextHTMLSibling(aHeader.GetNextSibling());
     }
     if (!sibling || !sibling->IsHTMLElement(nsGkAtoms::br)) {
       ClearCachedStyles();
@@ -7208,18 +7268,20 @@ HTMLEditRules::SplitParagraph(
   }
   if (NS_WARN_IF(!splitDivOrPResult.DidSplit())) {
     return NS_ERROR_FAILURE;
   }
 
   // Get rid of the break, if it is visible (otherwise it may be needed to
   // prevent an empty p).
   if (aNextBRNode && htmlEditor->IsVisibleBRElement(aNextBRNode)) {
-    rv = htmlEditor->DeleteNode(aNextBRNode);
-    NS_ENSURE_SUCCESS(rv, rv);
+    rv = htmlEditor->DeleteNodeWithTransaction(*aNextBRNode);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
   }
 
   // Remove ID attribute on the paragraph from the existing right node.
   rv = htmlEditor->RemoveAttribute(aParentDivOrP.AsElement(), nsGkAtoms::id);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // We need to ensure to both paragraphs visible even if they are empty.
   // However, moz-<br> element isn't useful in this case because moz-<br>
@@ -7299,18 +7361,20 @@ HTMLEditRules::ReturnInListItem(Selectio
         htmlEditor->MoveNode(&aListItem,
                              atNextSiblingOfLeftList.GetContainer(),
                              atNextSiblingOfLeftList.Offset());
       NS_ENSURE_SUCCESS(rv, rv);
       rv = aSelection.Collapse(&aListItem, 0);
       NS_ENSURE_SUCCESS(rv, rv);
     } else {
       // Otherwise kill this item
-      nsresult rv = htmlEditor->DeleteNode(&aListItem);
-      NS_ENSURE_SUCCESS(rv, rv);
+      nsresult rv = htmlEditor->DeleteNodeWithTransaction(aListItem);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
 
       // Time to insert a paragraph
       nsAtom& paraAtom = DefaultParagraphSeparator();
       // We want a wrapper even if we separate with <br>
       RefPtr<Element> pNode =
         htmlEditor->CreateNodeWithTransaction(&paraAtom == nsGkAtoms::br ?
                                                 *nsGkAtoms::p : paraAtom,
                                               atNextSiblingOfLeftList);
@@ -7381,21 +7445,25 @@ HTMLEditRules::ReturnInListItem(Selectio
           MOZ_DIAGNOSTIC_ASSERT(itemOffset != -1);
           EditorRawDOMPoint atNextListItem(list, aListItem.GetNextSibling(),
                                            itemOffset + 1);
           RefPtr<Element> newListItem =
             htmlEditor->CreateNodeWithTransaction(*listAtom, atNextListItem);
           if (NS_WARN_IF(!newListItem)) {
             return NS_ERROR_FAILURE;
           }
-          rv = htmlEditor->DeleteNode(&aListItem);
-          NS_ENSURE_SUCCESS(rv, rv);
-          rv = aSelection.Collapse(newListItem, 0);
-          NS_ENSURE_SUCCESS(rv, rv);
-
+          rv = htmlEditor->DeleteNodeWithTransaction(aListItem);
+          if (NS_WARN_IF(NS_FAILED(rv))) {
+            return rv;
+          }
+          ErrorResult error;
+          aSelection.Collapse(EditorRawDOMPoint(newListItem, 0), error);
+          if (NS_WARN_IF(error.Failed())) {
+            return error.StealNSResult();
+          }
           return NS_OK;
         }
 
         nsCOMPtr<Element> brNode;
         rv = htmlEditor->CopyLastEditableChildStyles(prevItem,
                                                      &aListItem,
                                                      getter_AddRefs(brNode));
         NS_ENSURE_SUCCESS(rv, rv);
@@ -7694,18 +7762,20 @@ HTMLEditRules::ApplyBlockStyle(nsTArray<
     }
 
     if (curNode->IsHTMLElement(nsGkAtoms::br)) {
       // If the node is a break, we honor it by putting further nodes in a new
       // parent
       if (curBlock) {
         // Forget any previous block used for previous inline nodes
         curBlock = nullptr;
-        nsresult rv = htmlEditor->DeleteNode(curNode);
-        NS_ENSURE_SUCCESS(rv, rv);
+        nsresult rv = htmlEditor->DeleteNodeWithTransaction(*curNode);
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return rv;
+        }
         continue;
       }
 
       // The break is the first (or even only) node we encountered.  Create a
       // block for it.
       SplitNodeResult splitNodeResult =
         MaybeSplitAncestorsForInsertWithTransaction(aBlockTag, atCurNode);
       if (NS_WARN_IF(splitNodeResult.Failed())) {
@@ -8573,18 +8643,20 @@ HTMLEditRules::RemoveEmptyNodes()
     }
 
     iter->Next();
   }
 
   // now delete the empty nodes
   for (OwningNonNull<nsINode>& delNode : arrayOfEmptyNodes) {
     if (htmlEditor->IsModifiableNode(delNode)) {
-      rv = htmlEditor->DeleteNode(delNode);
-      NS_ENSURE_SUCCESS(rv, rv);
+      rv = htmlEditor->DeleteNodeWithTransaction(*delNode);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
     }
   }
 
   // Now delete the empty mailcites.  This is a separate step because we want
   // to pull out any br's and preserve them.
   for (OwningNonNull<nsINode>& delNode : arrayOfEmptyCites) {
     bool bIsEmptyNode;
     rv = htmlEditor->IsEmptyNode(delNode, &bIsEmptyNode, false, true);
@@ -8592,18 +8664,20 @@ HTMLEditRules::RemoveEmptyNodes()
     if (!bIsEmptyNode) {
       // We are deleting a cite that has just a br.  We want to delete cite,
       // but preserve br.
       RefPtr<Element> br = htmlEditor->CreateBR(EditorRawDOMPoint(delNode));
       if (NS_WARN_IF(!br)) {
         return NS_ERROR_FAILURE;
       }
     }
-    rv = htmlEditor->DeleteNode(delNode);
-    NS_ENSURE_SUCCESS(rv, rv);
+    rv = htmlEditor->DeleteNodeWithTransaction(*delNode);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
   }
 
   return NS_OK;
 }
 
 nsresult
 HTMLEditRules::SelectionEndpointInNode(nsINode* aNode,
                                        bool* aResult)
@@ -8798,18 +8872,20 @@ HTMLEditRules::RemoveListStructure(Eleme
         nsresult rv = PopListItem(child, &isOutOfList);
         NS_ENSURE_SUCCESS(rv, rv);
       } while (!isOutOfList);
     } else if (HTMLEditUtils::IsList(child)) {
       nsresult rv = RemoveListStructure(*child->AsElement());
       NS_ENSURE_SUCCESS(rv, rv);
     } else {
       // Delete any non-list items for now
-      nsresult rv = htmlEditor->DeleteNode(child);
-      NS_ENSURE_SUCCESS(rv, rv);
+      nsresult rv = htmlEditor->DeleteNodeWithTransaction(*child);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
     }
   }
 
   // Delete the now-empty list
   nsresult rv = htmlEditor->RemoveBlockContainer(aList);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
@@ -9428,18 +9504,20 @@ HTMLEditRules::WillAbsolutePosition(Sele
     if (NS_WARN_IF(!positionedDiv)) {
       return NS_ERROR_FAILURE;
     }
     // 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);
+      rv = htmlEditor->DeleteNodeWithTransaction(*curNode);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
       arrayOfNodes.RemoveElementAt(0);
     }
     // Put selection in new block
     *aHandled = true;
     rv = aSelection.Collapse(positionedDiv, 0);
     // Don't restore the selection
     selectionRestorer.Abort();
     NS_ENSURE_SUCCESS(rv, rv);
@@ -9687,29 +9765,32 @@ HTMLEditRules::DocumentModified()
 
 void
 HTMLEditRules::DocumentModifiedWorker()
 {
   if (!mHTMLEditor) {
     return;
   }
 
-  // DeleteNode below may cause a flush, which could destroy the editor
+  // DeleteNodeWithTransaction() below may cause a flush, which could destroy
+  // the editor
   nsAutoScriptBlockerSuppressNodeRemoved scriptBlocker;
 
   RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
   RefPtr<Selection> selection = htmlEditor->GetSelection();
   if (!selection) {
     return;
   }
 
   // Delete our bogus node, if we have one, since the document might not be
   // empty any more.
   if (mBogusNode) {
-    htmlEditor->DeleteNode(mBogusNode);
+    DebugOnly<nsresult> rv = htmlEditor->DeleteNodeWithTransaction(*mBogusNode);
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+      "Failed to remove the bogus node");
     mBogusNode = nullptr;
   }
 
   // Try to recreate the bogus node if needed.
   CreateBogusNodeIfNeeded(selection);
 }
 
 } // namespace mozilla
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -1251,17 +1251,17 @@ HTMLEditor::ReplaceHeadContentsWithHTML(
            err.ErrorCodeAsInt());
 #endif
     return err.StealNSResult();
   }
   NS_ENSURE_TRUE(docfrag, NS_ERROR_NULL_POINTER);
 
   // First delete all children in head
   while (nsCOMPtr<nsIContent> child = headNode->GetFirstChild()) {
-    nsresult rv = DeleteNode(child);
+    nsresult rv = DeleteNodeWithTransaction(*child);
     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()) {
@@ -3178,40 +3178,55 @@ HTMLEditor::DeleteSelectionImpl(EDirecti
   if (content && !IsBlockNode(content) && !content->Length() &&
       content->IsEditable() && content != content->GetEditingHost()) {
     while (content->GetParent() && !IsBlockNode(content->GetParent()) &&
            content->GetParent()->Length() == 1 &&
            content->GetParent()->IsEditable() &&
            content->GetParent() != content->GetEditingHost()) {
       content = content->GetParent();
     }
-    rv = DeleteNode(content);
+    rv = DeleteNodeWithTransaction(*content);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
 
 nsresult
-HTMLEditor::DeleteNode(nsINode* aNode)
+HTMLEditor::DeleteNodeWithTransaction(nsINode& aNode)
 {
-  return DeleteNode(aNode->AsDOMNode());
+  if (NS_WARN_IF(!aNode.IsContent())) {
+    return NS_ERROR_INVALID_ARG;
+  }
+  // Do nothing if the node is read-only.
+  // XXX This is not a override method of EditorBase's method.  This might
+  //     cause not called accidentally.  We need to investigate this issue.
+  if (NS_WARN_IF(!IsModifiableNode(aNode.AsContent()) &&
+                 !IsMozEditorBogusNode(aNode.AsContent()))) {
+    return NS_ERROR_FAILURE;
+  }
+  nsresult rv = EditorBase::DeleteNodeWithTransaction(aNode);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  return NS_OK;
 }
 
 NS_IMETHODIMP
-HTMLEditor::DeleteNode(nsIDOMNode* aNode)
+HTMLEditor::DeleteNode(nsIDOMNode* aDOMNode)
 {
-  // do nothing if the node is read-only
-  nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
-  if (NS_WARN_IF(!IsModifiableNode(content) &&
-                 !IsMozEditorBogusNode(content))) {
-    return NS_ERROR_FAILURE;
-  }
-
-  return EditorBase::DeleteNode(aNode);
+  nsCOMPtr<nsINode> node = do_QueryInterface(aDOMNode);
+  if (NS_WARN_IF(!node)) {
+    return NS_ERROR_INVALID_ARG;
+  }
+  nsresult rv = DeleteNodeWithTransaction(*node);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  return NS_OK;
 }
 
 nsresult
 HTMLEditor::DeleteText(CharacterData& aCharData,
                        uint32_t aOffset,
                        uint32_t aLength)
 {
   // Do nothing if the node is read-only
@@ -4457,30 +4472,34 @@ HTMLEditor::AreNodesSameType(nsIContent*
                                          aNode2->AsElement());
 }
 
 nsresult
 HTMLEditor::CopyLastEditableChildStyles(nsINode* aPreviousBlock,
                                         nsINode* aNewBlock,
                                         Element** aOutBrNode)
 {
-  nsCOMPtr<nsINode> newBlock = do_QueryInterface(aNewBlock);
-  NS_ENSURE_STATE(newBlock || !aNewBlock);
+  if (NS_WARN_IF(!aNewBlock)) {
+    return NS_ERROR_INVALID_ARG;
+  }
+  nsCOMPtr<nsINode> newBlock(aNewBlock);
   *aOutBrNode = nullptr;
-  nsCOMPtr<nsINode> child, tmp;
-  // first, clear out aNewBlock.  Contract is that we want only the styles from previousBlock.
-  child = aNewBlock->GetFirstChild();
-  while (child) {
-    nsresult rv = DeleteNode(child);
-    NS_ENSURE_SUCCESS(rv, rv);
-    child = aNewBlock->GetFirstChild();
+  // First, clear out aNewBlock.  Contract is that we want only the styles
+  // from aPreviousBlock.
+  for (nsCOMPtr<nsINode> child = aNewBlock->GetFirstChild();
+       child;
+       child = aNewBlock->GetFirstChild()) {
+    nsresult rv = DeleteNodeWithTransaction(*child);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
   }
   // now find and clone the styles
-  child = aPreviousBlock;
-  tmp = aPreviousBlock;
+  nsCOMPtr<nsINode> child = aPreviousBlock;
+  nsCOMPtr<nsINode> tmp = aPreviousBlock;
   while (tmp) {
     child = tmp;
     tmp = GetLastEditableChild(*child);
   }
   while (child && TextEditUtils::IsBreak(child)) {
     child = GetPreviousEditableHTMLNode(*child);
   }
   nsCOMPtr<Element> newStyles, deepestStyle;
--- a/editor/libeditor/HTMLEditor.h
+++ b/editor/libeditor/HTMLEditor.h
@@ -380,18 +380,28 @@ public:
    */
   nsresult CollapseAdjacentTextNodes(nsRange* aRange);
 
   virtual bool AreNodesSameType(nsIContent* aNode1,
                                 nsIContent* aNode2) override;
 
   NS_IMETHOD DeleteSelectionImpl(EDirection aAction,
                                  EStripWrappers aStripWrappers) override;
-  nsresult DeleteNode(nsINode* aNode);
+
+  /**
+   * DeleteNodeWithTransaction() removes aNode from the DOM tree if it's
+   * modifiable.  Note that this is not an override of same method of
+   * EditorBase.
+   *
+   * @param aNode       The node to be removed from the DOM tree.
+   */
+  nsresult DeleteNodeWithTransaction(nsINode& aNode);
+
   NS_IMETHOD DeleteNode(nsIDOMNode* aNode) override;
+
   nsresult DeleteText(dom::CharacterData& aTextNode, uint32_t aOffset,
                       uint32_t aLength);
   virtual nsresult
   InsertTextImpl(nsIDocument& aDocument,
                  const nsAString& aStringToInsert,
                  const EditorRawDOMPoint& aPointToInsert,
                  EditorRawDOMPoint* aPointAfterInsertedString =
                    nullptr) override;
--- a/editor/libeditor/HTMLEditorDataTransfer.cpp
+++ b/editor/libeditor/HTMLEditorDataTransfer.cpp
@@ -351,18 +351,20 @@ HTMLEditor::DoInsertHTMLWithContext(cons
     // if there are any invisible br's after our insertion point, remove them.
     // this is because if there is a br at end of what we paste, it will make
     // the invisible br visible.
     WSRunObject wsObj(this, pointToInsert);
     if (wsObj.mEndReasonNode &&
         TextEditUtils::IsBreak(wsObj.mEndReasonNode) &&
         !IsVisibleBRElement(wsObj.mEndReasonNode)) {
       AutoEditorDOMPointChildInvalidator lockOffset(pointToInsert);
-      rv = DeleteNode(wsObj.mEndReasonNode);
-      NS_ENSURE_SUCCESS(rv, rv);
+      rv = DeleteNodeWithTransaction(*wsObj.mEndReasonNode);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
     }
 
     // Remember if we are in a link.
     bool bStartedInLink = IsInLink(pointToInsert.GetContainer());
 
     // Are we in a text node? If so, split it.
     if (pointToInsert.IsInTextNode()) {
       SplitNodeResult splitNodeResult =
@@ -486,17 +488,17 @@ HTMLEditor::DoInsertHTMLWithContext(cons
             if (HTMLEditUtils::IsListItem(pointToInsert.GetContainer())) {
               bool isEmpty;
               rv = IsEmptyNode(pointToInsert.GetContainer(), &isEmpty, true);
               if (NS_SUCCEEDED(rv) && isEmpty) {
                 if (NS_WARN_IF(!pointToInsert.GetContainer()->
                                                 GetParentNode())) {
                   // Is it an orphan node?
                 } else {
-                  DeleteNode(pointToInsert.GetContainer());
+                  DeleteNodeWithTransaction(*pointToInsert.GetContainer());
                   pointToInsert.Set(pointToInsert.GetContainer());
                 }
               }
             }
             EditorDOMPoint insertedPoint =
               InsertNodeIntoProperAncestor(
                 *firstChild, pointToInsert,
                 SplitAtEdges::eDoNotCreateEmptyContainer);
--- a/editor/libeditor/HTMLStyleEditor.cpp
+++ b/editor/libeditor/HTMLStyleEditor.cpp
@@ -591,18 +591,20 @@ HTMLEditor::ClearStyle(nsCOMPtr<nsINode>
                                      getter_AddRefs(rightNode));
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (leftNode) {
     bool bIsEmptyNode;
     IsEmptyNode(leftNode, &bIsEmptyNode, false, true);
     if (bIsEmptyNode) {
       // delete leftNode if it became empty
-      rv = DeleteNode(leftNode);
-      NS_ENSURE_SUCCESS(rv, rv);
+      rv = DeleteNodeWithTransaction(*leftNode);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
     }
   }
   if (rightNode) {
     nsCOMPtr<nsINode> secondSplitParent = GetLeftmostChild(rightNode);
     // don't try to split non-containers (br's, images, hr's, etc.)
     if (!secondSplitParent) {
       secondSplitParent = rightNode;
     }
@@ -622,18 +624,20 @@ HTMLEditor::ClearStyle(nsCOMPtr<nsINode>
                               getter_AddRefs(rightNode));
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (rightNode) {
       bool bIsEmptyNode;
       IsEmptyNode(rightNode, &bIsEmptyNode, false, true);
       if (bIsEmptyNode) {
         // delete rightNode if it became empty
-        rv = DeleteNode(rightNode);
-        NS_ENSURE_SUCCESS(rv, rv);
+        rv = DeleteNodeWithTransaction(*rightNode);
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return rv;
+        }
       }
     }
 
     if (!leftNode) {
       return NS_OK;
     }
 
     // should be impossible to not get a new leftnode here
--- a/editor/libeditor/HTMLTableEditor.cpp
+++ b/editor/libeditor/HTMLTableEditor.cpp
@@ -833,18 +833,24 @@ HTMLEditor::DeleteTableCell(int32_t aNum
         }
         if (!deleteCol) {
           // First get the next cell to delete
           nsCOMPtr<nsIDOMElement> nextCell;
           rv = GetNextSelectedCell(nullptr, getter_AddRefs(nextCell));
           NS_ENSURE_SUCCESS(rv, rv);
 
           // Then delete the cell
-          rv = DeleteNode(cell);
-          NS_ENSURE_SUCCESS(rv, rv);
+          nsCOMPtr<nsINode> cellToBeRemoved = do_QueryInterface(cell);
+          if (NS_WARN_IF(!cellToBeRemoved)) {
+            return NS_ERROR_FAILURE;
+          }
+          rv = DeleteNodeWithTransaction(*cellToBeRemoved);
+          if (NS_WARN_IF(NS_FAILED(rv))) {
+            return rv;
+          }
 
           // The next cell to delete
           cell = nextCell;
           if (cell) {
             rv = GetCellIndexes(cell, &startRowIndex, &startColIndex);
             NS_ENSURE_SUCCESS(rv, rv);
           }
         }
@@ -886,20 +892,25 @@ HTMLEditor::DeleteTableCell(int32_t aNum
         // More than 1 cell in the row
 
         // The setCaret object will call AutoSelectionSetterAfterTableEdit in its
         // destructor
         AutoSelectionSetterAfterTableEdit setCaret(*this, table, startRowIndex,
                                                    startColIndex, ePreviousColumn,
                                                    false);
         AutoTransactionsConserveSelection dontChangeSelection(this);
-
-        rv = DeleteNode(cell);
+        nsCOMPtr<nsINode> cellToBeRemoved = do_QueryInterface(cell);
+        if (NS_WARN_IF(!cellToBeRemoved)) {
+          return NS_ERROR_FAILURE;
+        }
+        rv = DeleteNodeWithTransaction(*cellToBeRemoved);
         // If we fail, don't try to delete any more cells???
-        NS_ENSURE_SUCCESS(rv, rv);
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return rv;
+        }
       }
     }
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HTMLEditor::DeleteTableCellContents()
@@ -958,18 +969,20 @@ HTMLEditor::DeleteCellContents(nsIDOMEle
 {
   nsCOMPtr<Element> cell = do_QueryInterface(aCell);
   NS_ENSURE_TRUE(cell, NS_ERROR_NULL_POINTER);
 
   // Prevent rules testing until we're done
   AutoRules beginRulesSniffing(this, EditAction::deleteNode, nsIEditor::eNext);
 
   while (nsCOMPtr<nsINode> child = cell->GetLastChild()) {
-    nsresult rv = DeleteNode(child);
-    NS_ENSURE_SUCCESS(rv, rv);
+    nsresult rv = DeleteNodeWithTransaction(*child);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HTMLEditor::DeleteTableColumn(int32_t aNumber)
 {
   RefPtr<Selection> selection;
@@ -1116,18 +1129,24 @@ HTMLEditor::DeleteColumn(nsIDOMElement* 
           rv = DeleteRow(aTable, startRowIndex);
           NS_ENSURE_SUCCESS(rv, rv);
 
           // Note that we don't incremenet rowIndex
           // since a row was deleted and "next"
           // row now has current rowIndex
         } else {
           // A more "normal" deletion
-          rv = DeleteNode(cell);
-          NS_ENSURE_SUCCESS(rv, rv);
+          nsCOMPtr<nsINode> cellToBeRemoved = do_QueryInterface(cell);
+          if (NS_WARN_IF(!cellToBeRemoved)) {
+            return NS_ERROR_FAILURE;
+          }
+          rv = DeleteNodeWithTransaction(*cellToBeRemoved);
+          if (NS_WARN_IF(NS_FAILED(rv))) {
+            return rv;
+          }
 
           //Skip over any rows spanned by this cell
           rowIndex += actualRowSpan;
         }
       }
     }
   } while (cell);
 
@@ -1307,18 +1326,24 @@ HTMLEditor::DeleteRow(nsIDOMElement* aTa
 
   // Delete the entire row
   nsCOMPtr<nsIDOMElement> parentRow;
   rv = GetElementOrParentByTagName(NS_LITERAL_STRING("tr"), cellInDeleteRow,
                                    getter_AddRefs(parentRow));
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (parentRow) {
-    rv = DeleteNode(parentRow);
-    NS_ENSURE_SUCCESS(rv, rv);
+    nsCOMPtr<nsINode> rowToBeRemoved = do_QueryInterface(parentRow);
+    if (NS_WARN_IF(!rowToBeRemoved)) {
+      return NS_ERROR_FAILURE;
+    }
+    rv = DeleteNodeWithTransaction(*rowToBeRemoved);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
   }
 
   // Now we can set new rowspans for cells stored above
   for (uint32_t i = 0, n = spanCellList.Length(); i < n; i++) {
     nsIDOMElement *cellPtr = spanCellList[i];
     if (cellPtr) {
       rv = SetRowSpan(cellPtr, newSpanList[i]);
       NS_ENSURE_SUCCESS(rv, rv);
@@ -2164,19 +2189,24 @@ HTMLEditor::JoinTableCells(bool aMergeNo
     // All cell contents are merged. Delete the empty cells we accumulated
     // Prevent rules testing until we're done
     AutoRules beginRulesSniffing(this, EditAction::deleteNode,
                                  nsIEditor::eNext);
 
     for (uint32_t i = 0, n = deleteList.Length(); i < n; i++) {
       nsIDOMElement *elementPtr = deleteList[i];
       if (elementPtr) {
-        nsCOMPtr<nsIDOMNode> node = do_QueryInterface(elementPtr);
-        rv = DeleteNode(node);
-        NS_ENSURE_SUCCESS(rv, rv);
+        nsCOMPtr<nsINode> nodeToBeRemoved = do_QueryInterface(elementPtr);
+        if (NS_WARN_IF(!nodeToBeRemoved)) {
+          return NS_ERROR_FAILURE;
+        }
+        rv = DeleteNodeWithTransaction(*nodeToBeRemoved);
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return rv;
+        }
       }
     }
     // Cleanup selection: remove ranges where cells were deleted
     RefPtr<Selection> selection = GetSelection();
     NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
 
     uint32_t rangeCount = selection->RangeCount();
 
@@ -2288,44 +2318,60 @@ HTMLEditor::MergeCells(nsCOMPtr<nsIDOMEl
     //  we insert at index 0
     int32_t insertIndex = 0;
 
     // Start inserting just after last child
     uint32_t len = targetCell->GetChildCount();
     if (len == 1 && IsEmptyCell(targetCell)) {
       // Delete the empty node
       nsIContent* cellChild = targetCell->GetFirstChild();
-      nsresult rv = DeleteNode(cellChild->AsDOMNode());
-      NS_ENSURE_SUCCESS(rv, rv);
+      if (NS_WARN_IF(!cellChild)) {
+        return NS_ERROR_FAILURE;
+      }
+      nsresult rv = DeleteNodeWithTransaction(*cellChild);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
       insertIndex = 0;
     } else {
       insertIndex = (int32_t)len;
     }
 
     // Move the contents
     while (cellToMerge->HasChildren()) {
       nsCOMPtr<nsIContent> cellChild = cellToMerge->GetLastChild();
-      // XXX We need HTMLEditor::DeleteNode(nsINode&).
-      nsresult rv = DeleteNode(cellChild->AsDOMNode());
-      NS_ENSURE_SUCCESS(rv, rv);
-
+      if (NS_WARN_IF(!cellChild)) {
+        return NS_ERROR_FAILURE;
+      }
+      nsresult rv = DeleteNodeWithTransaction(*cellChild);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
       rv = InsertNodeWithTransaction(*cellChild,
                                      EditorRawDOMPoint(aTargetCell,
                                                        insertIndex));
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
     }
   }
 
-  // Delete cells whose contents were moved
-  if (aDeleteCellToMerge) {
-    return DeleteNode(aCellToMerge);
+  if (!aDeleteCellToMerge) {
+    return NS_OK;
   }
 
+  // Delete cells whose contents were moved.
+  nsCOMPtr<nsIContent> cellToBeRemoved = do_QueryInterface(aCellToMerge);
+  if (NS_WARN_IF(!cellToBeRemoved)) {
+    return NS_ERROR_INVALID_ARG;
+  }
+  nsresult rv = DeleteNodeWithTransaction(*cellToBeRemoved);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
   return NS_OK;
 }
 
 
 nsresult
 HTMLEditor::FixBadRowSpan(nsIDOMElement* aTable,
                           int32_t aRowIndex,
                           int32_t& aNewRowCount)
--- a/editor/libeditor/TextEditRules.cpp
+++ b/editor/libeditor/TextEditRules.cpp
@@ -382,18 +382,23 @@ TextEditRules::WillInsert(Selection& aSe
     return;
   }
 
   // initialize out param
   *aCancel = false;
 
   // check for the magic content node and delete it if it exists
   if (mBogusNode) {
-    NS_ENSURE_TRUE_VOID(mTextEditor);
-    mTextEditor->DeleteNode(mBogusNode);
+    if (NS_WARN_IF(!mTextEditor)) {
+      return; // XXX Shouldn't we release mBogusNode now?
+    }
+    RefPtr<TextEditor> textEditor(mTextEditor);
+    DebugOnly<nsresult> rv = textEditor->DeleteNodeWithTransaction(*mBogusNode);
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+      "Failed to remove the bogus node");
     mBogusNode = nullptr;
   }
 }
 
 nsresult
 TextEditRules::DidInsert(Selection* aSelection,
                          nsresult aResult)
 {
@@ -1083,17 +1088,19 @@ TextEditRules::DidDeleteSelection(Select
 
   // Delete empty text nodes at selection.
   if (selectionStartPoint.IsInTextNode() &&
       !selectionStartPoint.GetContainer()->Length()) {
     if (NS_WARN_IF(!mTextEditor)) {
       return NS_ERROR_NOT_AVAILABLE;
     }
     RefPtr<TextEditor> textEditor(mTextEditor);
-    nsresult rv = textEditor->DeleteNode(selectionStartPoint.GetContainer());
+    nsresult rv =
+      textEditor->DeleteNodeWithTransaction(
+                    *selectionStartPoint.GetContainer());
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
     // Be aware, mTextEditor may be nullptr here.
   }
 
   if (mDidExplicitlySetInterline) {
     return NS_OK;
--- a/editor/libeditor/WSRunObject.cpp
+++ b/editor/libeditor/WSRunObject.cpp
@@ -1357,21 +1357,24 @@ WSRunObject::DeleteRange(const EditorDOM
   // MOOSE: this routine needs to be modified to preserve the integrity of the
   // wsFragment info.
 
   if (aStartPoint == aEndPoint) {
     // Nothing to delete
     return NS_OK;
   }
 
+  MOZ_ASSERT(mHTMLEditor);
+  RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
+
   if (aStartPoint.GetContainer() == aEndPoint.GetContainer() &&
       aStartPoint.IsInTextNode()) {
-    return mHTMLEditor->DeleteText(*aStartPoint.GetContainerAsText(),
-                                   aStartPoint.Offset(),
-                                   aEndPoint.Offset() - aStartPoint.Offset());
+    return htmlEditor->DeleteText(*aStartPoint.GetContainerAsText(),
+                                  aStartPoint.Offset(),
+                                  aEndPoint.Offset() - aStartPoint.Offset());
   }
 
   RefPtr<nsRange> range;
   int32_t count = mNodeArray.Length();
   int32_t idx = mNodeArray.IndexOf(aStartPoint.GetContainer());
   if (idx == -1) {
     // If our starting point wasn't one of our ws text nodes, then just go
     // through them from the beginning.
@@ -1381,26 +1384,26 @@ WSRunObject::DeleteRange(const EditorDOM
     RefPtr<Text> node = mNodeArray[idx];
     if (!node) {
       // We ran out of ws nodes; must have been deleting to end
       return NS_OK;
     }
     if (node == aStartPoint.GetContainer()) {
       if (!aStartPoint.IsEndOfContainer()) {
         nsresult rv =
-          mHTMLEditor->DeleteText(*node, aStartPoint.Offset(),
-                                  aStartPoint.GetContainer()->Length() -
-                                    aStartPoint.Offset());
+          htmlEditor->DeleteText(*node, aStartPoint.Offset(),
+                                 aStartPoint.GetContainer()->Length() -
+                                   aStartPoint.Offset());
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return rv;
         }
       }
     } else if (node == aEndPoint.GetContainer()) {
       if (!aEndPoint.IsStartOfContainer()) {
-        nsresult rv = mHTMLEditor->DeleteText(*node, 0, aEndPoint.Offset());
+        nsresult rv = htmlEditor->DeleteText(*node, 0, aEndPoint.Offset());
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return rv;
         }
       }
       break;
     } else {
       if (!range) {
         range = new nsRange(aStartPoint.GetContainer());
@@ -1414,17 +1417,17 @@ WSRunObject::DeleteRange(const EditorDOM
         nsRange::CompareNodeToRange(node, range, &nodeBefore, &nodeAfter);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
       if (nodeAfter) {
         break;
       }
       if (!nodeBefore) {
-        rv = mHTMLEditor->DeleteNode(node);
+        rv = htmlEditor->DeleteNodeWithTransaction(*node);
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return rv;
         }
         mNodeArray.RemoveElement(node);
         --count;
         --idx;
       }
     }