| 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 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 219 if (spellingSearchStart == spellingSearchEnd) | 219 if (spellingSearchStart == spellingSearchEnd) |
| 220 return; // nothing to search in | 220 return; // nothing to search in |
| 221 | 221 |
| 222 // We go to the end of our first range instead of the start of it, just to b
e sure | 222 // We go to the end of our first range instead of the start of it, just to b
e sure |
| 223 // we don't get foiled by any word boundary problems at the start. It means
we might | 223 // we don't get foiled by any word boundary problems at the start. It means
we might |
| 224 // do a tiny bit more searching. | 224 // do a tiny bit more searching. |
| 225 Node* searchEndNodeAfterWrap = spellingSearchEnd.computeContainerNode(); | 225 Node* searchEndNodeAfterWrap = spellingSearchEnd.computeContainerNode(); |
| 226 int searchEndOffsetAfterWrap = spellingSearchEnd.offsetInContainerNode(); | 226 int searchEndOffsetAfterWrap = spellingSearchEnd.offsetInContainerNode(); |
| 227 | 227 |
| 228 int misspellingOffset = 0; | 228 int misspellingOffset = 0; |
| 229 GrammarDetail grammarDetail; | 229 String misspelledWord = TextCheckingHelper(spellCheckerClient(), spellingSea
rchStart, spellingSearchEnd).findFirstMisspelling(misspellingOffset, false); |
| 230 int grammarPhraseOffset = 0; | |
| 231 Position grammarSearchStart, grammarSearchEnd; | |
| 232 String badGrammarPhrase; | |
| 233 String misspelledWord; | |
| 234 | 230 |
| 235 bool isSpelling = true; | 231 // If we did not find a misspelled word, wrap and try again (but don't bothe
r if we started at the beginning of the |
| 236 int foundOffset = 0; | |
| 237 String foundItem; | |
| 238 if (unifiedTextCheckerEnabled()) { | |
| 239 grammarSearchStart = spellingSearchStart; | |
| 240 grammarSearchEnd = spellingSearchEnd; | |
| 241 foundItem = TextCheckingHelper(spellCheckerClient(), spellingSearchStart
, spellingSearchEnd).findFirstMisspellingOrBadGrammar(isSpelling, foundOffset, g
rammarDetail); | |
| 242 if (isSpelling) { | |
| 243 misspelledWord = foundItem; | |
| 244 misspellingOffset = foundOffset; | |
| 245 } else { | |
| 246 badGrammarPhrase = foundItem; | |
| 247 grammarPhraseOffset = foundOffset; | |
| 248 } | |
| 249 } else { | |
| 250 misspelledWord = TextCheckingHelper(spellCheckerClient(), spellingSearch
Start, spellingSearchEnd).findFirstMisspelling(misspellingOffset, false); | |
| 251 grammarSearchStart = spellingSearchStart; | |
| 252 grammarSearchEnd = spellingSearchEnd; | |
| 253 if (!misspelledWord.isEmpty()) { | |
| 254 // Stop looking at start of next misspelled word | |
| 255 CharacterIterator chars(grammarSearchStart, grammarSearchEnd); | |
| 256 chars.advance(misspellingOffset); | |
| 257 grammarSearchEnd = chars.startPosition(); | |
| 258 } | |
| 259 | |
| 260 badGrammarPhrase = TextCheckingHelper(spellCheckerClient(), grammarSearc
hStart, grammarSearchEnd).findFirstBadGrammar(grammarDetail, grammarPhraseOffset
, false); | |
| 261 } | |
| 262 | |
| 263 // If we found neither bad grammar nor a misspelled word, wrap and try again
(but don't bother if we started at the beginning of the | |
| 264 // block rather than at a selection). | 232 // block rather than at a selection). |
| 265 if (startedWithSelection && !misspelledWord && !badGrammarPhrase) { | 233 if (startedWithSelection && !misspelledWord) { |
| 266 spellingSearchStart = Position::editingPositionOf(topNode, 0); | 234 spellingSearchStart = Position::editingPositionOf(topNode, 0); |
| 267 // going until the end of the very first chunk we tested is far enough | 235 // going until the end of the very first chunk we tested is far enough |
| 268 spellingSearchEnd = Position::editingPositionOf(searchEndNodeAfterWrap,
searchEndOffsetAfterWrap); | 236 spellingSearchEnd = Position::editingPositionOf(searchEndNodeAfterWrap,
searchEndOffsetAfterWrap); |
| 269 | 237 |
| 270 if (unifiedTextCheckerEnabled()) { | 238 misspelledWord = TextCheckingHelper(spellCheckerClient(), spellingSearch
Start, spellingSearchEnd).findFirstMisspelling(misspellingOffset, false); |
| 271 grammarSearchStart = spellingSearchStart; | |
| 272 grammarSearchEnd = spellingSearchEnd; | |
| 273 foundItem = TextCheckingHelper(spellCheckerClient(), spellingSearchS
tart, spellingSearchEnd).findFirstMisspellingOrBadGrammar(isSpelling, foundOffse
t, grammarDetail); | |
| 274 if (isSpelling) { | |
| 275 misspelledWord = foundItem; | |
| 276 misspellingOffset = foundOffset; | |
| 277 } else { | |
| 278 badGrammarPhrase = foundItem; | |
| 279 grammarPhraseOffset = foundOffset; | |
| 280 } | |
| 281 } else { | |
| 282 misspelledWord = TextCheckingHelper(spellCheckerClient(), spellingSe
archStart, spellingSearchEnd).findFirstMisspelling(misspellingOffset, false); | |
| 283 grammarSearchStart = spellingSearchStart; | |
| 284 grammarSearchEnd = spellingSearchEnd; | |
| 285 if (!misspelledWord.isEmpty()) { | |
| 286 // Stop looking at start of next misspelled word | |
| 287 CharacterIterator chars(grammarSearchStart, grammarSearchEnd); | |
| 288 chars.advance(misspellingOffset); | |
| 289 grammarSearchEnd = chars.startPosition(); | |
| 290 } | |
| 291 | |
| 292 badGrammarPhrase = TextCheckingHelper(spellCheckerClient(), grammarS
earchStart, grammarSearchEnd).findFirstBadGrammar(grammarDetail, grammarPhraseOf
fset, false); | |
| 293 } | |
| 294 } | 239 } |
| 295 | 240 |
| 296 if (!badGrammarPhrase.isEmpty()) { | 241 if (!misspelledWord.isEmpty()) { |
| 297 // We found bad grammar. Since we only searched for bad grammar up to th
e first misspelled word, the bad grammar | 242 // We found a misspelling. Select the misspelling, update the spelling p
anel, and store |
| 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. | |
| 300 | |
| 301 DCHECK_GT(badGrammarPhrase.length(), 0u); | |
| 302 DCHECK_NE(grammarDetail.location, -1); | |
| 303 DCHECK_GT(grammarDetail.length, 0); | |
| 304 | |
| 305 // FIXME 4859190: This gets confused with doubled punctuation at the end
of a paragraph | |
| 306 const EphemeralRange badGrammarRange = calculateCharacterSubrange(Epheme
ralRange(grammarSearchStart, grammarSearchEnd), grammarPhraseOffset + grammarDet
ail.location, grammarDetail.length); | |
| 307 frame().selection().setSelection(VisibleSelection(badGrammarRange)); | |
| 308 frame().selection().revealSelection(); | |
| 309 frame().document()->markers().addMarker(badGrammarRange.startPosition(),
badGrammarRange.endPosition(), DocumentMarker::Grammar, grammarDetail.userDescr
iption); | |
| 310 } 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 // a marker so we draw the red squiggle later. | 243 // a marker so we draw the red squiggle later. |
| 313 | 244 |
| 314 const EphemeralRange misspellingRange = calculateCharacterSubrange(Ephem
eralRange(spellingSearchStart, spellingSearchEnd), misspellingOffset, misspelled
Word.length()); | 245 const EphemeralRange misspellingRange = calculateCharacterSubrange(Ephem
eralRange(spellingSearchStart, spellingSearchEnd), misspellingOffset, misspelled
Word.length()); |
| 315 frame().selection().setSelection(VisibleSelection(misspellingRange)); | 246 frame().selection().setSelection(VisibleSelection(misspellingRange)); |
| 316 frame().selection().revealSelection(); | 247 frame().selection().revealSelection(); |
| 317 spellCheckerClient().updateSpellingUIWithMisspelledWord(misspelledWord); | 248 spellCheckerClient().updateSpellingUIWithMisspelledWord(misspelledWord); |
| 318 frame().document()->markers().addMarker(misspellingRange.startPosition()
, misspellingRange.endPosition(), DocumentMarker::Spelling); | 249 frame().document()->markers().addMarker(misspellingRange.startPosition()
, misspellingRange.endPosition(), DocumentMarker::Spelling); |
| 319 } | 250 } |
| 320 } | 251 } |
| 321 | 252 |
| 322 void SpellChecker::showSpellingGuessPanel() | 253 void SpellChecker::showSpellingGuessPanel() |
| 323 { | 254 { |
| 324 if (spellCheckerClient().spellingUIIsShowing()) { | 255 if (spellCheckerClient().spellingUIIsShowing()) { |
| 325 spellCheckerClient().showSpellingUI(false); | 256 spellCheckerClient().showSpellingUI(false); |
| 326 return; | 257 return; |
| 327 } | 258 } |
| 328 | 259 |
| 329 advanceToNextMisspelling(true); | 260 advanceToNextMisspelling(true); |
| 330 spellCheckerClient().showSpellingUI(true); | 261 spellCheckerClient().showSpellingUI(true); |
| 331 } | 262 } |
| 332 | 263 |
| 333 void SpellChecker::clearMisspellingsAndBadGrammar(const VisibleSelection &moving
Selection) | 264 void SpellChecker::clearMisspellingsAndBadGrammar(const VisibleSelection &moving
Selection) |
| 334 { | 265 { |
| 335 removeMarkers(movingSelection, DocumentMarker::MisspellingMarkers()); | 266 removeMarkers(movingSelection, DocumentMarker::MisspellingMarkers()); |
| 336 } | 267 } |
| 337 | 268 |
| 338 void SpellChecker::markMisspellingsAndBadGrammar(const VisibleSelection &movingS
election) | 269 void SpellChecker::markMisspellingsAndBadGrammar(const VisibleSelection &movingS
election) |
| 339 { | 270 { |
| 340 markMisspellingsAndBadGrammar(movingSelection, isContinuousSpellCheckingEnab
led(), movingSelection); | 271 if (!unifiedTextCheckerEnabled()) { |
| 272 markMisspellings(movingSelection); |
| 273 return; |
| 274 } |
| 275 |
| 276 if (!isContinuousSpellCheckingEnabled()) |
| 277 return; |
| 278 |
| 279 // markMisspellings() is triggered by selection change, in which case we che
ck spelling, but don't autocorrect misspellings. |
| 280 markAllMisspellingsInRange(movingSelection.toNormalizedEphemeralRange()); |
| 341 } | 281 } |
| 342 | 282 |
| 343 void SpellChecker::markMisspellingsAfterLineBreak(const VisibleSelection& wordSe
lection) | 283 void SpellChecker::markMisspellingsAfterLineBreak(const VisibleSelection& wordSe
lection) |
| 344 { | 284 { |
| 345 TRACE_EVENT0("blink", "SpellChecker::markMisspellingsAfterLineBreak"); | 285 TRACE_EVENT0("blink", "SpellChecker::markMisspellingsAfterLineBreak"); |
| 346 | 286 |
| 347 if (!unifiedTextCheckerEnabled()) { | 287 if (!unifiedTextCheckerEnabled()) { |
| 348 markMisspellings(wordSelection); | 288 markMisspellings(wordSelection); |
| 349 return; | 289 return; |
| 350 } | 290 } |
| 351 | 291 |
| 352 TextCheckingTypeMask textCheckingOptions = TextCheckingTypeGrammar; | |
| 353 | |
| 354 if (isContinuousSpellCheckingEnabled()) | 292 if (isContinuousSpellCheckingEnabled()) |
| 355 textCheckingOptions |= TextCheckingTypeSpelling; | 293 markAllMisspellingsInRange(wordSelection.toNormalizedEphemeralRange()); |
| 356 | |
| 357 VisibleSelection wholeParagraph( | |
| 358 startOfParagraph(wordSelection.visibleStart()), | |
| 359 endOfParagraph(wordSelection.visibleEnd())); | |
| 360 | |
| 361 markAllMisspellingsAndBadGrammarInRanges( | |
| 362 textCheckingOptions, wordSelection.toNormalizedEphemeralRange(), | |
| 363 wholeParagraph.toNormalizedEphemeralRange()); | |
| 364 } | 294 } |
| 365 | 295 |
| 366 void SpellChecker::markMisspellingsAfterTypingToWord(const VisiblePosition &word
Start, const VisibleSelection& selectionAfterTyping) | 296 void SpellChecker::markMisspellingsAfterTypingToWord(const VisiblePosition &word
Start, const VisibleSelection& selectionAfterTyping) |
| 367 { | 297 { |
| 368 TRACE_EVENT0("blink", "SpellChecker::markMisspellingsAfterTypingToWord"); | 298 TRACE_EVENT0("blink", "SpellChecker::markMisspellingsAfterTypingToWord"); |
| 369 | 299 |
| 300 if (!isContinuousSpellCheckingEnabled()) |
| 301 return; |
| 302 |
| 370 if (unifiedTextCheckerEnabled()) { | 303 if (unifiedTextCheckerEnabled()) { |
| 371 TextCheckingTypeMask textCheckingOptions = 0; | |
| 372 | |
| 373 if (isContinuousSpellCheckingEnabled()) | |
| 374 textCheckingOptions |= TextCheckingTypeSpelling; | |
| 375 | |
| 376 if (!(textCheckingOptions & TextCheckingTypeSpelling)) | |
| 377 return; | |
| 378 | |
| 379 textCheckingOptions |= TextCheckingTypeGrammar; | |
| 380 | |
| 381 VisibleSelection adjacentWords = VisibleSelection(startOfWord(wordStart,
LeftWordIfOnBoundary), endOfWord(wordStart, RightWordIfOnBoundary)); | 304 VisibleSelection adjacentWords = VisibleSelection(startOfWord(wordStart,
LeftWordIfOnBoundary), endOfWord(wordStart, RightWordIfOnBoundary)); |
| 382 if (textCheckingOptions & TextCheckingTypeGrammar) { | 305 markAllMisspellingsInRange(adjacentWords.toNormalizedEphemeralRange()); |
| 383 VisibleSelection selectedSentence = VisibleSelection(startOfSentence
(wordStart), endOfSentence(wordStart)); | |
| 384 markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, adjace
ntWords.toNormalizedEphemeralRange(), selectedSentence.toNormalizedEphemeralRang
e()); | |
| 385 } else { | |
| 386 markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, adjace
ntWords.toNormalizedEphemeralRange(), adjacentWords.toNormalizedEphemeralRange()
); | |
| 387 } | |
| 388 return; | 306 return; |
| 389 } | 307 } |
| 390 | 308 |
| 391 if (!isContinuousSpellCheckingEnabled()) | |
| 392 return; | |
| 393 | |
| 394 // Check spelling of one word | 309 // Check spelling of one word |
| 395 bool result = markMisspellings(VisibleSelection(startOfWord(wordStart, LeftW
ordIfOnBoundary), endOfWord(wordStart, RightWordIfOnBoundary))); | 310 markMisspellings(VisibleSelection(startOfWord(wordStart, LeftWordIfOnBoundar
y), endOfWord(wordStart, RightWordIfOnBoundary))); |
| 396 | |
| 397 if (!result) | |
| 398 return; | |
| 399 | |
| 400 // Check grammar of entire sentence | |
| 401 markBadGrammar(VisibleSelection(startOfSentence(wordStart), endOfSentence(wo
rdStart))); | |
| 402 } | |
| 403 | |
| 404 bool SpellChecker::markMisspellingsOrBadGrammar(const VisibleSelection& selectio
n, bool checkSpelling) | |
| 405 { | |
| 406 // This function is called with a selection already expanded to word boundar
ies. | |
| 407 // Might be nice to assert that here. | |
| 408 | |
| 409 // This function is used only for as-you-type checking, so if that's off we
do nothing. Note that | |
| 410 // grammar checking can only be on if spell checking is also on. | |
| 411 if (!isContinuousSpellCheckingEnabled()) | |
| 412 return false; | |
| 413 | |
| 414 TRACE_EVENT0("blink", "SpellChecker::markMisspellingsOrBadGrammar"); | |
| 415 | |
| 416 const EphemeralRange range = selection.toNormalizedEphemeralRange(); | |
| 417 if (range.isNull()) | |
| 418 return false; | |
| 419 | |
| 420 // If we're not in an editable node, bail. | |
| 421 Node* editableNode = range.startPosition().computeContainerNode(); | |
| 422 if (!editableNode || !hasEditableStyle(*editableNode)) | |
| 423 return false; | |
| 424 | |
| 425 if (!isSpellCheckingEnabledFor(editableNode)) | |
| 426 return false; | |
| 427 | |
| 428 TextCheckingHelper checker(spellCheckerClient(), range.startPosition(), rang
e.endPosition()); | |
| 429 if (checkSpelling) | |
| 430 return checker.markAllMisspellings(); | |
| 431 | |
| 432 checker.markAllBadGrammar(); | |
| 433 return false; | |
| 434 } | 311 } |
| 435 | 312 |
| 436 bool SpellChecker::isSpellCheckingEnabledFor(Node* node) const | 313 bool SpellChecker::isSpellCheckingEnabledFor(Node* node) const |
| 437 { | 314 { |
| 438 if (!node) | 315 if (!node) |
| 439 return false; | 316 return false; |
| 440 const Element* focusedElement = node->isElementNode() ? toElement(node) : no
de->parentElement(); | 317 const Element* focusedElement = node->isElementNode() ? toElement(node) : no
de->parentElement(); |
| 441 if (!focusedElement) | 318 if (!focusedElement) |
| 442 return false; | 319 return false; |
| 443 return focusedElement->isSpellCheckingEnabled(); | 320 return focusedElement->isSpellCheckingEnabled(); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 460 } | 337 } |
| 461 if (HTMLElement* element = Traversal<HTMLElement>::firstAncestorOrSelf(*sele
ction.start().anchorNode())) { | 338 if (HTMLElement* element = Traversal<HTMLElement>::firstAncestorOrSelf(*sele
ction.start().anchorNode())) { |
| 462 if (element->spellcheck()) | 339 if (element->spellcheck()) |
| 463 return true; | 340 return true; |
| 464 } | 341 } |
| 465 return false; | 342 return false; |
| 466 } | 343 } |
| 467 | 344 |
| 468 bool SpellChecker::markMisspellings(const VisibleSelection& selection) | 345 bool SpellChecker::markMisspellings(const VisibleSelection& selection) |
| 469 { | 346 { |
| 470 return markMisspellingsOrBadGrammar(selection, true); | 347 // This function is called with a selection already expanded to word boundar
ies. |
| 348 // Might be nice to assert that here. |
| 349 |
| 350 // This function is used only for as-you-type checking, so if that's off we
do nothing. |
| 351 if (!isContinuousSpellCheckingEnabled()) |
| 352 return false; |
| 353 |
| 354 TRACE_EVENT0("blink", "SpellChecker::markMisspellings"); |
| 355 |
| 356 const EphemeralRange range = selection.toNormalizedEphemeralRange(); |
| 357 if (range.isNull()) |
| 358 return false; |
| 359 |
| 360 // If we're not in an editable node, bail. |
| 361 Node* editableNode = range.startPosition().computeContainerNode(); |
| 362 if (!editableNode || !hasEditableStyle(*editableNode)) |
| 363 return false; |
| 364 |
| 365 if (!isSpellCheckingEnabledFor(editableNode)) |
| 366 return false; |
| 367 |
| 368 TextCheckingHelper checker(spellCheckerClient(), range.startPosition(), rang
e.endPosition()); |
| 369 return checker.markAllMisspellings(); |
| 471 } | 370 } |
| 472 | 371 |
| 473 void SpellChecker::markBadGrammar(const VisibleSelection& selection) | 372 void SpellChecker::markAllMisspellingsInRange(const EphemeralRange& spellingRang
e) |
| 474 { | |
| 475 markMisspellingsOrBadGrammar(selection, false); | |
| 476 } | |
| 477 | |
| 478 void SpellChecker::markAllMisspellingsAndBadGrammarInRanges(TextCheckingTypeMask
textCheckingOptions, const EphemeralRange& spellingRange, const EphemeralRange&
grammarRange) | |
| 479 { | 373 { |
| 480 DCHECK(unifiedTextCheckerEnabled()); | 374 DCHECK(unifiedTextCheckerEnabled()); |
| 481 | 375 |
| 482 bool shouldMarkGrammar = textCheckingOptions & TextCheckingTypeGrammar; | |
| 483 | |
| 484 // This function is called with selections already expanded to word boundari
es. | 376 // This function is called with selections already expanded to word boundari
es. |
| 485 if (spellingRange.isNull() || (shouldMarkGrammar && grammarRange.isNull())) | 377 if (spellingRange.isNull()) |
| 486 return; | 378 return; |
| 487 | 379 |
| 488 // If we're not in an editable node, bail. | 380 // If we're not in an editable node, bail. |
| 489 Node* editableNode = spellingRange.startPosition().computeContainerNode(); | 381 Node* editableNode = spellingRange.startPosition().computeContainerNode(); |
| 490 if (!editableNode || !hasEditableStyle(*editableNode)) | 382 if (!editableNode || !hasEditableStyle(*editableNode)) |
| 491 return; | 383 return; |
| 492 | 384 |
| 493 if (!isSpellCheckingEnabledFor(editableNode)) | 385 if (!isSpellCheckingEnabledFor(editableNode)) |
| 494 return; | 386 return; |
| 495 | 387 |
| 496 TextCheckingParagraph fullParagraphToCheck(shouldMarkGrammar ? grammarRange
: spellingRange); | 388 TextCheckingParagraph fullParagraphToCheck(spellingRange); |
| 497 chunkAndMarkAllMisspellingsAndBadGrammar(textCheckingOptions, fullParagraphT
oCheck); | 389 chunkAndMarkAllMisspellings(fullParagraphToCheck); |
| 498 } | 390 } |
| 499 | 391 |
| 500 static EphemeralRange expandEndToSentenceBoundary(const EphemeralRange& range) | 392 static EphemeralRange expandEndToSentenceBoundary(const EphemeralRange& range) |
| 501 { | 393 { |
| 502 DCHECK(range.isNotNull()); | 394 DCHECK(range.isNotNull()); |
| 503 const VisiblePosition& visibleEnd = createVisiblePosition(range.endPosition(
)); | 395 const VisiblePosition& visibleEnd = createVisiblePosition(range.endPosition(
)); |
| 504 DCHECK(visibleEnd.isNotNull()); | 396 DCHECK(visibleEnd.isNotNull()); |
| 505 const Position& sentenceEnd = endOfSentence(visibleEnd).deepEquivalent(); | 397 const Position& sentenceEnd = endOfSentence(visibleEnd).deepEquivalent(); |
| 506 return EphemeralRange(range.startPosition(), sentenceEnd.isNotNull() ? sente
nceEnd : range.endPosition()); | 398 return EphemeralRange(range.startPosition(), sentenceEnd.isNotNull() ? sente
nceEnd : range.endPosition()); |
| 507 } | 399 } |
| 508 | 400 |
| 509 static EphemeralRange expandRangeToSentenceBoundary(const EphemeralRange& range) | 401 static EphemeralRange expandRangeToSentenceBoundary(const EphemeralRange& range) |
| 510 { | 402 { |
| 511 DCHECK(range.isNotNull()); | 403 DCHECK(range.isNotNull()); |
| 512 const VisiblePosition& visibleStart = createVisiblePosition(range.startPosit
ion()); | 404 const VisiblePosition& visibleStart = createVisiblePosition(range.startPosit
ion()); |
| 513 DCHECK(visibleStart.isNotNull()); | 405 DCHECK(visibleStart.isNotNull()); |
| 514 const Position& sentenceStart = startOfSentence(visibleStart).deepEquivalent
(); | 406 const Position& sentenceStart = startOfSentence(visibleStart).deepEquivalent
(); |
| 515 return expandEndToSentenceBoundary(EphemeralRange(sentenceStart.isNull() ? r
ange.startPosition() : sentenceStart, range.endPosition())); | 407 return expandEndToSentenceBoundary(EphemeralRange(sentenceStart.isNull() ? r
ange.startPosition() : sentenceStart, range.endPosition())); |
| 516 } | 408 } |
| 517 | 409 |
| 518 void SpellChecker::chunkAndMarkAllMisspellingsAndBadGrammar(Node* node, const Ep
hemeralRange& insertedRange) | 410 void SpellChecker::chunkAndMarkAllMisspellingsAndBadGrammar(Node* node, const Ep
hemeralRange& insertedRange) |
| 519 { | 411 { |
| 520 TRACE_EVENT0("blink", "SpellChecker::chunkAndMarkAllMisspellingsAndBadGramma
r"); | 412 TRACE_EVENT0("blink", "SpellChecker::chunkAndMarkAllMisspellingsAndBadGramma
r"); |
| 521 if (!node) | 413 if (!node) |
| 522 return; | 414 return; |
| 523 EphemeralRange paragraphRange(Position::firstPositionInNode(node), Position:
:lastPositionInNode(node)); | 415 EphemeralRange paragraphRange(Position::firstPositionInNode(node), Position:
:lastPositionInNode(node)); |
| 524 TextCheckingParagraph textToCheck(insertedRange, paragraphRange); | 416 TextCheckingParagraph textToCheck(insertedRange, paragraphRange); |
| 525 chunkAndMarkAllMisspellingsAndBadGrammar(resolveTextCheckingTypeMask(TextChe
ckingTypeSpelling | TextCheckingTypeGrammar), textToCheck); | 417 chunkAndMarkAllMisspellings(textToCheck); |
| 526 } | 418 } |
| 527 | 419 |
| 528 void SpellChecker::chunkAndMarkAllMisspellingsAndBadGrammar(TextCheckingTypeMask
textCheckingOptions, const TextCheckingParagraph& fullParagraphToCheck) | 420 void SpellChecker::chunkAndMarkAllMisspellings(const TextCheckingParagraph& full
ParagraphToCheck) |
| 529 { | 421 { |
| 530 if (fullParagraphToCheck.isEmpty()) | 422 if (fullParagraphToCheck.isEmpty()) |
| 531 return; | 423 return; |
| 532 const EphemeralRange& paragraphRange = fullParagraphToCheck.paragraphRange()
; | 424 const EphemeralRange& paragraphRange = fullParagraphToCheck.paragraphRange()
; |
| 533 | 425 |
| 534 // Since the text may be quite big chunk it up and adjust to the sentence bo
undary. | 426 // Since the text may be quite big chunk it up and adjust to the sentence bo
undary. |
| 535 const int kChunkSize = 16 * 1024; | 427 const int kChunkSize = 16 * 1024; |
| 536 | 428 |
| 537 // Check the full paragraph instead if the paragraph is short, which saves | 429 // Check the full paragraph instead if the paragraph is short, which saves |
| 538 // the cost on sentence boundary finding. | 430 // the cost on sentence boundary finding. |
| 539 if (fullParagraphToCheck.rangeLength() <= kChunkSize) { | 431 if (fullParagraphToCheck.rangeLength() <= kChunkSize) { |
| 540 SpellCheckRequest* request = SpellCheckRequest::create(resolveTextChecki
ngTypeMask(textCheckingOptions), TextCheckingProcessBatch, paragraphRange, parag
raphRange, 0); | 432 SpellCheckRequest* request = SpellCheckRequest::create(TextCheckingTypeS
pelling, TextCheckingProcessBatch, paragraphRange, paragraphRange, 0); |
| 541 if (request) | 433 if (request) |
| 542 m_spellCheckRequester->requestCheckingFor(request); | 434 m_spellCheckRequester->requestCheckingFor(request); |
| 543 return; | 435 return; |
| 544 } | 436 } |
| 545 | 437 |
| 546 CharacterIterator checkRangeIterator(fullParagraphToCheck.checkingRange(), T
extIteratorEmitsObjectReplacementCharacter); | 438 CharacterIterator checkRangeIterator(fullParagraphToCheck.checkingRange(), T
extIteratorEmitsObjectReplacementCharacter); |
| 547 for (int requestNum = 0; !checkRangeIterator.atEnd(); requestNum++) { | 439 for (int requestNum = 0; !checkRangeIterator.atEnd(); requestNum++) { |
| 548 EphemeralRange chunkRange = checkRangeIterator.calculateCharacterSubrang
e(0, kChunkSize); | 440 EphemeralRange chunkRange = checkRangeIterator.calculateCharacterSubrang
e(0, kChunkSize); |
| 549 EphemeralRange checkRange = requestNum ? expandEndToSentenceBoundary(chu
nkRange) : expandRangeToSentenceBoundary(chunkRange); | 441 EphemeralRange checkRange = requestNum ? expandEndToSentenceBoundary(chu
nkRange) : expandRangeToSentenceBoundary(chunkRange); |
| 550 | 442 |
| 551 SpellCheckRequest* request = SpellCheckRequest::create(resolveTextChecki
ngTypeMask(textCheckingOptions), TextCheckingProcessBatch, checkRange, paragraph
Range, requestNum); | 443 SpellCheckRequest* request = SpellCheckRequest::create(TextCheckingTypeS
pelling, TextCheckingProcessBatch, checkRange, paragraphRange, requestNum); |
| 552 if (request) | 444 if (request) |
| 553 m_spellCheckRequester->requestCheckingFor(request); | 445 m_spellCheckRequester->requestCheckingFor(request); |
| 554 | 446 |
| 555 if (!checkRangeIterator.atEnd()) { | 447 if (!checkRangeIterator.atEnd()) { |
| 556 checkRangeIterator.advance(1); | 448 checkRangeIterator.advance(1); |
| 557 // The layout should be already update due to the initialization of
checkRangeIterator, | 449 // The layout should be already update due to the initialization of
checkRangeIterator, |
| 558 // so comparePositions can be directly called. | 450 // so comparePositions can be directly called. |
| 559 if (comparePositions(chunkRange.endPosition(), checkRange.endPositio
n()) < 0) | 451 if (comparePositions(chunkRange.endPosition(), checkRange.endPositio
n()) < 0) |
| 560 checkRangeIterator.advance(TextIterator::rangeLength(chunkRange.
endPosition(), checkRange.endPosition())); | 452 checkRangeIterator.advance(TextIterator::rangeLength(chunkRange.
endPosition(), checkRange.endPosition())); |
| 561 } | 453 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 575 if (request->rootEditableElement()->document() != frame().selection().docume
nt()) { | 467 if (request->rootEditableElement()->document() != frame().selection().docume
nt()) { |
| 576 // we ignore |request| made for another document. | 468 // we ignore |request| made for another document. |
| 577 // "editing/spelling/spellcheck-sequencenum.html" and others reach here. | 469 // "editing/spelling/spellcheck-sequencenum.html" and others reach here. |
| 578 return; | 470 return; |
| 579 } | 471 } |
| 580 | 472 |
| 581 TextCheckingTypeMask textCheckingOptions = request->data().mask(); | 473 TextCheckingTypeMask textCheckingOptions = request->data().mask(); |
| 582 TextCheckingParagraph paragraph(request->checkingRange(), request->paragraph
Range()); | 474 TextCheckingParagraph paragraph(request->checkingRange(), request->paragraph
Range()); |
| 583 | 475 |
| 584 bool shouldMarkSpelling = textCheckingOptions & TextCheckingTypeSpelling; | 476 bool shouldMarkSpelling = textCheckingOptions & TextCheckingTypeSpelling; |
| 585 bool shouldMarkGrammar = textCheckingOptions & TextCheckingTypeGrammar; | |
| 586 | 477 |
| 587 // Expand the range to encompass entire paragraphs, since text checking need
s that much context. | 478 // Expand the range to encompass entire paragraphs, since text checking need
s that much context. |
| 588 int selectionOffset = 0; | 479 int selectionOffset = 0; |
| 589 int ambiguousBoundaryOffset = -1; | 480 int ambiguousBoundaryOffset = -1; |
| 590 bool selectionChanged = false; | 481 bool selectionChanged = false; |
| 591 bool restoreSelectionAfterChange = false; | 482 bool restoreSelectionAfterChange = false; |
| 592 bool adjustSelectionForParagraphBoundaries = false; | 483 bool adjustSelectionForParagraphBoundaries = false; |
| 593 | 484 |
| 594 if (shouldMarkSpelling) { | 485 if (shouldMarkSpelling) { |
| 595 if (frame().selection().isCaret()) { | 486 if (frame().selection().isCaret()) { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 621 // Only mark misspelling if: | 512 // Only mark misspelling if: |
| 622 // 1. Current text checking isn't done for autocorrection, in which
case shouldMarkSpelling is false. | 513 // 1. Current text checking isn't done for autocorrection, in which
case shouldMarkSpelling is false. |
| 623 // 2. Result falls within spellingRange. | 514 // 2. Result falls within spellingRange. |
| 624 // 3. The word in question doesn't end at an ambiguous boundary. For
instance, we would not mark | 515 // 3. The word in question doesn't end at an ambiguous boundary. For
instance, we would not mark |
| 625 // "wouldn'" as misspelled right after apostrophe is typed. | 516 // "wouldn'" as misspelled right after apostrophe is typed. |
| 626 if (shouldMarkSpelling && result->decoration == TextDecorationTypeSp
elling && resultLocation >= paragraph.checkingStart() && resultLocation + result
Length <= spellingRangeEndOffset && !resultEndsAtAmbiguousBoundary) { | 517 if (shouldMarkSpelling && result->decoration == TextDecorationTypeSp
elling && resultLocation >= paragraph.checkingStart() && resultLocation + result
Length <= spellingRangeEndOffset && !resultEndsAtAmbiguousBoundary) { |
| 627 DCHECK_GT(resultLength, 0); | 518 DCHECK_GT(resultLength, 0); |
| 628 DCHECK_GE(resultLocation, 0); | 519 DCHECK_GE(resultLocation, 0); |
| 629 const EphemeralRange misspellingRange = calculateCharacterSubran
ge(paragraph.paragraphRange(), resultLocation, resultLength); | 520 const EphemeralRange misspellingRange = calculateCharacterSubran
ge(paragraph.paragraphRange(), resultLocation, resultLength); |
| 630 frame().document()->markers().addMarker(misspellingRange.startPo
sition(), misspellingRange.endPosition(), DocumentMarker::Spelling, result->repl
acement, result->hash); | 521 frame().document()->markers().addMarker(misspellingRange.startPo
sition(), misspellingRange.endPosition(), DocumentMarker::Spelling, result->repl
acement, result->hash); |
| 631 } else if (shouldMarkGrammar && result->decoration == TextDecoration
TypeGrammar && paragraph.checkingRangeCovers(resultLocation, resultLength)) { | |
| 632 DCHECK_GT(resultLength, 0); | |
| 633 DCHECK_GE(resultLocation, 0); | |
| 634 for (unsigned j = 0; j < result->details.size(); j++) { | |
| 635 const GrammarDetail* detail = &result->details[j]; | |
| 636 DCHECK_GT(detail->length, 0); | |
| 637 DCHECK_GE(detail->location, 0); | |
| 638 if (paragraph.checkingRangeCovers(resultLocation + detail->l
ocation, detail->length)) { | |
| 639 const EphemeralRange badGrammarRange = calculateCharacte
rSubrange(paragraph.paragraphRange(), resultLocation + detail->location, detail-
>length); | |
| 640 frame().document()->markers().addMarker(badGrammarRange.
startPosition(), badGrammarRange.endPosition(), DocumentMarker::Grammar, detail-
>userDescription, result->hash); | |
| 641 } | |
| 642 } | |
| 643 } else if (result->decoration == TextDecorationTypeInvisibleSpellche
ck && resultLocation >= paragraph.checkingStart() && resultLocation + resultLeng
th <= spellingRangeEndOffset) { | 522 } else if (result->decoration == TextDecorationTypeInvisibleSpellche
ck && resultLocation >= paragraph.checkingStart() && resultLocation + resultLeng
th <= spellingRangeEndOffset) { |
| 644 DCHECK_GT(resultLength, 0); | 523 DCHECK_GT(resultLength, 0); |
| 645 DCHECK_GE(resultLocation, 0); | 524 DCHECK_GE(resultLocation, 0); |
| 646 const EphemeralRange invisibleSpellcheckRange = calculateCharact
erSubrange(paragraph.paragraphRange(), resultLocation, resultLength); | 525 const EphemeralRange invisibleSpellcheckRange = calculateCharact
erSubrange(paragraph.paragraphRange(), resultLocation, resultLength); |
| 647 frame().document()->markers().addMarker(invisibleSpellcheckRange
.startPosition(), invisibleSpellcheckRange.endPosition(), DocumentMarker::Invisi
bleSpellcheck, result->replacement, result->hash); | 526 frame().document()->markers().addMarker(invisibleSpellcheckRange
.startPosition(), invisibleSpellcheckRange.endPosition(), DocumentMarker::Invisi
bleSpellcheck, result->replacement, result->hash); |
| 648 } | 527 } |
| 649 } | 528 } |
| 650 } | 529 } |
| 651 | 530 |
| 652 if (selectionChanged) { | 531 if (selectionChanged) { |
| 653 TextCheckingParagraph extendedParagraph(paragraph); | 532 TextCheckingParagraph extendedParagraph(paragraph); |
| 654 // Restore the caret position if we have made any replacements | 533 // Restore the caret position if we have made any replacements |
| 655 extendedParagraph.expandRangeToNextEnd(); | 534 extendedParagraph.expandRangeToNextEnd(); |
| 656 if (restoreSelectionAfterChange && selectionOffset >= 0 && selectionOffs
et <= extendedParagraph.rangeLength()) { | 535 if (restoreSelectionAfterChange && selectionOffset >= 0 && selectionOffs
et <= extendedParagraph.rangeLength()) { |
| 657 EphemeralRange selectionRange = extendedParagraph.subrange(0, select
ionOffset); | 536 EphemeralRange selectionRange = extendedParagraph.subrange(0, select
ionOffset); |
| 658 frame().selection().moveTo(selectionRange.endPosition(), TextAffinit
y::Downstream); | 537 frame().selection().moveTo(selectionRange.endPosition(), TextAffinit
y::Downstream); |
| 659 if (adjustSelectionForParagraphBoundaries) | 538 if (adjustSelectionForParagraphBoundaries) |
| 660 frame().selection().modify(FrameSelection::AlterationMove, Direc
tionForward, CharacterGranularity); | 539 frame().selection().modify(FrameSelection::AlterationMove, Direc
tionForward, CharacterGranularity); |
| 661 } else { | 540 } else { |
| 662 // If this fails for any reason, the fallback is to go one position
beyond the last replacement | 541 // If this fails for any reason, the fallback is to go one position
beyond the last replacement |
| 663 frame().selection().moveTo(frame().selection().selection().visibleEn
d()); | 542 frame().selection().moveTo(frame().selection().selection().visibleEn
d()); |
| 664 frame().selection().modify(FrameSelection::AlterationMove, Direction
Forward, CharacterGranularity); | 543 frame().selection().modify(FrameSelection::AlterationMove, Direction
Forward, CharacterGranularity); |
| 665 } | 544 } |
| 666 } | 545 } |
| 667 } | 546 } |
| 668 | 547 |
| 669 void SpellChecker::markMisspellingsAndBadGrammar(const VisibleSelection& spellin
gSelection, bool markGrammar, const VisibleSelection& grammarSelection) | |
| 670 { | |
| 671 if (unifiedTextCheckerEnabled()) { | |
| 672 if (!isContinuousSpellCheckingEnabled()) | |
| 673 return; | |
| 674 | |
| 675 // markMisspellingsAndBadGrammar() is triggered by selection change, in
which case we check spelling and grammar, but don't autocorrect misspellings. | |
| 676 TextCheckingTypeMask textCheckingOptions = TextCheckingTypeSpelling; | |
| 677 if (markGrammar) | |
| 678 textCheckingOptions |= TextCheckingTypeGrammar; | |
| 679 markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, spellingSe
lection.toNormalizedEphemeralRange(), grammarSelection.toNormalizedEphemeralRang
e()); | |
| 680 return; | |
| 681 } | |
| 682 | |
| 683 markMisspellings(spellingSelection); | |
| 684 if (markGrammar) | |
| 685 markBadGrammar(grammarSelection); | |
| 686 } | |
| 687 | |
| 688 void SpellChecker::updateMarkersForWordsAffectedByEditing(bool doNotRemoveIfSele
ctionAtWordBoundary) | 548 void SpellChecker::updateMarkersForWordsAffectedByEditing(bool doNotRemoveIfSele
ctionAtWordBoundary) |
| 689 { | 549 { |
| 690 DCHECK(frame().selection().isAvailable()); | 550 DCHECK(frame().selection().isAvailable()); |
| 691 TRACE_EVENT0("blink", "SpellChecker::updateMarkersForWordsAffectedByEditing"
); | 551 TRACE_EVENT0("blink", "SpellChecker::updateMarkersForWordsAffectedByEditing"
); |
| 692 if (!isSpellCheckingEnabledFor(frame().selection().selection())) | 552 if (!isSpellCheckingEnabledFor(frame().selection().selection())) |
| 693 return; | 553 return; |
| 694 | 554 |
| 695 // We want to remove the markers from a word if an editing command will chan
ge the word. This can happen in one of | 555 // We want to remove the markers from a word if an editing command will chan
ge the word. This can happen in one of |
| 696 // several scenarios: | 556 // several scenarios: |
| 697 // 1. Insert in the middle of a word. | 557 // 1. Insert in the middle of a word. |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 770 void SpellChecker::didEndEditingOnTextField(Element* e) | 630 void SpellChecker::didEndEditingOnTextField(Element* e) |
| 771 { | 631 { |
| 772 TRACE_EVENT0("blink", "SpellChecker::didEndEditingOnTextField"); | 632 TRACE_EVENT0("blink", "SpellChecker::didEndEditingOnTextField"); |
| 773 | 633 |
| 774 // Remove markers when deactivating a selection in an <input type="text"/>. | 634 // Remove markers when deactivating a selection in an <input type="text"/>. |
| 775 // Prevent new ones from appearing too. | 635 // Prevent new ones from appearing too. |
| 776 m_spellCheckRequester->cancelCheck(); | 636 m_spellCheckRequester->cancelCheck(); |
| 777 HTMLTextFormControlElement* textFormControlElement = toHTMLTextFormControlEl
ement(e); | 637 HTMLTextFormControlElement* textFormControlElement = toHTMLTextFormControlEl
ement(e); |
| 778 HTMLElement* innerEditor = textFormControlElement->innerEditorElement(); | 638 HTMLElement* innerEditor = textFormControlElement->innerEditorElement(); |
| 779 DocumentMarker::MarkerTypes markerTypes(DocumentMarker::Spelling); | 639 DocumentMarker::MarkerTypes markerTypes(DocumentMarker::Spelling); |
| 780 if (unifiedTextCheckerEnabled()) | |
| 781 markerTypes.add(DocumentMarker::Grammar); | |
| 782 for (Node& node : NodeTraversal::inclusiveDescendantsOf(*innerEditor)) | 640 for (Node& node : NodeTraversal::inclusiveDescendantsOf(*innerEditor)) |
| 783 frame().document()->markers().removeMarkers(&node, markerTypes); | 641 frame().document()->markers().removeMarkers(&node, markerTypes); |
| 784 } | 642 } |
| 785 | 643 |
| 786 void SpellChecker::replaceMisspelledRange(const String& text) | 644 void SpellChecker::replaceMisspelledRange(const String& text) |
| 787 { | 645 { |
| 788 EphemeralRange caretRange = frame().selection().selection().toNormalizedEphe
meralRange(); | 646 EphemeralRange caretRange = frame().selection().selection().toNormalizedEphe
meralRange(); |
| 789 if (caretRange.isNull()) | 647 if (caretRange.isNull()) |
| 790 return; | 648 return; |
| 791 DocumentMarkerVector markers = frame().document()->markers().markersInRange(
caretRange, DocumentMarker::MisspellingMarkers()); | 649 DocumentMarkerVector markers = frame().document()->markers().markersInRange(
caretRange, DocumentMarker::MisspellingMarkers()); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 812 | 670 |
| 813 void SpellChecker::respondToChangedSelection(const VisibleSelection& oldSelectio
n, FrameSelection::SetSelectionOptions options) | 671 void SpellChecker::respondToChangedSelection(const VisibleSelection& oldSelectio
n, FrameSelection::SetSelectionOptions options) |
| 814 { | 672 { |
| 815 TRACE_EVENT0("blink", "SpellChecker::respondToChangedSelection"); | 673 TRACE_EVENT0("blink", "SpellChecker::respondToChangedSelection"); |
| 816 if (!isSpellCheckingEnabledFor(oldSelection)) | 674 if (!isSpellCheckingEnabledFor(oldSelection)) |
| 817 return; | 675 return; |
| 818 | 676 |
| 819 // When continuous spell checking is off, existing markers disappear after t
he selection changes. | 677 // When continuous spell checking is off, existing markers disappear after t
he selection changes. |
| 820 if (!isContinuousSpellCheckingEnabled()) { | 678 if (!isContinuousSpellCheckingEnabled()) { |
| 821 frame().document()->markers().removeMarkers(DocumentMarker::Spelling); | 679 frame().document()->markers().removeMarkers(DocumentMarker::Spelling); |
| 822 frame().document()->markers().removeMarkers(DocumentMarker::Grammar); | |
| 823 return; | 680 return; |
| 824 } | 681 } |
| 825 | 682 |
| 826 if (!(options & FrameSelection::CloseTyping)) | 683 if (!(options & FrameSelection::CloseTyping)) |
| 827 return; | 684 return; |
| 828 if (!shouldCheckOldSelection(oldSelection)) | 685 if (!shouldCheckOldSelection(oldSelection)) |
| 829 return; | 686 return; |
| 830 | 687 |
| 831 VisibleSelection newAdjacentWords; | 688 VisibleSelection newAdjacentWords; |
| 832 const VisibleSelection newSelection = frame().selection().selection(); | 689 const VisibleSelection newSelection = frame().selection().selection(); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 879 } | 736 } |
| 880 | 737 |
| 881 void SpellChecker::spellCheckOldSelection(const VisibleSelection& oldSelection,
const VisibleSelection& newAdjacentWords) | 738 void SpellChecker::spellCheckOldSelection(const VisibleSelection& oldSelection,
const VisibleSelection& newAdjacentWords) |
| 882 { | 739 { |
| 883 TRACE_EVENT0("blink", "SpellChecker::spellCheckOldSelection"); | 740 TRACE_EVENT0("blink", "SpellChecker::spellCheckOldSelection"); |
| 884 | 741 |
| 885 VisiblePosition oldStart(oldSelection.visibleStart()); | 742 VisiblePosition oldStart(oldSelection.visibleStart()); |
| 886 VisibleSelection oldAdjacentWords = VisibleSelection(startOfWord(oldStart, L
eftWordIfOnBoundary), endOfWord(oldStart, RightWordIfOnBoundary)); | 743 VisibleSelection oldAdjacentWords = VisibleSelection(startOfWord(oldStart, L
eftWordIfOnBoundary), endOfWord(oldStart, RightWordIfOnBoundary)); |
| 887 if (oldAdjacentWords == newAdjacentWords) | 744 if (oldAdjacentWords == newAdjacentWords) |
| 888 return; | 745 return; |
| 889 if (isContinuousSpellCheckingEnabled()) { | 746 |
| 890 VisibleSelection selectedSentence = VisibleSelection(startOfSentence(old
Start), endOfSentence(oldStart)); | 747 markMisspellingsAndBadGrammar(oldAdjacentWords); |
| 891 markMisspellingsAndBadGrammar(oldAdjacentWords, true, selectedSentence); | |
| 892 return; | |
| 893 } | |
| 894 markMisspellingsAndBadGrammar(oldAdjacentWords, false, oldAdjacentWords); | |
| 895 } | 748 } |
| 896 | 749 |
| 897 static Node* findFirstMarkable(Node* node) | 750 static Node* findFirstMarkable(Node* node) |
| 898 { | 751 { |
| 899 while (node) { | 752 while (node) { |
| 900 if (!node->layoutObject()) | 753 if (!node->layoutObject()) |
| 901 return 0; | 754 return 0; |
| 902 if (node->layoutObject()->isText()) | 755 if (node->layoutObject()->isText()) |
| 903 return node; | 756 return node; |
| 904 if (node->layoutObject()->isTextControl()) | 757 if (node->layoutObject()->isTextControl()) |
| (...skipping 23 matching lines...) Expand all Loading... |
| 928 } | 781 } |
| 929 | 782 |
| 930 return false; | 783 return false; |
| 931 } | 784 } |
| 932 | 785 |
| 933 bool SpellChecker::selectionStartHasSpellingMarkerFor(int from, int length) cons
t | 786 bool SpellChecker::selectionStartHasSpellingMarkerFor(int from, int length) cons
t |
| 934 { | 787 { |
| 935 return selectionStartHasMarkerFor(DocumentMarker::Spelling, from, length); | 788 return selectionStartHasMarkerFor(DocumentMarker::Spelling, from, length); |
| 936 } | 789 } |
| 937 | 790 |
| 938 TextCheckingTypeMask SpellChecker::resolveTextCheckingTypeMask(TextCheckingTypeM
ask textCheckingOptions) | |
| 939 { | |
| 940 bool shouldMarkSpelling = textCheckingOptions & TextCheckingTypeSpelling; | |
| 941 bool shouldMarkGrammar = textCheckingOptions & TextCheckingTypeGrammar; | |
| 942 | |
| 943 TextCheckingTypeMask checkingTypes = 0; | |
| 944 if (shouldMarkSpelling) | |
| 945 checkingTypes |= TextCheckingTypeSpelling; | |
| 946 if (shouldMarkGrammar) | |
| 947 checkingTypes |= TextCheckingTypeGrammar; | |
| 948 | |
| 949 return checkingTypes; | |
| 950 } | |
| 951 | |
| 952 void SpellChecker::removeMarkers(const VisibleSelection& selection, DocumentMark
er::MarkerTypes markerTypes) | 791 void SpellChecker::removeMarkers(const VisibleSelection& selection, DocumentMark
er::MarkerTypes markerTypes) |
| 953 { | 792 { |
| 954 const EphemeralRange range = selection.toNormalizedEphemeralRange(); | 793 const EphemeralRange range = selection.toNormalizedEphemeralRange(); |
| 955 if (range.isNull()) | 794 if (range.isNull()) |
| 956 return; | 795 return; |
| 957 frame().document()->markers().removeMarkers(range, markerTypes); | 796 frame().document()->markers().removeMarkers(range, markerTypes); |
| 958 } | 797 } |
| 959 | 798 |
| 960 bool SpellChecker::unifiedTextCheckerEnabled() const | 799 bool SpellChecker::unifiedTextCheckerEnabled() const |
| 961 { | 800 { |
| 962 return blink::unifiedTextCheckerEnabled(m_frame); | 801 return blink::unifiedTextCheckerEnabled(m_frame); |
| 963 } | 802 } |
| 964 | 803 |
| 965 void SpellChecker::cancelCheck() | 804 void SpellChecker::cancelCheck() |
| 966 { | 805 { |
| 967 m_spellCheckRequester->cancelCheck(); | 806 m_spellCheckRequester->cancelCheck(); |
| 968 } | 807 } |
| 969 | 808 |
| 970 void SpellChecker::requestTextChecking(const Element& element) | 809 void SpellChecker::requestTextChecking(const Element& element) |
| 971 { | 810 { |
| 972 const EphemeralRange rangeToCheck = EphemeralRange::rangeOfContents(element)
; | 811 const EphemeralRange rangeToCheck = EphemeralRange::rangeOfContents(element)
; |
| 973 m_spellCheckRequester->requestCheckingFor(SpellCheckRequest::create(TextChec
kingTypeSpelling | TextCheckingTypeGrammar, TextCheckingProcessBatch, rangeToChe
ck, rangeToCheck)); | 812 m_spellCheckRequester->requestCheckingFor(SpellCheckRequest::create(TextChec
kingTypeSpelling, TextCheckingProcessBatch, rangeToCheck, rangeToCheck)); |
| 974 } | 813 } |
| 975 | 814 |
| 976 DEFINE_TRACE(SpellChecker) | 815 DEFINE_TRACE(SpellChecker) |
| 977 { | 816 { |
| 978 visitor->trace(m_frame); | 817 visitor->trace(m_frame); |
| 979 visitor->trace(m_spellCheckRequester); | 818 visitor->trace(m_spellCheckRequester); |
| 980 } | 819 } |
| 981 | 820 |
| 982 void SpellChecker::prepareForLeakDetection() | 821 void SpellChecker::prepareForLeakDetection() |
| 983 { | 822 { |
| 984 m_spellCheckRequester->prepareForLeakDetection(); | 823 m_spellCheckRequester->prepareForLeakDetection(); |
| 985 } | 824 } |
| 986 | 825 |
| 987 } // namespace blink | 826 } // namespace blink |
| OLD | NEW |