| 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 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 291 | 291 |
| 292 badGrammarPhrase = TextCheckingHelper(spellCheckerClient(), grammarS
earchStart, grammarSearchEnd).findFirstBadGrammar(grammarDetail, grammarPhraseOf
fset, false); | 292 badGrammarPhrase = TextCheckingHelper(spellCheckerClient(), grammarS
earchStart, grammarSearchEnd).findFirstBadGrammar(grammarDetail, grammarPhraseOf
fset, false); |
| 293 } | 293 } |
| 294 } | 294 } |
| 295 | 295 |
| 296 if (!badGrammarPhrase.isEmpty()) { | 296 if (!badGrammarPhrase.isEmpty()) { |
| 297 // We found bad grammar. Since we only searched for bad grammar up to th
e first misspelled word, the bad grammar | 297 // We found bad grammar. Since we only searched for bad grammar up to th
e first misspelled word, the bad grammar |
| 298 // takes precedence and we ignore any potential misspelled word. Select
the grammar detail, update the spelling | 298 // takes precedence and we ignore any potential misspelled word. Select
the grammar detail, update the spelling |
| 299 // panel, and store a marker so we draw the green squiggle later. | 299 // panel, and store a marker so we draw the green squiggle later. |
| 300 | 300 |
| 301 ASSERT(badGrammarPhrase.length() > 0); | 301 DCHECK_GT(badGrammarPhrase.length(), 0u); |
| 302 ASSERT(grammarDetail.location != -1 && grammarDetail.length > 0); | 302 DCHECK_NE(grammarDetail.location, -1); |
| 303 DCHECK_GT(grammarDetail.length, 0); |
| 303 | 304 |
| 304 // FIXME 4859190: This gets confused with doubled punctuation at the end
of a paragraph | 305 // FIXME 4859190: This gets confused with doubled punctuation at the end
of a paragraph |
| 305 const EphemeralRange badGrammarRange = calculateCharacterSubrange(Epheme
ralRange(grammarSearchStart, grammarSearchEnd), grammarPhraseOffset + grammarDet
ail.location, grammarDetail.length); | 306 const EphemeralRange badGrammarRange = calculateCharacterSubrange(Epheme
ralRange(grammarSearchStart, grammarSearchEnd), grammarPhraseOffset + grammarDet
ail.location, grammarDetail.length); |
| 306 frame().selection().setSelection(VisibleSelection(badGrammarRange)); | 307 frame().selection().setSelection(VisibleSelection(badGrammarRange)); |
| 307 frame().selection().revealSelection(); | 308 frame().selection().revealSelection(); |
| 308 | 309 |
| 309 frame().document()->markers().addMarker(badGrammarRange.startPosition(),
badGrammarRange.endPosition(), DocumentMarker::Grammar, grammarDetail.userDescr
iption); | 310 frame().document()->markers().addMarker(badGrammarRange.startPosition(),
badGrammarRange.endPosition(), DocumentMarker::Grammar, grammarDetail.userDescr
iption); |
| 310 } else if (!misspelledWord.isEmpty()) { | 311 } else if (!misspelledWord.isEmpty()) { |
| 311 // We found a misspelling, but not any earlier bad grammar. Select the m
isspelling, update the spelling panel, and store | 312 // We found a misspelling, but not any earlier bad grammar. Select the m
isspelling, update the spelling panel, and store |
| 312 // a marker so we draw the red squiggle later. | 313 // a marker so we draw the red squiggle later. |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 471 return markMisspellingsOrBadGrammar(selection, true); | 472 return markMisspellingsOrBadGrammar(selection, true); |
| 472 } | 473 } |
| 473 | 474 |
| 474 void SpellChecker::markBadGrammar(const VisibleSelection& selection) | 475 void SpellChecker::markBadGrammar(const VisibleSelection& selection) |
| 475 { | 476 { |
| 476 markMisspellingsOrBadGrammar(selection, false); | 477 markMisspellingsOrBadGrammar(selection, false); |
| 477 } | 478 } |
| 478 | 479 |
| 479 void SpellChecker::markAllMisspellingsAndBadGrammarInRanges(TextCheckingTypeMask
textCheckingOptions, const EphemeralRange& spellingRange, const EphemeralRange&
grammarRange) | 480 void SpellChecker::markAllMisspellingsAndBadGrammarInRanges(TextCheckingTypeMask
textCheckingOptions, const EphemeralRange& spellingRange, const EphemeralRange&
grammarRange) |
| 480 { | 481 { |
| 481 ASSERT(unifiedTextCheckerEnabled()); | 482 DCHECK(unifiedTextCheckerEnabled()); |
| 482 | 483 |
| 483 bool shouldMarkGrammar = textCheckingOptions & TextCheckingTypeGrammar; | 484 bool shouldMarkGrammar = textCheckingOptions & TextCheckingTypeGrammar; |
| 484 | 485 |
| 485 // This function is called with selections already expanded to word boundari
es. | 486 // This function is called with selections already expanded to word boundari
es. |
| 486 if (spellingRange.isNull() || (shouldMarkGrammar && grammarRange.isNull())) | 487 if (spellingRange.isNull() || (shouldMarkGrammar && grammarRange.isNull())) |
| 487 return; | 488 return; |
| 488 | 489 |
| 489 // If we're not in an editable node, bail. | 490 // If we're not in an editable node, bail. |
| 490 Node* editableNode = spellingRange.startPosition().computeContainerNode(); | 491 Node* editableNode = spellingRange.startPosition().computeContainerNode(); |
| 491 if (!editableNode || !editableNode->hasEditableStyle()) | 492 if (!editableNode || !editableNode->hasEditableStyle()) |
| 492 return; | 493 return; |
| 493 | 494 |
| 494 if (!isSpellCheckingEnabledFor(editableNode)) | 495 if (!isSpellCheckingEnabledFor(editableNode)) |
| 495 return; | 496 return; |
| 496 | 497 |
| 497 TextCheckingParagraph fullParagraphToCheck(shouldMarkGrammar ? grammarRange
: spellingRange); | 498 TextCheckingParagraph fullParagraphToCheck(shouldMarkGrammar ? grammarRange
: spellingRange); |
| 498 chunkAndMarkAllMisspellingsAndBadGrammar(textCheckingOptions, fullParagraphT
oCheck); | 499 chunkAndMarkAllMisspellingsAndBadGrammar(textCheckingOptions, fullParagraphT
oCheck); |
| 499 } | 500 } |
| 500 | 501 |
| 501 static EphemeralRange expandEndToSentenceBoundary(const EphemeralRange& range) | 502 static EphemeralRange expandEndToSentenceBoundary(const EphemeralRange& range) |
| 502 { | 503 { |
| 503 ASSERT(range.isNotNull()); | 504 DCHECK(range.isNotNull()); |
| 504 const VisiblePosition& visibleEnd = createVisiblePosition(range.endPosition(
)); | 505 const VisiblePosition& visibleEnd = createVisiblePosition(range.endPosition(
)); |
| 505 ASSERT(visibleEnd.isNotNull()); | 506 DCHECK(visibleEnd.isNotNull()); |
| 506 const Position& sentenceEnd = endOfSentence(visibleEnd).deepEquivalent(); | 507 const Position& sentenceEnd = endOfSentence(visibleEnd).deepEquivalent(); |
| 507 return EphemeralRange(range.startPosition(), sentenceEnd.isNotNull() ? sente
nceEnd : range.endPosition()); | 508 return EphemeralRange(range.startPosition(), sentenceEnd.isNotNull() ? sente
nceEnd : range.endPosition()); |
| 508 } | 509 } |
| 509 | 510 |
| 510 static EphemeralRange expandRangeToSentenceBoundary(const EphemeralRange& range) | 511 static EphemeralRange expandRangeToSentenceBoundary(const EphemeralRange& range) |
| 511 { | 512 { |
| 512 ASSERT(range.isNotNull()); | 513 DCHECK(range.isNotNull()); |
| 513 const VisiblePosition& visibleStart = createVisiblePosition(range.startPosit
ion()); | 514 const VisiblePosition& visibleStart = createVisiblePosition(range.startPosit
ion()); |
| 514 ASSERT(visibleStart.isNotNull()); | 515 DCHECK(visibleStart.isNotNull()); |
| 515 const Position& sentenceStart = startOfSentence(visibleStart).deepEquivalent
(); | 516 const Position& sentenceStart = startOfSentence(visibleStart).deepEquivalent
(); |
| 516 return expandEndToSentenceBoundary(EphemeralRange(sentenceStart.isNull() ? r
ange.startPosition() : sentenceStart, range.endPosition())); | 517 return expandEndToSentenceBoundary(EphemeralRange(sentenceStart.isNull() ? r
ange.startPosition() : sentenceStart, range.endPosition())); |
| 517 } | 518 } |
| 518 | 519 |
| 519 void SpellChecker::chunkAndMarkAllMisspellingsAndBadGrammar(Node* node, const Ep
hemeralRange& insertedRange) | 520 void SpellChecker::chunkAndMarkAllMisspellingsAndBadGrammar(Node* node, const Ep
hemeralRange& insertedRange) |
| 520 { | 521 { |
| 521 TRACE_EVENT0("blink", "SpellChecker::chunkAndMarkAllMisspellingsAndBadGramma
r"); | 522 TRACE_EVENT0("blink", "SpellChecker::chunkAndMarkAllMisspellingsAndBadGramma
r"); |
| 522 if (!node) | 523 if (!node) |
| 523 return; | 524 return; |
| 524 EphemeralRange paragraphRange(firstPositionInNode(node), lastPositionInNode(
node)); | 525 EphemeralRange paragraphRange(firstPositionInNode(node), lastPositionInNode(
node)); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 559 // so comparePositions can be directly called. | 560 // so comparePositions can be directly called. |
| 560 if (comparePositions(chunkRange.endPosition(), checkRange.endPositio
n()) < 0) | 561 if (comparePositions(chunkRange.endPosition(), checkRange.endPositio
n()) < 0) |
| 561 checkRangeIterator.advance(TextIterator::rangeLength(chunkRange.
endPosition(), checkRange.endPosition())); | 562 checkRangeIterator.advance(TextIterator::rangeLength(chunkRange.
endPosition(), checkRange.endPosition())); |
| 562 } | 563 } |
| 563 } | 564 } |
| 564 } | 565 } |
| 565 | 566 |
| 566 void SpellChecker::markAndReplaceFor(SpellCheckRequest* request, const Vector<Te
xtCheckingResult>& results) | 567 void SpellChecker::markAndReplaceFor(SpellCheckRequest* request, const Vector<Te
xtCheckingResult>& results) |
| 567 { | 568 { |
| 568 TRACE_EVENT0("blink", "SpellChecker::markAndReplaceFor"); | 569 TRACE_EVENT0("blink", "SpellChecker::markAndReplaceFor"); |
| 569 ASSERT(request); | 570 DCHECK(request); |
| 570 if (!request->isValid()) | 571 if (!request->isValid()) |
| 571 return; | 572 return; |
| 572 | 573 |
| 573 TextCheckingTypeMask textCheckingOptions = request->data().mask(); | 574 TextCheckingTypeMask textCheckingOptions = request->data().mask(); |
| 574 TextCheckingParagraph paragraph(request->checkingRange(), request->paragraph
Range()); | 575 TextCheckingParagraph paragraph(request->checkingRange(), request->paragraph
Range()); |
| 575 | 576 |
| 576 bool shouldMarkSpelling = textCheckingOptions & TextCheckingTypeSpelling; | 577 bool shouldMarkSpelling = textCheckingOptions & TextCheckingTypeSpelling; |
| 577 bool shouldMarkGrammar = textCheckingOptions & TextCheckingTypeGrammar; | 578 bool shouldMarkGrammar = textCheckingOptions & TextCheckingTypeGrammar; |
| 578 | 579 |
| 579 // Expand the range to encompass entire paragraphs, since text checking need
s that much context. | 580 // Expand the range to encompass entire paragraphs, since text checking need
s that much context. |
| (...skipping 22 matching lines...) Expand all Loading... |
| 602 int resultLocation = result->location + paragraph.checkingStart(); | 603 int resultLocation = result->location + paragraph.checkingStart(); |
| 603 int resultLength = result->length; | 604 int resultLength = result->length; |
| 604 bool resultEndsAtAmbiguousBoundary = ambiguousBoundaryOffset >= 0 && res
ultLocation + resultLength == ambiguousBoundaryOffset; | 605 bool resultEndsAtAmbiguousBoundary = ambiguousBoundaryOffset >= 0 && res
ultLocation + resultLength == ambiguousBoundaryOffset; |
| 605 | 606 |
| 606 // Only mark misspelling if: | 607 // Only mark misspelling if: |
| 607 // 1. Current text checking isn't done for autocorrection, in which case
shouldMarkSpelling is false. | 608 // 1. Current text checking isn't done for autocorrection, in which case
shouldMarkSpelling is false. |
| 608 // 2. Result falls within spellingRange. | 609 // 2. Result falls within spellingRange. |
| 609 // 3. The word in question doesn't end at an ambiguous boundary. For ins
tance, we would not mark | 610 // 3. The word in question doesn't end at an ambiguous boundary. For ins
tance, we would not mark |
| 610 // "wouldn'" as misspelled right after apostrophe is typed. | 611 // "wouldn'" as misspelled right after apostrophe is typed. |
| 611 if (shouldMarkSpelling && result->decoration == TextDecorationTypeSpelli
ng && resultLocation >= paragraph.checkingStart() && resultLocation + resultLeng
th <= spellingRangeEndOffset && !resultEndsAtAmbiguousBoundary) { | 612 if (shouldMarkSpelling && result->decoration == TextDecorationTypeSpelli
ng && resultLocation >= paragraph.checkingStart() && resultLocation + resultLeng
th <= spellingRangeEndOffset && !resultEndsAtAmbiguousBoundary) { |
| 612 ASSERT(resultLength > 0 && resultLocation >= 0); | 613 DCHECK_GT(resultLength, 0); |
| 614 DCHECK_GE(resultLocation, 0); |
| 613 const EphemeralRange misspellingRange = calculateCharacterSubrange(p
aragraph.paragraphRange(), resultLocation, resultLength); | 615 const EphemeralRange misspellingRange = calculateCharacterSubrange(p
aragraph.paragraphRange(), resultLocation, resultLength); |
| 614 frame().document()->markers().addMarker(misspellingRange.startPositi
on(), misspellingRange.endPosition(), DocumentMarker::Spelling, result->replacem
ent, result->hash); | 616 frame().document()->markers().addMarker(misspellingRange.startPositi
on(), misspellingRange.endPosition(), DocumentMarker::Spelling, result->replacem
ent, result->hash); |
| 615 } else if (shouldMarkGrammar && result->decoration == TextDecorationType
Grammar && paragraph.checkingRangeCovers(resultLocation, resultLength)) { | 617 } else if (shouldMarkGrammar && result->decoration == TextDecorationType
Grammar && paragraph.checkingRangeCovers(resultLocation, resultLength)) { |
| 616 ASSERT(resultLength > 0 && resultLocation >= 0); | 618 DCHECK_GT(resultLength, 0); |
| 619 DCHECK_GE(resultLocation, 0); |
| 617 for (unsigned j = 0; j < result->details.size(); j++) { | 620 for (unsigned j = 0; j < result->details.size(); j++) { |
| 618 const GrammarDetail* detail = &result->details[j]; | 621 const GrammarDetail* detail = &result->details[j]; |
| 619 ASSERT(detail->length > 0 && detail->location >= 0); | 622 DCHECK_GT(detail->length, 0); |
| 623 DCHECK_GE(detail->location, 0); |
| 620 if (paragraph.checkingRangeCovers(resultLocation + detail->locat
ion, detail->length)) { | 624 if (paragraph.checkingRangeCovers(resultLocation + detail->locat
ion, detail->length)) { |
| 621 const EphemeralRange badGrammarRange = calculateCharacterSub
range(paragraph.paragraphRange(), resultLocation + detail->location, detail->len
gth); | 625 const EphemeralRange badGrammarRange = calculateCharacterSub
range(paragraph.paragraphRange(), resultLocation + detail->location, detail->len
gth); |
| 622 frame().document()->markers().addMarker(badGrammarRange.star
tPosition(), badGrammarRange.endPosition(), DocumentMarker::Grammar, detail->use
rDescription, result->hash); | 626 frame().document()->markers().addMarker(badGrammarRange.star
tPosition(), badGrammarRange.endPosition(), DocumentMarker::Grammar, detail->use
rDescription, result->hash); |
| 623 } | 627 } |
| 624 } | 628 } |
| 625 } else if (result->decoration == TextDecorationTypeInvisibleSpellcheck &
& resultLocation >= paragraph.checkingStart() && resultLocation + resultLength <
= spellingRangeEndOffset) { | 629 } else if (result->decoration == TextDecorationTypeInvisibleSpellcheck &
& resultLocation >= paragraph.checkingStart() && resultLocation + resultLength <
= spellingRangeEndOffset) { |
| 626 ASSERT(resultLength > 0 && resultLocation >= 0); | 630 DCHECK_GT(resultLength, 0); |
| 631 DCHECK_GE(resultLocation, 0); |
| 627 const EphemeralRange invisibleSpellcheckRange = calculateCharacterSu
brange(paragraph.paragraphRange(), resultLocation, resultLength); | 632 const EphemeralRange invisibleSpellcheckRange = calculateCharacterSu
brange(paragraph.paragraphRange(), resultLocation, resultLength); |
| 628 frame().document()->markers().addMarker(invisibleSpellcheckRange.sta
rtPosition(), invisibleSpellcheckRange.endPosition(), DocumentMarker::InvisibleS
pellcheck, result->replacement, result->hash); | 633 frame().document()->markers().addMarker(invisibleSpellcheckRange.sta
rtPosition(), invisibleSpellcheckRange.endPosition(), DocumentMarker::InvisibleS
pellcheck, result->replacement, result->hash); |
| 629 } | 634 } |
| 630 } | 635 } |
| 631 | 636 |
| 632 if (selectionChanged) { | 637 if (selectionChanged) { |
| 633 TextCheckingParagraph extendedParagraph(paragraph); | 638 TextCheckingParagraph extendedParagraph(paragraph); |
| 634 // Restore the caret position if we have made any replacements | 639 // Restore the caret position if we have made any replacements |
| 635 extendedParagraph.expandRangeToNextEnd(); | 640 extendedParagraph.expandRangeToNextEnd(); |
| 636 if (restoreSelectionAfterChange && selectionOffset >= 0 && selectionOffs
et <= extendedParagraph.rangeLength()) { | 641 if (restoreSelectionAfterChange && selectionOffset >= 0 && selectionOffs
et <= extendedParagraph.rangeLength()) { |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 723 if (startOfFirstWord.isNull() || endOfFirstWord.isNull() || startOfLastWord.
isNull() || endOfLastWord.isNull()) | 728 if (startOfFirstWord.isNull() || endOfFirstWord.isNull() || startOfLastWord.
isNull() || endOfLastWord.isNull()) |
| 724 return; | 729 return; |
| 725 | 730 |
| 726 // Now we remove markers on everything between startOfFirstWord and endOfLas
tWord. | 731 // Now we remove markers on everything between startOfFirstWord and endOfLas
tWord. |
| 727 // However, if an autocorrection change a single word to multiple words, we
want to remove correction mark from all the | 732 // However, if an autocorrection change a single word to multiple words, we
want to remove correction mark from all the |
| 728 // resulted words even we only edit one of them. For example, assuming autoc
orrection changes "avantgarde" to "avant | 733 // resulted words even we only edit one of them. For example, assuming autoc
orrection changes "avantgarde" to "avant |
| 729 // garde", we will have CorrectionIndicator marker on both words and on the
whitespace between them. If we then edit garde, | 734 // garde", we will have CorrectionIndicator marker on both words and on the
whitespace between them. If we then edit garde, |
| 730 // we would like to remove the marker from word "avant" and whitespace as we
ll. So we need to get the continous range of | 735 // we would like to remove the marker from word "avant" and whitespace as we
ll. So we need to get the continous range of |
| 731 // of marker that contains the word in question, and remove marker on that w
hole range. | 736 // of marker that contains the word in question, and remove marker on that w
hole range. |
| 732 Document* document = frame().document(); | 737 Document* document = frame().document(); |
| 733 ASSERT(document); | 738 DCHECK(document); |
| 734 const EphemeralRange wordRange(startOfFirstWord.deepEquivalent(), endOfLastW
ord.deepEquivalent()); | 739 const EphemeralRange wordRange(startOfFirstWord.deepEquivalent(), endOfLastW
ord.deepEquivalent()); |
| 735 document->markers().removeMarkers(wordRange, DocumentMarker::MisspellingMark
ers(), DocumentMarkerController::RemovePartiallyOverlappingMarker); | 740 document->markers().removeMarkers(wordRange, DocumentMarker::MisspellingMark
ers(), DocumentMarkerController::RemovePartiallyOverlappingMarker); |
| 736 } | 741 } |
| 737 | 742 |
| 738 void SpellChecker::didEndEditingOnTextField(Element* e) | 743 void SpellChecker::didEndEditingOnTextField(Element* e) |
| 739 { | 744 { |
| 740 TRACE_EVENT0("blink", "SpellChecker::didEndEditingOnTextField"); | 745 TRACE_EVENT0("blink", "SpellChecker::didEndEditingOnTextField"); |
| 741 | 746 |
| 742 // Remove markers when deactivating a selection in an <input type="text"/>. | 747 // Remove markers when deactivating a selection in an <input type="text"/>. |
| 743 // Prevent new ones from appearing too. | 748 // Prevent new ones from appearing too. |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 944 visitor->trace(m_frame); | 949 visitor->trace(m_frame); |
| 945 visitor->trace(m_spellCheckRequester); | 950 visitor->trace(m_spellCheckRequester); |
| 946 } | 951 } |
| 947 | 952 |
| 948 void SpellChecker::prepareForLeakDetection() | 953 void SpellChecker::prepareForLeakDetection() |
| 949 { | 954 { |
| 950 m_spellCheckRequester->prepareForLeakDetection(); | 955 m_spellCheckRequester->prepareForLeakDetection(); |
| 951 } | 956 } |
| 952 | 957 |
| 953 } // namespace blink | 958 } // namespace blink |
| OLD | NEW |