Bug 1619914 - part 1: Make each transaction class grab their members with local variable before touching the DOM tree r=m_kato
☠☠ backed out by efd779b64b3f ☠ ☠
authorMasayuki Nakano <masayuki@d-toybox.com>
Fri, 03 Apr 2020 01:38:22 +0000
changeset 521961 876b1031a6ae41a87ed146976f279b96bde9c7f6
parent 521960 7f069649d6cf0d7d8cba14cfd987e835509b22fa
child 521962 d3816f82c0b9d4ceca0bb2ad177694164ed0921f
push id37280
push useropoprus@mozilla.com
push dateFri, 03 Apr 2020 21:40:10 +0000
treeherdermozilla-central@cf48e59e88de [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersm_kato
bugs1619914
milestone76.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 1619914 - part 1: Make each transaction class grab their members with local variable before touching the DOM tree r=m_kato Differential Revision: https://phabricator.services.mozilla.com/D69302
editor/libeditor/CSSEditUtils.cpp
editor/libeditor/ChangeAttributeTransaction.cpp
editor/libeditor/ChangeStyleTransaction.cpp
editor/libeditor/ChangeStyleTransaction.h
editor/libeditor/CompositionTransaction.cpp
editor/libeditor/CreateElementTransaction.cpp
editor/libeditor/CreateElementTransaction.h
editor/libeditor/DeleteNodeTransaction.cpp
editor/libeditor/DeleteNodeTransaction.h
editor/libeditor/DeleteRangeTransaction.cpp
editor/libeditor/DeleteTextTransaction.cpp
editor/libeditor/EditorBase.cpp
editor/libeditor/InsertNodeTransaction.cpp
editor/libeditor/InsertTextTransaction.cpp
editor/libeditor/JoinNodeTransaction.cpp
editor/libeditor/JoinNodeTransaction.h
editor/libeditor/SplitNodeTransaction.cpp
editor/libeditor/SplitNodeTransaction.h
--- a/editor/libeditor/CSSEditUtils.cpp
+++ b/editor/libeditor/CSSEditUtils.cpp
@@ -378,18 +378,22 @@ bool CSSEditUtils::IsCSSEditableProperty
   return false;
 }
 
 // The lowest level above the transaction; adds the CSS declaration
 // "aProperty : aValue" to the inline styles carried by aElement
 nsresult CSSEditUtils::SetCSSProperty(Element& aElement, nsAtom& aProperty,
                                       const nsAString& aValue,
                                       bool aSuppressTxn) {
+  nsCOMPtr<nsStyledElement> styledElement = do_QueryInterface(&aElement);
+  if (NS_WARN_IF(!styledElement)) {
+    return NS_ERROR_INVALID_ARG;
+  }
   RefPtr<ChangeStyleTransaction> transaction =
-      ChangeStyleTransaction::Create(aElement, aProperty, aValue);
+      ChangeStyleTransaction::Create(*styledElement, aProperty, aValue);
   if (aSuppressTxn) {
     return transaction->DoTransaction();
   }
   if (NS_WARN_IF(!mHTMLEditor)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
   RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
   nsresult rv = htmlEditor->DoTransactionInternal(transaction);
@@ -411,18 +415,22 @@ nsresult CSSEditUtils::SetCSSPropertyPix
 }
 
 // The lowest level above the transaction; removes the value aValue from the
 // list of values specified for the CSS property aProperty, or totally remove
 // the declaration if this property accepts only one value
 nsresult CSSEditUtils::RemoveCSSProperty(Element& aElement, nsAtom& aProperty,
                                          const nsAString& aValue,
                                          bool aSuppressTxn) {
+  nsCOMPtr<nsStyledElement> styledElement = do_QueryInterface(&aElement);
+  if (NS_WARN_IF(!styledElement)) {
+    return NS_ERROR_INVALID_ARG;
+  }
   RefPtr<ChangeStyleTransaction> transaction =
-      ChangeStyleTransaction::CreateToRemove(aElement, aProperty, aValue);
+      ChangeStyleTransaction::CreateToRemove(*styledElement, aProperty, aValue);
   if (aSuppressTxn) {
     nsresult rv = transaction->DoTransaction();
     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
                          "ChangeStyleTransaction::DoTransaction() failed");
     return rv;
   }
   if (NS_WARN_IF(!mHTMLEditor)) {
     return NS_ERROR_NOT_AVAILABLE;
--- a/editor/libeditor/ChangeAttributeTransaction.cpp
+++ b/editor/libeditor/ChangeAttributeTransaction.cpp
@@ -58,43 +58,55 @@ NS_IMETHODIMP ChangeAttributeTransaction
   // XXX: hack until attribute-was-set code is implemented
   if (!mUndoValue.IsEmpty()) {
     mAttributeWasSet = true;
   }
   // XXX: end hack
 
   // Now set the attribute to the new value
   if (mRemoveAttribute) {
-    nsresult rv = mElement->UnsetAttr(kNameSpaceID_None, mAttribute, true);
+    OwningNonNull<Element> element = *mElement;
+    nsresult rv = element->UnsetAttr(kNameSpaceID_None, mAttribute, true);
     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Element::UnsetAttr() failed");
     return rv;
   }
 
-  nsresult rv = mElement->SetAttr(kNameSpaceID_None, mAttribute, mValue, true);
+  OwningNonNull<Element> element = *mElement;
+  nsresult rv = element->SetAttr(kNameSpaceID_None, mAttribute, mValue, true);
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Element::SetAttr() failed");
   return rv;
 }
 
 NS_IMETHODIMP ChangeAttributeTransaction::UndoTransaction() {
+  if (NS_WARN_IF(!mElement)) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
   if (mAttributeWasSet) {
+    OwningNonNull<Element> element = *mElement;
     nsresult rv =
-        mElement->SetAttr(kNameSpaceID_None, mAttribute, mUndoValue, true);
+        element->SetAttr(kNameSpaceID_None, mAttribute, mUndoValue, true);
     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Element::SetAttr() failed");
     return rv;
   }
-  nsresult rv = mElement->UnsetAttr(kNameSpaceID_None, mAttribute, true);
+  OwningNonNull<Element> element = *mElement;
+  nsresult rv = element->UnsetAttr(kNameSpaceID_None, mAttribute, true);
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Element::UnsetAttr() failed");
   return rv;
 }
 
 NS_IMETHODIMP ChangeAttributeTransaction::RedoTransaction() {
+  if (NS_WARN_IF(!mElement)) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
   if (mRemoveAttribute) {
-    nsresult rv = mElement->UnsetAttr(kNameSpaceID_None, mAttribute, true);
+    OwningNonNull<Element> element = *mElement;
+    nsresult rv = element->UnsetAttr(kNameSpaceID_None, mAttribute, true);
     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Element::UnsetAttr() failed");
     return rv;
   }
 
-  nsresult rv = mElement->SetAttr(kNameSpaceID_None, mAttribute, mValue, true);
+  OwningNonNull<Element> element = *mElement;
+  nsresult rv = element->SetAttr(kNameSpaceID_None, mAttribute, mValue, true);
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Element::SetAttr() failed");
   return rv;
 }
 
 }  // namespace mozilla
--- a/editor/libeditor/ChangeStyleTransaction.cpp
+++ b/editor/libeditor/ChangeStyleTransaction.cpp
@@ -19,48 +19,50 @@
 #include "nsUnicharUtils.h"       // for nsCaseInsensitiveStringComparator
 
 namespace mozilla {
 
 using namespace dom;
 
 // static
 already_AddRefed<ChangeStyleTransaction> ChangeStyleTransaction::Create(
-    Element& aElement, nsAtom& aProperty, const nsAString& aValue) {
+    nsStyledElement& aStyledElement, nsAtom& aProperty,
+    const nsAString& aValue) {
   RefPtr<ChangeStyleTransaction> transaction =
-      new ChangeStyleTransaction(aElement, aProperty, aValue, false);
+      new ChangeStyleTransaction(aStyledElement, aProperty, aValue, false);
   return transaction.forget();
 }
 
 // static
 already_AddRefed<ChangeStyleTransaction> ChangeStyleTransaction::CreateToRemove(
-    Element& aElement, nsAtom& aProperty, const nsAString& aValue) {
+    nsStyledElement& aStyledElement, nsAtom& aProperty,
+    const nsAString& aValue) {
   RefPtr<ChangeStyleTransaction> transaction =
-      new ChangeStyleTransaction(aElement, aProperty, aValue, true);
+      new ChangeStyleTransaction(aStyledElement, aProperty, aValue, true);
   return transaction.forget();
 }
 
-ChangeStyleTransaction::ChangeStyleTransaction(Element& aElement,
+ChangeStyleTransaction::ChangeStyleTransaction(nsStyledElement& aStyledElement,
                                                nsAtom& aProperty,
                                                const nsAString& aValue,
                                                bool aRemove)
     : EditTransactionBase(),
-      mElement(&aElement),
+      mStyledElement(&aStyledElement),
       mProperty(&aProperty),
       mValue(aValue),
-      mRemoveProperty(aRemove),
       mUndoValue(),
       mRedoValue(),
+      mRemoveProperty(aRemove),
       mUndoAttributeWasSet(false),
       mRedoAttributeWasSet(false) {}
 
 #define kNullCh (char16_t('\0'))
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(ChangeStyleTransaction, EditTransactionBase,
-                                   mElement)
+                                   mStyledElement)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ChangeStyleTransaction)
 NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
 
 NS_IMPL_ADDREF_INHERITED(ChangeStyleTransaction, EditTransactionBase)
 NS_IMPL_RELEASE_INHERITED(ChangeStyleTransaction, EditTransactionBase)
 
 // Answers true if aValue is in the string list of white-space separated values
