Bug 1349138 Edit transactions should store their editor instance with strong reference r=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Tue, 21 Mar 2017 19:00:36 +0900
changeset 349374 596faf466bbc07412cfa2277ef4d233c748fc233
parent 349373 b5c478da01df453d8e8630f98558f5500548298e
child 349375 d5b7156ec45f277a225608c1e719cbb946850527
push id88408
push usermasayuki@d-toybox.com
push dateFri, 24 Mar 2017 03:14:46 +0000
treeherdermozilla-inbound@596faf466bbc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1349138
milestone55.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 1349138 Edit transactions should store their editor instance with strong reference r=smaug Edit transactions should store their editor instance with strong reference and they should be released at destroying the editor. MozReview-Commit-ID: D67KU8WFxyo
editor/libeditor/CompositionTransaction.cpp
editor/libeditor/CompositionTransaction.h
editor/libeditor/CreateElementTransaction.cpp
editor/libeditor/CreateElementTransaction.h
editor/libeditor/DeleteNodeTransaction.cpp
editor/libeditor/DeleteNodeTransaction.h
editor/libeditor/DeleteRangeTransaction.cpp
editor/libeditor/DeleteRangeTransaction.h
editor/libeditor/DeleteTextTransaction.cpp
editor/libeditor/DeleteTextTransaction.h
editor/libeditor/EditorBase.cpp
editor/libeditor/InsertNodeTransaction.cpp
editor/libeditor/InsertNodeTransaction.h
editor/libeditor/InsertTextTransaction.cpp
editor/libeditor/InsertTextTransaction.h
editor/libeditor/JoinNodeTransaction.cpp
editor/libeditor/JoinNodeTransaction.h
editor/libeditor/PlaceholderTransaction.cpp
editor/libeditor/PlaceholderTransaction.h
editor/libeditor/SplitNodeTransaction.cpp
editor/libeditor/SplitNodeTransaction.h
editor/libeditor/StyleSheetTransactions.cpp
editor/libeditor/StyleSheetTransactions.h
--- a/editor/libeditor/CompositionTransaction.cpp
+++ b/editor/libeditor/CompositionTransaction.cpp
@@ -28,46 +28,51 @@ CompositionTransaction::CompositionTrans
                           const nsAString& aStringToInsert,
                           EditorBase& aEditorBase,
                           RangeUpdater* aRangeUpdater)
   : mTextNode(&aTextNode)
   , mOffset(aOffset)
   , mReplaceLength(aReplaceLength)
   , mRanges(aTextRangeArray)
   , mStringToInsert(aStringToInsert)
-  , mEditorBase(aEditorBase)
+  , mEditorBase(&aEditorBase)
   , mRangeUpdater(aRangeUpdater)
   , mFixed(false)
 {
   MOZ_ASSERT(mTextNode->TextLength() >= mOffset);
 }
 
 CompositionTransaction::~CompositionTransaction()
 {
 }
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(CompositionTransaction, EditTransactionBase,
+                                   mEditorBase,
                                    mTextNode)
 // mRangeList can't lead to cycles
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CompositionTransaction)
   if (aIID.Equals(NS_GET_IID(CompositionTransaction))) {
     foundInterface = static_cast<nsITransaction*>(this);
   } else
 NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
 
 NS_IMPL_ADDREF_INHERITED(CompositionTransaction, EditTransactionBase)
 NS_IMPL_RELEASE_INHERITED(CompositionTransaction, EditTransactionBase)
 
 NS_IMETHODIMP
 CompositionTransaction::DoTransaction()
 {
+  if (NS_WARN_IF(!mEditorBase)) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
+
   // Fail before making any changes if there's no selection controller
   nsCOMPtr<nsISelectionController> selCon;
-  mEditorBase.GetSelectionController(getter_AddRefs(selCon));
+  mEditorBase->GetSelectionController(getter_AddRefs(selCon));
   NS_ENSURE_TRUE(selCon, NS_ERROR_NOT_INITIALIZED);
 
   // Advance caret: This requires the presentation shell to get the selection.
   if (mReplaceLength == 0) {
     nsresult rv = mTextNode->InsertData(mOffset, mStringToInsert);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
@@ -103,19 +108,23 @@ CompositionTransaction::DoTransaction()
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 CompositionTransaction::UndoTransaction()
 {
+  if (NS_WARN_IF(!mEditorBase)) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
+
   // Get the selection first so we'll fail before making any changes if we
   // can't get it
-  RefPtr<Selection> selection = mEditorBase.GetSelection();
+  RefPtr<Selection> selection = mEditorBase->GetSelection();
   NS_ENSURE_TRUE(selection, NS_ERROR_NOT_INITIALIZED);
 
   nsresult rv = mTextNode->DeleteData(mOffset, mStringToInsert.Length());
   NS_ENSURE_SUCCESS(rv, rv);
 
   // set the selection to the insertion point where the string was removed
   rv = selection->Collapse(mTextNode, mOffset);
   NS_ASSERTION(NS_SUCCEEDED(rv),
@@ -166,17 +175,20 @@ CompositionTransaction::GetTxnDescriptio
   return NS_OK;
 }
 
 /* ============ private methods ================== */
 
 nsresult
 CompositionTransaction::SetSelectionForRanges()
 {
-  return SetIMESelection(mEditorBase, mTextNode, mOffset,
+  if (NS_WARN_IF(!mEditorBase)) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
+  return SetIMESelection(*mEditorBase, mTextNode, mOffset,
                          mStringToInsert.Length(), mRanges);
 }
 
 // static
 nsresult
 CompositionTransaction::SetIMESelection(EditorBase& aEditorBase,
                                         Text* aTextNode,
                                         uint32_t aOffsetInNode,
--- a/editor/libeditor/CompositionTransaction.h
+++ b/editor/libeditor/CompositionTransaction.h
@@ -85,17 +85,17 @@ private:
 
   // The range list.
   RefPtr<TextRangeArray> mRanges;
 
   // The text to insert into mTextNode at mOffset.
   nsString mStringToInsert;
 
   // The editor, which is used to get the selection controller.
-  EditorBase& mEditorBase;
+  RefPtr<EditorBase> mEditorBase;
 
   RangeUpdater* mRangeUpdater;
 
   bool mFixed;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(CompositionTransaction, NS_IMETEXTTXN_IID)
 
--- a/editor/libeditor/CreateElementTransaction.cpp
+++ b/editor/libeditor/CreateElementTransaction.cpp
@@ -44,30 +44,33 @@ CreateElementTransaction::CreateElementT
 }
 
 CreateElementTransaction::~CreateElementTransaction()
 {
 }
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(CreateElementTransaction,
                                    EditTransactionBase,
+                                   mEditorBase,
                                    mParent,
                                    mNewNode,
                                    mRefNode)
 
 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)
 
 
 NS_IMETHODIMP
 CreateElementTransaction::DoTransaction()
 {
-  MOZ_ASSERT(mEditorBase && mTag && mParent);
+  if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTag) || NS_WARN_IF(!mParent)) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
 
   mNewNode = mEditorBase->CreateHTMLContent(mTag);
   NS_ENSURE_STATE(mNewNode);
 
   // Try to insert formatting whitespace for the new node:
   mEditorBase->MarkNodeDirty(GetAsDOMNode(mNewNode));
 
   // Insert the new node
@@ -100,28 +103,32 @@ CreateElementTransaction::DoTransaction(
   NS_ASSERTION(!rv.Failed(),
                "selection could not be collapsed after insert");
   return NS_OK;
 }
 
 NS_IMETHODIMP
 CreateElementTransaction::UndoTransaction()
 {
-  MOZ_ASSERT(mEditorBase && mParent);
+  if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mParent)) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
 
   ErrorResult rv;
   mParent->RemoveChild(*mNewNode, rv);
 
   return rv.StealNSResult();
 }
 
 NS_IMETHODIMP
 CreateElementTransaction::RedoTransaction()
 {
-  MOZ_ASSERT(mEditorBase && mParent);
+  if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mParent)) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
 
   // 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)
 
   // Now, reinsert mNewNode
   ErrorResult rv;
   nsCOMPtr<nsIContent> refNode = mRefNode;
