Bug 1455891: Remove nsFindContentIterator. r?mats draft
authorEmilio Cobos Álvarez <emilio@crisal.io>
Tue, 03 Jul 2018 09:48:42 +0200
changeset 813919 d0c3a5475f3335c4b94e108dcca33483b4e50bc3
parent 813918 217933c4a41ecf50e5d894b704edbb1df229e6ee
child 813920 da8525dc3818977f0202bbd614ab9e24a8097781
push id115046
push userbmo:emilio@crisal.io
push dateWed, 04 Jul 2018 05:02:13 +0000
reviewersmats
bugs1455891
milestone63.0a1
Bug 1455891: Remove nsFindContentIterator. r?mats MozReview-Commit-ID: 58AFqqaSLcC
toolkit/components/find/nsFind.cpp
--- a/toolkit/components/find/nsFind.cpp
+++ b/toolkit/components/find/nsFind.cpp
@@ -46,448 +46,16 @@ static NS_DEFINE_CID(kCPreContentIterato
 #define CH_RIGHT_DOUBLE_QUOTE ((char16_t)0x201D)
 
 #define CH_SHY ((char16_t)0xAD)
 
 // nsFind::Find casts CH_SHY to char before calling StripChars
 // This works correctly if and only if CH_SHY <= 255
 static_assert(CH_SHY <= 255, "CH_SHY is not an ascii character");
 
-// nsFindContentIterator is a special iterator that also goes through any
-// existing <textarea>'s or text <input>'s editor to lookup the anonymous DOM
-// content there.
-//
-// Details:
-// 1) We use two iterators: The "outer-iterator" goes through the normal DOM.
-// The "inner-iterator" goes through the anonymous DOM inside the editor.
-//
-// 2) [MaybeSetupInnerIterator] As soon as the outer-iterator's current node is
-// changed, a check is made to see if the node is a <textarea> or a text <input>
-// node. If so, an inner-iterator is created to lookup the anynomous contents of
-// the editor underneath the text control.
-//
-// 3) When the inner-iterator is created, we position the outer-iterator 'after'
-// (or 'before' in backward search) the text control to avoid revisiting that
-// control.
-//
-// 4) As a consequence of searching through text controls, we can be called via
-// FindNext with the current selection inside a <textarea> or a text <input>.
-// This means that we can be given an initial search range that stretches across
-// the anonymous DOM and the normal DOM. To cater for this situation, we split
-// the anonymous part into the inner-iterator and then reposition the outer-
-// iterator outside.
-//
-// 5) The implementation assumes that First() and Next() are only called in
-// find-forward mode, while Last() and Prev() are used in find-backward.
-
-class nsFindContentIterator final : public nsIContentIterator
-{
-public:
-  explicit nsFindContentIterator(bool aFindBackward)
-    : mStartOffset(0)
-    , mEndOffset(0)
-    , mFindBackward(aFindBackward)
-  {
-  }
-
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_CLASS(nsFindContentIterator)
-
-  // nsIContentIterator
-  virtual nsresult Init(nsINode* aRoot) override
-  {
-    MOZ_ASSERT_UNREACHABLE("internal error");
-    return NS_ERROR_NOT_IMPLEMENTED;
-  }
-  virtual nsresult Init(nsRange* aRange) override
-  {
-    MOZ_ASSERT_UNREACHABLE("internal error");
-    return NS_ERROR_NOT_IMPLEMENTED;
-  }
-  virtual nsresult Init(nsINode* aStartContainer, uint32_t aStartOffset,
-                        nsINode* aEndContainer, uint32_t aEndOffset) override
-  {
-    MOZ_ASSERT_UNREACHABLE("internal error");
-    return NS_ERROR_NOT_IMPLEMENTED;
-  }
-  virtual nsresult Init(const RawRangeBoundary& aStart,
-                        const RawRangeBoundary& aEnd) override
-  {
-    MOZ_ASSERT_UNREACHABLE("internal error");
-    return NS_ERROR_NOT_IMPLEMENTED;
-  }
-  // Not a range because one of the endpoints may be anonymous.
-  nsresult Init(nsINode* aStartNode, int32_t aStartOffset,
-                nsINode* aEndNode, int32_t aEndOffset);
-  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;
-
-  void Reset();
-protected:
-  virtual ~nsFindContentIterator() {}
-
-private:
-  static already_AddRefed<nsRange> CreateRange(nsINode* aNode)
-  {
-    RefPtr<nsRange> range = new nsRange(aNode);
-    range->SetMaySpanAnonymousSubtrees(true);
-    return range.forget();
-  }
-
-  nsCOMPtr<nsIContentIterator> mOuterIterator;
-  nsCOMPtr<nsIContentIterator> mInnerIterator;
-  // Can't use a range here, since we want to represent part of the flattened
-  // tree, including native anonymous content.
-  nsCOMPtr<nsINode> mStartNode;
-  int32_t mStartOffset;
-  nsCOMPtr<nsINode> mEndNode;
-  int32_t mEndOffset;
-
-  nsCOMPtr<nsIContent> mStartOuterContent;
-  nsCOMPtr<nsIContent> mEndOuterContent;
-  bool mFindBackward;
-
-  void MaybeSetupInnerIterator();
-  void SetupInnerIterator(nsIContent* aContent);
-};
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFindContentIterator)
-  NS_INTERFACE_MAP_ENTRY(nsIContentIterator)
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
-NS_INTERFACE_MAP_END
-
-NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFindContentIterator)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFindContentIterator)
-
-NS_IMPL_CYCLE_COLLECTION(nsFindContentIterator, mOuterIterator, mInnerIterator,
-                         mStartOuterContent, mEndOuterContent, mEndNode,
-                         mStartNode)
-
-nsresult
-nsFindContentIterator::Init(nsINode* aStartNode, int32_t aStartOffset,
-                            nsINode* aEndNode, int32_t aEndOffset)
-{
-  NS_ENSURE_ARG_POINTER(aStartNode);
-  NS_ENSURE_ARG_POINTER(aEndNode);
-  if (!mOuterIterator) {
-    if (mFindBackward) {
-      // Use post-order in the reverse case, so we get parents before children
-      // in case we want to prevent descending into a node.
-      mOuterIterator = do_CreateInstance(kCContentIteratorCID);
-    } else {
-      // Use pre-order in the forward case, so we get parents before children in
-      // case we want to prevent descending into a node.
-      mOuterIterator = do_CreateInstance(kCPreContentIteratorCID);
-    }
-    NS_ENSURE_ARG_POINTER(mOuterIterator);
-  }
-
-  // Set up the search "range" that we will examine
-  mStartNode = aStartNode;
-  mStartOffset = aStartOffset;
-  mEndNode = aEndNode;
-  mEndOffset = aEndOffset;
-
-  return NS_OK;
-}
-
-void
-nsFindContentIterator::First()
-{
-  Reset();
-}
-
-void
-nsFindContentIterator::Last()
-{
-  Reset();
-}
-
-void
-nsFindContentIterator::Next()
-{
-  if (mInnerIterator) {
-    mInnerIterator->Next();
-    if (!mInnerIterator->IsDone()) {
-      return;
-    }
-
-    // by construction, mOuterIterator is already on the next node
-  } else {
-    mOuterIterator->Next();
-  }
-  MaybeSetupInnerIterator();
-}
-
-void
-nsFindContentIterator::Prev()
-{
-  if (mInnerIterator) {
-    mInnerIterator->Prev();
-    if (!mInnerIterator->IsDone()) {
-      return;
-    }
-
-    // by construction, mOuterIterator is already on the previous node
-  } else {
-    mOuterIterator->Prev();
-  }
-  MaybeSetupInnerIterator();
-}
-
-nsINode*
-nsFindContentIterator::GetCurrentNode()
-{
-  if (mInnerIterator && !mInnerIterator->IsDone()) {
-    return mInnerIterator->GetCurrentNode();
-  }
-  return mOuterIterator->GetCurrentNode();
-}
-
-bool
-nsFindContentIterator::IsDone()
-{
-  if (mInnerIterator && !mInnerIterator->IsDone()) {
-    return false;
-  }
-  return mOuterIterator->IsDone();
-}
-
-static nsIContent&
-AnonymousSubtreeRootParent(nsINode& aNode)
-{
-  MOZ_ASSERT(aNode.IsInNativeAnonymousSubtree());
-
-  nsIContent* current = aNode.GetParent();
-  while (current->IsInNativeAnonymousSubtree()) {
-    current = current->GetParent();
-    MOZ_ASSERT(current, "huh?");
-  }
-  return *current;
-}
-
-nsresult
-nsFindContentIterator::PositionAt(nsINode* aCurNode)
-{
-  nsresult rv = mOuterIterator->PositionAt(aCurNode);
-  if (NS_SUCCEEDED(rv)) {
-    MaybeSetupInnerIterator();
-    return rv;
-  }
-
-  // If this failed, it means that aCurNode is necessarily anonymous.
-  nsIContent& nonAnonNode = AnonymousSubtreeRootParent(*aCurNode);
-  SetupInnerIterator(&nonAnonNode);
-  MOZ_ASSERT(mInnerIterator, "How did we have an anonymous node otherwise?");
-  rv = mInnerIterator->PositionAt(aCurNode);
-  MOZ_ASSERT(NS_SUCCEEDED(rv));
-  if (!mOuterIterator->IsDone()) {
-    if (mFindBackward) {
-      mOuterIterator->Last();
-    } else {
-      mOuterIterator->First();
-    }
-  }
-  return rv;
-}
-
-void
-nsFindContentIterator::Reset()
-{
-  mInnerIterator = nullptr;
-  mStartOuterContent = nullptr;
-  mEndOuterContent = nullptr;
-
-  // As a consequence of searching through text controls, we may have been
-  // initialized with a selection inside a <textarea> or a text <input>.
-
-  // see if the start node is an anonymous text node inside a text control
-  nsCOMPtr<nsIContent> startContent(do_QueryInterface(mStartNode));
-  if (startContent) {
-    mStartOuterContent = startContent->FindFirstNonChromeOnlyAccessContent();
-  }
-
-  // see if the end node is an anonymous text node inside a text control
-  nsCOMPtr<nsIContent> endContent(do_QueryInterface(mEndNode));
-  if (endContent) {
-    mEndOuterContent = endContent->FindFirstNonChromeOnlyAccessContent();
-  }
-
-  // Note: OK to just set up the outer iterator here; if our range has a native
-  // anonymous endpoint we'll end up setting up an inner iterator, and reset the
-  // outer one in the process.
-  nsCOMPtr<nsINode> node = mStartNode;
-  NS_ENSURE_TRUE_VOID(node);
-
-  RefPtr<nsRange> range = CreateRange(node);
-  range->SetStart(*mStartNode, mStartOffset, IgnoreErrors());
-  range->SetEnd(*mEndNode, mEndOffset, IgnoreErrors());
-  mOuterIterator->Init(range);
-
-  if (!mFindBackward) {
-    if (mStartOuterContent != startContent) {
-      // the start node was an anonymous text node
-      SetupInnerIterator(mStartOuterContent);
-      if (mInnerIterator) {
-        mInnerIterator->First();
-      }
-    }
-    if (!mOuterIterator->IsDone()) {
-      mOuterIterator->First();
-    }
-  } else {
-    if (mEndOuterContent != endContent) {
-      // the end node was an anonymous text node
-      SetupInnerIterator(mEndOuterContent);
-      if (mInnerIterator) {
-        mInnerIterator->Last();
-      }
-    }
-    if (!mOuterIterator->IsDone()) {
-      mOuterIterator->Last();
-    }
-  }
-
-  // if we didn't create an inner-iterator, the boundary node could still be
-  // a text control, in which case we also need an inner-iterator straightaway
-  if (!mInnerIterator) {
-    MaybeSetupInnerIterator();
-  }
-}
-
-void
-nsFindContentIterator::MaybeSetupInnerIterator()
-{
-  mInnerIterator = nullptr;
-
-  nsCOMPtr<nsIContent> content =
-    do_QueryInterface(mOuterIterator->GetCurrentNode());
-  if (!content || !content->IsNodeOfType(nsINode::eHTML_FORM_CONTROL)) {
-    return;
-  }
-
-  nsCOMPtr<nsIFormControl> formControl(do_QueryInterface(content));
-  if (!formControl->IsTextControl(true)) {
-    return;
-  }
-
-  SetupInnerIterator(content);
-  if (mInnerIterator) {
-    if (!mFindBackward) {
-      mInnerIterator->First();
-      // finish setup: position mOuterIterator on the actual "next" node (this
-      // completes its re-init, @see SetupInnerIterator)
-      if (!mOuterIterator->IsDone()) {
-        mOuterIterator->First();
-      }
-    } else {
-      mInnerIterator->Last();
-      // finish setup: position mOuterIterator on the actual "previous" node
-      // (this completes its re-init, @see SetupInnerIterator)
-      if (!mOuterIterator->IsDone()) {
-        mOuterIterator->Last();
-      }
-    }
-  }
-}
-
-void
-nsFindContentIterator::SetupInnerIterator(nsIContent* aContent)
-{
-  if (!aContent) {
-    return;
-  }
-  NS_ASSERTION(!aContent->IsRootOfNativeAnonymousSubtree(), "invalid call");
-
-  nsITextControlFrame* tcFrame = do_QueryFrame(aContent->GetPrimaryFrame());
-  if (!tcFrame) {
-    return;
-  }
-
-  // don't mess with disabled input fields
-  RefPtr<TextEditor> textEditor = tcFrame->GetTextEditor();
-  if (!textEditor || textEditor->IsDisabled()) {
-    return;
-  }
-
-  RefPtr<dom::Element> rootElement = textEditor->GetRoot();
-
-  if (!rootElement) {
-    return;
-  }
-
-  RefPtr<nsRange> innerRange = CreateRange(aContent);
-  RefPtr<nsRange> outerRange = CreateRange(aContent);
-  if (!innerRange || !outerRange) {
-    return;
-  }
-
-  // now create the inner-iterator
-  mInnerIterator = do_CreateInstance(kCPreContentIteratorCID);
-
-  if (mInnerIterator) {
-    innerRange->SelectNodeContents(*rootElement, IgnoreErrors());
-
-    // fix up the inner bounds, we may have to only lookup a portion
-    // of the text control if the current node is a boundary point
-    if (aContent == mStartOuterContent) {
-      innerRange->SetStart(*mStartNode, mStartOffset, IgnoreErrors());
-    }
-    if (aContent == mEndOuterContent) {
-      innerRange->SetEnd(*mEndNode, mEndOffset, IgnoreErrors());
-    }
-    // Note: we just init here. We do First() or Last() later.
-    mInnerIterator->Init(innerRange);
-
-    // make sure to place the outer-iterator outside the text control so that we
-    // don't go there again.
-    IgnoredErrorResult res1, res2;
-    if (!mFindBackward) { // find forward
-      // cut the outer-iterator after the current node
-      outerRange->SetEnd(*mEndNode, mEndOffset, res1);
-      outerRange->SetStartAfter(*aContent, res2);
-    } else { // find backward
-      // cut the outer-iterator before the current node
-      outerRange->SetStart(*mStartNode, mStartOffset, res1);
-      outerRange->SetEndBefore(*aContent, res2);
-    }
-    if (res1.Failed() || res2.Failed()) {
-      // we are done with the outer-iterator, the inner-iterator will traverse
-      // what we want
-      outerRange->Collapse(true);
-    }
-
-    // Note: we just re-init here, using the segment of our search range that
-    // is yet to be visited. Thus when we later do mOuterIterator->First() [or
-    // mOuterIterator->Last()], we will effectively be on the next node [or
-    // the previous node] _with respect to_ the search range.
-    mOuterIterator->Init(outerRange);
-  }
-}
-
-nsresult
-NS_NewFindContentIterator(bool aFindBackward, nsIContentIterator** aResult)
-{
-  NS_ENSURE_ARG_POINTER(aResult);
-  if (!aResult) {
-    return NS_ERROR_NULL_POINTER;
-  }
-
-  nsFindContentIterator* it = new nsFindContentIterator(aFindBackward);
-  if (!it) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-  return it->QueryInterface(NS_GET_IID(nsIContentIterator), (void**)aResult);
-}
-
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFind)
   NS_INTERFACE_MAP_ENTRY(nsIFind)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFind)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFind)
 
@@ -503,16 +71,29 @@ nsFind::nsFind()
 nsFind::~nsFind() = default;
 
 #ifdef DEBUG_FIND
 #define DEBUG_FIND_PRINTF(...) printf(__VA_ARGS__)
 #else
 #define DEBUG_FIND_PRINTF(...) /* nothing */
 #endif
 
+static nsIContent&
+AnonymousSubtreeRootParent(const nsINode& aNode)
+{
+  MOZ_ASSERT(aNode.IsInNativeAnonymousSubtree());
+
+  nsIContent* current = aNode.GetParent();
+  while (current->IsInNativeAnonymousSubtree()) {
+    current = current->GetParent();
+    MOZ_ASSERT(current, "huh?");
+  }
+  return *current;
+}
+
 static void
 DumpNode(const nsINode* aNode)
 {
 #ifdef DEBUG_FIND
   if (!aNode) {
     printf(">>>> Node: NULL\n");
     return;
   }