Bug 181137 - part 8: Make ContentIteratorBase and its subclasses non-refcountable r=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Fri, 11 Jan 2019 01:52:26 +0000
changeset 453439 dbf919528d9794a0570b6805a45e9baeac42629f
parent 453438 2a320da37ca0e1f47828e346f6b5e09ff2196ea8
child 453440 897a97a4931de01e125e04a23a0139693c4ca163
push id35357
push usernerli@mozilla.com
push dateFri, 11 Jan 2019 21:54:07 +0000
treeherdermozilla-central@0ce024c91511 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs181137
milestone66.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 181137 - part 8: Make ContentIteratorBase and its subclasses non-refcountable r=smaug This patch makes ContentIteratorBase, PostContentIterator, PreContentIterator and ContentSubtreeIterator classes non-refcountable because most users can create their instances in stack and such users may be in a hot path. So, we can save a lot of cost of instantiation. Unfortunately, only ScriptableContentIterator creates one of the concrete classes and needs to destroy it properly. Therefore, its EnsureContentIterator(), destructor, traverse and unlink code becomes messy. However, ScriptableContentIterator was designed for automated tests and we need to maintain it not so many times. Therefore, improvement of other users must be worthwhiler than this demerit. Differential Revision: https://phabricator.services.mozilla.com/D15928
dom/base/ContentIterator.cpp
dom/base/ContentIterator.h
dom/base/ScriptableContentIterator.cpp
dom/base/ScriptableContentIterator.h
dom/base/Selection.cpp
dom/base/Selection.h
dom/base/nsContentList.cpp
dom/base/nsRange.cpp
dom/events/ContentEventHandler.cpp
editor/libeditor/DeleteRangeTransaction.cpp
editor/libeditor/EditorUtils.cpp
editor/libeditor/EditorUtils.h
editor/libeditor/HTMLEditRules.cpp
editor/libeditor/HTMLEditor.cpp
editor/libeditor/HTMLStyleEditor.cpp
editor/libeditor/TextEditor.cpp
editor/spellchecker/FilteredContentIterator.cpp
editor/spellchecker/FilteredContentIterator.h
layout/base/PresShell.cpp
--- a/dom/base/ContentIterator.cpp
+++ b/dom/base/ContentIterator.cpp
@@ -63,29 +63,16 @@ static bool NodeIsInTraversalRange(nsINo
   }
 
   // Pre mode: start <= node < end.
   RawRangeBoundary beforeNode(parent, aNode->GetPreviousSibling());
   return nsContentUtils::ComparePoints(aStart, beforeNode) <= 0 &&
          nsContentUtils::ComparePoints(aEnd, beforeNode) > 0;
 }
 
-NS_IMPL_CYCLE_COLLECTION(ContentIteratorBase, mCurNode, mFirst, mLast,
-                         mCommonParent, mRange)
-
-NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(ContentIteratorBase, AddRef)
-NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(ContentIteratorBase, Release)
-
-void ContentIteratorBase::LastRelease() {
-  mCurNode = nullptr;
-  mFirst = nullptr;
-  mLast = nullptr;
-  mCommonParent = nullptr;
-}
-
 ContentIteratorBase::ContentIteratorBase(bool aPre)
     : mIsDone(false), mPre(aPre) {}
 
 /******************************************************
  * Init routines
  ******************************************************/
 
 nsresult ContentIteratorBase::Init(nsINode* aRoot) {
@@ -622,46 +609,17 @@ nsINode* ContentIteratorBase::GetCurrent
   }
 
   NS_ASSERTION(mCurNode, "Null current node in an iterator that's not done!");
 
   return mCurNode;
 }
 
 /******************************************************
- * PostContentIterator
- ******************************************************/
-
-NS_IMPL_CYCLE_COLLECTING_NATIVE_ADDREF(PostContentIterator)
-NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE_WITH_LAST_RELEASE(PostContentIterator,
-                                                          LastRelease())
-
-/******************************************************
- * PreContentIterator
- ******************************************************/
-
-NS_IMPL_CYCLE_COLLECTING_NATIVE_ADDREF(PreContentIterator)
-NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE_WITH_LAST_RELEASE(PreContentIterator,
-                                                          LastRelease())
-
-/******************************************************
- * ContentSubtreeIterator
- ******************************************************/
-
-void ContentSubtreeIterator::LastRelease() {
-  mRange = nullptr;
-  ContentIteratorBase::LastRelease();
-}
-
-NS_IMPL_CYCLE_COLLECTING_NATIVE_ADDREF(ContentSubtreeIterator)
-NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE_WITH_LAST_RELEASE(
-    ContentSubtreeIterator, LastRelease())
-
-/******************************************************
- * Init routines
+ * ContentSubtreeIterator init routines
  ******************************************************/
 
 nsresult ContentSubtreeIterator::Init(nsINode* aRoot) {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 nsresult ContentSubtreeIterator::Init(nsRange* aRange) {
   MOZ_ASSERT(aRange);
--- a/dom/base/ContentIterator.h
+++ b/dom/base/ContentIterator.h
@@ -18,27 +18,22 @@ namespace mozilla {
 
 /**
  * ContentIteratorBase is a base class of PostContentIterator,
  * PreContentIterator and ContentSubtreeIterator.  Making each concrete
  * classes "final", compiler can avoid virtual calls if they are treated
  * by the users directly.
  */
 class ContentIteratorBase {
- protected:
-  nsCycleCollectingAutoRefCnt mRefCnt;
-  NS_DECL_OWNINGTHREAD
-
  public:
   ContentIteratorBase() = delete;
   ContentIteratorBase(const ContentIteratorBase&) = delete;
   ContentIteratorBase& operator=(const ContentIteratorBase&) = delete;
+  virtual ~ContentIteratorBase() = default;
 
-  NS_IMETHOD_(MozExternalRefCountType) AddRef() = 0;
-  NS_IMETHOD_(MozExternalRefCountType) Release() = 0;
   NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(ContentIteratorBase)
 
   virtual nsresult Init(nsINode* aRoot);
   virtual nsresult Init(nsRange* aRange);
   virtual nsresult Init(nsINode* aStartContainer, uint32_t aStartOffset,
                         nsINode* aEndContainer, uint32_t aEndOffset);
   virtual nsresult Init(const RawRangeBoundary& aStart,
                         const RawRangeBoundary& aEnd);
@@ -51,17 +46,16 @@ class ContentIteratorBase {
   virtual nsINode* GetCurrentNode();
 
   virtual bool IsDone();
 
   virtual nsresult PositionAt(nsINode* aCurNode);
 
  protected:
   explicit ContentIteratorBase(bool aPre);
-  virtual ~ContentIteratorBase() = default;
 
   /**
    * Callers must guarantee that:
    * - Neither aStartContainer nor aEndContainer is nullptr.
    * - aStartOffset and aEndOffset are valid for its container.
    * - The start point and the end point are in document order.
    */
   nsresult InitInternal(const RawRangeBoundary& aStart,
@@ -80,75 +74,110 @@ class ContentIteratorBase {
   nsIContent* GetNextSibling(nsINode* aNode);
   nsIContent* GetPrevSibling(nsINode* aNode);
 
   nsINode* NextNode(nsINode* aNode);
   nsINode* PrevNode(nsINode* aNode);
 
   void MakeEmpty();
 
-  virtual void LastRelease();
-
   nsCOMPtr<nsINode> mCurNode;
   nsCOMPtr<nsINode> mFirst;
   nsCOMPtr<nsINode> mLast;
   nsCOMPtr<nsINode> mCommonParent;
 
-  // Used only by ContentSubtreeIterator class but we need to put this here
-  // for cycle collection because macros to implement classes in cycle
-  // collection do not support inherited classes without nsISupports interface.
-  RefPtr<nsRange> mRange;
-
   bool mIsDone;
   bool mPre;
+  friend void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback&,
+                                          ContentIteratorBase&, const char*,
+                                          uint32_t);
+  friend void ImplCycleCollectionUnlink(ContentIteratorBase&);
 };
 
+// Each concreate class of ContentIteratorBase may be owned by another class
+// which may be owned by JS.  Therefore, all of them should be in the cycle
+// collection.  However, we cannot make non-refcountable classes only with the
+// macros.  So, we need to make them cycle collectable without the macros.
+inline void ImplCycleCollectionTraverse(
+    nsCycleCollectionTraversalCallback& aCallback, ContentIteratorBase& aField,
+    const char* aName, uint32_t aFlags = 0) {
+  ImplCycleCollectionTraverse(aCallback, aField.mCurNode, aName, aFlags);
+  ImplCycleCollectionTraverse(aCallback, aField.mFirst, aName, aFlags);
+  ImplCycleCollectionTraverse(aCallback, aField.mLast, aName, aFlags);
+  ImplCycleCollectionTraverse(aCallback, aField.mCommonParent, aName, aFlags);
+}
+
+inline void ImplCycleCollectionUnlink(ContentIteratorBase& aField) {
+  ImplCycleCollectionUnlink(aField.mCurNode);
+  ImplCycleCollectionUnlink(aField.mFirst);
+  ImplCycleCollectionUnlink(aField.mLast);
+  ImplCycleCollectionUnlink(aField.mCommonParent);
+}
+
 /**
  * A simple iterator class for traversing the content in "close tag" order.
  */
 class PostContentIterator final : public ContentIteratorBase {
  public:
   PostContentIterator() : ContentIteratorBase(false) {}
   PostContentIterator(const PostContentIterator&) = delete;
   PostContentIterator& operator=(const PostContentIterator&) = delete;
-
-  NS_IMETHOD_(MozExternalRefCountType) AddRef() override;
-  NS_IMETHOD_(MozExternalRefCountType) Release() override;
+  virtual ~PostContentIterator() = default;
+  friend void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback&,
+                                          PostContentIterator&, const char*,
+                                          uint32_t);
+  friend void ImplCycleCollectionUnlink(PostContentIterator&);
+};
 
- protected:
-  virtual ~PostContentIterator() = default;
-};
+inline void ImplCycleCollectionTraverse(
+    nsCycleCollectionTraversalCallback& aCallback, PostContentIterator& aField,
+    const char* aName, uint32_t aFlags = 0) {
+  ImplCycleCollectionTraverse(
+      aCallback, static_cast<ContentIteratorBase&>(aField), aName, aFlags);
+}
+
+inline void ImplCycleCollectionUnlink(PostContentIterator& aField) {
+  ImplCycleCollectionUnlink(static_cast<ContentIteratorBase&>(aField));
+}
 
 /**
  * A simple iterator class for traversing the content in "start tag" order.
  */
 class PreContentIterator final : public ContentIteratorBase {
  public:
   PreContentIterator() : ContentIteratorBase(true) {}
   PreContentIterator(const PreContentIterator&) = delete;
   PreContentIterator& operator=(const PreContentIterator&) = delete;
-
-  NS_IMETHOD_(MozExternalRefCountType) AddRef() override;
-  NS_IMETHOD_(MozExternalRefCountType) Release() override;
+  virtual ~PreContentIterator() = default;
+  friend void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback&,
+                                          PreContentIterator&, const char*,
+                                          uint32_t);
+  friend void ImplCycleCollectionUnlink(PreContentIterator&);
+};
 
- protected:
-  virtual ~PreContentIterator() = default;
-};
+inline void ImplCycleCollectionTraverse(
+    nsCycleCollectionTraversalCallback& aCallback, PreContentIterator& aField,
+    const char* aName, uint32_t aFlags = 0) {
+  ImplCycleCollectionTraverse(
+      aCallback, static_cast<ContentIteratorBase&>(aField), aName, aFlags);
+}
+
+inline void ImplCycleCollectionUnlink(PreContentIterator& aField) {
+  ImplCycleCollectionUnlink(static_cast<ContentIteratorBase&>(aField));
+}
 
 /**
  *  A simple iterator class for traversing the content in "top subtree" order.
  */
 class ContentSubtreeIterator final : public ContentIteratorBase {
  public:
   ContentSubtreeIterator() : ContentIteratorBase(true) {}
   ContentSubtreeIterator(const ContentSubtreeIterator&) = delete;
   ContentSubtreeIterator& operator=(const ContentSubtreeIterator&) = delete;
-
-  NS_IMETHOD_(MozExternalRefCountType) AddRef() override;
-  NS_IMETHOD_(MozExternalRefCountType) Release() override;
+  virtual ~ContentSubtreeIterator() = default;
 
   virtual nsresult Init(nsINode* aRoot) override;
   virtual nsresult Init(nsRange* aRange) override;
   virtual nsresult Init(nsINode* aStartContainer, uint32_t aStartOffset,
                         nsINode* aEndContainer, uint32_t aEndOffset) override;
   virtual nsresult Init(const RawRangeBoundary& aStart,
                         const RawRangeBoundary& aEnd) override;
 
@@ -156,31 +185,47 @@ class ContentSubtreeIterator final : pub
   virtual void Prev() override;
   // Must override these because we don't do PositionAt
   virtual void First() override;
   // Must override these because we don't do PositionAt
   virtual void Last() override;
 
   virtual nsresult PositionAt(nsINode* aCurNode) override;
 
+  friend void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback&,
+                                          ContentSubtreeIterator&, const char*,
+                                          uint32_t);
+  friend void ImplCycleCollectionUnlink(ContentSubtreeIterator&);
+
  protected:
-  virtual ~ContentSubtreeIterator() = default;
-
   /**
    * Callers must guarantee that mRange isn't nullptr and is positioned.
    */
   nsresult InitWithRange();
 
   // Returns the highest inclusive ancestor of aNode that's in the range
   // (possibly aNode itself).  Returns null if aNode is null, or is not itself
   // in the range.  A node is in the range if (node, 0) comes strictly after
   // the range endpoint, and (node, node.length) comes strictly before it, so
   // the range's start and end nodes will never be considered "in" it.
   nsIContent* GetTopAncestorInRange(nsINode* aNode);
 
-  virtual void LastRelease() override;
+  RefPtr<nsRange> mRange;
 
   AutoTArray<nsIContent*, 8> mEndNodes;
 };
 
