Chromium Code Reviews| Index: third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp |
| diff --git a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp |
| index 931a12f679b2e71586a9b4ad451789373405eaff..50e206051aa131a19b52ac058dc9e6e3e5f5bae3 100644 |
| --- a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp |
| +++ b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp |
| @@ -39,7 +39,7 @@ |
| #include "core/editing/iterators/CharacterIterator.h" |
| #include "core/editing/markers/DocumentMarkerController.h" |
| #include "core/editing/spellcheck/SpellCheckRequester.h" |
| -#include "core/editing/spellcheck/TextCheckingHelper.h" |
| +#include "core/editing/spellcheck/TextCheckingParagraph.h" |
| #include "core/frame/LocalFrame.h" |
| #include "core/frame/Settings.h" |
| #include "core/html/HTMLInputElement.h" |
| @@ -47,6 +47,7 @@ |
| #include "core/loader/EmptyClients.h" |
| #include "core/page/Page.h" |
| #include "core/page/SpellCheckerClient.h" |
| +#include "platform/text/TextBreakIterator.h" |
| #include "platform/text/TextCheckerClient.h" |
| namespace blink { |
| @@ -157,6 +158,114 @@ void SpellChecker::ignoreSpelling() |
| removeMarkers(frame().selection().selection(), DocumentMarker::Spelling); |
| } |
| +void SpellChecker::findMisspellings(const String& text, Vector<TextCheckingResult>* results) |
|
yosin_UTC9
2016/08/16 06:04:06
Since WTF::Vector is now movable[1], let's return
Xiaocheng
2016/08/16 06:21:35
Didn't know that. Done.
|
| +{ |
| + Vector<UChar> characters; |
| + text.appendTo(characters); |
| + unsigned length = text.length(); |
| + |
| + TextBreakIterator* iterator = wordBreakIterator(characters.data(), length); |
| + if (!iterator) |
| + return; |
| + |
| + int wordStart = iterator->current(); |
| + while (0 <= wordStart) { |
| + int wordEnd = iterator->next(); |
| + if (wordEnd < 0) |
| + break; |
| + int wordLength = wordEnd - wordStart; |
| + int misspellingLocation = -1; |
| + int misspellingLength = 0; |
| + textChecker().checkSpellingOfString(String(characters.data() + wordStart, wordLength), &misspellingLocation, &misspellingLength); |
| + if (0 < misspellingLength) { |
|
yosin_UTC9
2016/08/16 06:04:06
I prefer |misspellingLength > 0|
Xiaocheng
2016/08/16 06:21:36
Done.
|
| + DCHECK_LE(0, misspellingLocation); |
|
yosin_UTC9
2016/08/16 06:04:06
I prefer DCHECK_GE(misspellingLocation, 0);
Xiaocheng
2016/08/16 06:21:35
Done.
|
| + DCHECK_LE(misspellingLocation, wordLength); |
| + DCHECK_LT(0, misspellingLength); |
|
yosin_UTC9
2016/08/16 06:04:06
I prefer DCHECK_GT(misspellingLength, 0)
Xiaocheng
2016/08/16 06:21:35
Done.
|
| + DCHECK_LE(misspellingLocation + misspellingLength, wordLength); |
| + TextCheckingResult misspelling; |
| + misspelling.decoration = TextDecorationTypeSpelling; |
| + misspelling.location = wordStart + misspellingLocation; |
| + misspelling.length = misspellingLength; |
| + results->append(misspelling); |
| + } |
| + |
|
yosin_UTC9
2016/08/16 06:04:06
nit: Please remove an extra blank line.
Xiaocheng
2016/08/16 06:21:36
Done.
|
| + wordStart = wordEnd; |
| + } |
| +} |
| + |
| +std::pair<String, int> SpellChecker::findFirstMisspelling(const Position& start, const Position& end) |
| +{ |
| + String misspelledWord; |
| + |
| + // Initialize out parameter; it will be updated if we find something to return. |
| + String firstFoundItem; |
| + int firstFoundOffset = 0; |
| + |
| + // Expand the search range to encompass entire paragraphs, since text checking needs that much context. |
| + // Determine the character offset from the start of the paragraph to the start of the original search range, |
| + // since we will want to ignore results in this area. |
| + Position paragraphStart = startOfParagraph(createVisiblePosition(start)).toParentAnchoredPosition(); |
| + Position paragraphEnd = end; |
| + int totalRangeLength = TextIterator::rangeLength(paragraphStart, paragraphEnd); |
| + paragraphEnd = endOfParagraph(createVisiblePosition(start)).toParentAnchoredPosition(); |
| + |
| + int rangeStartOffset = TextIterator::rangeLength(paragraphStart, start); |
| + int totalLengthProcessed = 0; |
| + |
| + bool firstIteration = true; |
| + bool lastIteration = false; |
| + while (totalLengthProcessed < totalRangeLength) { |
| + // Iterate through the search range by paragraphs, checking each one for spelling. |
| + int currentLength = TextIterator::rangeLength(paragraphStart, paragraphEnd); |
| + int currentStartOffset = firstIteration ? rangeStartOffset : 0; |
| + int currentEndOffset = currentLength; |
| + if (inSameParagraph(createVisiblePosition(paragraphStart), createVisiblePosition(end))) { |
| + // Determine the character offset from the end of the original search range to the end of the paragraph, |
| + // since we will want to ignore results in this area. |
| + currentEndOffset = TextIterator::rangeLength(paragraphStart, end); |
| + lastIteration = true; |
| + } |
| + if (currentStartOffset < currentEndOffset) { |
| + String paragraphString = plainText(EphemeralRange(paragraphStart, paragraphEnd)); |
| + if (paragraphString.length() > 0) { |
| + int spellingLocation = 0; |
| + |
| + Vector<TextCheckingResult> results; |
| + findMisspellings(paragraphString, &results); |
| + |
| + for (unsigned i = 0; i < results.size(); i++) { |
| + const TextCheckingResult* result = &results[i]; |
| + if (result->decoration == TextDecorationTypeSpelling && result->location >= currentStartOffset && result->location + result->length <= currentEndOffset) { |
| + DCHECK_GT(result->length, 0); |
| + DCHECK_GE(result->location, 0); |
| + spellingLocation = result->location; |
| + misspelledWord = paragraphString.substring(result->location, result->length); |
| + DCHECK(misspelledWord.length()); |
| + break; |
| + } |
| + } |
| + |
| + if (!misspelledWord.isEmpty()) { |
| + int spellingOffset = spellingLocation - currentStartOffset; |
| + if (!firstIteration) |
| + spellingOffset += TextIterator::rangeLength(start, paragraphStart); |
| + firstFoundOffset = spellingOffset; |
| + firstFoundItem = misspelledWord; |
| + break; |
| + } |
| + } |
| + } |
| + if (lastIteration || totalLengthProcessed + currentLength >= totalRangeLength) |
| + break; |
| + VisiblePosition newParagraphStart = startOfNextParagraph(createVisiblePosition(paragraphEnd)); |
| + paragraphStart = newParagraphStart.toParentAnchoredPosition(); |
| + paragraphEnd = endOfParagraph(newParagraphStart).toParentAnchoredPosition(); |
| + firstIteration = false; |
| + totalLengthProcessed += currentLength; |
| + } |
| + return std::make_pair(firstFoundItem, firstFoundOffset); |
| +} |
| + |
| void SpellChecker::advanceToNextMisspelling(bool startBeforeSelection) |
| { |
| DocumentLifecycle::DisallowTransitionScope(frame().document()->lifecycle()); |
| @@ -226,8 +335,10 @@ void SpellChecker::advanceToNextMisspelling(bool startBeforeSelection) |
| Node* searchEndNodeAfterWrap = spellingSearchEnd.computeContainerNode(); |
| int searchEndOffsetAfterWrap = spellingSearchEnd.offsetInContainerNode(); |
| - int misspellingOffset = 0; |
| - String misspelledWord = TextCheckingHelper(spellCheckerClient(), spellingSearchStart, spellingSearchEnd).findFirstMisspellingOrBadGrammar(misspellingOffset); |
| + std::pair<String, int> misspelledItem("", 0); |
| + String& misspelledWord = misspelledItem.first; |
| + int& misspellingOffset = misspelledItem.second; |
| + misspelledItem = findFirstMisspelling(spellingSearchStart, spellingSearchEnd); |
| // If we did not find a misspelled word, wrap and try again (but don't bother if we started at the beginning of the |
| // block rather than at a selection). |
| @@ -235,7 +346,7 @@ void SpellChecker::advanceToNextMisspelling(bool startBeforeSelection) |
| spellingSearchStart = Position::editingPositionOf(topNode, 0); |
| // going until the end of the very first chunk we tested is far enough |
| spellingSearchEnd = Position::editingPositionOf(searchEndNodeAfterWrap, searchEndOffsetAfterWrap); |
| - misspelledWord = TextCheckingHelper(spellCheckerClient(), spellingSearchStart, spellingSearchEnd).findFirstMisspellingOrBadGrammar(misspellingOffset); |
| + misspelledItem = findFirstMisspelling(spellingSearchStart, spellingSearchEnd); |
| } |
| if (!misspelledWord.isEmpty()) { |