--- a/editor/libeditor/CreateElementTransaction.h
+++ b/editor/libeditor/CreateElementTransaction.h
@@ -52,17 +52,17 @@ public:
   NS_IMETHOD RedoTransaction() override;
 
   already_AddRefed<dom::Element> GetNewNode();
 
 protected:
   virtual ~CreateElementTransaction();
 
   // The document into which the new node will be inserted.
-  EditorBase* mEditorBase;
+  RefPtr<EditorBase> mEditorBase;
 
   // The tag (mapping to object type) for the new element.
   nsCOMPtr<nsIAtom> mTag;
 
   // The node into which the new node will be inserted.
   nsCOMPtr<nsINode> mParent;
 
   // The index in mParent for the new node.
--- a/editor/libeditor/DeleteNodeTransaction.cpp
+++ b/editor/libeditor/DeleteNodeTransaction.cpp
@@ -10,46 +10,47 @@
 #include "nsError.h"
 #include "nsAString.h"
 
 namespace mozilla {
 
 DeleteNodeTransaction::DeleteNodeTransaction(EditorBase& aEditorBase,
                                              nsINode& aNodeToDelete,
                                              RangeUpdater* aRangeUpdater)
-  : mEditorBase(aEditorBase)
+  : mEditorBase(&aEditorBase)
   , mNodeToDelete(&aNodeToDelete)
   , mParentNode(aNodeToDelete.GetParentNode())
   , mRangeUpdater(aRangeUpdater)
 {
   // XXX We're not sure if this is really necessary.
   if (!CanDoIt()) {
     mRangeUpdater = nullptr;
   }
 }
 
 DeleteNodeTransaction::~DeleteNodeTransaction()
 {
 }
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(DeleteNodeTransaction, EditTransactionBase,
+                                   mEditorBase,
                                    mNodeToDelete,
                                    mParentNode,
                                    mRefNode)
 
 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) || !mParentNode ||
-      !mEditorBase.IsModifiableNode(mParentNode)) {
+  if (NS_WARN_IF(!mNodeToDelete) || NS_WARN_IF(!mEditorBase) ||
+      !mParentNode || !mEditorBase->IsModifiableNode(mParentNode)) {
     return false;
   }
   return true;
 }
 
 NS_IMETHODIMP
 DeleteNodeTransaction::DoTransaction()
 {
--- a/editor/libeditor/DeleteNodeTransaction.h
+++ b/editor/libeditor/DeleteNodeTransaction.h
@@ -41,17 +41,17 @@ public:
   NS_DECL_EDITTRANSACTIONBASE
 
   NS_IMETHOD RedoTransaction() override;
 
 protected:
   virtual ~DeleteNodeTransaction();
 
   // The editor for this transaction.
-  EditorBase& mEditorBase;
+  RefPtr<EditorBase> mEditorBase;
 
   // The element to delete.
   nsCOMPtr<nsINode> mNodeToDelete;
 
   // Parent of node to delete.
   nsCOMPtr<nsINode> mParentNode;
 
   // Next sibling to remember for undo/redo purposes.
--- a/editor/libeditor/DeleteRangeTransaction.cpp
+++ b/editor/libeditor/DeleteRangeTransaction.cpp
@@ -22,33 +22,36 @@
 namespace mozilla {
 
 using namespace dom;
 
 // note that aEditorBase is not refcounted
 DeleteRangeTransaction::DeleteRangeTransaction(EditorBase& aEditorBase,
                                                nsRange& aRangeToDelete,
                                                RangeUpdater* aRangeUpdater)
-  : mEditorBase(aEditorBase)
+  : mEditorBase(&aEditorBase)
   , mRangeToDelete(aRangeToDelete.CloneRange())
   , mRangeUpdater(aRangeUpdater)
 {
 }
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(DeleteRangeTransaction,
                                    EditAggregateTransaction,
+                                   mEditorBase,
                                    mRangeToDelete)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DeleteRangeTransaction)
 NS_INTERFACE_MAP_END_INHERITING(EditAggregateTransaction)
 
 NS_IMETHODIMP
 DeleteRangeTransaction::DoTransaction()
 {
-  MOZ_ASSERT(mRangeToDelete);
+  if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mRangeToDelete)) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
 
   // build the child transactions
   nsCOMPtr<nsINode> startParent = mRangeToDelete->GetStartParent();
   int32_t startOffset = mRangeToDelete->StartOffset();
   nsCOMPtr<nsINode> endParent = mRangeToDelete->GetEndParent();
   int32_t endOffset = mRangeToDelete->EndOffset();
   MOZ_ASSERT(startParent && endParent);
 