@@ -136,30 +138,30 @@ void ChangeStyleTransaction::RemoveValue
     }
 
     start = ++end;
   }
   aValues.Assign(outString);
 }
 
 NS_IMETHODIMP ChangeStyleTransaction::DoTransaction() {
-  // TODO: Change mElement to RefPtr<nsStyleElement>.
-  nsCOMPtr<nsStyledElement> inlineStyles = do_QueryInterface(mElement);
-  if (NS_WARN_IF(!inlineStyles)) {
-    return NS_ERROR_INVALID_ARG;
+  if (NS_WARN_IF(!mStyledElement)) {
+    return NS_ERROR_NOT_AVAILABLE;
   }
 
-  nsCOMPtr<nsICSSDeclaration> cssDecl = inlineStyles->Style();
+  OwningNonNull<nsStyledElement> styledElement = *mStyledElement;
+  nsCOMPtr<nsICSSDeclaration> cssDecl = styledElement->Style();
 
   // FIXME(bug 1606994): Using atoms forces a string copy here which is not
   // great.
   nsAutoCString propertyNameString;
   mProperty->ToUTF8String(propertyNameString);
 
-  mUndoAttributeWasSet = mElement->HasAttr(kNameSpaceID_None, nsGkAtoms::style);
+  mUndoAttributeWasSet =
+      mStyledElement->HasAttr(kNameSpaceID_None, nsGkAtoms::style);
 
   nsAutoString values;
   nsresult rv = cssDecl->GetPropertyValue(propertyNameString, values);
   if (NS_FAILED(rv)) {
     NS_WARNING("nsICSSDeclaration::GetPropertyPriorityValue() failed");
     return rv;
   }
   mUndoValue.Assign(values);
@@ -216,43 +218,45 @@ NS_IMETHODIMP ChangeStyleTransaction::Do
       return error.StealNSResult();
     }
   }
 
   // Let's be sure we don't keep an empty style attribute
   uint32_t length = cssDecl->Length();
   if (!length) {
     nsresult rv =
-        mElement->UnsetAttr(kNameSpaceID_None, nsGkAtoms::style, true);
+        styledElement->UnsetAttr(kNameSpaceID_None, nsGkAtoms::style, true);
     if (NS_FAILED(rv)) {
       NS_WARNING("Element::UnsetAttr(nsGkAtoms::style) failed");
       return rv;
     }
   } else {
     mRedoAttributeWasSet = true;
   }
 
   rv = cssDecl->GetPropertyValue(propertyNameString, mRedoValue);
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
                        "nsICSSDeclaration::GetPropertyValue() failed");
   return rv;
 }
 
 nsresult ChangeStyleTransaction::SetStyle(bool aAttributeWasSet,
                                           nsAString& aValue) {
+  if (NS_WARN_IF(!mStyledElement)) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
   if (aAttributeWasSet) {
+    OwningNonNull<nsStyledElement> styledElement = *mStyledElement;
+
     // The style attribute was not empty, let's recreate the declaration
     nsAutoCString propertyNameString;
     mProperty->ToUTF8String(propertyNameString);
 
-    nsCOMPtr<nsStyledElement> inlineStyles = do_QueryInterface(mElement);
-    if (NS_WARN_IF(!inlineStyles)) {
-      return NS_ERROR_INVALID_ARG;
-    }
-    nsCOMPtr<nsICSSDeclaration> cssDecl = inlineStyles->Style();
+    nsCOMPtr<nsICSSDeclaration> cssDecl = styledElement->Style();
 
     ErrorResult error;
     if (aValue.IsEmpty()) {
       // An empty value means we have to remove the property
       nsAutoString returnString;
       cssDecl->RemoveProperty(propertyNameString, returnString, error);
       if (error.Failed()) {
         NS_WARNING("nsICSSDeclaration::RemoveProperty() failed");
@@ -263,17 +267,20 @@ nsresult ChangeStyleTransaction::SetStyl
     nsAutoString priority;
     cssDecl->GetPropertyPriority(propertyNameString, priority);
     cssDecl->SetProperty(propertyNameString, NS_ConvertUTF16toUTF8(aValue),
                          priority, error);
     NS_WARNING_ASSERTION(!error.Failed(),
                          "nsICSSDeclaration::SetProperty() failed");
     return error.StealNSResult();
   }
-  nsresult rv = mElement->UnsetAttr(kNameSpaceID_None, nsGkAtoms::style, true);
+
+  OwningNonNull<nsStyledElement> styledElement = *mStyledElement;
+  nsresult rv =
+      styledElement->UnsetAttr(kNameSpaceID_None, nsGkAtoms::style, true);
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
                        "Element::UnsetAttr(nsGkAtoms::style) failed");
   return rv;
 }
 
 NS_IMETHODIMP ChangeStyleTransaction::UndoTransaction() {
   nsresult rv = SetStyle(mUndoAttributeWasSet, mUndoValue);
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
--- a/editor/libeditor/ChangeStyleTransaction.h
+++ b/editor/libeditor/ChangeStyleTransaction.h
@@ -7,52 +7,55 @@
 #define mozilla_ChangeStyleTransaction_h
 
 #include "mozilla/EditTransactionBase.h"   // base class
 #include "nsCOMPtr.h"                      // nsCOMPtr members
 #include "nsCycleCollectionParticipant.h"  // various macros
 #include "nsString.h"                      // nsString members
 
 class nsAtom;
+class nsStyledElement;
 
 namespace mozilla {
 
 namespace dom {
 class Element;
 }  // namespace dom
 
 /**
  * A transaction that changes the value of a CSS inline style of a content
  * node.  This transaction covers add, remove, and change a property's value.
  */
 class ChangeStyleTransaction final : public EditTransactionBase {
  protected:
-  ChangeStyleTransaction(dom::Element& aElement, nsAtom& aProperty,
+  ChangeStyleTransaction(nsStyledElement& aStyledElement, nsAtom& aProperty,
                          const nsAString& aValue, bool aRemove);
 
  public:
   /**
    * Creates a change style transaction.  This never returns nullptr.
    *
-   * @param aNode       The node whose style attribute will be changed.
-   * @param aProperty   The name of the property to change.
-   * @param aValue      New value for aProperty.
+   * @param aStyledElement  The node whose style attribute will be changed.
+   * @param aProperty       The name of the property to change.
+   * @param aValue          New value for aProperty.
    */
   static already_AddRefed<ChangeStyleTransaction> Create(
-      dom::Element& aElement, nsAtom& aProperty, const nsAString& aValue);
+      nsStyledElement& aStyledElement, nsAtom& aProperty,
+      const nsAString& aValue);
 
   /**
    * Creates a change style transaction.  This never returns nullptr.
    *
-   * @param aNode       The node whose style attribute will be changed.
-   * @param aProperty   The name of the property to change.
-   * @param aValue      The value to remove from aProperty.
+   * @param aStyledElement  The node whose style attribute will be changed.
+   * @param aProperty       The name of the property to change.
+   * @param aValue          The value to remove from aProperty.
    */
   static already_AddRefed<ChangeStyleTransaction> CreateToRemove(
-      dom::Element& aElement, nsAtom& aProperty, const nsAString& aValue);
+      nsStyledElement& aStyledElement, nsAtom& aProperty,
+      const nsAString& aValue);
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ChangeStyleTransaction,
                                            EditTransactionBase)
 
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_EDITTRANSACTIONBASE
 
@@ -101,31 +104,32 @@ class ChangeStyleTransaction final : pub
    * If the boolean is true and if the value is not the empty string,
    * set the property in the transaction to that value; if the value
    * is empty, remove the property from element's styles. If the boolean
    * is false, just remove the style attribute.
    */
   nsresult SetStyle(bool aAttributeWasSet, nsAString& aValue);
 
   // The element to operate upon.
-  nsCOMPtr<dom::Element> mElement;
+  RefPtr<nsStyledElement> mStyledElement;
 
   // The CSS property to change.
   RefPtr<nsAtom> mProperty;
 
   // The value to set the property to (ignored if mRemoveProperty==true).
   nsString mValue;
 
-  // true if the operation is to remove mProperty from mElement.
-  bool mRemoveProperty;
-
   // The value to set the property to for undo.
   nsString mUndoValue;
   // The value to set the property to for redo.
   nsString mRedoValue;
+
+  // true if the operation is to remove mProperty from mElement.
+  bool mRemoveProperty;
+
   // True if the style attribute was present and not empty before DoTransaction.
   bool mUndoAttributeWasSet;
   // True if the style attribute is present and not empty after DoTransaction.
   bool mRedoAttributeWasSet;
 };
 
 }  // namespace mozilla
 
--- a/editor/libeditor/CompositionTransaction.cpp
+++ b/editor/libeditor/CompositionTransaction.cpp
@@ -76,103 +76,104 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_INTERFACE_MAP_ENTRY_CONCRETE(CompositionTransaction)
 NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
 
 NS_IMPL_ADDREF_INHERITED(CompositionTransaction, EditTransactionBase)
 NS_IMPL_RELEASE_INHERITED(CompositionTransaction, EditTransactionBase)
 
 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP
 CompositionTransaction::DoTransaction() {
-  if (NS_WARN_IF(!mEditorBase)) {
-    return NS_ERROR_NOT_INITIALIZED;
+  if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTextNode)) {
+    return NS_ERROR_NOT_AVAILABLE;
   }
 
   // Fail before making any changes if there's no selection controller
   if (NS_WARN_IF(!mEditorBase->GetSelectionController())) {
-    return NS_ERROR_NOT_INITIALIZED;
+    return NS_ERROR_NOT_AVAILABLE;
   }
 
-  RefPtr<EditorBase> editorBase = mEditorBase;
-  RefPtr<Text> textNode = mTextNode;
+  OwningNonNull<EditorBase> editorBase = *mEditorBase;
+  OwningNonNull<Text> textNode = *mTextNode;
 
   // Advance caret: This requires the presentation shell to get the selection.
   if (mReplaceLength == 0) {
     ErrorResult error;
-    editorBase->DoInsertText(*textNode, mOffset, mStringToInsert, error);
+    editorBase->DoInsertText(textNode, mOffset, mStringToInsert, error);
     if (error.Failed()) {
       NS_WARNING("EditorBase::DoInsertText() failed");
       return error.StealNSResult();
     }
-    editorBase->RangeUpdaterRef().SelAdjInsertText(*textNode, mOffset,
+    editorBase->RangeUpdaterRef().SelAdjInsertText(textNode, mOffset,
                                                    mStringToInsert);
   } else {
     uint32_t replaceableLength = textNode->TextLength() - mOffset;
     ErrorResult error;
-    editorBase->DoReplaceText(*textNode, mOffset, mReplaceLength,
+    editorBase->DoReplaceText(textNode, mOffset, mReplaceLength,
                               mStringToInsert, error);
     if (error.Failed()) {
       NS_WARNING("EditorBase::DoReplaceText() failed");
       return error.StealNSResult();
     }
     DebugOnly<nsresult> rvIgnored =
-        editorBase->RangeUpdaterRef().SelAdjDeleteText(*textNode, mOffset,
+        editorBase->RangeUpdaterRef().SelAdjDeleteText(textNode, mOffset,
                                                        mReplaceLength);
     NS_WARNING_ASSERTION(
         NS_SUCCEEDED(rvIgnored),
         "RangeUpdater::SelAdjDeleteText() failed, but ignored");
-    editorBase->RangeUpdaterRef().SelAdjInsertText(*textNode, mOffset,
+    editorBase->RangeUpdaterRef().SelAdjInsertText(textNode, mOffset,
                                                    mStringToInsert);
 
     // If IME text node is multiple node, ReplaceData doesn't remove all IME
     // text.  So we need remove remained text into other text node.
     // XXX I think that this shouldn't occur.  Composition string should be
     //     in a text node.
     if (replaceableLength < mReplaceLength) {
       int32_t remainLength = mReplaceLength - replaceableLength;
-      nsCOMPtr<nsINode> node = textNode->GetNextSibling();
       IgnoredErrorResult ignoredError;
-      while (node && node->IsText() && remainLength > 0) {
-        RefPtr<Text> textNode = static_cast<Text*>(node.get());
+      for (nsIContent* nextSibling = textNode->GetNextSibling();
+           nextSibling && nextSibling->IsText() && remainLength;
+           nextSibling = nextSibling->GetNextSibling()) {
+        OwningNonNull<Text> textNode = *static_cast<Text*>(nextSibling);
         uint32_t textLength = textNode->TextLength();
-        editorBase->DoDeleteText(*textNode, 0, remainLength, ignoredError);
+        editorBase->DoDeleteText(textNode, 0, remainLength, ignoredError);
         NS_WARNING_ASSERTION(!ignoredError.Failed(),
                              "EditorBase::DoDeleteText() failed, but ignored");
         ignoredError.SuppressException();
-        editorBase->RangeUpdaterRef().SelAdjDeleteText(*textNode, 0,
+        // XXX Needs to check whether the text is deleted as expected.
+        editorBase->RangeUpdaterRef().SelAdjDeleteText(textNode, 0,
                                                        remainLength);
         remainLength -= textLength;
-        node = node->GetNextSibling();
       }
     }
   }
 
   nsresult rv = SetSelectionForRanges();
   NS_WARNING_ASSERTION(
       NS_SUCCEEDED(rv),
       "CompositionTransaction::SetSelectionForRanges() failed");
   return rv;
 }
 
 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP
 CompositionTransaction::UndoTransaction() {
-  if (NS_WARN_IF(!mEditorBase)) {
-    return NS_ERROR_NOT_INITIALIZED;
+  if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTextNode)) {
+    return NS_ERROR_NOT_AVAILABLE;
   }
 
   // Get the selection first so we'll fail before making any changes if we
   // can't get it
   RefPtr<Selection> selection = mEditorBase->GetSelection();
   if (NS_WARN_IF(!selection)) {
-    return NS_ERROR_NOT_INITIALIZED;
+    return NS_ERROR_NOT_AVAILABLE;
   }
 
-  RefPtr<EditorBase> editorBase = mEditorBase;
-  RefPtr<Text> textNode = mTextNode;
+  OwningNonNull<EditorBase> editorBase = *mEditorBase;
+  OwningNonNull<Text> textNode = *mTextNode;
   ErrorResult error;
-  editorBase->DoDeleteText(*textNode, mOffset, mStringToInsert.Length(), error);
+  editorBase->DoDeleteText(textNode, mOffset, mStringToInsert.Length(), error);
   if (error.Failed()) {
     NS_WARNING("EditorBase::DoDeleteText() failed");
     return error.StealNSResult();
   }
 
   // set the selection to the insertion point where the string was removed
   nsresult rv = selection->Collapse(textNode, mOffset);
   NS_ASSERTION(NS_SUCCEEDED(rv), "Selection::Collapse() failed");
@@ -206,21 +207,24 @@ NS_IMETHODIMP CompositionTransaction::Me
   return NS_OK;
 }
 
 void CompositionTransaction::MarkFixed() { mFixed = true; }
 
 /* ============ private methods ================== */
 
 nsresult CompositionTransaction::SetSelectionForRanges() {
-  if (NS_WARN_IF(!mEditorBase)) {
-    return NS_ERROR_NOT_INITIALIZED;
+  if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTextNode)) {
+    return NS_ERROR_NOT_AVAILABLE;
   }
-  nsresult rv = SetIMESelection(*mEditorBase, mTextNode, mOffset,
-                                mStringToInsert.Length(), mRanges);
+  OwningNonNull<EditorBase> editorBase = *mEditorBase;
+  OwningNonNull<Text> textNode = *mTextNode;
+  RefPtr<TextRangeArray> ranges = mRanges;
+  nsresult rv = SetIMESelection(editorBase, textNode, mOffset,
+                                mStringToInsert.Length(), ranges);
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
                        "CompositionTransaction::SetIMESelection() failed");
   return rv;
 }
 
 // static
 nsresult CompositionTransaction::SetIMESelection(
     EditorBase& aEditorBase, Text* aTextNode, uint32_t aOffsetInNode,
--- a/editor/libeditor/CreateElementTransaction.cpp
+++ b/editor/libeditor/CreateElementTransaction.cpp
@@ -49,44 +49,48 @@ already_AddRefed<CreateElementTransactio
 
 template <typename PT, typename CT>
 CreateElementTransaction::CreateElementTransaction(
     EditorBase& aEditorBase, nsAtom& aTag,
     const EditorDOMPointBase<PT, CT>& aPointToInsert)
     : EditTransactionBase(),
       mEditorBase(&aEditorBase),
       mTag(&aTag),
-      mPointToInsert(aPointToInsert) {}
+      mPointToInsert(aPointToInsert) {
+  MOZ_ASSERT(!mPointToInsert.IsInDataNode());
+  // We only need the child node at inserting new node.
+  AutoEditorDOMPointOffsetInvalidator lockChild(mPointToInsert);
+}
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(CreateElementTransaction,
                                    EditTransactionBase, mEditorBase,
-                                   mPointToInsert, mNewNode)
+                                   mPointToInsert, mNewElement)
 
 NS_IMPL_ADDREF_INHERITED(CreateElementTransaction, EditTransactionBase)
 NS_IMPL_RELEASE_INHERITED(CreateElementTransaction, EditTransactionBase)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CreateElementTransaction)
 NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
 
 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP
 CreateElementTransaction::DoTransaction() {
   if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTag) ||
       NS_WARN_IF(!mPointToInsert.IsSet())) {
     return NS_ERROR_NOT_INITIALIZED;
   }
 
