diff --git a/dom/base/test/test_find.html b/dom/base/test/test_find.html index 9a7e20888b46..03bc6279144c 100644 --- a/dom/base/test/test_find.html +++ b/dom/base/test/test_find.html @@ -122,6 +122,14 @@ let runTests = t.step_func_done(function() { document.documentElement.appendChild(div); }, "Mixed shadow and non-shadow text"); + testFindable(true, "Shadow", function(document) { + document.documentElement.innerHTML = ` + Sources +
whatever
+ `; + document.getElementById("host").attachShadow({ mode: "open" }).innerHTML = "Shadow text"; + }, "Test inside a shadow-root mid-match"); + // NOTE(emilio): It is probably doable / worth changing this to return true, // maybe, by relaxing the security checks in the ranges nsFind returns or // such. diff --git a/toolkit/components/find/nsFind.cpp b/toolkit/components/find/nsFind.cpp index b43aceebb0d7..cd845f43946a 100644 --- a/toolkit/components/find/nsFind.cpp +++ b/toolkit/components/find/nsFind.cpp @@ -614,12 +614,11 @@ nsFind::Find(const nsAString& aPatText, nsRange* aSearchRange, // 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: Text* matchAnchorNode = nullptr; int32_t matchAnchorOffset = 0; + char32_t matchAnchorChar = 0; // Get the end point, so we know when to end searches: nsINode* endNode = aEndPoint->GetEndContainer(); @@ -627,18 +626,19 @@ nsFind::Find(const nsAString& aPatText, nsRange* aSearchRange, char32_t c = 0; char32_t patc = 0; - char32_t prevChar = 0; char32_t prevCharInMatch = 0; State state(mFindBackward, *root, *aStartPoint); Text* current = nullptr; - auto EndPartialMatch = [&] { + auto EndPartialMatch = [&]() -> bool { + bool hadAnchorNode = !!matchAnchorNode; // 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; + c = matchAnchorChar; // +incr will be added to findex when we continue // Are we going back to a previous node? @@ -653,10 +653,13 @@ nsFind::Find(const nsAString& aPatText, nsRange* aSearchRange, } matchAnchorNode = nullptr; matchAnchorOffset = 0; + matchAnchorChar = 0; inWhitespace = false; + prevCharInMatch = 0; pindex = mFindBackward ? patLen : 0; DEBUG_FIND_PRINTF("Setting findex back to %d, pindex to %d\n", findex, pindex); + return hadAnchorNode; }; while (true) { @@ -667,8 +670,7 @@ nsFind::Find(const nsAString& aPatText, nsRange* aSearchRange, current = state.GetNextNode(!!matchAnchorNode); if (!current) { DEBUG_FIND_PRINTF("Reached the end, matching: %d\n", !!matchAnchorNode); - if (matchAnchorNode) { - EndPartialMatch(); + if (EndPartialMatch()) { continue; } return NS_OK; @@ -678,14 +680,12 @@ nsFind::Find(const nsAString& aPatText, nsRange* aSearchRange, //
, different blocks or what not. if (state.ForcedBreak()) { DEBUG_FIND_PRINTF("Forced break!\n"); - // End any pending match: - matchAnchorNode = nullptr; - matchAnchorOffset = 0; + if (EndPartialMatch()) { + continue; + } + // This ensures word breaking thinks it has a new word, which is + // effectively what we want. c = 0; - prevChar = 0; - prevCharInMatch = 0; - pindex = (mFindBackward ? patLen : 0); - inWhitespace = false; } frag = ¤t->TextFragment(); @@ -759,7 +759,7 @@ nsFind::Find(const nsAString& aPatText, nsRange* aSearchRange, } // Save the previous character for word boundary detection - prevChar = c; + char32_t prevChar = c; // The two characters we'll be comparing are c and patc. If not matching // diacritics, don't leave c set to a combining diacritical mark. (patc is // already guaranteed to not be a combining diacritical mark.) @@ -844,9 +844,12 @@ nsFind::Find(const nsAString& aPatText, nsRange* aSearchRange, } } - wordBreakPrev = false; + // Figure whether the previous char is a word-breaking one. + bool wordBreakPrev = false; if (mWordBreaker) { - if (prevChar == NBSP_CHARCODE) prevChar = CHAR_TO_UNICHAR(' '); + if (prevChar == NBSP_CHARCODE) { + prevChar = CHAR_TO_UNICHAR(' '); + } wordBreakPrev = BreakInBetween(prevChar, c); } @@ -870,7 +873,10 @@ nsFind::Find(const nsAString& aPatText, nsRange* aSearchRange, if (!matchAnchorNode) { matchAnchorNode = state.GetCurrentNode(); matchAnchorOffset = findex; - if (!IS_IN_BMP(c)) matchAnchorOffset -= incr; + if (!IS_IN_BMP(c)) { + matchAnchorOffset -= incr; + } + matchAnchorChar = c; } // Are we done? @@ -895,7 +901,9 @@ nsFind::Find(const nsAString& aPatText, nsRange* aSearchRange, nextChar = PeekNextChar(state, !!matchAnchorNode); } - if (nextChar == NBSP_CHARCODE) nextChar = CHAR_TO_UNICHAR(' '); + if (nextChar == NBSP_CHARCODE) { + nextChar = CHAR_TO_UNICHAR(' '); + } // If a word break isn't there when it needs to be, reset search. if (!BreakInBetween(c, nextChar)) {