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 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 65 { | 65 { |
| 66 HTMLTextFormControlElement* textControl = enclosingTextFormControl(selection .start()); | 66 HTMLTextFormControlElement* textControl = enclosingTextFormControl(selection .start()); |
| 67 return isHTMLTextAreaElement(textControl); | 67 return isHTMLTextAreaElement(textControl); |
| 68 } | 68 } |
| 69 | 69 |
| 70 bool isSelectionInTextFormControl(const VisibleSelection& selection) | 70 bool isSelectionInTextFormControl(const VisibleSelection& selection) |
| 71 { | 71 { |
| 72 return !!enclosingTextFormControl(selection.start()); | 72 return !!enclosingTextFormControl(selection.start()); |
| 73 } | 73 } |
| 74 | 74 |
| 75 static EphemeralRange expandEndToSentenceBoundary(const EphemeralRange& range) | |
| 76 { | |
| 77 DCHECK(range.isNotNull()); | |
| 78 const VisiblePosition& visibleEnd = createVisiblePosition(range.endPosition( )); | |
| 79 DCHECK(visibleEnd.isNotNull()); | |
| 80 const Position& sentenceEnd = endOfSentence(visibleEnd).deepEquivalent(); | |
| 81 // TODO(xiaochengh): |sentenceEnd < range.startPosition()| seems possible, | |
| 82 // which would trigger a DCHECK in EphemeralRange's constructor. Need more | |
| 83 // investigation, and if that is really the case, fix it. | |
| 84 return EphemeralRange(range.startPosition(), sentenceEnd.isNotNull() ? sente nceEnd : range.endPosition()); | |
| 85 } | |
| 86 | |
| 87 static EphemeralRange expandRangeToSentenceBoundary(const EphemeralRange& range) | |
| 88 { | |
| 89 DCHECK(range.isNotNull()); | |
| 90 const VisiblePosition& visibleStart = createVisiblePosition(range.startPosit ion()); | |
| 91 DCHECK(visibleStart.isNotNull()); | |
| 92 const Position& sentenceStart = startOfSentence(visibleStart).deepEquivalent (); | |
| 93 const VisiblePosition& visibleEnd = createVisiblePosition(range.endPosition( )); | |
| 94 DCHECK(visibleStart.isNotNull()); | |
| 95 const Position& sentenceEnd = endOfSentence(visibleEnd).deepEquivalent(); | |
| 96 return EphemeralRange(sentenceStart.isNull() ? range.startPosition() : sente nceStart, sentenceEnd.isNull() ? range.endPosition() : sentenceEnd); | |
| 97 } | |
| 98 | |
| 75 } // namespace | 99 } // namespace |
| 76 | 100 |
| 77 SpellChecker* SpellChecker::create(LocalFrame& frame) | 101 SpellChecker* SpellChecker::create(LocalFrame& frame) |
| 78 { | 102 { |
| 79 return new SpellChecker(frame); | 103 return new SpellChecker(frame); |
| 80 } | 104 } |
| 81 | 105 |
| 82 static SpellCheckerClient& emptySpellCheckerClient() | 106 static SpellCheckerClient& emptySpellCheckerClient() |
| 83 { | 107 { |
| 84 DEFINE_STATIC_LOCAL(EmptySpellCheckerClient, client, ()); | 108 DEFINE_STATIC_LOCAL(EmptySpellCheckerClient, client, ()); |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 259 | 283 |
| 260 advanceToNextMisspelling(true); | 284 advanceToNextMisspelling(true); |
| 261 spellCheckerClient().showSpellingUI(true); | 285 spellCheckerClient().showSpellingUI(true); |
| 262 } | 286 } |
| 263 | 287 |
| 264 void SpellChecker::clearMisspellingsAndBadGrammar(const VisibleSelection &moving Selection) | 288 void SpellChecker::clearMisspellingsAndBadGrammar(const VisibleSelection &moving Selection) |
| 265 { | 289 { |
| 266 removeMarkers(movingSelection, DocumentMarker::MisspellingMarkers()); | 290 removeMarkers(movingSelection, DocumentMarker::MisspellingMarkers()); |
| 267 } | 291 } |
| 268 | 292 |
| 269 void SpellChecker::markMisspellingsAndBadGrammar(const VisibleSelection &movingS election) | 293 void SpellChecker::markMisspellingsAndBadGrammar(const VisibleSelection& selecti on) |
| 270 { | 294 { |
| 271 markAllMisspellingsAndBadGrammar(movingSelection, movingSelection); | 295 if (!isContinuousSpellCheckingEnabled()) |
|
yosin_UTC9
2016/08/16 02:28:47
BTW, Could you rename |isContinuousSpellCheckingEn
| |
| 296 return; | |
| 297 | |
| 298 const EphemeralRange& range = selection.toNormalizedEphemeralRange(); | |
| 299 if (range.isNull()) | |
| 300 return; | |
| 301 | |
| 302 // If we're not in an editable node, bail. | |
| 303 Node* editableNode = range.startPosition().computeContainerNode(); | |
| 304 if (!editableNode || !hasEditableStyle(*editableNode)) | |
| 305 return; | |
| 306 | |
| 307 if (!isSpellCheckingEnabledFor(editableNode)) | |
| 308 return; | |
| 309 | |
| 310 TextCheckingParagraph fullParagraphToCheck(expandRangeToSentenceBoundary(ran ge)); | |
| 311 chunkAndMarkAllMisspellingsAndBadGrammar(fullParagraphToCheck); | |
| 272 } | 312 } |
| 273 | 313 |
| 274 void SpellChecker::markMisspellingsAfterLineBreak(const VisibleSelection& wordSe lection) | 314 void SpellChecker::markMisspellingsAfterLineBreak(const VisibleSelection& wordSe lection) |
| 275 { | 315 { |
| 276 if (!isContinuousSpellCheckingEnabled()) | 316 if (!isContinuousSpellCheckingEnabled()) |
| 277 return; | 317 return; |
| 278 | 318 |
| 279 TRACE_EVENT0("blink", "SpellChecker::markMisspellingsAfterLineBreak"); | 319 TRACE_EVENT0("blink", "SpellChecker::markMisspellingsAfterLineBreak"); |
| 280 | 320 |
| 281 VisibleSelection wholeParagraph( | 321 markMisspellingsAndBadGrammar(wordSelection); |
| 282 startOfParagraph(wordSelection.visibleStart()), | |
| 283 endOfParagraph(wordSelection.visibleEnd())); | |
| 284 | |
| 285 markAllMisspellingsAndBadGrammar(wordSelection, wholeParagraph); | |
| 286 } | 322 } |
| 287 | 323 |
| 288 void SpellChecker::markMisspellingsAfterTypingToWord(const VisiblePosition &word Start, const VisibleSelection& selectionAfterTyping) | 324 void SpellChecker::markMisspellingsAfterTypingToWord(const VisiblePosition &word Start, const VisibleSelection& selectionAfterTyping) |
| 289 { | 325 { |
| 290 if (!isContinuousSpellCheckingEnabled()) | 326 if (!isContinuousSpellCheckingEnabled()) |
| 291 return; | 327 return; |
| 292 | 328 |
| 293 TRACE_EVENT0("blink", "SpellChecker::markMisspellingsAfterTypingToWord"); | 329 TRACE_EVENT0("blink", "SpellChecker::markMisspellingsAfterTypingToWord"); |
| 294 | 330 |
| 295 VisibleSelection adjacentWords = VisibleSelection(startOfWord(wordStart, Lef tWordIfOnBoundary), endOfWord(wordStart, RightWordIfOnBoundary)); | 331 VisibleSelection adjacentWords = VisibleSelection(startOfWord(wordStart, Lef tWordIfOnBoundary), endOfWord(wordStart, RightWordIfOnBoundary)); |
| 296 VisibleSelection selectedSentence = VisibleSelection(startOfSentence(wordSta rt), endOfSentence(wordStart)); | 332 markMisspellingsAndBadGrammar(adjacentWords); |
| 297 markAllMisspellingsAndBadGrammar(adjacentWords, selectedSentence); | |
| 298 } | 333 } |
| 299 | 334 |
| 300 bool SpellChecker::isSpellCheckingEnabledFor(Node* node) const | 335 bool SpellChecker::isSpellCheckingEnabledFor(Node* node) const |
| 301 { | 336 { |
| 302 if (!node) | 337 if (!node) |
| 303 return false; | 338 return false; |
| 304 const Element* focusedElement = node->isElementNode() ? toElement(node) : no de->parentElement(); | 339 const Element* focusedElement = node->isElementNode() ? toElement(node) : no de->parentElement(); |
| 305 if (!focusedElement) | 340 if (!focusedElement) |
| 306 return false; | 341 return false; |
| 307 return focusedElement->isSpellCheckingEnabled(); | 342 return focusedElement->isSpellCheckingEnabled(); |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 322 if (isHTMLInputElement(textControl) && toHTMLInputElement(textControl)-> type() == InputTypeNames::password) | 357 if (isHTMLInputElement(textControl) && toHTMLInputElement(textControl)-> type() == InputTypeNames::password) |
| 323 return false; | 358 return false; |
| 324 } | 359 } |
| 325 if (HTMLElement* element = Traversal<HTMLElement>::firstAncestorOrSelf(*sele ction.start().anchorNode())) { | 360 if (HTMLElement* element = Traversal<HTMLElement>::firstAncestorOrSelf(*sele ction.start().anchorNode())) { |
| 326 if (element->spellcheck()) | 361 if (element->spellcheck()) |
| 327 return true; | 362 return true; |
| 328 } | 363 } |
| 329 return false; | 364 return false; |
| 330 } | 365 } |
| 331 | 366 |
| 332 void SpellChecker::markAllMisspellingsAndBadGrammar(const VisibleSelection& spel lingSelection, const VisibleSelection& grammarSelection) | |
| 333 { | |
| 334 if (!isContinuousSpellCheckingEnabled()) | |
| 335 return; | |
| 336 | |
| 337 // This function is called with selections already expanded to word boundari es. | |
| 338 // This function is triggered by selection change, in which case we check | |
| 339 // spelling and grammar, but don't autocorrect misspellings. | |
| 340 | |
| 341 const EphemeralRange& spellingRange = spellingSelection.toNormalizedEphemera lRange(); | |
| 342 const EphemeralRange& grammarRange = grammarSelection.toNormalizedEphemeralR ange(); | |
| 343 if (spellingRange.isNull() || grammarRange.isNull()) | |
| 344 return; | |
| 345 | |
| 346 // If we're not in an editable node, bail. | |
| 347 Node* editableNode = spellingRange.startPosition().computeContainerNode(); | |
| 348 if (!editableNode || !hasEditableStyle(*editableNode)) | |
| 349 return; | |
| 350 | |
| 351 if (!isSpellCheckingEnabledFor(editableNode)) | |
| 352 return; | |
| 353 | |
| 354 TextCheckingParagraph fullParagraphToCheck(grammarRange); | |
| 355 chunkAndMarkAllMisspellingsAndBadGrammar(fullParagraphToCheck); | |
| 356 } | |
| 357 | |
| 358 static EphemeralRange expandEndToSentenceBoundary(const EphemeralRange& range) | |
| 359 { | |
| 360 DCHECK(range.isNotNull()); | |
| 361 const VisiblePosition& visibleEnd = createVisiblePosition(range.endPosition( )); | |
| 362 DCHECK(visibleEnd.isNotNull()); | |
| 363 const Position& sentenceEnd = endOfSentence(visibleEnd).deepEquivalent(); | |
| 364 return EphemeralRange(range.startPosition(), sentenceEnd.isNotNull() ? sente nceEnd : range.endPosition()); | |
| 365 } | |
| 366 | |
| 367 static EphemeralRange expandRangeToSentenceBoundary(const EphemeralRange& range) | |
| 368 { | |
| 369 DCHECK(range.isNotNull()); | |
| 370 const VisiblePosition& visibleStart = createVisiblePosition(range.startPosit ion()); | |
| 371 DCHECK(visibleStart.isNotNull()); | |
| 372 const Position& sentenceStart = startOfSentence(visibleStart).deepEquivalent (); | |
| 373 return expandEndToSentenceBoundary(EphemeralRange(sentenceStart.isNull() ? r ange.startPosition() : sentenceStart, range.endPosition())); | |
| 374 } | |
| 375 | |
| 376 void SpellChecker::chunkAndMarkAllMisspellingsAndBadGrammar(Node* node, const Ep hemeralRange& insertedRange) | 367 void SpellChecker::chunkAndMarkAllMisspellingsAndBadGrammar(Node* node, const Ep hemeralRange& insertedRange) |
| 377 { | 368 { |
| 378 TRACE_EVENT0("blink", "SpellChecker::chunkAndMarkAllMisspellingsAndBadGramma r"); | 369 TRACE_EVENT0("blink", "SpellChecker::chunkAndMarkAllMisspellingsAndBadGramma r"); |
| 379 if (!node) | 370 if (!node) |
| 380 return; | 371 return; |
| 381 EphemeralRange paragraphRange(Position::firstPositionInNode(node), Position: :lastPositionInNode(node)); | 372 EphemeralRange paragraphRange(Position::firstPositionInNode(node), Position: :lastPositionInNode(node)); |
| 382 TextCheckingParagraph textToCheck(insertedRange, paragraphRange); | 373 TextCheckingParagraph textToCheck(insertedRange, paragraphRange); |
| 383 chunkAndMarkAllMisspellingsAndBadGrammar(textToCheck); | 374 chunkAndMarkAllMisspellingsAndBadGrammar(textToCheck); |
| 384 } | 375 } |
| 385 | 376 |
| (...skipping 328 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 714 { | 705 { |
| 715 if (!isContinuousSpellCheckingEnabled()) | 706 if (!isContinuousSpellCheckingEnabled()) |
| 716 return; | 707 return; |
| 717 | 708 |
| 718 TRACE_EVENT0("blink", "SpellChecker::spellCheckOldSelection"); | 709 TRACE_EVENT0("blink", "SpellChecker::spellCheckOldSelection"); |
| 719 | 710 |
| 720 VisiblePosition oldStart(oldSelection.visibleStart()); | 711 VisiblePosition oldStart(oldSelection.visibleStart()); |
| 721 VisibleSelection oldAdjacentWords = VisibleSelection(startOfWord(oldStart, L eftWordIfOnBoundary), endOfWord(oldStart, RightWordIfOnBoundary)); | 712 VisibleSelection oldAdjacentWords = VisibleSelection(startOfWord(oldStart, L eftWordIfOnBoundary), endOfWord(oldStart, RightWordIfOnBoundary)); |
| 722 if (oldAdjacentWords == newAdjacentWords) | 713 if (oldAdjacentWords == newAdjacentWords) |
| 723 return; | 714 return; |
| 724 VisibleSelection selectedSentence = VisibleSelection(startOfSentence(oldStar t), endOfSentence(oldStart)); | 715 markMisspellingsAndBadGrammar(oldAdjacentWords); |
| 725 markAllMisspellingsAndBadGrammar(oldAdjacentWords, selectedSentence); | |
| 726 } | 716 } |
| 727 | 717 |
| 728 static Node* findFirstMarkable(Node* node) | 718 static Node* findFirstMarkable(Node* node) |
| 729 { | 719 { |
| 730 while (node) { | 720 while (node) { |
| 731 if (!node->layoutObject()) | 721 if (!node->layoutObject()) |
| 732 return 0; | 722 return 0; |
| 733 if (node->layoutObject()->isText()) | 723 if (node->layoutObject()->isText()) |
| 734 return node; | 724 return node; |
| 735 if (node->layoutObject()->isTextControl()) | 725 if (node->layoutObject()->isTextControl()) |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 790 visitor->trace(m_frame); | 780 visitor->trace(m_frame); |
| 791 visitor->trace(m_spellCheckRequester); | 781 visitor->trace(m_spellCheckRequester); |
| 792 } | 782 } |
| 793 | 783 |
| 794 void SpellChecker::prepareForLeakDetection() | 784 void SpellChecker::prepareForLeakDetection() |
| 795 { | 785 { |
| 796 m_spellCheckRequester->prepareForLeakDetection(); | 786 m_spellCheckRequester->prepareForLeakDetection(); |
| 797 } | 787 } |
| 798 | 788 |
| 799 } // namespace blink | 789 } // namespace blink |
| OLD | NEW |