-  RefPtr<EditorBase> editorBase(mEditorBase);
+  OwningNonNull<EditorBase> editorBase = *mEditorBase;
 
-  mNewNode = editorBase->CreateHTMLContent(mTag);
-  if (!mNewNode) {
+  mNewElement = editorBase->CreateHTMLContent(mTag);
+  if (!mNewElement) {
     NS_WARNING("EditorBase::CreateHTMLContent() failed");
     return NS_ERROR_FAILURE;
   }
 
   // Try to insert formatting whitespace for the new node:
-  OwningNonNull<Element> newElement(*mNewNode);
+  OwningNonNull<Element> newElement = *mNewElement;
   nsresult rv = editorBase->MarkElementDirty(newElement);
   if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
     return EditorBase::ToGenericNSResult(rv);
   }
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
                        "EditorBase::MarkElementDirty() failed, but ignored");
 
   // Insert the new node
@@ -103,85 +107,94 @@ CreateElementTransaction::DoTransaction(
     return NS_OK;
   }
 
   RefPtr<Selection> selection = editorBase->GetSelection();
   if (NS_WARN_IF(!selection)) {
     return NS_ERROR_FAILURE;
   }
 
-  EditorRawDOMPoint afterNewNode(EditorRawDOMPoint::After(mNewNode));
+  EditorRawDOMPoint afterNewNode(EditorRawDOMPoint::After(newElement));
   if (NS_WARN_IF(!afterNewNode.IsSet())) {
     // If mutation observer or mutation event listener moved or removed the
     // new node, we hit this case.  Should we use script blocker while we're
     // in this method?
     return NS_ERROR_FAILURE;
   }
   IgnoredErrorResult ignoredError;
   selection->Collapse(afterNewNode, ignoredError);
   NS_WARNING_ASSERTION(!ignoredError.Failed(),
                        "Selection::Collapse() failed, but ignored");
   return NS_OK;
 }
 
 void CreateElementTransaction::InsertNewNode(ErrorResult& aError) {
+  MOZ_ASSERT(mNewElement);
+  MOZ_ASSERT(mPointToInsert.IsSet());
+
   if (mPointToInsert.IsSetAndValid()) {
     if (mPointToInsert.IsEndOfContainer()) {
-      mPointToInsert.GetContainer()->AppendChild(*mNewNode, aError);
+      OwningNonNull<nsINode> container = *mPointToInsert.GetContainer();
+      OwningNonNull<Element> newElement = *mNewElement;
+      container->AppendChild(newElement, aError);
       NS_WARNING_ASSERTION(!aError.Failed(),
                            "nsINode::AppendChild() failed, but ignored");
       return;
     }
-    mPointToInsert.GetContainer()->InsertBefore(
-        *mNewNode, mPointToInsert.GetChild(), aError);
+    MOZ_ASSERT(mPointToInsert.GetChild());
+    OwningNonNull<nsINode> container = *mPointToInsert.GetContainer();
+    OwningNonNull<nsIContent> child = *mPointToInsert.GetChild();
+    OwningNonNull<Element> newElement = *mNewElement;
+    container->InsertBefore(newElement, child, aError);
     NS_WARNING_ASSERTION(!aError.Failed(),
                          "nsINode::InsertBefore() failed, but ignored");
     return;
   }
 
-  if (NS_WARN_IF(mPointToInsert.GetChild() &&
-                 mPointToInsert.GetContainer() !=
-                     mPointToInsert.GetChild()->GetParentNode())) {
+  if (NS_WARN_IF(mPointToInsert.GetContainer() !=
+                 mPointToInsert.GetChild()->GetParentNode())) {
     aError.Throw(NS_ERROR_FAILURE);
     return;
   }
 
   // If mPointToInsert has only offset and it's not valid, we need to treat
   // it as pointing end of the container.
-  mPointToInsert.GetContainer()->AppendChild(*mNewNode, aError);
+  OwningNonNull<nsINode> container = *mPointToInsert.GetContainer();
+  OwningNonNull<Element> newElement = *mNewElement;
+  container->AppendChild(newElement, aError);
   NS_WARNING_ASSERTION(!aError.Failed(),
                        "nsINode::AppendChild() failed, but ignored");
 }
 
 NS_IMETHODIMP CreateElementTransaction::UndoTransaction() {
-  if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mPointToInsert.IsSet())) {
-    return NS_ERROR_NOT_INITIALIZED;
+  if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mPointToInsert.IsSet()) ||
+      NS_WARN_IF(!mNewElement)) {
+    return NS_ERROR_NOT_AVAILABLE;
   }
 
+  OwningNonNull<Element> newElement = *mNewElement;
+  OwningNonNull<nsINode> containerNode = *mPointToInsert.GetContainer();
   ErrorResult error;
-  mPointToInsert.GetContainer()->RemoveChild(*mNewNode, error);
+  containerNode->RemoveChild(newElement, error);
   NS_WARNING_ASSERTION(!error.Failed(), "nsINode::RemoveChild() failed");
   return error.StealNSResult();
 }
 
 NS_IMETHODIMP CreateElementTransaction::RedoTransaction() {
-  if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mPointToInsert.IsSet())) {
-    return NS_ERROR_NOT_INITIALIZED;
+  if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mPointToInsert.IsSet()) ||
+      NS_WARN_IF(!mNewElement)) {
+    return NS_ERROR_NOT_AVAILABLE;
   }
 
-  // First, reset mNewNode so it has no attributes or content
-  // XXX We never actually did this, we only cleared mNewNode's contents if it
-  // was a CharacterData node (which it's not, it's an Element)
+  // First, reset mNewElement so it has no attributes or content
+  // XXX We never actually did this, we only cleared mNewElement's contents if
+  // it was a CharacterData node (which it's not, it's an Element)
   // XXX Don't we need to set selection like DoTransaction()?
 
-  // Now, reinsert mNewNode
+  // Now, reinsert mNewElement
   ErrorResult error;
   InsertNewNode(error);
   NS_WARNING_ASSERTION(!error.Failed(),
                        "CreateElementTransaction::InsertNewNode() failed");
   return error.StealNSResult();
 }
 
-already_AddRefed<Element> CreateElementTransaction::GetNewNode() {
-  return nsCOMPtr<Element>(mNewNode).forget();
-}
-
 }  // namespace mozilla
--- a/editor/libeditor/CreateElementTransaction.h
+++ b/editor/libeditor/CreateElementTransaction.h
@@ -3,33 +3,29 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef CreateElementTransaction_h
 #define CreateElementTransaction_h
 
 #include "mozilla/EditorDOMPoint.h"
 #include "mozilla/EditTransactionBase.h"
-#include "nsCOMPtr.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/dom/Element.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsISupportsImpl.h"
 
 class nsAtom;
-class nsIContent;
-class nsINode;
 
 /**
  * A transaction that creates a new node in the content tree.
  */
 namespace mozilla {
 
 class EditorBase;
-namespace dom {
-class Element;
-}  // namespace dom
 
 class CreateElementTransaction final : public EditTransactionBase {
  protected:
   template <typename PT, typename CT>
   CreateElementTransaction(EditorBase& aEditorBase, nsAtom& aTag,
                            const EditorDOMPointBase<PT, CT>& aPointToInsert);
 
  public:
@@ -52,17 +48,17 @@ class CreateElementTransaction final : p
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(CreateElementTransaction,
                                            EditTransactionBase)
 
   NS_DECL_EDITTRANSACTIONBASE
 
   NS_IMETHOD RedoTransaction() override;
 
-  already_AddRefed<dom::Element> GetNewNode();
+  dom::Element* GetNewElement() const { return mNewElement; }
 
  protected:
   virtual ~CreateElementTransaction() = default;
 
   /**
    * InsertNewNode() inserts mNewNode before the child node at mPointToInsert.
    */
   void InsertNewNode(ErrorResult& aError);
@@ -72,14 +68,14 @@ class CreateElementTransaction final : p
 
   // The tag (mapping to object type) for the new element.
   RefPtr<nsAtom> mTag;
 
   // The DOM point we will insert mNewNode.
   EditorDOMPoint mPointToInsert;
 
   // The new node to insert.
-  nsCOMPtr<dom::Element> mNewNode;
+  RefPtr<dom::Element> mNewElement;
 };
 
 }  // namespace mozilla
 
 #endif  // #ifndef CreateElementTransaction_h
--- a/editor/libeditor/DeleteNodeTransaction.cpp
+++ b/editor/libeditor/DeleteNodeTransaction.cpp
@@ -9,93 +9,97 @@
 #include "nsDebug.h"
 #include "nsError.h"
 #include "nsAString.h"
 
 namespace mozilla {
 
 // static
 already_AddRefed<DeleteNodeTransaction> DeleteNodeTransaction::MaybeCreate(
-    EditorBase& aEditorBase, nsINode& aNodeToDelete) {
+    EditorBase& aEditorBase, nsIContent& aContentToDelete) {
   RefPtr<DeleteNodeTransaction> transaction =
-      new DeleteNodeTransaction(aEditorBase, aNodeToDelete);
+      new DeleteNodeTransaction(aEditorBase, aContentToDelete);
   if (NS_WARN_IF(!transaction->CanDoIt())) {
     return nullptr;
   }
   return transaction.forget();
 }
 
 DeleteNodeTransaction::DeleteNodeTransaction(EditorBase& aEditorBase,
-                                             nsINode& aNodeToDelete)
+                                             nsIContent& aContentToDelete)
     : mEditorBase(&aEditorBase),
