Bug 1455891: Use TreeIterator in nsFind. r?mats draft
authorEmilio Cobos Álvarez <emilio@crisal.io>
Tue, 03 Jul 2018 08:40:13 +0200
changeset 813918 217933c4a41ecf50e5d894b704edbb1df229e6ee
parent 813917 00d0cb65f72503452bcf83d3ea41240330c2dfb8
child 813919 d0c3a5475f3335c4b94e108dcca33483b4e50bc3
push id115046
push userbmo:emilio@crisal.io
push dateWed, 04 Jul 2018 05:02:13 +0000
reviewersmats
bugs1455891
milestone63.0a1
Bug 1455891: Use TreeIterator in nsFind. r?mats MozReview-Commit-ID: GSY5w6NYRS
toolkit/components/find/nsFind.cpp
--- a/toolkit/components/find/nsFind.cpp
+++ b/toolkit/components/find/nsFind.cpp
@@ -19,16 +19,18 @@
 #include "nsAtom.h"
 #include "nsServiceManagerUtils.h"
 #include "nsUnicharUtils.h"
 #include "nsCRT.h"
 #include "nsRange.h"
 #include "nsContentUtils.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/TextEditor.h"
+#include "mozilla/dom/ChildIterator.h"
+#include "mozilla/dom/TreeIterator.h"
 #include "mozilla/dom/Element.h"
 #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)
@@ -573,30 +575,47 @@ IsVisibleNode(const nsINode* aNode)
     // display: contents
     return true;
   }
 
   return frame->StyleVisibility()->IsVisible();
 }
 
 static bool
