| 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 499 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 510 if (fullParagraphToCheck.isEmpty()) | 510 if (fullParagraphToCheck.isEmpty()) |
| 511 return; | 511 return; |
| 512 const EphemeralRange& paragraphRange = fullParagraphToCheck.paragraphRange()
; | 512 const EphemeralRange& paragraphRange = fullParagraphToCheck.paragraphRange()
; |
| 513 | 513 |
| 514 // Since the text may be quite big chunk it up and adjust to the sentence bo
undary. | 514 // Since the text may be quite big chunk it up and adjust to the sentence bo
undary. |
| 515 const int kChunkSize = 16 * 1024; | 515 const int kChunkSize = 16 * 1024; |
| 516 | 516 |
| 517 // Check the full paragraph instead if the paragraph is short, which saves | 517 // Check the full paragraph instead if the paragraph is short, which saves |
| 518 // the cost on sentence boundary finding. | 518 // the cost on sentence boundary finding. |
| 519 if (fullParagraphToCheck.rangeLength() <= kChunkSize) { | 519 if (fullParagraphToCheck.rangeLength() <= kChunkSize) { |
| 520 SpellCheckRequest* request = SpellCheckRequest::create(TextCheckingTypeS
pelling | TextCheckingTypeGrammar, TextCheckingProcessBatch, paragraphRange, par
agraphRange, 0); | 520 SpellCheckRequest* request = SpellCheckRequest::create(TextCheckingProce
ssBatch, paragraphRange, paragraphRange, 0); |
| 521 if (request) | 521 if (request) |
| 522 m_spellCheckRequester->requestCheckingFor(request); | 522 m_spellCheckRequester->requestCheckingFor(request); |
| 523 return; | 523 return; |
| 524 } | 524 } |
| 525 | 525 |
| 526 CharacterIterator checkRangeIterator(fullParagraphToCheck.checkingRange(), T
extIteratorEmitsObjectReplacementCharacter); | 526 CharacterIterator checkRangeIterator(fullParagraphToCheck.checkingRange(), T
extIteratorEmitsObjectReplacementCharacter); |
| 527 for (int requestNum = 0; !checkRangeIterator.atEnd(); requestNum++) { | 527 for (int requestNum = 0; !checkRangeIterator.atEnd(); requestNum++) { |
| 528 EphemeralRange chunkRange = checkRangeIterator.calculateCharacterSubrang
e(0, kChunkSize); | 528 EphemeralRange chunkRange = checkRangeIterator.calculateCharacterSubrang
e(0, kChunkSize); |
| 529 EphemeralRange checkRange = requestNum ? expandEndToSentenceBoundary(chu
nkRange) : expandRangeToSentenceBoundary(chunkRange); | 529 EphemeralRange checkRange = requestNum ? expandEndToSentenceBoundary(chu
nkRange) : expandRangeToSentenceBoundary(chunkRange); |
| 530 | 530 |
| 531 SpellCheckRequest* request = SpellCheckRequest::create(TextCheckingTypeS
pelling | TextCheckingTypeGrammar, TextCheckingProcessBatch, checkRange, paragra
phRange, requestNum); | 531 SpellCheckRequest* request = SpellCheckRequest::create(TextCheckingProce
ssBatch, checkRange, paragraphRange, requestNum); |
| 532 if (request) | 532 if (request) |
| 533 m_spellCheckRequester->requestCheckingFor(request); | 533 m_spellCheckRequester->requestCheckingFor(request); |
| 534 | 534 |
| 535 if (!checkRangeIterator.atEnd()) { | 535 if (!checkRangeIterator.atEnd()) { |
| 536 checkRangeIterator.advance(1); | 536 checkRangeIterator.advance(1); |
| 537 // The layout should be already update due to the initialization of
checkRangeIterator, | 537 // The layout should be already update due to the initialization of
checkRangeIterator, |
| 538 // so comparePositions can be directly called. | 538 // so comparePositions can be directly called. |
| 539 if (comparePositions(chunkRange.endPosition(), checkRange.endPositio
n()) < 0) | 539 if (comparePositions(chunkRange.endPosition(), checkRange.endPositio
n()) < 0) |
| 540 checkRangeIterator.advance(TextIterator::rangeLength(chunkRange.
endPosition(), checkRange.endPosition())); | 540 checkRangeIterator.advance(TextIterator::rangeLength(chunkRange.
endPosition(), checkRange.endPosition())); |
| 541 } | 541 } |
| 542 } | 542 } |
| 543 } | 543 } |
| 544 | 544 |
| 545 void SpellChecker::markAndReplaceFor(SpellCheckRequest* request, const Vector<Te
xtCheckingResult>& results) | 545 void SpellChecker::markAndReplaceFor(SpellCheckRequest* request, const Vector<Te
xtCheckingResult>& results) |
| 546 { | 546 { |
| 547 TRACE_EVENT0("blink", "SpellChecker::markAndReplaceFor"); | 547 TRACE_EVENT0("blink", "SpellChecker::markAndReplaceFor"); |
| 548 DCHECK(request); | 548 DCHECK(request); |
| 549 if (!frame().selection().isAvailable()) { | 549 if (!frame().selection().isAvailable()) { |
| 550 // "editing/spelling/spellcheck-async-remove-frame.html" reaches here. | 550 // "editing/spelling/spellcheck-async-remove-frame.html" reaches here. |
| 551 return; | 551 return; |
| 552 } | 552 } |
| 553 if (!request->isValid()) | 553 if (!request->isValid()) |
| 554 return; | 554 return; |
| 555 if (request->rootEditableElement()->document() != frame().selection().docume
nt()) { | 555 if (request->rootEditableElement()->document() != frame().selection().docume
nt()) { |
| 556 // we ignore |request| made for another document. | 556 // we ignore |request| made for another document. |
| 557 // "editing/spelling/spellcheck-sequencenum.html" and others reach here. | 557 // "editing/spelling/spellcheck-sequencenum.html" and others reach here. |
| 558 return; | 558 return; |
| 559 } | 559 } |
| 560 | 560 |
| 561 TextCheckingTypeMask textCheckingOptions = request->data().mask(); | |
| 562 TextCheckingParagraph paragraph(request->checkingRange(), request->paragraph
Range()); | 561 TextCheckingParagraph paragraph(request->checkingRange(), request->paragraph
Range()); |
| 563 | 562 |
| 564 bool shouldMarkSpelling = textCheckingOptions & TextCheckingTypeSpelling; | |
| 565 bool shouldMarkGrammar = textCheckingOptions & TextCheckingTypeGrammar; | |
| 566 | |
| 567 // Expand the range to encompass entire paragraphs, since text checking need
s that much context. | 563 // Expand the range to encompass entire paragraphs, since text checking need
s that much context. |
| 568 int selectionOffset = 0; | 564 int selectionOffset = 0; |
| 569 int ambiguousBoundaryOffset = -1; | 565 int ambiguousBoundaryOffset = -1; |
| 570 bool selectionChanged = false; | 566 bool selectionChanged = false; |
| 571 bool restoreSelectionAfterChange = false; | 567 bool restoreSelectionAfterChange = false; |
| 572 bool adjustSelectionForParagraphBoundaries = false; | 568 bool adjustSelectionForParagraphBoundaries = false; |
| 573 | 569 |
| 574 if (shouldMarkSpelling) { | 570 if (frame().selection().isCaret()) { |
| 575 if (frame().selection().isCaret()) { | 571 // Attempt to save the caret position so we can restore it later if need
ed |
| 576 // Attempt to save the caret position so we can restore it later if
needed | 572 Position caretPosition = frame().selection().end(); |
| 577 Position caretPosition = frame().selection().end(); | 573 selectionOffset = paragraph.offsetTo(caretPosition); |
| 578 selectionOffset = paragraph.offsetTo(caretPosition); | 574 restoreSelectionAfterChange = true; |
| 579 restoreSelectionAfterChange = true; | 575 if (selectionOffset > 0 && (static_cast<unsigned>(selectionOffset) > par
agraph.text().length() || paragraph.textCharAt(selectionOffset - 1) == newlineCh
aracter)) |
| 580 if (selectionOffset > 0 && (static_cast<unsigned>(selectionOffset) >
paragraph.text().length() || paragraph.textCharAt(selectionOffset - 1) == newli
neCharacter)) | 576 adjustSelectionForParagraphBoundaries = true; |
| 581 adjustSelectionForParagraphBoundaries = true; | 577 if (selectionOffset > 0 && static_cast<unsigned>(selectionOffset) <= par
agraph.text().length() && isAmbiguousBoundaryCharacter(paragraph.textCharAt(sele
ctionOffset - 1))) |
| 582 if (selectionOffset > 0 && static_cast<unsigned>(selectionOffset) <=
paragraph.text().length() && isAmbiguousBoundaryCharacter(paragraph.textCharAt(
selectionOffset - 1))) | 578 ambiguousBoundaryOffset = selectionOffset - 1; |
| 583 ambiguousBoundaryOffset = selectionOffset - 1; | |
| 584 } | |
| 585 } | 579 } |
| 586 | 580 |
| 587 // TODO(dglazkov): The use of updateStyleAndLayoutIgnorePendingStylesheets n
eeds to be audited. | 581 // TODO(dglazkov): The use of updateStyleAndLayoutIgnorePendingStylesheets n
eeds to be audited. |
| 588 // see http://crbug.com/590369 for more details. | 582 // see http://crbug.com/590369 for more details. |
| 589 frame().document()->updateStyleAndLayoutIgnorePendingStylesheets(); | 583 frame().document()->updateStyleAndLayoutIgnorePendingStylesheets(); |
| 590 | 584 |
| 591 { | 585 { |
| 592 DocumentLifecycle::DisallowTransitionScope(frame().document()->lifecycle
()); | 586 DocumentLifecycle::DisallowTransitionScope(frame().document()->lifecycle
()); |
| 593 | 587 |
| 594 for (unsigned i = 0; i < results.size(); i++) { | 588 for (unsigned i = 0; i < results.size(); i++) { |
| 595 int spellingRangeEndOffset = paragraph.checkingEnd(); | 589 int spellingRangeEndOffset = paragraph.checkingEnd(); |
| 596 const TextCheckingResult* result = &results[i]; | 590 const TextCheckingResult* result = &results[i]; |
| 597 int resultLocation = result->location + paragraph.checkingStart(); | 591 int resultLocation = result->location + paragraph.checkingStart(); |
| 598 int resultLength = result->length; | 592 int resultLength = result->length; |
| 599 bool resultEndsAtAmbiguousBoundary = ambiguousBoundaryOffset >= 0 &&
resultLocation + resultLength == ambiguousBoundaryOffset; | 593 bool resultEndsAtAmbiguousBoundary = ambiguousBoundaryOffset >= 0 &&
resultLocation + resultLength == ambiguousBoundaryOffset; |
| 600 | 594 |
| 601 // Only mark misspelling if: | 595 // Only mark misspelling if: |
| 602 // 1. Current text checking isn't done for autocorrection, in which
case shouldMarkSpelling is false. | 596 // 1. Current text checking isn't done for autocorrection. |
| 603 // 2. Result falls within spellingRange. | 597 // 2. Result falls within spellingRange. |
| 604 // 3. The word in question doesn't end at an ambiguous boundary. For
instance, we would not mark | 598 // 3. The word in question doesn't end at an ambiguous boundary. For
instance, we would not mark |
| 605 // "wouldn'" as misspelled right after apostrophe is typed. | 599 // "wouldn'" as misspelled right after apostrophe is typed. |
| 606 if (shouldMarkSpelling && result->decoration == TextDecorationTypeSp
elling && resultLocation >= paragraph.checkingStart() && resultLocation + result
Length <= spellingRangeEndOffset && !resultEndsAtAmbiguousBoundary) { | 600 if (result->decoration == TextDecorationTypeSpelling && resultLocati
on >= paragraph.checkingStart() && resultLocation + resultLength <= spellingRang
eEndOffset && !resultEndsAtAmbiguousBoundary) { |
| 607 DCHECK_GT(resultLength, 0); | 601 DCHECK_GT(resultLength, 0); |
| 608 DCHECK_GE(resultLocation, 0); | 602 DCHECK_GE(resultLocation, 0); |
| 609 const EphemeralRange misspellingRange = calculateCharacterSubran
ge(paragraph.paragraphRange(), resultLocation, resultLength); | 603 const EphemeralRange misspellingRange = calculateCharacterSubran
ge(paragraph.paragraphRange(), resultLocation, resultLength); |
| 610 frame().document()->markers().addMarker(misspellingRange.startPo
sition(), misspellingRange.endPosition(), DocumentMarker::Spelling, result->repl
acement, result->hash); | 604 frame().document()->markers().addMarker(misspellingRange.startPo
sition(), misspellingRange.endPosition(), DocumentMarker::Spelling, result->repl
acement, result->hash); |
| 611 } else if (shouldMarkGrammar && result->decoration == TextDecoration
TypeGrammar && paragraph.checkingRangeCovers(resultLocation, resultLength)) { | 605 } else if (result->decoration == TextDecorationTypeGrammar && paragr
aph.checkingRangeCovers(resultLocation, resultLength)) { |
| 612 DCHECK_GT(resultLength, 0); | 606 DCHECK_GT(resultLength, 0); |
| 613 DCHECK_GE(resultLocation, 0); | 607 DCHECK_GE(resultLocation, 0); |
| 614 for (unsigned j = 0; j < result->details.size(); j++) { | 608 for (unsigned j = 0; j < result->details.size(); j++) { |
| 615 const GrammarDetail* detail = &result->details[j]; | 609 const GrammarDetail* detail = &result->details[j]; |
| 616 DCHECK_GT(detail->length, 0); | 610 DCHECK_GT(detail->length, 0); |
| 617 DCHECK_GE(detail->location, 0); | 611 DCHECK_GE(detail->location, 0); |
| 618 if (paragraph.checkingRangeCovers(resultLocation + detail->l
ocation, detail->length)) { | 612 if (paragraph.checkingRangeCovers(resultLocation + detail->l
ocation, detail->length)) { |
| 619 const EphemeralRange badGrammarRange = calculateCharacte
rSubrange(paragraph.paragraphRange(), resultLocation + detail->location, detail-
>length); | 613 const EphemeralRange badGrammarRange = calculateCharacte
rSubrange(paragraph.paragraphRange(), resultLocation + detail->location, detail-
>length); |
| 620 frame().document()->markers().addMarker(badGrammarRange.
startPosition(), badGrammarRange.endPosition(), DocumentMarker::Grammar, detail-
>userDescription, result->hash); | 614 frame().document()->markers().addMarker(badGrammarRange.
startPosition(), badGrammarRange.endPosition(), DocumentMarker::Grammar, detail-
>userDescription, result->hash); |
| 621 } | 615 } |
| (...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 926 } | 920 } |
| 927 | 921 |
| 928 void SpellChecker::cancelCheck() | 922 void SpellChecker::cancelCheck() |
| 929 { | 923 { |
| 930 m_spellCheckRequester->cancelCheck(); | 924 m_spellCheckRequester->cancelCheck(); |
| 931 } | 925 } |
| 932 | 926 |
| 933 void SpellChecker::requestTextChecking(const Element& element) | 927 void SpellChecker::requestTextChecking(const Element& element) |
| 934 { | 928 { |
| 935 const EphemeralRange rangeToCheck = EphemeralRange::rangeOfContents(element)
; | 929 const EphemeralRange rangeToCheck = EphemeralRange::rangeOfContents(element)
; |
| 936 m_spellCheckRequester->requestCheckingFor(SpellCheckRequest::create(TextChec
kingTypeSpelling | TextCheckingTypeGrammar, TextCheckingProcessBatch, rangeToChe
ck, rangeToCheck)); | 930 m_spellCheckRequester->requestCheckingFor(SpellCheckRequest::create(TextChec
kingProcessBatch, rangeToCheck, rangeToCheck)); |
| 937 } | 931 } |
| 938 | 932 |
| 939 DEFINE_TRACE(SpellChecker) | 933 DEFINE_TRACE(SpellChecker) |
| 940 { | 934 { |
| 941 visitor->trace(m_frame); | 935 visitor->trace(m_frame); |
| 942 visitor->trace(m_spellCheckRequester); | 936 visitor->trace(m_spellCheckRequester); |
| 943 } | 937 } |
| 944 | 938 |
| 945 void SpellChecker::prepareForLeakDetection() | 939 void SpellChecker::prepareForLeakDetection() |
| 946 { | 940 { |
| 947 m_spellCheckRequester->prepareForLeakDetection(); | 941 m_spellCheckRequester->prepareForLeakDetection(); |
| 948 } | 942 } |
| 949 | 943 |
| 950 } // namespace blink | 944 } // namespace blink |
| OLD | NEW |