-      mNodeToDelete(&aNodeToDelete),
-      mParentNode(aNodeToDelete.GetParentNode()) {}
+      mContentToDelete(&aContentToDelete),
+      mParentNode(aContentToDelete.GetParentNode()) {}
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(DeleteNodeTransaction, EditTransactionBase,
-                                   mEditorBase, mNodeToDelete, mParentNode,
-                                   mRefNode)
+                                   mEditorBase, mContentToDelete, mParentNode,
+                                   mRefContent)
 
 NS_IMPL_ADDREF_INHERITED(DeleteNodeTransaction, EditTransactionBase)
 NS_IMPL_RELEASE_INHERITED(DeleteNodeTransaction, EditTransactionBase)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DeleteNodeTransaction)
 NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
 
 bool DeleteNodeTransaction::CanDoIt() const {
-  if (NS_WARN_IF(!mNodeToDelete) || NS_WARN_IF(!mEditorBase) || !mParentNode ||
-      !mEditorBase->IsModifiableNode(*mParentNode)) {
+  if (NS_WARN_IF(!mContentToDelete) || NS_WARN_IF(!mEditorBase) ||
+      !mParentNode || !mEditorBase->IsModifiableNode(*mParentNode)) {
     return false;
   }
   return true;
 }
 
 NS_IMETHODIMP DeleteNodeTransaction::DoTransaction() {
   if (NS_WARN_IF(!CanDoIt())) {
     return NS_OK;
   }
 
-  if (!mEditorBase->AsHTMLEditor() && mNodeToDelete->IsText()) {
-    uint32_t length = mNodeToDelete->AsText()->TextLength();
+  if (!mEditorBase->AsHTMLEditor() && mContentToDelete->IsText()) {
+    uint32_t length = mContentToDelete->AsText()->TextLength();
     if (length > 0) {
       mEditorBase->AsTextEditor()->WillDeleteText(length, 0, length);
     }
   }
 
-  // Remember which child mNodeToDelete was (by remembering which child was
-  // next).  Note that mRefNode can be nullptr.
-  mRefNode = mNodeToDelete->GetNextSibling();
+  // Remember which child mContentToDelete was (by remembering which child was
+  // next).  Note that mRefContent can be nullptr.
+  mRefContent = mContentToDelete->GetNextSibling();
 
   // give range updater a chance.  SelAdjDeleteNode() needs to be called
   // *before* we do the action, unlike some of the other RangeItem update
   // methods.
-  mEditorBase->RangeUpdaterRef().SelAdjDeleteNode(*mNodeToDelete);
+  mEditorBase->RangeUpdaterRef().SelAdjDeleteNode(*mContentToDelete);
 
+  OwningNonNull<nsINode> parentNode = *mParentNode;
+  OwningNonNull<nsIContent> contentToDelete = *mContentToDelete;
   ErrorResult error;
-  mParentNode->RemoveChild(*mNodeToDelete, error);
+  parentNode->RemoveChild(contentToDelete, error);
   NS_WARNING_ASSERTION(!error.Failed(), "nsINode::RemoveChild() failed");
   return error.StealNSResult();
 }
 
 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP
 DeleteNodeTransaction::UndoTransaction() {
   if (NS_WARN_IF(!CanDoIt())) {
     // This is a legal state, the transaction is a no-op.
     return NS_OK;
   }
   ErrorResult error;
-  RefPtr<EditorBase> editorBase = mEditorBase;
-  nsCOMPtr<nsINode> parent = mParentNode;
-  nsCOMPtr<nsINode> nodeToDelete = mNodeToDelete;
-  nsCOMPtr<nsIContent> refNode = mRefNode;
-  parent->InsertBefore(*nodeToDelete, refNode, error);
+  OwningNonNull<EditorBase> editorBase = *mEditorBase;
+  OwningNonNull<nsINode> parentNode = *mParentNode;
+  OwningNonNull<nsIContent> contentToDelete = *mContentToDelete;
+  nsCOMPtr<nsIContent> refContent = mRefContent;
+  // XXX Perhaps, we should check `refContent` is a child of `parentNode`,
+  //     and if it's not, we should stop undoing or something.
+  parentNode->InsertBefore(contentToDelete, refContent, error);
   if (error.Failed()) {
     NS_WARNING("nsINode::InsertBefore() failed");
     return error.StealNSResult();
   }
-  if (!editorBase->AsHTMLEditor() && nodeToDelete->IsText()) {
-    uint32_t length = nodeToDelete->AsText()->TextLength();
+  if (!editorBase->AsHTMLEditor() && contentToDelete->IsText()) {
+    uint32_t length = contentToDelete->AsText()->TextLength();
     if (length > 0) {
       nsresult rv = MOZ_KnownLive(editorBase->AsTextEditor())
                         ->DidInsertText(length, 0, length);
       if (NS_FAILED(rv)) {
         NS_WARNING("TextEditor::DidInsertText() failed");
         return rv;
       }
     }
@@ -104,24 +108,26 @@ DeleteNodeTransaction::UndoTransaction()
 }
 
 NS_IMETHODIMP DeleteNodeTransaction::RedoTransaction() {
   if (NS_WARN_IF(!CanDoIt())) {
     // This is a legal state, the transaction is a no-op.
     return NS_OK;
   }
 
-  if (!mEditorBase->AsHTMLEditor() && mNodeToDelete->IsText()) {
-    uint32_t length = mNodeToDelete->AsText()->TextLength();
+  if (!mEditorBase->AsHTMLEditor() && mContentToDelete->IsText()) {
+    uint32_t length = mContentToDelete->AsText()->TextLength();
     if (length > 0) {
       mEditorBase->AsTextEditor()->WillDeleteText(length, 0, length);
     }
   }
 
-  mEditorBase->RangeUpdaterRef().SelAdjDeleteNode(*mNodeToDelete);
+  mEditorBase->RangeUpdaterRef().SelAdjDeleteNode(*mContentToDelete);
 
+  OwningNonNull<nsINode> parentNode = *mParentNode;
+  OwningNonNull<nsIContent> contentToDelete = *mContentToDelete;
   ErrorResult error;
-  mParentNode->RemoveChild(*mNodeToDelete, error);
+  parentNode->RemoveChild(contentToDelete, error);
   NS_WARNING_ASSERTION(!error.Failed(), "nsINode::RemoveChild() failed");
   return error.StealNSResult();
 }
 
 }  // namespace mozilla
--- a/editor/libeditor/DeleteNodeTransaction.h
+++ b/editor/libeditor/DeleteNodeTransaction.h
@@ -18,28 +18,28 @@ namespace mozilla {
 
 class EditorBase;
 
 /**
  * A transaction that deletes a single element
  */
 class DeleteNodeTransaction final : public EditTransactionBase {
  protected:
-  DeleteNodeTransaction(EditorBase& aEditorBase, nsINode& aNodeToDelete);
+  DeleteNodeTransaction(EditorBase& aEditorBase, nsIContent& aContentToDelete);
 
  public:
   /**
    * Creates a delete node transaction instance.  This returns nullptr if
    * it cannot remove the node from its parent.
    *
    * @param aEditorBase         The editor.
-   * @param aNodeToDelete       The node to be removed from the DOM tree.
+   * @param aContentToDelete    The node to be removed from the DOM tree.
    */
   static already_AddRefed<DeleteNodeTransaction> MaybeCreate(
-      EditorBase& aEditorBase, nsINode& aNodeToDelete);
+      EditorBase& aEditorBase, nsIContent& aContentToDelete);
 
   /**
    * CanDoIt() returns true if there are enough members and can modify the
    * parent.  Otherwise, false.
    */
   bool CanDoIt() const;
 
   NS_DECL_ISUPPORTS_INHERITED
@@ -52,20 +52,20 @@ class DeleteNodeTransaction final : publ
 
  protected:
   virtual ~DeleteNodeTransaction() = default;
 
   // The editor for this transaction.
   RefPtr<EditorBase> mEditorBase;
 
   // The element to delete.
-  nsCOMPtr<nsINode> mNodeToDelete;
+  nsCOMPtr<nsIContent> mContentToDelete;
 
   // Parent of node to delete.
   nsCOMPtr<nsINode> mParentNode;
 
   // Next sibling to remember for undo/redo purposes.
-  nsCOMPtr<nsIContent> mRefNode;
+  nsCOMPtr<nsIContent> mRefContent;
 };
 
 }  // namespace mozilla
 
 #endif  // #ifndef DeleteNodeTransaction_h
--- a/editor/libeditor/DeleteRangeTransaction.cpp
+++ b/editor/libeditor/DeleteRangeTransaction.cpp
@@ -125,17 +125,17 @@ nsresult DeleteRangeTransaction::CreateT
     return NS_ERROR_INVALID_ARG;
   }
 
   if (NS_WARN_IF(!mEditorBase)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   // see what kind of node we have
-  if (RefPtr<Text> textNode = Text::FromNode(aStart.Container())) {
+  if (Text* textNode = Text::FromNode(aStart.Container())) {
     // if the node is a chardata node, then delete chardata content
     int32_t numToDel;
     if (aStart == aEnd) {
       numToDel = 1;
     } else {
       numToDel = *aEnd.Offset(RawRangeBoundary::OffsetFilter::kValidOffsets) -
                  *aStart.Offset(RawRangeBoundary::OffsetFilter::kValidOffsets);
       MOZ_DIAGNOSTIC_ASSERT(numToDel > 0);
@@ -188,17 +188,17 @@ nsresult DeleteRangeTransaction::CreateT
   if (NS_WARN_IF(!aPoint.IsSetAndValid())) {
     return NS_ERROR_INVALID_ARG;
   }
 
   if (NS_WARN_IF(!mEditorBase)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  RefPtr<Text> textNode = Text::FromNode(aPoint.Container());
+  Text* textNode = Text::FromNode(aPoint.Container());
   if (!textNode) {
     return NS_OK;
   }
 
   // If the node is a chardata node, then delete chardata content
   uint32_t startOffset, numToDelete;
   if (nsIEditor::eNext == aAction) {
     startOffset = *aPoint.Offset(RawRangeBoundary::OffsetFilter::kValidOffsets);
@@ -238,23 +238,23 @@ nsresult DeleteRangeTransaction::CreateT
   ContentSubtreeIterator subtreeIter;
   nsresult rv = subtreeIter.Init(aRangeToDelete);
   if (NS_FAILED(rv)) {
     NS_WARNING("ContentSubtreeIterator::Init() failed");
     return rv;
   }
 
   for (; !subtreeIter.IsDone(); subtreeIter.Next()) {
-    nsCOMPtr<nsINode> node = subtreeIter.GetCurrentNode();
-    if (NS_WARN_IF(!node)) {
-      return NS_ERROR_NULL_POINTER;
+    nsINode* node = subtreeIter.GetCurrentNode();
+    if (NS_WARN_IF(!node) || NS_WARN_IF(!node->IsContent())) {
+      return NS_ERROR_FAILURE;
     }
 
     RefPtr<DeleteNodeTransaction> deleteNodeTransaction =
-        DeleteNodeTransaction::MaybeCreate(*mEditorBase, *node);
+        DeleteNodeTransaction::MaybeCreate(*mEditorBase, *node->AsContent());
     // XXX This is odd handling.  Even if some nodes in the range are not
     //     editable, editor should append transactions because they could
     //     at undoing/redoing.  Additionally, if the transaction needs to
     //     delete/restore all nodes, it should at undoing/redoing.
     if (!deleteNodeTransaction) {
       NS_WARNING("DeleteNodeTransaction::MaybeCreate() failed");
       return NS_ERROR_FAILURE;
     }
--- a/editor/libeditor/DeleteTextTransaction.cpp
+++ b/editor/libeditor/DeleteTextTransaction.cpp
@@ -94,38 +94,38 @@ bool DeleteTextTransaction::CanDoIt() co
   if (NS_WARN_IF(!mTextNode) || NS_WARN_IF(!mEditorBase)) {
     return false;
   }
   return mEditorBase->IsModifiableNode(*mTextNode);
 }
 
 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP
 DeleteTextTransaction::DoTransaction() {
-  if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTextNode)) {
+  if (NS_WARN_IF(!CanDoIt())) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   // Get the text that we're about to delete
   ErrorResult error;
   mTextNode->SubstringData(mOffset, mLengthToDelete, mDeletedText, error);
   if (error.Failed()) {
     NS_WARNING("Text::SubstringData() failed");
     return error.StealNSResult();
   }
 
-  RefPtr<EditorBase> editorBase = mEditorBase;
-  RefPtr<Text> textNode = mTextNode;
-  editorBase->DoDeleteText(*textNode, mOffset, mLengthToDelete, error);
+  OwningNonNull<EditorBase> editorBase = *mEditorBase;
+  OwningNonNull<Text> textNode = *mTextNode;
+  editorBase->DoDeleteText(textNode, mOffset, mLengthToDelete, error);
   if (error.Failed()) {
     NS_WARNING("EditorBase::DoDeleteText() failed");
     return error.StealNSResult();
   }
 
   DebugOnly<nsresult> rvIgnored =
-      editorBase->RangeUpdaterRef().SelAdjDeleteText(*textNode, mOffset,
+      editorBase->RangeUpdaterRef().SelAdjDeleteText(textNode, mOffset,
                                                      mLengthToDelete);
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
                        "RangeUpdater::SelAdjDeleteText() failed, but ignored");
 
   if (!editorBase->AllowsTransactionsToChangeSelection()) {
     return NS_OK;
   }
 
@@ -137,18 +137,18 @@ DeleteTextTransaction::DoTransaction() {
   NS_WARNING_ASSERTION(!error.Failed(), "Selection::Collapse() failed");
   return error.StealNSResult();
 }
 
 // XXX: We may want to store the selection state and restore it properly.  Was
 //     it an insertion point or an extended selection?
 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP
 DeleteTextTransaction::UndoTransaction() {
-  if (NS_WARN_IF(!mTextNode) || NS_WARN_IF(!mEditorBase)) {
-    return NS_ERROR_NOT_INITIALIZED;
+  if (NS_WARN_IF(!CanDoIt())) {
+    return NS_ERROR_NOT_AVAILABLE;
   }
   RefPtr<EditorBase> editorBase = mEditorBase;
   RefPtr<Text> textNode = mTextNode;
   ErrorResult error;
   editorBase->DoInsertText(*textNode, mOffset, mDeletedText, error);
   NS_WARNING_ASSERTION(!error.Failed(), "EditorBase::DoInsertText() failed");
   return error.StealNSResult();
 }
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -1442,17 +1442,17 @@ already_AddRefed<Element> EditorBase::Cr
     NS_WARNING("EditorBase::DoTransactionInternal() failed");
     // XXX Why do we do this even when DoTransaction() returned error?
     DebugOnly<nsresult> rvIgnored =
         RangeUpdaterRef().SelAdjCreateNode(aPointToInsert);
     NS_WARNING_ASSERTION(
         NS_SUCCEEDED(rvIgnored),
         "Rangeupdater::SelAdjCreateNode() failed, but ignored");
   } else {
-    newElement = transaction->GetNewNode();
+    newElement = transaction->GetNewElement();
     MOZ_ASSERT(newElement);
 
     // If we succeeded to create and insert new element, we need to adjust
     // ranges in RangeUpdaterRef().  It currently requires offset of the new
     // node.  So, let's call it with original offset.  Note that if
     // aPointToInsert stores child node, it may not be at the offset since new
     // element must be inserted before the old child.  Although, mutation
     // observer can do anything, but currently, we don't check it.
@@ -1662,53 +1662,54 @@ already_AddRefed<nsIContent> EditorBase:
   Unused << aStartOfRightNode.Offset();
 
   RefPtr<SplitNodeTransaction> transaction =
       SplitNodeTransaction::Create(*this, aStartOfRightNode);
   aError = DoTransactionInternal(transaction);
   NS_WARNING_ASSERTION(!aError.Failed(),
                        "EditorBase::DoTransactionInternal() failed");
 
-  nsCOMPtr<nsIContent> newContent = transaction->GetNewNode();
-  NS_WARNING_ASSERTION(newContent, "Failed to create a new left node");
-
-  if (newContent) {
+  nsCOMPtr<nsIContent> newLeftContent = transaction->GetNewLeftContent();
+  NS_WARNING_ASSERTION(newLeftContent, "Failed to create a new left node");
+
+  if (newLeftContent) {
     // XXX Some other transactions manage range updater by themselves.
     //     Why doesn't SplitNodeTransaction do it?
     DebugOnly<nsresult> rvIgnored = RangeUpdaterRef().SelAdjSplitNode(
-        *aStartOfRightNode.GetContainerAsContent(), *newContent);
+        *aStartOfRightNode.GetContainerAsContent(), *newLeftContent);
     NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
                          "RangeUpdater::SelAdjSplitNode() failed, but ignored");
   }
-  if (AsHTMLEditor() && newContent) {
+  if (AsHTMLEditor() && newLeftContent) {
     TopLevelEditSubActionDataRef().DidSplitContent(
-        *this, *aStartOfRightNode.GetContainerAsContent(), *newContent);
+        *this, *aStartOfRightNode.GetContainerAsContent(), *newLeftContent);
   }
 
   if (mInlineSpellChecker) {
     RefPtr<mozInlineSpellChecker> spellChecker = mInlineSpellChecker;
-    spellChecker->DidSplitNode(aStartOfRightNode.GetContainer(), newContent);
+    spellChecker->DidSplitNode(aStartOfRightNode.GetContainer(),
+                               newLeftContent);
   }
 
   if (!mActionListeners.IsEmpty()) {
     AutoActionListenerArray listeners(mActionListeners);
     for (auto& listener : listeners) {
-      DebugOnly<nsresult> rvIgnored =
-          listener->DidSplitNode(aStartOfRightNode.GetContainer(), newContent);
+      DebugOnly<nsresult> rvIgnored = listener->DidSplitNode(
+          aStartOfRightNode.GetContainer(), newLeftContent);
       NS_WARNING_ASSERTION(
           NS_SUCCEEDED(rvIgnored),
           "nsIEditActionListener::DidSplitNode() failed, but ignored");
     }
   }
 
   if (aError.Failed()) {
     return nullptr;
   }
 
-  return newContent.forget();
+  return newLeftContent.forget();
 }
 
 nsresult EditorBase::JoinNodesWithTransaction(nsINode& aLeftNode,
                                               nsINode& aRightNode) {
   MOZ_ASSERT(IsEditActionDataAvailable());
   MOZ_ASSERT(aLeftNode.IsContent());
   MOZ_ASSERT(aRightNode.IsContent());
 
@@ -1731,18 +1732,18 @@ nsresult EditorBase::JoinNodesWithTransa
   // Find the number of children of the lefthand node
   uint32_t oldLeftNodeLen = aLeftNode.Length();
 
   if (AsHTMLEditor()) {
     TopLevelEditSubActionDataRef().WillJoinContents(
         *this, *aLeftNode.AsContent(), *aRightNode.AsContent());
   }
 
-  RefPtr<JoinNodeTransaction> transaction =
-      JoinNodeTransaction::MaybeCreate(*this, aLeftNode, aRightNode);
+  RefPtr<JoinNodeTransaction> transaction = JoinNodeTransaction::MaybeCreate(
+      *this, *aLeftNode.AsContent(), *aRightNode.AsContent());
   NS_WARNING_ASSERTION(
       transaction, "JoinNodeTransaction::MaybeCreate() failed, but ignored");
 
   nsresult rv = NS_OK;
   if (transaction) {
     rv = DoTransactionInternal(transaction);
     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
                          "EditorBase::DoTransactionInternal() failed");
@@ -1820,17 +1821,17 @@ nsresult EditorBase::DeleteNodeWithTrans
 
   if (AsHTMLEditor()) {
     TopLevelEditSubActionDataRef().WillDeleteContent(*this, *aNode.AsContent());
   }
 
   // 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.AsContent());
   NS_WARNING_ASSERTION(deleteNodeTransaction,
                        "DeleteNodeTransaction::MaybeCreate() failed");
   nsresult rv;
   if (deleteNodeTransaction) {
     rv = DoTransactionInternal(deleteNodeTransaction);
     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
                          "EditorBase::DoTransactionInternal() failed");
 
@@ -4792,78 +4793,81 @@ already_AddRefed<EditTransactionBase> Ed
     *aOffset = deleteTextTransaction->Offset();
     *aLength = deleteTextTransaction->LengthToDelete();
     node.forget(aRemovingNode);
     return deleteTextTransaction.forget();
   }
 
   // we're either deleting a node or chardata, need to dig into the next/prev
   // node to find out
-  nsCOMPtr<nsINode> selectedNode;
+  nsCOMPtr<nsIContent> selectedContent;
   if (aAction == ePrevious) {
-    selectedNode =
+    selectedContent =
         GetPreviousEditableNode(EditorRawDOMPoint(node, child, offset));
   } else if (aAction == eNext) {
-    selectedNode = GetNextEditableNode(EditorRawDOMPoint(node, child, offset));
-  }
-
-  while (selectedNode && selectedNode->IsCharacterData() &&
-         !selectedNode->Length()) {
+    selectedContent =
+        GetNextEditableNode(EditorRawDOMPoint(node, child, offset));
+  }
+
+  while (selectedContent && selectedContent->IsCharacterData() &&
+         !selectedContent->Length()) {
     // Can't delete an empty chardata node (bug 762183)
     if (aAction == ePrevious) {
-      selectedNode = GetPreviousEditableNode(*selectedNode);
+      selectedContent = GetPreviousEditableNode(*selectedContent);
     } else if (aAction == eNext) {
-      selectedNode = GetNextEditableNode(*selectedNode);
+      selectedContent = GetNextEditableNode(*selectedContent);
     }
   }
 
-  if (NS_WARN_IF(!selectedNode)) {
+  if (NS_WARN_IF(!selectedContent)) {
     return nullptr;
   }
 
-  if (RefPtr<Text> selectedNodeAsText = Text::FromNode(selectedNode)) {
+  if (RefPtr<Text> selectedTextNode = Text::FromNode(selectedContent)) {
     if (NS_WARN_IF(aAction != ePrevious && aAction != eNext)) {
       return nullptr;
     }
     // we are deleting from a chardata node, so do a character deletion
     uint32_t position = 0;
     if (aAction == ePrevious) {
-      position = selectedNode->Length();
+      position = selectedTextNode->Length();
     }
     RefPtr<DeleteTextTransaction> deleteTextTransaction;
     if (aAction == ePrevious) {
       deleteTextTransaction =
           DeleteTextTransaction::MaybeCreateForPreviousCharacter(
-              *this, *selectedNodeAsText, position);
+              *this, *selectedTextNode, position);
       NS_WARNING_ASSERTION(
           deleteTextTransaction,
           "DeleteTextTransaction::MaybeCreateForPreviousCharacter() failed");
     } else {
       deleteTextTransaction =
           DeleteTextTransaction::MaybeCreateForNextCharacter(
-              *this, *selectedNodeAsText, position);
+              *this, *selectedTextNode, position);
       NS_WARNING_ASSERTION(
           deleteTextTransaction,
           "DeleteTextTransaction::MaybeCreateForNextCharacter() failed");
     }
     if (!deleteTextTransaction) {
       return nullptr;
     }
     *aOffset = deleteTextTransaction->Offset();
     *aLength = deleteTextTransaction->LengthToDelete();
-    selectedNode.forget(aRemovingNode);
+    nsCOMPtr<nsINode> removingNode(selectedTextNode);
+    removingNode.forget(aRemovingNode);
     return deleteTextTransaction.forget();
   }
 
   RefPtr<DeleteNodeTransaction> deleteNodeTransaction =
-      DeleteNodeTransaction::MaybeCreate(*this, *selectedNode);
+      DeleteNodeTransaction::MaybeCreate(*this, *selectedContent);
   if (NS_WARN_IF(!deleteNodeTransaction)) {
     return nullptr;
   }
-  selectedNode.forget(aRemovingNode);
+  nsCOMPtr<nsINode> removingNode(selectedContent);
+  removingNode.forget(aRemovingNode);
   return deleteNodeTransaction.forget();
 }
 
 nsresult EditorBase::CreateRange(nsINode* aStartContainer, int32_t aStartOffset,
                                  nsINode* aEndContainer, int32_t aEndOffset,
                                  nsRange** aRange) {
   RefPtr<nsRange> range = nsRange::Create(
       aStartContainer, aStartOffset, aEndContainer, aEndOffset, IgnoreErrors());
--- a/editor/libeditor/InsertNodeTransaction.cpp
+++ b/editor/libeditor/InsertNodeTransaction.cpp
@@ -59,17 +59,17 @@ NS_IMPL_ADDREF_INHERITED(InsertNodeTrans
 NS_IMPL_RELEASE_INHERITED(InsertNodeTransaction, EditTransactionBase)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(InsertNodeTransaction)
 NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
 
 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP
 InsertNodeTransaction::DoTransaction() {
   if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mContentToInsert) ||
       NS_WARN_IF(!mPointToInsert.IsSet())) {
-    return NS_ERROR_NOT_INITIALIZED;
+    return NS_ERROR_NOT_AVAILABLE;
   }
 
   if (!mPointToInsert.IsSetAndValid()) {
     // It seems that DOM tree has been changed after first DoTransaction()
     // and current RedoTranaction() call.
     if (mPointToInsert.GetChild()) {
       EditorDOMPoint newPointToInsert(mPointToInsert.GetChild());
       if (!newPointToInsert.IsSet()) {
@@ -84,32 +84,32 @@ InsertNodeTransaction::DoTransaction() {
     } else {
       mPointToInsert.SetToEndOf(mPointToInsert.GetContainer());
       if (NS_WARN_IF(!mPointToInsert.IsSet())) {
         return NS_ERROR_FAILURE;
       }
     }
   }
 
-  RefPtr<EditorBase> editorBase = mEditorBase;
-  nsCOMPtr<nsIContent> contentToInsert = mContentToInsert;
-  nsCOMPtr<nsINode> container = mPointToInsert.GetContainer();
+  OwningNonNull<EditorBase> editorBase = *mEditorBase;
+  OwningNonNull<nsIContent> contentToInsert = *mContentToInsert;
+  OwningNonNull<nsINode> container = *mPointToInsert.GetContainer();
   nsCOMPtr<nsIContent> refChild = mPointToInsert.GetChild();
   if (contentToInsert->IsElement()) {
     nsresult rv = editorBase->MarkElementDirty(
         MOZ_KnownLive(*contentToInsert->AsElement()));
     if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
       return EditorBase::ToGenericNSResult(rv);
     }
     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
                          "EditorBase::MarkElementDirty() failed, but ignored");
   }
 
   ErrorResult error;
-  container->InsertBefore(*contentToInsert, refChild, error);
+  container->InsertBefore(contentToInsert, refChild, error);
   if (error.Failed()) {
     NS_WARNING("nsINode::InsertBefore() failed");
     return error.StealNSResult();
   }
 
   if (!editorBase->AsHTMLEditor() && contentToInsert->IsText()) {
     uint32_t length = contentToInsert->AsText()->TextLength();
     if (length > 0) {
@@ -127,20 +127,20 @@ InsertNodeTransaction::DoTransaction() {
   }
 
   RefPtr<Selection> selection = mEditorBase->GetSelection();
   if (NS_WARN_IF(!selection)) {
     return NS_ERROR_FAILURE;
   }
 
   // Place the selection just after the inserted element.
-  EditorRawDOMPoint afterInsertedNode(mContentToInsert);
-  DebugOnly<bool> advanced = afterInsertedNode.AdvanceOffset();
-  NS_WARNING_ASSERTION(advanced,
-                       "Failed to advance offset after the inserted node");
+  EditorRawDOMPoint afterInsertedNode(
+      EditorRawDOMPoint::After(contentToInsert));
+  NS_WARNING_ASSERTION(afterInsertedNode.IsSet(),
+                       "Failed to set after the inserted node");
   IgnoredErrorResult ignoredError;
   selection->Collapse(afterInsertedNode, ignoredError);
   NS_WARNING_ASSERTION(!ignoredError.Failed(),
                        "Selection::Collapse() failed, but ignored");
   return NS_OK;
 }
 
 NS_IMETHODIMP InsertNodeTransaction::UndoTransaction() {
@@ -151,15 +151,17 @@ NS_IMETHODIMP InsertNodeTransaction::Und
   if (!mEditorBase->AsHTMLEditor() && mContentToInsert->IsText()) {
     uint32_t length = mContentToInsert->TextLength();
     if (length > 0) {
       mEditorBase->AsTextEditor()->WillDeleteText(length, 0, length);
     }
   }
   // XXX If the inserted node has been moved to different container node or
   //     just removed from the DOM tree, this always fails.
+  OwningNonNull<nsINode> container = *mPointToInsert.GetContainer();
+  OwningNonNull<nsIContent> contentToInsert = *mContentToInsert;
   ErrorResult error;
-  mPointToInsert.GetContainer()->RemoveChild(*mContentToInsert, error);
+  container->RemoveChild(contentToInsert, error);
   NS_WARNING("nsINode::RemoveChild() failed");
   return error.StealNSResult();
 }
 
 }  // namespace mozilla
--- a/editor/libeditor/InsertTextTransaction.cpp
+++ b/editor/libeditor/InsertTextTransaction.cpp
@@ -46,21 +46,21 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
 NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
 
 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP
 InsertTextTransaction::DoTransaction() {
   if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTextNode)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  RefPtr<EditorBase> editorBase = mEditorBase;
-  RefPtr<Text> textNode = mTextNode;
+  OwningNonNull<EditorBase> editorBase = *mEditorBase;
+  OwningNonNull<Text> textNode = *mTextNode;
 
   ErrorResult error;
-  editorBase->DoInsertText(*textNode, mOffset, mStringToInsert, error);
+  editorBase->DoInsertText(textNode, mOffset, mStringToInsert, error);
   if (error.Failed()) {
     NS_WARNING("EditorBase::DoInsertText() failed");
     return error.StealNSResult();
   }
 
   // Only set selection to insertion point if editor gives permission
   if (editorBase->AllowsTransactionsToChangeSelection()) {
     RefPtr<Selection> selection = editorBase->GetSelection();
@@ -71,31 +71,31 @@ InsertTextTransaction::DoTransaction() {
         selection->Collapse(textNode, mOffset + mStringToInsert.Length());
     NS_ASSERTION(NS_SUCCEEDED(rvIgnored),
                  "Selection::Collapse() failed, but ignored");
   } else {
     // Do nothing - DOM Range gravity will adjust selection
   }
   // XXX Other transactions do not do this but its callers do.
   //     Why do this transaction do this by itself?
-  editorBase->RangeUpdaterRef().SelAdjInsertText(*textNode, mOffset,
+  editorBase->RangeUpdaterRef().SelAdjInsertText(textNode, mOffset,
                                                  mStringToInsert);
 
   return NS_OK;
 }
 
 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP
 InsertTextTransaction::UndoTransaction() {
   if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTextNode)) {
     return NS_ERROR_NOT_INITIALIZED;
   }
-  RefPtr<EditorBase> editorBase = mEditorBase;
-  RefPtr<Text> textNode = mTextNode;
+  OwningNonNull<EditorBase> editorBase = *mEditorBase;
+  OwningNonNull<Text> textNode = *mTextNode;
   ErrorResult error;
-  editorBase->DoDeleteText(*textNode, mOffset, mStringToInsert.Length(), error);
+  editorBase->DoDeleteText(textNode, mOffset, mStringToInsert.Length(), error);
   NS_WARNING_ASSERTION(!error.Failed(), "EditorBase::DoDeleteText() failed");
   return error.StealNSResult();
 }
 
 NS_IMETHODIMP InsertTextTransaction::Merge(nsITransaction* aTransaction,
                                            bool* aDidMerge) {
   if (NS_WARN_IF(!aTransaction) || NS_WARN_IF(!aDidMerge)) {
     return NS_ERROR_INVALID_ARG;
--- a/editor/libeditor/JoinNodeTransaction.cpp
+++ b/editor/libeditor/JoinNodeTransaction.cpp
@@ -14,117 +14,126 @@
 #include "nsISupportsImpl.h"  // for QueryInterface, etc.
 
 namespace mozilla {
 
 using namespace dom;
 
 // static
 already_AddRefed<JoinNodeTransaction> JoinNodeTransaction::MaybeCreate(
-    EditorBase& aEditorBase, nsINode& aLeftNode, nsINode& aRightNode) {
+    EditorBase& aEditorBase, nsIContent& aLeftContent,
+    nsIContent& aRightContent) {
   RefPtr<JoinNodeTransaction> transaction =
-      new JoinNodeTransaction(aEditorBase, aLeftNode, aRightNode);
+      new JoinNodeTransaction(aEditorBase, aLeftContent, aRightContent);
   if (NS_WARN_IF(!transaction->CanDoIt())) {
     return nullptr;
   }
   return transaction.forget();
 }
 
 JoinNodeTransaction::JoinNodeTransaction(EditorBase& aEditorBase,
-                                         nsINode& aLeftNode,
-                                         nsINode& aRightNode)
+                                         nsIContent& aLeftContent,
+                                         nsIContent& aRightContent)
     : mEditorBase(&aEditorBase),
-      mLeftNode(&aLeftNode),
-      mRightNode(&aRightNode),
+      mLeftContent(&aLeftContent),
+      mRightContent(&aRightContent),
       mOffset(0) {}
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(JoinNodeTransaction, EditTransactionBase,
-                                   mEditorBase, mLeftNode, mRightNode, mParent)
+                                   mEditorBase, mLeftContent, mRightContent,
+                                   mParentNode)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(JoinNodeTransaction)
 NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
 
 bool JoinNodeTransaction::CanDoIt() const {
-  if (NS_WARN_IF(!mLeftNode) || NS_WARN_IF(!mRightNode) ||
-      NS_WARN_IF(!mEditorBase) || !mLeftNode->GetParentNode()) {
+  if (NS_WARN_IF(!mLeftContent) || NS_WARN_IF(!mRightContent) ||
+      NS_WARN_IF(!mEditorBase) || !mLeftContent->GetParentNode()) {
     return false;
   }
-  return mEditorBase->IsModifiableNode(*mLeftNode->GetParentNode());
+  return mEditorBase->IsModifiableNode(*mLeftContent->GetParentNode());
 }
 
 // After DoTransaction() and RedoTransaction(), the left node is removed from
 // the content tree and right node remains.
 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP JoinNodeTransaction::DoTransaction() {
-  if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mLeftNode) ||
-      NS_WARN_IF(!mRightNode)) {
-    return NS_ERROR_NOT_INITIALIZED;
+  if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mLeftContent) ||
+      NS_WARN_IF(!mRightContent)) {
+    return NS_ERROR_NOT_AVAILABLE;
   }
 
   // Get the parent node
-  nsCOMPtr<nsINode> leftNodeParent = mLeftNode->GetParentNode();
-  if (NS_WARN_IF(!leftNodeParent)) {
-    return NS_ERROR_FAILURE;
+  nsCOMPtr<nsINode> leftContentParent = mLeftContent->GetParentNode();
+  if (NS_WARN_IF(!leftContentParent)) {
+    return NS_ERROR_NOT_AVAILABLE;
   }
 
-  // Verify that mLeftNode and mRightNode have the same parent
-  if (leftNodeParent != mRightNode->GetParentNode()) {
+  // Verify that mLeftContent and mRightContent have the same parent
+  if (leftContentParent != mRightContent->GetParentNode()) {
     NS_ASSERTION(false, "Nodes do not have same parent");
-    return NS_ERROR_INVALID_ARG;
+    return NS_ERROR_NOT_AVAILABLE;
   }
 
-  // Set this instance's mParent.  Other methods will see a non-null mParent
-  // and know all is well
-  mParent = leftNodeParent;
-  mOffset = mLeftNode->Length();
+  // Set this instance's mParentNode.  Other methods will see a non-null
+  // mParentNode and know all is well
+  mParentNode = leftContentParent;
+  mOffset = mLeftContent->Length();
 
-  RefPtr<EditorBase> editorBase = mEditorBase;
-  nsCOMPtr<nsINode> leftNode = mLeftNode;
-  nsCOMPtr<nsINode> rightNode = mRightNode;
-  nsresult rv = editorBase->DoJoinNodes(rightNode, leftNode, leftNodeParent);
+  OwningNonNull<EditorBase> editorBase = *mEditorBase;
+  OwningNonNull<nsINode> leftNode = *mLeftContent;
+  OwningNonNull<nsINode> rightNode = *mRightContent;
+  nsresult rv = editorBase->DoJoinNodes(rightNode, leftNode, leftContentParent);
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "EditorBase::DoJoinNodes() failed");
   return rv;
 }
 
 // XXX: What if instead of split, we just deleted the unneeded children of
 //     mRight and re-inserted mLeft?
 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP
 JoinNodeTransaction::UndoTransaction() {
-  if (NS_WARN_IF(!mParent) || NS_WARN_IF(!mLeftNode) ||
-      NS_WARN_IF(!mRightNode) || NS_WARN_IF(!mEditorBase)) {
-    return NS_ERROR_NOT_INITIALIZED;
+  if (NS_WARN_IF(!mParentNode) || NS_WARN_IF(!mLeftContent) ||
+      NS_WARN_IF(!mRightContent) || NS_WARN_IF(!mEditorBase)) {
+    return NS_ERROR_NOT_AVAILABLE;
   }
 
+  OwningNonNull<nsIContent> leftContent = *mLeftContent;
+  OwningNonNull<nsIContent> rightContent = *mRightContent;
+  OwningNonNull<nsINode> parentNode = *mParentNode;
+
   // First, massage the existing node so it is in its post-split state
   ErrorResult error;
-  if (mRightNode->GetAsText()) {
-    RefPtr<EditorBase> editorBase = mEditorBase;
-    RefPtr<Text> rightNodeAsText = mRightNode->GetAsText();
-    editorBase->DoDeleteText(*rightNodeAsText, 0, mOffset, error);
+  if (Text* rightTextNode = rightContent->GetAsText()) {
+    OwningNonNull<EditorBase> editorBase = *mEditorBase;
+    editorBase->DoDeleteText(MOZ_KnownLive(*rightTextNode), 0, mOffset, error);
     if (error.Failed()) {
       NS_WARNING("EditorBase::DoDeleteText() failed");
       return error.StealNSResult();
     }
   } else {
-    nsCOMPtr<nsIContent> child = mRightNode->GetFirstChild();
-    for (uint32_t i = 0; i < mOffset; i++) {
+    AutoTArray<OwningNonNull<nsIContent>, 24> movingChildren;
+    if (nsIContent* child = mRightContent->GetFirstChild()) {
+      movingChildren.AppendElement(*child);
+      for (uint32_t i = 0; i < mOffset; i++) {
+        child = child->GetNextSibling();
+        if (!child) {
+          break;
+        }
+        movingChildren.AppendElement(*child);
+      }
+    }
+    for (OwningNonNull<nsIContent>& child : movingChildren) {
+      leftContent->AppendChild(child, error);
       if (error.Failed()) {
+        NS_WARNING("nsINode::AppendChild() failed");
         return error.StealNSResult();
       }
-      if (!child) {
-        return NS_ERROR_NULL_POINTER;
-      }
-      nsCOMPtr<nsIContent> nextSibling = child->GetNextSibling();
-      mLeftNode->AppendChild(*child, error);
-      NS_WARNING_ASSERTION(!error.Failed(), "nsINode::AppendChild() failed");
-      child = nextSibling;
     }
   }
 
   NS_WARNING_ASSERTION(!error.Failed(), "The previous error was ignored");
 
   // Second, re-insert the left node into the tree
-  nsCOMPtr<nsINode> refNode = mRightNode;
-  mParent->InsertBefore(*mLeftNode, refNode, error);
+  parentNode->InsertBefore(leftContent, rightContent, error);
   NS_WARNING_ASSERTION(!error.Failed(), "nsINode::InsertBefore() failed");
   return error.StealNSResult();
 }
 
 }  // namespace mozilla
--- a/editor/libeditor/JoinNodeTransaction.h
+++ b/editor/libeditor/JoinNodeTransaction.h
@@ -7,69 +7,71 @@
 #define JoinNodeTransaction_h
 
 #include "mozilla/EditTransactionBase.h"  // for EditTransactionBase, etc.
 #include "nsCOMPtr.h"                     // for nsCOMPtr
 #include "nsCycleCollectionParticipant.h"
 #include "nsID.h"    // for REFNSIID
 #include "nscore.h"  // for NS_IMETHOD
 
+class nsIContent;
 class nsINode;
 
 namespace mozilla {
 
 class EditorBase;
 
 /**
  * A transaction that joins two nodes E1 (left node) and E2 (right node) into a
  * single node E.  The children of E are the children of E1 followed by the
  * children of E2.  After DoTransaction() and RedoTransaction(), E1 is removed
  * from the content tree and E2 remains.
  */
 class JoinNodeTransaction final : public EditTransactionBase {
  protected:
-  JoinNodeTransaction(EditorBase& aEditorBase, nsINode& aLeftNode,
-                      nsINode& aRightNode);
+  JoinNodeTransaction(EditorBase& aEditorBase, nsIContent& aLeftContent,
+                      nsIContent& aRightContent);
 
  public:
   /**
    * Creates a join node transaction.  This returns nullptr if cannot join the
    * nodes.
    *
    * @param aEditorBase     The provider of core editing operations.
-   * @param aLeftNode       The first of two nodes to join.
-   * @param aRightNode      The second of two nodes to join.
+   * @param aLeftContent    The first of two nodes to join.
+   * @param aRightContent   The second of two nodes to join.
    */
   static already_AddRefed<JoinNodeTransaction> MaybeCreate(
-      EditorBase& aEditorBase, nsINode& aLeftNode, nsINode& aRightNode);
+      EditorBase& aEditorBase, nsIContent& aLeftContent,
+      nsIContent& aRightContent);
 
   /**
    * CanDoIt() returns true if there are enough members and can join or
    * restore the nodes.  Otherwise, false.
    */
   bool CanDoIt() const;
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(JoinNodeTransaction,
                                            EditTransactionBase)
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
 
   NS_DECL_EDITTRANSACTIONBASE
 
  protected:
   RefPtr<EditorBase> mEditorBase;
 
-  // The nodes to operate upon.  After the merge, mRightNode remains and
-  // mLeftNode is removed from the content tree.
-  nsCOMPtr<nsINode> mLeftNode;
-  nsCOMPtr<nsINode> mRightNode;
+  // The nodes to operate upon.  After the merge, mRightContent remains and
+  // mLeftContent is removed from the content tree.
+  nsCOMPtr<nsIContent> mLeftContent;
+  nsCOMPtr<nsIContent> mRightContent;
 
   // The offset into mNode where the children of mElement are split (for
   // undo). mOffset is the index of the first child in the right node.  -1
   // means the left node had no children.
   uint32_t mOffset;
 
-  // The parent node containing mLeftNode and mRightNode.
-  nsCOMPtr<nsINode> mParent;
+  // The parent node containing mLeftContent and mRightContent.
+  nsCOMPtr<nsINode> mParentNode;
 };
 
 }  // namespace mozilla
 
 #endif  // #ifndef JoinNodeTransaction_h
--- a/editor/libeditor/SplitNodeTransaction.cpp
+++ b/editor/libeditor/SplitNodeTransaction.cpp
@@ -13,92 +13,93 @@
 #include "nsError.h"     // for NS_ERROR_NOT_INITIALIZED, etc.
 #include "nsIContent.h"  // for nsIContent
 
 namespace mozilla {
 
 using namespace dom;
 
 template already_AddRefed<SplitNodeTransaction> SplitNodeTransaction::Create(
-    EditorBase& aEditorBase, const EditorDOMPoint& aStartOfRightNode);
+    EditorBase& aEditorBase, const EditorDOMPoint& aStartOfRightContent);
 template already_AddRefed<SplitNodeTransaction> SplitNodeTransaction::Create(
-    EditorBase& aEditorBase, const EditorRawDOMPoint& aStartOfRightNode);
+    EditorBase& aEditorBase, const EditorRawDOMPoint& aStartOfRightContent);
 
 // static
 template <typename PT, typename CT>
 already_AddRefed<SplitNodeTransaction> SplitNodeTransaction::Create(
     EditorBase& aEditorBase,
-    const EditorDOMPointBase<PT, CT>& aStartOfRightNode) {
+    const EditorDOMPointBase<PT, CT>& aStartOfRightContent) {
   RefPtr<SplitNodeTransaction> transaction =
-      new SplitNodeTransaction(aEditorBase, aStartOfRightNode);
+      new SplitNodeTransaction(aEditorBase, aStartOfRightContent);
   return transaction.forget();
 }
 
 template <typename PT, typename CT>
 SplitNodeTransaction::SplitNodeTransaction(
     EditorBase& aEditorBase,
-    const EditorDOMPointBase<PT, CT>& aStartOfRightNode)
-    : mEditorBase(&aEditorBase), mStartOfRightNode(aStartOfRightNode) {
-  MOZ_DIAGNOSTIC_ASSERT(aStartOfRightNode.IsSet());
-  MOZ_DIAGNOSTIC_ASSERT(aStartOfRightNode.GetContainerAsContent());
+    const EditorDOMPointBase<PT, CT>& aStartOfRightContent)
+    : mEditorBase(&aEditorBase), mStartOfRightContent(aStartOfRightContent) {
+  MOZ_DIAGNOSTIC_ASSERT(aStartOfRightContent.IsSet());
+  MOZ_DIAGNOSTIC_ASSERT(aStartOfRightContent.GetContainerAsContent());
 }
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(SplitNodeTransaction, EditTransactionBase,
-                                   mEditorBase, mStartOfRightNode, mParent,
-                                   mNewLeftNode)
+                                   mEditorBase, mStartOfRightContent,
+                                   mContainerParentNode, mNewLeftContent)
 
 NS_IMPL_ADDREF_INHERITED(SplitNodeTransaction, EditTransactionBase)
 NS_IMPL_RELEASE_INHERITED(SplitNodeTransaction, EditTransactionBase)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SplitNodeTransaction)
 NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
 
 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP
 SplitNodeTransaction::DoTransaction() {
-  if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mStartOfRightNode.IsSet())) {
-    return NS_ERROR_NOT_INITIALIZED;
+  if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mStartOfRightContent.IsSet())) {
+    return NS_ERROR_NOT_AVAILABLE;
   }
-  MOZ_ASSERT(mStartOfRightNode.IsSetAndValid());
+  MOZ_ASSERT(mStartOfRightContent.IsSetAndValid());
 
   // Create a new node
   ErrorResult error;
   // Don't use .downcast directly because AsContent has an assertion we want
   nsCOMPtr<nsINode> cloneOfRightContainer =
-      mStartOfRightNode.GetContainer()->CloneNode(false, error);
+      mStartOfRightContent.GetContainer()->CloneNode(false, error);
   if (error.Failed()) {
     NS_WARNING("nsINode::CloneNode() failed");
     return error.StealNSResult();
   }
   if (NS_WARN_IF(!cloneOfRightContainer)) {
     return NS_ERROR_UNEXPECTED;
   }
 
-  RefPtr<EditorBase> editorBase(mEditorBase);
+  mNewLeftContent = cloneOfRightContainer->AsContent();
+
+  mContainerParentNode = mStartOfRightContent.GetContainerParent();
+  if (!mContainerParentNode) {
+    NS_WARNING("Right container was an orphan node");
+    return NS_ERROR_NOT_AVAILABLE;
+  }
 
-  mNewLeftNode = cloneOfRightContainer->AsContent();
+  OwningNonNull<EditorBase> editorBase = *mEditorBase;
+  OwningNonNull<nsIContent> newLeftContent = *mNewLeftContent;
+  OwningNonNull<nsINode> containerParentNode = *mContainerParentNode;
+  EditorDOMPoint startOfRightContent(mStartOfRightContent);
+
   if (RefPtr<Element> startOfRightNode =
-          mStartOfRightNode.GetContainerAsElement()) {
+          startOfRightContent.GetContainerAsElement()) {
     nsresult rv = editorBase->MarkElementDirty(*startOfRightNode);
     if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
       return EditorBase::ToGenericNSResult(rv);
     }
     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
                          "EditorBase::MarkElementDirty() failed, but ignored");
   }
 
-  // Get the parent node
-  mParent = mStartOfRightNode.GetContainerParent();
-  if (!mParent) {
-    NS_WARNING("Right container was an orphan node");
-    return NS_ERROR_FAILURE;
-  }
-
   // Insert the new node
-  nsCOMPtr<nsIContent> newLeftNode = mNewLeftNode;
-  editorBase->DoSplitNode(EditorDOMPoint(mStartOfRightNode), *newLeftNode,
-                          error);
+  editorBase->DoSplitNode(startOfRightContent, newLeftContent, error);
   if (error.Failed()) {
     NS_WARNING("EditorBase::DoSplitNode() failed");
     return error.StealNSResult();
   }
 
   if (!editorBase->AllowsTransactionsToChangeSelection()) {
     return NS_OK;
   }
@@ -106,94 +107,92 @@ SplitNodeTransaction::DoTransaction() {
   NS_WARNING_ASSERTION(
       !editorBase->Destroyed(),
       "The editor has gone but SplitNodeTransaction keeps trying to modify "
       "Selection");
   RefPtr<Selection> selection = editorBase->GetSelection();
   if (NS_WARN_IF(!selection)) {
     return NS_ERROR_FAILURE;
   }
-  EditorRawDOMPoint atEndOfLeftNode(EditorRawDOMPoint::AtEndOf(mNewLeftNode));
+  EditorRawDOMPoint atEndOfLeftNode(EditorRawDOMPoint::AtEndOf(newLeftContent));
   selection->Collapse(atEndOfLeftNode, error);
   NS_WARNING_ASSERTION(!error.Failed(), "Selection::Collapse() failed");
   return error.StealNSResult();
 }
 
 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP
 SplitNodeTransaction::UndoTransaction() {
-  if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mNewLeftNode) ||
-      NS_WARN_IF(!mParent) || NS_WARN_IF(!mStartOfRightNode.IsSet())) {
-    return NS_ERROR_NOT_INITIALIZED;
+  if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mNewLeftContent) ||
+      NS_WARN_IF(!mContainerParentNode) ||
+      NS_WARN_IF(!mStartOfRightContent.IsSet())) {
+    return NS_ERROR_NOT_AVAILABLE;
   }
 
   // This assumes Do inserted the new node in front of the prior existing node
   // XXX Perhaps, we should reset mStartOfRightNode with current first child
   //     of the right node.
