Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(777)

Side by Side Diff: third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp

Issue 2397023002: Reflow comments in //third_party/WebKit/Source/core/editing/spellcheck (Closed)
Patch Set: Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/WebKit/Source/core/editing/spellcheck/SpellCheckRequester.cpp ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 190 matching lines...) Expand 10 before | Expand all | Expand 10 after
201 element = textControl->innerEditorElement(); 201 element = textControl->innerEditorElement();
202 if (!element) 202 if (!element)
203 return; 203 return;
204 isTextField = isHTMLInputElement(*textControl) && 204 isTextField = isHTMLInputElement(*textControl) &&
205 toHTMLInputElement(*textControl).isTextField(); 205 toHTMLInputElement(*textControl).isTextField();
206 } 206 }
207 207
208 if (isTextField || !parent->isAlreadySpellChecked()) { 208 if (isTextField || !parent->isAlreadySpellChecked()) {
209 if (EditingStrategy::editingIgnoresContent(element)) 209 if (EditingStrategy::editingIgnoresContent(element))
210 return; 210 return;
211 // We always recheck textfields because markers are removed from them on blu r. 211 // We always recheck textfields because markers are removed from them on
212 // blur.
212 VisibleSelection selection = 213 VisibleSelection selection =
213 VisibleSelection::selectionFromContentsOfNode(element); 214 VisibleSelection::selectionFromContentsOfNode(element);
214 markMisspellingsAndBadGrammar(selection); 215 markMisspellingsAndBadGrammar(selection);
215 if (!isTextField) 216 if (!isTextField)
216 parent->setAlreadySpellChecked(true); 217 parent->setAlreadySpellChecked(true);
217 } 218 }
218 } 219 }
219 220
220 void SpellChecker::ignoreSpelling() { 221 void SpellChecker::ignoreSpelling() {
221 removeMarkers(frame().selection().selection(), DocumentMarker::Spelling); 222 removeMarkers(frame().selection().selection(), DocumentMarker::Spelling);
222 } 223 }
223 224
224 void SpellChecker::advanceToNextMisspelling(bool startBeforeSelection) { 225 void SpellChecker::advanceToNextMisspelling(bool startBeforeSelection) {
225 DocumentLifecycle::DisallowTransitionScope disallowTransition( 226 DocumentLifecycle::DisallowTransitionScope disallowTransition(
226 frame().document()->lifecycle()); 227 frame().document()->lifecycle());
227 228
228 // The basic approach is to search in two phases - from the selection end to t he end of the doc, and 229 // The basic approach is to search in two phases - from the selection end to
229 // then we wrap and search from the doc start to (approximately) where we star ted. 230 // the end of the doc, and then we wrap and search from the doc start to
231 // (approximately) where we started.
230 232
231 // Start at the end of the selection, search to edge of document. Starting at the selection end makes 233 // Start at the end of the selection, search to edge of document. Starting at
232 // repeated "check spelling" commands work. 234 // the selection end makes repeated "check spelling" commands work.
233 VisibleSelection selection(frame().selection().selection()); 235 VisibleSelection selection(frame().selection().selection());
234 Position spellingSearchStart, spellingSearchEnd; 236 Position spellingSearchStart, spellingSearchEnd;
235 Range::selectNodeContents(frame().document(), spellingSearchStart, 237 Range::selectNodeContents(frame().document(), spellingSearchStart,
236 spellingSearchEnd); 238 spellingSearchEnd);
237 239
238 bool startedWithSelection = false; 240 bool startedWithSelection = false;
239 if (selection.start().anchorNode()) { 241 if (selection.start().anchorNode()) {
240 startedWithSelection = true; 242 startedWithSelection = true;
241 if (startBeforeSelection) { 243 if (startBeforeSelection) {
242 VisiblePosition start(selection.visibleStart()); 244 VisiblePosition start(selection.visibleStart());
243 // We match AppKit's rule: Start 1 character before the selection. 245 // We match AppKit's rule: Start 1 character before the selection.
244 VisiblePosition oneBeforeStart = previousPositionOf(start); 246 VisiblePosition oneBeforeStart = previousPositionOf(start);
245 spellingSearchStart = 247 spellingSearchStart =
246 (oneBeforeStart.isNotNull() ? oneBeforeStart : start) 248 (oneBeforeStart.isNotNull() ? oneBeforeStart : start)
247 .toParentAnchoredPosition(); 249 .toParentAnchoredPosition();
248 } else { 250 } else {
249 spellingSearchStart = selection.visibleEnd().toParentAnchoredPosition(); 251 spellingSearchStart = selection.visibleEnd().toParentAnchoredPosition();
250 } 252 }
251 } 253 }
252 254
253 Position position = spellingSearchStart; 255 Position position = spellingSearchStart;
254 if (!isEditablePosition(position)) { 256 if (!isEditablePosition(position)) {
255 // This shouldn't happen in very often because the Spelling menu items aren' t enabled unless the 257 // This shouldn't happen in very often because the Spelling menu items
256 // selection is editable. 258 // aren't enabled unless the selection is editable. This can happen in Mail
257 // This can happen in Mail for a mix of non-editable and editable content (l ike Stationary), 259 // for a mix of non-editable and editable content (like Stationary), when
258 // when spell checking the whole document before sending the message. 260 // spell checking the whole document before sending the message. In that
259 // In that case the document might not be editable, but there are editable p ockets that need to be spell checked. 261 // case the document might not be editable, but there are editable pockets
262 // that need to be spell checked.
260 263
261 if (!frame().document()->documentElement()) 264 if (!frame().document()->documentElement())
262 return; 265 return;
263 position = firstEditableVisiblePositionAfterPositionInRoot( 266 position = firstEditableVisiblePositionAfterPositionInRoot(
264 position, *frame().document()->documentElement()) 267 position, *frame().document()->documentElement())
265 .deepEquivalent(); 268 .deepEquivalent();
266 if (position.isNull()) 269 if (position.isNull())
267 return; 270 return;
268 271
269 spellingSearchStart = position.parentAnchoredEquivalent(); 272 spellingSearchStart = position.parentAnchoredEquivalent();
(...skipping 17 matching lines...) Expand all
287 rootEditableElementOf(oneBeforeStart) == 290 rootEditableElementOf(oneBeforeStart) ==
288 rootEditableElementOf(spellingSearchStart)) 291 rootEditableElementOf(spellingSearchStart))
289 spellingSearchStart = 292 spellingSearchStart =
290 endOfWord(oneBeforeStart).toParentAnchoredPosition(); 293 endOfWord(oneBeforeStart).toParentAnchoredPosition();
291 // else we were already at the start of the editable node 294 // else we were already at the start of the editable node
292 } 295 }
293 296
294 if (spellingSearchStart == spellingSearchEnd) 297 if (spellingSearchStart == spellingSearchEnd)
295 return; // nothing to search in 298 return; // nothing to search in
296 299
297 // We go to the end of our first range instead of the start of it, just to be sure 300 // We go to the end of our first range instead of the start of it, just to be
298 // we don't get foiled by any word boundary problems at the start. It means we might 301 // sure we don't get foiled by any word boundary problems at the start. It
299 // do a tiny bit more searching. 302 // means we might do a tiny bit more searching.
300 Node* searchEndNodeAfterWrap = spellingSearchEnd.computeContainerNode(); 303 Node* searchEndNodeAfterWrap = spellingSearchEnd.computeContainerNode();
301 int searchEndOffsetAfterWrap = spellingSearchEnd.offsetInContainerNode(); 304 int searchEndOffsetAfterWrap = spellingSearchEnd.offsetInContainerNode();
302 305
303 std::pair<String, int> misspelledItem(String(), 0); 306 std::pair<String, int> misspelledItem(String(), 0);
304 String& misspelledWord = misspelledItem.first; 307 String& misspelledWord = misspelledItem.first;
305 int& misspellingOffset = misspelledItem.second; 308 int& misspellingOffset = misspelledItem.second;
306 misspelledItem = findFirstMisspelling(spellingSearchStart, spellingSearchEnd); 309 misspelledItem = findFirstMisspelling(spellingSearchStart, spellingSearchEnd);
307 310
308 // If we did not find a misspelled word, wrap and try again (but don't bother if we started at the beginning of the 311 // If we did not find a misspelled word, wrap and try again (but don't bother
309 // block rather than at a selection). 312 // if we started at the beginning of the block rather than at a selection).
310 if (startedWithSelection && !misspelledWord) { 313 if (startedWithSelection && !misspelledWord) {
311 spellingSearchStart = Position::editingPositionOf(topNode, 0); 314 spellingSearchStart = Position::editingPositionOf(topNode, 0);
312 // going until the end of the very first chunk we tested is far enough 315 // going until the end of the very first chunk we tested is far enough
313 spellingSearchEnd = Position::editingPositionOf(searchEndNodeAfterWrap, 316 spellingSearchEnd = Position::editingPositionOf(searchEndNodeAfterWrap,
314 searchEndOffsetAfterWrap); 317 searchEndOffsetAfterWrap);
315 misspelledItem = 318 misspelledItem =
316 findFirstMisspelling(spellingSearchStart, spellingSearchEnd); 319 findFirstMisspelling(spellingSearchStart, spellingSearchEnd);
317 } 320 }
318 321
319 if (!misspelledWord.isEmpty()) { 322 if (!misspelledWord.isEmpty()) {
320 // We found a misspelling. Select the misspelling, update the spelling panel , and store 323 // We found a misspelling. Select the misspelling, update the spelling
321 // a marker so we draw the red squiggle later. 324 // panel, and store a marker so we draw the red squiggle later.
322 325
323 const EphemeralRange misspellingRange = calculateCharacterSubrange( 326 const EphemeralRange misspellingRange = calculateCharacterSubrange(
324 EphemeralRange(spellingSearchStart, spellingSearchEnd), 327 EphemeralRange(spellingSearchStart, spellingSearchEnd),
325 misspellingOffset, misspelledWord.length()); 328 misspellingOffset, misspelledWord.length());
326 frame().selection().setSelection(createVisibleSelection(misspellingRange)); 329 frame().selection().setSelection(createVisibleSelection(misspellingRange));
327 frame().selection().revealSelection(); 330 frame().selection().revealSelection();
328 spellCheckerClient().updateSpellingUIWithMisspelledWord(misspelledWord); 331 spellCheckerClient().updateSpellingUIWithMisspelledWord(misspelledWord);
329 frame().document()->markers().addMarker(misspellingRange.startPosition(), 332 frame().document()->markers().addMarker(misspellingRange.startPosition(),
330 misspellingRange.endPosition(), 333 misspellingRange.endPosition(),
331 DocumentMarker::Spelling); 334 DocumentMarker::Spelling);
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
404 if (cmd.inputType() != InputEvent::InputType::InsertFromPaste) 407 if (cmd.inputType() != InputEvent::InputType::InsertFromPaste)
405 return; 408 return;
406 409
407 markMisspellingsAfterReplaceSelectionCommand(toReplaceSelectionCommand(cmd)); 410 markMisspellingsAfterReplaceSelectionCommand(toReplaceSelectionCommand(cmd));
408 } 411 }
409 412
410 void SpellChecker::markMisspellingsAfterTypingCommand( 413 void SpellChecker::markMisspellingsAfterTypingCommand(
411 const TypingCommand& cmd) { 414 const TypingCommand& cmd) {
412 m_spellCheckRequester->cancelCheck(); 415 m_spellCheckRequester->cancelCheck();
413 416
414 // Take a look at the selection that results after typing and determine whethe r we need to spellcheck. 417 // Take a look at the selection that results after typing and determine
415 // Since the word containing the current selection is never marked, this does a check to 418 // whether we need to spellcheck. Since the word containing the current
416 // see if typing made a new word that is not in the current selection. Basical ly, you 419 // selection is never marked, this does a check to see if typing made a new
417 // get this by being at the end of a word and typing a space. 420 // word that is not in the current selection. Basically, you get this by
421 // being at the end of a word and typing a space.
418 VisiblePosition start = createVisiblePosition( 422 VisiblePosition start = createVisiblePosition(
419 cmd.endingSelection().start(), cmd.endingSelection().affinity()); 423 cmd.endingSelection().start(), cmd.endingSelection().affinity());
420 VisiblePosition previous = previousPositionOf(start); 424 VisiblePosition previous = previousPositionOf(start);
421 425
422 VisiblePosition wordStartOfPrevious = 426 VisiblePosition wordStartOfPrevious =
423 startOfWord(previous, LeftWordIfOnBoundary); 427 startOfWord(previous, LeftWordIfOnBoundary);
424 428
425 if (cmd.commandTypeOfOpenCommand() == 429 if (cmd.commandTypeOfOpenCommand() ==
426 TypingCommand::InsertParagraphSeparator) { 430 TypingCommand::InsertParagraphSeparator) {
427 VisiblePosition nextWord = nextWordPosition(start); 431 VisiblePosition nextWord = nextWordPosition(start);
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
486 TextCheckingParagraph textToCheck(insertedRange, paragraphRange); 490 TextCheckingParagraph textToCheck(insertedRange, paragraphRange);
487 chunkAndMarkAllMisspellingsAndBadGrammar(textToCheck); 491 chunkAndMarkAllMisspellingsAndBadGrammar(textToCheck);
488 } 492 }
489 493
490 void SpellChecker::chunkAndMarkAllMisspellingsAndBadGrammar( 494 void SpellChecker::chunkAndMarkAllMisspellingsAndBadGrammar(
491 const TextCheckingParagraph& fullParagraphToCheck) { 495 const TextCheckingParagraph& fullParagraphToCheck) {
492 if (fullParagraphToCheck.isEmpty()) 496 if (fullParagraphToCheck.isEmpty())
493 return; 497 return;
494 const EphemeralRange& paragraphRange = fullParagraphToCheck.paragraphRange(); 498 const EphemeralRange& paragraphRange = fullParagraphToCheck.paragraphRange();
495 499
496 // Since the text may be quite big chunk it up and adjust to the sentence boun dary. 500 // Since the text may be quite big chunk it up and adjust to the sentence
501 // boundary.
497 const int kChunkSize = 16 * 1024; 502 const int kChunkSize = 16 * 1024;
498 503
499 // Check the full paragraph instead if the paragraph is short, which saves 504 // Check the full paragraph instead if the paragraph is short, which saves
500 // the cost on sentence boundary finding. 505 // the cost on sentence boundary finding.
501 if (fullParagraphToCheck.rangeLength() <= kChunkSize) { 506 if (fullParagraphToCheck.rangeLength() <= kChunkSize) {
502 SpellCheckRequest* request = 507 SpellCheckRequest* request =
503 SpellCheckRequest::create(TextCheckingProcessBatch, paragraphRange, 0); 508 SpellCheckRequest::create(TextCheckingProcessBatch, paragraphRange, 0);
504 if (request) 509 if (request)
505 m_spellCheckRequester->requestCheckingFor(request); 510 m_spellCheckRequester->requestCheckingFor(request);
506 return; 511 return;
507 } 512 }
508 513
509 CharacterIterator checkRangeIterator( 514 CharacterIterator checkRangeIterator(
510 fullParagraphToCheck.checkingRange(), 515 fullParagraphToCheck.checkingRange(),
511 TextIteratorEmitsObjectReplacementCharacter); 516 TextIteratorEmitsObjectReplacementCharacter);
512 for (int requestNum = 0; !checkRangeIterator.atEnd(); requestNum++) { 517 for (int requestNum = 0; !checkRangeIterator.atEnd(); requestNum++) {
513 EphemeralRange chunkRange = 518 EphemeralRange chunkRange =
514 checkRangeIterator.calculateCharacterSubrange(0, kChunkSize); 519 checkRangeIterator.calculateCharacterSubrange(0, kChunkSize);
515 EphemeralRange checkRange = requestNum 520 EphemeralRange checkRange = requestNum
516 ? expandEndToSentenceBoundary(chunkRange) 521 ? expandEndToSentenceBoundary(chunkRange)
517 : expandRangeToSentenceBoundary(chunkRange); 522 : expandRangeToSentenceBoundary(chunkRange);
518 523
519 SpellCheckRequest* request = SpellCheckRequest::create( 524 SpellCheckRequest* request = SpellCheckRequest::create(
520 TextCheckingProcessBatch, checkRange, requestNum); 525 TextCheckingProcessBatch, checkRange, requestNum);
521 if (request) 526 if (request)
522 m_spellCheckRequester->requestCheckingFor(request); 527 m_spellCheckRequester->requestCheckingFor(request);
523 528
524 if (!checkRangeIterator.atEnd()) { 529 if (!checkRangeIterator.atEnd()) {
525 checkRangeIterator.advance(1); 530 checkRangeIterator.advance(1);
526 // The layout should be already update due to the initialization of checkR angeIterator, 531 // The layout should be already update due to the initialization of
527 // so comparePositions can be directly called. 532 // checkRangeIterator, so comparePositions can be directly called.
528 if (comparePositions(chunkRange.endPosition(), checkRange.endPosition()) < 533 if (comparePositions(chunkRange.endPosition(), checkRange.endPosition()) <
529 0) 534 0)
530 checkRangeIterator.advance(TextIterator::rangeLength( 535 checkRangeIterator.advance(TextIterator::rangeLength(
531 chunkRange.endPosition(), checkRange.endPosition())); 536 chunkRange.endPosition(), checkRange.endPosition()));
532 } 537 }
533 } 538 }
534 } 539 }
535 540
536 void SpellChecker::markAndReplaceFor( 541 void SpellChecker::markAndReplaceFor(
537 SpellCheckRequest* request, 542 SpellCheckRequest* request,
538 const Vector<TextCheckingResult>& results) { 543 const Vector<TextCheckingResult>& results) {
539 TRACE_EVENT0("blink", "SpellChecker::markAndReplaceFor"); 544 TRACE_EVENT0("blink", "SpellChecker::markAndReplaceFor");
540 DCHECK(request); 545 DCHECK(request);
541 if (!frame().selection().isAvailable()) { 546 if (!frame().selection().isAvailable()) {
542 // "editing/spelling/spellcheck-async-remove-frame.html" reaches here. 547 // "editing/spelling/spellcheck-async-remove-frame.html" reaches here.
543 return; 548 return;
544 } 549 }
545 if (!request->isValid()) 550 if (!request->isValid())
546 return; 551 return;
547 if (request->rootEditableElement()->document() != 552 if (request->rootEditableElement()->document() !=
548 frame().selection().document()) { 553 frame().selection().document()) {
549 // we ignore |request| made for another document. 554 // we ignore |request| made for another document.
550 // "editing/spelling/spellcheck-sequencenum.html" and others reach here. 555 // "editing/spelling/spellcheck-sequencenum.html" and others reach here.
551 return; 556 return;
552 } 557 }
553 558
554 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets n eeds to be audited. 559 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
555 // see http://crbug.com/590369 for more details. 560 // needs to be audited. See http://crbug.com/590369 for more details.
556 frame().document()->updateStyleAndLayoutIgnorePendingStylesheets(); 561 frame().document()->updateStyleAndLayoutIgnorePendingStylesheets();
557 562
558 TextCheckingParagraph paragraph(request->checkingRange(), 563 TextCheckingParagraph paragraph(request->checkingRange(),
559 request->checkingRange()); 564 request->checkingRange());
560 565
561 // Expand the range to encompass entire paragraphs, since text checking needs that much context. 566 // Expand the range to encompass entire paragraphs, since text checking needs
567 // that much context.
562 int selectionOffset = 0; 568 int selectionOffset = 0;
563 int ambiguousBoundaryOffset = -1; 569 int ambiguousBoundaryOffset = -1;
564 bool selectionChanged = false; 570 bool selectionChanged = false;
565 bool restoreSelectionAfterChange = false; 571 bool restoreSelectionAfterChange = false;
566 bool adjustSelectionForParagraphBoundaries = false; 572 bool adjustSelectionForParagraphBoundaries = false;
567 573
568 { 574 {
569 DocumentLifecycle::DisallowTransitionScope disallowTransition( 575 DocumentLifecycle::DisallowTransitionScope disallowTransition(
570 frame().document()->lifecycle()); 576 frame().document()->lifecycle());
571 577
(...skipping 18 matching lines...) Expand all
590 const TextCheckingResult* result = &results[i]; 596 const TextCheckingResult* result = &results[i];
591 int resultLocation = result->location + paragraph.checkingStart(); 597 int resultLocation = result->location + paragraph.checkingStart();
592 int resultLength = result->length; 598 int resultLength = result->length;
593 bool resultEndsAtAmbiguousBoundary = 599 bool resultEndsAtAmbiguousBoundary =
594 ambiguousBoundaryOffset >= 0 && 600 ambiguousBoundaryOffset >= 0 &&
595 resultLocation + resultLength == ambiguousBoundaryOffset; 601 resultLocation + resultLength == ambiguousBoundaryOffset;
596 602
597 // Only mark misspelling if: 603 // Only mark misspelling if:
598 // 1. Current text checking isn't done for autocorrection. 604 // 1. Current text checking isn't done for autocorrection.
599 // 2. Result falls within spellingRange. 605 // 2. Result falls within spellingRange.
600 // 3. The word in question doesn't end at an ambiguous boundary. For insta nce, we would not mark 606 // 3. The word in question doesn't end at an ambiguous boundary. For
601 // "wouldn'" as misspelled right after apostrophe is typed. 607 // instance, we would not mark "wouldn'" as misspelled right after
608 // apostrophe is typed.
602 if (result->decoration == TextDecorationTypeSpelling && 609 if (result->decoration == TextDecorationTypeSpelling &&
603 resultLocation >= paragraph.checkingStart() && 610 resultLocation >= paragraph.checkingStart() &&
604 resultLocation + resultLength <= spellingRangeEndOffset && 611 resultLocation + resultLength <= spellingRangeEndOffset &&
605 !resultEndsAtAmbiguousBoundary) { 612 !resultEndsAtAmbiguousBoundary) {
606 DCHECK_GT(resultLength, 0); 613 DCHECK_GT(resultLength, 0);
607 DCHECK_GE(resultLocation, 0); 614 DCHECK_GE(resultLocation, 0);
608 const EphemeralRange misspellingRange = calculateCharacterSubrange( 615 const EphemeralRange misspellingRange = calculateCharacterSubrange(
609 paragraph.paragraphRange(), resultLocation, resultLength); 616 paragraph.paragraphRange(), resultLocation, resultLength);
610 frame().document()->markers().addMarker( 617 frame().document()->markers().addMarker(
611 misspellingRange.startPosition(), misspellingRange.endPosition(), 618 misspellingRange.startPosition(), misspellingRange.endPosition(),
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
652 if (restoreSelectionAfterChange && selectionOffset >= 0 && 659 if (restoreSelectionAfterChange && selectionOffset >= 0 &&
653 selectionOffset <= extendedParagraph.rangeLength()) { 660 selectionOffset <= extendedParagraph.rangeLength()) {
654 EphemeralRange selectionRange = 661 EphemeralRange selectionRange =
655 extendedParagraph.subrange(0, selectionOffset); 662 extendedParagraph.subrange(0, selectionOffset);
656 frame().selection().moveTo(selectionRange.endPosition(), 663 frame().selection().moveTo(selectionRange.endPosition(),
657 TextAffinity::Downstream); 664 TextAffinity::Downstream);
658 if (adjustSelectionForParagraphBoundaries) 665 if (adjustSelectionForParagraphBoundaries)
659 frame().selection().modify(FrameSelection::AlterationMove, 666 frame().selection().modify(FrameSelection::AlterationMove,
660 DirectionForward, CharacterGranularity); 667 DirectionForward, CharacterGranularity);
661 } else { 668 } else {
662 // If this fails for any reason, the fallback is to go one position beyond the last replacement 669 // If this fails for any reason, the fallback is to go one position beyond
670 // the last replacement
663 frame().selection().moveTo(frame().selection().selection().visibleEnd()); 671 frame().selection().moveTo(frame().selection().selection().visibleEnd());
664 frame().selection().modify(FrameSelection::AlterationMove, 672 frame().selection().modify(FrameSelection::AlterationMove,
665 DirectionForward, CharacterGranularity); 673 DirectionForward, CharacterGranularity);
666 } 674 }
667 } 675 }
668 } 676 }
669 677
670 void SpellChecker::updateMarkersForWordsAffectedByEditing( 678 void SpellChecker::updateMarkersForWordsAffectedByEditing(
671 bool doNotRemoveIfSelectionAtWordBoundary) { 679 bool doNotRemoveIfSelectionAtWordBoundary) {
672 DCHECK(frame().selection().isAvailable()); 680 DCHECK(frame().selection().isAvailable());
673 TRACE_EVENT0("blink", "SpellChecker::updateMarkersForWordsAffectedByEditing"); 681 TRACE_EVENT0("blink", "SpellChecker::updateMarkersForWordsAffectedByEditing");
674 if (!isSpellCheckingEnabledFor(frame().selection().selection())) 682 if (!isSpellCheckingEnabledFor(frame().selection().selection()))
675 return; 683 return;
676 684
677 Document* document = frame().document(); 685 Document* document = frame().document();
678 DCHECK(document); 686 DCHECK(document);
679 687
680 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets 688 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
681 // needs to be audited. See http://crbug.com/590369 for more details. 689 // needs to be audited. See http://crbug.com/590369 for more details.
682 document->updateStyleAndLayoutIgnorePendingStylesheets(); 690 document->updateStyleAndLayoutIgnorePendingStylesheets();
683 691
684 // We want to remove the markers from a word if an editing command will change the word. This can happen in one of 692 // We want to remove the markers from a word if an editing command will change
685 // several scenarios: 693 // the word. This can happen in one of several scenarios:
686 // 1. Insert in the middle of a word. 694 // 1. Insert in the middle of a word.
687 // 2. Appending non whitespace at the beginning of word. 695 // 2. Appending non whitespace at the beginning of word.
688 // 3. Appending non whitespace at the end of word. 696 // 3. Appending non whitespace at the end of word.
689 // Note that, appending only whitespaces at the beginning or end of word won't change the word, so we don't need to 697 // Note that, appending only whitespaces at the beginning or end of word won't
690 // remove the markers on that word. 698 // change the word, so we don't need to remove the markers on that word. Of
691 // Of course, if current selection is a range, we potentially will edit two wo rds that fall on the boundaries of 699 // course, if current selection is a range, we potentially will edit two words
692 // selection, and remove words between the selection boundaries. 700 // that fall on the boundaries of selection, and remove words between the
693 // 701 // selection boundaries.
694 VisiblePosition startOfSelection = 702 VisiblePosition startOfSelection =
695 frame().selection().selection().visibleStart(); 703 frame().selection().selection().visibleStart();
696 VisiblePosition endOfSelection = frame().selection().selection().visibleEnd(); 704 VisiblePosition endOfSelection = frame().selection().selection().visibleEnd();
697 if (startOfSelection.isNull()) 705 if (startOfSelection.isNull())
698 return; 706 return;
699 // First word is the word that ends after or on the start of selection. 707 // First word is the word that ends after or on the start of selection.
700 VisiblePosition startOfFirstWord = 708 VisiblePosition startOfFirstWord =
701 startOfWord(startOfSelection, LeftWordIfOnBoundary); 709 startOfWord(startOfSelection, LeftWordIfOnBoundary);
702 VisiblePosition endOfFirstWord = 710 VisiblePosition endOfFirstWord =
703 endOfWord(startOfSelection, LeftWordIfOnBoundary); 711 endOfWord(startOfSelection, LeftWordIfOnBoundary);
704 // Last word is the word that begins before or on the end of selection 712 // Last word is the word that begins before or on the end of selection
705 VisiblePosition startOfLastWord = 713 VisiblePosition startOfLastWord =
706 startOfWord(endOfSelection, RightWordIfOnBoundary); 714 startOfWord(endOfSelection, RightWordIfOnBoundary);
707 VisiblePosition endOfLastWord = 715 VisiblePosition endOfLastWord =
708 endOfWord(endOfSelection, RightWordIfOnBoundary); 716 endOfWord(endOfSelection, RightWordIfOnBoundary);
709 717
710 if (startOfFirstWord.isNull()) { 718 if (startOfFirstWord.isNull()) {
711 startOfFirstWord = startOfWord(startOfSelection, RightWordIfOnBoundary); 719 startOfFirstWord = startOfWord(startOfSelection, RightWordIfOnBoundary);
712 endOfFirstWord = endOfWord(startOfSelection, RightWordIfOnBoundary); 720 endOfFirstWord = endOfWord(startOfSelection, RightWordIfOnBoundary);
713 } 721 }
714 722
715 if (endOfLastWord.isNull()) { 723 if (endOfLastWord.isNull()) {
716 startOfLastWord = startOfWord(endOfSelection, LeftWordIfOnBoundary); 724 startOfLastWord = startOfWord(endOfSelection, LeftWordIfOnBoundary);
717 endOfLastWord = endOfWord(endOfSelection, LeftWordIfOnBoundary); 725 endOfLastWord = endOfWord(endOfSelection, LeftWordIfOnBoundary);
718 } 726 }
719 727
720 // If doNotRemoveIfSelectionAtWordBoundary is true, and first word ends at the start of selection, 728 // If doNotRemoveIfSelectionAtWordBoundary is true, and first word ends at the
721 // we choose next word as the first word. 729 // start of selection, we choose next word as the first word.
722 if (doNotRemoveIfSelectionAtWordBoundary && 730 if (doNotRemoveIfSelectionAtWordBoundary &&
723 endOfFirstWord.deepEquivalent() == startOfSelection.deepEquivalent()) { 731 endOfFirstWord.deepEquivalent() == startOfSelection.deepEquivalent()) {
724 startOfFirstWord = nextWordPosition(startOfFirstWord); 732 startOfFirstWord = nextWordPosition(startOfFirstWord);
725 endOfFirstWord = endOfWord(startOfFirstWord, RightWordIfOnBoundary); 733 endOfFirstWord = endOfWord(startOfFirstWord, RightWordIfOnBoundary);
726 if (startOfFirstWord.deepEquivalent() == endOfSelection.deepEquivalent()) 734 if (startOfFirstWord.deepEquivalent() == endOfSelection.deepEquivalent())
727 return; 735 return;
728 } 736 }
729 737
730 // If doNotRemoveIfSelectionAtWordBoundary is true, and last word begins at th e end of selection, 738 // If doNotRemoveIfSelectionAtWordBoundary is true, and last word begins at
731 // we choose previous word as the last word. 739 // the end of selection, we choose previous word as the last word.
732 if (doNotRemoveIfSelectionAtWordBoundary && 740 if (doNotRemoveIfSelectionAtWordBoundary &&
733 startOfLastWord.deepEquivalent() == endOfSelection.deepEquivalent()) { 741 startOfLastWord.deepEquivalent() == endOfSelection.deepEquivalent()) {
734 startOfLastWord = previousWordPosition(startOfLastWord); 742 startOfLastWord = previousWordPosition(startOfLastWord);
735 endOfLastWord = endOfWord(startOfLastWord, RightWordIfOnBoundary); 743 endOfLastWord = endOfWord(startOfLastWord, RightWordIfOnBoundary);
736 if (endOfLastWord.deepEquivalent() == startOfSelection.deepEquivalent()) 744 if (endOfLastWord.deepEquivalent() == startOfSelection.deepEquivalent())
737 return; 745 return;
738 } 746 }
739 747
740 if (startOfFirstWord.isNull() || endOfFirstWord.isNull() || 748 if (startOfFirstWord.isNull() || endOfFirstWord.isNull() ||
741 startOfLastWord.isNull() || endOfLastWord.isNull()) 749 startOfLastWord.isNull() || endOfLastWord.isNull())
742 return; 750 return;
743 751
744 const Position& removeMarkerStart = startOfFirstWord.deepEquivalent(); 752 const Position& removeMarkerStart = startOfFirstWord.deepEquivalent();
745 const Position& removeMarkerEnd = endOfLastWord.deepEquivalent(); 753 const Position& removeMarkerEnd = endOfLastWord.deepEquivalent();
746 if (removeMarkerStart > removeMarkerEnd) { 754 if (removeMarkerStart > removeMarkerEnd) {
747 // editing/inserting/insert-br-008.html and more reach here. 755 // editing/inserting/insert-br-008.html and more reach here.
748 // TODO(yosin): To avoid |DCHECK(removeMarkerStart <= removeMarkerEnd)| 756 // TODO(yosin): To avoid |DCHECK(removeMarkerStart <= removeMarkerEnd)|
749 // in |EphemeralRange| constructor, we have this if-statement. Once we 757 // in |EphemeralRange| constructor, we have this if-statement. Once we
750 // fix |startOfWord()| and |endOfWord()|, we should remove this 758 // fix |startOfWord()| and |endOfWord()|, we should remove this
751 // if-statement. 759 // if-statement.
752 return; 760 return;
753 } 761 }
754 762
755 // Now we remove markers on everything between startOfFirstWord and endOfLastW ord. 763 // Now we remove markers on everything between startOfFirstWord and
756 // However, if an autocorrection change a single word to multiple words, we wa nt to remove correction mark from all the 764 // endOfLastWord. However, if an autocorrection change a single word to
757 // resulted words even we only edit one of them. For example, assuming autocor rection changes "avantgarde" to "avant 765 // multiple words, we want to remove correction mark from all the resulted
758 // garde", we will have CorrectionIndicator marker on both words and on the wh itespace between them. If we then edit garde, 766 // words even we only edit one of them. For example, assuming autocorrection
759 // we would like to remove the marker from word "avant" and whitespace as well . So we need to get the continous range of 767 // changes "avantgarde" to "avant garde", we will have CorrectionIndicator
760 // of marker that contains the word in question, and remove marker on that who le range. 768 // marker on both words and on the whitespace between them. If we then edit
769 // garde, we would like to remove the marker from word "avant" and whitespace
770 // as well. So we need to get the continous range of of marker that contains
771 // the word in question, and remove marker on that whole range.
761 const EphemeralRange wordRange(removeMarkerStart, removeMarkerEnd); 772 const EphemeralRange wordRange(removeMarkerStart, removeMarkerEnd);
762 document->markers().removeMarkers( 773 document->markers().removeMarkers(
763 wordRange, DocumentMarker::MisspellingMarkers(), 774 wordRange, DocumentMarker::MisspellingMarkers(),
764 DocumentMarkerController::RemovePartiallyOverlappingMarker); 775 DocumentMarkerController::RemovePartiallyOverlappingMarker);
765 } 776 }
766 777
767 void SpellChecker::didEndEditingOnTextField(Element* e) { 778 void SpellChecker::didEndEditingOnTextField(Element* e) {
768 TRACE_EVENT0("blink", "SpellChecker::didEndEditingOnTextField"); 779 TRACE_EVENT0("blink", "SpellChecker::didEndEditingOnTextField");
769 780
770 // Remove markers when deactivating a selection in an <input type="text"/>. 781 // Remove markers when deactivating a selection in an <input type="text"/>.
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
825 return oldSelection.isContentEditable(); 836 return oldSelection.isContentEditable();
826 } 837 }
827 838
828 void SpellChecker::respondToChangedSelection( 839 void SpellChecker::respondToChangedSelection(
829 const VisibleSelection& oldSelection, 840 const VisibleSelection& oldSelection,
830 FrameSelection::SetSelectionOptions options) { 841 FrameSelection::SetSelectionOptions options) {
831 TRACE_EVENT0("blink", "SpellChecker::respondToChangedSelection"); 842 TRACE_EVENT0("blink", "SpellChecker::respondToChangedSelection");
832 if (!isSpellCheckingEnabledFor(oldSelection)) 843 if (!isSpellCheckingEnabledFor(oldSelection))
833 return; 844 return;
834 845
835 // When spell checking is off, existing markers disappear after the selection changes. 846 // When spell checking is off, existing markers disappear after the selection
847 // changes.
836 if (!isSpellCheckingEnabled()) { 848 if (!isSpellCheckingEnabled()) {
837 frame().document()->markers().removeMarkers(DocumentMarker::Spelling); 849 frame().document()->markers().removeMarkers(DocumentMarker::Spelling);
838 frame().document()->markers().removeMarkers(DocumentMarker::Grammar); 850 frame().document()->markers().removeMarkers(DocumentMarker::Grammar);
839 return; 851 return;
840 } 852 }
841 853
842 if (!(options & FrameSelection::CloseTyping)) 854 if (!(options & FrameSelection::CloseTyping))
843 return; 855 return;
844 if (!shouldCheckOldSelection(oldSelection)) 856 if (!shouldCheckOldSelection(oldSelection))
845 return; 857 return;
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
1045 } 1057 }
1046 wordStart = wordEnd; 1058 wordStart = wordEnd;
1047 } 1059 }
1048 return results; 1060 return results;
1049 } 1061 }
1050 1062
1051 std::pair<String, int> SpellChecker::findFirstMisspelling(const Position& start, 1063 std::pair<String, int> SpellChecker::findFirstMisspelling(const Position& start,
1052 const Position& end) { 1064 const Position& end) {
1053 String misspelledWord; 1065 String misspelledWord;
1054 1066
1055 // Initialize out parameters; they will be updated if we find something to ret urn. 1067 // Initialize out parameters; they will be updated if we find something to
1068 // return.
1056 String firstFoundItem; 1069 String firstFoundItem;
1057 int firstFoundOffset = 0; 1070 int firstFoundOffset = 0;
1058 1071
1059 // Expand the search range to encompass entire paragraphs, since text checking needs that much context. 1072 // Expand the search range to encompass entire paragraphs, since text checking
1060 // Determine the character offset from the start of the paragraph to the start of the original search range, 1073 // needs that much context. Determine the character offset from the start of
1061 // since we will want to ignore results in this area. 1074 // the paragraph to the start of the original search range, since we will want
1075 // to ignore results in this area.
1062 Position paragraphStart = 1076 Position paragraphStart =
1063 startOfParagraph(createVisiblePosition(start)).toParentAnchoredPosition(); 1077 startOfParagraph(createVisiblePosition(start)).toParentAnchoredPosition();
1064 Position paragraphEnd = end; 1078 Position paragraphEnd = end;
1065 int totalRangeLength = 1079 int totalRangeLength =
1066 TextIterator::rangeLength(paragraphStart, paragraphEnd); 1080 TextIterator::rangeLength(paragraphStart, paragraphEnd);
1067 paragraphEnd = 1081 paragraphEnd =
1068 endOfParagraph(createVisiblePosition(start)).toParentAnchoredPosition(); 1082 endOfParagraph(createVisiblePosition(start)).toParentAnchoredPosition();
1069 1083
1070 int rangeStartOffset = TextIterator::rangeLength(paragraphStart, start); 1084 int rangeStartOffset = TextIterator::rangeLength(paragraphStart, start);
1071 int totalLengthProcessed = 0; 1085 int totalLengthProcessed = 0;
1072 1086
1073 bool firstIteration = true; 1087 bool firstIteration = true;
1074 bool lastIteration = false; 1088 bool lastIteration = false;
1075 while (totalLengthProcessed < totalRangeLength) { 1089 while (totalLengthProcessed < totalRangeLength) {
1076 // Iterate through the search range by paragraphs, checking each one for spe lling. 1090 // Iterate through the search range by paragraphs, checking each one for
1091 // spelling.
1077 int currentLength = TextIterator::rangeLength(paragraphStart, paragraphEnd); 1092 int currentLength = TextIterator::rangeLength(paragraphStart, paragraphEnd);
1078 int currentStartOffset = firstIteration ? rangeStartOffset : 0; 1093 int currentStartOffset = firstIteration ? rangeStartOffset : 0;
1079 int currentEndOffset = currentLength; 1094 int currentEndOffset = currentLength;
1080 if (inSameParagraph(createVisiblePosition(paragraphStart), 1095 if (inSameParagraph(createVisiblePosition(paragraphStart),
1081 createVisiblePosition(end))) { 1096 createVisiblePosition(end))) {
1082 // Determine the character offset from the end of the original search rang e to the end of the paragraph, 1097 // Determine the character offset from the end of the original search
1083 // since we will want to ignore results in this area. 1098 // range to the end of the paragraph, since we will want to ignore results
1099 // in this area.
1084 currentEndOffset = TextIterator::rangeLength(paragraphStart, end); 1100 currentEndOffset = TextIterator::rangeLength(paragraphStart, end);
1085 lastIteration = true; 1101 lastIteration = true;
1086 } 1102 }
1087 if (currentStartOffset < currentEndOffset) { 1103 if (currentStartOffset < currentEndOffset) {
1088 String paragraphString = 1104 String paragraphString =
1089 plainText(EphemeralRange(paragraphStart, paragraphEnd)); 1105 plainText(EphemeralRange(paragraphStart, paragraphEnd));
1090 if (paragraphString.length() > 0) { 1106 if (paragraphString.length() > 0) {
1091 int spellingLocation = 0; 1107 int spellingLocation = 0;
1092 1108
1093 Vector<TextCheckingResult> results = findMisspellings(paragraphString); 1109 Vector<TextCheckingResult> results = findMisspellings(paragraphString);
(...skipping 29 matching lines...) Expand all
1123 startOfNextParagraph(createVisiblePosition(paragraphEnd)); 1139 startOfNextParagraph(createVisiblePosition(paragraphEnd));
1124 paragraphStart = newParagraphStart.toParentAnchoredPosition(); 1140 paragraphStart = newParagraphStart.toParentAnchoredPosition();
1125 paragraphEnd = endOfParagraph(newParagraphStart).toParentAnchoredPosition(); 1141 paragraphEnd = endOfParagraph(newParagraphStart).toParentAnchoredPosition();
1126 firstIteration = false; 1142 firstIteration = false;
1127 totalLengthProcessed += currentLength; 1143 totalLengthProcessed += currentLength;
1128 } 1144 }
1129 return std::make_pair(firstFoundItem, firstFoundOffset); 1145 return std::make_pair(firstFoundItem, firstFoundOffset);
1130 } 1146 }
1131 1147
1132 } // namespace blink 1148 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/editing/spellcheck/SpellCheckRequester.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698