@@ -72,19 +75,19 @@ DeleteRangeTransaction::DoTransaction()
   }
 
   // if we've successfully built this aggregate transaction, then do it.
   nsresult rv = EditAggregateTransaction::DoTransaction();
   NS_ENSURE_SUCCESS(rv, rv);
 
   // only set selection to deletion point if editor gives permission
   bool bAdjustSelection;
-  mEditorBase.ShouldTxnSetSelection(&bAdjustSelection);
+  mEditorBase->ShouldTxnSetSelection(&bAdjustSelection);
   if (bAdjustSelection) {
-    RefPtr<Selection> selection = mEditorBase.GetSelection();
+    RefPtr<Selection> selection = mEditorBase->GetSelection();
     NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
     rv = selection->Collapse(startParent, startOffset);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   // else do nothing - dom range gravity will adjust selection
 
   return NS_OK;
 }
@@ -112,31 +115,35 @@ DeleteRangeTransaction::GetTxnDescriptio
   return NS_OK;
 }
 
 nsresult
 DeleteRangeTransaction::CreateTxnsToDeleteBetween(nsINode* aNode,
                                                   int32_t aStartOffset,
                                                   int32_t aEndOffset)
 {
+  if (NS_WARN_IF(!mEditorBase)) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
   // see what kind of node we have
   if (aNode->IsNodeOfType(nsINode::eDATA_NODE)) {
     // if the node is a chardata node, then delete chardata content
     int32_t numToDel;
     if (aStartOffset == aEndOffset) {
       numToDel = 1;
     } else {
       numToDel = aEndOffset - aStartOffset;
     }
 
     RefPtr<nsGenericDOMDataNode> charDataNode =
       static_cast<nsGenericDOMDataNode*>(aNode);
 
     RefPtr<DeleteTextTransaction> deleteTextTransaction =
-      new DeleteTextTransaction(mEditorBase, *charDataNode, aStartOffset,
+      new DeleteTextTransaction(*mEditorBase, *charDataNode, aStartOffset,
                                 numToDel, mRangeUpdater);
     // If the text node isn't editable, it should be never undone/redone.
     // So, the transaction shouldn't be recorded.
     if (NS_WARN_IF(!deleteTextTransaction->CanDoIt())) {
       return NS_ERROR_FAILURE;
     }
     AppendChild(deleteTextTransaction);
     return NS_OK;
@@ -145,17 +152,17 @@ DeleteRangeTransaction::CreateTxnsToDele
   nsCOMPtr<nsIContent> child = aNode->GetChildAt(aStartOffset);
   for (int32_t i = aStartOffset; i < aEndOffset; ++i) {
     // Even if we detect invalid range, we should ignore it for removing
     // specified range's nodes as far as possible.
     if (NS_WARN_IF(!child)) {
       break;
     }
     RefPtr<DeleteNodeTransaction> deleteNodeTransaction =
-      new DeleteNodeTransaction(mEditorBase, *child, mRangeUpdater);
+      new DeleteNodeTransaction(*mEditorBase, *child, mRangeUpdater);
     // XXX This is odd handling.  Even if some children are not editable,
     //     editor should append transactions because they could be editable
     //     at undoing/redoing.  Additionally, if the transaction needs to
     //     delete/restore all nodes, it should at undoing/redoing.
     if (deleteNodeTransaction->CanDoIt()) {
       AppendChild(deleteNodeTransaction);
     }
     child = child->GetNextSibling();
@@ -164,62 +171,70 @@ DeleteRangeTransaction::CreateTxnsToDele
   return NS_OK;
 }
 
 nsresult
 DeleteRangeTransaction::CreateTxnsToDeleteContent(nsINode* aNode,
                                                   int32_t aOffset,
                                                   nsIEditor::EDirection aAction)
 {
+  if (NS_WARN_IF(!mEditorBase)) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
   // see what kind of node we have
   if (aNode->IsNodeOfType(nsINode::eDATA_NODE)) {
     // if the node is a chardata node, then delete chardata content
     uint32_t start, numToDelete;
     if (nsIEditor::eNext == aAction) {
       start = aOffset;
       numToDelete = aNode->Length() - aOffset;
     } else {
       start = 0;
       numToDelete = aOffset;
     }
 
     if (numToDelete) {
       RefPtr<nsGenericDOMDataNode> dataNode =
         static_cast<nsGenericDOMDataNode*>(aNode);
       RefPtr<DeleteTextTransaction> deleteTextTransaction =
-        new DeleteTextTransaction(mEditorBase, *dataNode, start, numToDelete,
+        new DeleteTextTransaction(*mEditorBase, *dataNode, start, numToDelete,
                                   mRangeUpdater);
       // If the text node isn't editable, it should be never undone/redone.
       // So, the transaction shouldn't be recorded.
       if (NS_WARN_IF(!deleteTextTransaction->CanDoIt())) {
         return NS_ERROR_FAILURE;
       }
       AppendChild(deleteTextTransaction);
     }
   }
 
   return NS_OK;
 }
 
 nsresult
 DeleteRangeTransaction::CreateTxnsToDeleteNodesBetween()
 {
+  if (NS_WARN_IF(!mEditorBase)) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
   nsCOMPtr<nsIContentIterator> iter = NS_NewContentSubtreeIterator();
 
   nsresult rv = iter->Init(mRangeToDelete);
   NS_ENSURE_SUCCESS(rv, rv);
 
   while (!iter->IsDone()) {
     nsCOMPtr<nsINode> node = iter->GetCurrentNode();
     if (NS_WARN_IF(!node)) {
       return NS_ERROR_NULL_POINTER;
     }
 
     RefPtr<DeleteNodeTransaction> deleteNodeTransaction =
-      new DeleteNodeTransaction(mEditorBase, *node, mRangeUpdater);
+      new DeleteNodeTransaction(*mEditorBase, *node, mRangeUpdater);
     // 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 (NS_WARN_IF(!deleteNodeTransaction->CanDoIt())) {
       return NS_ERROR_FAILURE;
     }
     AppendChild(deleteNodeTransaction);
--- a/editor/libeditor/DeleteRangeTransaction.h
+++ b/editor/libeditor/DeleteRangeTransaction.h
@@ -56,17 +56,17 @@ protected:
 
   nsresult CreateTxnsToDeleteNodesBetween();
 
   nsresult CreateTxnsToDeleteContent(nsINode* aParent,
                                      int32_t aOffset,
                                      nsIEditor::EDirection aAction);
 
   // The editor for this transaction.
-  EditorBase& mEditorBase;
+  RefPtr<EditorBase> mEditorBase;
 
   // P1 in the range.
   RefPtr<nsRange> mRangeToDelete;
 
   // Range updater object.
   RangeUpdater* mRangeUpdater;
 };
 
--- a/editor/libeditor/DeleteTextTransaction.cpp
+++ b/editor/libeditor/DeleteTextTransaction.cpp
@@ -20,77 +20,81 @@ namespace mozilla {
 using namespace dom;
 
 DeleteTextTransaction::DeleteTextTransaction(
                          EditorBase& aEditorBase,
                          nsGenericDOMDataNode& aCharData,
                          uint32_t aOffset,
                          uint32_t aNumCharsToDelete,
                          RangeUpdater* aRangeUpdater)
-  : mEditorBase(aEditorBase)
+  : mEditorBase(&aEditorBase)
   , mCharData(&aCharData)
   , mOffset(aOffset)
   , mNumCharsToDelete(aNumCharsToDelete)
   , mRangeUpdater(aRangeUpdater)
 {
   NS_ASSERTION(mCharData->Length() >= aOffset + aNumCharsToDelete,
                "Trying to delete more characters than in node");
 }
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(DeleteTextTransaction, EditTransactionBase,
+                                   mEditorBase,
                                    mCharData)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DeleteTextTransaction)
 NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
 
 bool
 DeleteTextTransaction::CanDoIt() const
 {
-  if (NS_WARN_IF(!mCharData)) {
+  if (NS_WARN_IF(!mCharData) || NS_WARN_IF(!mEditorBase)) {
     return false;
   }
-  return mEditorBase.IsModifiableNode(mCharData);
+  return mEditorBase->IsModifiableNode(mCharData);
 }
 
 NS_IMETHODIMP
 DeleteTextTransaction::DoTransaction()
 {
-  MOZ_ASSERT(mCharData);
+  if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mCharData)) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
 
   // Get the text that we're about to delete
   nsresult rv = mCharData->SubstringData(mOffset, mNumCharsToDelete,
                                          mDeletedText);
   MOZ_ASSERT(NS_SUCCEEDED(rv));
   rv = mCharData->DeleteData(mOffset, mNumCharsToDelete);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (mRangeUpdater) {
     mRangeUpdater->SelAdjDeleteText(mCharData, mOffset, mNumCharsToDelete);
   }
 
   // Only set selection to deletion point if editor gives permission
-  if (mEditorBase.GetShouldTxnSetSelection()) {
-    RefPtr<Selection> selection = mEditorBase.GetSelection();
+  if (mEditorBase->GetShouldTxnSetSelection()) {
+    RefPtr<Selection> selection = mEditorBase->GetSelection();
     NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
     rv = selection->Collapse(mCharData, mOffset);
     NS_ASSERTION(NS_SUCCEEDED(rv),
                  "Selection could not be collapsed after undo of deletetext");
     NS_ENSURE_SUCCESS(rv, rv);
   }
   // Else do nothing - DOM Range gravity will adjust selection
   return NS_OK;
 }
 
 //XXX: We may want to store the selection state and restore it properly.  Was
 //     it an insertion point or an extended selection?
 NS_IMETHODIMP
 DeleteTextTransaction::UndoTransaction()
 {
-  MOZ_ASSERT(mCharData);
-
+  if (NS_WARN_IF(!mCharData)) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
   return mCharData->InsertData(mOffset, mDeletedText);
 }
 
 NS_IMETHODIMP
 DeleteTextTransaction::GetTxnDescription(nsAString& aString)
 {
   aString.AssignLiteral("DeleteTextTransaction: ");
   aString += mDeletedText;
--- a/editor/libeditor/DeleteTextTransaction.h
+++ b/editor/libeditor/DeleteTextTransaction.h
@@ -52,17 +52,17 @@ public:
   NS_DECL_EDITTRANSACTIONBASE
 
   uint32_t GetOffset() { return mOffset; }
 
   uint32_t GetNumCharsToDelete() { return mNumCharsToDelete; }
 
 protected:
   // The provider of basic editing operations.
-  EditorBase& mEditorBase;
+  RefPtr<EditorBase> mEditorBase;
 
   // The CharacterData node to operate upon.
   RefPtr<nsGenericDOMDataNode> mCharData;
 
   // The offset into mCharData where the deletion is to take place.
   uint32_t mOffset;
 
   // The number of characters to delete.
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -460,16 +460,23 @@ EditorBase::PreDestroy(bool aDestroyingF
   HideCaret(false);
   mActionListeners.Clear();
   mEditorObservers.Clear();
   mDocStateListeners.Clear();
   mInlineSpellChecker = nullptr;
   mSpellcheckCheckboxState = eTriUnset;
   mRootElement = nullptr;
 
+  // Transaction may grab this instance.  Therefore, they should be released
+  // here for stopping the circular reference with this instance.
+  if (mTxnMgr) {
+    mTxnMgr->Clear();
+    mTxnMgr = nullptr;
+  }
+
   mDidPreDestroy = true;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 EditorBase::GetFlags(uint32_t* aFlags)
 {
   *aFlags = mFlags;
--- a/editor/libeditor/InsertNodeTransaction.cpp
+++ b/editor/libeditor/InsertNodeTransaction.cpp
@@ -23,70 +23,74 @@ using namespace dom;
 
 InsertNodeTransaction::InsertNodeTransaction(nsIContent& aNode,
                                              nsINode& aParent,
                                              int32_t aOffset,
                                              EditorBase& aEditorBase)
   : mNode(&aNode)
   , mParent(&aParent)
   , mOffset(aOffset)
-  , mEditorBase(aEditorBase)
+  , mEditorBase(&aEditorBase)
 {
 }
 
 InsertNodeTransaction::~InsertNodeTransaction()
 {
 }
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(InsertNodeTransaction, EditTransactionBase,
+                                   mEditorBase,
                                    mNode,
                                    mParent)
 
 NS_IMPL_ADDREF_INHERITED(InsertNodeTransaction, EditTransactionBase)
 NS_IMPL_RELEASE_INHERITED(InsertNodeTransaction, EditTransactionBase)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(InsertNodeTransaction)
 NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
 
 NS_IMETHODIMP
 InsertNodeTransaction::DoTransaction()
 {
-  MOZ_ASSERT(mNode && mParent);
+  if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mNode) || NS_WARN_IF(!mParent)) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
 
   uint32_t count = mParent->GetChildCount();
   if (mOffset > static_cast<int32_t>(count) || mOffset == -1) {
     // -1 is sentinel value meaning "append at end"
     mOffset = count;
   }
 
   // Note, it's ok for ref to be null. That means append.
   nsCOMPtr<nsIContent> ref = mParent->GetChildAt(mOffset);
 
-  mEditorBase.MarkNodeDirty(GetAsDOMNode(mNode));
+  mEditorBase->MarkNodeDirty(GetAsDOMNode(mNode));
 
   ErrorResult rv;
   mParent->InsertBefore(*mNode, ref, rv);
   NS_ENSURE_TRUE(!rv.Failed(), rv.StealNSResult());
 
   // Only set selection to insertion point if editor gives permission
-  if (mEditorBase.GetShouldTxnSetSelection()) {
-    RefPtr<Selection> selection = mEditorBase.GetSelection();
+  if (mEditorBase->GetShouldTxnSetSelection()) {
+    RefPtr<Selection> selection = mEditorBase->GetSelection();
     NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
     // Place the selection just after the inserted element
     selection->Collapse(mParent, mOffset + 1);
   } else {
     // Do nothing - DOM Range gravity will adjust selection
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 InsertNodeTransaction::UndoTransaction()
 {
-  MOZ_ASSERT(mNode && mParent);
-
+  if (NS_WARN_IF(!mNode) || NS_WARN_IF(!mParent)) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
   ErrorResult rv;
   mParent->RemoveChild(*mNode, rv);
   return rv.StealNSResult();
 }
 
 NS_IMETHODIMP
 InsertNodeTransaction::GetTxnDescription(nsAString& aString)
 {
--- a/editor/libeditor/InsertNodeTransaction.h
+++ b/editor/libeditor/InsertNodeTransaction.h
@@ -45,14 +45,14 @@ protected:
 
   // The node into which the new node will be inserted.
   nsCOMPtr<nsINode> mParent;
 
   // The index in mParent for the new node.
   int32_t mOffset;
 
   // The editor for this transaction.
-  EditorBase& mEditorBase;
+  RefPtr<EditorBase> mEditorBase;
 };
 
 } // namespace mozilla
 
 #endif // #ifndef InsertNodeTransaction_h
--- a/editor/libeditor/InsertTextTransaction.cpp
+++ b/editor/libeditor/InsertTextTransaction.cpp
@@ -21,46 +21,51 @@ using namespace dom;
 InsertTextTransaction::InsertTextTransaction(Text& aTextNode,
                                              uint32_t aOffset,
                                              const nsAString& aStringToInsert,
                                              EditorBase& aEditorBase,
                                              RangeUpdater* aRangeUpdater)
   : mTextNode(&aTextNode)
   , mOffset(aOffset)
   , mStringToInsert(aStringToInsert)
-  , mEditorBase(aEditorBase)
+  , mEditorBase(&aEditorBase)
   , mRangeUpdater(aRangeUpdater)
 {
 }
 
 InsertTextTransaction::~InsertTextTransaction()
 {
 }
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(InsertTextTransaction, EditTransactionBase,
+                                   mEditorBase,
                                    mTextNode)
 
 NS_IMPL_ADDREF_INHERITED(InsertTextTransaction, EditTransactionBase)
 NS_IMPL_RELEASE_INHERITED(InsertTextTransaction, EditTransactionBase)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(InsertTextTransaction)
   if (aIID.Equals(NS_GET_IID(InsertTextTransaction))) {
     foundInterface = static_cast<nsITransaction*>(this);
   } else
 NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
 
 
 NS_IMETHODIMP
 InsertTextTransaction::DoTransaction()
 {
+  if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTextNode)) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
   nsresult rv = mTextNode->InsertData(mOffset, mStringToInsert);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Only set selection to insertion point if editor gives permission
-  if (mEditorBase.GetShouldTxnSetSelection()) {
-    RefPtr<Selection> selection = mEditorBase.GetSelection();
+  if (mEditorBase->GetShouldTxnSetSelection()) {
+    RefPtr<Selection> selection = mEditorBase->GetSelection();
     NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
     DebugOnly<nsresult> rv =
       selection->Collapse(mTextNode, mOffset + mStringToInsert.Length());
     NS_ASSERTION(NS_SUCCEEDED(rv),
                  "Selection could not be collapsed after insert");
   } else {
     // Do nothing - DOM Range gravity will adjust selection
   }
--- a/editor/libeditor/InsertTextTransaction.h
+++ b/editor/libeditor/InsertTextTransaction.h
@@ -71,17 +71,17 @@ private:
 
   // The offset into mTextNode where the insertion is to take place.
   uint32_t mOffset;
 
   // The text to insert into mTextNode at mOffset.
   nsString mStringToInsert;
 
   // The editor, which we'll need to get the selection.
-  EditorBase& mEditorBase;
+  RefPtr<EditorBase> mEditorBase;
 
   RangeUpdater* mRangeUpdater;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(InsertTextTransaction, NS_INSERTTEXTTXN_IID)
 
 } // namespace mozilla
 
--- a/editor/libeditor/JoinNodeTransaction.cpp
+++ b/editor/libeditor/JoinNodeTransaction.cpp
@@ -16,71 +16,83 @@
 
 namespace mozilla {
 
 using namespace dom;
 
 JoinNodeTransaction::JoinNodeTransaction(EditorBase& aEditorBase,
                                          nsINode& aLeftNode,
                                          nsINode& aRightNode)
-  : mEditorBase(aEditorBase)
+  : mEditorBase(&aEditorBase)
   , mLeftNode(&aLeftNode)
   , mRightNode(&aRightNode)
   , mOffset(0)
 {
 }
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(JoinNodeTransaction, EditTransactionBase,
+                                   mEditorBase,
                                    mLeftNode,
                                    mRightNode,
                                    mParent)
 
 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()) {
     return false;
   }
-  return mEditorBase.IsModifiableNode(mLeftNode->GetParentNode());
+  return mEditorBase->IsModifiableNode(mLeftNode->GetParentNode());
 }
 
 // After DoTransaction() and RedoTransaction(), the left node is removed from
 // the content tree and right node remains.
 NS_IMETHODIMP
 JoinNodeTransaction::DoTransaction()
 {
+  if (NS_WARN_IF(!mEditorBase) ||
+      NS_WARN_IF(!mLeftNode) ||
+      NS_WARN_IF(!mRightNode)) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
+
   // Get the parent node
   nsCOMPtr<nsINode> leftParent = mLeftNode->GetParentNode();
   NS_ENSURE_TRUE(leftParent, NS_ERROR_NULL_POINTER);
 
   // Verify that mLeftNode and mRightNode have the same parent
   if (leftParent != mRightNode->GetParentNode()) {
     NS_ASSERTION(false, "Nodes do not have same parent");
     return NS_ERROR_INVALID_ARG;
   }
 
   // Set this instance's mParent.  Other methods will see a non-null mParent
   // and know all is well
   mParent = leftParent;
   mOffset = mLeftNode->Length();
 
-  return mEditorBase.JoinNodesImpl(mRightNode, mLeftNode, mParent);
+  return mEditorBase->JoinNodesImpl(mRightNode, mLeftNode, mParent);
 }
 
 //XXX: What if instead of split, we just deleted the unneeded children of
 //     mRight and re-inserted mLeft?
 NS_IMETHODIMP
 JoinNodeTransaction::UndoTransaction()
 {
-  MOZ_ASSERT(mParent);
+  if (NS_WARN_IF(!mParent) ||
+      NS_WARN_IF(!mLeftNode) ||
+      NS_WARN_IF(!mRightNode)) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
 
   // First, massage the existing node so it is in its post-split state
   ErrorResult rv;
   if (mRightNode->GetAsText()) {
     rv = mRightNode->GetAsText()->DeleteData(0, mOffset);
   } else {
     nsCOMPtr<nsIContent> child = mRightNode->GetFirstChild();
     for (uint32_t i = 0; i < mOffset; i++) {
--- a/editor/libeditor/JoinNodeTransaction.h
+++ b/editor/libeditor/JoinNodeTransaction.h
@@ -43,17 +43,17 @@ public:
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(JoinNodeTransaction,
                                            EditTransactionBase)
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
 
   NS_DECL_EDITTRANSACTIONBASE
 
 protected:
-  EditorBase& mEditorBase;
+  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 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
--- a/editor/libeditor/PlaceholderTransaction.cpp
+++ b/editor/libeditor/PlaceholderTransaction.cpp
@@ -20,40 +20,42 @@ PlaceholderTransaction::PlaceholderTrans
                           EditorBase& aEditorBase,
                           nsIAtom* aName,
                           UniquePtr<SelectionState> aSelState)
   : mAbsorb(true)
   , mForwarding(nullptr)
   , mCompositionTransaction(nullptr)
   , mCommitted(false)
   , mStartSel(Move(aSelState))
-  , mEditorBase(aEditorBase)
+  , mEditorBase(&aEditorBase)
 {
   mName = aName;
 }
 
 PlaceholderTransaction::~PlaceholderTransaction()
 {
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(PlaceholderTransaction)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PlaceholderTransaction,
                                                 EditAggregateTransaction)
   if (tmp->mStartSel) {
     ImplCycleCollectionUnlink(*tmp->mStartSel);
   }
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mEditorBase);
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mEndSel);
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PlaceholderTransaction,
                                                   EditAggregateTransaction)
   if (tmp->mStartSel) {
     ImplCycleCollectionTraverse(cb, *tmp->mStartSel, "mStartSel", 0);
   }
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEditorBase);
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEndSel);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PlaceholderTransaction)
   NS_INTERFACE_MAP_ENTRY(nsIAbsorbingTransaction)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
 NS_INTERFACE_MAP_END_INHERITING(EditAggregateTransaction)
 
@@ -64,37 +66,45 @@ NS_IMETHODIMP
 PlaceholderTransaction::DoTransaction()
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PlaceholderTransaction::UndoTransaction()
 {
+  if (NS_WARN_IF(!mEditorBase)) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
+
   // Undo transactions.
   nsresult rv = EditAggregateTransaction::UndoTransaction();
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ENSURE_TRUE(mStartSel, NS_ERROR_NULL_POINTER);
 
   // now restore selection
-  RefPtr<Selection> selection = mEditorBase.GetSelection();
+  RefPtr<Selection> selection = mEditorBase->GetSelection();
   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
   return mStartSel->RestoreSelection(selection);
 }
 
 NS_IMETHODIMP
 PlaceholderTransaction::RedoTransaction()
 {
+  if (NS_WARN_IF(!mEditorBase)) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
+
   // Redo transactions.
   nsresult rv = EditAggregateTransaction::RedoTransaction();
   NS_ENSURE_SUCCESS(rv, rv);
 
   // now restore selection
-  RefPtr<Selection> selection = mEditorBase.GetSelection();
+  RefPtr<Selection> selection = mEditorBase->GetSelection();
   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
   return mEndSel.RestoreSelection(selection);
 }
 
 
 NS_IMETHODIMP
 PlaceholderTransaction::Merge(nsITransaction* aTransaction,
                               bool* aDidMerge)
@@ -249,15 +259,19 @@ PlaceholderTransaction::Commit()
 {
   mCommitted = true;
   return NS_OK;
 }
 
 nsresult
 PlaceholderTransaction::RememberEndingSelection()
 {
-  RefPtr<Selection> selection = mEditorBase.GetSelection();
+  if (NS_WARN_IF(!mEditorBase)) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
+
+  RefPtr<Selection> selection = mEditorBase->GetSelection();
   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
   mEndSel.SaveSelection(selection);
   return NS_OK;
 }
 
 } // namespace mozilla
