--- a/toolkit/components/find/nsFind.cpp
+++ b/toolkit/components/find/nsFind.cpp
@@ -20,18 +20,20 @@
#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/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)
static NS_DEFINE_CID(kCContentIteratorCID, NS_CONTENTITERATOR_CID);
static NS_DEFINE_CID(kCPreContentIteratorCID, NS_PRECONTENTITERATOR_CID);
#define CH_QUOTE ((char16_t)0x22)
@@ -116,16 +118,17 @@ public:
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);
@@ -140,17 +143,16 @@ private:
int32_t mStartOffset;
nsCOMPtr<nsINode> mEndNode;
int32_t mEndOffset;
nsCOMPtr<nsIContent> mStartOuterContent;
nsCOMPtr<nsIContent> mEndOuterContent;
bool mFindBackward;
- void Reset();
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
@@ -452,64 +454,16 @@ NS_NewFindContentIterator(bool aFindBack
nsFindContentIterator* it = new nsFindContentIterator(aFindBackward);
if (!it) {
return NS_ERROR_OUT_OF_MEMORY;
}
return it->QueryInterface(NS_GET_IID(nsIContentIterator), (void**)aResult);
}
-struct nsFind::State final
-{
- // Disallow copying because copying the iterator would be a lie.
- State(const State&) = delete;
- State() = default;
-
- int32_t mIterOffset = 0;
-
- // TODO(emilio): I'm reasonably sure these can be weak pointers, since we
- // don't mutate the DOM.
- nsCOMPtr<nsINode> mIterNode;
- nsCOMPtr<nsIContent> mLastBlockParent;
-
- RefPtr<nsFindContentIterator> mIterator;
-};
-
-class MOZ_STACK_CLASS nsFind::StateRestorer final
-{
-public:
- explicit StateRestorer(State& aState)
- : mState(aState)
- , mIterOffset(aState.mIterOffset)
- , mIterNode(aState.mIterNode)
- , mCurrNode(aState.mIterator->GetCurrentNode())
- , mLastBlockParent(aState.mLastBlockParent)
- {
- }
-
- ~StateRestorer()
- {
- mState.mIterOffset = mIterOffset;
- mState.mIterNode = mIterNode;
- mState.mLastBlockParent = mLastBlockParent;
- mState.mIterator->PositionAt(mCurrNode);
- }
-
-private:
- State& mState;
-
- int32_t mIterOffset;
-
- // TODO(emilio): I'm reasonably sure these can be weak pointers, since we
- // don't mutate the DOM.
- nsCOMPtr<nsINode> mIterNode;
- nsCOMPtr<nsINode> mCurrNode;
- nsCOMPtr<nsIContent> mLastBlockParent;
-};
-
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)
@@ -526,17 +480,17 @@ nsFind::~nsFind() = default;
#ifdef DEBUG_FIND
#define DEBUG_FIND_PRINTF(...) printf(__VA_ARGS__)
#else
#define DEBUG_FIND_PRINTF(...) /* nothing */
#endif
static void
-DumpNode(nsINode* aNode)
+DumpNode(const nsINode* aNode)
{
#ifdef DEBUG_FIND
if (!aNode) {
printf(">>>> Node: NULL\n");
return;
}
nsString nodeName = aNode->NodeName();
if (aNode->IsText()) {
@@ -547,17 +501,17 @@ DumpNode(nsINode* aNode)
NS_LossyConvertUTF16toASCII(newText).get());
} else {
printf(">>>> Node: %s\n", NS_LossyConvertUTF16toASCII(nodeName).get());
}
#endif
}
static bool
-IsBlockNode(nsIContent* aContent)
+IsBlockNode(const nsIContent* aContent)
{
if (aContent->IsElement() && aContent->AsElement()->IsDisplayContents()) {
return false;
}
// FIXME(emilio): This is dubious...
if (aContent->IsAnyOfHTMLElements(nsGkAtoms::img,
nsGkAtoms::hr,
@@ -566,51 +520,50 @@ IsBlockNode(nsIContent* aContent)
return true;
}
nsIFrame* frame = aContent->GetPrimaryFrame();
return frame && frame->StyleDisplay()->IsBlockOutsideStyle();
}
static bool
-IsDisplayedNode(nsINode* aNode)
+IsDisplayedNode(const nsINode* aNode)
{
if (!aNode->IsContent()) {
return false;
}
- nsIFrame* frame = aNode->AsContent()->GetPrimaryFrame();
- if (!frame) {
- // No frame! Not visible then, unless it's display: contents.
- return aNode->IsElement() && aNode->AsElement()->IsDisplayContents();
+ if (aNode->AsContent()->GetPrimaryFrame()) {
+ return true;
}
- return true;
+ // If there's no frame, it's not displayed, unless it's display: contents.
+ return aNode->IsElement() && aNode->AsElement()->IsDisplayContents();
}
static bool
-IsVisibleNode(nsINode* aNode)
+IsVisibleNode(const nsINode* aNode)
{
if (!IsDisplayedNode(aNode)) {
return false;
}
nsIFrame* frame = aNode->AsContent()->GetPrimaryFrame();
if (!frame) {
// display: contents
return true;
}
return frame->StyleVisibility()->IsVisible();
}
static bool
-SkipNode(nsIContent* aContent)
+SkipNode(const nsIContent* aContent)
{
- nsIContent* content = 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);
@@ -623,64 +576,226 @@ SkipNode(nsIContent* aContent)
}
content = content->GetParent();
}
return false;
}
-static nsIContent*
-GetBlockParent(nsINode* aNode)
+static const nsIContent*
+GetBlockParent(const Text* aNode)
{
- if (!aNode) {
- return nullptr;
- }
// FIXME(emilio): This should use GetFlattenedTreeParent instead to properly
// handle Shadow DOM.
- for (nsIContent* current = aNode->GetParent(); current;
+ for (const nsIContent* current = aNode->GetParent(); current;
current = current->GetParent()) {
if (IsBlockNode(current)) {
return current;
}
}
return nullptr;
}
-nsresult
-nsFind::InitIterator(State& aState,
- nsINode* aStartNode,
- int32_t aStartOffset,
- nsINode* aEndNode,
- int32_t aEndOffset) const
+struct nsFind::State final
{
- if (!aState.mIterator) {
- aState.mIterator = new nsFindContentIterator(mFindBackward);
+ // 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)
+ : mFindBackward(aFindBackward)
+ , mSearchRange(aSearchRange)
+ , mStartPoint(aStartPoint)
+ , mEndPoint(aEndPoint)
+ {
+ }
+
+ Text* GetCurrentNode() const
+ {
+ MOZ_ASSERT(mInitialized);
+ nsINode* node = mIterator->GetCurrentNode();
+ MOZ_ASSERT(!node || node->IsText());
+ return node ? node->GetAsText() : nullptr;
+ }
+
+ Text* GetNextNode()
+ {
+ if (MOZ_UNLIKELY(!mInitialized)) {
+ Initialize();
+ } else {
+ Advance();
+ mIterOffset = -1; // mIterOffset only really applies to the first node.
+ }
+ return GetCurrentNode();
}
- NS_ENSURE_ARG_POINTER(aStartNode);
- NS_ENSURE_ARG_POINTER(aEndNode);
+ // Gets the next non-empty text fragment in the same block, starting by the
+ // _next_ node.
+ const nsTextFragment* GetNextNonEmptyTextFragmentInSameBlock();
+
+ const bool mFindBackward;
+ // An offset into the text of the first node we're starting to search at.
+ int32_t mIterOffset = -1;
+ const nsIContent* mLastBlockParent = nullptr;
+ RefPtr<nsFindContentIterator> mIterator;
+
+private:
+ // Advance to the next visible text-node.
+ void Advance();
+ // Sets up the first node position and offset.
+ void Initialize();
+
+ // Whether we've called GetNextNode() at least once.
+ bool mInitialized = false;
+
+ // 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();
+ }
- DEBUG_FIND_PRINTF("InitIterator search range:\n");
- DEBUG_FIND_PRINTF(" -- start %d, ", aStartOffset);
- DumpNode(aStartNode);
- DEBUG_FIND_PRINTF(" -- end %d, ", aEndOffset);
- DumpNode(aEndNode);
+ nsINode* current = mIterator->GetCurrentNode();
+ if (!current) {
+ return;
+ }
+
+ if (!current->IsContent() || SkipNode(current->AsContent())) {
+ continue;
+ }
+
+ if (current->IsText()) {
+ return;
+ }
+ }
+}
+
+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 =
- aState.mIterator->Init(aStartNode, aStartOffset, aEndNode, aEndOffset);
- NS_ENSURE_SUCCESS(rv, rv);
- if (mFindBackward) {
- aState.mIterator->Last();
- } else {
- aState.mIterator->First();
+ nsresult rv =
+ mIterator->Init(startNode,
+ static_cast<int32_t>(startOffset),
+ endNode,
+ static_cast<int32_t>(endOffset));
+ if (NS_FAILED(rv)) {
+ return;
+ }
+
+ mIterator->Reset();
+ }
+
+ nsINode* current = mIterator->GetCurrentNode();
+ 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;
}
- return NS_OK;
+
+ mIterOffset = mFindBackward ? mStartPoint.EndOffset()
+ : mStartPoint.StartOffset();
+}
+
+const nsTextFragment*
+nsFind::State::GetNextNonEmptyTextFragmentInSameBlock()
+{
+ while (true) {
+ const Text* current = GetNextNode();
+ if (!current) {
+ return nullptr;
+ }
+
+ // Get the block parent.
+ const nsIContent* blockParent = GetBlockParent(current);
+ if (!blockParent || blockParent != mLastBlockParent) {
+ return nullptr;
+ }
+
+ const nsTextFragment& frag = current->TextFragment();
+ if (frag.GetLength()) {
+ return &frag;
+ }
+ }
}
+class MOZ_STACK_CLASS nsFind::StateRestorer final
+{
+public:
+ explicit StateRestorer(State& aState)
+ : mState(aState)
+ , mIterOffset(aState.mIterOffset)
+ , mCurrNode(aState.mIterator->GetCurrentNode())
+ , mLastBlockParent(aState.mLastBlockParent)
+ {
+ }
+
+ ~StateRestorer()
+ {
+ mState.mIterOffset = mIterOffset;
+ mState.mIterator->PositionAt(mCurrNode);
+ mState.mLastBlockParent = mLastBlockParent;
+ }
+
+private:
+ State& mState;
+
+ int32_t mIterOffset;
+ nsINode* mCurrNode;
+ const nsIContent* mLastBlockParent;
+};
+
NS_IMETHODIMP
nsFind::GetFindBackwards(bool* aFindBackward)
{
if (!aFindBackward) {
return NS_ERROR_NULL_POINTER;
}
*aFindBackward = mFindBackward;
@@ -737,181 +852,40 @@ nsFind::SetEntireWord(bool aEntireWord)
// iterator to go back to a previously visited node, so we always save the
// "match anchor" node and offset.
//
// Text nodes store their text in an nsTextFragment, which is effectively a
// union of a one-byte string or a two-byte string. Single and double strings
// are intermixed in the dom. We don't have string classes which can deal with
// intermixed strings, so all the handling is done explicitly here.
-nsresult
-nsFind::NextNode(State& aState,
- const nsRange* aSearchRange,
- const nsRange* aStartPoint,
- const nsRange* aEndPoint) const
-{
- nsresult rv;
-
- nsCOMPtr<nsIContent> content;
-
- if (!aState.mIterator) {
- // If we are continuing, that means we have a match in progress. In that
- // case, we want to continue from the end point (where we are now) to the
- // beginning/end of the search range.
- nsCOMPtr<nsINode> startNode;
- nsCOMPtr<nsINode> endNode;
- uint32_t startOffset, endOffset;
- if (mFindBackward) {
- startNode = aSearchRange->GetStartContainer();
- startOffset = aSearchRange->StartOffset();
- endNode = aStartPoint->GetEndContainer();
- endOffset = aStartPoint->EndOffset();
- // XXX Needs work: Problem with this approach: if there is a match which
- // starts just before the current selection and continues into the
- // selection, we will miss it, because our search algorithm only starts
- // searching from the end of the word, so we would have to search the
- // current selection but discount any matches that fall entirely inside
- // it.
- } else { // forward
- startNode = aStartPoint->GetStartContainer();
- startOffset = aStartPoint->StartOffset();
- endNode = aEndPoint->GetEndContainer();
- endOffset = aEndPoint->EndOffset();
- }
-
- rv = InitIterator(aState,
- startNode,
- static_cast<int32_t>(startOffset),
- endNode,
- static_cast<int32_t>(endOffset));
- NS_ENSURE_SUCCESS(rv, rv);
- if (!aStartPoint) {
- aStartPoint = aSearchRange;
- }
-
- content = do_QueryInterface(aState.mIterator->GetCurrentNode());
- DEBUG_FIND_PRINTF(":::::: Got the first node ");
- DumpNode(content);
-
- if (content && content->IsText() && !SkipNode(content)) {
- aState.mIterNode = content;
- // Also set mIterOffset if appropriate:
- nsCOMPtr<nsINode> node;
- if (mFindBackward) {
- node = aStartPoint->GetEndContainer();
- if (aState.mIterNode == node) {
- uint32_t endOffset = aStartPoint->EndOffset();
- aState.mIterOffset = static_cast<int32_t>(endOffset);
- } else {
- aState.mIterOffset = -1; // sign to start from end
- }
- } else {
- node = aStartPoint->GetStartContainer();
- if (aState.mIterNode == node) {
- uint32_t startOffset = aStartPoint->StartOffset();
- aState.mIterOffset = static_cast<int32_t>(startOffset);
- } else {
- aState.mIterOffset = 0;
- }
- }
- DEBUG_FIND_PRINTF("Setting initial offset to %d\n", aState.mIterOffset);
- return NS_OK;
- }
- }
-
- while (true) {
- if (mFindBackward) {
- aState.mIterator->Prev();
- } else {
- aState.mIterator->Next();
- }
-
- content = do_QueryInterface(aState.mIterator->GetCurrentNode());
- if (!content) {
- break;
- }
-
- DEBUG_FIND_PRINTF(":::::: Got another node ");
- DumpNode(content);
-
- // If we ever cross a block node, we might want to reset the match anchor:
- // we don't match patterns extending across block boundaries. But we can't
- // depend on this test here now, because the iterator doesn't give us the
- // parent going in and going out, and we need it both times to depend on
- // this.
- //if (IsBlockNode(content))
-
- // Now see if we need to skip this node -- e.g. is it part of a script or
- // other invisible node? Note that we don't ask for CSS information; a node
- // can be invisible due to CSS, and we'd still find it.
- if (SkipNode(content)) {
- continue;
- }
-
- if (content->IsText()) {
- break;
- }
- DEBUG_FIND_PRINTF("Not a text node: ");
- DumpNode(content);
- }
-
- // FIXME(emilio): Is there a case for mIterNode !=
- // mIterator->GetCurrentNode()? If not, why does it exist?
- aState.mIterNode = content;
- aState.mIterOffset = -1;
-
- DEBUG_FIND_PRINTF("Iterator gave: ");
- DumpNode(aState.mIterNode);
- return NS_OK;
-}
-
char16_t
-nsFind::PeekNextChar(State& aState,
- const nsRange* aSearchRange,
- const nsRange* aStartPoint,
- const nsRange* aEndPoint) const
+nsFind::PeekNextChar(State& aState) const
{
// We need to restore the necessary state before this function returns.
StateRestorer restorer(aState);
- const nsTextFragment *frag;
- int32_t fragLen;
-
- // Loop through non-block nodes until we find one that's not empty.
- do {
- NextNode(aState, aSearchRange, aStartPoint, aEndPoint);
-
- // Get the text content:
- nsCOMPtr<nsIContent> tc = do_QueryInterface(aState.mIterNode);
+ const nsTextFragment* frag = aState.GetNextNonEmptyTextFragmentInSameBlock();
+ if (!frag) {
+ return L'\0';
+ }
- // Get the block parent.
- nsIContent* blockParent = GetBlockParent(aState.mIterNode);
- if (!blockParent)
- return L'\0';
-
- // If out of nodes or in new parent.
- if (!aState.mIterNode || !tc || blockParent != aState.mLastBlockParent)
- return L'\0';
-
- frag = tc->GetText();
- fragLen = frag->GetLength();
- } while (fragLen <= 0);
-
- const char16_t *t2b = nullptr;
- const char *t1b = nullptr;
+ const char16_t* t2b = nullptr;
+ const char* t1b = nullptr;
if (frag->Is2b()) {
t2b = frag->Get2b();
} else {
t1b = frag->Get1b();
}
- // Index of char to return.
- int32_t index = mFindBackward ? fragLen - 1 : 0;
+ uint32_t len = frag->GetLength();
+ MOZ_ASSERT(len);
+ int32_t index = mFindBackward ? len - 1 : 0;
return t1b ? CHAR_TO_UNICHAR(t1b[index]) : t2b[index];
}
#define NBSP_CHARCODE (CHAR_TO_UNICHAR(160))
#define IsSpace(c) (nsCRT::IsAsciiSpace(c) || (c) == NBSP_CHARCODE)
#define OVERFLOW_PINDEX (mFindBackward ? pindex < 0 : pindex > patLen)
#define DONE_WITH_PINDEX (mFindBackward ? pindex <= 0 : pindex >= patLen)
#define ALMOST_DONE_WITH_PINDEX (mFindBackward ? pindex <= 0 : pindex >= patLen - 1)
@@ -954,117 +928,103 @@ nsFind::Find(const char16_t* aPatText, n
int32_t pindex = (mFindBackward ? patLen : 0);
// Current offset into the fragment
int32_t findex = 0;
// Direction to move pindex and ptr*
int incr = (mFindBackward ? -1 : 1);
- nsCOMPtr<nsIContent> tc;
const nsTextFragment* frag = nullptr;
int32_t fragLen = 0;
// Pointers into the current fragment:
const char16_t* t2b = nullptr;
const char* t1b = nullptr;
// Keep track of when we're in whitespace:
// (only matters when we're matching)
bool inWhitespace = false;
// 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:
- nsCOMPtr<nsINode> matchAnchorNode;
+ Text* matchAnchorNode = nullptr;
int32_t matchAnchorOffset = 0;
// Get the end point, so we know when to end searches:
nsCOMPtr<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;
+ State state(mFindBackward, *aSearchRange, *aStartPoint, *aEndPoint);
+ Text* current = nullptr;
- while (1) {
+ while (true) {
DEBUG_FIND_PRINTF("Loop ...\n");
// If this is our first time on a new node, reset the pointers:
if (!frag) {
-
- tc = nullptr;
- NextNode(state, aSearchRange, aStartPoint, aEndPoint);
- if (!state.mIterNode) { // Out of nodes
+ current = state.GetNextNode();
+ if (!current) {
return NS_OK;
}
// We have a new text content. If its block parent is different from the
// block parent of the last text content, then we need to clear the match
// since we don't want to find across block boundaries.
- nsIContent* blockParent = GetBlockParent(state.mIterNode);
+ const nsIContent* blockParent = GetBlockParent(current);
DEBUG_FIND_PRINTF("New node: old blockparent = %p, new = %p\n",
- (void*)state.mLastBlockParent.get(), (void*)blockParent);
+ (void*)state.mLastBlockParent, (void*)blockParent);
if (blockParent != state.mLastBlockParent) {
DEBUG_FIND_PRINTF("Different block parent!\n");
state.mLastBlockParent = blockParent;
// End any pending match:
matchAnchorNode = nullptr;
matchAnchorOffset = 0;
c = 0;
prevChar = 0;
prevCharInMatch = 0;
pindex = (mFindBackward ? patLen : 0);
inWhitespace = false;
}
- // Get the text content:
- tc = do_QueryInterface(state.mIterNode);
- if (!tc || !(frag = tc->GetText())) { // Out of nodes
- return NS_OK;
- }
-
+ frag = current->GetText();
fragLen = frag->GetLength();
// Set our starting point in this node. If we're going back to the anchor
// node, which means that we just ended a partial match, use the saved
// offset:
- if (state.mIterNode == matchAnchorNode) {
+ //
+ // FIXME(emilio): How could current ever be the anchor node, if we had not
+ // seen current so far?
+ if (current == matchAnchorNode) {
findex = matchAnchorOffset + (mFindBackward ? 1 : 0);
- }
-
- // state.mIterOffset, if set, is the range's idea of an offset, and points
- // between characters. But when translated to a string index, it points to
- // a character. If we're going backward, this is one character too late
- // and we'll match part of our previous pattern.
- else if (state.mIterOffset >= 0) {
+ } else if (state.mIterOffset >= 0) {
findex = state.mIterOffset - (mFindBackward ? 1 : 0);
- }
-
- // Otherwise, just start at the appropriate end of the fragment:
- else if (mFindBackward) {
- findex = fragLen - 1;
} else {
- findex = 0;
+ findex = mFindBackward ? (fragLen - 1) : 0;
}
// Offset can only apply to the first node:
state.mIterOffset = -1;
+ DEBUG_FIND_PRINTF("Starting from offset %d of %d\n", findex, fragLen);
+
// If this is outside the bounds of the string, then skip this node:
if (findex < 0 || findex > fragLen - 1) {
DEBUG_FIND_PRINTF("At the end of a text node -- skipping to the next\n");
- frag = 0;
+ frag = nullptr;
continue;
}
- DEBUG_FIND_PRINTF("Starting from offset %d\n", findex);
if (frag->Is2b()) {
t2b = frag->Get2b();
t1b = nullptr;
#ifdef DEBUG_FIND
nsAutoString str2(t2b, fragLen);
DEBUG_FIND_PRINTF("2 byte, '%s'\n", NS_LossyConvertUTF16toASCII(str2).get());
#endif
} else {
@@ -1086,17 +1046,17 @@ nsFind::Find(const char16_t* aPatText, n
// Done with this node. Pull a new one.
frag = nullptr;
continue;
}
}
// Have we gone past the endpoint yet? If we have, and we're not in the
// middle of a match, return.
- if (state.mIterNode == endNode &&
+ if (state.GetCurrentNode() == endNode &&
((mFindBackward && findex < static_cast<int32_t>(endOffset)) ||
(!mFindBackward && findex > static_cast<int32_t>(endOffset)))) {
return NS_OK;
}
// Save the previous character for word boundary detection
prevChar = c;
// The two characters we'll be comparing:
@@ -1191,86 +1151,79 @@ nsFind::Find(const char16_t* aPatText, n
if (inWhitespace) {
DEBUG_FIND_PRINTF("YES (whitespace)(%d of %d)\n", pindex, patLen);
} else {
DEBUG_FIND_PRINTF("YES! '%c' == '%c' (%d of %d)\n", c, patc, pindex, patLen);
}
// Save the range anchors if we haven't already:
if (!matchAnchorNode) {
- matchAnchorNode = state.mIterNode;
+ matchAnchorNode = state.GetCurrentNode();
matchAnchorOffset = findex;
}
// Are we done?
if (DONE_WITH_PINDEX) {
// Matched the whole string!
DEBUG_FIND_PRINTF("Found a match!\n");
// Make the range:
- nsCOMPtr<nsINode> startParent;
- nsCOMPtr<nsINode> endParent;
-
// Check for word break (if necessary)
if (mWordBreaker) {
int32_t nextfindex = findex + incr;
char16_t nextChar;
// If still in array boundaries, get nextChar.
if (mFindBackward ? (nextfindex >= 0) : (nextfindex < fragLen))
nextChar = (t2b ? t2b[nextfindex] : CHAR_TO_UNICHAR(t1b[nextfindex]));
// Get next character from the next node.
else
- nextChar = PeekNextChar(state, aSearchRange, aStartPoint, aEndPoint);
+ nextChar = PeekNextChar(state);
if (nextChar == NBSP_CHARCODE)
nextChar = CHAR_TO_UNICHAR(' ');
// If a word break isn't there when it needs to be, reset search.
if (!mWordBreaker->BreakInBetween(&c, 1, &nextChar, 1)) {
matchAnchorNode = nullptr;
continue;
}
}
- RefPtr<nsRange> range = new nsRange(tc);
- if (range) {
- int32_t matchStartOffset, matchEndOffset;
- // convert char index to range point:
- int32_t mao = matchAnchorOffset + (mFindBackward ? 1 : 0);
- if (mFindBackward) {
- startParent = tc;
- endParent = matchAnchorNode;
- matchStartOffset = findex;
- matchEndOffset = mao;
- } else {
- startParent = matchAnchorNode;
- endParent = tc;
- matchStartOffset = mao;
- matchEndOffset = findex + 1;
- }
- if (startParent && endParent &&
- IsVisibleNode(startParent) && IsVisibleNode(endParent)) {
- range->SetStart(*startParent, matchStartOffset, IgnoreErrors());
- range->SetEnd(*endParent, matchEndOffset, IgnoreErrors());
- *aRangeRet = range.get();
- NS_ADDREF(*aRangeRet);
- } else {
- // This match is no good -- invisible or bad range
- startParent = nullptr;
- }
+ RefPtr<nsRange> range = new nsRange(current);
+
+ int32_t matchStartOffset;
+ int32_t matchEndOffset;
+ // convert char index to range point:
+ int32_t mao = matchAnchorOffset + (mFindBackward ? 1 : 0);
+ Text* startParent;
+ Text* endParent;
+ if (mFindBackward) {
+ startParent = current;
+ endParent = matchAnchorNode;
+ matchStartOffset = findex;
+ matchEndOffset = mao;
+ } else {
+ startParent = matchAnchorNode;
+ endParent = current;
+ matchStartOffset = mao;
+ matchEndOffset = findex + 1;
+ }
+ if (startParent && endParent &&
+ IsVisibleNode(startParent) && IsVisibleNode(endParent)) {
+ range->SetStart(*startParent, matchStartOffset, IgnoreErrors());
+ range->SetEnd(*endParent, matchEndOffset, IgnoreErrors());
+ *aRangeRet = range.get();
+ NS_ADDREF(*aRangeRet);
+ } else {
+ // This match is no good -- invisible or bad range
+ startParent = nullptr;
}
if (startParent) {
- // If startParent == nullptr, we didn't successfully make range
- // or, we didn't make a range because the start or end node were
- // invisible. Reset the offset to the other end of the found string:
- state.mIterOffset = findex + (mFindBackward ? 1 : 0);
- DEBUG_FIND_PRINTF("mIterOffset = %d, mIterNode = ", state.mIterOffset);
- DumpNode(state.mIterNode);
return NS_OK;
}
// This match is no good, continue on in document
matchAnchorNode = nullptr;
}
if (matchAnchorNode) {
// Not done, but still matching. Advance and loop around for the next
@@ -1291,30 +1244,29 @@ nsFind::Find(const char16_t* aPatText, n
// If we didn't match, go back to the beginning of patStr, and set findex
// back to the next char after we started the current match.
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.mIterNode) {
- nsCOMPtr<nsIContent> content(do_QueryInterface(matchAnchorNode));
- DebugOnly<nsresult> rv = NS_ERROR_UNEXPECTED;
- if (content) {
- rv = state.mIterator->PositionAt(content);
- }
- frag = 0;
- NS_ASSERTION(NS_SUCCEEDED(rv), "Text content wasn't nsIContent!");
+ if (matchAnchorNode != state.GetCurrentNode()) {
+ frag = nullptr;
+
+ nsresult rv = state.mIterator->PositionAt(matchAnchorNode);
+ NS_ASSERTION(NS_SUCCEEDED(rv),
+ "nsFindContentIterator failed to rewind "
+ "because it doesn't handle NAC properly...");
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;
- pindex = (mFindBackward ? patLen : 0);
+ pindex = mFindBackward ? patLen : 0;
DEBUG_FIND_PRINTF("Setting findex back to %d, pindex to %d\n", findex, pindex);
}
return NS_OK;
}