Bug 1497746 - part 4: Move EditorBase::mRangeUpdater to AutoEditActionDataSetter r=m_kato
authorMasayuki Nakano <masayuki@d-toybox.com>
Mon, 26 Nov 2018 06:31:56 +0000
changeset 504387 ceb75e2e0421b36d6d9e680830902d4196e94717
parent 504386 465ebb044ee1494d7c2dca9ff04839cc45772b35
child 504388 324232a1330c2a0661973d49f54ab5d29ca30a64
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersm_kato
bugs1497746
milestone65.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 1497746 - part 4: Move EditorBase::mRangeUpdater to AutoEditActionDataSetter r=m_kato Similar to EditorBase::mSavedSel, we can move EditorBase::mRangeUpdater too because of it's referred only when there is AutoEditActionDataSetter instance so that it also does not need to be in the cycle collection. And now, it can be marked as MOZ_STACK_CLASS and remove cycle collection support. Differential Revision: https://phabricator.services.mozilla.com/D12402
editor/libeditor/EditorBase.cpp
editor/libeditor/EditorBase.h
editor/libeditor/HTMLEditRules.cpp
editor/libeditor/HTMLStyleEditor.cpp
editor/libeditor/SelectionState.h
editor/libeditor/TextEditorDataTransfer.cpp
editor/libeditor/WSRunObject.cpp
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -206,17 +206,16 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Ed
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mTextServicesDocument)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mTextInputListener)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mTransactionManager)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mActionListeners)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mEditorObservers)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocStateListeners)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mEventTarget)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mPlaceholderTransaction)
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mRangeUpdater);
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(EditorBase)
  nsIDocument* currentDoc =
    tmp->mRootElement ? tmp->mRootElement->GetUncomposedDoc() : nullptr;
  if (currentDoc &&
      nsCCUncollectableMarker::InGeneration(cb, currentDoc->GetMarkedCCGeneration())) {
    return NS_SUCCESS_INTERRUPTED_TRAVERSE;
@@ -230,17 +229,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTextInputListener)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransactionManager)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mActionListeners)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEditorObservers)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocStateListeners)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEventTarget)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEventListener)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlaceholderTransaction)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRangeUpdater);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(EditorBase)
  NS_INTERFACE_MAP_ENTRY(nsISelectionListener)
  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
  NS_INTERFACE_MAP_ENTRY(nsIEditor)
  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIEditor)
 NS_INTERFACE_MAP_END