--- a/editor/libeditor/PlaceholderTransaction.h
+++ b/editor/libeditor/PlaceholderTransaction.h
@@ -77,14 +77,14 @@ protected:
   // at the end.  This is so that UndoTransaction() and RedoTransaction() can
   // restore the selection properly.
 
   // Use a pointer because this is constructed before we exist.
   UniquePtr<SelectionState> mStartSel;
   SelectionState mEndSel;
 
   // The editor for this transaction.
-  EditorBase& mEditorBase;
+  RefPtr<EditorBase> mEditorBase;
 };
 
 } // namespace mozilla
 
 #endif // #ifndef PlaceholderTransaction_h
--- a/editor/libeditor/SplitNodeTransaction.cpp
+++ b/editor/libeditor/SplitNodeTransaction.cpp
@@ -14,78 +14,90 @@
 
 namespace mozilla {
 
 using namespace dom;
 
 SplitNodeTransaction::SplitNodeTransaction(EditorBase& aEditorBase,
                                            nsIContent& aNode,
                                            int32_t aOffset)
-  : mEditorBase(aEditorBase)
+  : mEditorBase(&aEditorBase)
   , mExistingRightNode(&aNode)
   , mOffset(aOffset)
 {
 }
 
 SplitNodeTransaction::~SplitNodeTransaction()
 {
 }
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(SplitNodeTransaction, EditTransactionBase,
+                                   mEditorBase,
                                    mParent,
                                    mNewLeftNode)
 
 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)
 
 NS_IMETHODIMP
 SplitNodeTransaction::DoTransaction()
 {
+  if (NS_WARN_IF(!mEditorBase)) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
+
   // Create a new node
   ErrorResult rv;
   // Don't use .downcast directly because AsContent has an assertion we want
   nsCOMPtr<nsINode> clone = mExistingRightNode->CloneNode(false, rv);
   NS_ASSERTION(!rv.Failed() && clone, "Could not create clone");
   NS_ENSURE_TRUE(!rv.Failed() && clone, rv.StealNSResult());
   mNewLeftNode = dont_AddRef(clone.forget().take()->AsContent());
-  mEditorBase.MarkNodeDirty(mExistingRightNode->AsDOMNode());
+  mEditorBase->MarkNodeDirty(mExistingRightNode->AsDOMNode());
 
   // Get the parent node
   mParent = mExistingRightNode->GetParentNode();
   NS_ENSURE_TRUE(mParent, NS_ERROR_NULL_POINTER);
 
   // Insert the new node
-  rv = mEditorBase.SplitNodeImpl(*mExistingRightNode, mOffset, *mNewLeftNode);
-  if (mEditorBase.GetShouldTxnSetSelection()) {
-    RefPtr<Selection> selection = mEditorBase.GetSelection();
+  rv = mEditorBase->SplitNodeImpl(*mExistingRightNode, mOffset, *mNewLeftNode);
+  if (mEditorBase->GetShouldTxnSetSelection()) {
+    RefPtr<Selection> selection = mEditorBase->GetSelection();
     NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
     rv = selection->Collapse(mNewLeftNode, mOffset);
   }
   return rv.StealNSResult();
 }
 
 NS_IMETHODIMP
 SplitNodeTransaction::UndoTransaction()
 {
-  MOZ_ASSERT(mNewLeftNode && mParent);
+  if (NS_WARN_IF(!mEditorBase) ||
+      NS_WARN_IF(!mNewLeftNode) ||
+      NS_WARN_IF(!mParent)) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
 
   // This assumes Do inserted the new node in front of the prior existing node
-  return mEditorBase.JoinNodesImpl(mExistingRightNode, mNewLeftNode, mParent);
+  return mEditorBase->JoinNodesImpl(mExistingRightNode, mNewLeftNode, mParent);
 }
 
 /* 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.
  */
 NS_IMETHODIMP
 SplitNodeTransaction::RedoTransaction()
 {
-  MOZ_ASSERT(mNewLeftNode && mParent);
+  if (NS_WARN_IF(!mNewLeftNode) ||
+      NS_WARN_IF(!mParent)) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
 
   ErrorResult rv;
   // First, massage the existing node so it is in its post-split state
   if (mExistingRightNode->GetAsText()) {
     rv = mExistingRightNode->GetAsText()->DeleteData(0, mOffset);
     NS_ENSURE_TRUE(!rv.Failed(), rv.StealNSResult());
   } else {
     nsCOMPtr<nsIContent> child = mExistingRightNode->GetFirstChild();
--- a/editor/libeditor/SplitNodeTransaction.h
+++ b/editor/libeditor/SplitNodeTransaction.h
@@ -44,17 +44,17 @@ public:
 
   NS_IMETHOD RedoTransaction() override;
 
   nsIContent* GetNewNode();
 
 protected:
   virtual ~SplitNodeTransaction();
 
-  EditorBase& mEditorBase;
+  RefPtr<EditorBase> mEditorBase;
 
   // The node to operate upon.
   nsCOMPtr<nsIContent> mExistingRightNode;
 
   // The offset into mExistingRightNode where its children are split.  mOffset
   // is the index of the first child in the right node.  -1 means the new node
   // gets no children.
   int32_t mOffset;
--- a/editor/libeditor/StyleSheetTransactions.cpp
+++ b/editor/libeditor/StyleSheetTransactions.cpp
@@ -39,90 +39,97 @@ RemoveStyleSheet(EditorBase& aEditor, St
     doc->EndUpdate(UPDATE_STYLE);
   }
 }
 
 /******************************************************************************
  * AddStyleSheetTransaction
  ******************************************************************************/
 
-AddStyleSheetTransaction::AddStyleSheetTransaction(EditorBase& aEditor,
+AddStyleSheetTransaction::AddStyleSheetTransaction(EditorBase& aEditorBase,
                                                    StyleSheet* aSheet)
-  : mEditor(aEditor)
+  : mEditorBase(&aEditorBase)
   , mSheet(aSheet)
 {
   MOZ_ASSERT(aSheet);
 }
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(AddStyleSheetTransaction,
                                    EditTransactionBase,
+                                   mEditorBase,
                                    mSheet)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AddStyleSheetTransaction)
 NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
 
 NS_IMETHODIMP
 AddStyleSheetTransaction::DoTransaction()
 {
-  NS_ENSURE_TRUE(mSheet, NS_ERROR_NOT_INITIALIZED);
-
-  AddStyleSheet(mEditor, mSheet);
+  if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mSheet)) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
+  AddStyleSheet(*mEditorBase, mSheet);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 AddStyleSheetTransaction::UndoTransaction()
 {
-  NS_ENSURE_TRUE(mSheet, NS_ERROR_NOT_INITIALIZED);
-
-  RemoveStyleSheet(mEditor, mSheet);
+  if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mSheet)) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
+  RemoveStyleSheet(*mEditorBase, mSheet);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 AddStyleSheetTransaction::GetTxnDescription(nsAString& aString)
 {
   aString.AssignLiteral("AddStyleSheetTransaction");
   return NS_OK;
 }
 
 /******************************************************************************
  * RemoveStyleSheetTransaction
  ******************************************************************************/
 
