Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2006, 2007, 2008, 2011 Apple Inc. All rights reserved. | 2 * Copyright (C) 2006, 2007, 2008, 2011 Apple Inc. All rights reserved. |
| 3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) | 3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) |
| 4 * | 4 * |
| 5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
| 6 * modification, are permitted provided that the following conditions | 6 * modification, are permitted provided that the following conditions |
| 7 * are met: | 7 * are met: |
| 8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 32 #include "core/dom/Element.h" | 32 #include "core/dom/Element.h" |
| 33 #include "core/dom/ElementTraversal.h" | 33 #include "core/dom/ElementTraversal.h" |
| 34 #include "core/dom/NodeTraversal.h" | 34 #include "core/dom/NodeTraversal.h" |
| 35 #include "core/editing/EditingUtilities.h" | 35 #include "core/editing/EditingUtilities.h" |
| 36 #include "core/editing/Editor.h" | 36 #include "core/editing/Editor.h" |
| 37 #include "core/editing/EphemeralRange.h" | 37 #include "core/editing/EphemeralRange.h" |
| 38 #include "core/editing/VisibleUnits.h" | 38 #include "core/editing/VisibleUnits.h" |
| 39 #include "core/editing/iterators/CharacterIterator.h" | 39 #include "core/editing/iterators/CharacterIterator.h" |
| 40 #include "core/editing/markers/DocumentMarkerController.h" | 40 #include "core/editing/markers/DocumentMarkerController.h" |
| 41 #include "core/editing/spellcheck/SpellCheckRequester.h" | 41 #include "core/editing/spellcheck/SpellCheckRequester.h" |
| 42 #include "core/editing/spellcheck/TextCheckingHelper.h" | 42 #include "core/editing/spellcheck/TextCheckingParagraph.h" |
| 43 #include "core/frame/LocalFrame.h" | 43 #include "core/frame/LocalFrame.h" |
| 44 #include "core/frame/Settings.h" | 44 #include "core/frame/Settings.h" |
| 45 #include "core/html/HTMLInputElement.h" | 45 #include "core/html/HTMLInputElement.h" |
| 46 #include "core/layout/LayoutTextControl.h" | 46 #include "core/layout/LayoutTextControl.h" |
| 47 #include "core/loader/EmptyClients.h" | 47 #include "core/loader/EmptyClients.h" |
| 48 #include "core/page/Page.h" | 48 #include "core/page/Page.h" |
| 49 #include "core/page/SpellCheckerClient.h" | 49 #include "core/page/SpellCheckerClient.h" |
| 50 #include "platform/text/TextBreakIterator.h" | |
| 50 #include "platform/text/TextCheckerClient.h" | 51 #include "platform/text/TextCheckerClient.h" |
| 51 | 52 |
| 52 namespace blink { | 53 namespace blink { |
| 53 | 54 |
| 54 using namespace HTMLNames; | 55 using namespace HTMLNames; |
| 55 | 56 |
| 56 namespace { | 57 namespace { |
| 57 | 58 |
| 58 bool isSelectionInTextField(const VisibleSelection& selection) | 59 bool isSelectionInTextField(const VisibleSelection& selection) |
| 59 { | 60 { |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 150 if (!isTextField) | 151 if (!isTextField) |
| 151 parent->setAlreadySpellChecked(true); | 152 parent->setAlreadySpellChecked(true); |
| 152 } | 153 } |
| 153 } | 154 } |
| 154 | 155 |
| 155 void SpellChecker::ignoreSpelling() | 156 void SpellChecker::ignoreSpelling() |
| 156 { | 157 { |
| 157 removeMarkers(frame().selection().selection(), DocumentMarker::Spelling); | 158 removeMarkers(frame().selection().selection(), DocumentMarker::Spelling); |
| 158 } | 159 } |
| 159 | 160 |
| 161 void SpellChecker::findMisspellings(const String& text, Vector<TextCheckingResul t>* 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.
| |
| 162 { | |
| 163 Vector<UChar> characters; | |
| 164 text.appendTo(characters); | |
| 165 unsigned length = text.length(); | |
| 166 | |
| 167 TextBreakIterator* iterator = wordBreakIterator(characters.data(), length); | |
| 168 if (!iterator) | |
| 169 return; | |
| 170 | |
| 171 int wordStart = iterator->current(); | |
| 172 while (0 <= wordStart) { | |
| 173 int wordEnd = iterator->next(); | |
| 174 if (wordEnd < 0) | |
| 175 break; | |
| 176 int wordLength = wordEnd - wordStart; | |
| 177 int misspellingLocation = -1; | |
| 178 int misspellingLength = 0; | |
| 179 textChecker().checkSpellingOfString(String(characters.data() + wordStart , wordLength), &misspellingLocation, &misspellingLength); | |
| 180 if (0 < misspellingLength) { | |
|
yosin_UTC9
2016/08/16 06:04:06
I prefer |misspellingLength > 0|
Xiaocheng
2016/08/16 06:21:36
Done.
| |
| 181 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.
| |
| 182 DCHECK_LE(misspellingLocation, wordLength); | |
| 183 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.
| |
| 184 DCHECK_LE(misspellingLocation + misspellingLength, wordLength); | |
| 185 TextCheckingResult misspelling; | |
| 186 misspelling.decoration = TextDecorationTypeSpelling; | |
| 187 misspelling.location = wordStart + misspellingLocation; | |
| 188 misspelling.length = misspellingLength; | |
| 189 results->append(misspelling); | |
| 190 } | |
| 191 | |
|
yosin_UTC9
2016/08/16 06:04:06
nit: Please remove an extra blank line.
Xiaocheng
2016/08/16 06:21:36
Done.
| |
| 192 wordStart = wordEnd; | |
| 193 } | |
| 194 } | |
| 195 | |
| 196 std::pair<String, int> SpellChecker::findFirstMisspelling(const Position& start, const Position& end) | |
| 197 { | |
| 198 String misspelledWord; | |
| 199 | |
| 200 // Initialize out parameter; it will be updated if we find something to retu rn. | |
| 201 String firstFoundItem; | |
| 202 int firstFoundOffset = 0; | |
| 203 | |
| 204 // Expand the search range to encompass entire paragraphs, since text checki ng needs that much context. | |
| 205 // Determine the character offset from the start of the paragraph to the sta rt of the original search range, | |
| 206 // since we will want to ignore results in this area. | |
| 207 Position paragraphStart = startOfParagraph(createVisiblePosition(start)).toP arentAnchoredPosition(); | |
| 208 Position paragraphEnd = end; | |
| 209 int totalRangeLength = TextIterator::rangeLength(paragraphStart, paragraphEn d); | |
| 210 paragraphEnd = endOfParagraph(createVisiblePosition(start)).toParentAnchored Position(); | |
| 211 | |
| 212 int rangeStartOffset = TextIterator::rangeLength(paragraphStart, start); | |
| 213 int totalLengthProcessed = 0; | |
| 214 | |
| 215 bool firstIteration = true; | |
| 216 bool lastIteration = false; | |
| 217 while (totalLengthProcessed < totalRangeLength) { | |
| 218 // Iterate through the search range by paragraphs, checking each one for spelling. | |
| 219 int currentLength = TextIterator::rangeLength(paragraphStart, paragraphE nd); | |
| 220 int currentStartOffset = firstIteration ? rangeStartOffset : 0; | |
| 221 int currentEndOffset = currentLength; | |
| 222 if (inSameParagraph(createVisiblePosition(paragraphStart), createVisible Position(end))) { | |
| 223 // Determine the character offset from the end of the original searc h range to the end of the paragraph, | |
| 224 // since we will want to ignore results in this area. | |
| 225 currentEndOffset = TextIterator::rangeLength(paragraphStart, end); | |
| 226 lastIteration = true; | |
| 227 } | |
| 228 if (currentStartOffset < currentEndOffset) { | |
| 229 String paragraphString = plainText(EphemeralRange(paragraphStart, pa ragraphEnd)); | |
| 230 if (paragraphString.length() > 0) { | |
| 231 int spellingLocation = 0; | |
| 232 | |
| 233 Vector<TextCheckingResult> results; | |
| 234 findMisspellings(paragraphString, &results); | |
| 235 | |
| 236 for (unsigned i = 0; i < results.size(); i++) { | |
| 237 const TextCheckingResult* result = &results[i]; | |
| 238 if (result->decoration == TextDecorationTypeSpelling && resu lt->location >= currentStartOffset && result->location + result->length <= curre ntEndOffset) { | |
| 239 DCHECK_GT(result->length, 0); | |
| 240 DCHECK_GE(result->location, 0); | |
| 241 spellingLocation = result->location; | |
| 242 misspelledWord = paragraphString.substring(result->locat ion, result->length); | |
| 243 DCHECK(misspelledWord.length()); | |
| 244 break; | |
| 245 } | |
| 246 } | |
| 247 | |
| 248 if (!misspelledWord.isEmpty()) { | |
| 249 int spellingOffset = spellingLocation - currentStartOffset; | |
| 250 if (!firstIteration) | |
| 251 spellingOffset += TextIterator::rangeLength(start, parag raphStart); | |
| 252 firstFoundOffset = spellingOffset; | |
| 253 firstFoundItem = misspelledWord; | |
| 254 break; | |
| 255 } | |
| 256 } | |
| 257 } | |
| 258 if (lastIteration || totalLengthProcessed + currentLength >= totalRangeL ength) | |
| 259 break; | |
| 260 VisiblePosition newParagraphStart = startOfNextParagraph(createVisiblePo sition(paragraphEnd)); | |
| 261 paragraphStart = newParagraphStart.toParentAnchoredPosition(); | |
| 262 paragraphEnd = endOfParagraph(newParagraphStart).toParentAnchoredPositio n(); | |
| 263 firstIteration = false; | |
| 264 totalLengthProcessed += currentLength; | |
| 265 } | |
| 266 return std::make_pair(firstFoundItem, firstFoundOffset); | |
| 267 } | |
| 268 | |
| 160 void SpellChecker::advanceToNextMisspelling(bool startBeforeSelection) | 269 void SpellChecker::advanceToNextMisspelling(bool startBeforeSelection) |
| 161 { | 270 { |
| 162 DocumentLifecycle::DisallowTransitionScope(frame().document()->lifecycle()); | 271 DocumentLifecycle::DisallowTransitionScope(frame().document()->lifecycle()); |
| 163 | 272 |
| 164 // The basic approach is to search in two phases - from the selection end to the end of the doc, and | 273 // The basic approach is to search in two phases - from the selection end to the end of the doc, and |
| 165 // then we wrap and search from the doc start to (approximately) where we st arted. | 274 // then we wrap and search from the doc start to (approximately) where we st arted. |
| 166 | 275 |
| 167 // Start at the end of the selection, search to edge of document. Starting a t the selection end makes | 276 // Start at the end of the selection, search to edge of document. Starting a t the selection end makes |
| 168 // repeated "check spelling" commands work. | 277 // repeated "check spelling" commands work. |
| 169 VisibleSelection selection(frame().selection().selection()); | 278 VisibleSelection selection(frame().selection().selection()); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 219 | 328 |
| 220 if (spellingSearchStart == spellingSearchEnd) | 329 if (spellingSearchStart == spellingSearchEnd) |
| 221 return; // nothing to search in | 330 return; // nothing to search in |
| 222 | 331 |
| 223 // We go to the end of our first range instead of the start of it, just to b e sure | 332 // We go to the end of our first range instead of the start of it, just to b e sure |
| 224 // we don't get foiled by any word boundary problems at the start. It means we might | 333 // we don't get foiled by any word boundary problems at the start. It means we might |
| 225 // do a tiny bit more searching. | 334 // do a tiny bit more searching. |
| 226 Node* searchEndNodeAfterWrap = spellingSearchEnd.computeContainerNode(); | 335 Node* searchEndNodeAfterWrap = spellingSearchEnd.computeContainerNode(); |
| 227 int searchEndOffsetAfterWrap = spellingSearchEnd.offsetInContainerNode(); | 336 int searchEndOffsetAfterWrap = spellingSearchEnd.offsetInContainerNode(); |
| 228 | 337 |
| 229 int misspellingOffset = 0; | 338 std::pair<String, int> misspelledItem("", 0); |
| 230 String misspelledWord = TextCheckingHelper(spellCheckerClient(), spellingSea rchStart, spellingSearchEnd).findFirstMisspellingOrBadGrammar(misspellingOffset) ; | 339 String& misspelledWord = misspelledItem.first; |
| 340 int& misspellingOffset = misspelledItem.second; | |
| 341 misspelledItem = findFirstMisspelling(spellingSearchStart, spellingSearchEnd ); | |
| 231 | 342 |
| 232 // If we did not find a misspelled word, wrap and try again (but don't bothe r if we started at the beginning of the | 343 // If we did not find a misspelled word, wrap and try again (but don't bothe r if we started at the beginning of the |
| 233 // block rather than at a selection). | 344 // block rather than at a selection). |
| 234 if (startedWithSelection && !misspelledWord) { | 345 if (startedWithSelection && !misspelledWord) { |
| 235 spellingSearchStart = Position::editingPositionOf(topNode, 0); | 346 spellingSearchStart = Position::editingPositionOf(topNode, 0); |
| 236 // going until the end of the very first chunk we tested is far enough | 347 // going until the end of the very first chunk we tested is far enough |
| 237 spellingSearchEnd = Position::editingPositionOf(searchEndNodeAfterWrap, searchEndOffsetAfterWrap); | 348 spellingSearchEnd = Position::editingPositionOf(searchEndNodeAfterWrap, searchEndOffsetAfterWrap); |
| 238 misspelledWord = TextCheckingHelper(spellCheckerClient(), spellingSearch Start, spellingSearchEnd).findFirstMisspellingOrBadGrammar(misspellingOffset); | 349 misspelledItem = findFirstMisspelling(spellingSearchStart, spellingSearc hEnd); |
| 239 } | 350 } |
| 240 | 351 |
| 241 if (!misspelledWord.isEmpty()) { | 352 if (!misspelledWord.isEmpty()) { |
| 242 // We found a misspelling. Select the misspelling, update the spelling p anel, and store | 353 // We found a misspelling. Select the misspelling, update the spelling p anel, and store |
| 243 // a marker so we draw the red squiggle later. | 354 // a marker so we draw the red squiggle later. |
| 244 | 355 |
| 245 const EphemeralRange misspellingRange = calculateCharacterSubrange(Ephem eralRange(spellingSearchStart, spellingSearchEnd), misspellingOffset, misspelled Word.length()); | 356 const EphemeralRange misspellingRange = calculateCharacterSubrange(Ephem eralRange(spellingSearchStart, spellingSearchEnd), misspellingOffset, misspelled Word.length()); |
| 246 frame().selection().setSelection(VisibleSelection(misspellingRange)); | 357 frame().selection().setSelection(VisibleSelection(misspellingRange)); |
| 247 frame().selection().revealSelection(); | 358 frame().selection().revealSelection(); |
| 248 spellCheckerClient().updateSpellingUIWithMisspelledWord(misspelledWord); | 359 spellCheckerClient().updateSpellingUIWithMisspelledWord(misspelledWord); |
| (...skipping 541 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 790 visitor->trace(m_frame); | 901 visitor->trace(m_frame); |
| 791 visitor->trace(m_spellCheckRequester); | 902 visitor->trace(m_spellCheckRequester); |
| 792 } | 903 } |
| 793 | 904 |
| 794 void SpellChecker::prepareForLeakDetection() | 905 void SpellChecker::prepareForLeakDetection() |
| 795 { | 906 { |
| 796 m_spellCheckRequester->prepareForLeakDetection(); | 907 m_spellCheckRequester->prepareForLeakDetection(); |
| 797 } | 908 } |
| 798 | 909 |
| 799 } // namespace blink | 910 } // namespace blink |
| OLD | NEW |