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()) { |