-RemoveStyleSheetTransaction::RemoveStyleSheetTransaction(EditorBase& aEditor,
-                                                         StyleSheet* aSheet)
-  : mEditor(aEditor)
+RemoveStyleSheetTransaction::RemoveStyleSheetTransaction(
+                               EditorBase& aEditorBase,
+                               StyleSheet* aSheet)
+  : mEditorBase(&aEditorBase)
   , mSheet(aSheet)
 {
   MOZ_ASSERT(aSheet);
 }
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(RemoveStyleSheetTransaction,
                                    EditTransactionBase,
+                                   mEditorBase,
                                    mSheet)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(RemoveStyleSheetTransaction)
 NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
 
 NS_IMETHODIMP
 RemoveStyleSheetTransaction::DoTransaction()
 {
-  NS_ENSURE_TRUE(mSheet, NS_ERROR_NOT_INITIALIZED);
-
-  RemoveStyleSheet(mEditor, mSheet);
+  if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mSheet)) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
+  RemoveStyleSheet(*mEditorBase, mSheet);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 RemoveStyleSheetTransaction::UndoTransaction()
 {
-  NS_ENSURE_TRUE(mSheet, NS_ERROR_NOT_INITIALIZED);
-
-  AddStyleSheet(mEditor, mSheet);
+  if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mSheet)) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
+  AddStyleSheet(*mEditorBase, mSheet);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 RemoveStyleSheetTransaction::GetTxnDescription(nsAString& aString)
 {
   aString.AssignLiteral("RemoveStyleSheetTransaction");
   return NS_OK;
--- a/editor/libeditor/StyleSheetTransactions.h
+++ b/editor/libeditor/StyleSheetTransactions.h
@@ -27,17 +27,17 @@ public:
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(AddStyleSheetTransaction,
                                            EditTransactionBase)
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
 
   NS_DECL_EDITTRANSACTIONBASE
 
 protected:
   // The editor that created this transaction.
-  EditorBase& mEditor;
+  RefPtr<EditorBase> mEditorBase;
   // The style sheet to add.
   RefPtr<mozilla::StyleSheet> mSheet;
 };
 
 
 class RemoveStyleSheetTransaction final : public EditTransactionBase
 {
 public:
@@ -50,17 +50,17 @@ public:
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(RemoveStyleSheetTransaction,
                                            EditTransactionBase)
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
 
   NS_DECL_EDITTRANSACTIONBASE
 
 protected:
   // The editor that created this transaction.
-  EditorBase& mEditor;
+  RefPtr<EditorBase> mEditorBase;
   // The style sheet to remove.
   RefPtr<StyleSheet> mSheet;
 
 };
 
 } // namespace mozilla
 
 #endif // #ifndef StylesheetTransactions_h