@@ -948,17 +946,17 @@ EditorBase::BeginPlaceholderTransaction(
     mSelState.emplace();
     mSelState->SaveSelection(SelectionRefPtr());
     // Composition transaction can modify multiple nodes and it merges text
     // node for ime into single text node.
     // So if current selection is into IME text node, it might be failed
     // to restore selection by UndoTransaction.
     // So we need update selection by range updater.
     if (mPlaceholderName == nsGkAtoms::IMETxnName) {
-      mRangeUpdater.RegisterSelectionState(*mSelState);
+      RangeUpdaterRef().RegisterSelectionState(*mSelState);
     }
   }
   mPlaceholderBatch++;
 }
 
 void
 EditorBase::EndPlaceholderTransaction()
 {
@@ -985,17 +983,17 @@ EditorBase::EndPlaceholderTransaction()
 
     // cached for frame offset are Not available now
     SelectionRefPtr()->SetCanCacheFrameOffset(false);
 
     if (mSelState) {
       // we saved the selection state, but never got to hand it to placeholder
       // (else we ould have nulled out this pointer), so destroy it to prevent leaks.
       if (mPlaceholderName == nsGkAtoms::IMETxnName) {
-        mRangeUpdater.DropSelectionState(*mSelState);
+        RangeUpdaterRef().DropSelectionState(*mSelState);
       }
       mSelState.reset();
     }
     // We might have never made a placeholder if no action took place.
     if (mPlaceholderTransaction) {
       mPlaceholderTransaction->EndPlaceHolderBatch();
       // notify editor observers of action but if composing, it's done by
       // compositionchange event handler.
@@ -1406,46 +1404,46 @@ already_AddRefed<Element>
 EditorBase::CreateNodeWithTransaction(
               nsAtom& aTagName,
               const EditorDOMPointBase<PT, CT>& aPointToInsert)
 {
   MOZ_ASSERT(IsEditActionDataAvailable());
 
   MOZ_ASSERT(aPointToInsert.IsSetAndValid());
 
-  // XXX We need offset at new node for mRangeUpdater.  Therefore, we need
+  // XXX We need offset at new node for RangeUpdaterRef().  Therefore, we need
   //     to compute the offset now but this is expensive.  So, if it's possible,
-  //     we need to redesign mRangeUpdater as avoiding using indices.
+  //     we need to redesign RangeUpdaterRef() as avoiding using indices.
   Unused << aPointToInsert.Offset();
 
   AutoTopLevelEditSubActionNotifier maybeTopLevelEditSubAction(
                                       *this, EditSubAction::eCreateNode,
                                       nsIEditor::eNext);
 
   RefPtr<Element> newElement;
 
   RefPtr<CreateElementTransaction> transaction =
     CreateElementTransaction::Create(*this, aTagName, aPointToInsert);
   nsresult rv = DoTransactionInternal(transaction);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     // XXX Why do we do this even when DoTransaction() returned error?
-    mRangeUpdater.SelAdjCreateNode(aPointToInsert);
+    RangeUpdaterRef().SelAdjCreateNode(aPointToInsert);
   } else {
     newElement = transaction->GetNewNode();
     MOZ_ASSERT(newElement);
 
     // If we succeeded to create and insert new element, we need to adjust
-    // ranges in mRangeUpdater.  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.
-    mRangeUpdater.SelAdjCreateNode(
-                    EditorRawDOMPoint(aPointToInsert.GetContainer(),
-                                      aPointToInsert.Offset()));
+    // 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.
+    RangeUpdaterRef().SelAdjCreateNode(
+                        EditorRawDOMPoint(aPointToInsert.GetContainer(),
+                                          aPointToInsert.Offset()));
   }
 
   if (mRules && mRules->AsHTMLEditRules() && newElement) {
     RefPtr<HTMLEditRules> htmlEditRules = mRules->AsHTMLEditRules();
     htmlEditRules->DidCreateNode(*newElement);
   }
 
   if (!mActionListeners.IsEmpty()) {
@@ -1500,17 +1498,17 @@ EditorBase::InsertNodeWithTransaction(
   AutoTopLevelEditSubActionNotifier maybeTopLevelEditSubAction(
                                       *this, EditSubAction::eInsertNode,
                                       nsIEditor::eNext);
 
   RefPtr<InsertNodeTransaction> transaction =
     InsertNodeTransaction::Create(*this, aContentToInsert, aPointToInsert);
   nsresult rv = DoTransactionInternal(transaction);
 
-  mRangeUpdater.SelAdjInsertNode(aPointToInsert);
+  RangeUpdaterRef().SelAdjInsertNode(aPointToInsert);
 
   if (mRules && mRules->AsHTMLEditRules()) {
     RefPtr<HTMLEditRules> htmlEditRules = mRules->AsHTMLEditRules();
     htmlEditRules->DidInsertNode(aContentToInsert);
   }
 
   if (!mActionListeners.IsEmpty()) {
     AutoActionListenerArray listeners(mActionListeners);
@@ -1576,18 +1574,18 @@ EditorBase::SplitNodeWithTransaction(
     SplitNodeTransaction::Create(*this, aStartOfRightNode);
   aError = DoTransactionInternal(transaction);
 
   nsCOMPtr<nsIContent> newNode = transaction->GetNewNode();
   NS_WARNING_ASSERTION(newNode, "Failed to create a new left node");
 
   // XXX Some other transactions manage range updater by themselves.
   //     Why doesn't SplitNodeTransaction do it?
-  mRangeUpdater.SelAdjSplitNode(*aStartOfRightNode.GetContainerAsContent(),
-                                newNode);
+  RangeUpdaterRef().SelAdjSplitNode(*aStartOfRightNode.GetContainerAsContent(),
+                                    newNode);
 
   if (mRules && mRules->AsHTMLEditRules() && newNode) {
     RefPtr<HTMLEditRules> htmlEditRules = mRules->AsHTMLEditRules();
     htmlEditRules->DidSplitNode(*aStartOfRightNode.GetContainer(), *newNode);
   }
 
   if (mInlineSpellChecker) {
     RefPtr<mozInlineSpellChecker> spellChecker = mInlineSpellChecker;
@@ -1655,18 +1653,18 @@ EditorBase::JoinNodesWithTransaction(nsI
   RefPtr<JoinNodeTransaction> transaction =
     JoinNodeTransaction::MaybeCreate(*this, aLeftNode, aRightNode);
   if (transaction)  {
     rv = DoTransactionInternal(transaction);
   }
 
   // XXX Some other transactions manage range updater by themselves.
   //     Why doesn't JoinNodeTransaction do it?
-  mRangeUpdater.SelAdjJoinNodes(aLeftNode, aRightNode, *parent, offset,
-                                (int32_t)oldLeftNodeLen);
+  RangeUpdaterRef().SelAdjJoinNodes(aLeftNode, aRightNode, *parent, offset,
+                                    static_cast<int32_t>(oldLeftNodeLen));
 
   if (mRules && mRules->AsHTMLEditRules()) {
     RefPtr<HTMLEditRules> htmlEditRules = mRules->AsHTMLEditRules();
     htmlEditRules->DidJoinNodes(aLeftNode, aRightNode);
   }
 
   if (mInlineSpellChecker) {
     RefPtr<mozInlineSpellChecker> spellChecker = mInlineSpellChecker;
@@ -1744,16 +1742,18 @@ EditorBase::DeleteNodeWithTransaction(ns
 already_AddRefed<Element>
 EditorBase::ReplaceContainerWithTransactionInternal(
               Element& aOldContainer,
               nsAtom& aTagName,
               nsAtom& aAttribute,
               const nsAString& aAttributeValue,
               bool aCloneAllAttributes)
 {
+  MOZ_ASSERT(IsEditActionDataAvailable());
+
   EditorDOMPoint atOldContainer(&aOldContainer);
   if (NS_WARN_IF(!atOldContainer.IsSet())) {
     return nullptr;
   }
 
   RefPtr<Element> newContainer = CreateHTMLContent(&aTagName);
   if (NS_WARN_IF(!newContainer)) {
     return nullptr;
@@ -1769,19 +1769,19 @@ EditorBase::ReplaceContainerWithTransact
                             true);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return nullptr;
     }
   }
 
   // Notify our internal selection state listener.
   // Note: An AutoSelectionRestorer object must be created before calling this
-  // to initialize mRangeUpdater.
-  AutoReplaceContainerSelNotify selStateNotify(mRangeUpdater, &aOldContainer,
-                                               newContainer);
+  // to initialize RangeUpdaterRef().
+  AutoReplaceContainerSelNotify selStateNotify(RangeUpdaterRef(),
+                                               &aOldContainer, newContainer);
   {
     AutoTransactionsConserveSelection conserveSelection(*this);
     // Move all children from the old container to the new container.
     while (aOldContainer.HasChildren()) {
       nsCOMPtr<nsIContent> child = aOldContainer.GetFirstChild();
       if (NS_WARN_IF(!child)) {
         return nullptr;
       }
@@ -1814,23 +1814,25 @@ EditorBase::ReplaceContainerWithTransact
   }
 
   return newContainer.forget();
 }
 
 nsresult
 EditorBase::RemoveContainerWithTransaction(Element& aElement)
 {
+  MOZ_ASSERT(IsEditActionDataAvailable());
+
   EditorDOMPoint pointToInsertChildren(&aElement);
   if (NS_WARN_IF(!pointToInsertChildren.IsSet())) {
     return NS_ERROR_FAILURE;
   }
 
   // Notify our internal selection state listener.
-  AutoRemoveContainerSelNotify selNotify(mRangeUpdater, &aElement,
+  AutoRemoveContainerSelNotify selNotify(RangeUpdaterRef(), &aElement,
                                          pointToInsertChildren.GetContainer(),
                                          pointToInsertChildren.Offset(),
                                          aElement.GetChildCount());
 
   // Move all children from aNode to its parent.
   while (aElement.HasChildren()) {
     nsCOMPtr<nsIContent> child = aElement.GetLastChild();
     if (NS_WARN_IF(!child)) {
@@ -1893,17 +1895,17 @@ EditorBase::InsertContainerWithTransacti
       newContainer->SetAttr(kNameSpaceID_None, &aAttribute, aAttributeValue,
                             true);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return nullptr;
     }
   }
 
   // Notify our internal selection state listener
-  AutoInsertContainerSelNotify selNotify(mRangeUpdater);
+  AutoInsertContainerSelNotify selNotify(RangeUpdaterRef());
 
   // Put aNode in the new container, first.
   nsresult rv = DeleteNodeWithTransaction(aContent);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return nullptr;
   }
 
   {
@@ -1939,17 +1941,17 @@ EditorBase::MoveNodeWithTransaction(
 
   // Don't do anything if it's already in right place.
   if (aPointToInsert == oldPoint) {
     return NS_OK;
   }
 
   // Notify our internal selection state listener
   EditorDOMPoint newPoint(aPointToInsert);
-  AutoMoveNodeSelNotify selNotify(mRangeUpdater, oldPoint, newPoint);
+  AutoMoveNodeSelNotify selNotify(RangeUpdaterRef(), oldPoint, newPoint);
 
   // Hold a reference so aNode doesn't go away when we remove it (bug 772282)
   nsresult rv = DeleteNodeWithTransaction(aContent);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   // Mutation event listener could break insertion point. Let's check it.
@@ -2299,17 +2301,17 @@ EditorBase::ArePreservingSelection()
 }
 
 void
 EditorBase::PreserveSelectionAcrossActions()
 {
   MOZ_ASSERT(IsEditActionDataAvailable());
 
   SavedSelectionRef().SaveSelection(SelectionRefPtr());
-  mRangeUpdater.RegisterSelectionState(SavedSelectionRef());
+  RangeUpdaterRef().RegisterSelectionState(SavedSelectionRef());
 }
 
 nsresult
 EditorBase::RestorePreservedSelection()
 {
   MOZ_ASSERT(IsEditActionDataAvailable());
 
   if (SavedSelectionRef().IsEmpty()) {
@@ -2320,17 +2322,17 @@ EditorBase::RestorePreservedSelection()
   return NS_OK;
 }
 
 void
 EditorBase::StopPreservingSelection()
 {
   MOZ_ASSERT(IsEditActionDataAvailable());
 
-  mRangeUpdater.DropSelectionState(SavedSelectionRef());
+  RangeUpdaterRef().DropSelectionState(SavedSelectionRef());
   SavedSelectionRef().MakeEmpty();
 }
 
 NS_IMETHODIMP
 EditorBase::ForceCompositionEnd()
 {
   return CommitComposition();
 }
@@ -2931,18 +2933,18 @@ EditorBase::SetTextImpl(const nsAString&
   {
     // Create a nested scope to not overwrite rv from the outer scope.
     DebugOnly<nsresult> rv =
       SelectionRefPtr()->Collapse(&aCharData, aString.Length());
     NS_ASSERTION(NS_SUCCEEDED(rv),
                  "Selection could not be collapsed after insert");
   }
 
-  mRangeUpdater.SelAdjDeleteText(&aCharData, 0, length);
-  mRangeUpdater.SelAdjInsertText(aCharData, 0, aString);
+  RangeUpdaterRef().SelAdjDeleteText(&aCharData, 0, length);
+  RangeUpdaterRef().SelAdjInsertText(aCharData, 0, aString);
 
   if (mRules && mRules->AsHTMLEditRules()) {
     RefPtr<HTMLEditRules> htmlEditRules = mRules->AsHTMLEditRules();
     if (length) {
       htmlEditRules->DidDeleteText(aCharData, 0, length);
     }
     if (!aString.IsEmpty()) {
       htmlEditRules->DidInsertText(aCharData, 0, aString);
--- a/editor/libeditor/EditorBase.h
+++ b/editor/libeditor/EditorBase.h
@@ -310,18 +310,16 @@ public:
     return selection;
   }
 
   /**
    * Fast non-refcounting editor root element accessor
    */
   Element* GetRoot() const { return mRootElement; }
 
-  RangeUpdater& RangeUpdaterRef() { return mRangeUpdater; }
-
   /**
    * Set or unset TextInputListener.  If setting non-nullptr when the editor
    * already has a TextInputListener, this will crash in debug build.
    */
   void SetTextInputListener(TextInputListener* aTextInputListener);
 
   /**
    * Set or unset IMEContentObserver.  If setting non-nullptr when the editor
@@ -791,27 +789,39 @@ protected: // AutoEditActionDataSetter, 
     {
       return mParentData ? mParentData->SavedSelectionRef() : mSavedSelection;
     }
     const SelectionState& SavedSelectionRef() const
     {
       return mParentData ? mParentData->SavedSelectionRef() : mSavedSelection;
     }
 
+    RangeUpdater& RangeUpdaterRef()
+    {
+      return mParentData ? mParentData->RangeUpdaterRef() : mRangeUpdater;
+    }
+    const RangeUpdater& RangeUpdaterRef() const
+    {
+      return mParentData ? mParentData->RangeUpdaterRef() : mRangeUpdater;
+    }
+
   private:
     EditorBase& mEditorBase;
     RefPtr<Selection> mSelection;
     // EditAction may be nested, for example, a command may be executed
     // from mutation event listener which is run while editor changes
     // the DOM tree.  In such case, we need to handle edit action separately.
     AutoEditActionDataSetter* mParentData;
 
     // Cached selection for AutoSelectionRestorer.
     SelectionState mSavedSelection;
 
+    // Utility class object for maintaining preserved ranges.
+    RangeUpdater mRangeUpdater;
+
     EditAction mEditAction;
     EditSubAction mTopLevelEditSubAction;
     EDirection mDirectionOfTopLevelEditSubAction;
 
     AutoEditActionDataSetter() = delete;
     AutoEditActionDataSetter(const AutoEditActionDataSetter& aOther) = delete;
   };
 
@@ -891,16 +901,27 @@ protected: // May be called by friends.
     return mEditActionData->SavedSelectionRef();
   }
   const SelectionState& SavedSelectionRef() const
   {
     MOZ_ASSERT(IsEditActionDataAvailable());
     return mEditActionData->SavedSelectionRef();
   }
 
+  RangeUpdater& RangeUpdaterRef()
+  {
+    MOZ_ASSERT(IsEditActionDataAvailable());
+    return mEditActionData->RangeUpdaterRef();
+  }
+  const RangeUpdater& RangeUpdaterRef() const
+  {
+    MOZ_ASSERT(IsEditActionDataAvailable());
+    return mEditActionData->RangeUpdaterRef();
+  }
+
   /**
    * InsertTextWithTransaction() inserts aStringToInsert to aPointToInsert or
    * better insertion point around it.  If aPointToInsert isn't in a text node,
    * this method looks for the nearest point in a text node with
    * FindBetterInsertionPoint().  If there is no text node, this creates
    * new text node and put aStringToInsert to it.
    *
    * @param aDocument       The document of this editor.
@@ -2328,19 +2349,16 @@ protected:
   typedef AutoTArray<OwningNonNull<nsIEditorObserver>, 3>
             AutoEditorObserverArray;
   AutoEditorObserverArray mEditorObservers;
   // Listen to overall doc state (dirty or not, just created, etc.).
   typedef AutoTArray<OwningNonNull<nsIDocumentStateListener>, 1>
             AutoDocumentStateListenerArray;
   AutoDocumentStateListenerArray mDocStateListeners;
 
-  // Utility class object for maintaining preserved ranges.
-  RangeUpdater mRangeUpdater;
-
   // Number of modifications (for undo/redo stack).
   uint32_t mModCount;
   // Behavior flags. See nsIPlaintextEditor.idl for the flags we use.
   uint32_t mFlags;
 
   int32_t mUpdateCount;
 
   // Nesting count for batching.
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -376,17 +376,17 @@ HTMLEditRules::BeforeEdit(EditSubAction 
     if (!SelectionRefPtr()->RangeCount()) {
       return NS_ERROR_UNEXPECTED;
     }
     mRangeItem->StoreRange(SelectionRefPtr()->GetRangeAt(0));
     nsCOMPtr<nsINode> selStartNode = mRangeItem->mStartContainer;
     nsCOMPtr<nsINode> selEndNode = mRangeItem->mEndContainer;
 
     // Register with range updater to track this as we perturb the doc
-    HTMLEditorRef().mRangeUpdater.RegisterRangeItem(mRangeItem);
+    HTMLEditorRef().RangeUpdaterRef().RegisterRangeItem(mRangeItem);
 
     // Clear deletion state bool
     mDidDeleteSelection = false;
 
     // Clear out mDocChangeRange and mUtilRange
     if (mDocChangeRange) {
       // Clear out our accounting of what changed
       mDocChangeRange->Reset();
@@ -453,17 +453,17 @@ HTMLEditRules::AfterEdit(EditSubAction a
 
     // Do all the tricky stuff
     rv = AfterEditInner(aEditSubAction, aDirection);
     // Perhaps, we need to do the following jobs even if the editor has been
     // destroyed since they adjust some states of HTML document but don't
     // modify the DOM tree nor Selection.
 
     // Free up selectionState range item
-    HTMLEditorRef().mRangeUpdater.DropRangeItem(mRangeItem);
+    HTMLEditorRef().RangeUpdaterRef().DropRangeItem(mRangeItem);
 
     // Reset the contenteditable count to its previous value
     if (mRestoreContentEditableCount) {
       nsHTMLDocument* htmlDoc = HTMLEditorRef().GetHTMLDocument();
       if (NS_WARN_IF(!htmlDoc)) {
         return NS_ERROR_FAILURE;
       }
       if (htmlDoc->GetEditingState() == nsIHTMLDocument::eContentEditable) {
@@ -1465,17 +1465,18 @@ HTMLEditRules::WillInsertText(EditSubAct
   // don't change my selection in subtransactions
   AutoTransactionsConserveSelection dontChangeMySelection(HTMLEditorRef());
   nsAutoString tString(*inString);
   const char16_t *unicodeBuf = tString.get();
   int32_t pos = 0;
   NS_NAMED_LITERAL_STRING(newlineStr, LFSTR);
 
   {
-    AutoTrackDOMPoint tracker(HTMLEditorRef().mRangeUpdater, &pointToInsert);
+    AutoTrackDOMPoint tracker(HTMLEditorRef().RangeUpdaterRef(),
+                              &pointToInsert);
 
     // for efficiency, break out the pre case separately.  This is because
     // its a lot cheaper to search the input string for only newlines than
     // it is to search for both tabs and newlines.
     if (isPRE || IsPlaintextEditor()) {
       while (unicodeBuf && pos != -1 &&
              pos < static_cast<int32_t>(inString->Length())) {
         int32_t oldPos = pos;
@@ -2807,17 +2808,17 @@ HTMLEditRules::WillDeleteSelection(nsIEd
           "Failed to collapse selection at edge of the block");
         return NS_OK;
       }
 
       // Else we are joining content to block
 
       EditorDOMPoint selPoint(startPoint);
       {
-        AutoTrackDOMPoint tracker(HTMLEditorRef().mRangeUpdater, &selPoint);
+        AutoTrackDOMPoint tracker(HTMLEditorRef().RangeUpdaterRef(), &selPoint);
         if (NS_WARN_IF(!leftNode) ||
             NS_WARN_IF(!leftNode->IsContent()) ||
             NS_WARN_IF(!rightNode) ||
             NS_WARN_IF(!rightNode->IsContent())) {
           return NS_ERROR_FAILURE;
         }
         EditActionResult ret =
           TryToJoinBlocksWithTransaction(*leftNode->AsContent(),
@@ -2890,17 +2891,17 @@ HTMLEditRules::WillDeleteSelection(nsIEd
       // Don't cross table boundaries -- cancel it
       if (InDifferentTableElements(leftNode, rightNode)) {
         *aCancel = true;
         return NS_OK;
       }
 
       EditorDOMPoint selPoint(startPoint);
       {
-        AutoTrackDOMPoint tracker(HTMLEditorRef().mRangeUpdater, &selPoint);
+        AutoTrackDOMPoint tracker(HTMLEditorRef().RangeUpdaterRef(), &selPoint);
         if (NS_WARN_IF(!leftNode->IsContent()) ||
             NS_WARN_IF(!rightNode->IsContent())) {
           return NS_ERROR_FAILURE;
         }
         EditActionResult ret =
           TryToJoinBlocksWithTransaction(*leftNode->AsContent(),
                                          *rightNode->AsContent());
         // This should claim that trying to join the block means that
@@ -2960,19 +2961,19 @@ HTMLEditRules::WillDeleteSelection(nsIEd
     }
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
   {
     // Track location of where we are deleting
-    AutoTrackDOMPoint startTracker(HTMLEditorRef().mRangeUpdater,
+    AutoTrackDOMPoint startTracker(HTMLEditorRef().RangeUpdaterRef(),
                                    address_of(startNode), &startOffset);
-    AutoTrackDOMPoint endTracker(HTMLEditorRef().mRangeUpdater,
+    AutoTrackDOMPoint endTracker(HTMLEditorRef().RangeUpdaterRef(),
                                  address_of(endNode), &endOffset);
     // We are handling all ranged deletions directly now.
     *aHandled = true;
 
     if (endNode == startNode) {
       rv = HTMLEditorRef().DeleteSelectionWithTransaction(aAction,
                                                           aStripWrappers);
       if (NS_WARN_IF(!CanHandleEditAction())) {
@@ -3142,19 +3143,19 @@ HTMLEditRules::WillDeleteSelection(nsIEd
           }
         }
       }
     }
   }
 
   // We might have left only collapsed whitespace in the start/end nodes
   {
-    AutoTrackDOMPoint startTracker(HTMLEditorRef().mRangeUpdater,
+    AutoTrackDOMPoint startTracker(HTMLEditorRef().RangeUpdaterRef(),
                                    address_of(startNode), &startOffset);
-    AutoTrackDOMPoint endTracker(HTMLEditorRef().mRangeUpdater,
+    AutoTrackDOMPoint endTracker(HTMLEditorRef().RangeUpdaterRef(),
                                  address_of(endNode), &endOffset);
 
     nsresult rv = DeleteNodeIfCollapsedText(*startNode);
     if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
       return NS_ERROR_EDITOR_DESTROYED;
     }
     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
       "Failed to delete start node even though it's collapsed text");
@@ -3386,17 +3387,17 @@ HTMLEditRules::TryToJoinBlocksWithTransa
       return EditActionIgnored(NS_ERROR_EDITOR_DESTROYED);
     }
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return EditActionIgnored(rv);
     }
 
     {
       // We can't just track rightBlock because it's an Element.
-      AutoTrackDOMPoint tracker(HTMLEditorRef().mRangeUpdater,
+      AutoTrackDOMPoint tracker(HTMLEditorRef().RangeUpdaterRef(),
                                 &atRightBlockChild);
       rv = WSRunObject::ScrubBlockBoundary(&HTMLEditorRef(),
                                            WSRunObject::kAfterBlock,
                                            atRightBlockChild.GetContainer(),
                                            atRightBlockChild.Offset());
       if (NS_WARN_IF(!CanHandleEditAction())) {
         return EditActionIgnored(NS_ERROR_EDITOR_DESTROYED);
       }
@@ -3485,17 +3486,18 @@ HTMLEditRules::TryToJoinBlocksWithTransa
     }
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return EditActionIgnored(rv);
     }
 
     {
       // We can't just track leftBlock because it's an Element, so track
       // something else.
-      AutoTrackDOMPoint tracker(HTMLEditorRef().mRangeUpdater, &leftBlockChild);
+      AutoTrackDOMPoint tracker(HTMLEditorRef().RangeUpdaterRef(),
+                                &leftBlockChild);
       rv = WSRunObject::ScrubBlockBoundary(&HTMLEditorRef(),
                                            WSRunObject::kBeforeBlock,
                                            leftBlock, leftBlockChild.Offset());
       if (NS_WARN_IF(!CanHandleEditAction())) {
         return EditActionIgnored(NS_ERROR_EDITOR_DESTROYED);
       }
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return EditActionIgnored(rv);
@@ -7365,29 +7367,29 @@ HTMLEditRules::GetNodesForOperation(
   if (aTouchContent == TouchContent::yes) {
     nsTArray<OwningNonNull<RangeItem>> rangeItemArray;
     rangeItemArray.AppendElements(aArrayOfRanges.Length());
 
     // First register ranges for special editor gravity
     for (auto& rangeItem : rangeItemArray) {
       rangeItem = new RangeItem();
       rangeItem->StoreRange(aArrayOfRanges[0]);
-      HTMLEditorRef().mRangeUpdater.RegisterRangeItem(rangeItem);
+      HTMLEditorRef().RangeUpdaterRef().RegisterRangeItem(rangeItem);
       aArrayOfRanges.RemoveElementAt(0);
     }
     // Now bust up inlines.
     for (auto& item : Reversed(rangeItemArray)) {
       nsresult rv = BustUpInlinesAtRangeEndpoints(*item);
       if (NS_FAILED(rv)) {
         break;
       }
     }
     // Then unregister the ranges
     for (auto& item : rangeItemArray) {
-      HTMLEditorRef().mRangeUpdater.DropRangeItem(item);
+      HTMLEditorRef().RangeUpdaterRef().DropRangeItem(item);
       RefPtr<nsRange> range = item->GetRange();
       if (range) {
         aArrayOfRanges.AppendElement(range);
       }
     }
   }
   // Gather up a list of all the nodes
   for (auto& range : aArrayOfRanges) {
--- a/editor/libeditor/HTMLStyleEditor.cpp
+++ b/editor/libeditor/HTMLStyleEditor.cpp
@@ -545,46 +545,55 @@ HTMLEditor::SetInlinePropertyOnNode(nsIC
     rv = SetInlinePropertyOnNodeImpl(node, aProperty, aAttribute, aValue);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
 
 nsresult
-HTMLEditor::SplitStyleAboveRange(nsRange* inRange,
+HTMLEditor::SplitStyleAboveRange(nsRange* aRange,
                                  nsAtom* aProperty,
                                  nsAtom* aAttribute)
 {
-  NS_ENSURE_TRUE(inRange, NS_ERROR_NULL_POINTER);
+  MOZ_ASSERT(IsEditActionDataAvailable());
 
-  nsCOMPtr<nsINode> startNode = inRange->GetStartContainer();
-  int32_t startOffset = inRange->StartOffset();
-  nsCOMPtr<nsINode> endNode = inRange->GetEndContainer();
-  int32_t endOffset = inRange->EndOffset();
+  if (NS_WARN_IF(!aRange)) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  nsCOMPtr<nsINode> startNode = aRange->GetStartContainer();
+  int32_t startOffset = aRange->StartOffset();
+  nsCOMPtr<nsINode> endNode = aRange->GetEndContainer();
+  int32_t endOffset = aRange->EndOffset();
 
   nsCOMPtr<nsINode> origStartNode = startNode;
 
   // split any matching style nodes above the start of range
   {
-    AutoTrackDOMPoint tracker(mRangeUpdater, address_of(endNode), &endOffset);
+    AutoTrackDOMPoint tracker(RangeUpdaterRef(),
+                              address_of(endNode), &endOffset);
     nsresult rv =
       SplitStyleAbovePoint(address_of(startNode), &startOffset, aProperty,
                            aAttribute);
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
   }
 
   // second verse, same as the first...
   nsresult rv =
     SplitStyleAbovePoint(address_of(endNode), &endOffset, aProperty,
                          aAttribute);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
 
   // reset the range
-  rv = inRange->SetStartAndEnd(startNode, startOffset, endNode, endOffset);
+  rv = aRange->SetStartAndEnd(startNode, startOffset, endNode, endOffset);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
   return NS_OK;
 }
 
 nsresult
 HTMLEditor::SplitStyleAbovePoint(nsCOMPtr<nsINode>* aNode,
@@ -659,16 +668,18 @@ HTMLEditor::SplitStyleAbovePoint(nsCOMPt
 }
 
 nsresult
 HTMLEditor::ClearStyle(nsCOMPtr<nsINode>* aNode,
                        int32_t* aOffset,
                        nsAtom* aProperty,
                        nsAtom* aAttribute)
 {
+  MOZ_ASSERT(IsEditActionDataAvailable());
+
   nsCOMPtr<nsIContent> leftNode, rightNode;
   nsresult rv = SplitStyleAbovePoint(aNode, aOffset, aProperty,
                                      aAttribute, getter_AddRefs(leftNode),
                                      getter_AddRefs(rightNode));
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (leftNode) {
     bool bIsEmptyNode;
@@ -737,17 +748,17 @@ HTMLEditor::ClearStyle(nsCOMPtr<nsINode>
     // remove the style on this new hierarchy
     int32_t newSelOffset = 0;
     {
       // Track the point at the new hierarchy.  This is so we can know where
       // to put the selection after we call RemoveStyleInside().
       // RemoveStyleInside() could remove any and all of those nodes, so I
       // have to use the range tracking system to find the right spot to put
       // selection.
-      AutoTrackDOMPoint tracker(mRangeUpdater,
+      AutoTrackDOMPoint tracker(RangeUpdaterRef(),
                                 address_of(newSelParent), &newSelOffset);
       rv = RemoveStyleInside(*leftNode, aProperty, aAttribute);
       NS_ENSURE_SUCCESS(rv, rv);
     }
     // reset our node offset values to the resulting new sel point
     *aNode = newSelParent;
     *aOffset = newSelOffset;
   }
--- a/editor/libeditor/SelectionState.h
+++ b/editor/libeditor/SelectionState.h
@@ -88,17 +88,17 @@ ImplCycleCollectionTraverse(nsCycleColle
 }
 
 inline void
 ImplCycleCollectionUnlink(SelectionState& aField)
 {
   ImplCycleCollectionUnlink(aField.mArray);
 }
 
-class RangeUpdater final
+class MOZ_STACK_CLASS RangeUpdater final
 {
 public:
   RangeUpdater();
   ~RangeUpdater();
 
   void RegisterRangeItem(RangeItem* aRangeItem);
   void DropRangeItem(RangeItem* aRangeItem);
   nsresult RegisterSelectionState(SelectionState& aSelState);
@@ -135,41 +135,20 @@ public:
                               int32_t aOffset, uint32_t aNodeOrigLen);
   nsresult WillInsertContainer();
   nsresult DidInsertContainer();
   void WillMoveNode();
   void DidMoveNode(nsINode* aOldParent, int32_t aOldOffset,
                    nsINode* aNewParent, int32_t aNewOffset);
 
 private:
-  friend void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback&,
-                                          RangeUpdater&,
-                                          const char*,
-                                          uint32_t);
-  friend void ImplCycleCollectionUnlink(RangeUpdater& aField);
-
   nsTArray<RefPtr<RangeItem>> mArray;
   bool mLock;
 };
 
-inline void
-ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
-                            RangeUpdater& aField,
-                            const char* aName,
-                            uint32_t aFlags = 0)
-{
-  ImplCycleCollectionTraverse(aCallback, aField.mArray, aName, aFlags);
-}
-
-inline void
-ImplCycleCollectionUnlink(RangeUpdater& aField)
-{
-  ImplCycleCollectionUnlink(aField.mArray);
-}
-
 /**
  * Helper class for using SelectionState.  Stack based class for doing
  * preservation of dom points across editor actions.
  */
 
 class MOZ_STACK_CLASS AutoTrackDOMPoint final
 {
 private:
--- a/editor/libeditor/TextEditorDataTransfer.cpp
+++ b/editor/libeditor/TextEditorDataTransfer.cpp
@@ -69,17 +69,17 @@ TextEditor::PrepareToInsertContent(const
                                    bool aDoDeleteSelection)
 {
   MOZ_ASSERT(IsEditActionDataAvailable());
 
   MOZ_ASSERT(aPointToInsert.IsSet());
 
   EditorDOMPoint pointToInsert(aPointToInsert);
   if (aDoDeleteSelection) {
-    AutoTrackDOMPoint tracker(mRangeUpdater, &pointToInsert);
+    AutoTrackDOMPoint tracker(RangeUpdaterRef(), &pointToInsert);
     nsresult rv = DeleteSelectionAsSubAction(eNone, eStrip);
     if (NS_WARN_IF(Destroyed())) {
       return NS_ERROR_EDITOR_DESTROYED;
     }
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
--- a/editor/libeditor/WSRunObject.cpp
+++ b/editor/libeditor/WSRunObject.cpp
@@ -145,19 +145,19 @@ WSRunObject::PrepareToDeleteRange(HTMLEd
                                   nsCOMPtr<nsINode>* aStartNode,
                                   int32_t* aStartOffset,
                                   nsCOMPtr<nsINode>* aEndNode,
                                   int32_t* aEndOffset)
 {
   NS_ENSURE_TRUE(aHTMLEditor && aStartNode && *aStartNode && aStartOffset &&
                  aEndNode && *aEndNode && aEndOffset, NS_ERROR_NULL_POINTER);
 
-  AutoTrackDOMPoint trackerStart(aHTMLEditor->mRangeUpdater,
+  AutoTrackDOMPoint trackerStart(aHTMLEditor->RangeUpdaterRef(),
                                  aStartNode, aStartOffset);
-  AutoTrackDOMPoint trackerEnd(aHTMLEditor->mRangeUpdater,
+  AutoTrackDOMPoint trackerEnd(aHTMLEditor->RangeUpdaterRef(),
                                aEndNode, aEndOffset);
 
   WSRunObject leftWSObj(aHTMLEditor, *aStartNode, *aStartOffset);
   WSRunObject rightWSObj(aHTMLEditor, *aEndNode, *aEndOffset);
 
   return leftWSObj.PrepareToDeleteRangePriv(&rightWSObj);
 }
 
@@ -180,17 +180,17 @@ WSRunObject::PrepareToDeleteNode(HTMLEdi
 nsresult
 WSRunObject::PrepareToSplitAcrossBlocks(HTMLEditor* aHTMLEditor,
                                         nsCOMPtr<nsINode>* aSplitNode,
                                         int32_t* aSplitOffset)
 {
   NS_ENSURE_TRUE(aHTMLEditor && aSplitNode && *aSplitNode && aSplitOffset,
                  NS_ERROR_NULL_POINTER);
 
-  AutoTrackDOMPoint tracker(aHTMLEditor->mRangeUpdater,
+  AutoTrackDOMPoint tracker(aHTMLEditor->RangeUpdaterRef(),
                             aSplitNode, aSplitOffset);
 
   WSRunObject wsObj(aHTMLEditor, *aSplitNode, *aSplitOffset);
 
   return wsObj.PrepareToSplitAcrossBlocksPriv();
 }
 
 template<typename PT, typename CT>
@@ -209,17 +209,17 @@ WSRunObject::InsertBreak(Selection& aSel
 
   WSFragment* beforeRun = FindNearestRun(aPointToInsert, false);
   WSFragment* afterRun = FindNearestRun(aPointToInsert, true);
 
   EditorDOMPoint pointToInsert(aPointToInsert);
   {
     // Some scoping for AutoTrackDOMPoint.  This will track our insertion
     // point while we tweak any surrounding whitespace
-    AutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater, &pointToInsert);
+    AutoTrackDOMPoint tracker(mHTMLEditor->RangeUpdaterRef(), &pointToInsert);
 
     // Handle any changes needed to ws run after inserted br
     if (!afterRun || (afterRun->mType & WSType::trailingWS)) {
       // Don't need to do anything.  Just insert break.  ws won't change.
     } else if (afterRun->mType & WSType::leadingWS) {
       // Delete the leading ws that is after insertion point.  We don't
       // have to (it would still not be significant after br), but it's
       // just more aesthetically pleasing to.
@@ -303,17 +303,17 @@ WSRunObject::InsertText(nsIDocument& aDo
   WSFragment* beforeRun = FindNearestRun(aPointToInsert, false);
   WSFragment* afterRun = FindNearestRun(aPointToInsert, true);
 
   EditorDOMPoint pointToInsert(aPointToInsert);
   nsAutoString theString(aStringToInsert);
   {
     // Some scoping for AutoTrackDOMPoint.  This will track our insertion
     // point while we tweak any surrounding whitespace
-    AutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater, &pointToInsert);
+    AutoTrackDOMPoint tracker(mHTMLEditor->RangeUpdaterRef(), &pointToInsert);
 
     // Handle any changes needed to ws run after inserted text
     if (!afterRun || afterRun->mType & WSType::trailingWS) {
       // Don't need to do anything.  Just insert text.  ws won't change.
     } else if (afterRun->mType & WSType::leadingWS) {
       // Delete the leading ws that is after insertion point, because it
       // would become significant after text inserted.
       nsresult rv = DeleteRange(pointToInsert, afterRun->EndPoint());