-  RefPtr<EditorBase> editorBase = mEditorBase;
-  nsCOMPtr<nsINode> container = mStartOfRightNode.GetContainer();
-  nsCOMPtr<nsINode> newLeftNode = mNewLeftNode;
-  nsCOMPtr<nsINode> parent = mParent;
-  nsresult rv = editorBase->DoJoinNodes(container, newLeftNode, parent);
+  OwningNonNull<EditorBase> editorBase = *mEditorBase;
+  OwningNonNull<nsINode> containerNode = *mStartOfRightContent.GetContainer();
+  OwningNonNull<nsINode> newLeftContent = *mNewLeftContent;
+  OwningNonNull<nsINode> containerParentNode = *mContainerParentNode;
+  nsresult rv = editorBase->DoJoinNodes(containerNode, newLeftContent,
+                                        containerParentNode);
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "EditorBase::DoJoinNodes() failed");
   return rv;
 }
 
 /* Redo cannot simply resplit the right node, because subsequent transactions
  * on the redo stack may depend on the left node existing in its previous
  * state.
  */
 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP
 SplitNodeTransaction::RedoTransaction() {
-  if (NS_WARN_IF(!mNewLeftNode) || NS_WARN_IF(!mParent) ||
-      NS_WARN_IF(!mStartOfRightNode.IsSet()) || NS_WARN_IF(!mEditorBase)) {
-    return NS_ERROR_NOT_INITIALIZED;
+  if (NS_WARN_IF(!mNewLeftContent) || NS_WARN_IF(!mContainerParentNode) ||
+      NS_WARN_IF(!mStartOfRightContent.IsSet()) || NS_WARN_IF(!mEditorBase)) {
+    return NS_ERROR_NOT_AVAILABLE;
   }
 
+  OwningNonNull<EditorBase> editorBase = *mEditorBase;
+  OwningNonNull<nsINode> newLeftContent = *mNewLeftContent;
+  OwningNonNull<nsINode> containerParentNode = *mContainerParentNode;
+  EditorDOMPoint startOfRightContent(mStartOfRightContent);
+
   // First, massage the existing node so it is in its post-split state
   ErrorResult error;
-  if (mStartOfRightNode.IsInTextNode()) {
-    RefPtr<EditorBase> editorBase = mEditorBase;
-    RefPtr<Text> rightNodeAsText = mStartOfRightNode.GetContainerAsText();
-    MOZ_DIAGNOSTIC_ASSERT(rightNodeAsText);
-    editorBase->DoDeleteText(*rightNodeAsText, 0, mStartOfRightNode.Offset(),
-                             error);
+  if (startOfRightContent.IsInTextNode()) {
+    Text* rightTextNode = startOfRightContent.ContainerAsText();
+    editorBase->DoDeleteText(MOZ_KnownLive(*rightTextNode), 0,
+                             startOfRightContent.Offset(), error);
     if (error.Failed()) {
       NS_WARNING("EditorBase::DoDeleteText() failed");
       return error.StealNSResult();
     }
   } else {
-    nsCOMPtr<nsIContent> child =
-        mStartOfRightNode.GetContainer()->GetFirstChild();
-    nsCOMPtr<nsIContent> nextSibling;
+    AutoTArray<OwningNonNull<nsIContent>, 24> movingChildren;
+    if (nsIContent* child =
+            startOfRightContent.GetContainer()->GetFirstChild()) {
+      movingChildren.AppendElement(*child);
+      for (uint32_t i = 0; i < startOfRightContent.Offset(); i++) {
+        child = child->GetNextSibling();
+        if (!child) {
+          break;
+        }
+        movingChildren.AppendElement(*child);
+      }
+    }
     ErrorResult error;
-    for (uint32_t i = 0; i < mStartOfRightNode.Offset(); i++) {
-      // XXX This must be bad behavior.  Perhaps, we should work with
-      //     mStartOfRightNode::GetChild().  Even if some children
-      //     before the right node have been inserted or removed, we should
-      //     move all children before the right node because user must focus
-      //     on the right node, so, it must be the expected behavior.
-      if (NS_WARN_IF(!child)) {
-        return NS_ERROR_NULL_POINTER;
-      }
-      nextSibling = child->GetNextSibling();
-      mStartOfRightNode.GetContainer()->RemoveChild(*child, error);
-      if (error.Failed()) {
-        NS_WARNING("nsINode::RemoveChild() failed");
-        return error.StealNSResult();
-      }
-      mNewLeftNode->AppendChild(*child, error);
+    for (OwningNonNull<nsIContent>& child : movingChildren) {
+      newLeftContent->AppendChild(child, error);
       if (error.Failed()) {
         NS_WARNING("nsINode::AppendChild() failed");
         return error.StealNSResult();
       }
-      child = nextSibling;
     }
   }
   MOZ_ASSERT(!error.Failed());
   // Second, re-insert the left node into the tree
-  mParent->InsertBefore(*mNewLeftNode, mStartOfRightNode.GetContainer(), error);
+  containerParentNode->InsertBefore(newLeftContent,
+                                    startOfRightContent.GetContainer(), error);
   NS_WARNING_ASSERTION(!error.Failed(), "nsINode::InsertBefore() failed");
   return error.StealNSResult();
 }
 
-nsIContent* SplitNodeTransaction::GetNewNode() { return mNewLeftNode; }
-
 }  // namespace mozilla
--- a/editor/libeditor/SplitNodeTransaction.h
+++ b/editor/libeditor/SplitNodeTransaction.h
@@ -5,74 +5,72 @@
 
 #ifndef SplitNodeTransaction_h
 #define SplitNodeTransaction_h
 
 #include "mozilla/EditorDOMPoint.h"  // for RangeBoundary, EditorRawDOMPoint
 #include "mozilla/EditTransactionBase.h"  // for EditTxn, etc.
 #include "nsCOMPtr.h"                     // for nsCOMPtr
 #include "nsCycleCollectionParticipant.h"
+#include "nsIContent.h"
 #include "nsISupportsImpl.h"  // for NS_DECL_ISUPPORTS_INHERITED
 #include "nscore.h"           // for NS_IMETHOD
 
-class nsIContent;
-class nsINode;
-
 namespace mozilla {
 
 class EditorBase;
 
 /**
  * A transaction that splits a node into two identical nodes, with the children
  * divided between the new nodes.
  */
 class SplitNodeTransaction final : public EditTransactionBase {
  private:
   template <typename PT, typename CT>
   SplitNodeTransaction(EditorBase& aEditorBase,
-                       const EditorDOMPointBase<PT, CT>& aStartOfRightNode);
+                       const EditorDOMPointBase<PT, CT>& aStartOfRightContent);
 
  public:
   /**
    * Creates a transaction to create a new node (left node) identical to an
    * existing node (right node), and split the contents between the same point
    * in both nodes.
    *
-   * @param aEditorBase         The provider of core editing operations.
-   * @param aStartOfRightNode   The point to split.  Its container will be
-   *                            the right node, i.e., become the new node's
-   *                            next sibling.  And the point will be start
-   *                            of the right node.
+   * @param aEditorBase             The provider of core editing operations.
+   * @param aStartOfRightContent    The point to split.  Its container will be
+   *                                the right node, i.e., become the new node's
+   *                                next sibling.  And the point will be start
+   *                                of the right node.
    */
   template <typename PT, typename CT>
   static already_AddRefed<SplitNodeTransaction> Create(
       EditorBase& aEditorBase,
-      const EditorDOMPointBase<PT, CT>& aStartOfRightNode);
+      const EditorDOMPointBase<PT, CT>& aStartOfRightContent);
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(SplitNodeTransaction,
                                            EditTransactionBase)
 
   NS_DECL_EDITTRANSACTIONBASE
 
   NS_IMETHOD RedoTransaction() override;
 
-  nsIContent* GetNewNode();
+  nsIContent* GetNewLeftContent() const { return mNewLeftContent; }
 
  protected:
   virtual ~SplitNodeTransaction() = default;
 
   RefPtr<EditorBase> mEditorBase;
 
   // The container is existing right node (will be split).
   // The point referring this is start of the right node after it's split.
-  EditorDOMPoint mStartOfRightNode;
+  EditorDOMPoint mStartOfRightContent;
 
-  // The node we create when splitting mExistingRightNode.
-  nsCOMPtr<nsIContent> mNewLeftNode;
+  // The node we create when splitting mExistingRightContent.
+  nsCOMPtr<nsIContent> mNewLeftContent;
 
-  // The parent shared by mExistingRightNode and mNewLeftNode.
-  nsCOMPtr<nsINode> mParent;
+  // The parent shared by mExistingRightContent and mNewLeftContent.
+  nsCOMPtr<nsINode> mContainerParentNode;
 };
 
 }  // namespace mozilla
 
 #endif  // #ifndef SplitNodeTransaction_h