Backed out 8 changesets (bug 181137) for bustage on FragmentOrElement.cpp:1751. CLOSED TREE
authorCsoregi Natalia <ncsoregi@mozilla.com>
Thu, 10 Jan 2019 11:42:27 +0200
changeset 453222 5562d6967f3d6a7d4a5f9a16e7a492452163ff14
parent 453221 3bd1a8ffe4a900c980f82ae6c868e31ab20e933b
child 453223 f65f0c93a581bad32c5afb454f19596f701083f5
push id35349
push userbtara@mozilla.com
push dateThu, 10 Jan 2019 17:19:27 +0000
treeherdermozilla-central@a51746f37520 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs181137
milestone66.0a1
backs out99a977d519a0b78e267d3dce4afb009b8d3be769
65a4b245e8514a5a9d5c9a101c09919f27a3680a
5385d5fd9b8bfaaec01f9757305f3a5cb0eb9e4e
83bec02c21d965b6cd5eb0fc682a18ef6ac74b68
b7ab59bf545e46eb2e677eaf1f68adc100cbebae
b6fc7a332db7a7a3e3fe89f311b3c44e49145ad6
654fdbad67db2de8a0eca4b0a2d6326d743cc127
90a1ff49b6b1463090cb19cbc54a85f152f2488f
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
Backed out 8 changesets (bug 181137) for bustage on FragmentOrElement.cpp:1751. CLOSED TREE Backed out changeset 99a977d519a0 (bug 181137) Backed out changeset 65a4b245e851 (bug 181137) Backed out changeset 5385d5fd9b8b (bug 181137) Backed out changeset 83bec02c21d9 (bug 181137) Backed out changeset b7ab59bf545e (bug 181137) Backed out changeset b6fc7a332db7 (bug 181137) Backed out changeset 654fdbad67db (bug 181137) Backed out changeset 90a1ff49b6b1 (bug 181137)
dom/base/ContentIterator.cpp
dom/base/ContentIterator.h
dom/base/Element.cpp
dom/base/FragmentOrElement.cpp
dom/base/ScriptableContentIterator.cpp
dom/base/ScriptableContentIterator.h
dom/base/Selection.cpp
dom/base/Selection.h
dom/base/moz.build
dom/base/nsContentCID.h
dom/base/nsContentIterator.cpp
dom/base/nsContentList.cpp
dom/base/nsDOMWindowUtils.cpp
dom/base/nsIContentIterator.h
dom/base/nsINode.cpp
dom/base/nsIScriptableContentIterator.idl
dom/base/nsRange.cpp
dom/base/test/test_bug976673.html
dom/base/test/test_content_iterator_subtree.html
dom/events/ContentEventHandler.cpp
dom/events/IMEContentObserver.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
editor/spellchecker/TextServicesDocument.cpp
editor/spellchecker/TextServicesDocument.h
editor/spellchecker/moz.build
editor/spellchecker/nsFilteredContentIterator.cpp
editor/spellchecker/nsFilteredContentIterator.h
layout/base/PresShell.cpp
layout/generic/nsFrameSelection.cpp
toolkit/components/find/nsFind.cpp
toolkit/components/find/nsFind.h
deleted file mode 100644
--- a/dom/base/ContentIterator.cpp
+++ /dev/null
@@ -1,934 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * 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/. */
-
-#include "ContentIterator.h"
-
-#include "mozilla/DebugOnly.h"
-#include "mozilla/RangeBoundary.h"
-
-#include "nsContentUtils.h"
-#include "nsElementTable.h"
-#include "nsIContent.h"
-#include "nsRange.h"
-
-namespace mozilla {
-
-///////////////////////////////////////////////////////////////////////////
-// NodeIsInTraversalRange: returns true if content is visited during
-// the traversal of the range in the specified mode.
-//
-static bool NodeIsInTraversalRange(nsINode* aNode, bool aIsPreMode,
-                                   const RawRangeBoundary& aStart,
-                                   const RawRangeBoundary& aEnd) {
-  if (NS_WARN_IF(!aStart.IsSet()) || NS_WARN_IF(!aEnd.IsSet()) ||
-      NS_WARN_IF(!aNode)) {
-    return false;
-  }
-
-  // If a leaf node contains an end point of the traversal range, it is
-  // always in the traversal range.
-  if (aNode == aStart.Container() || aNode == aEnd.Container()) {
-    if (aNode->IsCharacterData()) {
-      return true;  // text node or something
-    }
-    if (!aNode->HasChildren()) {
-      MOZ_ASSERT(
-          aNode != aStart.Container() || aStart.IsStartOfContainer(),
-          "aStart.Container() doesn't have children and not a data node, "
-          "aStart should be at the beginning of its container");
-      MOZ_ASSERT(aNode != aEnd.Container() || aEnd.IsStartOfContainer(),
-                 "aEnd.Container() doesn't have children and not a data node, "
-                 "aEnd should be at the beginning of its container");
-      return true;
-    }
-  }
-
-  nsINode* parent = aNode->GetParentNode();
-  if (!parent) {
-    return false;
-  }
-
-  if (!aIsPreMode) {
-    // aNode should always be content, as we have a parent, but let's just be
-    // extra careful and check.
-    nsIContent* content =
-        NS_WARN_IF(!aNode->IsContent()) ? nullptr : aNode->AsContent();
-    // Post mode: start < node <= end.
-    RawRangeBoundary afterNode(parent, content);
-    return nsContentUtils::ComparePoints(aStart, afterNode) < 0 &&
-           nsContentUtils::ComparePoints(aEnd, afterNode) >= 0;
-  }
-
-  // Pre mode: start <= node < end.
-  RawRangeBoundary beforeNode(parent, aNode->GetPreviousSibling());
-  return nsContentUtils::ComparePoints(aStart, beforeNode) <= 0 &&
-         nsContentUtils::ComparePoints(aEnd, beforeNode) > 0;
-}
-
-ContentIteratorBase::ContentIteratorBase(bool aPre)
-    : mIsDone(false), mPre(aPre) {}
-
-/******************************************************
- * Init routines
- ******************************************************/
-
-nsresult ContentIteratorBase::Init(nsINode* aRoot) {
-  if (NS_WARN_IF(!aRoot)) {
-    return NS_ERROR_NULL_POINTER;
-  }
-
-  mIsDone = false;
-
-  if (mPre) {
-    mFirst = aRoot;
-    mLast = GetDeepLastChild(aRoot);
-    NS_WARNING_ASSERTION(mLast, "GetDeepLastChild returned null");
-  } else {
-    mFirst = GetDeepFirstChild(aRoot);
-    NS_WARNING_ASSERTION(mFirst, "GetDeepFirstChild returned null");
-    mLast = aRoot;
-  }
-
-  mCommonParent = aRoot;
-  mCurNode = mFirst;
-  return NS_OK;
-}
-
-nsresult ContentIteratorBase::Init(nsRange* aRange) {
-  mIsDone = false;
-
-  if (NS_WARN_IF(!aRange)) {
-    return NS_ERROR_INVALID_ARG;
-  }
-
-  if (NS_WARN_IF(!aRange->IsPositioned())) {
-    return NS_ERROR_INVALID_ARG;
-  }
-
-  return InitInternal(aRange->StartRef().AsRaw(), aRange->EndRef().AsRaw());
-}
-
-nsresult ContentIteratorBase::Init(nsINode* aStartContainer,
-                                   uint32_t aStartOffset,
-                                   nsINode* aEndContainer,
-                                   uint32_t aEndOffset) {
-  mIsDone = false;
-
-  if (NS_WARN_IF(!nsRange::IsValidPoints(aStartContainer, aStartOffset,
-                                         aEndContainer, aEndOffset))) {
-    return NS_ERROR_INVALID_ARG;
-  }
-
-  return InitInternal(RawRangeBoundary(aStartContainer, aStartOffset),
-                      RawRangeBoundary(aEndContainer, aEndOffset));
-}
-
-nsresult ContentIteratorBase::Init(const RawRangeBoundary& aStart,
-                                   const RawRangeBoundary& aEnd) {
-  mIsDone = false;
-
-  if (NS_WARN_IF(!nsRange::IsValidPoints(aStart.Container(), aStart.Offset(),
-                                         aEnd.Container(), aEnd.Offset()))) {
-    return NS_ERROR_INVALID_ARG;
-  }
-
-  return InitInternal(aStart, aEnd);
-}
-
-nsresult ContentIteratorBase::InitInternal(const RawRangeBoundary& aStart,
-                                           const RawRangeBoundary& aEnd) {
-  // get common content parent
-  mCommonParent =
-      nsContentUtils::GetCommonAncestor(aStart.Container(), aEnd.Container());
-  if (NS_WARN_IF(!mCommonParent)) {
-    return NS_ERROR_FAILURE;
-  }
-
-  bool startIsData = aStart.Container()->IsCharacterData();
-
-  // Check to see if we have a collapsed range, if so, there is nothing to
-  // iterate over.
-  //
-  // XXX: CharacterDataNodes (text nodes) are currently an exception, since
-  //      we always want to be able to iterate text nodes at the end points
-  //      of a range.
-
-  if (!startIsData && aStart == aEnd) {
-    MakeEmpty();
-    return NS_OK;
-  }
-
-  // Handle ranges within a single character data node.
-  if (startIsData && aStart.Container() == aEnd.Container()) {
-    mFirst = aStart.Container()->AsContent();
-    mLast = mFirst;
-    mCurNode = mFirst;
-
-    return NS_OK;
-  }
-
-  // Find first node in range.
-
-  nsIContent* cChild = nullptr;
-
-  // Try to get the child at our starting point. This might return null if
-  // aStart is immediately after the last node in aStart.Container().
-  if (!startIsData) {
-    cChild = aStart.GetChildAtOffset();
-  }
-
-  if (!cChild) {
-    // No children (possibly a <br> or text node), or index is after last child.
-
-    if (mPre) {
-      // XXX: In the future, if start offset is after the last
-      //      character in the cdata node, should we set mFirst to
-      //      the next sibling?
-
-      // Normally we would skip the start node because the start node is outside
-      // of the range in pre mode. However, if aStartOffset == 0, and the node
-      // is a non-container node (e.g. <br>), we don't skip the node in this
-      // case in order to address bug 1215798.
-      bool startIsContainer = true;
-      if (aStart.Container()->IsHTMLElement()) {
-        nsAtom* name = aStart.Container()->NodeInfo()->NameAtom();
-        startIsContainer =
-            nsHTMLElement::IsContainer(nsHTMLTags::AtomTagToId(name));
-      }
-      if (!startIsData && (startIsContainer || !aStart.IsStartOfContainer())) {
-        mFirst = GetNextSibling(aStart.Container());
-        NS_WARNING_ASSERTION(mFirst, "GetNextSibling returned null");
-
-        // Does mFirst node really intersect the range?  The range could be
-        // 'degenerate', i.e., not collapsed but still contain no content.
-        if (mFirst &&
-            NS_WARN_IF(!NodeIsInTraversalRange(mFirst, mPre, aStart, aEnd))) {
-          mFirst = nullptr;
-        }
-      } else {
-        mFirst = aStart.Container()->AsContent();
-      }
-    } else {
-      // post-order
-      if (NS_WARN_IF(!aStart.Container()->IsContent())) {
-        // What else can we do?
-        mFirst = nullptr;
-      } else {
-        mFirst = aStart.Container()->AsContent();
-      }
-    }
-  } else {
-    if (mPre) {
-      mFirst = cChild;
-    } else {
-      // post-order
-      mFirst = GetDeepFirstChild(cChild);
-      NS_WARNING_ASSERTION(mFirst, "GetDeepFirstChild returned null");
-
-      // Does mFirst node really intersect the range?  The range could be
-      // 'degenerate', i.e., not collapsed but still contain no content.
-
-      if (mFirst && !NodeIsInTraversalRange(mFirst, mPre, aStart, aEnd)) {
-        mFirst = nullptr;
-      }
-    }
-  }
-
-  // Find last node in range.
-
-  bool endIsData = aEnd.Container()->IsCharacterData();
-
-  if (endIsData || !aEnd.Container()->HasChildren() ||
-      aEnd.IsStartOfContainer()) {
-    if (mPre) {
-      if (NS_WARN_IF(!aEnd.Container()->IsContent())) {
-        // Not much else to do here...
-        mLast = nullptr;
-      } else {
-        // If the end node is a non-container element and the end offset is 0,
-        // the last element should be the previous node (i.e., shouldn't
-        // include the end node in the range).
-        bool endIsContainer = true;
-        if (aEnd.Container()->IsHTMLElement()) {
-          nsAtom* name = aEnd.Container()->NodeInfo()->NameAtom();
-          endIsContainer =
-              nsHTMLElement::IsContainer(nsHTMLTags::AtomTagToId(name));
-        }
-        if (!endIsData && !endIsContainer && aEnd.IsStartOfContainer()) {
-          mLast = PrevNode(aEnd.Container());
-          NS_WARNING_ASSERTION(mLast, "PrevNode returned null");
-          if (mLast && mLast != mFirst &&
-              NS_WARN_IF(!NodeIsInTraversalRange(
-                  mLast, mPre, RawRangeBoundary(mFirst, 0), aEnd))) {
-            mLast = nullptr;
-          }
-        } else {
-          mLast = aEnd.Container()->AsContent();
-        }
-      }
-    } else {
-      // post-order
-      //
-      // XXX: In the future, if end offset is before the first character in the
-      //      cdata node, should we set mLast to the prev sibling?
-
-      if (!endIsData) {
-        mLast = GetPrevSibling(aEnd.Container());
-        NS_WARNING_ASSERTION(mLast, "GetPrevSibling returned null");
-
-        if (!NodeIsInTraversalRange(mLast, mPre, aStart, aEnd)) {
-          mLast = nullptr;
-        }
-      } else {
-        mLast = aEnd.Container()->AsContent();
-      }
-    }
-  } else {
-    cChild = aEnd.Ref();
-
-    if (NS_WARN_IF(!cChild)) {
-      // No child at offset!
-      MOZ_ASSERT_UNREACHABLE("ContentIterator::ContentIterator");
-      return NS_ERROR_FAILURE;
-    }
-
-    if (mPre) {
-      mLast = GetDeepLastChild(cChild);
-      NS_WARNING_ASSERTION(mLast, "GetDeepLastChild returned null");
-
-      if (NS_WARN_IF(!NodeIsInTraversalRange(mLast, mPre, aStart, aEnd))) {
-        mLast = nullptr;
-      }
-    } else {
-      // post-order
-      mLast = cChild;
-    }
-  }
-
-  // If either first or last is null, they both have to be null!
-
-  if (!mFirst || !mLast) {
-    mFirst = nullptr;
-    mLast = nullptr;
-  }
-
-  mCurNode = mFirst;
-  mIsDone = !mCurNode;
-
-  return NS_OK;
-}
-
-void ContentIteratorBase::MakeEmpty() {
-  mCurNode = nullptr;
-  mFirst = nullptr;
-  mLast = nullptr;
-  mCommonParent = nullptr;
-  mIsDone = true;
-}
-
-nsINode* ContentIteratorBase::GetDeepFirstChild(nsINode* aRoot) {
-  if (NS_WARN_IF(!aRoot) || !aRoot->HasChildren()) {
-    return aRoot;
-  }
-
-  return GetDeepFirstChild(aRoot->GetFirstChild());
-}
-
-nsIContent* ContentIteratorBase::GetDeepFirstChild(nsIContent* aRoot) {
-  if (NS_WARN_IF(!aRoot)) {
-    return nullptr;
-  }
-
-  nsIContent* node = aRoot;
-  nsIContent* child = node->GetFirstChild();
-
-  while (child) {
-    node = child;
-    child = node->GetFirstChild();
-  }
-
-  return node;
-}
-
-nsINode* ContentIteratorBase::GetDeepLastChild(nsINode* aRoot) {
-  if (NS_WARN_IF(!aRoot) || !aRoot->HasChildren()) {
-    return aRoot;
-  }
-
-  return GetDeepLastChild(aRoot->GetLastChild());
-}
-
-nsIContent* ContentIteratorBase::GetDeepLastChild(nsIContent* aRoot) {
-  if (NS_WARN_IF(!aRoot)) {
-    return nullptr;
-  }
-
-  nsIContent* node = aRoot;
-  while (node->HasChildren()) {
-    nsIContent* child = node->GetLastChild();
-    node = child;
-  }
-  return node;
-}
-
-// Get the next sibling, or parent's next sibling, or grandpa's next sibling...
-nsIContent* ContentIteratorBase::GetNextSibling(nsINode* aNode) {
-  if (NS_WARN_IF(!aNode)) {
-    return nullptr;
-  }
-
-  if (aNode->GetNextSibling()) {
-    return aNode->GetNextSibling();
-  }
-
-  nsINode* parent = aNode->GetParentNode();
-  if (NS_WARN_IF(!parent)) {
-    return nullptr;
-  }
-
-  // XXX This is a hack to preserve previous behaviour: This should be fixed
-  // in bug 1404916. If we were positioned on anonymous content, move to
-  // the first child of our parent.
-  if (parent->GetLastChild() && parent->GetLastChild() != aNode) {
-    return parent->GetFirstChild();
-  }
-
-  return GetNextSibling(parent);
-}
-
-// Get the prev sibling, or parent's prev sibling, or grandpa's prev sibling...
-nsIContent* ContentIteratorBase::GetPrevSibling(nsINode* aNode) {
-  if (NS_WARN_IF(!aNode)) {
-    return nullptr;
-  }
-
-  if (aNode->GetPreviousSibling()) {
-    return aNode->GetPreviousSibling();
-  }
-
-  nsINode* parent = aNode->GetParentNode();
-  if (NS_WARN_IF(!parent)) {
-    return nullptr;
-  }
-
-  // XXX This is a hack to preserve previous behaviour: This should be fixed
-  // in bug 1404916. If we were positioned on anonymous content, move to
-  // the last child of our parent.
-  if (parent->GetFirstChild() && parent->GetFirstChild() != aNode) {
-    return parent->GetLastChild();
-  }
-
-  return GetPrevSibling(parent);
-}
-
-nsINode* ContentIteratorBase::NextNode(nsINode* aNode) {
-  nsINode* node = aNode;
-
-  // if we are a Pre-order iterator, use pre-order
-  if (mPre) {
-    // if it has children then next node is first child
-    if (node->HasChildren()) {
-      nsIContent* firstChild = node->GetFirstChild();
-      MOZ_ASSERT(firstChild);
-
-      return firstChild;
-    }
-
-    // else next sibling is next
-    return GetNextSibling(node);
-  }
-
-  // post-order
-  nsINode* parent = node->GetParentNode();
-  if (NS_WARN_IF(!parent)) {
-    MOZ_ASSERT(parent, "The node is the root node but not the last node");
-    mIsDone = true;
-    return node;
-  }
-
-  nsIContent* sibling = node->GetNextSibling();
-  if (sibling) {
-    // next node is sibling's "deep left" child
-    return GetDeepFirstChild(sibling);
-  }
-
-  return parent;
-}
-
-nsINode* ContentIteratorBase::PrevNode(nsINode* aNode) {
-  nsINode* node = aNode;
-
-  // if we are a Pre-order iterator, use pre-order
-  if (mPre) {
-    nsINode* parent = node->GetParentNode();
-    if (NS_WARN_IF(!parent)) {
-      MOZ_ASSERT(parent, "The node is the root node but not the first node");
-      mIsDone = true;
-      return aNode;
-    }
-
-    nsIContent* sibling = node->GetPreviousSibling();
-    if (sibling) {
-      return GetDeepLastChild(sibling);
-    }
-
-    return parent;
-  }
-
-  // post-order
-  if (node->HasChildren()) {
-    return node->GetLastChild();
-  }
-
-  // else prev sibling is previous
-  return GetPrevSibling(node);
-}
-
-/******************************************************
- * ContentIteratorBase routines
- ******************************************************/
-
-void ContentIteratorBase::First() {
-  if (mFirst) {
-    mozilla::DebugOnly<nsresult> rv = PositionAt(mFirst);
-    NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to position iterator!");
-  }
-
-  mIsDone = mFirst == nullptr;
-}
-
-void ContentIteratorBase::Last() {
-  // Note that mLast can be nullptr if MakeEmpty() is called in Init() since
-  // at that time, Init() returns NS_OK.
-  if (!mLast) {
-    MOZ_ASSERT(mIsDone);
-    return;
-  }
-
-  mozilla::DebugOnly<nsresult> rv = PositionAt(mLast);
-  NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to position iterator!");
-
-  mIsDone = mLast == nullptr;
-}
-
-void ContentIteratorBase::Next() {
-  if (mIsDone || NS_WARN_IF(!mCurNode)) {
-    return;
-  }
-
-  if (mCurNode == mLast) {
-    mIsDone = true;
-    return;
-  }
-
-  mCurNode = NextNode(mCurNode);
-}
-
-void ContentIteratorBase::Prev() {
-  if (NS_WARN_IF(mIsDone) || NS_WARN_IF(!mCurNode)) {
-    return;
-  }
-
-  if (mCurNode == mFirst) {
-    mIsDone = true;
-    return;
-  }
-
-  mCurNode = PrevNode(mCurNode);
-}
-
-bool ContentIteratorBase::IsDone() { return mIsDone; }
-
-// Keeping arrays of indexes for the stack of nodes makes PositionAt
-// interesting...
-nsresult ContentIteratorBase::PositionAt(nsINode* aCurNode) {
-  if (NS_WARN_IF(!aCurNode)) {
-    return NS_ERROR_NULL_POINTER;
-  }
-
-  // take an early out if this doesn't actually change the position
-  if (mCurNode == aCurNode) {
-    mIsDone = false;
-    return NS_OK;
-  }
-  mCurNode = aCurNode;
-
-  // Check to see if the node falls within the traversal range.
-
-  RawRangeBoundary first(mFirst, 0);
-  RawRangeBoundary last(mLast, 0);
-
-  if (mFirst && mLast) {
-    if (mPre) {
-      // In pre we want to record the point immediately before mFirst, which is
-      // the point immediately after mFirst's previous sibling.
-      first.SetAfterRef(mFirst->GetParentNode(), mFirst->GetPreviousSibling());
-
-      // If mLast has no children, then we want to make sure to include it.
-      if (!mLast->HasChildren()) {
-        last.SetAfterRef(mLast->GetParentNode(), mLast->AsContent());
-      }
-    } else {
-      // If the first node has any children, we want to be immediately after the
-      // last. Otherwise we want to be immediately before mFirst.
-      if (mFirst->HasChildren()) {
-        first.SetAfterRef(mFirst, mFirst->GetLastChild());
-      } else {
-        first.SetAfterRef(mFirst->GetParentNode(),
-                          mFirst->GetPreviousSibling());
-      }
-
-      // Set the last point immediately after the final node.
-      last.SetAfterRef(mLast->GetParentNode(), mLast->AsContent());
-    }
-  }
-
-  NS_WARNING_ASSERTION(first.IsSetAndValid(), "first is not valid");
-  NS_WARNING_ASSERTION(last.IsSetAndValid(), "last is not valid");
-
-  // The end positions are always in the range even if it has no parent.  We
-  // need to allow that or 'iter->Init(root)' would assert in Last() or First()
-  // for example, bug 327694.
-  if (mFirst != mCurNode && mLast != mCurNode &&
-      (NS_WARN_IF(!first.IsSet()) || NS_WARN_IF(!last.IsSet()) ||
-       NS_WARN_IF(!NodeIsInTraversalRange(mCurNode, mPre, first, last)))) {
-    mIsDone = true;
-    return NS_ERROR_FAILURE;
-  }
-
-  mIsDone = false;
-  return NS_OK;
-}
-
-nsINode* ContentIteratorBase::GetCurrentNode() {
-  if (mIsDone) {
-    return nullptr;
-  }
-
-  NS_ASSERTION(mCurNode, "Null current node in an iterator that's not done!");
-
-  return mCurNode;
-}
-
-/******************************************************
- * ContentSubtreeIterator init routines
- ******************************************************/
-
-nsresult ContentSubtreeIterator::Init(nsINode* aRoot) {
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-nsresult ContentSubtreeIterator::Init(nsRange* aRange) {
-  MOZ_ASSERT(aRange);
-
-  mIsDone = false;
-
-  if (NS_WARN_IF(!aRange->IsPositioned())) {
-    return NS_ERROR_INVALID_ARG;
-  }
-
-  mRange = aRange;
-
-  return InitWithRange();
-}
-
-nsresult ContentSubtreeIterator::Init(nsINode* aStartContainer,
-                                      uint32_t aStartOffset,
-                                      nsINode* aEndContainer,
-                                      uint32_t aEndOffset) {
-  return Init(RawRangeBoundary(aStartContainer, aStartOffset),
-              RawRangeBoundary(aEndContainer, aEndOffset));
-}
-
-nsresult ContentSubtreeIterator::Init(const RawRangeBoundary& aStart,
-                                      const RawRangeBoundary& aEnd) {
-  mIsDone = false;
-
-  RefPtr<nsRange> range;
-  nsresult rv = nsRange::CreateRange(aStart, aEnd, getter_AddRefs(range));
-  if (NS_WARN_IF(NS_FAILED(rv)) || NS_WARN_IF(!range) ||
-      NS_WARN_IF(!range->IsPositioned())) {
-    return NS_ERROR_INVALID_ARG;
-  }
-
-  if (NS_WARN_IF(range->StartRef() != aStart) ||
-      NS_WARN_IF(range->EndRef() != aEnd)) {
-    return NS_ERROR_UNEXPECTED;
-  }
-
-  mRange = std::move(range);
-
-  return InitWithRange();
-}
-
-nsresult ContentSubtreeIterator::InitWithRange() {
-  MOZ_ASSERT(mRange);
-  MOZ_ASSERT(mRange->IsPositioned());
-
-  // get the start node and offset, convert to nsINode
-  mCommonParent = mRange->GetCommonAncestor();
-  nsINode* startContainer = mRange->GetStartContainer();
-  int32_t startOffset = mRange->StartOffset();
-  nsINode* endContainer = mRange->GetEndContainer();
-  int32_t endOffset = mRange->EndOffset();
-  MOZ_ASSERT(mCommonParent && startContainer && endContainer);
-  // Bug 767169
-  MOZ_ASSERT(uint32_t(startOffset) <= startContainer->Length() &&
-             uint32_t(endOffset) <= endContainer->Length());
-
-  // short circuit when start node == end node
-  if (startContainer == endContainer) {
-    nsINode* child = startContainer->GetFirstChild();
-
-    if (!child || startOffset == endOffset) {
-      // Text node, empty container, or collapsed
-      MakeEmpty();
-      return NS_OK;
-    }
-  }
-
-  // cache ancestors
-  mEndNodes.Clear();
-  nsIContent* endNode =
-      endContainer->IsContent() ? endContainer->AsContent() : nullptr;
-  while (endNode) {
-    mEndNodes.AppendElement(endNode);
-    endNode = endNode->GetParent();
-  }
-
-  nsIContent* firstCandidate = nullptr;
-  nsIContent* lastCandidate = nullptr;
-
-  // find first node in range
-  int32_t offset = mRange->StartOffset();
-
-  nsINode* node = nullptr;
-  if (!startContainer->GetChildCount()) {
-    // no children, start at the node itself
-    node = startContainer;
-  } else {
-    nsIContent* child = mRange->GetChildAtStartOffset();
-    MOZ_ASSERT(child == startContainer->GetChildAt_Deprecated(offset));
-    if (!child) {
-      // offset after last child
-      node = startContainer;
-    } else {
-      firstCandidate = child;
-    }
-  }
-
-  if (!firstCandidate) {
-    // then firstCandidate is next node after node
-    firstCandidate = GetNextSibling(node);
-
-    if (!firstCandidate) {
-      MakeEmpty();
-      return NS_OK;
-    }
-  }
-
-  firstCandidate = GetDeepFirstChild(firstCandidate);
-
-  // confirm that this first possible contained node is indeed contained.  Else
-  // we have a range that does not fully contain any node.
-
-  bool nodeBefore, nodeAfter;
-  MOZ_ALWAYS_SUCCEEDS(nsRange::CompareNodeToRange(firstCandidate, mRange,
-                                                  &nodeBefore, &nodeAfter));
-
-  if (nodeBefore || nodeAfter) {
-    MakeEmpty();
-    return NS_OK;
-  }
-
-  // cool, we have the first node in the range.  Now we walk up its ancestors
-  // to find the most senior that is still in the range.  That's the real first
-  // node.
-  mFirst = GetTopAncestorInRange(firstCandidate);
-
-  // now to find the last node
-  offset = mRange->EndOffset();
-  int32_t numChildren = endContainer->GetChildCount();
-
-  if (offset > numChildren) {
-    // Can happen for text nodes
-    offset = numChildren;
-  }
-  if (!offset || !numChildren) {
-    node = endContainer;
-  } else {
-    lastCandidate = mRange->EndRef().Ref();
-    MOZ_ASSERT(lastCandidate == endContainer->GetChildAt_Deprecated(--offset));
-    NS_ASSERTION(lastCandidate,
-                 "tree traversal trouble in ContentSubtreeIterator::Init");
-  }
-
-  if (!lastCandidate) {
-    // then lastCandidate is prev node before node
-    lastCandidate = GetPrevSibling(node);
-  }
-
-  if (!lastCandidate) {
-    MakeEmpty();
-    return NS_OK;
-  }
-
-  lastCandidate = GetDeepLastChild(lastCandidate);
-
-  // confirm that this last possible contained node is indeed contained.  Else
-  // we have a range that does not fully contain any node.
-
-  MOZ_ALWAYS_SUCCEEDS(nsRange::CompareNodeToRange(lastCandidate, mRange,
-                                                  &nodeBefore, &nodeAfter));
-
-  if (nodeBefore || nodeAfter) {
-    MakeEmpty();
-    return NS_OK;
-  }
-
-  // cool, we have the last node in the range.  Now we walk up its ancestors to
-  // find the most senior that is still in the range.  That's the real first
-  // node.
-  mLast = GetTopAncestorInRange(lastCandidate);
-
-  mCurNode = mFirst;
-
-  return NS_OK;
-}
-
-/****************************************************************
- * ContentSubtreeIterator overrides of ContentIterator routines
- ****************************************************************/
-
-// we can't call PositionAt in a subtree iterator...
-void ContentSubtreeIterator::First() {
-  mIsDone = mFirst == nullptr;
-
-  mCurNode = mFirst;
-}
-
-// we can't call PositionAt in a subtree iterator...
-void ContentSubtreeIterator::Last() {
-  mIsDone = mLast == nullptr;
-
-  mCurNode = mLast;
-}
-
-void ContentSubtreeIterator::Next() {
-  if (mIsDone || !mCurNode) {
-    return;
-  }
-
-  if (mCurNode == mLast) {
-    mIsDone = true;
-    return;
-  }
-
-  nsINode* nextNode = GetNextSibling(mCurNode);
-  NS_ASSERTION(nextNode, "No next sibling!?! This could mean deadlock!");
-
-  int32_t i = mEndNodes.IndexOf(nextNode);
-  while (i != -1) {
-    // as long as we are finding ancestors of the endpoint of the range,
-    // dive down into their children
-    nextNode = nextNode->GetFirstChild();
-    NS_ASSERTION(nextNode, "Iterator error, expected a child node!");
-
-    // should be impossible to get a null pointer.  If we went all the way
-    // down the child chain to the bottom without finding an interior node,
-    // then the previous node should have been the last, which was
-    // was tested at top of routine.
-    i = mEndNodes.IndexOf(nextNode);
-  }
-
-  mCurNode = nextNode;
-
-  // This shouldn't be needed, but since our selection code can put us
-  // in a situation where mLast is in generated content, we need this
-  // to stop the iterator when we've walked past past the last node!
-  mIsDone = mCurNode == nullptr;
-}
-
-void ContentSubtreeIterator::Prev() {
-  // Prev should be optimized to use the mStartNodes, just as Next
-  // uses mEndNodes.
-  if (mIsDone || !mCurNode) {
-    return;
-  }
-
-  if (mCurNode == mFirst) {
-    mIsDone = true;
-    return;
-  }
-
-  // If any of these function calls return null, so will all succeeding ones,
-  // so mCurNode will wind up set to null.
-  nsINode* prevNode = GetDeepFirstChild(mCurNode);
-
-  prevNode = PrevNode(prevNode);
-
-  prevNode = GetDeepLastChild(prevNode);
-
-  mCurNode = GetTopAncestorInRange(prevNode);
-
-  // This shouldn't be needed, but since our selection code can put us
-  // in a situation where mFirst is in generated content, we need this
-  // to stop the iterator when we've walked past past the first node!
-  mIsDone = mCurNode == nullptr;
-}
-
-nsresult ContentSubtreeIterator::PositionAt(nsINode* aCurNode) {
-  NS_ERROR("Not implemented!");
-
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-/****************************************************************
- * ContentSubtreeIterator helper routines
- ****************************************************************/
-
-nsIContent* ContentSubtreeIterator::GetTopAncestorInRange(nsINode* aNode) {
-  if (!aNode || !aNode->GetParentNode()) {
-    return nullptr;
-  }
-
-  // aNode has a parent, so it must be content.
-  nsIContent* content = aNode->AsContent();
-
-  // sanity check: aNode is itself in the range
-  bool nodeBefore, nodeAfter;
-  nsresult res =
-      nsRange::CompareNodeToRange(aNode, mRange, &nodeBefore, &nodeAfter);
-  NS_ASSERTION(NS_SUCCEEDED(res) && !nodeBefore && !nodeAfter,
-               "aNode isn't in mRange, or something else weird happened");
-  if (NS_FAILED(res) || nodeBefore || nodeAfter) {
-    return nullptr;
-  }
-
-  while (content) {
-    nsIContent* parent = content->GetParent();
-    // content always has a parent.  If its parent is the root, however --
-    // i.e., either it's not content, or it is content but its own parent is
-    // null -- then we're finished, since we don't go up to the root.
-    //
-    // We have to special-case this because CompareNodeToRange treats the root
-    // node differently -- see bug 765205.
-    if (!parent || !parent->GetParentNode()) {
-      return content;
-    }
-    MOZ_ALWAYS_SUCCEEDS(
-        nsRange::CompareNodeToRange(parent, mRange, &nodeBefore, &nodeAfter));
-
-    if (nodeBefore || nodeAfter) {
-      return content;
-    }
-    content = parent;
-  }
-
-  MOZ_CRASH("This should only be possible if aNode was null");
-}
-
-}  // namespace mozilla
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -22,16 +22,17 @@
 #include "mozilla/dom/ScriptLoader.h"
 #include "mozilla/dom/Text.h"
 #include "mozilla/gfx/Matrix.h"
 #include "nsAtom.h"
 #include "nsDOMAttributeMap.h"
 #include "nsIContentInlines.h"
 #include "mozilla/dom/NodeInfo.h"
 #include "mozilla/dom/DocumentTimeline.h"
+#include "nsIContentIterator.h"
 #include "nsFlexContainerFrame.h"
 #include "nsFocusManager.h"
 #include "nsILinkHandler.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIURL.h"
 #include "nsContainerFrame.h"
 #include "nsIAnonymousContentCreator.h"
 #include "nsIPresShell.h"
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -31,16 +31,17 @@
 #include "nsAtom.h"
 #include "mozilla/dom/NodeInfo.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/ScriptLoader.h"
 #include "mozilla/dom/TouchEvent.h"
 #include "mozilla/dom/Document.h"
 #include "mozilla/dom/DocumentInlines.h"
 #include "nsIDocumentEncoder.h"
+#include "nsIContentIterator.h"
 #include "nsFocusManager.h"
 #include "nsILinkHandler.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIURL.h"
 #include "nsNetUtil.h"
 #include "nsIFrame.h"
 #include "nsIAnonymousContentCreator.h"
 #include "nsIPresShell.h"
--- a/dom/base/ScriptableContentIterator.cpp
+++ b/dom/base/ScriptableContentIterator.cpp
@@ -1,91 +1,47 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 #include "ScriptableContentIterator.h"
-
-#include "mozilla/ContentIterator.h"
 #include "nsINode.h"
 #include "nsRange.h"
 
 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_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
+NS_IMPL_CYCLE_COLLECTION(ScriptableContentIterator, mContentIterator)
 
 ScriptableContentIterator::ScriptableContentIterator()
     : mIteratorType(NOT_INITIALIZED) {}
 
 void ScriptableContentIterator::EnsureContentIterator() {
   if (mContentIterator) {
     return;
   }
   switch (mIteratorType) {
     case POST_ORDER_ITERATOR:
     default:
-      mContentIterator = MakeUnique<PostContentIterator>();
+      mContentIterator = NS_NewContentIterator();
       break;
     case PRE_ORDER_ITERATOR:
-      mContentIterator = MakeUnique<PreContentIterator>();
+      mContentIterator = NS_NewPreContentIterator();
       break;
     case SUBTREE_ITERATOR:
-      mContentIterator = MakeUnique<ContentSubtreeIterator>();
+      mContentIterator = NS_NewContentSubtreeIterator();
       break;
   }
 }
 
 NS_IMETHODIMP
 ScriptableContentIterator::InitWithRootNode(IteratorType aType,
                                             nsINode* aRoot) {
   if (aType == NOT_INITIALIZED ||
--- a/dom/base/ScriptableContentIterator.h
+++ b/dom/base/ScriptableContentIterator.h
@@ -3,33 +3,32 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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 "nsIContentIterator.h"
 #include "nsIScriptableContentIterator.h"
 
 namespace mozilla {
 
 class ScriptableContentIterator final : public nsIScriptableContentIterator {
  public:
   ScriptableContentIterator();
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS(ScriptableContentIterator)
   NS_DECL_NSISCRIPTABLECONTENTITERATOR
 
  protected:
   virtual ~ScriptableContentIterator() = default;
   void EnsureContentIterator();
 
   IteratorType mIteratorType;
-  UniquePtr<ContentIteratorBase> mContentIterator;
+  nsCOMPtr<nsIContentIterator> mContentIterator;
 };
 
 }  // namespace mozilla
 
 #endif  // #ifndef mozilla_scriptablecontentiterator_h
--- a/dom/base/Selection.cpp
+++ b/dom/base/Selection.cpp
@@ -9,17 +9,16 @@
  */
 
 #include "mozilla/dom/Selection.h"
 
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/AutoCopyListener.h"
 #include "mozilla/AutoRestore.h"
-#include "mozilla/ContentIterator.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/SelectionBinding.h"
 #include "mozilla/dom/ShadowRoot.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/HTMLEditor.h"
 #include "mozilla/RangeBoundary.h"
 #include "mozilla/Telemetry.h"
@@ -33,16 +32,17 @@
 #include "nsIContent.h"
 #include "nsRange.h"
 #include "nsITableCellLayout.h"
 #include "nsTArray.h"
 #include "nsTableWrapperFrame.h"
 #include "nsTableCellFrame.h"
 #include "nsIScrollableFrame.h"
 #include "nsCCUncollectableMarker.h"
+#include "nsIContentIterator.h"
 #include "nsIDocumentEncoder.h"
 #include "nsTextFragment.h"
 #include <algorithm>
 #include "nsContentUtils.h"
 
 #include "nsGkAtoms.h"
 #include "nsLayoutUtils.h"
 #include "nsBidiPresUtils.h"
@@ -1476,31 +1476,32 @@ void Selection::SelectFramesForContent(n
     textFrame->SetSelectedRange(0, aContent->GetText()->GetLength(), aSelected,
                                 mSelectionType);
   } else {
     frame->InvalidateFrameSubtree();  // frame continuations?
   }
 }
 
 // select all content children of aContent
-nsresult Selection::SelectAllFramesForContent(
-    PostContentIterator& aPostOrderIter, nsIContent* aContent, bool aSelected) {
+nsresult Selection::SelectAllFramesForContent(nsIContentIterator* aInnerIter,
+                                              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(aInnerIter->Init(aContent)))) {
     return NS_ERROR_FAILURE;
   }
 
-  for (; !aPostOrderIter.IsDone(); aPostOrderIter.Next()) {
-    nsINode* node = aPostOrderIter.GetCurrentNode();
+  for (; !aInnerIter->IsDone(); aInnerIter->Next()) {
+    nsINode* node = aInnerIter->GetCurrentNode();
     MOZ_ASSERT(node);
     nsIContent* innercontent = node->IsContent() ? node->AsContent() : nullptr;
     SelectFramesForContent(innercontent, aSelected);
   }
 
   return NS_OK;
 }
 
@@ -1570,28 +1571,28 @@ nsresult Selection::SelectFrames(nsPresC
   if (aRange->Collapsed() ||
       (startNode == endNode && !startNode->HasChildren())) {
     if (!isFirstContentTextNode) {
       SelectFramesForContent(startContent, aSelect);
     }
     return NS_OK;
   }
 
-  ContentSubtreeIterator subtreeIter;
-  subtreeIter.Init(aRange);
-  if (isFirstContentTextNode && !subtreeIter.IsDone() &&
-      subtreeIter.GetCurrentNode() == startNode) {
-    subtreeIter.Next();  // first content has already been handled.
+  nsCOMPtr<nsIContentIterator> iter = NS_NewContentSubtreeIterator();
+  iter->Init(aRange);
+  if (isFirstContentTextNode && !iter->IsDone() &&
+      iter->GetCurrentNode() == startNode) {
+    iter->Next();  // first content has already been handled.
   }
-  PostContentIterator postOrderIter;
-  for (; !subtreeIter.IsDone(); subtreeIter.Next()) {
-    nsINode* node = subtreeIter.GetCurrentNode();
+  nsCOMPtr<nsIContentIterator> inneriter = NS_NewContentIterator();
+  for (; !iter->IsDone(); iter->Next()) {
+    nsINode* node = iter->GetCurrentNode();
     MOZ_ASSERT(node);
     nsIContent* content = node->IsContent() ? node->AsContent() : nullptr;
-    SelectAllFramesForContent(postOrderIter, content, aSelect);
+    SelectAllFramesForContent(inneriter, content, aSelect);
   }
 
   // We must now do the last one if it is not the same as the first
   if (endNode != startNode) {
     nsIContent* endContent =
         endNode->IsContent() ? endNode->AsContent() : nullptr;
     // XXX The range can end at a document node and such range can be
     //     added to Selection with JS.  Therefore, even in such cases,
--- a/dom/base/Selection.h
+++ b/dom/base/Selection.h
@@ -22,28 +22,28 @@
 #include "nsISelectionListener.h"
 #include "nsRange.h"
 #include "nsTArrayForwardDeclare.h"
 #include "nsThreadUtils.h"
 #include "nsWrapperCache.h"
 
 struct CachedOffsetForFrame;
 class nsAutoScrollTimer;
+class nsIContentIterator;
 class nsIFrame;
 class nsFrameSelection;
 class nsPIDOMWindowOuter;
 struct SelectionDetails;
 struct SelectionCustomColors;
 class nsCopySupport;
 class nsHTMLCopyEncoder;
 
 namespace mozilla {
 class ErrorResult;
 class HTMLEditor;
-class PostContentIterator;
 enum class TableSelection : uint32_t;
 struct AutoPrepareFocusRange;
 namespace dom {
 class DocGroup;
 }  // namespace dom
 }  // namespace mozilla
 
 struct RangeData {
@@ -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(nsIContentIterator* aInnerIter,
                                      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/moz.build
+++ b/dom/base/moz.build
@@ -69,16 +69,17 @@ EXPORTS += [
     'nsFrameLoader.h',  # Because binding headers include it.
     'nsFrameMessageManager.h',
     'nsGlobalWindow.h',  # Because binding headers include it.
     'nsGlobalWindowInner.h',  # Because binding headers include it.
     'nsGlobalWindowOuter.h',  # Because binding headers include it.
     'nsIAnimationObserver.h',
     'nsIContent.h',
     'nsIContentInlines.h',
+    'nsIContentIterator.h',
     'nsIContentSerializer.h',
     'nsIDocumentObserver.h',
     'nsIGlobalObject.h',
     'nsImageLoadingContent.h',
     'nsIMutationObserver.h',
     'nsINode.h',
     'nsINodeList.h',
     'nsIScriptContext.h',
@@ -119,17 +120,16 @@ EXPORTS += [
 
 if CONFIG['MOZ_WEBRTC']:
     EXPORTS += [
         'nsDOMDataChannel.h',
         'nsDOMDataChannelDeclarations.h',
     ]
 
 EXPORTS.mozilla += [
-    'ContentIterator.h',
     'CORSMode.h',
     'FlushType.h',
     'FullscreenChange.h',
     'IdentifierMapEntry.h',
     'RangeBoundary.h',
     'ScriptableContentIterator.h',
     'SelectionChangeEventDispatcher.h',
     'TextInputProcessor.h',
@@ -256,17 +256,16 @@ UNIFIED_SOURCES += [
     'CharacterData.cpp',
     'ChildIterator.cpp',
     'ChromeMessageBroadcaster.cpp',
     'ChromeMessageSender.cpp',
     'ChromeNodeList.cpp',
     'ChromeUtils.cpp',
     'Comment.cpp',
     'ContentFrameMessageManager.cpp',
-    'ContentIterator.cpp',
     'ContentProcessMessageManager.cpp',
     'Crypto.cpp',
     'CustomElementRegistry.cpp',
     'DirectionalityUtils.cpp',
     'DispatcherTrait.cpp',
     'DocGroup.cpp',
     'Document.cpp',
     'DocumentFragment.cpp',
@@ -306,16 +305,17 @@ UNIFIED_SOURCES += [
     'Navigator.cpp',
     'NodeInfo.cpp',
     'NodeIterator.cpp',
     'NodeUbiReporting.cpp',
     'nsAttrValue.cpp',
     'nsAttrValueOrString.cpp',
     'nsCCUncollectableMarker.cpp',
     'nsContentAreaDragDrop.cpp',
+    'nsContentIterator.cpp',
     'nsContentList.cpp',
     'nsContentPermissionHelper.cpp',
     'nsContentPolicy.cpp',
     'nsContentSink.cpp',
     'nsContentTypeParser.cpp',
     'nsCopySupport.cpp',
     'nsDataDocumentContentPolicy.cpp',
     'nsDocumentEncoder.cpp',
--- a/dom/base/nsContentCID.h
+++ b/dom/base/nsContentCID.h
@@ -25,16 +25,37 @@
 
 #define NS_NAMESPACEMANAGER_CID                      \
   { /* d9783472-8fe9-11d2-9d3c-0060088f9ff7 */       \
     0xd9783472, 0x8fe9, 0x11d2, {                    \
       0x9d, 0x3c, 0x00, 0x60, 0x08, 0x8f, 0x9f, 0xf7 \
     }                                                \
   }
 
+#define NS_CONTENTITERATOR_CID                       \
+  { /* {a6cf90e3-15b3-11d2-932e-00805f8add32}*/      \
+    0xa6cf90e3, 0x15b3, 0x11d2, {                    \
+      0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32 \
+    }                                                \
+  }
+
+#define NS_PRECONTENTITERATOR_CID                    \
+  { /* {80D7E247-D4B8-45d7-BB59-6F1DD56F384C} */     \
+    0x80d7e247, 0xd4b8, 0x45d7, {                    \
+      0xbb, 0x59, 0x6f, 0x1d, 0xd5, 0x6f, 0x38, 0x4c \
+    }                                                \
+  }
+
+#define NS_SUBTREEITERATOR_CID                       \
+  { /* {a6cf90e5-15b3-11d2-932e-00805f8add32}*/      \
+    0xa6cf90e5, 0x15b3, 0x11d2, {                    \
+      0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32 \
+    }                                                \
+  }
+
 // {09F689E0-B4DA-11d2-A68B-00104BDE6048}
 #define NS_EVENTLISTENERMANAGER_CID                 \
   {                                                 \
     0x9f689e0, 0xb4da, 0x11d2, {                    \
       0xa6, 0x8b, 0x0, 0x10, 0x4b, 0xde, 0x60, 0x48 \
     }                                               \
   }
 
rename from dom/base/ContentIterator.h
rename to dom/base/nsContentIterator.cpp
--- a/dom/base/ContentIterator.h
+++ b/dom/base/nsContentIterator.cpp
@@ -1,61 +1,121 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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_ContentIterator_h
-#define mozilla_ContentIterator_h
-
-#include "mozilla/RangeBoundary.h"
+#include "mozilla/DebugOnly.h"
+#include "nsISupports.h"
+#include "nsIContentIterator.h"
+#include "nsRange.h"
+#include "nsIContent.h"
 #include "nsCOMPtr.h"
+#include "nsTArray.h"
+#include "nsContentUtils.h"
+#include "nsINode.h"
 #include "nsCycleCollectionParticipant.h"
-#include "nsIContent.h"
-#include "nsRange.h"
-#include "nsTArray.h"
+#include "nsElementTable.h"
+
+using mozilla::DebugOnly;
+using mozilla::RawRangeBoundary;
+
+// couple of utility static functs
+
+///////////////////////////////////////////////////////////////////////////
+// NodeIsInTraversalRange: returns true if content is visited during
+// the traversal of the range in the specified mode.
+//
+static bool NodeIsInTraversalRange(nsINode* aNode, bool aIsPreMode,
+                                   const RawRangeBoundary& aStart,
+                                   const RawRangeBoundary& aEnd) {
+  if (NS_WARN_IF(!aStart.IsSet()) || NS_WARN_IF(!aEnd.IsSet()) ||
+      NS_WARN_IF(!aNode)) {
+    return false;
+  }
 
-namespace mozilla {
+  // If a leaf node contains an end point of the traversal range, it is
+  // always in the traversal range.
+  if (aNode == aStart.Container() || aNode == aEnd.Container()) {
+    if (aNode->IsCharacterData()) {
+      return true;  // text node or something
+    }
+    if (!aNode->HasChildren()) {
+      MOZ_ASSERT(
+          aNode != aStart.Container() || aStart.IsStartOfContainer(),
+          "aStart.Container() doesn't have children and not a data node, "
+          "aStart should be at the beginning of its container");
+      MOZ_ASSERT(aNode != aEnd.Container() || aEnd.IsStartOfContainer(),
+                 "aEnd.Container() doesn't have children and not a data node, "
+                 "aEnd should be at the beginning of its container");
+      return true;
+    }
+  }
 
-/**
- * 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.
+  nsINode* parent = aNode->GetParentNode();
+  if (!parent) {
+    return false;
+  }
+
+  if (!aIsPreMode) {
+    // aNode should always be content, as we have a parent, but let's just be
+    // extra careful and check.
+    nsIContent* content =
+        NS_WARN_IF(!aNode->IsContent()) ? nullptr : aNode->AsContent();
+    // Post mode: start < node <= end.
+    RawRangeBoundary afterNode(parent, content);
+    return nsContentUtils::ComparePoints(aStart, afterNode) < 0 &&
+           nsContentUtils::ComparePoints(aEnd, afterNode) >= 0;
+  }
+
+  // Pre mode: start <= node < end.
+  RawRangeBoundary beforeNode(parent, aNode->GetPreviousSibling());
+  return nsContentUtils::ComparePoints(aStart, beforeNode) <= 0 &&
+         nsContentUtils::ComparePoints(aEnd, beforeNode) > 0;
+}
+
+/*
+ *  A simple iterator class for traversing the content in "close tag" order
  */
-class ContentIteratorBase {
+class nsContentIterator : public nsIContentIterator {
  public:
-  ContentIteratorBase() = delete;
-  ContentIteratorBase(const ContentIteratorBase&) = delete;
-  ContentIteratorBase& operator=(const ContentIteratorBase&) = delete;
-  virtual ~ContentIteratorBase() = default;
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS(nsContentIterator)
+
+  explicit nsContentIterator(bool aPre);
+
+  // nsIContentIterator interface methods ------------------------------
 
-  NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(ContentIteratorBase)
+  virtual nsresult Init(nsINode* aRoot) override;
+
+  virtual nsresult Init(nsRange* aRange) override;
 
-  virtual nsresult Init(nsINode* aRoot);
-  virtual nsresult Init(nsRange* aRange);
   virtual nsresult Init(nsINode* aStartContainer, uint32_t aStartOffset,
-                        nsINode* aEndContainer, uint32_t aEndOffset);
+                        nsINode* aEndContainer, uint32_t aEndOffset) override;
+
   virtual nsresult Init(const RawRangeBoundary& aStart,
-                        const RawRangeBoundary& aEnd);
+                        const RawRangeBoundary& aEnd) override;
+
+  virtual void First() override;
+
+  virtual void Last() override;
+
+  virtual void Next() override;
 
-  virtual void First();
-  virtual void Last();
-  virtual void Next();
-  virtual void Prev();
+  virtual void Prev() override;
+
+  virtual nsINode* GetCurrentNode() override;
 
-  virtual nsINode* GetCurrentNode();
+  virtual bool IsDone() override;
 
-  virtual bool IsDone();
-
-  virtual nsresult PositionAt(nsINode* aCurNode);
+  virtual nsresult PositionAt(nsINode* aCurNode) override;
 
  protected:
-  explicit ContentIteratorBase(bool aPre);
+  virtual ~nsContentIterator();
 
   /**
    * 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,
@@ -74,158 +134,1019 @@ 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;
 
   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;
-  virtual ~PostContentIterator() = default;
-  friend void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback&,
-                                          PostContentIterator&, const char*,
-                                          uint32_t);
-  friend void ImplCycleCollectionUnlink(PostContentIterator&);
+ private:
+  // no copies or assigns  FIX ME
+  nsContentIterator(const nsContentIterator&);
+  nsContentIterator& operator=(const nsContentIterator&);
 };
 
-inline void ImplCycleCollectionTraverse(
-    nsCycleCollectionTraversalCallback& aCallback, PostContentIterator& aField,
-    const char* aName, uint32_t aFlags = 0) {
-  ImplCycleCollectionTraverse(
-      aCallback, static_cast<ContentIteratorBase&>(aField), aName, aFlags);
+/******************************************************
+ * repository cruft
+ ******************************************************/
+
+already_AddRefed<nsIContentIterator> NS_NewContentIterator() {
+  nsCOMPtr<nsIContentIterator> iter = new nsContentIterator(false);
+  return iter.forget();
+}
+
+already_AddRefed<nsIContentIterator> NS_NewPreContentIterator() {
+  nsCOMPtr<nsIContentIterator> iter = new nsContentIterator(true);
+  return iter.forget();
+}
+
+/******************************************************
+ * XPCOM cruft
+ ******************************************************/
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsContentIterator)
+NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(nsContentIterator,
+                                                   LastRelease())
+
+NS_INTERFACE_MAP_BEGIN(nsContentIterator)
+  NS_INTERFACE_MAP_ENTRY(nsIContentIterator)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentIterator)
+  NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsContentIterator)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTION(nsContentIterator, mCurNode, mFirst, mLast,
+                         mCommonParent)
+
+void nsContentIterator::LastRelease() {
+  mCurNode = nullptr;
+  mFirst = nullptr;
+  mLast = nullptr;
+  mCommonParent = nullptr;
+}
+
+/******************************************************
+ * constructor/destructor
+ ******************************************************/
+
+nsContentIterator::nsContentIterator(bool aPre) : mIsDone(false), mPre(aPre) {}
+
+nsContentIterator::~nsContentIterator() {}
+
+/******************************************************
+ * Init routines
+ ******************************************************/
+
+nsresult nsContentIterator::Init(nsINode* aRoot) {
+  if (NS_WARN_IF(!aRoot)) {
+    return NS_ERROR_NULL_POINTER;
+  }
+
+  mIsDone = false;
+
+  if (mPre) {
+    mFirst = aRoot;
+    mLast = GetDeepLastChild(aRoot);
+    NS_WARNING_ASSERTION(mLast, "GetDeepLastChild returned null");
+  } else {
+    mFirst = GetDeepFirstChild(aRoot);
+    NS_WARNING_ASSERTION(mFirst, "GetDeepFirstChild returned null");
+    mLast = aRoot;
+  }
+
+  mCommonParent = aRoot;
+  mCurNode = mFirst;
+  return NS_OK;
+}
+
+nsresult nsContentIterator::Init(nsRange* aRange) {
+  mIsDone = false;
+
+  if (NS_WARN_IF(!aRange)) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  if (NS_WARN_IF(!aRange->IsPositioned())) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  return InitInternal(aRange->StartRef().AsRaw(), aRange->EndRef().AsRaw());
+}
+
+nsresult nsContentIterator::Init(nsINode* aStartContainer,
+                                 uint32_t aStartOffset, nsINode* aEndContainer,
+                                 uint32_t aEndOffset) {
+  mIsDone = false;
+
+  if (NS_WARN_IF(!nsRange::IsValidPoints(aStartContainer, aStartOffset,
+                                         aEndContainer, aEndOffset))) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  return InitInternal(RawRangeBoundary(aStartContainer, aStartOffset),
+                      RawRangeBoundary(aEndContainer, aEndOffset));
+}
+
+nsresult nsContentIterator::Init(const RawRangeBoundary& aStart,
+                                 const RawRangeBoundary& aEnd) {
+  mIsDone = false;
+
+  if (NS_WARN_IF(!nsRange::IsValidPoints(aStart.Container(), aStart.Offset(),
+                                         aEnd.Container(), aEnd.Offset()))) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  return InitInternal(aStart, aEnd);
 }
 
-inline void ImplCycleCollectionUnlink(PostContentIterator& aField) {
-  ImplCycleCollectionUnlink(static_cast<ContentIteratorBase&>(aField));
+nsresult nsContentIterator::InitInternal(const RawRangeBoundary& aStart,
+                                         const RawRangeBoundary& aEnd) {
+  // get common content parent
+  mCommonParent =
+      nsContentUtils::GetCommonAncestor(aStart.Container(), aEnd.Container());
+  if (NS_WARN_IF(!mCommonParent)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  bool startIsData = aStart.Container()->IsCharacterData();
+
+  // Check to see if we have a collapsed range, if so, there is nothing to
+  // iterate over.
+  //
+  // XXX: CharacterDataNodes (text nodes) are currently an exception, since
+  //      we always want to be able to iterate text nodes at the end points
+  //      of a range.
+
+  if (!startIsData && aStart == aEnd) {
+    MakeEmpty();
+    return NS_OK;
+  }
+
+  // Handle ranges within a single character data node.
+  if (startIsData && aStart.Container() == aEnd.Container()) {
+    mFirst = aStart.Container()->AsContent();
+    mLast = mFirst;
+    mCurNode = mFirst;
+
+    return NS_OK;
+  }
+
+  // Find first node in range.
+
+  nsIContent* cChild = nullptr;
+
+  // Try to get the child at our starting point. This might return null if
+  // aStart is immediately after the last node in aStart.Container().
+  if (!startIsData) {
+    cChild = aStart.GetChildAtOffset();
+  }
+
+  if (!cChild) {
+    // No children (possibly a <br> or text node), or index is after last child.
+
+    if (mPre) {
+      // XXX: In the future, if start offset is after the last
+      //      character in the cdata node, should we set mFirst to
+      //      the next sibling?
+
+      // Normally we would skip the start node because the start node is outside
+      // of the range in pre mode. However, if aStartOffset == 0, and the node
+      // is a non-container node (e.g. <br>), we don't skip the node in this
+      // case in order to address bug 1215798.
+      bool startIsContainer = true;
+      if (aStart.Container()->IsHTMLElement()) {
+        nsAtom* name = aStart.Container()->NodeInfo()->NameAtom();
+        startIsContainer =
+            nsHTMLElement::IsContainer(nsHTMLTags::AtomTagToId(name));
+      }
+      if (!startIsData && (startIsContainer || !aStart.IsStartOfContainer())) {
+        mFirst = GetNextSibling(aStart.Container());
+        NS_WARNING_ASSERTION(mFirst, "GetNextSibling returned null");
+
+        // Does mFirst node really intersect the range?  The range could be
+        // 'degenerate', i.e., not collapsed but still contain no content.
+        if (mFirst &&
+            NS_WARN_IF(!NodeIsInTraversalRange(mFirst, mPre, aStart, aEnd))) {
+          mFirst = nullptr;
+        }
+      } else {
+        mFirst = aStart.Container()->AsContent();
+      }
+    } else {
+      // post-order
+      if (NS_WARN_IF(!aStart.Container()->IsContent())) {
+        // What else can we do?
+        mFirst = nullptr;
+      } else {
+        mFirst = aStart.Container()->AsContent();
+      }
+    }
+  } else {
+    if (mPre) {
+      mFirst = cChild;
+    } else {
+      // post-order
+      mFirst = GetDeepFirstChild(cChild);
+      NS_WARNING_ASSERTION(mFirst, "GetDeepFirstChild returned null");
+
+      // Does mFirst node really intersect the range?  The range could be
+      // 'degenerate', i.e., not collapsed but still contain no content.
+
+      if (mFirst && !NodeIsInTraversalRange(mFirst, mPre, aStart, aEnd)) {
+        mFirst = nullptr;
+      }
+    }
+  }
+
+  // Find last node in range.
+
+  bool endIsData = aEnd.Container()->IsCharacterData();
+
+  if (endIsData || !aEnd.Container()->HasChildren() ||
+      aEnd.IsStartOfContainer()) {
+    if (mPre) {
+      if (NS_WARN_IF(!aEnd.Container()->IsContent())) {
+        // Not much else to do here...
+        mLast = nullptr;
+      } else {
+        // If the end node is a non-container element and the end offset is 0,
+        // the last element should be the previous node (i.e., shouldn't
+        // include the end node in the range).
+        bool endIsContainer = true;
+        if (aEnd.Container()->IsHTMLElement()) {
+          nsAtom* name = aEnd.Container()->NodeInfo()->NameAtom();
+          endIsContainer =
+              nsHTMLElement::IsContainer(nsHTMLTags::AtomTagToId(name));
+        }
+        if (!endIsData && !endIsContainer && aEnd.IsStartOfContainer()) {
+          mLast = PrevNode(aEnd.Container());
+          NS_WARNING_ASSERTION(mLast, "PrevNode returned null");
+          if (mLast && mLast != mFirst &&
+              NS_WARN_IF(!NodeIsInTraversalRange(
+                  mLast, mPre, RawRangeBoundary(mFirst, 0), aEnd))) {
+            mLast = nullptr;
+          }
+        } else {
+          mLast = aEnd.Container()->AsContent();
+        }
+      }
+    } else {
+      // post-order
+      //
+      // XXX: In the future, if end offset is before the first character in the
+      //      cdata node, should we set mLast to the prev sibling?
+
+      if (!endIsData) {
+        mLast = GetPrevSibling(aEnd.Container());
+        NS_WARNING_ASSERTION(mLast, "GetPrevSibling returned null");
+
+        if (!NodeIsInTraversalRange(mLast, mPre, aStart, aEnd)) {
+          mLast = nullptr;
+        }
+      } else {
+        mLast = aEnd.Container()->AsContent();
+      }
+    }
+  } else {
+    cChild = aEnd.Ref();
+
+    if (NS_WARN_IF(!cChild)) {
+      // No child at offset!
+      MOZ_ASSERT_UNREACHABLE("nsContentIterator::nsContentIterator");
+      return NS_ERROR_FAILURE;
+    }
+
+    if (mPre) {
+      mLast = GetDeepLastChild(cChild);
+      NS_WARNING_ASSERTION(mLast, "GetDeepLastChild returned null");
+
+      if (NS_WARN_IF(!NodeIsInTraversalRange(mLast, mPre, aStart, aEnd))) {
+        mLast = nullptr;
+      }
+    } else {
+      // post-order
+      mLast = cChild;
+    }
+  }
+
+  // If either first or last is null, they both have to be null!
+
+  if (!mFirst || !mLast) {
+    mFirst = nullptr;
+    mLast = nullptr;
+  }
+
+  mCurNode = mFirst;
+  mIsDone = !mCurNode;
+
+  return NS_OK;
+}
+
+void nsContentIterator::MakeEmpty() {
+  mCurNode = nullptr;
+  mFirst = nullptr;
+  mLast = nullptr;
+  mCommonParent = nullptr;
+  mIsDone = true;
 }
 
-/**
- * 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;
-  virtual ~PreContentIterator() = default;
-  friend void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback&,
-                                          PreContentIterator&, const char*,
-                                          uint32_t);
-  friend void ImplCycleCollectionUnlink(PreContentIterator&);
-};
+nsINode* nsContentIterator::GetDeepFirstChild(nsINode* aRoot) {
+  if (NS_WARN_IF(!aRoot) || !aRoot->HasChildren()) {
+    return aRoot;
+  }
+
+  return GetDeepFirstChild(aRoot->GetFirstChild());
+}
+
+nsIContent* nsContentIterator::GetDeepFirstChild(nsIContent* aRoot) {
+  if (NS_WARN_IF(!aRoot)) {
+    return nullptr;
+  }
+
+  nsIContent* node = aRoot;
+  nsIContent* child = node->GetFirstChild();
+
+  while (child) {
+    node = child;
+    child = node->GetFirstChild();
+  }
+
+  return node;
+}
+
+nsINode* nsContentIterator::GetDeepLastChild(nsINode* aRoot) {
+  if (NS_WARN_IF(!aRoot) || !aRoot->HasChildren()) {
+    return aRoot;
+  }
+
+  return GetDeepLastChild(aRoot->GetLastChild());
+}
+
+nsIContent* nsContentIterator::GetDeepLastChild(nsIContent* aRoot) {
+  if (NS_WARN_IF(!aRoot)) {
+    return nullptr;
+  }
+
+  nsIContent* node = aRoot;
+  while (node->HasChildren()) {
+    nsIContent* child = node->GetLastChild();
+    node = child;
+  }
+  return node;
+}
+
+// Get the next sibling, or parent's next sibling, or grandpa's next sibling...
+nsIContent* nsContentIterator::GetNextSibling(nsINode* aNode) {
+  if (NS_WARN_IF(!aNode)) {
+    return nullptr;
+  }
+
+  if (aNode->GetNextSibling()) {
+    return aNode->GetNextSibling();
+  }
+
+  nsINode* parent = aNode->GetParentNode();
+  if (NS_WARN_IF(!parent)) {
+    return nullptr;
+  }
 
-inline void ImplCycleCollectionTraverse(
-    nsCycleCollectionTraversalCallback& aCallback, PreContentIterator& aField,
-    const char* aName, uint32_t aFlags = 0) {
-  ImplCycleCollectionTraverse(
-      aCallback, static_cast<ContentIteratorBase&>(aField), aName, aFlags);
+  // XXX This is a hack to preserve previous behaviour: This should be fixed
+  // in bug 1404916. If we were positioned on anonymous content, move to
+  // the first child of our parent.
+  if (parent->GetLastChild() && parent->GetLastChild() != aNode) {
+    return parent->GetFirstChild();
+  }
+
+  return GetNextSibling(parent);
+}
+
+// Get the prev sibling, or parent's prev sibling, or grandpa's prev sibling...
+nsIContent* nsContentIterator::GetPrevSibling(nsINode* aNode) {
+  if (NS_WARN_IF(!aNode)) {
+    return nullptr;
+  }
+
+  if (aNode->GetPreviousSibling()) {
+    return aNode->GetPreviousSibling();
+  }
+
+  nsINode* parent = aNode->GetParentNode();
+  if (NS_WARN_IF(!parent)) {
+    return nullptr;
+  }
+
+  // XXX This is a hack to preserve previous behaviour: This should be fixed
+  // in bug 1404916. If we were positioned on anonymous content, move to
+  // the last child of our parent.
+  if (parent->GetFirstChild() && parent->GetFirstChild() != aNode) {
+    return parent->GetLastChild();
+  }
+
+  return GetPrevSibling(parent);
+}
+
+nsINode* nsContentIterator::NextNode(nsINode* aNode) {
+  nsINode* node = aNode;
+
+  // if we are a Pre-order iterator, use pre-order
+  if (mPre) {
+    // if it has children then next node is first child
+    if (node->HasChildren()) {
+      nsIContent* firstChild = node->GetFirstChild();
+      MOZ_ASSERT(firstChild);
+
+      return firstChild;
+    }
+
+    // else next sibling is next
+    return GetNextSibling(node);
+  }
+
+  // post-order
+  nsINode* parent = node->GetParentNode();
+  if (NS_WARN_IF(!parent)) {
+    MOZ_ASSERT(parent, "The node is the root node but not the last node");
+    mIsDone = true;
+    return node;
+  }
+
+  nsIContent* sibling = node->GetNextSibling();
+  if (sibling) {
+    // next node is sibling's "deep left" child
+    return GetDeepFirstChild(sibling);
+  }
+
+  return parent;
 }
 
-inline void ImplCycleCollectionUnlink(PreContentIterator& aField) {
-  ImplCycleCollectionUnlink(static_cast<ContentIteratorBase&>(aField));
+nsINode* nsContentIterator::PrevNode(nsINode* aNode) {
+  nsINode* node = aNode;
+
+  // if we are a Pre-order iterator, use pre-order
+  if (mPre) {
+    nsINode* parent = node->GetParentNode();
+    if (NS_WARN_IF(!parent)) {
+      MOZ_ASSERT(parent, "The node is the root node but not the first node");
+      mIsDone = true;
+      return aNode;
+    }
+
+    nsIContent* sibling = node->GetPreviousSibling();
+    if (sibling) {
+      return GetDeepLastChild(sibling);
+    }
+
+    return parent;
+  }
+
+  // post-order
+  if (node->HasChildren()) {
+    return node->GetLastChild();
+  }
+
+  // else prev sibling is previous
+  return GetPrevSibling(node);
+}
+
+/******************************************************
+ * ContentIterator routines
+ ******************************************************/
+
+void nsContentIterator::First() {
+  if (mFirst) {
+    mozilla::DebugOnly<nsresult> rv = PositionAt(mFirst);
+    NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to position iterator!");
+  }
+
+  mIsDone = mFirst == nullptr;
+}
+
+void nsContentIterator::Last() {
+  // Note that mLast can be nullptr if MakeEmpty() is called in Init() since
+  // at that time, Init() returns NS_OK.
+  if (!mLast) {
+    MOZ_ASSERT(mIsDone);
+    return;
+  }
+
+  mozilla::DebugOnly<nsresult> rv = PositionAt(mLast);
+  NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to position iterator!");
+
+  mIsDone = mLast == nullptr;
+}
+
+void nsContentIterator::Next() {
+  if (mIsDone || NS_WARN_IF(!mCurNode)) {
+    return;
+  }
+
+  if (mCurNode == mLast) {
+    mIsDone = true;
+    return;
+  }
+
+  mCurNode = NextNode(mCurNode);
+}
+
+void nsContentIterator::Prev() {
+  if (NS_WARN_IF(mIsDone) || NS_WARN_IF(!mCurNode)) {
+    return;
+  }
+
+  if (mCurNode == mFirst) {
+    mIsDone = true;
+    return;
+  }
+
+  mCurNode = PrevNode(mCurNode);
 }
 
-/**
- *  A simple iterator class for traversing the content in "top subtree" order.
+bool nsContentIterator::IsDone() { return mIsDone; }
+
+// Keeping arrays of indexes for the stack of nodes makes PositionAt
+// interesting...
+nsresult nsContentIterator::PositionAt(nsINode* aCurNode) {
+  if (NS_WARN_IF(!aCurNode)) {
+    return NS_ERROR_NULL_POINTER;
+  }
+
+  // take an early out if this doesn't actually change the position
+  if (mCurNode == aCurNode) {
+    mIsDone = false;
+    return NS_OK;
+  }
+  mCurNode = aCurNode;
+
+  // Check to see if the node falls within the traversal range.
+
+  RawRangeBoundary first(mFirst, 0);
+  RawRangeBoundary last(mLast, 0);
+
+  if (mFirst && mLast) {
+    if (mPre) {
+      // In pre we want to record the point immediately before mFirst, which is
+      // the point immediately after mFirst's previous sibling.
+      first.SetAfterRef(mFirst->GetParentNode(), mFirst->GetPreviousSibling());
+
+      // If mLast has no children, then we want to make sure to include it.
+      if (!mLast->HasChildren()) {
+        last.SetAfterRef(mLast->GetParentNode(), mLast->AsContent());
+      }
+    } else {
+      // If the first node has any children, we want to be immediately after the
+      // last. Otherwise we want to be immediately before mFirst.
+      if (mFirst->HasChildren()) {
+        first.SetAfterRef(mFirst, mFirst->GetLastChild());
+      } else {
+        first.SetAfterRef(mFirst->GetParentNode(),
+                          mFirst->GetPreviousSibling());
+      }
+
+      // Set the last point immediately after the final node.
+      last.SetAfterRef(mLast->GetParentNode(), mLast->AsContent());
+    }
+  }
+
+  NS_WARNING_ASSERTION(first.IsSetAndValid(), "first is not valid");
+  NS_WARNING_ASSERTION(last.IsSetAndValid(), "last is not valid");
+
+  // The end positions are always in the range even if it has no parent.  We
+  // need to allow that or 'iter->Init(root)' would assert in Last() or First()
+  // for example, bug 327694.
+  if (mFirst != mCurNode && mLast != mCurNode &&
+      (NS_WARN_IF(!first.IsSet()) || NS_WARN_IF(!last.IsSet()) ||
+       NS_WARN_IF(!NodeIsInTraversalRange(mCurNode, mPre, first, last)))) {
+    mIsDone = true;
+    return NS_ERROR_FAILURE;
+  }
+
+  mIsDone = false;
+  return NS_OK;
+}
+
+nsINode* nsContentIterator::GetCurrentNode() {
+  if (mIsDone) {
+    return nullptr;
+  }
+
+  NS_ASSERTION(mCurNode, "Null current node in an iterator that's not done!");
+
+  return mCurNode;
+}
+
+/*====================================================================================*/
+/*====================================================================================*/
+
+/******************************************************
+ * nsContentSubtreeIterator
+ ******************************************************/
+
+/*
+ *  A simple iterator class for traversing the content in "top subtree" order
  */
-class ContentSubtreeIterator final : public ContentIteratorBase {
+class nsContentSubtreeIterator : public nsContentIterator {
  public:
-  ContentSubtreeIterator() : ContentIteratorBase(true) {}
-  ContentSubtreeIterator(const ContentSubtreeIterator&) = delete;
-  ContentSubtreeIterator& operator=(const ContentSubtreeIterator&) = delete;
-  virtual ~ContentSubtreeIterator() = default;
+  nsContentSubtreeIterator() : nsContentIterator(false) {}
+
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsContentSubtreeIterator,
+                                           nsContentIterator)
+
+  // nsContentIterator overrides ------------------------------
 
   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;
 
   virtual void Next() override;
+
   virtual void Prev() override;
+
+  virtual nsresult PositionAt(nsINode* aCurNode) 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;
+ protected:
+  virtual ~nsContentSubtreeIterator() {}
 
-  friend void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback&,
-                                          ContentSubtreeIterator&, const char*,
-                                          uint32_t);
-  friend void ImplCycleCollectionUnlink(ContentSubtreeIterator&);
-
- protected:
   /**
    * 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);
 
+  // no copy's or assigns  FIX ME
+  nsContentSubtreeIterator(const nsContentSubtreeIterator&);
+  nsContentSubtreeIterator& operator=(const nsContentSubtreeIterator&);
+
+  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);
+NS_IMPL_ADDREF_INHERITED(nsContentSubtreeIterator, nsContentIterator)
+NS_IMPL_RELEASE_INHERITED(nsContentSubtreeIterator, nsContentIterator)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsContentSubtreeIterator)
+NS_INTERFACE_MAP_END_INHERITING(nsContentIterator)
+
+NS_IMPL_CYCLE_COLLECTION_INHERITED(nsContentSubtreeIterator, nsContentIterator,
+                                   mRange)
+
+void nsContentSubtreeIterator::LastRelease() {
+  mRange = nullptr;
+  nsContentIterator::LastRelease();
+}
+
+/******************************************************
+ * repository cruft
+ ******************************************************/
+
+already_AddRefed<nsIContentIterator> NS_NewContentSubtreeIterator() {
+  nsCOMPtr<nsIContentIterator> iter = new nsContentSubtreeIterator();
+  return iter.forget();
+}
+
+/******************************************************
+ * Init routines
+ ******************************************************/
+
+nsresult nsContentSubtreeIterator::Init(nsINode* aRoot) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+nsresult nsContentSubtreeIterator::Init(nsRange* aRange) {
+  MOZ_ASSERT(aRange);
+
+  mIsDone = false;
+
+  if (NS_WARN_IF(!aRange->IsPositioned())) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  mRange = aRange;
+
+  return InitWithRange();
+}
+
+nsresult nsContentSubtreeIterator::Init(nsINode* aStartContainer,
+                                        uint32_t aStartOffset,
+                                        nsINode* aEndContainer,
+                                        uint32_t aEndOffset) {
+  return Init(RawRangeBoundary(aStartContainer, aStartOffset),
+              RawRangeBoundary(aEndContainer, aEndOffset));
+}
+
+nsresult nsContentSubtreeIterator::Init(const RawRangeBoundary& aStart,
+                                        const RawRangeBoundary& aEnd) {
+  mIsDone = false;
+
+  RefPtr<nsRange> range;
+  nsresult rv = nsRange::CreateRange(aStart, aEnd, getter_AddRefs(range));
+  if (NS_WARN_IF(NS_FAILED(rv)) || NS_WARN_IF(!range) ||
+      NS_WARN_IF(!range->IsPositioned())) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  if (NS_WARN_IF(range->StartRef() != aStart) ||
+      NS_WARN_IF(range->EndRef() != aEnd)) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  mRange = std::move(range);
+
+  return InitWithRange();
 }
 
-inline void ImplCycleCollectionUnlink(ContentSubtreeIterator& aField) {
-  ImplCycleCollectionUnlink(aField.mRange);
-  ImplCycleCollectionUnlink(static_cast<ContentIteratorBase&>(aField));
+nsresult nsContentSubtreeIterator::InitWithRange() {
+  MOZ_ASSERT(mRange);
+  MOZ_ASSERT(mRange->IsPositioned());
+
+  // get the start node and offset, convert to nsINode
+  mCommonParent = mRange->GetCommonAncestor();
+  nsINode* startContainer = mRange->GetStartContainer();
+  int32_t startOffset = mRange->StartOffset();
+  nsINode* endContainer = mRange->GetEndContainer();
+  int32_t endOffset = mRange->EndOffset();
+  MOZ_ASSERT(mCommonParent && startContainer && endContainer);
+  // Bug 767169
+  MOZ_ASSERT(uint32_t(startOffset) <= startContainer->Length() &&
+             uint32_t(endOffset) <= endContainer->Length());
+
+  // short circuit when start node == end node
+  if (startContainer == endContainer) {
+    nsINode* child = startContainer->GetFirstChild();
+
+    if (!child || startOffset == endOffset) {
+      // Text node, empty container, or collapsed
+      MakeEmpty();
+      return NS_OK;
+    }
+  }
+
+  // cache ancestors
+  mEndNodes.Clear();
+  nsIContent* endNode =
+      endContainer->IsContent() ? endContainer->AsContent() : nullptr;
+  while (endNode) {
+    mEndNodes.AppendElement(endNode);
+    endNode = endNode->GetParent();
+  }
+
+  nsIContent* firstCandidate = nullptr;
+  nsIContent* lastCandidate = nullptr;
+
+  // find first node in range
+  int32_t offset = mRange->StartOffset();
+
+  nsINode* node = nullptr;
+  if (!startContainer->GetChildCount()) {
+    // no children, start at the node itself
+    node = startContainer;
+  } else {
+    nsIContent* child = mRange->GetChildAtStartOffset();
+    MOZ_ASSERT(child == startContainer->GetChildAt_Deprecated(offset));
+    if (!child) {
+      // offset after last child
+      node = startContainer;
+    } else {
+      firstCandidate = child;
+    }
+  }
+
+  if (!firstCandidate) {
+    // then firstCandidate is next node after node
+    firstCandidate = GetNextSibling(node);
+
+    if (!firstCandidate) {
+      MakeEmpty();
+      return NS_OK;
+    }
+  }
+
+  firstCandidate = GetDeepFirstChild(firstCandidate);
+
+  // confirm that this first possible contained node is indeed contained.  Else
+  // we have a range that does not fully contain any node.
+
+  bool nodeBefore, nodeAfter;
+  MOZ_ALWAYS_SUCCEEDS(nsRange::CompareNodeToRange(firstCandidate, mRange,
+                                                  &nodeBefore, &nodeAfter));
+
+  if (nodeBefore || nodeAfter) {
+    MakeEmpty();
+    return NS_OK;
+  }
+
+  // cool, we have the first node in the range.  Now we walk up its ancestors
+  // to find the most senior that is still in the range.  That's the real first
+  // node.
+  mFirst = GetTopAncestorInRange(firstCandidate);
+
+  // now to find the last node
+  offset = mRange->EndOffset();
+  int32_t numChildren = endContainer->GetChildCount();
+
+  if (offset > numChildren) {
+    // Can happen for text nodes
+    offset = numChildren;
+  }
+  if (!offset || !numChildren) {
+    node = endContainer;
+  } else {
+    lastCandidate = mRange->EndRef().Ref();
+    MOZ_ASSERT(lastCandidate == endContainer->GetChildAt_Deprecated(--offset));
+    NS_ASSERTION(lastCandidate,
+                 "tree traversal trouble in nsContentSubtreeIterator::Init");
+  }
+
+  if (!lastCandidate) {
+    // then lastCandidate is prev node before node
+    lastCandidate = GetPrevSibling(node);
+  }
+
+  if (!lastCandidate) {
+    MakeEmpty();
+    return NS_OK;
+  }
+
+  lastCandidate = GetDeepLastChild(lastCandidate);
+
+  // confirm that this last possible contained node is indeed contained.  Else
+  // we have a range that does not fully contain any node.
+
+  MOZ_ALWAYS_SUCCEEDS(nsRange::CompareNodeToRange(lastCandidate, mRange,
+                                                  &nodeBefore, &nodeAfter));
+
+  if (nodeBefore || nodeAfter) {
+    MakeEmpty();
+    return NS_OK;
+  }
+
+  // cool, we have the last node in the range.  Now we walk up its ancestors to
+  // find the most senior that is still in the range.  That's the real first
+  // node.
+  mLast = GetTopAncestorInRange(lastCandidate);
+
+  mCurNode = mFirst;
+
+  return NS_OK;
 }
 
-}  // namespace mozilla
+/****************************************************************
+ * nsContentSubtreeIterator overrides of ContentIterator routines
+ ****************************************************************/
+
+// we can't call PositionAt in a subtree iterator...
+void nsContentSubtreeIterator::First() {
+  mIsDone = mFirst == nullptr;
+
+  mCurNode = mFirst;
+}
+
+// we can't call PositionAt in a subtree iterator...
+void nsContentSubtreeIterator::Last() {
+  mIsDone = mLast == nullptr;
+
+  mCurNode = mLast;
+}
+
+void nsContentSubtreeIterator::Next() {
+  if (mIsDone || !mCurNode) {
+    return;
+  }
+
+  if (mCurNode == mLast) {
+    mIsDone = true;
+    return;
+  }
+
+  nsINode* nextNode = GetNextSibling(mCurNode);
+  NS_ASSERTION(nextNode, "No next sibling!?! This could mean deadlock!");
+
+  int32_t i = mEndNodes.IndexOf(nextNode);
+  while (i != -1) {
+    // as long as we are finding ancestors of the endpoint of the range,
+    // dive down into their children
+    nextNode = nextNode->GetFirstChild();
+    NS_ASSERTION(nextNode, "Iterator error, expected a child node!");
+
+    // should be impossible to get a null pointer.  If we went all the way
+    // down the child chain to the bottom without finding an interior node,
+    // then the previous node should have been the last, which was
+    // was tested at top of routine.
+    i = mEndNodes.IndexOf(nextNode);
+  }
+
+  mCurNode = nextNode;
+
+  // This shouldn't be needed, but since our selection code can put us
+  // in a situation where mLast is in generated content, we need this
+  // to stop the iterator when we've walked past past the last node!
+  mIsDone = mCurNode == nullptr;
+}
+
+void nsContentSubtreeIterator::Prev() {
+  // Prev should be optimized to use the mStartNodes, just as Next
+  // uses mEndNodes.
+  if (mIsDone || !mCurNode) {
+    return;
+  }
+
+  if (mCurNode == mFirst) {
+    mIsDone = true;
+    return;
+  }
 
-#endif  // #ifndef mozilla_ContentIterator_h
+  // If any of these function calls return null, so will all succeeding ones,
+  // so mCurNode will wind up set to null.
+  nsINode* prevNode = GetDeepFirstChild(mCurNode);
+
+  prevNode = PrevNode(prevNode);
+
+  prevNode = GetDeepLastChild(prevNode);
+
+  mCurNode = GetTopAncestorInRange(prevNode);
+
+  // This shouldn't be needed, but since our selection code can put us
+  // in a situation where mFirst is in generated content, we need this
+  // to stop the iterator when we've walked past past the first node!
+  mIsDone = mCurNode == nullptr;
+}
+
+nsresult nsContentSubtreeIterator::PositionAt(nsINode* aCurNode) {
+  NS_ERROR("Not implemented!");
+
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/****************************************************************
+ * nsContentSubtreeIterator helper routines
+ ****************************************************************/
+
+nsIContent* nsContentSubtreeIterator::GetTopAncestorInRange(nsINode* aNode) {
+  if (!aNode || !aNode->GetParentNode()) {
+    return nullptr;
+  }
+
+  // aNode has a parent, so it must be content.
+  nsIContent* content = aNode->AsContent();
+
+  // sanity check: aNode is itself in the range
+  bool nodeBefore, nodeAfter;
+  nsresult res =
+      nsRange::CompareNodeToRange(aNode, mRange, &nodeBefore, &nodeAfter);
+  NS_ASSERTION(NS_SUCCEEDED(res) && !nodeBefore && !nodeAfter,
+               "aNode isn't in mRange, or something else weird happened");
+  if (NS_FAILED(res) || nodeBefore || nodeAfter) {
+    return nullptr;
+  }
+
+  while (content) {
+    nsIContent* parent = content->GetParent();
+    // content always has a parent.  If its parent is the root, however --
+    // i.e., either it's not content, or it is content but its own parent is
+    // null -- then we're finished, since we don't go up to the root.
+    //
+    // We have to special-case this because CompareNodeToRange treats the root
+    // node differently -- see bug 765205.
+    if (!parent || !parent->GetParentNode()) {
+      return content;
+    }
+    MOZ_ALWAYS_SUCCEEDS(
+        nsRange::CompareNodeToRange(parent, mRange, &nodeBefore, &nodeAfter));
+
+    if (nodeBefore || nodeAfter) {
+      return content;
+    }
+    content = parent;
+  }
+
+  MOZ_CRASH("This should only be possible if aNode was null");
+}
--- a/dom/base/nsContentList.cpp
+++ b/dom/base/nsContentList.cpp
@@ -8,17 +8,16 @@
  * nsBaseContentList is a basic list of content nodes; nsContentList
  * is a commonly used NodeList implementation (used for
  * getElementsByTagName, some properties on HTMLDocument/Document, etc).
  */
 
 #include "nsContentList.h"
 #include "nsIContent.h"
 #include "mozilla/dom/Document.h"
-#include "mozilla/ContentIterator.h"
 #include "mozilla/dom/Element.h"
 #include "nsWrapperCacheInlines.h"
 #include "nsContentUtils.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsGkAtoms.h"
 #include "mozilla/dom/HTMLCollectionBinding.h"
 #include "mozilla/dom/NodeListBinding.h"
 #include "mozilla/Likely.h"
@@ -26,16 +25,17 @@
 #include "jsfriendapi.h"
 #include <algorithm>
 #include "mozilla/dom/NodeInfoInlines.h"
 #include "mozilla/MruCache.h"
 
 #include "PLDHashTable.h"
 
 #ifdef DEBUG_CONTENT_LIST
+#include "nsIContentIterator.h"
 #define ASSERT_IN_SYNC AssertInSync()
 #else
 #define ASSERT_IN_SYNC PR_BEGIN_MACRO PR_END_MACRO
 #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
@@ -885,42 +885,43 @@ 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();
 
-  PreContentIterator preOrderIter;
+  nsCOMPtr<nsIContentIterator> iter;
   if (mDeep) {
-    preOrderIter.Init(root);
-    preOrderIter.First();
+    iter = NS_NewPreContentIterator();
+    iter->Init(root);
+    iter->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 ? iter->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();
+      iter->Next();
     }
   }
 
   NS_ASSERTION(cnt == mElements.Length(), "Too few elements");
 }
 #endif
 
 //-----------------------------------------------------
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -93,16 +93,17 @@
 #include "FrameLayerBuilder.h"
 #include "nsDisplayList.h"
 #include "nsROCSSPrimitiveValue.h"
 #include "nsIBaseWindow.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "GeckoProfiler.h"
 #include "mozilla/Preferences.h"
+#include "nsIContentIterator.h"
 #include "nsIStyleSheetService.h"
 #include "nsContentPermissionHelper.h"
 #include "nsCSSPseudoElements.h"  // for CSSPseudoElementType
 #include "nsNetUtil.h"
 #include "HTMLImageElement.h"
 #include "HTMLCanvasElement.h"
 #include "mozilla/css/ImageLoader.h"
 #include "mozilla/layers/IAPZCTreeManager.h"  // for layers::ZoomToRectBehavior
new file mode 100644
--- /dev/null
+++ b/dom/base/nsIContentIterator.h
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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 __nsIContentIterator_h___
+#define __nsIContentIterator_h___
+
+#include "nsISupports.h"
+#include "nsCOMPtr.h"
+#include "mozilla/RangeBoundary.h"
+
+class nsINode;
+class nsRange;
+
+#define NS_ICONTENTITERATOR_IID                      \
+  {                                                  \
+    0x2550078e, 0xae87, 0x4914, {                    \
+      0xb3, 0x04, 0xe4, 0xd1, 0x46, 0x19, 0x3d, 0x5f \
+    }                                                \
+  }
+
+class nsIContentIterator : public nsISupports {
+ public:
+  NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICONTENTITERATOR_IID)
+
+  /* Initializes an iterator for the subtree rooted by the node aRoot
+   */
+  virtual nsresult Init(nsINode* aRoot) = 0;
+
+  /* Initializes an iterator for the subtree defined by the range aRange
+     Subclasses should make sure they implement both of these!
+   */
+  virtual nsresult Init(nsRange* aRange) = 0;
+
+  /* Initializes an iterator for the subtree between
+     aStartContainer/aStartOffset and aEndContainer/aEndOffset
+     Callers should guarantee that the start point and end point are in
+     document order.
+   */
+  virtual nsresult Init(nsINode* aStartContainer, uint32_t aStartOffset,
+                        nsINode* aEndContainer, uint32_t aEndOffset) = 0;
+
+  /* Initializes an iterator for the subtree between aStart and aEnd.
+     Callers should guarantee that the start point and end point are in
+     document order.
+   */
+  virtual nsresult Init(const mozilla::RawRangeBoundary& aStart,
+                        const mozilla::RawRangeBoundary& aEnd) = 0;
+
+  /** First will reset the list.
+   */
+  virtual void First() = 0;
+
+  /** Last will reset the list to the end.
+   */
+  virtual void Last() = 0;
+
+  /** Next will advance the list.
+   */
+  virtual void Next() = 0;
+
+  /** Prev will decrement the list.
+   */
+  virtual void Prev() = 0;
+
+  /** CurrentItem will return the current item, or null if the list is empty
+   *  @return the current node
+   */
+  virtual nsINode* GetCurrentNode() = 0;
+
+  /** return if the collection is at the end. that is the beginning following a
+   * call to Prev and it is the end of the list following a call to next
+   *  @return if the iterator is done.
+   */
+  virtual bool IsDone() = 0;
+
+  /** PositionAt will position the iterator to the supplied node
+   */
+  virtual nsresult PositionAt(nsINode* aCurNode) = 0;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIContentIterator, NS_ICONTENTITERATOR_IID)
+
+already_AddRefed<nsIContentIterator> NS_NewContentIterator();
+already_AddRefed<nsIContentIterator> NS_NewPreContentIterator();
+already_AddRefed<nsIContentIterator> NS_NewContentSubtreeIterator();
+
+#endif  // __nsIContentIterator_h___
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -55,16 +55,17 @@
 #include "nsFrameSelection.h"
 #include "nsGenericHTMLElement.h"
 #include "nsGkAtoms.h"
 #include "nsIAnonymousContentCreator.h"
 #include "nsAtom.h"
 #include "nsIBaseWindow.h"
 #include "nsICategoryManager.h"
 #include "nsIContentInlines.h"
+#include "nsIContentIterator.h"
 #include "nsIControllers.h"
 #include "mozilla/dom/Document.h"
 #include "nsIDOMEventListener.h"
 #include "nsILinkHandler.h"
 #include "mozilla/dom/NodeInfo.h"
 #include "mozilla/dom/NodeInfoInlines.h"
 #include "nsIPresShell.h"
 #include "nsIScriptError.h"
--- a/dom/base/nsIScriptableContentIterator.idl
+++ b/dom/base/nsIScriptableContentIterator.idl
@@ -5,17 +5,17 @@
 
 #include "nsISupports.idl"
 
 webidl Node;
 webidl Range;
 
 /**
  * nsIScriptableContentIterator is designed to testing concrete classes of
- * ContentIteratorBase.
+ * nsIContentIterator.
  */
 [scriptable, builtinclass, uuid(9f25fb2a-265f-44f9-a122-62bbf443239e)]
 interface nsIScriptableContentIterator : nsISupports
 {
   cenum IteratorType : 8 {
     NOT_INITIALIZED,
     POST_ORDER_ITERATOR,
     PRE_ORDER_ITERATOR,
@@ -25,48 +25,48 @@ interface nsIScriptableContentIterator :
   /**
    * You need to call initWith*() first.  Then, the instance of this interface
    * decides the type of iterator with its aType argument.  You can call
    * initWith*() multiple times, but you need to keep setting same type as
    * previous call.  If you set different type, these method with throw an
    * exception.
    */
 
-  // See ContentIteratorBase::Init(nsINode*)
+  // See nsIContentIterator::Init(nsINode*)
   void initWithRootNode(in nsIScriptableContentIterator_IteratorType aType,
                         in Node aRoot);
 
-  // See ContentIteratorBase::Init(nsRange*)
+  // See nsIContentIterator::Init(nsRange*)
   void initWithRange(in nsIScriptableContentIterator_IteratorType aType,
                      in Range aRange);
 
-  // See ContentIteratorBase::Init(nsINode*, uint32_t, nsINode*, uint32_t)
+  // See nsIContentIterator::Init(nsINode*, uint32_t, nsINode*, uint32_t)
   void initWithPositions(in nsIScriptableContentIterator_IteratorType aType,
                          in Node aStartContainer, in unsigned long aStartOffset,
                          in Node aEndContainer, in unsigned long aEndOffset);
 
-  // See ContentIteratorBase::First()
+  // See nsIContentIterator::First()
   void first();
 
-  // See ContentIteratorBase::Last()
+  // See nsIContentIterator::Last()
   void last();
 
-  // See ContentIteratorBase::Next()
+  // See nsIContentIterator::Next()
   void next();
 
-  // See ContentIteratorBase::Prev()
+  // See nsIContentIterator::Prev()
   void prev();
 
-  // See ContentIteratorBase::GetCurrentNode()
+  // See nsIContentIterator::GetCurrentNode()
   readonly attribute Node currentNode;
 
-  // See ContentIteratorBase::IsDone()
+  // See nsIContentIterator::IsDone()
   readonly attribute bool isDone;
 
-  // See ContentIteratorBase::PositionAt(nsINode*)
+  // See nsIContentIterator::PositionAt(nsINode*)
   void positionAt(in Node aNode);
 };
 
 %{C++
 #define SCRIPTABLE_CONTENT_ITERATOR_CID \
   { 0xf68037ec, 0x2790, 0x44c5, \
     { 0x8e, 0x5f, 0xdf, 0x5d, 0xa5, 0x8b, 0x93, 0xa7 } }
 #define SCRIPTABLE_CONTENT_ITERATOR_CONTRACTID \
--- a/dom/base/nsRange.cpp
+++ b/dom/base/nsRange.cpp
@@ -11,32 +11,31 @@
 #include "nscore.h"
 #include "nsRange.h"
 
 #include "nsString.h"
 #include "nsReadableUtils.h"
 #include "nsIContent.h"
 #include "mozilla/dom/Document.h"
 #include "nsError.h"
+#include "nsIContentIterator.h"
 #include "nsINodeList.h"
 #include "nsGkAtoms.h"
 #include "nsContentUtils.h"
 #include "nsTextFrame.h"
-#include "mozilla/ContentIterator.h"
 #include "mozilla/dom/CharacterData.h"
 #include "mozilla/dom/DocumentFragment.h"
 #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;
@@ -1487,26 +1486,26 @@ void nsRange::SelectNodeContents(nsINode
 // The Subtree Content Iterator only returns subtrees that are
 // completely within a given range. It doesn't return a CharacterData
 // node that contains either the start or end point of the range.,
 // nor does it return element nodes when nothing in the element is selected.
 // We need an iterator that will also include these start/end points
 // so that our methods/algorithms aren't cluttered with special
 // case code that tries to include these points while iterating.
 //
-// The RangeSubtreeIterator class mimics the ContentSubtreeIterator
+// The RangeSubtreeIterator class mimics the nsIContentIterator
 // 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 };
 
-  UniquePtr<ContentSubtreeIterator> mSubtreeIter;
+  nsCOMPtr<nsIContentIterator> mIter;
   RangeSubtreeIterState mIterState;
 
   nsCOMPtr<nsINode> mStart;
   nsCOMPtr<nsINode> mEnd;
 
  public:
   RangeSubtreeIterator() : mIterState(eDone) {}
   ~RangeSubtreeIterator() {}
@@ -1558,27 +1557,27 @@ 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 = MakeUnique<ContentSubtreeIterator>();
-
-    nsresult res = mSubtreeIter->Init(aRange);
+    mIter = NS_NewContentSubtreeIterator();
+
+    nsresult res = mIter->Init(aRange);
     if (NS_FAILED(res)) return res;
 
-    if (mSubtreeIter->IsDone()) {
+    if (mIter->IsDone()) {
       // The subtree iterator thinks there's nothing
       // to iterate over, so just free it up so we
       // don't accidentally call into it.
 
-      mSubtreeIter = nullptr;
+      mIter = nullptr;
     }
   }
 
   // Initialize the iterator by calling First().
   // Note that we are ignoring the return value on purpose!
 
   First();
 
@@ -1587,86 +1586,86 @@ nsresult RangeSubtreeIterator::Init(nsRa
 
 already_AddRefed<nsINode> RangeSubtreeIterator::GetCurrentNode() {
   nsCOMPtr<nsINode> node;
 
   if (mIterState == eUseStart && mStart) {
     node = mStart;
   } else if (mIterState == eUseEnd && mEnd) {
     node = mEnd;
-  } else if (mIterState == eUseIterator && mSubtreeIter) {
-    node = mSubtreeIter->GetCurrentNode();
+  } else if (mIterState == eUseIterator && mIter) {
+    node = mIter->GetCurrentNode();
   }
 
   return node.forget();
 }
 
 void RangeSubtreeIterator::First() {
   if (mStart)
     mIterState = eUseStart;
-  else if (mSubtreeIter) {
-    mSubtreeIter->First();
+  else if (mIter) {
+    mIter->First();
 
     mIterState = eUseIterator;
   } else if (mEnd)
     mIterState = eUseEnd;
   else
     mIterState = eDone;
 }
 
 void RangeSubtreeIterator::Last() {
   if (mEnd)
     mIterState = eUseEnd;
-  else if (mSubtreeIter) {
-    mSubtreeIter->Last();
+  else if (mIter) {
+    mIter->Last();
 
     mIterState = eUseIterator;
   } else if (mStart)
     mIterState = eUseStart;
   else
     mIterState = eDone;
 }
 
 void RangeSubtreeIterator::Next() {
   if (mIterState == eUseStart) {
-    if (mSubtreeIter) {
-      mSubtreeIter->First();
+    if (mIter) {
+      mIter->First();
 
       mIterState = eUseIterator;
     } else if (mEnd)
       mIterState = eUseEnd;
     else
       mIterState = eDone;
   } else if (mIterState == eUseIterator) {
-    mSubtreeIter->Next();
-
-    if (mSubtreeIter->IsDone()) {
+    mIter->Next();
+
+    if (mIter->IsDone()) {
       if (mEnd)
         mIterState = eUseEnd;
       else
         mIterState = eDone;
     }
   } else
     mIterState = eDone;
 }
 
 void RangeSubtreeIterator::Prev() {
   if (mIterState == eUseEnd) {
-    if (mSubtreeIter) {
-      mSubtreeIter->Last();
+    if (mIter) {
+      mIter->Last();
 
       mIterState = eUseIterator;
     } else if (mStart)
       mIterState = eUseStart;
     else
       mIterState = eDone;
   } else if (mIterState == eUseIterator) {
-    mSubtreeIter->Prev();
-
-    if (mSubtreeIter->IsDone()) {
+    mIter->Prev();
+
+    if (mIter->IsDone()) {
       if (mStart)
         mIterState = eUseStart;
       else
         mIterState = eDone;
     }
   } else
     mIterState = eDone;
 }
@@ -2612,29 +2611,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.
   */
 
-  PostContentIterator postOrderIter;
-  nsresult rv = postOrderIter.Init(this);
+  nsCOMPtr<nsIContentIterator> iter = NS_NewContentIterator();
+  nsresult rv = iter->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();
+  while (!iter->IsDone()) {
+    nsINode* n = iter->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
     {
@@ -2647,16 +2646,18 @@ void nsRange::ToString(nsAString& aRetur
                  mEnd.Container()) {  // only include text before end offset
         textNode->SubstringData(0, mEnd.Offset(), tempString, IgnoreErrors());
         aReturn += tempString;
       } else {  // grab the whole kit-n-kaboodle
         textNode->GetData(tempString);
         aReturn += tempString;
       }
     }
+
+    iter->Next();
   }
 
 #ifdef DEBUG_range
   printf("End Range dump: -----------------------\n");
 #endif /* DEBUG */
 }
 
 void nsRange::Detach() {}
@@ -3053,33 +3054,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) {
-    PreContentIterator preOrderIter;
-    nsresult rv = preOrderIter.Init(range);
+    nsCOMPtr<nsIContentIterator> iter = NS_NewPreContentIterator();
+    nsresult rv = iter->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 = iter->GetCurrentNode();
+      iter->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).
@@ -3095,17 +3096,17 @@ void nsRange::ExcludeNonSelectableNodes(
           }
         }
       }
 
       if (!selectable) {
         if (!firstNonSelectableContent) {
           firstNonSelectableContent = content;
         }
-        if (preOrderIter.IsDone() && seenSelectable) {
+        if (iter->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.
@@ -3151,17 +3152,17 @@ void nsRange::ExcludeNonSelectableNodes(
         }
       } else {
         seenSelectable = true;
         if (!added) {
           added = true;
           aOutRanges->AppendElement(range);
         }
       }
-      if (preOrderIter.IsDone()) {
+      if (iter->IsDone()) {
         return;
       }
     }
   }
 }
 
 struct InnerTextAccumulator {
   explicit InnerTextAccumulator(mozilla::dom::DOMString& aValue)
--- a/dom/base/test/test_bug976673.html
+++ b/dom/base/test/test_bug976673.html
@@ -23,17 +23,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <button id="button">set focus</button>
 <iframe id="iframe" src="http://example.org:80/tests/dom/base/test/iframe_bug976673.html"></iframe>
 <script>
 
 SimpleTest.waitForExplicitFinish();
 
 // In e10s mode, ContentCacheInChild tries to retrieve selected text and
 // caret position when IMEContentObserver notifies IME of focus.  At this time,
-// we hit assertion in ContentIterator.
+// we hit assertion in nsContentIterator.
 SimpleTest.expectAssertions(0, 6);
 
 window.addEventListener("mousedown", function (aEvent) { aEvent.preventDefault(); });
 
 function testSetFocus(aEventType, aCallback)
 {
   var description = "Setting focus from " + aEventType + " handler: ";
 
--- a/dom/base/test/test_content_iterator_subtree.html
+++ b/dom/base/test/test_content_iterator_subtree.html
@@ -75,17 +75,17 @@ function getNodeDescription(aNode) {
   }
 }
 
 SimpleTest.waitForExplicitFinish();
 SimpleTest.waitForFocus(function () {
   let iter = createContentIterator();
 
   /**
-   * FYI: ContentSubtreeIterator does not support initWithRootNode() nor positionAt().
+   * FYI: nsContentSubtreeIterator does not support initWithRootNode() nor positionAt().
    */
 
   /**
    * Basic behavior tests of first(), last(), prev() and next() after initialized with a range which selects empty element.
    */
   document.body.innerHTML = "<div></div>";
   let range = document.createRange();
   range.selectNode(document.body.firstChild);
--- a/dom/events/ContentEventHandler.cpp
+++ b/dom/events/ContentEventHandler.cpp
@@ -1,31 +1,30 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 #include "ContentEventHandler.h"
-
-#include "mozilla/ContentIterator.h"
 #include "mozilla/IMEStateManager.h"
 #include "mozilla/TextComposition.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/HTMLUnknownElement.h"
 #include "mozilla/dom/Selection.h"
 #include "nsCaret.h"
 #include "nsCOMPtr.h"
 #include "nsContentUtils.h"
 #include "nsCopySupport.h"
 #include "nsElementTable.h"
 #include "nsFocusManager.h"
 #include "nsFontMetrics.h"
 #include "nsFrameSelection.h"
+#include "nsIContentIterator.h"
 #include "nsIPresShell.h"
 #include "nsIFrame.h"
 #include "nsIObjectFrame.h"
 #include "nsLayoutUtils.h"
 #include "nsPresContext.h"
 #include "nsQueryObject.h"
 #include "nsRange.h"
 #include "nsTextFragment.h"
@@ -195,17 +194,17 @@ nsresult ContentEventHandler::RawRange::
 // 2. End of range:
 //   2.1. Cases: ]textNode or text]Node or textNode]
 //        When a text node is end of a range, end node is the text node and
 //        end offset is any number between 0 and the length of the text.
 //   2.2. Case: ]<element>
 //        When before an element node (meaning before the open tag of the
 //        element) is end of a range, end node is previous node causing text.
 //        Note that this case shouldn't be handled directly.  If rule 2.1 and
-//        2.3 are handled correctly, the loop with ContentIterator shouldn't
+//        2.3 are handled correctly, the loop with nsContentIterator shouldn't
 //        reach the element node since the loop should've finished already at
 //        handling the last node which caused some text.
 //   2.3. Case: <element>]
 //        When a line break is caused before a non-empty element node and it's
 //        end of a range, end node is the element and end offset is 0.
 //        (i.e., including open tag of the element)
 //   2.4. Cases: <element/>]
 //        When after an empty element node is end of a range, end node is
@@ -726,24 +725,23 @@ 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;
   }
 
-  PreContentIterator preOrderIter;
-  nsresult rv =
-      preOrderIter.Init(aRawRange.Start().AsRaw(), aRawRange.End().AsRaw());
+  nsCOMPtr<nsIContentIterator> iter = NS_NewPreContentIterator();
+  nsresult rv = iter->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 (; !iter->IsDone(); iter->Next()) {
+    nsINode* node = iter->GetCurrentNode();
     if (NS_WARN_IF(!node)) {
       break;
     }
     if (!node->IsContent()) {
       continue;
     }
     nsIContent* content = node->AsContent();
 
@@ -887,24 +885,23 @@ 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;
-  PreContentIterator preOrderIter;
-  nsresult rv =
-      preOrderIter.Init(aRawRange.Start().AsRaw(), aRawRange.End().AsRaw());
+  nsCOMPtr<nsIContentIterator> iter = NS_NewPreContentIterator();
+  nsresult rv = iter->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 (; !iter->IsDone(); iter->Next()) {
+    nsINode* node = iter->GetCurrentNode();
     if (NS_WARN_IF(!node)) {
       break;
     }
     if (!node->IsContent()) {
       continue;
     }
     nsIContent* content = node->AsContent();
 
@@ -1013,27 +1010,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;
     }
   }
 
-  PreContentIterator preOrderIter;
-  nsresult rv = preOrderIter.Init(mRootContent);
+  nsCOMPtr<nsIContentIterator> iter = NS_NewPreContentIterator();
+  nsresult rv = iter->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 (; !iter->IsDone(); iter->Next()) {
+    nsINode* node = iter->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 +1442,23 @@ 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;
-  PreContentIterator preOrderIter;
-  nsresult rv =
-      preOrderIter.Init(aRawRange.Start().AsRaw(), aRawRange.End().AsRaw());
+  nsCOMPtr<nsIContentIterator> iter = NS_NewPreContentIterator();
+  nsresult rv = iter->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 (; !iter->IsDone(); iter->Next()) {
+    nsINode* node = iter->GetCurrentNode();
     if (NS_WARN_IF(!node)) {
       break;
     }
 
     if (!node->IsContent()) {
       continue;
     }
 
@@ -1494,19 +1490,18 @@ ContentEventHandler::GetFirstFrameInRang
   GetFrameForTextRect(nodePosition.Container(), nodePosition.Offset(), true,
                       &firstFrame);
   return FrameAndNodeOffset(firstFrame, nodePosition.Offset());
 }
 
 ContentEventHandler::FrameAndNodeOffset
 ContentEventHandler::GetLastFrameInRangeForTextRect(const RawRange& aRawRange) {
   NodePosition nodePosition;
-  PreContentIterator preOrderIter;
-  nsresult rv =
-      preOrderIter.Init(aRawRange.Start().AsRaw(), aRawRange.End().AsRaw());
+  nsCOMPtr<nsIContentIterator> iter = NS_NewPreContentIterator();
+  nsresult rv = iter->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 +1528,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 (iter->Last(); !iter->IsDone(); iter->Prev()) {
+    nsINode* node = iter->GetCurrentNode();
     if (NS_WARN_IF(!node)) {
       break;
     }
 
     if (!node->IsContent() || node == nextNodeOfRangeEnd) {
       continue;
     }
 
@@ -2105,18 +2100,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
-  PostContentIterator postOrderIter;
-  rv = postOrderIter.Init(rawRange.Start().AsRaw(), rawRange.End().AsRaw());
+  nsCOMPtr<nsIContentIterator> iter = NS_NewContentIterator();
+  rv = iter->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 +2288,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();
+        iter->Next();
+        nsINode* node = iter->GetCurrentNode();
         if (!node) {
           break;
         }
         if (!node->IsContent()) {
           continue;
         }
         nsIFrame* primaryFrame = node->AsContent()->GetPrimaryFrame();
         // The node may be hidden by CSS.
@@ -2314,17 +2309,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 && !iter->IsDone());
       if (!frame) {
         break;
       }
     }
     if (frame->IsTextFrame()) {
       frameRect.SetRect(nsPoint(0, 0), frame->GetRect().Size());
     } else {
       MOZ_ASSERT(frame->IsBrFrame());
@@ -2653,17 +2648,19 @@ nsresult ContentEventHandler::OnQueryDOM
     return NS_ERROR_INVALID_ARG;
   }
 
   if (aStartPosition == aEndPosition) {
     *aLength = 0;
     return NS_OK;
   }
 
-  PreContentIterator preOrderIter;
+  // Don't create nsContentIterator instance until it's really necessary since
+  // destroying without initializing causes unexpected NS_ASSERTION() call.
+  nsCOMPtr<nsIContentIterator> iter;
 
   // 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
@@ -2677,17 +2674,18 @@ 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");
-    nsresult rv = preOrderIter.Init(aStartPosition.Container());
+    iter = NS_NewPreContentIterator();
+    nsresult rv = iter->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;
@@ -2721,44 +2719,45 @@ 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;
       }
-      rv = preOrderIter.Init(prevRawRange.Start().AsRaw(),
-                             prevRawRange.End().AsRaw());
+      iter = NS_NewPreContentIterator();
+      rv = iter->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;
       }
-      rv = preOrderIter.Init(prevRawRange.Start().AsRaw(),
-                             prevRawRange.End().AsRaw());
+      iter = NS_NewPreContentIterator();
+      rv = iter->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
-      rv = preOrderIter.Init(aRootContent);
+      iter = NS_NewPreContentIterator();
+      rv = iter->Init(aRootContent);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
     }
   }
 
   *aLength = 0;
-  for (; !preOrderIter.IsDone(); preOrderIter.Next()) {
-    nsINode* node = preOrderIter.GetCurrentNode();
+  for (; !iter->IsDone(); iter->Next()) {
+    nsINode* node = iter->GetCurrentNode();
     if (NS_WARN_IF(!node)) {
       break;
     }
     if (!node->IsContent()) {
       continue;
     }
     nsIContent* content = node->AsContent();
 
@@ -2788,17 +2787,17 @@ nsresult ContentEventHandler::OnQueryDOM
     }
   }
   return NS_OK;
 }
 
 nsresult ContentEventHandler::GetStartOffset(const RawRange& aRawRange,
                                              uint32_t* aOffset,
                                              LineBreakType aLineBreakType) {
-  // To match the "no skip start" hack in ContentIterator::Init, when range
+  // To match the "no skip start" hack in nsContentIterator::Init, when range
   // offset is 0 and the range node is not a container, we have to assume the
   // range _includes_ the node, which means the start offset should _not_
   // include the node.
   //
   // For example, for this content: <br>abc, and range (<br>, 0)-("abc", 1), the
   // range includes the linebreak from <br>, so the start offset should _not_
   // include <br>, and the start offset should be 0.
   //
--- a/dom/events/IMEContentObserver.cpp
+++ b/dom/events/IMEContentObserver.cpp
@@ -1546,17 +1546,17 @@ void IMEContentObserver::FlushMergeableN
   //       another change.
 
   MOZ_LOG(sIMECOLog, LogLevel::Debug,
           ("0x%p IMEContentObserver::FlushMergeableNotifications(), "
            "creating IMENotificationSender...",
            this));
 
   // If contents in selection range is modified, the selection range still
-  // has removed node from the tree.  In such case, ContentIterator won't
+  // has removed node from the tree.  In such case, nsContentIterator won't
   // work well.  Therefore, we shouldn't use AddScriptRunnder() here since
   // it may kick runnable event immediately after DOM tree is changed but
   // the selection range isn't modified yet.
   mQueuedSender = new IMENotificationSender(this);
   mQueuedSender->Dispatch(mDocShell);
   MOZ_LOG(sIMECOLog, LogLevel::Debug,
           ("0x%p IMEContentObserver::FlushMergeableNotifications(), "
            "finished",
--- a/editor/libeditor/DeleteRangeTransaction.cpp
+++ b/editor/libeditor/DeleteRangeTransaction.cpp
@@ -3,25 +3,25 @@
  * 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/. */
 
 #include "DeleteRangeTransaction.h"
 
 #include "DeleteNodeTransaction.h"
 #include "DeleteTextTransaction.h"
 #include "mozilla/Assertions.h"
-#include "mozilla/ContentIterator.h"
+#include "mozilla/EditorBase.h"
 #include "mozilla/dom/Selection.h"
-#include "mozilla/EditorBase.h"
 #include "mozilla/mozalloc.h"
 #include "mozilla/RangeBoundary.h"
 #include "nsCOMPtr.h"
 #include "nsDebug.h"
 #include "nsError.h"
 #include "nsIContent.h"
+#include "nsIContentIterator.h"
 #include "nsINode.h"
 #include "nsAString.h"
 
 namespace mozilla {
 
 using namespace dom;
 
 DeleteRangeTransaction::DeleteRangeTransaction(EditorBase& aEditorBase,
@@ -209,35 +209,36 @@ nsresult DeleteRangeTransaction::CreateT
 }
 
 nsresult DeleteRangeTransaction::CreateTxnsToDeleteNodesBetween(
     nsRange* aRangeToDelete) {
   if (NS_WARN_IF(!mEditorBase)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  ContentSubtreeIterator subtreeIter;
-  nsresult rv = subtreeIter.Init(aRangeToDelete);
+  nsCOMPtr<nsIContentIterator> iter = NS_NewContentSubtreeIterator();
+
+  nsresult rv = iter->Init(aRangeToDelete);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  while (!subtreeIter.IsDone()) {
-    nsCOMPtr<nsINode> node = subtreeIter.GetCurrentNode();
+  while (!iter->IsDone()) {
+    nsCOMPtr<nsINode> node = iter->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();
+    iter->Next();
   }
   return NS_OK;
 }
 
 }  // namespace mozilla
--- a/editor/libeditor/EditorUtils.cpp
+++ b/editor/libeditor/EditorUtils.cpp
@@ -1,76 +1,80 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 #include "mozilla/EditorUtils.h"
 
-#include "mozilla/ContentIterator.h"
 #include "mozilla/EditorDOMPoint.h"
 #include "mozilla/OwningNonNull.h"
 #include "mozilla/dom/Selection.h"
 #include "nsComponentManagerUtils.h"
 #include "nsError.h"
 #include "nsIContent.h"
+#include "nsIContentIterator.h"
 #include "nsIDocShell.h"
 #include "mozilla/dom/Document.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsINode.h"
 
 class nsISupports;
 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)
-    : mIter(&mPostOrderIter) {
+DOMIterator::DOMIterator(
+    nsINode& aNode MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) {
   MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+  mIter = NS_NewContentIterator();
   DebugOnly<nsresult> rv = mIter->Init(&aNode);
   MOZ_ASSERT(NS_SUCCEEDED(rv));
 }
 
 nsresult DOMIterator::Init(nsRange& aRange) {
+  mIter = NS_NewContentIterator();
   return mIter->Init(&aRange);
 }
 
-DOMIterator::DOMIterator(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
-    : mIter(&mPostOrderIter) {
+DOMIterator::DOMIterator(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL) {
   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) {
-  mIter = &mSubtreeIter;
+    : DOMIterator(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT) {}
+
+nsresult DOMSubtreeIterator::Init(nsRange& aRange) {
+  mIter = NS_NewContentSubtreeIterator();
+  return mIter->Init(&aRange);
 }
 
-nsresult DOMSubtreeIterator::Init(nsRange& aRange) {
-  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) {
--- a/editor/libeditor/EditorUtils.h
+++ b/editor/libeditor/EditorUtils.h
@@ -1,28 +1,28 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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_EditorUtils_h
 #define mozilla_EditorUtils_h
 
-#include "mozilla/ContentIterator.h"
 #include "mozilla/dom/Selection.h"
 #include "mozilla/EditAction.h"
 #include "mozilla/EditorBase.h"
 #include "mozilla/EditorDOMPoint.h"
 #include "mozilla/GuardObjects.h"
 #include "nsCOMPtr.h"
 #include "nsDebug.h"
 #include "nsIEditor.h"
 #include "nscore.h"
 
 class nsAtom;
+class nsIContentIterator;
 class nsISimpleEnumerator;
 class nsITransferable;
 class nsRange;
 
 namespace mozilla {
 template <class T>
 class OwningNonNull;
 
@@ -445,41 +445,35 @@ 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() = default;
+  virtual ~DOMIterator();
 
   nsresult Init(nsRange& aRange);
 
   void AppendList(
       const BoolDomIterFunctor& functor,
       nsTArray<mozilla::OwningNonNull<nsINode>>& arrayOfNodes) const;
 
  protected:
-  ContentIteratorBase* mIter;
-  PostContentIterator mPostOrderIter;
+  nsCOMPtr<nsIContentIterator> mIter;
   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 class MOZ_RAII DOMSubtreeIterator final : public DOMIterator {
  public:
   explicit DOMSubtreeIterator(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
-  virtual ~DOMSubtreeIterator() = default;
+  virtual ~DOMSubtreeIterator();
 
   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
@@ -7,17 +7,16 @@
 #include "HTMLEditRules.h"
 
 #include <stdlib.h>
 
 #include "HTMLEditUtils.h"
 #include "TextEditUtils.h"
 #include "WSRunObject.h"
 #include "mozilla/Assertions.h"
-#include "mozilla/ContentIterator.h"
 #include "mozilla/CSSEditUtils.h"
 #include "mozilla/EditAction.h"
 #include "mozilla/EditorDOMPoint.h"
 #include "mozilla/EditorUtils.h"
 #include "mozilla/HTMLEditor.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/Move.h"
 #include "mozilla/Preferences.h"
@@ -35,16 +34,17 @@
 #include "nsComponentManagerUtils.h"
 #include "nsContentUtils.h"
 #include "nsDebug.h"
 #include "nsError.h"
 #include "nsGkAtoms.h"
 #include "nsAtom.h"
 #include "nsHTMLDocument.h"
 #include "nsIContent.h"
+#include "nsIContentIterator.h"
 #include "nsID.h"
 #include "nsIFrame.h"
 #include "nsIHTMLAbsPosEditor.h"
 #include "nsINode.h"
 #include "nsLiteralString.h"
 #include "nsRange.h"
 #include "nsReadableUtils.h"
 #include "nsString.h"
@@ -9432,28 +9432,30 @@ 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.
 
-  PostContentIterator postOrderIter;
-  nsresult rv = postOrderIter.Init(mDocChangeRange);
+  // need an iterator
+  nsCOMPtr<nsIContentIterator> iter = NS_NewContentIterator();
+
+  nsresult rv = iter->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();
+  while (!iter->IsDone()) {
+    OwningNonNull<nsINode> node = *iter->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) {
@@ -9508,16 +9510,18 @@ nsresult HTMLEditRules::RemoveEmptyNodes
         }
       }
 
       if (!isEmptyNode && parent) {
         // put parent on skip list
         skipList.AppendElement(*parent);
       }
     }
+
+    iter->Next();
   }
 
   // now delete the empty nodes
   for (OwningNonNull<nsINode>& delNode : arrayOfEmptyNodes) {
     if (HTMLEditorRef().IsModifiableNode(delNode)) {
       rv = HTMLEditorRef().DeleteNodeWithTransaction(*delNode);
       if (NS_WARN_IF(!CanHandleEditAction())) {
         return NS_ERROR_EDITOR_DESTROYED;
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 #include "mozilla/HTMLEditor.h"
 
 #include "mozilla/ComposerCommandsUpdater.h"
-#include "mozilla/ContentIterator.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/EditAction.h"
 #include "mozilla/EditorDOMPoint.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/mozInlineSpellChecker.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/TextEvents.h"
 
@@ -30,16 +29,17 @@
 #include "mozilla/dom/DocumentInlines.h"
 #include "nsISelectionController.h"
 #include "nsILinkHandler.h"
 #include "nsIInlineSpellChecker.h"
 
 #include "mozilla/css/Loader.h"
 
 #include "nsIContent.h"
+#include "nsIContentIterator.h"
 #include "nsIMutableArray.h"
 #include "nsContentUtils.h"
 #include "nsIDocumentEncoder.h"
 #include "nsGenericHTMLElement.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
 #include "nsFocusManager.h"
 #include "nsPIDOMWindow.h"
@@ -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
-  PostContentIterator postOrderIter;
-  nsresult rv = postOrderIter.Init(table);
+  nsCOMPtr<nsIContentIterator> iter = NS_NewContentIterator();
+  nsresult rv = iter->Init(table);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
-  // position postOrderIter at block
-  rv = postOrderIter.PositionAt(cellElement);
+  // position iter at block
+  rv = iter->PositionAt(cellElement);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   nsCOMPtr<nsINode> node;
   do {
     if (inIsShift) {
-      postOrderIter.Prev();
+      iter->Prev();
     } else {
-      postOrderIter.Next();
+      iter->Next();
     }
 
-    node = postOrderIter.GetCurrentNode();
+    node = iter->GetCurrentNode();
 
     if (node && HTMLEditUtils::IsTableCell(node) &&
         GetEnclosingTable(node) == table) {
       CollapseSelectionToDeepestNonTableFirstChild(node);
       *outHandled = true;
       return NS_OK;
     }
-  } while (!postOrderIter.IsDone());
+  } while (!iter->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,21 @@ already_AddRefed<Element> HTMLEditor::Ge
       }
     }
   }
 
   if (SelectionRefPtr()->IsCollapsed()) {
     return nullptr;
   }
 
-  PostContentIterator postOrderIter;
-  postOrderIter.Init(firstRange);
+  nsCOMPtr<nsIContentIterator> iter = NS_NewContentIterator();
+  iter->Init(firstRange);
 
   RefPtr<Element> lastElementInRange;
-  for (nsINode* lastNodeInRange = nullptr; !postOrderIter.IsDone();
-       postOrderIter.Next()) {
+  for (nsINode* lastNodeInRange = nullptr; !iter->IsDone(); iter->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 +2803,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 = iter->GetCurrentNode();
     MOZ_ASSERT(currentNode);
     if (lastNodeInRange && lastNodeInRange->GetParentNode() != currentNode &&
         lastNodeInRange->GetNextSibling() != currentNode) {
       return nullptr;
     }
 
     lastNodeInRange = currentNode;
 
@@ -3057,33 +3056,34 @@ 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;
   }
 
+  nsCOMPtr<nsIContentIterator> iter = NS_NewContentIterator();
   RefPtr<Document> doc = GetDocument();
   NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED);
 
-  PostContentIterator postOrderIter;
-  postOrderIter.Init(doc->GetRootElement());
+  iter->Init(doc->GetRootElement());
 
   // loop through the content iterator for each content node
-  for (; !postOrderIter.IsDone(); postOrderIter.Next()) {
-    nsCOMPtr<nsINode> node = postOrderIter.GetCurrentNode();
+  while (!iter->IsDone()) {
+    nsCOMPtr<nsINode> node = iter->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);
       }
     }
+    iter->Next();
   }
 
   nodes.forget(aNodeList);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HTMLEditor::AddOverrideStyleSheet(const nsAString& aURL) {
@@ -3773,24 +3773,28 @@ 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
-  ContentSubtreeIterator subtreeIter;
-  subtreeIter.Init(aInRange);
-  for (; !subtreeIter.IsDone(); subtreeIter.Next()) {
-    nsINode* node = subtreeIter.GetCurrentNode();
+  nsCOMPtr<nsIContentIterator> iter = NS_NewContentSubtreeIterator();
+
+  iter->Init(aInRange);
+
+  while (!iter->IsDone()) {
+    nsINode* node = iter->GetCurrentNode();
     if (node->NodeType() == nsINode::TEXT_NODE &&
         IsEditable(node->AsContent())) {
       textNodes.AppendElement(node);
     }
+
+    iter->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];
@@ -4431,28 +4435,29 @@ 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).
 
+        OwningNonNull<nsIContentIterator> iter = NS_NewContentSubtreeIterator();
+
         nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
         nsCOMPtr<nsINode> node;
 
         // Iterate range and build up array
-        ContentSubtreeIterator subtreeIter;
-        rv = subtreeIter.Init(range);
+        rv = iter->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 (; !iter->IsDone(); iter->Next()) {
+            node = iter->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
@@ -4,17 +4,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/HTMLEditor.h"
 
 #include "HTMLEditUtils.h"
 #include "TextEditUtils.h"
 #include "TypeInState.h"
 #include "mozilla/Assertions.h"
-#include "mozilla/ContentIterator.h"
 #include "mozilla/EditAction.h"
 #include "mozilla/EditorUtils.h"
 #include "mozilla/SelectionState.h"
 #include "mozilla/TextEditRules.h"
 #include "mozilla/dom/Selection.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/mozalloc.h"
 #include "nsAString.h"
@@ -22,16 +21,17 @@
 #include "nsCOMPtr.h"
 #include "nsCaseTreatment.h"
 #include "nsComponentManagerUtils.h"
 #include "nsDebug.h"
 #include "nsError.h"
 #include "nsGkAtoms.h"
 #include "nsAtom.h"
 #include "nsIContent.h"
+#include "nsIContentIterator.h"
 #include "nsNameSpaceManager.h"
 #include "nsINode.h"
 #include "nsISupportsImpl.h"
 #include "nsLiteralString.h"
 #include "nsRange.h"
 #include "nsReadableUtils.h"
 #include "nsString.h"
 #include "nsStringFwd.h"
@@ -170,27 +170,28 @@ 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).
 
+      OwningNonNull<nsIContentIterator> iter = NS_NewContentSubtreeIterator();
+
       nsTArray<OwningNonNull<nsIContent>> arrayOfNodes;
 
       // Iterate range and build up array
-      ContentSubtreeIterator subtreeIter;
-      rv = subtreeIter.Init(range);
+      rv = iter->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 (; !iter->IsDone(); iter->Next()) {
+          OwningNonNull<nsINode> node = *iter->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
@@ -1035,32 +1036,28 @@ nsresult HTMLEditor::GetInlinePropertyBa
 
       isSet = IsTextPropertySetByContent(collapsedNode, &aProperty, aAttribute,
                                          aValue, outValue);
       *aFirst = *aAny = *aAll = isSet;
       return NS_OK;
     }
 
     // Non-collapsed selection
+    nsCOMPtr<nsIContentIterator> iter = NS_NewContentIterator();
 
     nsAutoString firstValue, theValue;
 
     nsCOMPtr<nsINode> endNode = range->GetEndContainer();
     int32_t endOffset = range->EndOffset();
 
-    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()) {
+    for (iter->Init(range); !iter->IsDone(); iter->Next()) {
+      if (!iter->GetCurrentNode()->IsContent()) {
         continue;
       }
-      nsCOMPtr<nsIContent> content =
-          postOrderIter.GetCurrentNode()->AsContent();
+      nsCOMPtr<nsIContent> content = iter->GetCurrentNode()->AsContent();
 
       if (content->IsHTMLElement(nsGkAtoms::body)) {
         break;
       }
 
       // just ignore any non-editable nodes
       if (content->GetAsText() &&
           (!IsEditable(content) || IsEmptyTextNode(*content))) {
@@ -1339,26 +1336,23 @@ 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.
+        nsCOMPtr<nsIContentIterator> iter = NS_NewContentSubtreeIterator();
 
         nsTArray<OwningNonNull<nsIContent>> arrayOfNodes;
 
         // Iterate range and build up array
-        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();
+        for (iter->Init(range); !iter->IsDone(); iter->Next()) {
+          nsCOMPtr<nsINode> node = iter->GetCurrentNode();
           if (NS_WARN_IF(!node)) {
             return NS_ERROR_FAILURE;
           }
           if (IsEditable(node) && node->IsContent()) {
             arrayOfNodes.AppendElement(*node->AsContent());
           }
         }
 
@@ -1489,27 +1483,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).
 
+      OwningNonNull<nsIContentIterator> iter = NS_NewContentSubtreeIterator();
+
       // Iterate range and build up array
-      ContentSubtreeIterator subtreeIter;
-      rv = subtreeIter.Init(range);
+      rv = iter->Init(range);
       if (NS_SUCCEEDED(rv)) {
         nsTArray<OwningNonNull<nsIContent>> arrayOfNodes;
-        for (; !subtreeIter.IsDone(); subtreeIter.Next()) {
-          if (NS_WARN_IF(!subtreeIter.GetCurrentNode()->IsContent())) {
+        for (; !iter->IsDone(); iter->Next()) {
+          if (NS_WARN_IF(!iter->GetCurrentNode()->IsContent())) {
             return NS_ERROR_FAILURE;
           }
-          OwningNonNull<nsIContent> node =
-              *subtreeIter.GetCurrentNode()->AsContent();
+          OwningNonNull<nsIContent> node = *iter->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
@@ -6,17 +6,16 @@
 #include "mozilla/TextEditor.h"
 
 #include "EditAggregateTransaction.h"
 #include "HTMLEditRules.h"
 #include "InternetCiter.h"
 #include "TextEditUtils.h"
 #include "gfxFontUtils.h"
 #include "mozilla/Assertions.h"
-#include "mozilla/ContentIterator.h"
 #include "mozilla/EditAction.h"
 #include "mozilla/EditorDOMPoint.h"
 #include "mozilla/HTMLEditor.h"
 #include "mozilla/IMEStateManager.h"
 #include "mozilla/mozalloc.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/TextEditRules.h"
 #include "mozilla/TextComposition.h"
@@ -35,16 +34,17 @@
 #include "nsCopySupport.h"
 #include "nsDebug.h"
 #include "nsDependentSubstring.h"
 #include "nsError.h"
 #include "nsGkAtoms.h"
 #include "nsIAbsorbingTransaction.h"
 #include "nsIClipboard.h"
 #include "nsIContent.h"
+#include "nsIContentIterator.h"
 #include "nsIDocumentEncoder.h"
 #include "nsINode.h"
 #include "nsIPresShell.h"
 #include "nsISelectionController.h"
 #include "nsISupportsPrimitives.h"
 #include "nsITransferable.h"
 #include "nsIWeakReferenceUtils.h"
 #include "nsNameSpaceManager.h"
@@ -1450,21 +1450,22 @@ TextEditor::GetTextLength(int32_t* aCoun
     return NS_OK;
   }
 
   Element* rootElement = GetRoot();
   if (NS_WARN_IF(!rootElement)) {
     return NS_ERROR_FAILURE;
   }
 
+  nsCOMPtr<nsIContentIterator> iter = NS_NewContentIterator();
+
   uint32_t totalLength = 0;
-  PostContentIterator postOrderIter;
-  postOrderIter.Init(rootElement);
-  for (; !postOrderIter.IsDone(); postOrderIter.Next()) {
-    nsCOMPtr<nsINode> currentNode = postOrderIter.GetCurrentNode();
+  iter->Init(rootElement);
+  for (; !iter->IsDone(); iter->Next()) {
+    nsCOMPtr<nsINode> currentNode = iter->GetCurrentNode();
     if (IsTextNode(currentNode) && IsEditable(currentNode)) {
       totalLength += currentNode->Length();
     }
   }
 
   *aCount = totalLength;
   return NS_OK;
 }
--- a/editor/spellchecker/TextServicesDocument.cpp
+++ b/editor/spellchecker/TextServicesDocument.cpp
@@ -1,30 +1,31 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 #include "TextServicesDocument.h"
 
-#include "FilteredContentIterator.h"  // for FilteredContentIterator
 #include "mozilla/Assertions.h"   // for MOZ_ASSERT, etc
 #include "mozilla/EditorUtils.h"  // for AutoTransactionBatchExternal
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/Selection.h"
 #include "mozilla/mozalloc.h"    // for operator new, etc
 #include "mozilla/TextEditor.h"  // for TextEditor
 #include "nsAString.h"           // for nsAString::Length, etc
 #include "nsContentUtils.h"      // for nsContentUtils
 #include "nsComposeTxtSrvFilter.h"
 #include "nsDebug.h"                    // for NS_ENSURE_TRUE, etc
 #include "nsDependentSubstring.h"       // for Substring
 #include "nsError.h"                    // for NS_OK, NS_ERROR_FAILURE, etc
+#include "nsFilteredContentIterator.h"  // for nsFilteredContentIterator
 #include "nsGenericHTMLElement.h"       // for nsGenericHTMLElement
 #include "nsIContent.h"                 // for nsIContent, etc
+#include "nsIContentIterator.h"         // for nsIContentIterator
 #include "nsID.h"                       // for NS_GET_IID
 #include "nsIEditor.h"                  // for nsIEditor, etc
 #include "nsINode.h"                    // for nsINode
 #include "nsISelectionController.h"     // for nsISelectionController, etc
 #include "nsISupportsBase.h"            // for nsISupports
 #include "nsISupportsUtils.h"           // for NS_IF_ADDREF, NS_ADDREF, etc
 #include "mozilla/intl/WordBreaker.h"   // for WordRange, WordBreaker
 #include "nsRange.h"                    // for nsRange
@@ -80,17 +81,17 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(TextSer
 
 NS_INTERFACE_MAP_BEGIN(TextServicesDocument)
   NS_INTERFACE_MAP_ENTRY(nsIEditActionListener)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIEditActionListener)
   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(TextServicesDocument)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTION(TextServicesDocument, mDocument, mSelCon, mTextEditor,
-                         mFilteredIter, mPrevTextBlock, mNextTextBlock, mExtent)
+                         mIterator, mPrevTextBlock, mNextTextBlock, mExtent)
 
 nsresult TextServicesDocument::InitWithEditor(nsIEditor* aEditor) {
   nsCOMPtr<nsISelectionController> selCon;
 
   NS_ENSURE_TRUE(aEditor, NS_ERROR_NULL_POINTER);
 
   // Check to see if we already have an mSelCon. If we do, it
   // better be the same one the editor uses!
@@ -115,17 +116,17 @@ nsresult TextServicesDocument::InitWithE
   RefPtr<Document> doc = aEditor->AsEditorBase()->GetDocument();
   if (!doc || (mDocument && doc != mDocument)) {
     return NS_ERROR_FAILURE;
   }
 
   if (!mDocument) {
     mDocument = doc;
 
-    rv = CreateDocumentContentIterator(getter_AddRefs(mFilteredIter));
+    rv = CreateDocumentContentIterator(getter_AddRefs(mIterator));
 
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     mIteratorStatus = IteratorStatus::eDone;
 
     rv = FirstBlock();
@@ -148,18 +149,17 @@ nsresult TextServicesDocument::SetExtent
 
   // We need to store a copy of aDOMRange since we don't
   // know where it came from.
 
   mExtent = aRange->CloneRange();
 
   // Create a new iterator based on our new extent range.
 
-  nsresult rv =
-      CreateFilteredContentIterator(mExtent, getter_AddRefs(mFilteredIter));
+  nsresult rv = CreateContentIterator(mExtent, getter_AddRefs(mIterator));
 
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   // Now position the iterator at the start of the first block
   // in the range.
 
@@ -181,49 +181,49 @@ nsresult TextServicesDocument::ExpandRan
   nsresult rv =
       GetRangeEndPoints(aRange, getter_AddRefs(rngStartNode), &rngStartOffset,
                         getter_AddRefs(rngEndNode), &rngEndOffset);
 
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Create a content iterator based on the range.
 
-  RefPtr<FilteredContentIterator> filteredIter;
-  rv = CreateFilteredContentIterator(aRange, getter_AddRefs(filteredIter));
+  nsCOMPtr<nsIContentIterator> iter;
+  rv = CreateContentIterator(aRange, getter_AddRefs(iter));
 
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Find the first text node in the range.
 
   IteratorStatus iterStatus = IteratorStatus::eDone;
 
-  rv = FirstTextNode(filteredIter, &iterStatus);
+  rv = FirstTextNode(iter, &iterStatus);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (iterStatus == IteratorStatus::eDone) {
     // No text was found so there's no adjustment necessary!
     return NS_OK;
   }
 
-  nsINode* firstText = filteredIter->GetCurrentNode();
+  nsINode* firstText = iter->GetCurrentNode();
   NS_ENSURE_TRUE(firstText, NS_ERROR_FAILURE);
 
   // Find the last text node in the range.
 
-  rv = LastTextNode(filteredIter, &iterStatus);
+  rv = LastTextNode(iter, &iterStatus);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (iterStatus == IteratorStatus::eDone) {
     // We should never get here because a first text block
     // was found above.
     NS_ASSERTION(false, "Found a first without a last!");
     return NS_ERROR_FAILURE;
   }
 
-  nsINode* lastText = filteredIter->GetCurrentNode();
+  nsINode* lastText = iter->GetCurrentNode();
   NS_ENSURE_TRUE(lastText, NS_ERROR_FAILURE);
 
   // Now make sure our end points are in terms of text nodes in the range!
 
   if (rngStartNode != firstText) {
     // The range includes the start of the first text node!
     rngStartNode = firstText;
     rngStartOffset = 0;
@@ -233,33 +233,33 @@ nsresult TextServicesDocument::ExpandRan
     // The range includes the end of the last text node!
     rngEndNode = lastText;
     rngEndOffset = lastText->Length();
   }
 
   // Create a doc iterator so that we can scan beyond
   // the bounds of the extent range.
 
-  RefPtr<FilteredContentIterator> docFilteredIter;
-  rv = CreateDocumentContentIterator(getter_AddRefs(docFilteredIter));
+  nsCOMPtr<nsIContentIterator> docIter;
+  rv = CreateDocumentContentIterator(getter_AddRefs(docIter));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Grab all the text in the block containing our
   // first text node.
 
-  rv = docFilteredIter->PositionAt(firstText);
+  rv = docIter->PositionAt(firstText);
   NS_ENSURE_SUCCESS(rv, rv);
 
   iterStatus = IteratorStatus::eValid;
 
   nsTArray<OffsetEntry*> offsetTable;
   nsAutoString blockStr;
 
-  rv = CreateOffsetTable(&offsetTable, docFilteredIter, &iterStatus, nullptr,
-                         &blockStr);
+  rv =
+      CreateOffsetTable(&offsetTable, docIter, &iterStatus, nullptr, &blockStr);
   if (NS_FAILED(rv)) {
     ClearOffsetTable(&offsetTable);
     return rv;
   }
 
   nsCOMPtr<nsINode> wordStartNode, wordEndNode;
   int32_t wordStartOffset, wordEndOffset;
 
@@ -272,23 +272,23 @@ nsresult TextServicesDocument::ExpandRan
   NS_ENSURE_SUCCESS(rv, rv);
 
   rngStartNode = wordStartNode;
   rngStartOffset = wordStartOffset;
 
   // Grab all the text in the block containing our
   // last text node.
 
-  rv = docFilteredIter->PositionAt(lastText);
+  rv = docIter->PositionAt(lastText);
   NS_ENSURE_SUCCESS(rv, rv);
 
   iterStatus = IteratorStatus::eValid;
 
-  rv = CreateOffsetTable(&offsetTable, docFilteredIter, &iterStatus, nullptr,
-                         &blockStr);
+  rv =
+      CreateOffsetTable(&offsetTable, docIter, &iterStatus, nullptr, &blockStr);
   if (NS_FAILED(rv)) {
     ClearOffsetTable(&offsetTable);
     return rv;
   }
 
   rv = FindWordBounds(&offsetTable, &blockStr, rngEndNode, rngEndOffset,
                       getter_AddRefs(wordStartNode), &wordStartOffset,
                       getter_AddRefs(wordEndNode), &wordEndOffset);
@@ -323,30 +323,30 @@ nsresult TextServicesDocument::SetFilter
   return NS_OK;
 }
 
 nsresult TextServicesDocument::GetCurrentTextBlock(nsString* aStr) {
   NS_ENSURE_TRUE(aStr, NS_ERROR_NULL_POINTER);
 
   aStr->Truncate();
 
-  NS_ENSURE_TRUE(mFilteredIter, NS_ERROR_FAILURE);
-
-  nsresult rv = CreateOffsetTable(&mOffsetTable, mFilteredIter,
-                                  &mIteratorStatus, mExtent, aStr);
+  NS_ENSURE_TRUE(mIterator, NS_ERROR_FAILURE);
+
+  nsresult rv = CreateOffsetTable(&mOffsetTable, mIterator, &mIteratorStatus,
+                                  mExtent, aStr);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
   return NS_OK;
 }
 
 nsresult TextServicesDocument::FirstBlock() {
-  NS_ENSURE_TRUE(mFilteredIter, NS_ERROR_FAILURE);
-
-  nsresult rv = FirstTextNode(mFilteredIter, &mIteratorStatus);
+  NS_ENSURE_TRUE(mIterator, NS_ERROR_FAILURE);
+
+  nsresult rv = FirstTextNode(mIterator, &mIteratorStatus);
 
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   // Keep track of prev and next blocks, just in case
   // the text service blows away the current block.
 
@@ -369,26 +369,27 @@ nsresult TextServicesDocument::LastSelec
     int32_t* aSelLength) {
   NS_ENSURE_TRUE(aSelStatus && aSelOffset && aSelLength, NS_ERROR_NULL_POINTER);
 
   mIteratorStatus = IteratorStatus::eDone;
 
   *aSelStatus = BlockSelectionStatus::eBlockNotFound;
   *aSelOffset = *aSelLength = -1;
 
-  if (!mSelCon || !mFilteredIter) {
+  if (!mSelCon || !mIterator) {
     return NS_ERROR_FAILURE;
   }
 
   RefPtr<Selection> selection =
       mSelCon->GetSelection(nsISelectionController::SELECTION_NORMAL);
   if (NS_WARN_IF(!selection)) {
     return NS_ERROR_FAILURE;
   }
 
+  nsCOMPtr<nsIContentIterator> iter;
   RefPtr<nsRange> range;
   nsCOMPtr<nsINode> parent;
 
   if (selection->IsCollapsed()) {
     // We have a caret. Check if the caret is in a text node.
     // If it is, make the text node's block the current block.
     // If the caret isn't in a text node, search forwards in
     // the document, till we find a text node.
@@ -405,31 +406,31 @@ nsresult TextServicesDocument::LastSelec
     }
 
     nsresult rv;
     if (parent->IsText()) {
       // The caret is in a text node. Find the beginning
       // of the text block containing this text node and
       // return.
 
-      rv = mFilteredIter->PositionAt(parent);
+      rv = mIterator->PositionAt(parent);
 
       if (NS_FAILED(rv)) {
         return rv;
       }
 
-      rv = FirstTextNodeInCurrentBlock(mFilteredIter);
+      rv = FirstTextNodeInCurrentBlock(mIterator);
 
       if (NS_FAILED(rv)) {
         return rv;
       }
 
       mIteratorStatus = IteratorStatus::eValid;
 
-      rv = CreateOffsetTable(&mOffsetTable, mFilteredIter, &mIteratorStatus,
+      rv = CreateOffsetTable(&mOffsetTable, mIterator, &mIteratorStatus,
                              mExtent, nullptr);
 
       if (NS_FAILED(rv)) {
         return rv;
       }
 
       rv = GetSelection(aSelStatus, aSelOffset, aSelLength);
 
@@ -454,53 +455,53 @@ nsresult TextServicesDocument::LastSelec
       }
 
       if (range->Collapsed()) {
         // If we get here, the range is collapsed because there is nothing after
         // the caret! Just return NS_OK;
         return NS_OK;
       }
 
-      RefPtr<FilteredContentIterator> filteredIter;
-      rv = CreateFilteredContentIterator(range, getter_AddRefs(filteredIter));
+      rv = CreateContentIterator(range, getter_AddRefs(iter));
 
       if (NS_FAILED(rv)) {
         return rv;
       }
 
-      filteredIter->First();
+      iter->First();
 
       nsIContent* content = nullptr;
-      for (; !filteredIter->IsDone(); filteredIter->Next()) {
-        nsINode* currentNode = filteredIter->GetCurrentNode();
+      while (!iter->IsDone()) {
+        nsINode* currentNode = iter->GetCurrentNode();
         if (currentNode->IsText()) {
           content = currentNode->AsContent();
           break;
         }
+        iter->Next();
       }
 
       if (!content) {
         return NS_OK;
       }
 
-      rv = mFilteredIter->PositionAt(content);
+      rv = mIterator->PositionAt(content);
 
       if (NS_FAILED(rv)) {
         return rv;
       }
 
-      rv = FirstTextNodeInCurrentBlock(mFilteredIter);
+      rv = FirstTextNodeInCurrentBlock(mIterator);
 
       if (NS_FAILED(rv)) {
         return rv;
       }
 
       mIteratorStatus = IteratorStatus::eValid;
 
-      rv = CreateOffsetTable(&mOffsetTable, mFilteredIter, &mIteratorStatus,
+      rv = CreateOffsetTable(&mOffsetTable, mIterator, &mIteratorStatus,
                              mExtent, nullptr);
 
       if (NS_FAILED(rv)) {
         return rv;
       }
 
       rv = GetSelection(aSelStatus, aSelOffset, aSelLength);
 
@@ -535,59 +536,59 @@ nsresult TextServicesDocument::LastSelec
     range = selection->GetRangeAt(i);
 
     if (!range) {
       return NS_OK;  // XXX Really?
     }
 
     // Create an iterator for the range.
 
-    RefPtr<FilteredContentIterator> filteredIter;
-    nsresult rv =
-        CreateFilteredContentIterator(range, getter_AddRefs(filteredIter));
+    nsresult rv = CreateContentIterator(range, getter_AddRefs(iter));
 
     if (NS_FAILED(rv)) {
       return rv;
     }
 
-    filteredIter->Last();
+    iter->Last();
 
     // Now walk through the range till we find a text node.
 
-    for (; !filteredIter->IsDone(); filteredIter->Prev()) {
-      if (filteredIter->GetCurrentNode()->NodeType() == nsINode::TEXT_NODE) {
+    while (!iter->IsDone()) {
+      if (iter->GetCurrentNode()->NodeType() == nsINode::TEXT_NODE) {
         // We found a text node, so position the document's
         // iterator at the beginning of the block, then get
         // the selection in terms of the string offset.
 
-        rv = mFilteredIter->PositionAt(filteredIter->GetCurrentNode());
+        rv = mIterator->PositionAt(iter->GetCurrentNode());
 
         if (NS_FAILED(rv)) {
           return rv;
         }
 
-        rv = FirstTextNodeInCurrentBlock(mFilteredIter);
+        rv = FirstTextNodeInCurrentBlock(mIterator);
 
         if (NS_FAILED(rv)) {
           return rv;
         }
 
         mIteratorStatus = IteratorStatus::eValid;
 
-        rv = CreateOffsetTable(&mOffsetTable, mFilteredIter, &mIteratorStatus,
+        rv = CreateOffsetTable(&mOffsetTable, mIterator, &mIteratorStatus,
                                mExtent, nullptr);
 
         if (NS_FAILED(rv)) {
           return rv;
         }
 
         rv = GetSelection(aSelStatus, aSelOffset, aSelLength);
 
         return rv;
       }
+
+      iter->Prev();
     }
   }
 
   // If we get here, we didn't find any text node in the selection!
   // Create a range that extends from the end of the selection,
   // to the end of the document, then iterate forwards through
   // it till you find a text node!
 
@@ -610,82 +611,82 @@ nsresult TextServicesDocument::LastSelec
   }
 
   if (range->Collapsed()) {
     // If we get here, the range is collapsed because there is nothing after
     // the current selection! Just return NS_OK;
     return NS_OK;
   }
 
-  RefPtr<FilteredContentIterator> filteredIter;
-  nsresult rv =
-      CreateFilteredContentIterator(range, getter_AddRefs(filteredIter));
+  nsresult rv = CreateContentIterator(range, getter_AddRefs(iter));
 
   if (NS_FAILED(rv)) {
     return rv;
   }
 
-  filteredIter->First();
-
-  for (; !filteredIter->IsDone(); filteredIter->Next()) {
-    if (filteredIter->GetCurrentNode()->NodeType() == nsINode::TEXT_NODE) {
+  iter->First();
+
+  while (!iter->IsDone()) {
+    if (iter->GetCurrentNode()->NodeType() == nsINode::TEXT_NODE) {
       // We found a text node! Adjust the document's iterator to point
       // to the beginning of its text block, then get the current selection.
-      rv = mFilteredIter->PositionAt(filteredIter->GetCurrentNode());
+      rv = mIterator->PositionAt(iter->GetCurrentNode());
 
       if (NS_FAILED(rv)) {
         return rv;
       }
 
-      rv = FirstTextNodeInCurrentBlock(mFilteredIter);
+      rv = FirstTextNodeInCurrentBlock(mIterator);
 
       if (NS_FAILED(rv)) {
         return rv;
       }
 
       mIteratorStatus = IteratorStatus::eValid;
 
-      rv = CreateOffsetTable(&mOffsetTable, mFilteredIter, &mIteratorStatus,
+      rv = CreateOffsetTable(&mOffsetTable, mIterator, &mIteratorStatus,
                              mExtent, nullptr);
 
       if (NS_FAILED(rv)) {
         return rv;
       }
 
       rv = GetSelection(aSelStatus, aSelOffset, aSelLength);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
       return NS_OK;
     }
+
+    iter->Next();
   }
 
   // If we get here, we didn't find any block before or inside
   // the selection! Just return OK.
   return NS_OK;
 }
 
 nsresult TextServicesDocument::PrevBlock() {
-  NS_ENSURE_TRUE(mFilteredIter, NS_ERROR_FAILURE);
+  NS_ENSURE_TRUE(mIterator, NS_ERROR_FAILURE);
 
   if (mIteratorStatus == IteratorStatus::eDone) {
     return NS_OK;
   }
 
   switch (mIteratorStatus) {
     case IteratorStatus::eValid:
     case IteratorStatus::eNext: {
-      nsresult rv = FirstTextNodeInPrevBlock(mFilteredIter);
+      nsresult rv = FirstTextNodeInPrevBlock(mIterator);
 
       if (NS_FAILED(rv)) {
         mIteratorStatus = IteratorStatus::eDone;
         return rv;
       }
 
-      if (mFilteredIter->IsDone()) {
+      if (mIterator->IsDone()) {
         mIteratorStatus = IteratorStatus::eDone;
         return NS_OK;
       }
 
       mIteratorStatus = IteratorStatus::eValid;
       break;
     }
     case IteratorStatus::ePrev:
@@ -714,34 +715,34 @@ nsresult TextServicesDocument::PrevBlock
     mNextTextBlock = nullptr;
   }
 
   // XXX The result of GetFirstTextNodeInNextBlock() or NS_OK.
   return rv;
 }
 
 nsresult TextServicesDocument::NextBlock() {
-  NS_ENSURE_TRUE(mFilteredIter, NS_ERROR_FAILURE);
+  NS_ENSURE_TRUE(mIterator, NS_ERROR_FAILURE);
 
   if (mIteratorStatus == IteratorStatus::eDone) {
     return NS_OK;
   }
 
   switch (mIteratorStatus) {
     case IteratorStatus::eValid: {
       // Advance the iterator to the next text block.
 
-      nsresult rv = FirstTextNodeInNextBlock(mFilteredIter);
+      nsresult rv = FirstTextNodeInNextBlock(mIterator);
 
       if (NS_FAILED(rv)) {
         mIteratorStatus = IteratorStatus::eDone;
         return rv;
       }
 
-      if (mFilteredIter->IsDone()) {
+      if (mIterator->IsDone()) {
         mIteratorStatus = IteratorStatus::eDone;
         return NS_OK;
       }
 
       mIteratorStatus = IteratorStatus::eValid;
       break;
     }
     case IteratorStatus::eNext:
@@ -780,17 +781,17 @@ nsresult TextServicesDocument::NextBlock
   return rv;
 }
 
 nsresult TextServicesDocument::IsDone(bool* aIsDone) {
   NS_ENSURE_TRUE(aIsDone, NS_ERROR_NULL_POINTER);
 
   *aIsDone = false;
 
-  NS_ENSURE_TRUE(mFilteredIter, NS_ERROR_FAILURE);
+  NS_ENSURE_TRUE(mIterator, NS_ERROR_FAILURE);
 
   *aIsDone = mIteratorStatus == IteratorStatus::eDone;
 
   return NS_OK;
 }
 
 nsresult TextServicesDocument::SetSelection(int32_t aOffset, int32_t aLength) {
   NS_ENSURE_TRUE(mSelCon && aOffset >= 0 && aLength >= 0, NS_ERROR_FAILURE);
@@ -937,17 +938,17 @@ nsresult TextServicesDocument::DeleteSel
 
     if (i != mSelStartIndex && i != mSelEndIndex) {
       // The entire entry is contained in the selection. Mark the
       // entry invalid.
       entry->mIsValid = false;
     }
   }
 
-  // Make sure mFilteredIter always points to something valid!
+  // Make sure mIterator always points to something valid!
 
   AdjustContentIterator();
 
   // Now delete the actual content!
   RefPtr<TextEditor> textEditor = mTextEditor;
   nsresult rv = textEditor->DeleteSelectionAsAction(nsIEditor::ePrevious,
                                                     nsIEditor::eStrip);
   if (NS_FAILED(rv)) {
@@ -976,35 +977,34 @@ nsresult TextServicesDocument::DeleteSel
 
       nsCOMPtr<nsIContent> curContent;
 
       if (mIteratorStatus != IteratorStatus::eDone) {
         // The old iterator is still pointing to something valid,
         // so get its current node so we can restore it after we
         // create the new iterator!
 
-        curContent = mFilteredIter->GetCurrentNode()
-                         ? mFilteredIter->GetCurrentNode()->AsContent()
+        curContent = mIterator->GetCurrentNode()
+                         ? mIterator->GetCurrentNode()->AsContent()
                          : nullptr;
       }
 
       // Create the new iterator.
 
-      rv =
-          CreateFilteredContentIterator(mExtent, getter_AddRefs(mFilteredIter));
+      rv = CreateContentIterator(mExtent, getter_AddRefs(mIterator));
 
       if (NS_FAILED(rv)) {
         return rv;
       }
 
       // Now make the new iterator point to the content node
       // the old one was pointing at.
 
       if (curContent) {
-        rv = mFilteredIter->PositionAt(curContent);
+        rv = mIterator->PositionAt(curContent);
 
         if (NS_FAILED(rv)) {
           mIteratorStatus = IteratorStatus::eDone;
         } else {
           mIteratorStatus = IteratorStatus::eValid;
         }
       }
     }
@@ -1235,17 +1235,17 @@ nsresult TextServicesDocument::InsertTex
       return rv;
     }
   }
 
   return NS_OK;
 }
 
 void TextServicesDocument::DidDeleteNode(nsINode* aChild) {
-  if (NS_WARN_IF(!mFilteredIter)) {
+  if (NS_WARN_IF(!mIterator)) {
     return;
   }
 
   int32_t nodeIndex = 0;
   bool hasEntry = false;
   OffsetEntry* entry;
 
   nsresult rv =
@@ -1255,17 +1255,17 @@ void TextServicesDocument::DidDeleteNode
   }
 
   if (!hasEntry) {
     // It's okay if the node isn't in the offset table, the
     // editor could be cleaning house.
     return;
   }
 
-  nsINode* node = mFilteredIter->GetCurrentNode();
+  nsINode* node = mIterator->GetCurrentNode();
   if (node && node == aChild && mIteratorStatus != IteratorStatus::eDone) {
     // XXX: This should never really happen because
     // AdjustContentIterator() should have been called prior
     // to the delete to try and position the iterator on the
     // next valid text node in the offset table, and if there
     // wasn't a next, it would've set mIteratorStatus to eIsDone.
 
     NS_ERROR("DeleteNode called for current iterator node.");
@@ -1360,49 +1360,49 @@ void TextServicesDocument::DidJoinNodes(
     if (entry->mIsValid) {
       entry->mNodeOffset += nodeLength;
     }
   }
 
   // Now check to see if the iterator is pointing to the
   // left node. If it is, make it point to the right node!
 
-  if (mFilteredIter->GetCurrentNode() == &aLeftNode) {
-    mFilteredIter->PositionAt(&aRightNode);
+  if (mIterator->GetCurrentNode() == &aLeftNode) {
+    mIterator->PositionAt(&aRightNode);
   }
 }
 
-nsresult TextServicesDocument::CreateFilteredContentIterator(
-    nsRange* aRange, FilteredContentIterator** aFilteredIter) {
-  NS_ENSURE_TRUE(aRange && aFilteredIter, NS_ERROR_NULL_POINTER);
-
-  *aFilteredIter = nullptr;
+nsresult TextServicesDocument::CreateContentIterator(
+    nsRange* aRange, nsIContentIterator** aIterator) {
+  NS_ENSURE_TRUE(aRange && aIterator, NS_ERROR_NULL_POINTER);
+
+  *aIterator = nullptr;
 
   UniquePtr<nsComposeTxtSrvFilter> composeFilter;
   switch (mTxtSvcFilterType) {
     case nsIEditorSpellCheck::FILTERTYPE_NORMAL:
       composeFilter = nsComposeTxtSrvFilter::CreateNormalFilter();
       break;
     case nsIEditorSpellCheck::FILTERTYPE_MAIL:
       composeFilter = nsComposeTxtSrvFilter::CreateMailFilter();
       break;
   }
 
-  // Create a FilteredContentIterator
+  // Create a nsFilteredContentIterator
   // This class wraps the ContentIterator in order to give itself a chance
   // to filter out certain content nodes
-  RefPtr<FilteredContentIterator> filter =
-      new FilteredContentIterator(std::move(composeFilter));
+  RefPtr<nsFilteredContentIterator> filter =
+      new nsFilteredContentIterator(std::move(composeFilter));
 
   nsresult rv = filter->Init(aRange);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
-  filter.forget(aFilteredIter);
+  filter.forget(aIterator);
   return NS_OK;
 }
 
 Element* TextServicesDocument::GetDocumentContentRootNode() const {
   if (NS_WARN_IF(!mDocument)) {
     return nullptr;
   }
 
@@ -1471,32 +1471,32 @@ TextServicesDocument::CreateDocumentCont
                                      getter_AddRefs(range));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return nullptr;
   }
   return range.forget();
 }
 
 nsresult TextServicesDocument::CreateDocumentContentIterator(
-    FilteredContentIterator** aFilteredIter) {
-  NS_ENSURE_TRUE(aFilteredIter, NS_ERROR_NULL_POINTER);
+    nsIContentIterator** aIterator) {
+  NS_ENSURE_TRUE(aIterator, NS_ERROR_NULL_POINTER);
 
   RefPtr<nsRange> range = CreateDocumentContentRange();
   if (NS_WARN_IF(!range)) {
-    *aFilteredIter = nullptr;
+    *aIterator = nullptr;
     return NS_ERROR_FAILURE;
   }
 
-  return CreateFilteredContentIterator(range, aFilteredIter);
+  return CreateContentIterator(range, aIterator);
 }
 
 nsresult TextServicesDocument::AdjustContentIterator() {
-  NS_ENSURE_TRUE(mFilteredIter, NS_ERROR_FAILURE);
-
-  nsCOMPtr<nsINode> node = mFilteredIter->GetCurrentNode();
+  NS_ENSURE_TRUE(mIterator, NS_ERROR_FAILURE);
+
+  nsCOMPtr<nsINode> node = mIterator->GetCurrentNode();
   NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
 
   size_t tcount = mOffsetTable.Length();
 
   nsINode* prevValidNode = nullptr;
   nsINode* nextValidNode = nullptr;
   bool foundEntry = false;
   OffsetEntry* entry;
@@ -1535,66 +1535,79 @@ nsresult TextServicesDocument::AdjustCon
     }
   } else if (nextValidNode) {
     if (nextValidNode->IsContent()) {
       content = nextValidNode->AsContent();
     }
   }
 
   if (content) {
-    nsresult rv = mFilteredIter->PositionAt(content);
+    nsresult rv = mIterator->PositionAt(content);
 
     if (NS_FAILED(rv)) {
       mIteratorStatus = IteratorStatus::eDone;
     } else {
       mIteratorStatus = IteratorStatus::eValid;
     }
     return rv;
   }
 
   // If we get here, there aren't any valid entries
   // in the offset table! Try to position the iterator
   // on the next text block first, then previous if
   // one doesn't exist!
 
   if (mNextTextBlock) {
-    nsresult rv = mFilteredIter->PositionAt(mNextTextBlock);
+    nsresult rv = mIterator->PositionAt(mNextTextBlock);
 
     if (NS_FAILED(rv)) {
       mIteratorStatus = IteratorStatus::eDone;
       return rv;
     }
 
     mIteratorStatus = IteratorStatus::eNext;
   } else if (mPrevTextBlock) {
-    nsresult rv = mFilteredIter->PositionAt(mPrevTextBlock);
+    nsresult rv = mIterator->PositionAt(mPrevTextBlock);
 
     if (NS_FAILED(rv)) {
       mIteratorStatus = IteratorStatus::eDone;
       return rv;
     }
 
     mIteratorStatus = IteratorStatus::ePrev;
   } else {
     mIteratorStatus = IteratorStatus::eDone;
   }
   return NS_OK;
 }
 
 // static
-bool TextServicesDocument::DidSkip(FilteredContentIterator* aFilteredIter) {
-  return aFilteredIter && aFilteredIter->DidSkip();
+bool TextServicesDocument::DidSkip(nsIContentIterator* aFilteredIter) {
+  // We can assume here that the Iterator is a nsFilteredContentIterator because
+  // all the iterator are created in CreateContentIterator which create a
+  // nsFilteredContentIterator
+  // So if the iterator bailed on one of the "filtered" content nodes then we
+  // consider that to be a block and bail with true
+  if (aFilteredIter) {
+    nsFilteredContentIterator* filter =
+        static_cast<nsFilteredContentIterator*>(aFilteredIter);
+    if (filter && filter->DidSkip()) {
+      return true;
+    }
+  }
+  return false;
 }
 
 // static
-void TextServicesDocument::ClearDidSkip(
-    FilteredContentIterator* aFilteredIter) {
+void TextServicesDocument::ClearDidSkip(nsIContentIterator* aFilteredIter) {
   // Clear filter's skip flag
   if (aFilteredIter) {
-    aFilteredIter->ClearDidSkip();
+    nsFilteredContentIterator* filter =
+        static_cast<nsFilteredContentIterator*>(aFilteredIter);
+    filter->ClearDidSkip();
   }
 }
 
 // static
 bool TextServicesDocument::IsBlockNode(nsIContent* aContent) {
   if (!aContent) {
     NS_ERROR("How did a null pointer get passed to IsBlockNode?");
     return false;
@@ -1906,85 +1919,89 @@ nsresult TextServicesDocument::GetCollap
   // this range, with its initial position set to the closest
   // child of this non-text node. Then look for the closest text
   // node.
 
   nsresult rv = nsRange::CreateRange(eStart->mNode, eStartOffset, eEnd->mNode,
                                      eEndOffset, getter_AddRefs(range));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  RefPtr<FilteredContentIterator> filteredIter;
-  rv = CreateFilteredContentIterator(range, getter_AddRefs(filteredIter));
+  nsCOMPtr<nsIContentIterator> iter;
+  rv = CreateContentIterator(range, getter_AddRefs(iter));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsIContent* saveNode;
   if (parent->HasChildren()) {
     // XXX: We need to make sure that all of parent's
     //      children are in the text block.
 
     // If the parent has children, position the iterator
     // on the child that is to the left of the offset.
 
     nsIContent* content = range->GetChildAtStartOffset();
     if (content && parent->GetFirstChild() != content) {
       content = content->GetPreviousSibling();
     }
     NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
 
-    rv = filteredIter->PositionAt(content);
+    rv = iter->PositionAt(content);
     NS_ENSURE_SUCCESS(rv, rv);
 
     saveNode = content;
   } else {
     // The parent has no children, so position the iterator
     // on the parent.
     NS_ENSURE_TRUE(parent->IsContent(), NS_ERROR_FAILURE);
     nsCOMPtr<nsIContent> content = parent->AsContent();
 
-    rv = filteredIter->PositionAt(content);
+    rv = iter->PositionAt(content);
     NS_ENSURE_SUCCESS(rv, rv);
 
     saveNode = content;
   }
 
   // Now iterate to the left, towards the beginning of
   // the text block, to find the first text node you
   // come across.
 
   nsIContent* node = nullptr;
-  for (; !filteredIter->IsDone(); filteredIter->Prev()) {
-    nsINode* current = filteredIter->GetCurrentNode();
+  while (!iter->IsDone()) {
+    nsINode* current = iter->GetCurrentNode();
     if (current->NodeType() == nsINode::TEXT_NODE) {
       node = current->AsContent();
       break;
     }
+
+    iter->Prev();
   }
 
   if (node) {
     // We found a node, now set the offset to the end
     // of the text node.
     offset = node->TextLength();
   } else {
     // We should never really get here, but I'm paranoid.
 
     // We didn't find a text node above, so iterate to
     // the right, towards the end of the text block, looking
     // for a text node.
 
-    rv = filteredIter->PositionAt(saveNode);
+    rv = iter->PositionAt(saveNode);
     NS_ENSURE_SUCCESS(rv, rv);
 
     node = nullptr;
-    for (; !filteredIter->IsDone(); filteredIter->Next()) {
-      nsINode* current = filteredIter->GetCurrentNode();
+    while (!iter->IsDone()) {
+      nsINode* current = iter->GetCurrentNode();
 
       if (current->NodeType() == nsINode::TEXT_NODE) {
         node = current->AsContent();
         break;
       }
+
+      iter->Next();
     }
 
     NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
 
     // We found a text node, so set the offset to
     // the beginning of the node.
 
     offset = 0;
@@ -2142,61 +2159,66 @@ nsresult TextServicesDocument::GetUncoll
 
   nsresult rv = nsRange::CreateRange(p1, o1, p2, o2, getter_AddRefs(range));
 
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Now iterate over this range to figure out the selection's
   // block offset and length.
 
-  RefPtr<FilteredContentIterator> filteredIter;
-  rv = CreateFilteredContentIterator(range, getter_AddRefs(filteredIter));
+  nsCOMPtr<nsIContentIterator> iter;
+
+  rv = CreateContentIterator(range, getter_AddRefs(iter));
 
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Find the first text node in the range.
 
   bool found;
   nsCOMPtr<nsIContent> content;
 
-  filteredIter->First();
+  iter->First();
 
   if (!p1->IsText()) {
     found = false;
 
-    for (; !filteredIter->IsDone(); filteredIter->Next()) {
-      nsINode* node = filteredIter->GetCurrentNode();
+    while (!iter->IsDone()) {
+      nsINode* node = iter->GetCurrentNode();
 
       if (node->IsText()) {
         p1 = node;
         o1 = 0;
         found = true;
 
         break;
       }
+
+      iter->Next();
     }
 
     NS_ENSURE_TRUE(found, NS_ERROR_FAILURE);
   }
 
   // Find the last text node in the range.
 
-  filteredIter->Last();
+  iter->Last();
 
   if (!p2->IsText()) {
     found = false;
-    for (; !filteredIter->IsDone(); filteredIter->Prev()) {
-      nsINode* node = filteredIter->GetCurrentNode();
+    while (!iter->IsDone()) {
+      nsINode* node = iter->GetCurrentNode();
       if (node->IsText()) {
         p2 = node;
         o2 = p2->Length();
         found = true;
 
         break;
       }
+
+      iter->Prev();
     }
 
     NS_ENSURE_TRUE(found, NS_ERROR_FAILURE);
   }
 
   found = false;
   *aSelLength = 0;
 
@@ -2259,233 +2281,236 @@ nsresult TextServicesDocument::GetRangeE
   NS_IF_ADDREF(*aEndContainer = aRange->GetEndContainer());
   NS_ENSURE_TRUE(aEndContainer, NS_ERROR_FAILURE);
 
   *aEndOffset = static_cast<int32_t>(aRange->EndOffset());
   return NS_OK;
 }
 
 // static
-nsresult TextServicesDocument::FirstTextNode(
-    FilteredContentIterator* aFilteredIter, IteratorStatus* aIteratorStatus) {
+nsresult TextServicesDocument::FirstTextNode(nsIContentIterator* aIterator,
+                                             IteratorStatus* aIteratorStatus) {
   if (aIteratorStatus) {
     *aIteratorStatus = IteratorStatus::eDone;
   }
 
-  for (aFilteredIter->First(); !aFilteredIter->IsDone();
-       aFilteredIter->Next()) {
-    if (aFilteredIter->GetCurrentNode()->NodeType() == nsINode::TEXT_NODE) {
+  aIterator->First();
+
+  while (!aIterator->IsDone()) {
+    if (aIterator->GetCurrentNode()->NodeType() == nsINode::TEXT_NODE) {
       if (aIteratorStatus) {
         *aIteratorStatus = IteratorStatus::eValid;
       }
       break;
     }
+    aIterator->Next();
   }
 
   return NS_OK;
 }
 
 // static
-nsresult TextServicesDocument::LastTextNode(
-    FilteredContentIterator* aFilteredIter, IteratorStatus* aIteratorStatus) {
+nsresult TextServicesDocument::LastTextNode(nsIContentIterator* aIterator,
+                                            IteratorStatus* aIteratorStatus) {
   if (aIteratorStatus) {
     *aIteratorStatus = IteratorStatus::eDone;
   }
 
-  for (aFilteredIter->Last(); !aFilteredIter->IsDone(); aFilteredIter->Prev()) {
-    if (aFilteredIter->GetCurrentNode()->NodeType() == nsINode::TEXT_NODE) {
+  aIterator->Last();
+
+  while (!aIterator->IsDone()) {
+    if (aIterator->GetCurrentNode()->NodeType() == nsINode::TEXT_NODE) {
       if (aIteratorStatus) {
         *aIteratorStatus = IteratorStatus::eValid;
       }
       break;
     }
+    aIterator->Prev();
   }
 
   return NS_OK;
 }
 
 // static
 nsresult TextServicesDocument::FirstTextNodeInCurrentBlock(
-    FilteredContentIterator* aFilteredIter) {
-  NS_ENSURE_TRUE(aFilteredIter, NS_ERROR_NULL_POINTER);
-
-  ClearDidSkip(aFilteredIter);
+    nsIContentIterator* aIter) {
+  NS_ENSURE_TRUE(aIter, NS_ERROR_NULL_POINTER);
+
+  ClearDidSkip(aIter);
 
   nsCOMPtr<nsIContent> last;
 
   // Walk backwards over adjacent text nodes until
   // we hit a block boundary:
 
-  while (!aFilteredIter->IsDone()) {
-    nsCOMPtr<nsIContent> content =
-        aFilteredIter->GetCurrentNode()->IsContent()
-            ? aFilteredIter->GetCurrentNode()->AsContent()
-            : nullptr;
+  while (!aIter->IsDone()) {
+    nsCOMPtr<nsIContent> content = aIter->GetCurrentNode()->IsContent()
+                                       ? aIter->GetCurrentNode()->AsContent()
+                                       : nullptr;
     if (last && IsBlockNode(content)) {
       break;
     }
     if (IsTextNode(content)) {
       if (last && !HasSameBlockNodeParent(content, last)) {
         // We're done, the current text node is in a
         // different block.
         break;
       }
       last = content;
     }
 
-    aFilteredIter->Prev();
-
-    if (DidSkip(aFilteredIter)) {
+    aIter->Prev();
+
+    if (DidSkip(aIter)) {
       break;
     }
   }
 
   if (last) {
-    aFilteredIter->PositionAt(last);
+    aIter->PositionAt(last);
   }
 
   // XXX: What should we return if last is null?
 
   return NS_OK;
 }
 
 // static
 nsresult TextServicesDocument::FirstTextNodeInPrevBlock(
-    FilteredContentIterator* aFilteredIter) {
-  NS_ENSURE_TRUE(aFilteredIter, NS_ERROR_NULL_POINTER);
-
-  // XXX: What if mFilteredIter is not currently on a text node?
-
-  // Make sure mFilteredIter is pointing to the first text node in the
+    nsIContentIterator* aIterator) {
+  NS_ENSURE_TRUE(aIterator, NS_ERROR_NULL_POINTER);
+
+  // XXX: What if mIterator is not currently on a text node?
+
+  // Make sure mIterator is pointing to the first text node in the
   // current block:
 
-  nsresult rv = FirstTextNodeInCurrentBlock(aFilteredIter);
+  nsresult rv = FirstTextNodeInCurrentBlock(aIterator);
 
   NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
 
-  // Point mFilteredIter to the first node before the first text node:
-
-  aFilteredIter->Prev();
-
-  if (aFilteredIter->IsDone()) {
+  // Point mIterator to the first node before the first text node:
+
+  aIterator->Prev();
+
+  if (aIterator->IsDone()) {
     return NS_ERROR_FAILURE;
   }
 
   // Now find the first text node of the next block:
 
-  return FirstTextNodeInCurrentBlock(aFilteredIter);
+  return FirstTextNodeInCurrentBlock(aIterator);
 }
 
 // static
 nsresult TextServicesDocument::FirstTextNodeInNextBlock(
-    FilteredContentIterator* aFilteredIter) {
+    nsIContentIterator* aIterator) {
   nsCOMPtr<nsIContent> prev;
   bool crossedBlockBoundary = false;
 
-  NS_ENSURE_TRUE(aFilteredIter, NS_ERROR_NULL_POINTER);
-
-  ClearDidSkip(aFilteredIter);
-
-  while (!aFilteredIter->IsDone()) {
+  NS_ENSURE_TRUE(aIterator, NS_ERROR_NULL_POINTER);
+
+  ClearDidSkip(aIterator);
+
+  while (!aIterator->IsDone()) {
     nsCOMPtr<nsIContent> content =
-        aFilteredIter->GetCurrentNode()->IsContent()
-            ? aFilteredIter->GetCurrentNode()->AsContent()
+        aIterator->GetCurrentNode()->IsContent()
+            ? aIterator->GetCurrentNode()->AsContent()
             : nullptr;
 
     if (IsTextNode(content)) {
       if (crossedBlockBoundary ||
           (prev && !HasSameBlockNodeParent(prev, content))) {
         break;
       }
       prev = content;
     } else if (!crossedBlockBoundary && IsBlockNode(content)) {
       crossedBlockBoundary = true;
     }
 
-    aFilteredIter->Next();
-
-    if (!crossedBlockBoundary && DidSkip(aFilteredIter)) {
+    aIterator->Next();
+
+    if (!crossedBlockBoundary && DidSkip(aIterator)) {
       crossedBlockBoundary = true;
     }
   }
 
   return NS_OK;
 }
 
 nsresult TextServicesDocument::GetFirstTextNodeInPrevBlock(
     nsIContent** aContent) {
   NS_ENSURE_TRUE(aContent, NS_ERROR_NULL_POINTER);
 
   *aContent = 0;
 
   // Save the iterator's current content node so we can restore
   // it when we are done:
 
-  nsINode* node = mFilteredIter->GetCurrentNode();
-
-  nsresult rv = FirstTextNodeInPrevBlock(mFilteredIter);
+  nsINode* node = mIterator->GetCurrentNode();
+
+  nsresult rv = FirstTextNodeInPrevBlock(mIterator);
 
   if (NS_FAILED(rv)) {
     // Try to restore the iterator before returning.
-    mFilteredIter->PositionAt(node);
+    mIterator->PositionAt(node);
     return rv;
   }
 
-  if (!mFilteredIter->IsDone()) {
+  if (!mIterator->IsDone()) {
     nsCOMPtr<nsIContent> current =
-        mFilteredIter->GetCurrentNode()->IsContent()
-            ? mFilteredIter->GetCurrentNode()->AsContent()
+        mIterator->GetCurrentNode()->IsContent()
+            ? mIterator->GetCurrentNode()->AsContent()
             : nullptr;
     current.forget(aContent);
   }
 
   // Restore the iterator:
 
-  return mFilteredIter->PositionAt(node);
+  return mIterator->PositionAt(node);
 }
 
 nsresult TextServicesDocument::GetFirstTextNodeInNextBlock(
     nsIContent** aContent) {
   NS_ENSURE_TRUE(aContent, NS_ERROR_NULL_POINTER);
 
   *aContent = 0;
 
   // Save the iterator's current content node so we can restore
   // it when we are done:
 
-  nsINode* node = mFilteredIter->GetCurrentNode();
-
-  nsresult rv = FirstTextNodeInNextBlock(mFilteredIter);
+  nsINode* node = mIterator->GetCurrentNode();
+
+  nsresult rv = FirstTextNodeInNextBlock(mIterator);
 
   if (NS_FAILED(rv)) {
     // Try to restore the iterator before returning.
-    mFilteredIter->PositionAt(node);
+    mIterator->PositionAt(node);
     return rv;
   }
 
-  if (!mFilteredIter->IsDone()) {
+  if (!mIterator->IsDone()) {
     nsCOMPtr<nsIContent> current =
-        mFilteredIter->GetCurrentNode()->IsContent()
-            ? mFilteredIter->GetCurrentNode()->AsContent()
+        mIterator->GetCurrentNode()->IsContent()
+            ? mIterator->GetCurrentNode()->AsContent()
             : nullptr;
     current.forget(aContent);
   }
 
   // Restore the iterator:
-  return mFilteredIter->PositionAt(node);
+  return mIterator->PositionAt(node);
 }
 
 nsresult TextServicesDocument::CreateOffsetTable(
-    nsTArray<OffsetEntry*>* aOffsetTable,
-    FilteredContentIterator* aFilteredIter, IteratorStatus* aIteratorStatus,
-    nsRange* aIterRange, nsString* aStr) {
+    nsTArray<OffsetEntry*>* aOffsetTable, nsIContentIterator* aIterator,
+    IteratorStatus* aIteratorStatus, nsRange* aIterRange, nsString* aStr) {
   nsCOMPtr<nsIContent> first;
   nsCOMPtr<nsIContent> prev;
 
-  NS_ENSURE_TRUE(aFilteredIter, NS_ERROR_NULL_POINTER);
+  NS_ENSURE_TRUE(aIterator, NS_ERROR_NULL_POINTER);
 
   ClearOffsetTable(aOffsetTable);
 
   if (aStr) {
     aStr->Truncate();
   }
 
   if (*aIteratorStatus == IteratorStatus::eDone) {
@@ -2506,28 +2531,28 @@ nsresult TextServicesDocument::CreateOff
 
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // The text service could have added text nodes to the beginning
   // of the current block and called this method again. Make sure
   // we really are at the beginning of the current block:
 
-  nsresult rv = FirstTextNodeInCurrentBlock(aFilteredIter);
+  nsresult rv = FirstTextNodeInCurrentBlock(aIterator);
 
   NS_ENSURE_SUCCESS(rv, rv);
 
   int32_t offset = 0;
 
-  ClearDidSkip(aFilteredIter);
-
-  while (!aFilteredIter->IsDone()) {
+  ClearDidSkip(aIterator);
+
+  while (!aIterator->IsDone()) {
     nsCOMPtr<nsIContent> content =
-        aFilteredIter->GetCurrentNode()->IsContent()
-            ? aFilteredIter->GetCurrentNode()->AsContent()
+        aIterator->GetCurrentNode()->IsContent()
+            ? aIterator->GetCurrentNode()->AsContent()
             : nullptr;
     if (IsTextNode(content)) {
       if (prev && !HasSameBlockNodeParent(prev, content)) {
         break;
       }
 
       nsString str;
       content->GetNodeValue(str);
@@ -2579,27 +2604,27 @@ nsresult TextServicesDocument::CreateOff
       }
     }
     // XXX This should be checked before IsTextNode(), but IsBlockNode() returns
     //     true even if content is a text node.  See bug 1311934.
     else if (IsBlockNode(content)) {
       break;
     }
 
-    aFilteredIter->Next();
-
-    if (DidSkip(aFilteredIter)) {
+    aIterator->Next();
+
+    if (DidSkip(aIterator)) {
       break;
     }
   }
 
   if (first) {
     // Always leave the iterator pointing at the first
     // text node of the current block!
-    aFilteredIter->PositionAt(first);
+    aIterator->PositionAt(first);
   } else {
     // If we never ran across a text node, the iterator
     // might have been pointing to something invalid to
     // begin with.
     *aIteratorStatus = IteratorStatus::eDone;
   }
 
   return NS_OK;
--- a/editor/spellchecker/TextServicesDocument.h
+++ b/editor/spellchecker/TextServicesDocument.h
@@ -10,24 +10,24 @@
 #include "nsCycleCollectionParticipant.h"
 #include "nsIEditActionListener.h"
 #include "nsISupportsImpl.h"
 #include "nsStringFwd.h"
 #include "nsTArray.h"
 #include "nscore.h"
 
 class nsIContent;
+class nsIContentIterator;
 class nsIEditor;
 class nsINode;
 class nsISelectionController;
 class nsRange;
 
 namespace mozilla {
 
-class FilteredContentIterator;
 class OffsetEntry;
 class TextEditor;
 
 namespace dom {
 class Document;
 class Element;
 };
 
@@ -46,17 +46,17 @@ class TextServicesDocument final : publi
     ePrev,
     // No TN in CB, I points to first TN in next block.
     eNext,
   };
 
   RefPtr<dom::Document> mDocument;
   nsCOMPtr<nsISelectionController> mSelCon;
   RefPtr<TextEditor> mTextEditor;
-  RefPtr<FilteredContentIterator> mFilteredIter;
+  nsCOMPtr<nsIContentIterator> mIterator;
   nsCOMPtr<nsIContent> mPrevTextBlock;
   nsCOMPtr<nsIContent> mNextTextBlock;
   nsTArray<OffsetEntry*> mOffsetTable;
   RefPtr<nsRange> mExtent;
   uint32_t mTxtSvcFilterType;
 
   int32_t mSelStartIndex;
   int32_t mSelStartOffset;
@@ -226,48 +226,44 @@ class TextServicesDocument final : publi
   void DidJoinNodes(nsINode& aLeftNode, nsINode& aRightNode);
 
   static nsresult GetRangeEndPoints(nsRange* aRange, nsINode** aStartContainer,
                                     int32_t* aStartOffset,
                                     nsINode** aEndContainer,
                                     int32_t* aEndOffset);
 
  private:
-  nsresult CreateFilteredContentIterator(
-      nsRange* aRange, FilteredContentIterator** aFilteredIter);
+  nsresult CreateContentIterator(nsRange* aRange,
+                                 nsIContentIterator** aIterator);
 
   dom::Element* GetDocumentContentRootNode() const;
   already_AddRefed<nsRange> CreateDocumentContentRange();
   already_AddRefed<nsRange> CreateDocumentContentRootToNodeOffsetRange(
       nsINode* aParent, uint32_t aOffset, bool aToStart);
-  nsresult CreateDocumentContentIterator(
-      FilteredContentIterator** aFilteredIter);
+  nsresult CreateDocumentContentIterator(nsIContentIterator** aIterator);
 
   nsresult AdjustContentIterator();
 
-  static nsresult FirstTextNode(FilteredContentIterator* aFilteredIter,
+  static nsresult FirstTextNode(nsIContentIterator* aIterator,
                                 IteratorStatus* aIteratorStatus);
-  static nsresult LastTextNode(FilteredContentIterator* aFilteredIter,
+  static nsresult LastTextNode(nsIContentIterator* aIterator,
                                IteratorStatus* aIteratorStatus);
 
-  static nsresult FirstTextNodeInCurrentBlock(
-      FilteredContentIterator* aFilteredIter);
-  static nsresult FirstTextNodeInPrevBlock(
-      FilteredContentIterator* aFilteredIter);
-  static nsresult FirstTextNodeInNextBlock(
-      FilteredContentIterator* aFilteredIter);
+  static nsresult FirstTextNodeInCurrentBlock(nsIContentIterator* aIterator);
+  static nsresult FirstTextNodeInPrevBlock(nsIContentIterator* aIterator);
+  static nsresult FirstTextNodeInNextBlock(nsIContentIterator* aIterator);
 
   nsresult GetFirstTextNodeInPrevBlock(nsIContent** aContent);
   nsresult GetFirstTextNodeInNextBlock(nsIContent** aContent);
 
   static bool IsBlockNode(nsIContent* aContent);
   static bool IsTextNode(nsIContent* aContent);
 
-  static bool DidSkip(FilteredContentIterator* aFilteredIter);
-  static void ClearDidSkip(FilteredContentIterator* aFilteredIter);
+  static bool DidSkip(nsIContentIterator* aFilteredIter);
+  static void ClearDidSkip(nsIContentIterator* aFilteredIter);
 
   static bool HasSameBlockNodeParent(nsIContent* aContent1,
                                      nsIContent* aContent2);
 
   nsresult SetSelectionInternal(int32_t aOffset, int32_t aLength,
                                 bool aDoUpdate);
   nsresult GetSelection(BlockSelectionStatus* aSelStatus, int32_t* aSelOffset,
                         int32_t* aSelLength);
@@ -275,17 +271,17 @@ class TextServicesDocument final : publi
                                  int32_t* aSelOffset, int32_t* aSelLength);
   nsresult GetUncollapsedSelection(BlockSelectionStatus* aSelStatus,
                                    int32_t* aSelOffset, int32_t* aSelLength);
 
   bool SelectionIsCollapsed();
   bool SelectionIsValid();
 
   static nsresult CreateOffsetTable(nsTArray<OffsetEntry*>* aOffsetTable,
-                                    FilteredContentIterator* aFilteredIter,
+                                    nsIContentIterator* aIterator,
                                     IteratorStatus* aIteratorStatus,
                                     nsRange* aIterRange, nsString* aStr);
   static nsresult ClearOffsetTable(nsTArray<OffsetEntry*>* aOffsetTable);
 
   static nsresult NodeHasOffsetEntry(nsTArray<OffsetEntry*>* aOffsetTable,
                                      nsINode* aNode, bool* aHasEntry,
                                      int32_t* aEntryIndex);
 
--- a/editor/spellchecker/moz.build
+++ b/editor/spellchecker/moz.build
@@ -14,14 +14,14 @@ XPIDL_MODULE = 'txtsvc'
 
 EXPORTS.mozilla += [
     'EditorSpellCheck.h',
     'TextServicesDocument.h',
 ]
 
 UNIFIED_SOURCES += [
     'EditorSpellCheck.cpp',
-    'FilteredContentIterator.cpp',
     'nsComposeTxtSrvFilter.cpp',
+    'nsFilteredContentIterator.cpp',
     'TextServicesDocument.cpp',
 ]
 
 FINAL_LIBRARY = 'xul'
rename from editor/spellchecker/FilteredContentIterator.cpp
rename to editor/spellchecker/nsFilteredContentIterator.cpp
--- a/editor/spellchecker/FilteredContentIterator.cpp
+++ b/editor/spellchecker/nsFilteredContentIterator.cpp
@@ -1,176 +1,196 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
-#include "FilteredContentIterator.h"
-
-#include "mozilla/ContentIterator.h"
+#include "mozilla/mozalloc.h"
 #include "mozilla/Move.h"
-#include "mozilla/mozalloc.h"
-
 #include "nsComponentManagerUtils.h"
 #include "nsComposeTxtSrvFilter.h"
 #include "nsContentUtils.h"
 #include "nsDebug.h"
 #include "nsError.h"
+#include "nsFilteredContentIterator.h"
 #include "nsAtom.h"
 #include "nsIContent.h"
+#include "nsIContentIterator.h"
 #include "nsINode.h"
 #include "nsISupportsBase.h"
 #include "nsISupportsUtils.h"
 #include "nsRange.h"
 
-namespace mozilla {
+using namespace mozilla;
 
-FilteredContentIterator::FilteredContentIterator(
+//------------------------------------------------------------
+nsFilteredContentIterator::nsFilteredContentIterator(
     UniquePtr<nsComposeTxtSrvFilter> aFilter)
-    : mCurrentIterator(nullptr),
+    : mIterator(NS_NewContentIterator()),
+      mPreIterator(NS_NewPreContentIterator()),
       mFilter(std::move(aFilter)),
       mDidSkip(false),
       mIsOutOfRange(false),
       mDirection(eDirNotSet) {}
 
-FilteredContentIterator::~FilteredContentIterator() {}
+//------------------------------------------------------------
+nsFilteredContentIterator::~nsFilteredContentIterator() {}
 
-NS_IMPL_CYCLE_COLLECTION(FilteredContentIterator, mPostIterator, mPreIterator,
-                         mRange)
+//------------------------------------------------------------
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFilteredContentIterator)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFilteredContentIterator)
 
-NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(FilteredContentIterator, AddRef)
-NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(FilteredContentIterator, Release)
+NS_INTERFACE_MAP_BEGIN(nsFilteredContentIterator)
+  NS_INTERFACE_MAP_ENTRY(nsIContentIterator)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentIterator)
+  NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsFilteredContentIterator)
+NS_INTERFACE_MAP_END
 
-nsresult FilteredContentIterator::Init(nsINode* aRoot) {
+NS_IMPL_CYCLE_COLLECTION(nsFilteredContentIterator, mCurrentIterator, mIterator,
+                         mPreIterator, mRange)
+
+//------------------------------------------------------------
+nsresult nsFilteredContentIterator::Init(nsINode* aRoot) {
   NS_ENSURE_ARG_POINTER(aRoot);
+  NS_ENSURE_TRUE(mPreIterator, NS_ERROR_FAILURE);
+  NS_ENSURE_TRUE(mIterator, 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 mIterator->Init(mRange);
 }
 
-nsresult FilteredContentIterator::Init(nsRange* aRange) {
+//------------------------------------------------------------
+nsresult nsFilteredContentIterator::Init(nsRange* aRange) {
   if (NS_WARN_IF(!aRange)) {
     return NS_ERROR_INVALID_ARG;
   }
 
   if (NS_WARN_IF(!aRange->IsPositioned())) {
     return NS_ERROR_INVALID_ARG;
   }
 
   mRange = aRange->CloneRange();
 
   return InitWithRange();
 }
 
-nsresult FilteredContentIterator::Init(nsINode* aStartContainer,
-                                       uint32_t aStartOffset,
-                                       nsINode* aEndContainer,
-                                       uint32_t aEndOffset) {
+//------------------------------------------------------------
+nsresult nsFilteredContentIterator::Init(nsINode* aStartContainer,
+                                         uint32_t aStartOffset,
+                                         nsINode* aEndContainer,
+                                         uint32_t aEndOffset) {
   return Init(RawRangeBoundary(aStartContainer, aStartOffset),
               RawRangeBoundary(aEndContainer, aEndOffset));
 }
 
-nsresult FilteredContentIterator::Init(const RawRangeBoundary& aStart,
-                                       const RawRangeBoundary& aEnd) {
+nsresult nsFilteredContentIterator::Init(const RawRangeBoundary& aStart,
+                                         const RawRangeBoundary& aEnd) {
   RefPtr<nsRange> range;
   nsresult rv = nsRange::CreateRange(aStart, aEnd, getter_AddRefs(range));
   if (NS_WARN_IF(NS_FAILED(rv)) || NS_WARN_IF(!range) ||
       NS_WARN_IF(!range->IsPositioned())) {
     return NS_ERROR_INVALID_ARG;
   }
 
   MOZ_ASSERT(range->StartRef() == aStart);
   MOZ_ASSERT(range->EndRef() == aEnd);
 
   mRange = std::move(range);
 
   return InitWithRange();
 }
 
-nsresult FilteredContentIterator::InitWithRange() {
+nsresult nsFilteredContentIterator::InitWithRange() {
   MOZ_ASSERT(mRange);
   MOZ_ASSERT(mRange->IsPositioned());
 
+  if (NS_WARN_IF(!mPreIterator) || NS_WARN_IF(!mIterator)) {
+    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 mIterator->Init(mRange);
 }
 
-nsresult FilteredContentIterator::SwitchDirections(bool aChangeToForward) {
+//------------------------------------------------------------
+nsresult nsFilteredContentIterator::SwitchDirections(bool aChangeToForward) {
   nsINode* node = mCurrentIterator->GetCurrentNode();
 
   if (aChangeToForward) {
-    mCurrentIterator = &mPreIterator;
+    mCurrentIterator = mPreIterator;
     mDirection = eForward;
   } else {
-    mCurrentIterator = &mPostIterator;
+    mCurrentIterator = mIterator;
     mDirection = eBackward;
   }
 
   if (node) {
     nsresult rv = mCurrentIterator->PositionAt(node);
     if (NS_FAILED(rv)) {
       mIsOutOfRange = true;
       return rv;
     }
   }
   return NS_OK;
 }
 
-void FilteredContentIterator::First() {
+//------------------------------------------------------------
+void nsFilteredContentIterator::First() {
   if (!mCurrentIterator) {
     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;
   }
 
   nsINode* currentNode = mCurrentIterator->GetCurrentNode();
 
   bool didCross;
   CheckAdvNode(currentNode, didCross, eForward);
 }
 
-void FilteredContentIterator::Last() {
+//------------------------------------------------------------
+void nsFilteredContentIterator::Last() {
   if (!mCurrentIterator) {
     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 = mIterator;
     mDirection = eBackward;
     mIsOutOfRange = false;
   }
 
   mCurrentIterator->Last();
 
   if (mCurrentIterator->IsDone()) {
     return;
@@ -235,20 +255,21 @@ static bool ContentIsInTraversalRange(ns
   NS_ENSURE_TRUE(aNextContent && aRange, false);
 
   return ContentIsInTraversalRange(
       aNextContent, aIsPreMode, aRange->GetStartContainer(),
       static_cast<int32_t>(aRange->StartOffset()), aRange->GetEndContainer(),
       static_cast<int32_t>(aRange->EndOffset()));
 }
 
+//------------------------------------------------------------
 // Helper function to advance to the next or previous node
-nsresult FilteredContentIterator::AdvanceNode(nsINode* aNode,
-                                              nsINode*& aNewNode,
-                                              eDirectionType aDir) {
+nsresult nsFilteredContentIterator::AdvanceNode(nsINode* aNode,
+                                                nsINode*& aNewNode,
+                                                eDirectionType aDir) {
   nsCOMPtr<nsIContent> nextNode;
   if (aDir == eForward) {
     nextNode = aNode->GetNextSibling();
   } else {
     nextNode = aNode->GetPreviousSibling();
   }
 
   if (nextNode) {
@@ -282,19 +303,20 @@ nsresult FilteredContentIterator::Advanc
 
   // if we get here it pretty much means
   // we went out of the DOM Range
   mIsOutOfRange = true;
 
   return NS_ERROR_FAILURE;
 }
 
+//------------------------------------------------------------
 // Helper function to see if the next/prev node should be skipped
-void FilteredContentIterator::CheckAdvNode(nsINode* aNode, bool& aDidSkip,
-                                           eDirectionType aDir) {
+void nsFilteredContentIterator::CheckAdvNode(nsINode* aNode, bool& aDidSkip,
+                                             eDirectionType aDir) {
   aDidSkip = false;
   mIsOutOfRange = false;
 
   if (aNode && mFilter) {
     nsCOMPtr<nsINode> currentNode = aNode;
     while (1) {
       if (mFilter->Skip(aNode)) {
         aDidSkip = true;
@@ -313,17 +335,17 @@ void FilteredContentIterator::CheckAdvNo
           mCurrentIterator->PositionAt(content);
         }
         return;  // found something
       }
     }
   }
 }
 
-void FilteredContentIterator::Next() {
+void nsFilteredContentIterator::Next() {
   if (mIsOutOfRange || !mCurrentIterator) {
     NS_ASSERTION(mCurrentIterator, "Missing iterator!");
 
     return;
   }
 
   // If we are switching directions then
   // we need to switch how we process the nodes
@@ -342,17 +364,17 @@ void FilteredContentIterator::Next() {
 
   // If we can't get the current node then
   // don't check to see if we can skip it
   nsINode* currentNode = mCurrentIterator->GetCurrentNode();
 
   CheckAdvNode(currentNode, mDidSkip, eForward);
 }
 
-void FilteredContentIterator::Prev() {
+void nsFilteredContentIterator::Prev() {
   if (mIsOutOfRange || !mCurrentIterator) {
     NS_ASSERTION(mCurrentIterator, "Missing iterator!");
 
     return;
   }
 
   // If we are switching directions then
   // we need to switch how we process the nodes
@@ -371,31 +393,29 @@ void FilteredContentIterator::Prev() {
 
   // If we can't get the current node then
   // don't check to see if we can skip it
   nsINode* currentNode = mCurrentIterator->GetCurrentNode();
 
   CheckAdvNode(currentNode, mDidSkip, eBackward);
 }
 
-nsINode* FilteredContentIterator::GetCurrentNode() {
+nsINode* nsFilteredContentIterator::GetCurrentNode() {
   if (mIsOutOfRange || !mCurrentIterator) {
     return nullptr;
   }
 
   return mCurrentIterator->GetCurrentNode();
 }
 
-bool FilteredContentIterator::IsDone() {
+bool nsFilteredContentIterator::IsDone() {
   if (mIsOutOfRange || !mCurrentIterator) {
     return true;
   }
 
   return mCurrentIterator->IsDone();
 }
 
-nsresult FilteredContentIterator::PositionAt(nsINode* aCurNode) {
+nsresult nsFilteredContentIterator::PositionAt(nsINode* aCurNode) {
   NS_ENSURE_TRUE(mCurrentIterator, NS_ERROR_FAILURE);
   mIsOutOfRange = false;
   return mCurrentIterator->PositionAt(aCurNode);
 }
-
-}  // namespace mozilla
rename from editor/spellchecker/FilteredContentIterator.h
rename to editor/spellchecker/nsFilteredContentIterator.h
--- a/editor/spellchecker/FilteredContentIterator.h
+++ b/editor/spellchecker/nsFilteredContentIterator.h
@@ -1,83 +1,83 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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 FilteredContentIterator_h
-#define FilteredContentIterator_h
+#ifndef nsFilteredContentIterator_h__
+#define nsFilteredContentIterator_h__
 
-#include "nsComposeTxtSrvFilter.h"
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
+#include "nsIContentIterator.h"
 #include "nsISupportsImpl.h"
 #include "nscore.h"
-#include "mozilla/ContentIterator.h"
 #include "mozilla/UniquePtr.h"
 
 class nsAtom;
+class nsComposeTxtSrvFilter;
 class nsINode;
 class nsRange;
 
-namespace mozilla {
-
-class FilteredContentIterator final {
+class nsFilteredContentIterator final : public nsIContentIterator {
  public:
-  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(FilteredContentIterator)
-  NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(FilteredContentIterator)
+  // nsISupports interface...
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS(nsFilteredContentIterator)
 
-  explicit FilteredContentIterator(UniquePtr<nsComposeTxtSrvFilter> aFilter);
+  explicit nsFilteredContentIterator(
+      mozilla::UniquePtr<nsComposeTxtSrvFilter> aFilter);
 
-  nsresult Init(nsINode* aRoot);
-  nsresult Init(nsRange* aRange);
-  nsresult Init(nsINode* aStartContainer, uint32_t aStartOffset,
-                nsINode* aEndContainer, uint32_t aEndOffset);
-  nsresult Init(const RawRangeBoundary& aStart, const RawRangeBoundary& aEnd);
-  void First();
-  void Last();
-  void Next();
-  void Prev();
-  nsINode* GetCurrentNode();
-  bool IsDone();
-  nsresult PositionAt(nsINode* aCurNode);
+  /* nsIContentIterator */
+  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 mozilla::RawRangeBoundary& aStart,
+                        const mozilla::RawRangeBoundary& aEnd) override;
+  virtual void First() override;
+  virtual void Last() override;
+  virtual void Next() override;
+  virtual void Prev() override;
+  virtual nsINode* GetCurrentNode() override;
+  virtual bool IsDone() override;
+  virtual nsresult PositionAt(nsINode* aCurNode) override;
 
   /* Helpers */
   bool DidSkip() { return mDidSkip; }
   void ClearDidSkip() { mDidSkip = false; }
 
  protected:
-  FilteredContentIterator()
+  nsFilteredContentIterator()
       : mDidSkip(false), mIsOutOfRange(false), mDirection{eDirNotSet} {}
 
-  virtual ~FilteredContentIterator();
+  virtual ~nsFilteredContentIterator();
 
   /**
    * Callers must guarantee that mRange isn't nullptr and it's positioned.
    */
   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);
 
-  ContentIteratorBase* MOZ_NON_OWNING_REF mCurrentIterator;
-  PostContentIterator mPostIterator;
-  PreContentIterator mPreIterator;
+  nsCOMPtr<nsIContentIterator> mCurrentIterator;
+  nsCOMPtr<nsIContentIterator> mIterator;
+  nsCOMPtr<nsIContentIterator> mPreIterator;
 
   RefPtr<nsAtom> mBlockQuoteAtom;
   RefPtr<nsAtom> mScriptAtom;
   RefPtr<nsAtom> mTextAreaAtom;
   RefPtr<nsAtom> mSelectAreaAtom;
   RefPtr<nsAtom> mMapAtom;
 
-  UniquePtr<nsComposeTxtSrvFilter> mFilter;
+  mozilla::UniquePtr<nsComposeTxtSrvFilter> mFilter;
   RefPtr<nsRange> mRange;
   bool mDidSkip;
   bool mIsOutOfRange;
   eDirectionType mDirection;
 };
 
-}  // namespace mozilla
-
-#endif  // #ifndef FilteredContentIterator_h
+#endif
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -7,17 +7,16 @@
 /* a presentation of a document, part 2 */
 
 #include "mozilla/PresShell.h"
 
 #include "mozilla/dom/FontFaceSet.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/AutoRestore.h"
-#include "mozilla/ContentIterator.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/IMEStateManager.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/Likely.h"
 #include "mozilla/Logging.h"
@@ -36,16 +35,17 @@
 #endif
 
 #include "gfxContext.h"
 #include "gfxPrefs.h"
 #include "gfxUserFontSet.h"
 #include "nsContentList.h"
 #include "nsPresContext.h"
 #include "nsIContent.h"
+#include "nsIContentIterator.h"
 #include "nsIPresShellInlines.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/PointerEventHandler.h"
 #include "mozilla/dom/PopupBlocker.h"
 #include "mozilla/dom/Document.h"
 #include "nsAnimationManager.h"
 #include "nsNameSpaceManager.h"  // for Pref-related rule management (bugs 22963,20760,31816)
 #include "nsFrame.h"
@@ -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);
 
-  ContentSubtreeIterator subtreeIter;
-  nsresult rv = subtreeIter.Init(aRange);
+  nsCOMPtr<nsIContentIterator> iter = NS_NewContentSubtreeIterator();
+  nsresult rv = iter->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 (; !iter->IsDone(); iter->Next()) {
+    nsCOMPtr<nsINode> node = iter->GetCurrentNode();
     BuildDisplayListForNode(node);
   }
   if (endContainer != startContainer &&
       endContainer->NodeType() == nsINode::TEXT_NODE) {
     BuildDisplayListForNode(endContainer);
   }
 
 #ifdef DEBUG
--- a/layout/generic/nsFrameSelection.cpp
+++ b/layout/generic/nsFrameSelection.cpp
@@ -24,16 +24,17 @@
 #include "nsIContent.h"
 #include "nsRange.h"
 #include "nsITableCellLayout.h"
 #include "nsTArray.h"
 #include "nsTableWrapperFrame.h"
 #include "nsTableCellFrame.h"
 #include "nsIScrollableFrame.h"
 #include "nsCCUncollectableMarker.h"
+#include "nsIContentIterator.h"
 #include "nsIDocumentEncoder.h"
 #include "nsTextFragment.h"
 #include <algorithm>
 #include "nsContentUtils.h"
 #include "nsCSSFrameConstructor.h"
 
 #include "nsGkAtoms.h"
 #include "nsIFrameTraversal.h"
--- a/toolkit/components/find/nsFind.cpp
+++ b/toolkit/components/find/nsFind.cpp
@@ -30,16 +30,19 @@
 #include "mozilla/dom/Text.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 // Yikes!  Casting a char to unichar can fill with ones!
 #define CHAR_TO_UNICHAR(c) ((char16_t)(unsigned char)c)
 
+static NS_DEFINE_CID(kCContentIteratorCID, NS_CONTENTITERATOR_CID);
+static NS_DEFINE_CID(kCPreContentIteratorCID, NS_PRECONTENTITERATOR_CID);
+
 #define CH_QUOTE ((char16_t)0x22)
 #define CH_APOSTROPHE ((char16_t)0x27)
 #define CH_LEFT_SINGLE_QUOTE ((char16_t)0x2018)
 #define CH_RIGHT_SINGLE_QUOTE ((char16_t)0x2019)
 #define CH_LEFT_DOUBLE_QUOTE ((char16_t)0x201C)
 #define CH_RIGHT_DOUBLE_QUOTE ((char16_t)0x201D)
 
 #define CH_SHY ((char16_t)0xAD)
--- a/toolkit/components/find/nsFind.h
+++ b/toolkit/components/find/nsFind.h
@@ -7,16 +7,17 @@
 #ifndef nsFind_h__
 #define nsFind_h__
 
 #include "nsIFind.h"
 
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsINode.h"
+#include "nsIContentIterator.h"
 #include "mozilla/intl/WordBreaker.h"
 
 class nsIContent;
 class nsRange;
 
 #define NS_FIND_CONTRACTID "@mozilla.org/embedcomp/rangefind;1"
 
 #define NS_FIND_CID                                  \