+IsTextFormControl(nsIContent& aContent)
+{
+  if (!aContent.IsNodeOfType(nsINode::eHTML_FORM_CONTROL)) {
+    return false;
+  }
+
+  nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(&aContent);
+  return formControl->IsTextControl(true);
+}
+
+static bool
 SkipNode(const nsIContent* aContent)
 {
   const nsIContent* content = aContent;
   while (content) {
     if (!IsDisplayedNode(content) ||
         content->IsComment() ||
         content->IsAnyOfHTMLElements(nsGkAtoms::script,
                                      nsGkAtoms::noframes,
                                      nsGkAtoms::select)) {
       DEBUG_FIND_PRINTF("Skipping node: ");
       DumpNode(content);
       return true;
     }
 
+    // Skip NAC in non-form-control.
+    if (content->IsInNativeAnonymousSubtree() &&
+        !IsTextFormControl(AnonymousSubtreeRootParent(*content))) {
+      return true;
+    }
+
     // Only climb to the nearest block node
     if (IsBlockNode(content)) {
       return false;
     }
 
     content = content->GetParent();
   }
 
@@ -614,37 +633,35 @@ GetBlockParent(const Text* aNode)
       return current;
     }
   }
   return nullptr;
 }
 
 struct nsFind::State final
 {
-  // Disallow copying because copying the iterator would be a lie.
-  State(const State&) = delete;
-
-  State(bool aFindBackward,
-        const nsRange& aSearchRange,
-        const nsRange& aStartPoint,
-        const nsRange& aEndPoint)
+  State(bool aFindBackward, nsIContent& aRoot, const nsRange& aStartPoint)
     : mFindBackward(aFindBackward)
     , mInitialized(false)
     , mIterOffset(-1)
     , mLastBlockParent(nullptr)
-    , mSearchRange(aSearchRange)
+    , mIterator(aRoot)
     , mStartPoint(aStartPoint)
-    , mEndPoint(aEndPoint)
   {
   }
 
+  void PositionAt(Text& aNode)
+  {
+    mIterator.Seek(aNode);
+  }
+
   Text* GetCurrentNode() const
   {
     MOZ_ASSERT(mInitialized);
-    nsINode* node = mIterator->GetCurrentNode();
+    nsINode* node = mIterator.GetCurrent();
     MOZ_ASSERT(!node || node->IsText());
     return node ? node->GetAsText() : nullptr;
   }
 
   Text* GetNextNode()
   {
     if (MOZ_UNLIKELY(!mInitialized)) {
       Initialize();
@@ -669,37 +686,31 @@ private:
 
   // Whether we've called GetNextNode() at least once.
   bool mInitialized;
 
 public:
   // An offset into the text of the first node we're starting to search at.
   int mIterOffset;
   const nsIContent* mLastBlockParent;
-  RefPtr<nsFindContentIterator> mIterator;
+  TreeIterator<StyleChildrenIterator> mIterator;
 
   // These are only needed for the first GetNextNode() call.
-  const nsRange& mSearchRange;
   const nsRange& mStartPoint;
-  const nsRange& mEndPoint;
 };
 
 void
 nsFind::State::Advance()
 {
   MOZ_ASSERT(mInitialized);
 
   while (true) {
-    if (mFindBackward) {
-      mIterator->Prev();
-    } else {
-      mIterator->Next();
-    }
+    nsIContent* current =
+      mFindBackward ? mIterator.GetPrev() : mIterator.GetNext();
 
-    nsINode* current = mIterator->GetCurrentNode();
     if (!current) {
       return;
     }
 
     if (!current->IsContent() || SkipNode(current->AsContent())) {
       continue;
     }
 
@@ -710,63 +721,36 @@ nsFind::State::Advance()
 }
 
 void
 nsFind::State::Initialize()
 {
   MOZ_ASSERT(!mInitialized);
   mInitialized = true;
   mIterOffset = mFindBackward ? -1 : 0;
-  mIterator = new nsFindContentIterator(mFindBackward);
 
   // Set up ourselves at the first node we want to start searching at.
-  {
-    nsINode* startNode;
-    nsINode* endNode;
-    uint32_t startOffset;
-    uint32_t endOffset;
-    if (mFindBackward) {
-      startNode = mSearchRange.GetStartContainer();
-      startOffset = mSearchRange.StartOffset();
-      endNode = mStartPoint.GetEndContainer();
-      endOffset = mStartPoint.EndOffset();
-    } else {
-      startNode = mStartPoint.GetStartContainer();
-      startOffset = mStartPoint.StartOffset();
-      endNode = mEndPoint.GetEndContainer();
-      endOffset = mEndPoint.EndOffset();
-    }
-
-    nsresult rv =
-      mIterator->Init(startNode,
-                      static_cast<int32_t>(startOffset),
-                      endNode,
-                      static_cast<int32_t>(endOffset));
-    if (NS_FAILED(rv)) {
-      return;
-    }
-
-    mIterator->Reset();
+  nsINode* beginning = mFindBackward ? mStartPoint.GetEndContainer()
+                                     : mStartPoint.GetStartContainer();
+  if (beginning && beginning->IsContent()) {
+    mIterator.Seek(*beginning->AsContent());
   }
 
-  nsINode* current = mIterator->GetCurrentNode();
+  nsINode* current = mIterator.GetCurrent();
   if (!current) {
     return;
   }
 
   if (!current->IsText() || SkipNode(current->AsText())) {
     Advance();
     return;
   }
 
   mLastBlockParent = GetBlockParent(current->AsText());
 
-  // We found a text node at the start, find the offset if we can.
-  nsINode* beginning = mFindBackward ? mStartPoint.GetEndContainer()
-                                     : mStartPoint.GetStartContainer();
   if (current != beginning) {
     return;
   }
 
   mIterOffset = mFindBackward ? mStartPoint.EndOffset()
                               : mStartPoint.StartOffset();
 }
 
@@ -792,33 +776,35 @@ nsFind::State::GetNextNonEmptyTextFragme
 }
 
 class MOZ_STACK_CLASS nsFind::StateRestorer final
 {
 public:
   explicit StateRestorer(State& aState)
     : mState(aState)
     , mIterOffset(aState.mIterOffset)
-    , mCurrNode(aState.mIterator->GetCurrentNode())
+    , mCurrNode(aState.GetCurrentNode())
     , mLastBlockParent(aState.mLastBlockParent)
   {
   }
 
   ~StateRestorer()
   {
     mState.mIterOffset = mIterOffset;
-    mState.mIterator->PositionAt(mCurrNode);
+    if (mCurrNode) {
+      mState.PositionAt(*mCurrNode);
+    }
     mState.mLastBlockParent = mLastBlockParent;
   }
 
 private:
   State& mState;
 
   int32_t mIterOffset;
-  nsINode* mCurrNode;
+  Text* mCurrNode;
   const nsIContent* mLastBlockParent;
 };
 
 NS_IMETHODIMP
 nsFind::GetFindBackwards(bool* aFindBackward)
 {
   if (!aFindBackward) {
     return NS_ERROR_NULL_POINTER;
@@ -927,16 +913,24 @@ nsFind::Find(const char16_t* aPatText, n
                     NS_LossyConvertUTF16toASCII(aPatText).get(),
                     mFindBackward ? " (backward)" : " (forward)",
                     (void*)aSearchRange, (void*)aStartPoint, (void*)aEndPoint);
 
   NS_ENSURE_ARG(aSearchRange);
   NS_ENSURE_ARG(aStartPoint);
   NS_ENSURE_ARG(aEndPoint);
   NS_ENSURE_ARG_POINTER(aRangeRet);
+
+  nsIDocument* document =
+    aStartPoint->GetRoot() ? aStartPoint->GetRoot()->OwnerDoc() : nullptr;
+  NS_ENSURE_ARG(document);
+
+  Element* root = document->GetRootElement();
+  NS_ENSURE_ARG(root);
+
   *aRangeRet = 0;
 
   if (!aPatText) {
     return NS_ERROR_NULL_POINTER;
   }
 
   nsAutoString patAutoStr(aPatText);
   if (!mCaseSensitive) {
@@ -972,25 +966,25 @@ nsFind::Find(const char16_t* aPatText, n
   // Keep track of whether the previous char was a word-breaking one.
   bool wordBreakPrev = false;
 
   // Place to save the range start point in case we find a match:
   Text* matchAnchorNode = nullptr;
   int32_t matchAnchorOffset = 0;
 
   // Get the end point, so we know when to end searches:
-  nsCOMPtr<nsINode> endNode = aEndPoint->GetEndContainer();;
+  nsINode* endNode = aEndPoint->GetEndContainer();
   uint32_t endOffset = aEndPoint->EndOffset();
 
   char16_t c = 0;
   char16_t patc = 0;
   char16_t prevChar = 0;
   char16_t prevCharInMatch = 0;
 
-  State state(mFindBackward, *aSearchRange, *aStartPoint, *aEndPoint);
+  State state(mFindBackward, *root, *aStartPoint);
   Text* current = nullptr;
 
   while (true) {
     DEBUG_FIND_PRINTF("Loop ...\n");
 
     // If this is our first time on a new node, reset the pointers:
     if (!frag) {
       current = state.GetNextNode();
@@ -1272,19 +1266,17 @@ nsFind::Find(const char16_t* aPatText, n
     if (matchAnchorNode) { // we're ending a partial match
       findex = matchAnchorOffset;
       state.mIterOffset = matchAnchorOffset;
       // +incr will be added to findex when we continue
 
       // Are we going back to a previous node?
       if (matchAnchorNode != state.GetCurrentNode()) {
         frag = nullptr;
-
-        DebugOnly<nsresult> rv = state.mIterator->PositionAt(matchAnchorNode);
-        MOZ_ASSERT(NS_SUCCEEDED(rv), "nsFindContentIterator failed to rewind");
+        state.PositionAt(*matchAnchorNode);
         DEBUG_FIND_PRINTF("Repositioned anchor node\n");
       }
       DEBUG_FIND_PRINTF("Ending a partial match; findex -> %d, mIterOffset -> %d\n",
                         findex, state.mIterOffset);
     }
     matchAnchorNode = nullptr;
     matchAnchorOffset = 0;
     inWhitespace = false;