--- 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;