+inline void ImplCycleCollectionTraverse(
+    nsCycleCollectionTraversalCallback& aCallback,
+    ContentSubtreeIterator& aField, const char* aName, uint32_t aFlags = 0) {
+  ImplCycleCollectionTraverse(aCallback, aField.mRange, aName, aFlags);
+  ImplCycleCollectionTraverse(
+      aCallback, static_cast<ContentIteratorBase&>(aField), aName, aFlags);
+}
+
+inline void ImplCycleCollectionUnlink(ContentSubtreeIterator& aField) {
+  ImplCycleCollectionUnlink(aField.mRange);
+  ImplCycleCollectionUnlink(static_cast<ContentIteratorBase&>(aField));
+}
+
 }  // namespace mozilla
 
 #endif  // #ifndef mozilla_ContentIterator_h
--- a/dom/base/ScriptableContentIterator.cpp
+++ b/dom/base/ScriptableContentIterator.cpp
@@ -15,35 +15,77 @@ namespace mozilla {
 NS_IMPL_CYCLE_COLLECTING_ADDREF(ScriptableContentIterator)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(ScriptableContentIterator)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ScriptableContentIterator)
   NS_INTERFACE_MAP_ENTRY(nsIScriptableContentIterator)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
-NS_IMPL_CYCLE_COLLECTION(ScriptableContentIterator, mContentIterator)
+NS_IMPL_CYCLE_COLLECTION_CLASS(ScriptableContentIterator)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ScriptableContentIterator)
+  if (tmp->mContentIterator) {
+    switch (tmp->mIteratorType) {
+      case POST_ORDER_ITERATOR:
+      default:
+        ImplCycleCollectionUnlink(
+            static_cast<PostContentIterator&>(*tmp->mContentIterator));
+        break;
+      case PRE_ORDER_ITERATOR:
+        ImplCycleCollectionUnlink(
+            static_cast<PreContentIterator&>(*tmp->mContentIterator));
+        break;
+      case SUBTREE_ITERATOR:
+        ImplCycleCollectionUnlink(
+            static_cast<ContentSubtreeIterator&>(*tmp->mContentIterator));
+        break;
+    }
+  }
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ScriptableContentIterator)
+  if (tmp->mContentIterator) {
+    switch (tmp->mIteratorType) {
+      case POST_ORDER_ITERATOR:
+      default:
+        ImplCycleCollectionTraverse(
+            cb, static_cast<PostContentIterator&>(*tmp->mContentIterator),
+            "mContentIterator");
+        break;
+      case PRE_ORDER_ITERATOR:
+        ImplCycleCollectionTraverse(
+            cb, static_cast<PreContentIterator&>(*tmp->mContentIterator),
+            "mContentIterator");
+        break;
+      case SUBTREE_ITERATOR:
+        ImplCycleCollectionTraverse(
+            cb, static_cast<ContentSubtreeIterator&>(*tmp->mContentIterator),
+            "mContentIterator");
+        break;
+    }
+  }
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 ScriptableContentIterator::ScriptableContentIterator()
     : mIteratorType(NOT_INITIALIZED) {}
 
 void ScriptableContentIterator::EnsureContentIterator() {
   if (mContentIterator) {
     return;
   }
   switch (mIteratorType) {
     case POST_ORDER_ITERATOR:
     default:
-      mContentIterator = new PostContentIterator();
+      mContentIterator = MakeUnique<PostContentIterator>();
       break;
     case PRE_ORDER_ITERATOR:
-      mContentIterator = new PreContentIterator();
+      mContentIterator = MakeUnique<PreContentIterator>();
       break;
     case SUBTREE_ITERATOR:
-      mContentIterator = new ContentSubtreeIterator();
+      mContentIterator = MakeUnique<ContentSubtreeIterator>();
       break;
   }
 }
 
 NS_IMETHODIMP
 ScriptableContentIterator::InitWithRootNode(IteratorType aType,
                                             nsINode* aRoot) {
   if (aType == NOT_INITIALIZED ||
--- a/dom/base/ScriptableContentIterator.h
+++ b/dom/base/ScriptableContentIterator.h
@@ -4,16 +4,17 @@
  * 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 mozilla_scriptablecontentiterator_h
 #define mozilla_scriptablecontentiterator_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/ContentIterator.h"
+#include "mozilla/UniquePtr.h"
 #include "nsCOMPtr.h"
 #include "nsIScriptableContentIterator.h"
 
 namespace mozilla {
 
 class ScriptableContentIterator final : public nsIScriptableContentIterator {
  public:
   ScriptableContentIterator();
@@ -21,14 +22,14 @@ class ScriptableContentIterator final : 
   NS_DECL_CYCLE_COLLECTION_CLASS(ScriptableContentIterator)
   NS_DECL_NSISCRIPTABLECONTENTITERATOR
 
  protected:
   virtual ~ScriptableContentIterator() = default;
   void EnsureContentIterator();
 
   IteratorType mIteratorType;
-  RefPtr<ContentIteratorBase> mContentIterator;
+  UniquePtr<ContentIteratorBase> mContentIterator;
 };
 
 }  // namespace mozilla
 
 #endif  // #ifndef mozilla_scriptablecontentiterator_h
--- a/dom/base/Selection.cpp
+++ b/dom/base/Selection.cpp
@@ -1477,30 +1477,30 @@ void Selection::SelectFramesForContent(n
                                 mSelectionType);
   } else {
     frame->InvalidateFrameSubtree();  // frame continuations?
   }
 }
 
 // select all content children of aContent
 nsresult Selection::SelectAllFramesForContent(
-    PostContentIterator* aPostOrderIter, nsIContent* aContent, bool aSelected) {
+    PostContentIterator& aPostOrderIter, nsIContent* aContent, bool aSelected) {
   // If aContent doesn't have children, we should avoid to use the content
   // iterator for performance reason.
   if (!aContent->HasChildren()) {
     SelectFramesForContent(aContent, aSelected);
     return NS_OK;
   }
 
-  if (NS_WARN_IF(NS_FAILED(aPostOrderIter->Init(aContent)))) {
+  if (NS_WARN_IF(NS_FAILED(aPostOrderIter.Init(aContent)))) {
     return NS_ERROR_FAILURE;
   }
 
-  for (; !aPostOrderIter->IsDone(); aPostOrderIter->Next()) {
-    nsINode* node = aPostOrderIter->GetCurrentNode();
+  for (; !aPostOrderIter.IsDone(); aPostOrderIter.Next()) {
+    nsINode* node = aPostOrderIter.GetCurrentNode();
     MOZ_ASSERT(node);
     nsIContent* innercontent = node->IsContent() ? node->AsContent() : nullptr;
     SelectFramesForContent(innercontent, aSelected);
   }
 
   return NS_OK;
 }
 
@@ -1570,25 +1570,25 @@ nsresult Selection::SelectFrames(nsPresC
   if (aRange->Collapsed() ||
       (startNode == endNode && !startNode->HasChildren())) {
     if (!isFirstContentTextNode) {
       SelectFramesForContent(startContent, aSelect);
     }
     return NS_OK;
   }
 
-  RefPtr<ContentSubtreeIterator> subtreeIter = new ContentSubtreeIterator();
-  subtreeIter->Init(aRange);
-  if (isFirstContentTextNode && !subtreeIter->IsDone() &&
-      subtreeIter->GetCurrentNode() == startNode) {
-    subtreeIter->Next();  // first content has already been handled.
+  ContentSubtreeIterator subtreeIter;
+  subtreeIter.Init(aRange);
+  if (isFirstContentTextNode && !subtreeIter.IsDone() &&
+      subtreeIter.GetCurrentNode() == startNode) {
+    subtreeIter.Next();  // first content has already been handled.
   }
-  RefPtr<PostContentIterator> postOrderIter = new PostContentIterator();
-  for (; !subtreeIter->IsDone(); subtreeIter->Next()) {
-    nsINode* node = subtreeIter->GetCurrentNode();
+  PostContentIterator postOrderIter;
+  for (; !subtreeIter.IsDone(); subtreeIter.Next()) {
+    nsINode* node = subtreeIter.GetCurrentNode();
     MOZ_ASSERT(node);
     nsIContent* content = node->IsContent() ? node->AsContent() : nullptr;
     SelectAllFramesForContent(postOrderIter, content, aSelect);
   }
 
   // We must now do the last one if it is not the same as the first
   if (endNode != startNode) {
     nsIContent* endContent =
--- a/dom/base/Selection.h
+++ b/dom/base/Selection.h
@@ -587,17 +587,17 @@ class Selection final : public nsSupport
   /**
    * Set mAnchorFocusRange to mRanges[aIndex] if aIndex is a valid index.
    * Set mAnchorFocusRange to nullptr if aIndex is negative.
    * Otherwise, i.e., if aIndex is positive but out of bounds of mRanges, do
    * nothing.
    */
   void SetAnchorFocusRange(int32_t aIndex);
   void SelectFramesForContent(nsIContent* aContent, bool aSelected);
-  nsresult SelectAllFramesForContent(PostContentIterator* aPostOrderIter,
+  nsresult SelectAllFramesForContent(PostContentIterator& aPostOrderIter,
                                      nsIContent* aContent, bool aSelected);
   nsresult SelectFrames(nsPresContext* aPresContext, nsRange* aRange,
                         bool aSelect);
 
   /**
    * Test whether the supplied range points to a single table element.
    * Result is one of the TableSelection constants. "None" means
    * a table element isn't selected.
--- a/dom/base/nsContentList.cpp
+++ b/dom/base/nsContentList.cpp
@@ -885,43 +885,42 @@ void nsContentList::AssertInSync() {
   }
 
   // XXX This code will need to change if nsContentLists can ever match
   // elements that are outside of the document element.
   nsIContent* root = mRootNode->IsDocument()
                          ? mRootNode->AsDocument()->GetRootElement()
                          : mRootNode->AsContent();
 
-  RefPtr<PreContentIterator> preOrderIter;
+  PreContentIterator preOrderIter;
   if (mDeep) {
-    preOrderIter = new PreContentIterator();
-    preOrderIter->Init(root);
-    preOrderIter->First();
+    preOrderIter.Init(root);
+    preOrderIter.First();
   }
 
   uint32_t cnt = 0, index = 0;
   while (true) {
     if (cnt == mElements.Length() && mState == LIST_LAZY) {
       break;
     }
 
     nsIContent* cur =
-        mDeep ? preOrderIter->GetCurrentNode() : mRootNode->GetChildAt(index++);
+        mDeep ? preOrderIter.GetCurrentNode() : mRootNode->GetChildAt(index++);
     if (!cur) {
       break;
     }
 
     if (cur->IsElement() && Match(cur->AsElement())) {
       NS_ASSERTION(cnt < mElements.Length() && mElements[cnt] == cur,
                    "Elements is out of sync");
       ++cnt;
     }
 
     if (mDeep) {
-      preOrderIter->Next();
+      preOrderIter.Next();
     }
   }
 
   NS_ASSERTION(cnt == mElements.Length(), "Too few elements");
 }
 #endif
 
 //-----------------------------------------------------
--- a/dom/base/nsRange.cpp
+++ b/dom/base/nsRange.cpp
@@ -26,16 +26,17 @@
 #include "mozilla/dom/DocumentType.h"
 #include "mozilla/dom/RangeBinding.h"
 #include "mozilla/dom/DOMRect.h"
 #include "mozilla/dom/DOMStringList.h"
 #include "mozilla/dom/ShadowRoot.h"
 #include "mozilla/dom/Selection.h"
 #include "mozilla/dom/Text.h"
 #include "mozilla/Telemetry.h"
+#include "mozilla/UniquePtr.h"
 #include "mozilla/Likely.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsStyleStruct.h"
 #include "nsStyleStructInlines.h"
 #include "nsComputedDOMStyle.h"
 #include "mozilla/dom/InspectorFontFace.h"
 
 using namespace mozilla;
@@ -1495,17 +1496,17 @@ void nsRange::SelectNodeContents(nsINode
 // methods we need, so should the Content Iterator support the
 // start/end points in the future, we can switchover relatively
 // easy.
 
 class MOZ_STACK_CLASS RangeSubtreeIterator {
  private:
   enum RangeSubtreeIterState { eDone = 0, eUseStart, eUseIterator, eUseEnd };
 
-  RefPtr<ContentSubtreeIterator> mSubtreeIter;
+  UniquePtr<ContentSubtreeIterator> mSubtreeIter;
   RangeSubtreeIterState mIterState;
 
   nsCOMPtr<nsINode> mStart;
   nsCOMPtr<nsINode> mEnd;
 
  public:
   RangeSubtreeIterator() : mIterState(eDone) {}
   ~RangeSubtreeIterator() {}
@@ -1557,17 +1558,17 @@ nsresult RangeSubtreeIterator::Init(nsRa
     // node. Null out the end pointer so we only visit the
     // node once!
 
     mEnd = nullptr;
   } else {
     // Now create a Content Subtree Iterator to be used
     // for the subtrees between the end points!
 
-    mSubtreeIter = new ContentSubtreeIterator();
+    mSubtreeIter = MakeUnique<ContentSubtreeIterator>();
 
     nsresult res = mSubtreeIter->Init(aRange);
     if (NS_FAILED(res)) return res;
 
     if (mSubtreeIter->IsDone()) {
       // The subtree iterator thinks there's nothing
       // to iterate over, so just free it up so we
       // don't accidentally call into it.
@@ -2611,29 +2612,29 @@ void nsRange::ToString(nsAString& aRetur
     }
   }
 
   /* complex case: mStart.Container() != mEnd.Container(), or mStartParent not a
      text node revisit - there are potential optimizations here and also
      tradeoffs.
   */
 
-  RefPtr<PostContentIterator> postOrderIter = new PostContentIterator();
-  nsresult rv = postOrderIter->Init(this);
+  PostContentIterator postOrderIter;
+  nsresult rv = postOrderIter.Init(this);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     aErr.Throw(rv);
     return;
   }
 
   nsString tempString;
 
   // loop through the content iterator, which returns nodes in the range in
   // close tag order, and grab the text from any text node
-  for (; !postOrderIter->IsDone(); postOrderIter->Next()) {
-    nsINode* n = postOrderIter->GetCurrentNode();
+  for (; !postOrderIter.IsDone(); postOrderIter.Next()) {
+    nsINode* n = postOrderIter.GetCurrentNode();
 
 #ifdef DEBUG_range
     // If debug, dump it:
     n->List(stdout);
 #endif /* DEBUG */
     Text* textNode = n->GetAsText();
     if (textNode)  // if it's a text node, get the text
     {
@@ -3052,33 +3053,33 @@ static bool ExcludeIfNextToNonSelectable
 void nsRange::ExcludeNonSelectableNodes(nsTArray<RefPtr<nsRange>>* aOutRanges) {
   MOZ_ASSERT(mIsPositioned);
   MOZ_ASSERT(mEnd.Container());
   MOZ_ASSERT(mStart.Container());
 
   nsRange* range = this;
   RefPtr<nsRange> newRange;
   while (range) {
-    RefPtr<PreContentIterator> preOrderIter = new PreContentIterator();
-    nsresult rv = preOrderIter->Init(range);
+    PreContentIterator preOrderIter;
+    nsresult rv = preOrderIter.Init(range);
     if (NS_FAILED(rv)) {
       return;
     }
 
     bool added = false;
     bool seenSelectable = false;
     // |firstNonSelectableContent| is the first node in a consecutive sequence
     // of non-IsSelectable nodes.  When we find a selectable node after such
     // a sequence we'll end the last nsRange, create a new one and restart
     // the outer loop.
     nsIContent* firstNonSelectableContent = nullptr;
     while (true) {
       ErrorResult err;
-      nsINode* node = preOrderIter->GetCurrentNode();
-      preOrderIter->Next();
+      nsINode* node = preOrderIter.GetCurrentNode();
+      preOrderIter.Next();
       bool selectable = true;
       nsIContent* content =
           node && node->IsContent() ? node->AsContent() : nullptr;
       if (content) {
         if (firstNonSelectableContent &&
             ExcludeIfNextToNonSelectable(content)) {
           // Ignorable whitespace next to a sequence of non-selectable nodes
           // counts as non-selectable (bug 1216001).
@@ -3094,17 +3095,17 @@ void nsRange::ExcludeNonSelectableNodes(
           }
         }
       }
 
       if (!selectable) {
         if (!firstNonSelectableContent) {
           firstNonSelectableContent = content;
         }
-        if (preOrderIter->IsDone() && seenSelectable) {
+        if (preOrderIter.IsDone() && seenSelectable) {
           // The tail end of the initial range is non-selectable - truncate the
           // current range before the first non-selectable node.
           range->SetEndBefore(*firstNonSelectableContent, err);
         }
       } else if (firstNonSelectableContent) {
         if (range == this && !seenSelectable) {
           // This is the initial range and all its nodes until now are
           // non-selectable so just trim them from the start.
@@ -3150,17 +3151,17 @@ void nsRange::ExcludeNonSelectableNodes(
         }
       } else {
         seenSelectable = true;
         if (!added) {
           added = true;
           aOutRanges->AppendElement(range);
         }
       }
-      if (preOrderIter->IsDone()) {
+      if (preOrderIter.IsDone()) {
         return;
       }
     }
   }
 }
 
 struct InnerTextAccumulator {
   explicit InnerTextAccumulator(mozilla::dom::DOMString& aValue)
--- a/dom/events/ContentEventHandler.cpp
+++ b/dom/events/ContentEventHandler.cpp
@@ -726,24 +726,24 @@ nsresult ContentEventHandler::GenerateFl
   if (startNode == endNode && startNode->IsText()) {
     nsIContent* content = startNode->AsContent();
     AppendSubString(aString, content, aRawRange.StartOffset(),
                     aRawRange.EndOffset() - aRawRange.StartOffset());
     ConvertToNativeNewlines(aString);
     return NS_OK;
   }
 
-  RefPtr<PreContentIterator> preOrderIter = new PreContentIterator();
+  PreContentIterator preOrderIter;
   nsresult rv =
-      preOrderIter->Init(aRawRange.Start().AsRaw(), aRawRange.End().AsRaw());
+      preOrderIter.Init(aRawRange.Start().AsRaw(), aRawRange.End().AsRaw());
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
-  for (; !preOrderIter->IsDone(); preOrderIter->Next()) {
-    nsINode* node = preOrderIter->GetCurrentNode();
+  for (; !preOrderIter.IsDone(); preOrderIter.Next()) {
+    nsINode* node = preOrderIter.GetCurrentNode();
     if (NS_WARN_IF(!node)) {
       break;
     }
     if (!node->IsContent()) {
       continue;
     }
     nsIContent* content = node->AsContent();
 
@@ -887,24 +887,24 @@ nsresult ContentEventHandler::GenerateFl
   nsINode* startNode = aRawRange.GetStartContainer();
   nsINode* endNode = aRawRange.GetEndContainer();
   if (NS_WARN_IF(!startNode) || NS_WARN_IF(!endNode)) {
     return NS_ERROR_FAILURE;
   }
 
   // baseOffset is the flattened offset of each content node.
   int32_t baseOffset = 0;
-  RefPtr<PreContentIterator> preOrderIter = new PreContentIterator();
+  PreContentIterator preOrderIter;
   nsresult rv =
-      preOrderIter->Init(aRawRange.Start().AsRaw(), aRawRange.End().AsRaw());
+      preOrderIter.Init(aRawRange.Start().AsRaw(), aRawRange.End().AsRaw());
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
-  for (; !preOrderIter->IsDone(); preOrderIter->Next()) {
-    nsINode* node = preOrderIter->GetCurrentNode();
+  for (; !preOrderIter.IsDone(); preOrderIter.Next()) {
+    nsINode* node = preOrderIter.GetCurrentNode();
     if (NS_WARN_IF(!node)) {
       break;
     }
     if (!node->IsContent()) {
       continue;
     }
     nsIContent* content = node->AsContent();
 
@@ -1013,27 +1013,27 @@ nsresult ContentEventHandler::SetRawRang
   // Special case like <br contenteditable>
   if (!mRootContent->HasChildren()) {
     nsresult rv = aRawRange->CollapseTo(RawRangeBoundary(mRootContent, 0));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
-  RefPtr<PreContentIterator> preOrderIter = new PreContentIterator();
-  nsresult rv = preOrderIter->Init(mRootContent);
+  PreContentIterator preOrderIter;
+  nsresult rv = preOrderIter.Init(mRootContent);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   uint32_t offset = 0;
   uint32_t endOffset = aOffset + aLength;
   bool startSet = false;
-  for (; !preOrderIter->IsDone(); preOrderIter->Next()) {
-    nsINode* node = preOrderIter->GetCurrentNode();
+  for (; !preOrderIter.IsDone(); preOrderIter.Next()) {
+    nsINode* node = preOrderIter.GetCurrentNode();
     if (NS_WARN_IF(!node)) {
       break;
     }
     // FYI: mRootContent shouldn't cause any text. So, we can skip it simply.
     if (node == mRootContent || !node->IsContent()) {
       continue;
     }
     nsIContent* content = node->AsContent();
@@ -1445,24 +1445,24 @@ void ContentEventHandler::EnsureNonEmpty
   aRect.height = std::max(1, aRect.height);
   aRect.width = std::max(1, aRect.width);
 }
 
 ContentEventHandler::FrameAndNodeOffset
 ContentEventHandler::GetFirstFrameInRangeForTextRect(
     const RawRange& aRawRange) {
   NodePosition nodePosition;
-  RefPtr<PreContentIterator> preOrderIter = new PreContentIterator();
+  PreContentIterator preOrderIter;
   nsresult rv =
-      preOrderIter->Init(aRawRange.Start().AsRaw(), aRawRange.End().AsRaw());
+      preOrderIter.Init(aRawRange.Start().AsRaw(), aRawRange.End().AsRaw());
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return FrameAndNodeOffset();
   }
-  for (; !preOrderIter->IsDone(); preOrderIter->Next()) {
-    nsINode* node = preOrderIter->GetCurrentNode();
+  for (; !preOrderIter.IsDone(); preOrderIter.Next()) {
+    nsINode* node = preOrderIter.GetCurrentNode();
     if (NS_WARN_IF(!node)) {
       break;
     }
 
     if (!node->IsContent()) {
       continue;
     }
 
@@ -1494,19 +1494,19 @@ ContentEventHandler::GetFirstFrameInRang
   GetFrameForTextRect(nodePosition.Container(), nodePosition.Offset(), true,
                       &firstFrame);
   return FrameAndNodeOffset(firstFrame, nodePosition.Offset());
 }
 
 ContentEventHandler::FrameAndNodeOffset
 ContentEventHandler::GetLastFrameInRangeForTextRect(const RawRange& aRawRange) {
   NodePosition nodePosition;
-  RefPtr<PreContentIterator> preOrderIter = new PreContentIterator();
+  PreContentIterator preOrderIter;
   nsresult rv =
-      preOrderIter->Init(aRawRange.Start().AsRaw(), aRawRange.End().AsRaw());
+      preOrderIter.Init(aRawRange.Start().AsRaw(), aRawRange.End().AsRaw());
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return FrameAndNodeOffset();
   }
 
   const RangeBoundary& endPoint = aRawRange.End();
   MOZ_ASSERT(endPoint.IsSet());
   // If the end point is start of a text node or specified by its parent and
   // index, the node shouldn't be included into the range.  For example,
@@ -1533,18 +1533,18 @@ ContentEventHandler::GetLastFrameInRange
     if (endPoint.IsStartOfContainer() &&
         aRawRange.GetStartContainer() != endPoint.Container()) {
       nextNodeOfRangeEnd = endPoint.Container();
     }
   } else if (endPoint.IsSetAndValid()) {
     nextNodeOfRangeEnd = endPoint.GetChildAtOffset();
   }
 
-  for (preOrderIter->Last(); !preOrderIter->IsDone(); preOrderIter->Prev()) {
-    nsINode* node = preOrderIter->GetCurrentNode();
+  for (preOrderIter.Last(); !preOrderIter.IsDone(); preOrderIter.Prev()) {
+    nsINode* node = preOrderIter.GetCurrentNode();
     if (NS_WARN_IF(!node)) {
       break;
     }
 
     if (!node->IsContent() || node == nextNodeOfRangeEnd) {
       continue;
     }
 
@@ -2105,18 +2105,18 @@ nsresult ContentEventHandler::OnQueryTex
   rv = SetRawRangeFromFlatTextOffset(
       &rawRange, aEvent->mInput.mOffset, aEvent->mInput.mLength, lineBreakType,
       true, &aEvent->mReply.mOffset, getter_AddRefs(lastTextContent));
   NS_ENSURE_SUCCESS(rv, rv);
   rv = GenerateFlatTextContent(rawRange, aEvent->mReply.mString, lineBreakType);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // used to iterate over all contents and their frames
-  RefPtr<PostContentIterator> postOrderIter = new PostContentIterator();
-  rv = postOrderIter->Init(rawRange.Start().AsRaw(), rawRange.End().AsRaw());
+  PostContentIterator postOrderIter;
+  rv = postOrderIter.Init(rawRange.Start().AsRaw(), rawRange.End().AsRaw());
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return NS_ERROR_FAILURE;
   }
 
   // Get the first frame which causes some text after the offset.
   FrameAndNodeOffset firstFrame = GetFirstFrameInRangeForTextRect(rawRange);
 
   // If GetFirstFrameInRangeForTextRect() does not return valid frame, that
@@ -2293,18 +2293,18 @@ nsresult ContentEventHandler::OnQueryTex
     return NS_ERROR_FAILURE;
   }
 
   // iterate over all covered frames
   for (nsIFrame* frame = firstFrame; frame != lastFrame;) {
     frame = frame->GetNextContinuation();
     if (!frame) {
       do {
-        postOrderIter->Next();
-        nsINode* node = postOrderIter->GetCurrentNode();
+        postOrderIter.Next();
+        nsINode* node = postOrderIter.GetCurrentNode();
         if (!node) {
           break;
         }
         if (!node->IsContent()) {
           continue;
         }
         nsIFrame* primaryFrame = node->AsContent()->GetPrimaryFrame();
         // The node may be hidden by CSS.
@@ -2314,17 +2314,17 @@ nsresult ContentEventHandler::OnQueryTex
         // We should take only text frame's rect and br frame's rect.  We can
         // always use frame rect of text frame and GetLineBreakerRectBefore()
         // can return exactly correct rect only for <br> frame for now.  On the
         // other hand, GetLineBreakRectBefore() returns guessed caret rect for
         // the other frames.  We shouldn't include such odd rect to the result.
         if (primaryFrame->IsTextFrame() || primaryFrame->IsBrFrame()) {
           frame = primaryFrame;
         }
-      } while (!frame && !postOrderIter->IsDone());
+      } while (!frame && !postOrderIter.IsDone());
       if (!frame) {
         break;
       }
     }
     if (frame->IsTextFrame()) {
       frameRect.SetRect(nsPoint(0, 0), frame->GetRect().Size());
     } else {
       MOZ_ASSERT(frame->IsBrFrame());
@@ -2653,19 +2653,17 @@ nsresult ContentEventHandler::OnQueryDOM
     return NS_ERROR_INVALID_ARG;
   }
 
   if (aStartPosition == aEndPosition) {
     *aLength = 0;
     return NS_OK;
   }
 
-  // Don't create ContentIterator instance until it's really necessary since
-  // destroying without initializing causes unexpected NS_ASSERTION() call.
-  RefPtr<PreContentIterator> preOrderIter;
+  PreContentIterator preOrderIter;
 
   // Working with ContentIterator, we may need to adjust the end position for
   // including it forcibly.
   NodePosition endPosition(aEndPosition);
 
   // This may be called for retrieving the text of removed nodes.  Even in this
   // case, the node thinks it's still in the tree because UnbindFromTree() will
   // be called after here.  However, the node was already removed from the
@@ -2679,18 +2677,17 @@ nsresult ContentEventHandler::OnQueryDOM
     MOZ_ASSERT(aStartPosition.Container() == endPosition.Container(),
                "At removing the node, start and end node should be same");
     MOZ_ASSERT(aStartPosition.Offset() == 0,
                "When the node is being removed, the start offset should be 0");
     MOZ_ASSERT(
         static_cast<uint32_t>(endPosition.Offset()) ==
             endPosition.Container()->GetChildCount(),
         "When the node is being removed, the end offset should be child count");
-    preOrderIter = new PreContentIterator();
-    nsresult rv = preOrderIter->Init(aStartPosition.Container());
+    nsresult rv = preOrderIter.Init(aStartPosition.Container());
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   } else {
     RawRange prevRawRange;
     nsresult rv = prevRawRange.SetStart(aStartPosition.AsRaw());
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
@@ -2724,47 +2721,44 @@ nsresult ContentEventHandler::OnQueryDOM
     }
 
     if (endPosition.IsSetAndValid()) {
       // Offset is within node's length; set end of range to that offset
       rv = prevRawRange.SetEnd(endPosition.AsRaw());
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
-      preOrderIter = new PreContentIterator();
-      rv = preOrderIter->Init(prevRawRange.Start().AsRaw(),
-                              prevRawRange.End().AsRaw());
+      rv = preOrderIter.Init(prevRawRange.Start().AsRaw(),
+                             prevRawRange.End().AsRaw());
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
     } else if (endPosition.Container() != aRootContent) {
       // Offset is past node's length; set end of range to end of node
       rv = prevRawRange.SetEndAfter(endPosition.Container());
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
-      preOrderIter = new PreContentIterator();
-      rv = preOrderIter->Init(prevRawRange.Start().AsRaw(),
-                              prevRawRange.End().AsRaw());
+      rv = preOrderIter.Init(prevRawRange.Start().AsRaw(),
+                             prevRawRange.End().AsRaw());
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
     } else {
       // Offset is past the root node; set end of range to end of root node
-      preOrderIter = new PreContentIterator();
-      rv = preOrderIter->Init(aRootContent);
+      rv = preOrderIter.Init(aRootContent);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
     }
   }
 
   *aLength = 0;
-  for (; !preOrderIter->IsDone(); preOrderIter->Next()) {
-    nsINode* node = preOrderIter->GetCurrentNode();
+  for (; !preOrderIter.IsDone(); preOrderIter.Next()) {
+    nsINode* node = preOrderIter.GetCurrentNode();
     if (NS_WARN_IF(!node)) {
       break;
     }
     if (!node->IsContent()) {
       continue;
     }
     nsIContent* content = node->AsContent();
 
--- a/editor/libeditor/DeleteRangeTransaction.cpp
+++ b/editor/libeditor/DeleteRangeTransaction.cpp
@@ -209,36 +209,35 @@ nsresult DeleteRangeTransaction::CreateT
 }
 
 nsresult DeleteRangeTransaction::CreateTxnsToDeleteNodesBetween(
     nsRange* aRangeToDelete) {
   if (NS_WARN_IF(!mEditorBase)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  RefPtr<ContentSubtreeIterator> subtreeIter = new ContentSubtreeIterator();
-
-  nsresult rv = subtreeIter->Init(aRangeToDelete);
+  ContentSubtreeIterator subtreeIter;
+  nsresult rv = subtreeIter.Init(aRangeToDelete);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  while (!subtreeIter->IsDone()) {
-    nsCOMPtr<nsINode> node = subtreeIter->GetCurrentNode();
+  while (!subtreeIter.IsDone()) {
+    nsCOMPtr<nsINode> node = subtreeIter.GetCurrentNode();
     if (NS_WARN_IF(!node)) {
       return NS_ERROR_NULL_POINTER;
     }
 
     RefPtr<DeleteNodeTransaction> deleteNodeTransaction =
         DeleteNodeTransaction::MaybeCreate(*mEditorBase, *node);
     // 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)) {
       return NS_ERROR_FAILURE;
     }
     AppendChild(deleteNodeTransaction);
 
-    subtreeIter->Next();
+    subtreeIter.Next();
   }
   return NS_OK;
 }
 
 }  // namespace mozilla
--- a/editor/libeditor/EditorUtils.cpp
+++ b/editor/libeditor/EditorUtils.cpp
@@ -23,59 +23,55 @@ class nsRange;
 namespace mozilla {
 
 using namespace dom;
 
 /******************************************************************************
  * some helper classes for iterating the dom tree
  *****************************************************************************/
 
-DOMIterator::DOMIterator(
-    nsINode& aNode MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) {
+DOMIterator::DOMIterator(nsINode& aNode MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
+    : mIter(&mPostOrderIter) {
   MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-  mIter = new PostContentIterator();
   DebugOnly<nsresult> rv = mIter->Init(&aNode);
   MOZ_ASSERT(NS_SUCCEEDED(rv));
 }
 
 nsresult DOMIterator::Init(nsRange& aRange) {
-  mIter = new PostContentIterator();
   return mIter->Init(&aRange);
 }
 
-DOMIterator::DOMIterator(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL) {
+DOMIterator::DOMIterator(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
+    : mIter(&mPostOrderIter) {
   MOZ_GUARD_OBJECT_NOTIFIER_INIT;
 }
 
-DOMIterator::~DOMIterator() {}
-
 void DOMIterator::AppendList(
     const BoolDomIterFunctor& functor,
     nsTArray<OwningNonNull<nsINode>>& arrayOfNodes) const {
   // Iterate through dom and build list
   for (; !mIter->IsDone(); mIter->Next()) {
     nsCOMPtr<nsINode> node = mIter->GetCurrentNode();
 
     if (functor(node)) {
       arrayOfNodes.AppendElement(*node);
     }
   }
 }
 
 DOMSubtreeIterator::DOMSubtreeIterator(
     MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
-    : DOMIterator(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT) {}
+    : DOMIterator(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT) {
+  mIter = &mSubtreeIter;
+}
 
 nsresult DOMSubtreeIterator::Init(nsRange& aRange) {
-  mIter = new ContentSubtreeIterator();
   return mIter->Init(&aRange);
 }
 
-DOMSubtreeIterator::~DOMSubtreeIterator() {}
-
 /******************************************************************************
  * some general purpose editor utils
  *****************************************************************************/
 
 bool EditorUtils::IsDescendantOf(const nsINode& aNode, const nsINode& aParent,
                                  EditorRawDOMPoint* aOutPoint /* = nullptr */) {
   if (aOutPoint) {
     aOutPoint->Clear();
--- a/editor/libeditor/EditorUtils.h
+++ b/editor/libeditor/EditorUtils.h
@@ -445,35 +445,41 @@ class BoolDomIterFunctor {
   virtual bool operator()(nsINode* aNode) const = 0;
 };
 
 class MOZ_RAII DOMIterator {
  public:
   explicit DOMIterator(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
 
   explicit DOMIterator(nsINode& aNode MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
-  virtual ~DOMIterator();
+  virtual ~DOMIterator() = default;
 
   nsresult Init(nsRange& aRange);
 
   void AppendList(
       const BoolDomIterFunctor& functor,
       nsTArray<mozilla::OwningNonNull<nsINode>>& arrayOfNodes) const;
 
  protected:
-  RefPtr<ContentIteratorBase> mIter;
+  ContentIteratorBase* mIter;
+  PostContentIterator mPostOrderIter;
   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 class MOZ_RAII DOMSubtreeIterator final : public DOMIterator {
  public:
   explicit DOMSubtreeIterator(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
-  virtual ~DOMSubtreeIterator();
+  virtual ~DOMSubtreeIterator() = default;
 
   nsresult Init(nsRange& aRange);
+
+ private:
+  ContentSubtreeIterator mSubtreeIter;
+  explicit DOMSubtreeIterator(nsINode& aNode MOZ_GUARD_OBJECT_NOTIFIER_PARAM) =
+      delete;
 };
 
 class TrivialFunctor final : public BoolDomIterFunctor {
  public:
   // Used to build list of all nodes iterator covers
   virtual bool operator()(nsINode* aNode) const override { return true; }
 };
 
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -9432,30 +9432,28 @@ nsresult HTMLEditRules::RemoveEmptyNodes
   // the skiplist as being empty (without even doing the IsEmptyNode check) on
   // the theory that if they weren't empty, we would have encountered a
   // non-empty child earlier and thus put this parent node on the skiplist.
   //
   // Unfortunately I can't use that strategy here, because the range may
   // include some children of a node while excluding others.  Thus I could find
   // all the _examined_ children empty, but still not have an empty parent.
 
-  // need an iterator
-  RefPtr<PostContentIterator> postOrderIter = new PostContentIterator();
-
-  nsresult rv = postOrderIter->Init(mDocChangeRange);
+  PostContentIterator postOrderIter;
+  nsresult rv = postOrderIter.Init(mDocChangeRange);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   nsTArray<OwningNonNull<nsINode>> arrayOfEmptyNodes, arrayOfEmptyCites,
       skipList;
 
   // Check for empty nodes
-  for (; !postOrderIter->IsDone(); postOrderIter->Next()) {
-    OwningNonNull<nsINode> node = *postOrderIter->GetCurrentNode();
+  for (; !postOrderIter.IsDone(); postOrderIter.Next()) {
+    OwningNonNull<nsINode> node = *postOrderIter.GetCurrentNode();
 
     nsCOMPtr<nsINode> parent = node->GetParentNode();
 
     size_t idx = skipList.IndexOf(node);
     if (idx != skipList.NoIndex) {
       // This node is on our skip list.  Skip processing for this node, and
       // replace its value in the skip list with the value of its parent
       if (parent) {
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -1119,44 +1119,44 @@ nsresult HTMLEditor::TabInTable(bool inI
   // find enclosing table
   RefPtr<Element> table = GetEnclosingTable(cellElement);
   if (NS_WARN_IF(!table)) {
     return NS_OK;
   }
 
   // advance to next cell
   // first create an iterator over the table
-  RefPtr<PostContentIterator> postOrderIter = new PostContentIterator();
-  nsresult rv = postOrderIter->Init(table);
+  PostContentIterator postOrderIter;
+  nsresult rv = postOrderIter.Init(table);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
   // position postOrderIter at block
-  rv = postOrderIter->PositionAt(cellElement);
+  rv = postOrderIter.PositionAt(cellElement);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   nsCOMPtr<nsINode> node;
   do {
     if (inIsShift) {
-      postOrderIter->Prev();
+      postOrderIter.Prev();
     } else {
-      postOrderIter->Next();
+      postOrderIter.Next();
     }
 
-    node = postOrderIter->GetCurrentNode();
+    node = postOrderIter.GetCurrentNode();
 
     if (node && HTMLEditUtils::IsTableCell(node) &&
         GetEnclosingTable(node) == table) {
       CollapseSelectionToDeepestNonTableFirstChild(node);
       *outHandled = true;
       return NS_OK;
     }
-  } while (!postOrderIter->IsDone());
+  } while (!postOrderIter.IsDone());
 
   if (!(*outHandled) && !inIsShift) {
     // If we haven't handled it yet, then we must have run off the end of the
     // table.  Insert a new row.
     // XXX We should investigate whether this behavior is supported by other
     //     browsers later.
     AutoEditActionDataSetter editActionData(*this,
                                             EditAction::eInsertTableRowElement);
@@ -2781,22 +2781,22 @@ already_AddRefed<Element> HTMLEditor::Ge
       }
     }
   }
 
   if (SelectionRefPtr()->IsCollapsed()) {
     return nullptr;
   }
 
-  RefPtr<PostContentIterator> postOrderIter = new PostContentIterator();
-  postOrderIter->Init(firstRange);
+  PostContentIterator postOrderIter;
+  postOrderIter.Init(firstRange);
 
   RefPtr<Element> lastElementInRange;
-  for (nsINode* lastNodeInRange = nullptr; !postOrderIter->IsDone();
-       postOrderIter->Next()) {
+  for (nsINode* lastNodeInRange = nullptr; !postOrderIter.IsDone();
+       postOrderIter.Next()) {
     if (lastElementInRange) {
       // When any node follows an element node, not only one element is
       // selected so that return nullptr.
       return nullptr;
     }
 
     // This loop ignored any non-element nodes before first element node.
     // Its purpose must be that this method allow to this case as selecting
@@ -2804,17 +2804,17 @@ already_AddRefed<Element> HTMLEditor::Ge
     // - <p>abc <b>d[ef</b>}</p>
     // because children of an element node is listed up before the element.
     // However, this case must not be expected by the initial developer:
     // - <p>a[bc <b>def</b>}</p>
     // When we meet non-parent and non-next-sibling node of previous node,
     // it means that the range across element boundary (open tag in HTML
     // source).  So, in this case, we should not say only the following
     // element is selected.
-    nsINode* currentNode = postOrderIter->GetCurrentNode();
+    nsINode* currentNode = postOrderIter.GetCurrentNode();
     MOZ_ASSERT(currentNode);
     if (lastNodeInRange && lastNodeInRange->GetParentNode() != currentNode &&
         lastNodeInRange->GetNextSibling() != currentNode) {
       return nullptr;
     }
 
     lastNodeInRange = currentNode;
 
@@ -3057,25 +3057,25 @@ HTMLEditor::GetLinkedObjects(nsIArray** 
   NS_ENSURE_TRUE(aNodeList, NS_ERROR_NULL_POINTER);
 
   nsresult rv;
   nsCOMPtr<nsIMutableArray> nodes = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
-  RefPtr<PostContentIterator> postOrderIter = new PostContentIterator();
   RefPtr<Document> doc = GetDocument();
   NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED);
 
-  postOrderIter->Init(doc->GetRootElement());
+  PostContentIterator postOrderIter;
+  postOrderIter.Init(doc->GetRootElement());
 
   // loop through the content iterator for each content node
-  for (; !postOrderIter->IsDone(); postOrderIter->Next()) {
-    nsCOMPtr<nsINode> node = postOrderIter->GetCurrentNode();
+  for (; !postOrderIter.IsDone(); postOrderIter.Next()) {
+    nsCOMPtr<nsINode> node = postOrderIter.GetCurrentNode();
     if (node) {
       // Let nsURIRefObject make the hard decisions:
       nsCOMPtr<nsIURIRefObject> refObject;
       rv = NS_NewHTMLURIRefObject(getter_AddRefs(refObject), node);
       if (NS_SUCCEEDED(rv)) {
         nodes->AppendElement(refObject);
       }
     }
@@ -3773,28 +3773,24 @@ nsresult HTMLEditor::CollapseAdjacentTex
   NS_ENSURE_TRUE(aInRange, NS_ERROR_NULL_POINTER);
   AutoTransactionsConserveSelection dontChangeMySelection(*this);
   nsTArray<nsCOMPtr<nsINode>> textNodes;
   // we can't actually do anything during iteration, so store the text nodes in
   // an array don't bother ref counting them because we know we can hold them
   // for the lifetime of this method
 
   // build a list of editable text nodes
-  RefPtr<ContentSubtreeIterator> subtreeIter = new ContentSubtreeIterator();
-
-  subtreeIter->Init(aInRange);
-
-  while (!subtreeIter->IsDone()) {
-    nsINode* node = subtreeIter->GetCurrentNode();
+  ContentSubtreeIterator subtreeIter;
+  subtreeIter.Init(aInRange);
+  for (; !subtreeIter.IsDone(); subtreeIter.Next()) {
+    nsINode* node = subtreeIter.GetCurrentNode();
     if (node->NodeType() == nsINode::TEXT_NODE &&
         IsEditable(node->AsContent())) {
       textNodes.AppendElement(node);
     }
-
-    subtreeIter->Next();
   }
 
   // now that I have a list of text nodes, collapse adjacent text nodes
   // NOTE: assumption that JoinNodes keeps the righthand node
   while (textNodes.Length() > 1) {
     // we assume a textNodes entry can't be nullptr
     nsINode* leftTextNode = textNodes[0];
     nsINode* rightTextNode = textNodes[1];
@@ -4435,30 +4431,28 @@ nsresult HTMLEditor::SetCSSBackgroundCol
         // starting textnode and an ending textnode which are only partially
         // contained by the range.
 
         // Let's handle the nodes reported by the iterator.  These nodes are
         // entirely contained in the selection range.  We build up a list of
         // them (since doing operations on the document during iteration would
         // perturb the iterator).
 
-        RefPtr<ContentSubtreeIterator> subtreeIter =
-            new ContentSubtreeIterator();
-
         nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
         nsCOMPtr<nsINode> node;
 
         // Iterate range and build up array
-        rv = subtreeIter->Init(range);
+        ContentSubtreeIterator subtreeIter;
+        rv = subtreeIter.Init(range);
         // Init returns an error if no nodes in range.  This can easily happen
         // with the subtree iterator if the selection doesn't contain any
         // *whole* nodes.
         if (NS_SUCCEEDED(rv)) {
-          for (; !subtreeIter->IsDone(); subtreeIter->Next()) {
-            node = subtreeIter->GetCurrentNode();
+          for (; !subtreeIter.IsDone(); subtreeIter.Next()) {
+            node = subtreeIter.GetCurrentNode();
             NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
 
             if (IsEditable(node)) {
               arrayOfNodes.AppendElement(*node);
             }
           }
         }
         // First check the start parent of the range to see if it needs to be
--- a/editor/libeditor/HTMLStyleEditor.cpp
+++ b/editor/libeditor/HTMLStyleEditor.cpp
@@ -170,28 +170,27 @@ nsresult HTMLEditor::SetInlinePropertyIn
       // starting textnode and an ending textnode which are only partially
       // contained by the range.
 
       // Let's handle the nodes reported by the iterator.  These nodes are
       // entirely contained in the selection range.  We build up a list of them
       // (since doing operations on the document during iteration would perturb
       // the iterator).
 
-      RefPtr<ContentSubtreeIterator> subtreeIter = new ContentSubtreeIterator();
-
       nsTArray<OwningNonNull<nsIContent>> arrayOfNodes;
 
       // Iterate range and build up array
-      rv = subtreeIter->Init(range);
+      ContentSubtreeIterator subtreeIter;
+      rv = subtreeIter.Init(range);
       // Init returns an error if there are no nodes in range.  This can easily
       // happen with the subtree iterator if the selection doesn't contain any
       // *whole* nodes.
       if (NS_SUCCEEDED(rv)) {
-        for (; !subtreeIter->IsDone(); subtreeIter->Next()) {
-          OwningNonNull<nsINode> node = *subtreeIter->GetCurrentNode();
+        for (; !subtreeIter.IsDone(); subtreeIter.Next()) {
+          OwningNonNull<nsINode> node = *subtreeIter.GetCurrentNode();
 
           if (node->IsContent() && IsEditable(node)) {
             arrayOfNodes.AppendElement(*node->AsContent());
           }
         }
       }
       // First check the start parent of the range to see if it needs to be
       // separately handled (it does if it's a text node, due to how the
@@ -1036,30 +1035,32 @@ nsresult HTMLEditor::GetInlinePropertyBa
 
       isSet = IsTextPropertySetByContent(collapsedNode, &aProperty, aAttribute,
                                          aValue, outValue);
       *aFirst = *aAny = *aAll = isSet;
       return NS_OK;
     }
 
     // Non-collapsed selection
-    RefPtr<PostContentIterator> postOrderIter = new PostContentIterator();
 
     nsAutoString firstValue, theValue;
 
     nsCOMPtr<nsINode> endNode = range->GetEndContainer();
     int32_t endOffset = range->EndOffset();
 
-    for (postOrderIter->Init(range); !postOrderIter->IsDone();
-         postOrderIter->Next()) {
-      if (!postOrderIter->GetCurrentNode()->IsContent()) {
+    PostContentIterator postOrderIter;
+    DebugOnly<nsresult> rvIgnored = postOrderIter.Init(range);
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
+                         "Failed to initialize post-order content iterator");
+    for (; !postOrderIter.IsDone(); postOrderIter.Next()) {
+      if (!postOrderIter.GetCurrentNode()->IsContent()) {
         continue;
       }
       nsCOMPtr<nsIContent> content =
-          postOrderIter->GetCurrentNode()->AsContent();
+          postOrderIter.GetCurrentNode()->AsContent();
 
       if (content->IsHTMLElement(nsGkAtoms::body)) {
         break;
       }
 
       // just ignore any non-editable nodes
       if (content->GetAsText() &&
           (!IsEditable(content) || IsEmptyTextNode(*content))) {
@@ -1338,25 +1339,26 @@ nsresult HTMLEditor::RemoveInlinePropert
               SetInlinePropertyOnTextNode(
                   *startNode->GetAsText(), range->StartOffset(),
                   range->EndOffset(), *aProperty, aAttribute, value);
             }
           }
         }
       } else {
         // Not the easy case.  Range not contained in single text node.
-        RefPtr<ContentSubtreeIterator> subtreeIter =
-            new ContentSubtreeIterator();
 
         nsTArray<OwningNonNull<nsIContent>> arrayOfNodes;
 
         // Iterate range and build up array
-        for (subtreeIter->Init(range); !subtreeIter->IsDone();
-             subtreeIter->Next()) {
-          nsCOMPtr<nsINode> node = subtreeIter->GetCurrentNode();
+        ContentSubtreeIterator subtreeIter;
+        DebugOnly<nsresult> rvIgnored = subtreeIter.Init(range);
+        NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
+                             "Failed to initialize subtree iterator");
+        for (; !subtreeIter.IsDone(); subtreeIter.Next()) {
+          nsCOMPtr<nsINode> node = subtreeIter.GetCurrentNode();
           if (NS_WARN_IF(!node)) {
             return NS_ERROR_FAILURE;
           }
           if (IsEditable(node) && node->IsContent()) {
             arrayOfNodes.AppendElement(*node->AsContent());
           }
         }
 
@@ -1487,28 +1489,27 @@ nsresult HTMLEditor::RelativeFontChange(
       // starting textnode and an ending textnode which are only partially
       // contained by the range.
 
       // Let's handle the nodes reported by the iterator.  These nodes are
       // entirely contained in the selection range.  We build up a list of them
       // (since doing operations on the document during iteration would perturb
       // the iterator).
 
-      RefPtr<ContentSubtreeIterator> subtreeIter = new ContentSubtreeIterator();
-
       // Iterate range and build up array
-      rv = subtreeIter->Init(range);
+      ContentSubtreeIterator subtreeIter;
+      rv = subtreeIter.Init(range);
       if (NS_SUCCEEDED(rv)) {
         nsTArray<OwningNonNull<nsIContent>> arrayOfNodes;
-        for (; !subtreeIter->IsDone(); subtreeIter->Next()) {
-          if (NS_WARN_IF(!subtreeIter->GetCurrentNode()->IsContent())) {
+        for (; !subtreeIter.IsDone(); subtreeIter.Next()) {
+          if (NS_WARN_IF(!subtreeIter.GetCurrentNode()->IsContent())) {
             return NS_ERROR_FAILURE;
           }
           OwningNonNull<nsIContent> node =
-              *subtreeIter->GetCurrentNode()->AsContent();
+              *subtreeIter.GetCurrentNode()->AsContent();
 
           if (IsEditable(node)) {
             arrayOfNodes.AppendElement(node);
           }
         }
 
         // Now that we have the list, do the font size change on each node
         for (auto& node : arrayOfNodes) {
--- a/editor/libeditor/TextEditor.cpp
+++ b/editor/libeditor/TextEditor.cpp
@@ -1450,22 +1450,21 @@ TextEditor::GetTextLength(int32_t* aCoun
     return NS_OK;
   }
 
   Element* rootElement = GetRoot();
   if (NS_WARN_IF(!rootElement)) {
     return NS_ERROR_FAILURE;
   }
 
-  RefPtr<PostContentIterator> postOrderIter = new PostContentIterator();
-
   uint32_t totalLength = 0;
-  postOrderIter->Init(rootElement);
-  for (; !postOrderIter->IsDone(); postOrderIter->Next()) {
-    nsCOMPtr<nsINode> currentNode = postOrderIter->GetCurrentNode();
+  PostContentIterator postOrderIter;
+  postOrderIter.Init(rootElement);
+  for (; !postOrderIter.IsDone(); postOrderIter.Next()) {
+    nsCOMPtr<nsINode> currentNode = postOrderIter.GetCurrentNode();
     if (IsTextNode(currentNode) && IsEditable(currentNode)) {
       totalLength += currentNode->Length();
     }
   }
 
   *aCount = totalLength;
   return NS_OK;
 }
--- a/editor/spellchecker/FilteredContentIterator.cpp
+++ b/editor/spellchecker/FilteredContentIterator.cpp
@@ -20,45 +20,42 @@
 #include "nsISupportsBase.h"
 #include "nsISupportsUtils.h"
 #include "nsRange.h"
 
 namespace mozilla {
 
 FilteredContentIterator::FilteredContentIterator(
     UniquePtr<nsComposeTxtSrvFilter> aFilter)
-    : mPostIterator(new PostContentIterator()),
-      mPreIterator(new PreContentIterator()),
+    : mCurrentIterator(nullptr),
       mFilter(std::move(aFilter)),
       mDidSkip(false),
       mIsOutOfRange(false),
       mDirection(eDirNotSet) {}
 
 FilteredContentIterator::~FilteredContentIterator() {}
 
-NS_IMPL_CYCLE_COLLECTION(FilteredContentIterator, mCurrentIterator,
-                         mPostIterator, mPreIterator, mRange)
+NS_IMPL_CYCLE_COLLECTION(FilteredContentIterator, mPostIterator, mPreIterator,
+                         mRange)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(FilteredContentIterator, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(FilteredContentIterator, Release)
 
 nsresult FilteredContentIterator::Init(nsINode* aRoot) {
   NS_ENSURE_ARG_POINTER(aRoot);
-  NS_ENSURE_TRUE(mPreIterator, NS_ERROR_FAILURE);
-  NS_ENSURE_TRUE(mPostIterator, NS_ERROR_FAILURE);
   mIsOutOfRange = false;
   mDirection = eForward;
-  mCurrentIterator = mPreIterator;
+  mCurrentIterator = &mPreIterator;
 
   mRange = new nsRange(aRoot);
   mRange->SelectNode(*aRoot, IgnoreErrors());
 
-  nsresult rv = mPreIterator->Init(mRange);
+  nsresult rv = mPreIterator.Init(mRange);
   NS_ENSURE_SUCCESS(rv, rv);
-  return mPostIterator->Init(mRange);
+  return mPostIterator.Init(mRange);
 }
 
 nsresult FilteredContentIterator::Init(nsRange* aRange) {
   if (NS_WARN_IF(!aRange)) {
     return NS_ERROR_INVALID_ARG;
   }
 
   if (NS_WARN_IF(!aRange->IsPositioned())) {
@@ -94,39 +91,35 @@ nsresult FilteredContentIterator::Init(c
 
   return InitWithRange();
 }
 
 nsresult FilteredContentIterator::InitWithRange() {
   MOZ_ASSERT(mRange);
   MOZ_ASSERT(mRange->IsPositioned());
 
-  if (NS_WARN_IF(!mPreIterator) || NS_WARN_IF(!mPostIterator)) {
-    return NS_ERROR_FAILURE;
-  }
-
   mIsOutOfRange = false;
   mDirection = eForward;
-  mCurrentIterator = mPreIterator;
+  mCurrentIterator = &mPreIterator;
 
-  nsresult rv = mPreIterator->Init(mRange);
+  nsresult rv = mPreIterator.Init(mRange);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
-  return mPostIterator->Init(mRange);
+  return mPostIterator.Init(mRange);
 }
 
 nsresult FilteredContentIterator::SwitchDirections(bool aChangeToForward) {
   nsINode* node = mCurrentIterator->GetCurrentNode();
 
   if (aChangeToForward) {
-    mCurrentIterator = mPreIterator;
+    mCurrentIterator = &mPreIterator;
     mDirection = eForward;
   } else {
-    mCurrentIterator = mPostIterator;
+    mCurrentIterator = &mPostIterator;
     mDirection = eBackward;
   }
 
   if (node) {
     nsresult rv = mCurrentIterator->PositionAt(node);
     if (NS_FAILED(rv)) {
       mIsOutOfRange = true;
       return rv;
@@ -140,17 +133,17 @@ void FilteredContentIterator::First() {
     NS_ERROR("Missing iterator!");
 
     return;
   }
 
   // If we are switching directions then
   // we need to switch how we process the nodes
   if (mDirection != eForward) {
-    mCurrentIterator = mPreIterator;
+    mCurrentIterator = &mPreIterator;
     mDirection = eForward;
     mIsOutOfRange = false;
   }
 
   mCurrentIterator->First();
 
   if (mCurrentIterator->IsDone()) {
     return;
@@ -167,17 +160,17 @@ void FilteredContentIterator::Last() {
     NS_ERROR("Missing iterator!");
 
     return;
   }
 
   // If we are switching directions then
   // we need to switch how we process the nodes
   if (mDirection != eBackward) {
-    mCurrentIterator = mPostIterator;
+    mCurrentIterator = &mPostIterator;
     mDirection = eBackward;
     mIsOutOfRange = false;
   }
 
   mCurrentIterator->Last();
 
   if (mCurrentIterator->IsDone()) {
     return;
--- a/editor/spellchecker/FilteredContentIterator.h
+++ b/editor/spellchecker/FilteredContentIterator.h
@@ -56,19 +56,19 @@ class FilteredContentIterator final {
   nsresult InitWithRange();
 
   // enum to give us the direction
   typedef enum { eDirNotSet, eForward, eBackward } eDirectionType;
   nsresult AdvanceNode(nsINode* aNode, nsINode*& aNewNode, eDirectionType aDir);
   void CheckAdvNode(nsINode* aNode, bool& aDidSkip, eDirectionType aDir);
   nsresult SwitchDirections(bool aChangeToForward);
 
-  RefPtr<ContentIteratorBase> mCurrentIterator;
-  RefPtr<PostContentIterator> mPostIterator;
-  RefPtr<PreContentIterator> mPreIterator;
+  ContentIteratorBase* MOZ_NON_OWNING_REF mCurrentIterator;
+  PostContentIterator mPostIterator;
+  PreContentIterator mPreIterator;
 
   RefPtr<nsAtom> mBlockQuoteAtom;
   RefPtr<nsAtom> mScriptAtom;
   RefPtr<nsAtom> mTextAreaAtom;
   RefPtr<nsAtom> mSelectAreaAtom;
   RefPtr<nsAtom> mMapAtom;
 
   UniquePtr<nsComposeTxtSrvFilter> mFilter;
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -4659,18 +4659,18 @@ UniquePtr<RangePaintInfo> PresShell::Cre
   // get a display list containing the range
   auto info = MakeUnique<RangePaintInfo>(aRange, ancestorFrame);
   info->mBuilder.SetIncludeAllOutOfFlows();
   if (aForPrimarySelection) {
     info->mBuilder.SetSelectedFramesOnly();
   }
   info->mBuilder.EnterPresShell(ancestorFrame);
 
-  RefPtr<ContentSubtreeIterator> subtreeIter = new ContentSubtreeIterator();
-  nsresult rv = subtreeIter->Init(aRange);
+  ContentSubtreeIterator subtreeIter;
+  nsresult rv = subtreeIter.Init(aRange);
   if (NS_FAILED(rv)) {
     return nullptr;
   }
 
   auto BuildDisplayListForNode = [&](nsINode* aNode) {
     if (MOZ_UNLIKELY(!aNode->IsContent())) {
       return;
     }
@@ -4681,18 +4681,18 @@ UniquePtr<RangePaintInfo> PresShell::Cre
       info->mBuilder.SetVisibleRect(frame->GetVisualOverflowRect());
       info->mBuilder.SetDirtyRect(frame->GetVisualOverflowRect());
       frame->BuildDisplayListForStackingContext(&info->mBuilder, &info->mList);
     }
   };
   if (startContainer->NodeType() == nsINode::TEXT_NODE) {
     BuildDisplayListForNode(startContainer);
   }
-  for (; !subtreeIter->IsDone(); subtreeIter->Next()) {
-    nsCOMPtr<nsINode> node = subtreeIter->GetCurrentNode();
+  for (; !subtreeIter.IsDone(); subtreeIter.Next()) {
+    nsCOMPtr<nsINode> node = subtreeIter.GetCurrentNode();
     BuildDisplayListForNode(node);
   }
   if (endContainer != startContainer &&
       endContainer->NodeType() == nsINode::TEXT_NODE) {
     BuildDisplayListForNode(endContainer);
   }
 
 #ifdef DEBUG