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 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
230 int misspellingOffset = 0; | 230 int misspellingOffset = 0; |
231 GrammarDetail grammarDetail; | 231 GrammarDetail grammarDetail; |
232 int grammarPhraseOffset = 0; | 232 int grammarPhraseOffset = 0; |
233 Position grammarSearchStart, grammarSearchEnd; | 233 Position grammarSearchStart, grammarSearchEnd; |
234 String badGrammarPhrase; | 234 String badGrammarPhrase; |
235 String misspelledWord; | 235 String misspelledWord; |
236 | 236 |
237 bool isSpelling = true; | 237 bool isSpelling = true; |
238 int foundOffset = 0; | 238 int foundOffset = 0; |
239 String foundItem; | 239 String foundItem; |
240 RefPtrWillBeRawPtr<Range> firstMisspellingRange = nullptr; | |
241 if (unifiedTextCheckerEnabled()) { | 240 if (unifiedTextCheckerEnabled()) { |
242 grammarSearchStart = spellingSearchStart; | 241 grammarSearchStart = spellingSearchStart; |
243 grammarSearchEnd = spellingSearchEnd; | 242 grammarSearchEnd = spellingSearchEnd; |
244 foundItem = TextCheckingHelper(spellCheckerClient(), spellingSearchStart
, spellingSearchEnd).findFirstMisspellingOrBadGrammar(isGrammarCheckingEnabled()
, isSpelling, foundOffset, grammarDetail); | 243 foundItem = TextCheckingHelper(spellCheckerClient(), spellingSearchStart
, spellingSearchEnd).findFirstMisspellingOrBadGrammar(isGrammarCheckingEnabled()
, isSpelling, foundOffset, grammarDetail); |
245 if (isSpelling) { | 244 if (isSpelling) { |
246 misspelledWord = foundItem; | 245 misspelledWord = foundItem; |
247 misspellingOffset = foundOffset; | 246 misspellingOffset = foundOffset; |
248 } else { | 247 } else { |
249 badGrammarPhrase = foundItem; | 248 badGrammarPhrase = foundItem; |
250 grammarPhraseOffset = foundOffset; | 249 grammarPhraseOffset = foundOffset; |
251 } | 250 } |
252 } else { | 251 } else { |
253 misspelledWord = TextCheckingHelper(spellCheckerClient(), spellingSearch
Start, spellingSearchEnd).findFirstMisspelling(misspellingOffset, false, firstMi
sspellingRange); | 252 misspelledWord = TextCheckingHelper(spellCheckerClient(), spellingSearch
Start, spellingSearchEnd).findFirstMisspelling(misspellingOffset, false); |
254 grammarSearchStart = spellingSearchStart; | 253 grammarSearchStart = spellingSearchStart; |
255 grammarSearchEnd = spellingSearchEnd; | 254 grammarSearchEnd = spellingSearchEnd; |
256 if (!misspelledWord.isEmpty()) { | 255 if (!misspelledWord.isEmpty()) { |
257 // Stop looking at start of next misspelled word | 256 // Stop looking at start of next misspelled word |
258 CharacterIterator chars(grammarSearchStart, grammarSearchEnd); | 257 CharacterIterator chars(grammarSearchStart, grammarSearchEnd); |
259 chars.advance(misspellingOffset); | 258 chars.advance(misspellingOffset); |
260 grammarSearchEnd = chars.startPosition(); | 259 grammarSearchEnd = chars.startPosition(); |
261 } | 260 } |
262 | 261 |
263 if (isGrammarCheckingEnabled()) | 262 if (isGrammarCheckingEnabled()) |
(...skipping 12 matching lines...) Expand all Loading... |
276 grammarSearchEnd = spellingSearchEnd; | 275 grammarSearchEnd = spellingSearchEnd; |
277 foundItem = TextCheckingHelper(spellCheckerClient(), spellingSearchS
tart, spellingSearchEnd).findFirstMisspellingOrBadGrammar(isGrammarCheckingEnabl
ed(), isSpelling, foundOffset, grammarDetail); | 276 foundItem = TextCheckingHelper(spellCheckerClient(), spellingSearchS
tart, spellingSearchEnd).findFirstMisspellingOrBadGrammar(isGrammarCheckingEnabl
ed(), isSpelling, foundOffset, grammarDetail); |
278 if (isSpelling) { | 277 if (isSpelling) { |
279 misspelledWord = foundItem; | 278 misspelledWord = foundItem; |
280 misspellingOffset = foundOffset; | 279 misspellingOffset = foundOffset; |
281 } else { | 280 } else { |
282 badGrammarPhrase = foundItem; | 281 badGrammarPhrase = foundItem; |
283 grammarPhraseOffset = foundOffset; | 282 grammarPhraseOffset = foundOffset; |
284 } | 283 } |
285 } else { | 284 } else { |
286 misspelledWord = TextCheckingHelper(spellCheckerClient(), spellingSe
archStart, spellingSearchEnd).findFirstMisspelling(misspellingOffset, false, fir
stMisspellingRange); | 285 misspelledWord = TextCheckingHelper(spellCheckerClient(), spellingSe
archStart, spellingSearchEnd).findFirstMisspelling(misspellingOffset, false); |
287 grammarSearchStart = spellingSearchStart; | 286 grammarSearchStart = spellingSearchStart; |
288 grammarSearchEnd = spellingSearchEnd; | 287 grammarSearchEnd = spellingSearchEnd; |
289 if (!misspelledWord.isEmpty()) { | 288 if (!misspelledWord.isEmpty()) { |
290 // Stop looking at start of next misspelled word | 289 // Stop looking at start of next misspelled word |
291 CharacterIterator chars(grammarSearchStart, grammarSearchEnd); | 290 CharacterIterator chars(grammarSearchStart, grammarSearchEnd); |
292 chars.advance(misspellingOffset); | 291 chars.advance(misspellingOffset); |
293 grammarSearchEnd = chars.startPosition(); | 292 grammarSearchEnd = chars.startPosition(); |
294 } | 293 } |
295 | 294 |
296 if (isGrammarCheckingEnabled()) | 295 if (isGrammarCheckingEnabled()) |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
343 | 342 |
344 void SpellChecker::markMisspellingsAndBadGrammar(const VisibleSelection &movingS
election) | 343 void SpellChecker::markMisspellingsAndBadGrammar(const VisibleSelection &movingS
election) |
345 { | 344 { |
346 markMisspellingsAndBadGrammar(movingSelection, isContinuousSpellCheckingEnab
led() && isGrammarCheckingEnabled(), movingSelection); | 345 markMisspellingsAndBadGrammar(movingSelection, isContinuousSpellCheckingEnab
led() && isGrammarCheckingEnabled(), movingSelection); |
347 } | 346 } |
348 | 347 |
349 void SpellChecker::markMisspellingsAfterLineBreak(const VisibleSelection& wordSe
lection) | 348 void SpellChecker::markMisspellingsAfterLineBreak(const VisibleSelection& wordSe
lection) |
350 { | 349 { |
351 TRACE_EVENT0("blink", "SpellChecker::markMisspellingsAfterLineBreak"); | 350 TRACE_EVENT0("blink", "SpellChecker::markMisspellingsAfterLineBreak"); |
352 | 351 |
353 if (unifiedTextCheckerEnabled()) { | 352 if (!unifiedTextCheckerEnabled()) { |
354 TextCheckingTypeMask textCheckingOptions = 0; | 353 markMisspellings(wordSelection); |
| 354 return; |
| 355 } |
355 | 356 |
356 if (isContinuousSpellCheckingEnabled()) | 357 TextCheckingTypeMask textCheckingOptions = 0; |
357 textCheckingOptions |= TextCheckingTypeSpelling; | |
358 | 358 |
359 if (isGrammarCheckingEnabled()) | 359 if (isContinuousSpellCheckingEnabled()) |
360 textCheckingOptions |= TextCheckingTypeGrammar; | 360 textCheckingOptions |= TextCheckingTypeSpelling; |
361 | 361 |
362 VisibleSelection wholeParagraph( | 362 if (isGrammarCheckingEnabled()) |
363 startOfParagraph(wordSelection.visibleStart()), | 363 textCheckingOptions |= TextCheckingTypeGrammar; |
364 endOfParagraph(wordSelection.visibleEnd())); | |
365 | 364 |
366 markAllMisspellingsAndBadGrammarInRanges( | 365 VisibleSelection wholeParagraph( |
367 textCheckingOptions, wordSelection.toNormalizedEphemeralRange(), | 366 startOfParagraph(wordSelection.visibleStart()), |
368 wholeParagraph.toNormalizedEphemeralRange()); | 367 endOfParagraph(wordSelection.visibleEnd())); |
369 } else { | 368 |
370 RefPtrWillBeRawPtr<Range> misspellingRange = nullptr; | 369 markAllMisspellingsAndBadGrammarInRanges( |
371 markMisspellings(wordSelection, misspellingRange); | 370 textCheckingOptions, wordSelection.toNormalizedEphemeralRange(), |
372 } | 371 wholeParagraph.toNormalizedEphemeralRange()); |
373 } | 372 } |
374 | 373 |
375 void SpellChecker::markMisspellingsAfterTypingToWord(const VisiblePosition &word
Start, const VisibleSelection& selectionAfterTyping) | 374 void SpellChecker::markMisspellingsAfterTypingToWord(const VisiblePosition &word
Start, const VisibleSelection& selectionAfterTyping) |
376 { | 375 { |
377 TRACE_EVENT0("blink", "SpellChecker::markMisspellingsAfterTypingToWord"); | 376 TRACE_EVENT0("blink", "SpellChecker::markMisspellingsAfterTypingToWord"); |
378 | 377 |
379 if (unifiedTextCheckerEnabled()) { | 378 if (unifiedTextCheckerEnabled()) { |
380 TextCheckingTypeMask textCheckingOptions = 0; | 379 TextCheckingTypeMask textCheckingOptions = 0; |
381 | 380 |
382 if (isContinuousSpellCheckingEnabled()) | 381 if (isContinuousSpellCheckingEnabled()) |
(...skipping 12 matching lines...) Expand all Loading... |
395 } else { | 394 } else { |
396 markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, adjace
ntWords.toNormalizedEphemeralRange(), adjacentWords.toNormalizedEphemeralRange()
); | 395 markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, adjace
ntWords.toNormalizedEphemeralRange(), adjacentWords.toNormalizedEphemeralRange()
); |
397 } | 396 } |
398 return; | 397 return; |
399 } | 398 } |
400 | 399 |
401 if (!isContinuousSpellCheckingEnabled()) | 400 if (!isContinuousSpellCheckingEnabled()) |
402 return; | 401 return; |
403 | 402 |
404 // Check spelling of one word | 403 // Check spelling of one word |
405 RefPtrWillBeRawPtr<Range> misspellingRange = nullptr; | 404 bool result = markMisspellings(VisibleSelection(startOfWord(wordStart, LeftW
ordIfOnBoundary), endOfWord(wordStart, RightWordIfOnBoundary))); |
406 markMisspellings(VisibleSelection(startOfWord(wordStart, LeftWordIfOnBoundar
y), endOfWord(wordStart, RightWordIfOnBoundary)), misspellingRange); | |
407 | 405 |
408 if (!misspellingRange || !isGrammarCheckingEnabled()) | 406 if (!result || !isGrammarCheckingEnabled()) |
409 return; | 407 return; |
410 | 408 |
411 // Check grammar of entire sentence | 409 // Check grammar of entire sentence |
412 markBadGrammar(VisibleSelection(startOfSentence(wordStart), endOfSentence(wo
rdStart))); | 410 markBadGrammar(VisibleSelection(startOfSentence(wordStart), endOfSentence(wo
rdStart))); |
413 } | 411 } |
414 | 412 |
415 void SpellChecker::markMisspellingsOrBadGrammar(const VisibleSelection& selectio
n, bool checkSpelling, RefPtrWillBeRawPtr<Range>& firstMisspellingRange) | 413 bool SpellChecker::markMisspellingsOrBadGrammar(const VisibleSelection& selectio
n, bool checkSpelling) |
416 { | 414 { |
417 // This function is called with a selection already expanded to word boundar
ies. | 415 // This function is called with a selection already expanded to word boundar
ies. |
418 // Might be nice to assert that here. | 416 // Might be nice to assert that here. |
419 | 417 |
420 // This function is used only for as-you-type checking, so if that's off we
do nothing. Note that | 418 // This function is used only for as-you-type checking, so if that's off we
do nothing. Note that |
421 // grammar checking can only be on if spell checking is also on. | 419 // grammar checking can only be on if spell checking is also on. |
422 if (!isContinuousSpellCheckingEnabled()) | 420 if (!isContinuousSpellCheckingEnabled()) |
423 return; | 421 return false; |
424 | 422 |
425 TRACE_EVENT0("blink", "SpellChecker::markMisspellingsOrBadGrammar"); | 423 TRACE_EVENT0("blink", "SpellChecker::markMisspellingsOrBadGrammar"); |
426 | 424 |
427 const EphemeralRange range = selection.toNormalizedEphemeralRange(); | 425 const EphemeralRange range = selection.toNormalizedEphemeralRange(); |
428 if (range.isNull()) | 426 if (range.isNull()) |
429 return; | 427 return false; |
430 | 428 |
431 // If we're not in an editable node, bail. | 429 // If we're not in an editable node, bail. |
432 Node* editableNode = range.startPosition().computeContainerNode(); | 430 Node* editableNode = range.startPosition().computeContainerNode(); |
433 if (!editableNode || !editableNode->hasEditableStyle()) | 431 if (!editableNode || !editableNode->hasEditableStyle()) |
434 return; | 432 return false; |
435 | 433 |
436 if (!isSpellCheckingEnabledFor(editableNode)) | 434 if (!isSpellCheckingEnabledFor(editableNode)) |
437 return; | 435 return false; |
438 | 436 |
439 TextCheckingHelper checker(spellCheckerClient(), range.startPosition(), rang
e.endPosition()); | 437 TextCheckingHelper checker(spellCheckerClient(), range.startPosition(), rang
e.endPosition()); |
440 if (checkSpelling) | 438 if (checkSpelling) |
441 checker.markAllMisspellings(firstMisspellingRange); | 439 return checker.markAllMisspellings(); |
442 else if (isGrammarCheckingEnabled()) | 440 |
| 441 if (isGrammarCheckingEnabled()) |
443 checker.markAllBadGrammar(); | 442 checker.markAllBadGrammar(); |
| 443 return false; |
444 } | 444 } |
445 | 445 |
446 bool SpellChecker::isSpellCheckingEnabledFor(Node* node) const | 446 bool SpellChecker::isSpellCheckingEnabledFor(Node* node) const |
447 { | 447 { |
448 if (!node) | 448 if (!node) |
449 return false; | 449 return false; |
450 const Element* focusedElement = node->isElementNode() ? toElement(node) : no
de->parentElement(); | 450 const Element* focusedElement = node->isElementNode() ? toElement(node) : no
de->parentElement(); |
451 if (!focusedElement) | 451 if (!focusedElement) |
452 return false; | 452 return false; |
453 return focusedElement->isSpellCheckingEnabled(); | 453 return focusedElement->isSpellCheckingEnabled(); |
454 } | 454 } |
455 | 455 |
456 bool SpellChecker::isSpellCheckingEnabledInFocusedNode() const | 456 bool SpellChecker::isSpellCheckingEnabledInFocusedNode() const |
457 { | 457 { |
458 return isSpellCheckingEnabledFor(frame().selection().start().anchorNode()); | 458 return isSpellCheckingEnabledFor(frame().selection().start().anchorNode()); |
459 } | 459 } |
460 | 460 |
461 void SpellChecker::markMisspellings(const VisibleSelection& selection, RefPtrWil
lBeRawPtr<Range>& firstMisspellingRange) | 461 bool SpellChecker::markMisspellings(const VisibleSelection& selection) |
462 { | 462 { |
463 markMisspellingsOrBadGrammar(selection, true, firstMisspellingRange); | 463 return markMisspellingsOrBadGrammar(selection, true); |
464 } | 464 } |
465 | 465 |
466 void SpellChecker::markBadGrammar(const VisibleSelection& selection) | 466 void SpellChecker::markBadGrammar(const VisibleSelection& selection) |
467 { | 467 { |
468 RefPtrWillBeRawPtr<Range> firstMisspellingRange = nullptr; | 468 markMisspellingsOrBadGrammar(selection, false); |
469 markMisspellingsOrBadGrammar(selection, false, firstMisspellingRange); | |
470 } | 469 } |
471 | 470 |
472 void SpellChecker::markAllMisspellingsAndBadGrammarInRanges(TextCheckingTypeMask
textCheckingOptions, const EphemeralRange& spellingRange, const EphemeralRange&
grammarRange) | 471 void SpellChecker::markAllMisspellingsAndBadGrammarInRanges(TextCheckingTypeMask
textCheckingOptions, const EphemeralRange& spellingRange, const EphemeralRange&
grammarRange) |
473 { | 472 { |
474 ASSERT(unifiedTextCheckerEnabled()); | 473 ASSERT(unifiedTextCheckerEnabled()); |
475 | 474 |
476 bool shouldMarkGrammar = textCheckingOptions & TextCheckingTypeGrammar; | 475 bool shouldMarkGrammar = textCheckingOptions & TextCheckingTypeGrammar; |
477 | 476 |
478 // This function is called with selections already expanded to word boundari
es. | 477 // This function is called with selections already expanded to word boundari
es. |
479 if (spellingRange.isNull() || (shouldMarkGrammar && grammarRange.isNull())) | 478 if (spellingRange.isNull() || (shouldMarkGrammar && grammarRange.isNull())) |
480 return; | 479 return; |
481 | 480 |
482 // If we're not in an editable node, bail. | 481 // If we're not in an editable node, bail. |
483 Node* editableNode = spellingRange.startPosition().computeContainerNode(); | 482 Node* editableNode = spellingRange.startPosition().computeContainerNode(); |
484 if (!editableNode || !editableNode->hasEditableStyle()) | 483 if (!editableNode || !editableNode->hasEditableStyle()) |
485 return; | 484 return; |
486 | 485 |
487 if (!isSpellCheckingEnabledFor(editableNode)) | 486 if (!isSpellCheckingEnabledFor(editableNode)) |
488 return; | 487 return; |
489 | 488 |
490 RefPtrWillBeRawPtr<Range> rangeToCheck = createRange(shouldMarkGrammar ? gra
mmarRange : spellingRange); | 489 TextCheckingParagraph fullParagraphToCheck(shouldMarkGrammar ? grammarRange
: spellingRange); |
491 TextCheckingParagraph fullParagraphToCheck(rangeToCheck); | |
492 | 490 |
493 bool asynchronous = frame().settings() && frame().settings()->asynchronousSp
ellCheckingEnabled(); | 491 bool asynchronous = frame().settings() && frame().settings()->asynchronousSp
ellCheckingEnabled(); |
494 chunkAndMarkAllMisspellingsAndBadGrammar(textCheckingOptions, fullParagraphT
oCheck, asynchronous); | 492 chunkAndMarkAllMisspellingsAndBadGrammar(textCheckingOptions, fullParagraphT
oCheck, asynchronous); |
495 } | 493 } |
496 | 494 |
497 void SpellChecker::chunkAndMarkAllMisspellingsAndBadGrammar(Node* node) | 495 void SpellChecker::chunkAndMarkAllMisspellingsAndBadGrammar(Node* node) |
498 { | 496 { |
499 TRACE_EVENT0("blink", "SpellChecker::chunkAndMarkAllMisspellingsAndBadGramma
r"); | 497 TRACE_EVENT0("blink", "SpellChecker::chunkAndMarkAllMisspellingsAndBadGramma
r"); |
500 if (!node) | 498 if (!node) |
501 return; | 499 return; |
502 RefPtrWillBeRawPtr<Range> rangeToCheck = Range::create(*frame().document(),
firstPositionInNode(node), lastPositionInNode(node)); | 500 RefPtrWillBeRawPtr<Range> rangeToCheck = Range::create(*frame().document(),
firstPositionInNode(node), lastPositionInNode(node)); |
503 TextCheckingParagraph textToCheck(rangeToCheck, rangeToCheck); | 501 TextCheckingParagraph textToCheck(rangeToCheck, rangeToCheck); |
504 bool asynchronous = true; | 502 bool asynchronous = true; |
505 chunkAndMarkAllMisspellingsAndBadGrammar(resolveTextCheckingTypeMask(TextChe
ckingTypeSpelling | TextCheckingTypeGrammar), textToCheck, asynchronous); | 503 chunkAndMarkAllMisspellingsAndBadGrammar(resolveTextCheckingTypeMask(TextChe
ckingTypeSpelling | TextCheckingTypeGrammar), textToCheck, asynchronous); |
506 } | 504 } |
507 | 505 |
508 void SpellChecker::chunkAndMarkAllMisspellingsAndBadGrammar(TextCheckingTypeMask
textCheckingOptions, const TextCheckingParagraph& fullParagraphToCheck, bool as
ynchronous) | 506 void SpellChecker::chunkAndMarkAllMisspellingsAndBadGrammar(TextCheckingTypeMask
textCheckingOptions, const TextCheckingParagraph& fullParagraphToCheck, bool as
ynchronous) |
509 { | 507 { |
510 if (fullParagraphToCheck.isEmpty()) | 508 if (fullParagraphToCheck.isEmpty()) |
511 return; | 509 return; |
512 | 510 |
513 // Since the text may be quite big chunk it up and adjust to the sentence bo
undary. | 511 // Since the text may be quite big chunk it up and adjust to the sentence bo
undary. |
514 const int kChunkSize = 16 * 1024; | 512 const int kChunkSize = 16 * 1024; |
515 int start = fullParagraphToCheck.checkingStart(); | 513 int start = fullParagraphToCheck.checkingStart(); |
516 int end = fullParagraphToCheck.checkingEnd(); | 514 int end = fullParagraphToCheck.checkingEnd(); |
517 start = std::min(start, end); | 515 start = std::min(start, end); |
518 end = std::max(start, end); | 516 end = std::max(start, end); |
519 const int kNumChunksToCheck = asynchronous ? (end - start + kChunkSize - 1)
/ (kChunkSize) : 1; | 517 const int kNumChunksToCheck = asynchronous ? (end - start + kChunkSize - 1)
/ (kChunkSize) : 1; |
520 int currentChunkStart = start; | 518 int currentChunkStart = start; |
521 RefPtrWillBeRawPtr<Range> checkRange = fullParagraphToCheck.checkingRange(); | |
522 if (kNumChunksToCheck == 1 && asynchronous) { | 519 if (kNumChunksToCheck == 1 && asynchronous) { |
523 markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, checkRange
.get(), checkRange.get(), asynchronous, 0); | 520 EphemeralRange checkRange = fullParagraphToCheck.checkingRange(); |
| 521 markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, checkRange
, checkRange, asynchronous, 0); |
524 return; | 522 return; |
525 } | 523 } |
526 | 524 |
527 for (int iter = 0; iter < kNumChunksToCheck; ++iter) { | 525 for (int iter = 0; iter < kNumChunksToCheck; ++iter) { |
528 checkRange = fullParagraphToCheck.subrange(currentChunkStart, kChunkSize
); | 526 EphemeralRange checkRange = expandRangeToSentenceBoundary(fullParagraphT
oCheck.subrange(currentChunkStart, kChunkSize)); |
529 expandRangeToSentenceBoundary(*checkRange); | |
530 | 527 |
531 int checkingLength = 0; | 528 int checkingLength = 0; |
532 markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, checkRange
.get(), checkRange.get(), asynchronous, iter, &checkingLength); | 529 markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, checkRange
, checkRange, asynchronous, iter, &checkingLength); |
533 currentChunkStart += checkingLength; | 530 currentChunkStart += checkingLength; |
534 } | 531 } |
535 } | 532 } |
536 | 533 |
537 void SpellChecker::markAllMisspellingsAndBadGrammarInRanges(TextCheckingTypeMask
textCheckingOptions, Range* checkRange, Range* paragraphRange, bool asynchronou
s, int requestNumber, int* checkingLength) | 534 void SpellChecker::markAllMisspellingsAndBadGrammarInRanges(TextCheckingTypeMask
textCheckingOptions, const EphemeralRange& checkRange, const EphemeralRange& pa
ragraphRange, bool asynchronous, int requestNumber, int* checkingLength) |
538 { | 535 { |
539 TextCheckingParagraph sentenceToCheck(checkRange, paragraphRange); | 536 TextCheckingParagraph sentenceToCheck(checkRange, paragraphRange); |
540 if (checkingLength) | 537 if (checkingLength) |
541 *checkingLength = sentenceToCheck.checkingLength(); | 538 *checkingLength = sentenceToCheck.checkingLength(); |
542 | 539 |
543 RefPtrWillBeRawPtr<SpellCheckRequest> request = SpellCheckRequest::create(re
solveTextCheckingTypeMask(textCheckingOptions), TextCheckingProcessBatch, checkR
ange, paragraphRange, requestNumber); | 540 RefPtrWillBeRawPtr<SpellCheckRequest> request = SpellCheckRequest::create(re
solveTextCheckingTypeMask(textCheckingOptions), TextCheckingProcessBatch, create
Range(checkRange), createRange(paragraphRange), requestNumber); |
544 if (!request) | 541 if (!request) |
545 return; | 542 return; |
546 | 543 |
547 if (asynchronous) { | 544 if (asynchronous) { |
548 m_spellCheckRequester->requestCheckingFor(request); | 545 m_spellCheckRequester->requestCheckingFor(request); |
549 } else { | 546 return; |
550 Vector<TextCheckingResult> results; | |
551 checkTextOfParagraph(textChecker(), sentenceToCheck.text(), resolveTextC
heckingTypeMask(textCheckingOptions), results); | |
552 markAndReplaceFor(request, results); | |
553 } | 547 } |
| 548 |
| 549 Vector<TextCheckingResult> results; |
| 550 checkTextOfParagraph(textChecker(), sentenceToCheck.text(), resolveTextCheck
ingTypeMask(textCheckingOptions), results); |
| 551 markAndReplaceFor(request, results); |
554 } | 552 } |
555 | 553 |
556 void SpellChecker::markAndReplaceFor(PassRefPtrWillBeRawPtr<SpellCheckRequest> r
equest, const Vector<TextCheckingResult>& results) | 554 void SpellChecker::markAndReplaceFor(PassRefPtrWillBeRawPtr<SpellCheckRequest> r
equest, const Vector<TextCheckingResult>& results) |
557 { | 555 { |
558 TRACE_EVENT0("blink", "SpellChecker::markAndReplaceFor"); | 556 TRACE_EVENT0("blink", "SpellChecker::markAndReplaceFor"); |
559 ASSERT(request); | 557 ASSERT(request); |
560 | 558 |
561 TextCheckingTypeMask textCheckingOptions = request->data().mask(); | 559 TextCheckingTypeMask textCheckingOptions = request->data().mask(); |
562 TextCheckingParagraph paragraph(request->checkingRange(), request->paragraph
Range()); | 560 TextCheckingParagraph paragraph(request->checkingRange(), request->paragraph
Range()); |
563 | 561 |
564 bool shouldMarkSpelling = textCheckingOptions & TextCheckingTypeSpelling; | 562 bool shouldMarkSpelling = textCheckingOptions & TextCheckingTypeSpelling; |
565 bool shouldMarkGrammar = textCheckingOptions & TextCheckingTypeGrammar; | 563 bool shouldMarkGrammar = textCheckingOptions & TextCheckingTypeGrammar; |
566 | 564 |
567 // Expand the range to encompass entire paragraphs, since text checking need
s that much context. | 565 // Expand the range to encompass entire paragraphs, since text checking need
s that much context. |
568 int selectionOffset = 0; | 566 int selectionOffset = 0; |
569 int ambiguousBoundaryOffset = -1; | 567 int ambiguousBoundaryOffset = -1; |
570 bool selectionChanged = false; | 568 bool selectionChanged = false; |
571 bool restoreSelectionAfterChange = false; | 569 bool restoreSelectionAfterChange = false; |
572 bool adjustSelectionForParagraphBoundaries = false; | 570 bool adjustSelectionForParagraphBoundaries = false; |
573 | 571 |
574 if (shouldMarkSpelling) { | 572 if (shouldMarkSpelling) { |
575 if (frame().selection().isCaret()) { | 573 if (frame().selection().isCaret()) { |
576 // Attempt to save the caret position so we can restore it later if
needed | 574 // Attempt to save the caret position so we can restore it later if
needed |
577 Position caretPosition = frame().selection().end(); | 575 Position caretPosition = frame().selection().end(); |
578 selectionOffset = paragraph.offsetTo(caretPosition, ASSERT_NO_EXCEPT
ION); | 576 selectionOffset = paragraph.offsetTo(caretPosition); |
579 restoreSelectionAfterChange = true; | 577 restoreSelectionAfterChange = true; |
580 if (selectionOffset > 0 && (static_cast<unsigned>(selectionOffset) >
paragraph.text().length() || paragraph.textCharAt(selectionOffset - 1) == newli
neCharacter)) | 578 if (selectionOffset > 0 && (static_cast<unsigned>(selectionOffset) >
paragraph.text().length() || paragraph.textCharAt(selectionOffset - 1) == newli
neCharacter)) |
581 adjustSelectionForParagraphBoundaries = true; | 579 adjustSelectionForParagraphBoundaries = true; |
582 if (selectionOffset > 0 && static_cast<unsigned>(selectionOffset) <=
paragraph.text().length() && isAmbiguousBoundaryCharacter(paragraph.textCharAt(
selectionOffset - 1))) | 580 if (selectionOffset > 0 && static_cast<unsigned>(selectionOffset) <=
paragraph.text().length() && isAmbiguousBoundaryCharacter(paragraph.textCharAt(
selectionOffset - 1))) |
583 ambiguousBoundaryOffset = selectionOffset - 1; | 581 ambiguousBoundaryOffset = selectionOffset - 1; |
584 } | 582 } |
585 } | 583 } |
586 | 584 |
587 for (unsigned i = 0; i < results.size(); i++) { | 585 for (unsigned i = 0; i < results.size(); i++) { |
588 int spellingRangeEndOffset = paragraph.checkingEnd(); | 586 int spellingRangeEndOffset = paragraph.checkingEnd(); |
589 const TextCheckingResult* result = &results[i]; | 587 const TextCheckingResult* result = &results[i]; |
590 int resultLocation = result->location + paragraph.checkingStart(); | 588 int resultLocation = result->location + paragraph.checkingStart(); |
591 int resultLength = result->length; | 589 int resultLength = result->length; |
592 bool resultEndsAtAmbiguousBoundary = ambiguousBoundaryOffset >= 0 && res
ultLocation + resultLength == ambiguousBoundaryOffset; | 590 bool resultEndsAtAmbiguousBoundary = ambiguousBoundaryOffset >= 0 && res
ultLocation + resultLength == ambiguousBoundaryOffset; |
593 | 591 |
594 // Only mark misspelling if: | 592 // Only mark misspelling if: |
595 // 1. Current text checking isn't done for autocorrection, in which case
shouldMarkSpelling is false. | 593 // 1. Current text checking isn't done for autocorrection, in which case
shouldMarkSpelling is false. |
596 // 2. Result falls within spellingRange. | 594 // 2. Result falls within spellingRange. |
597 // 3. The word in question doesn't end at an ambiguous boundary. For ins
tance, we would not mark | 595 // 3. The word in question doesn't end at an ambiguous boundary. For ins
tance, we would not mark |
598 // "wouldn'" as misspelled right after apostrophe is typed. | 596 // "wouldn'" as misspelled right after apostrophe is typed. |
599 if (shouldMarkSpelling && result->decoration == TextDecorationTypeSpelli
ng && resultLocation >= paragraph.checkingStart() && resultLocation + resultLeng
th <= spellingRangeEndOffset && !resultEndsAtAmbiguousBoundary) { | 597 if (shouldMarkSpelling && result->decoration == TextDecorationTypeSpelli
ng && resultLocation >= paragraph.checkingStart() && resultLocation + resultLeng
th <= spellingRangeEndOffset && !resultEndsAtAmbiguousBoundary) { |
600 ASSERT(resultLength > 0 && resultLocation >= 0); | 598 ASSERT(resultLength > 0 && resultLocation >= 0); |
601 const EphemeralRange misspellingRange = calculateCharacterSubrange(E
phemeralRange(paragraph.paragraphRange().get()), resultLocation, resultLength); | 599 const EphemeralRange misspellingRange = calculateCharacterSubrange(p
aragraph.paragraphRange(), resultLocation, resultLength); |
602 frame().document()->markers().addMarker(misspellingRange.startPositi
on(), misspellingRange.endPosition(), DocumentMarker::Spelling, result->replacem
ent, result->hash); | 600 frame().document()->markers().addMarker(misspellingRange.startPositi
on(), misspellingRange.endPosition(), DocumentMarker::Spelling, result->replacem
ent, result->hash); |
603 } else if (shouldMarkGrammar && result->decoration == TextDecorationType
Grammar && paragraph.checkingRangeCovers(resultLocation, resultLength)) { | 601 } else if (shouldMarkGrammar && result->decoration == TextDecorationType
Grammar && paragraph.checkingRangeCovers(resultLocation, resultLength)) { |
604 ASSERT(resultLength > 0 && resultLocation >= 0); | 602 ASSERT(resultLength > 0 && resultLocation >= 0); |
605 for (unsigned j = 0; j < result->details.size(); j++) { | 603 for (unsigned j = 0; j < result->details.size(); j++) { |
606 const GrammarDetail* detail = &result->details[j]; | 604 const GrammarDetail* detail = &result->details[j]; |
607 ASSERT(detail->length > 0 && detail->location >= 0); | 605 ASSERT(detail->length > 0 && detail->location >= 0); |
608 if (paragraph.checkingRangeCovers(resultLocation + detail->locat
ion, detail->length)) { | 606 if (paragraph.checkingRangeCovers(resultLocation + detail->locat
ion, detail->length)) { |
609 const EphemeralRange badGrammarRange = calculateCharacterSub
range(EphemeralRange(paragraph.paragraphRange().get()), resultLocation + detail-
>location, detail->length); | 607 const EphemeralRange badGrammarRange = calculateCharacterSub
range(paragraph.paragraphRange(), resultLocation + detail->location, detail->len
gth); |
610 frame().document()->markers().addMarker(badGrammarRange.star
tPosition(), badGrammarRange.endPosition(), DocumentMarker::Grammar, detail->use
rDescription, result->hash); | 608 frame().document()->markers().addMarker(badGrammarRange.star
tPosition(), badGrammarRange.endPosition(), DocumentMarker::Grammar, detail->use
rDescription, result->hash); |
611 } | 609 } |
612 } | 610 } |
613 } else if (result->decoration == TextDecorationTypeInvisibleSpellcheck &
& resultLocation >= paragraph.checkingStart() && resultLocation + resultLength <
= spellingRangeEndOffset) { | 611 } else if (result->decoration == TextDecorationTypeInvisibleSpellcheck &
& resultLocation >= paragraph.checkingStart() && resultLocation + resultLength <
= spellingRangeEndOffset) { |
614 ASSERT(resultLength > 0 && resultLocation >= 0); | 612 ASSERT(resultLength > 0 && resultLocation >= 0); |
615 const EphemeralRange invisibleSpellcheckRange = calculateCharacterSu
brange(EphemeralRange(paragraph.paragraphRange().get()), resultLocation, resultL
ength); | 613 const EphemeralRange invisibleSpellcheckRange = calculateCharacterSu
brange(paragraph.paragraphRange(), resultLocation, resultLength); |
616 frame().document()->markers().addMarker(invisibleSpellcheckRange.sta
rtPosition(), invisibleSpellcheckRange.endPosition(), DocumentMarker::InvisibleS
pellcheck, result->replacement, result->hash); | 614 frame().document()->markers().addMarker(invisibleSpellcheckRange.sta
rtPosition(), invisibleSpellcheckRange.endPosition(), DocumentMarker::InvisibleS
pellcheck, result->replacement, result->hash); |
617 } | 615 } |
618 } | 616 } |
619 | 617 |
620 if (selectionChanged) { | 618 if (selectionChanged) { |
621 TextCheckingParagraph extendedParagraph(paragraph); | 619 TextCheckingParagraph extendedParagraph(paragraph); |
622 // Restore the caret position if we have made any replacements | 620 // Restore the caret position if we have made any replacements |
623 extendedParagraph.expandRangeToNextEnd(); | 621 extendedParagraph.expandRangeToNextEnd(); |
624 if (restoreSelectionAfterChange && selectionOffset >= 0 && selectionOffs
et <= extendedParagraph.rangeLength()) { | 622 if (restoreSelectionAfterChange && selectionOffset >= 0 && selectionOffs
et <= extendedParagraph.rangeLength()) { |
625 RefPtrWillBeRawPtr<Range> selectionRange = extendedParagraph.subrang
e(0, selectionOffset); | 623 EphemeralRange selectionRange = extendedParagraph.subrange(0, select
ionOffset); |
626 frame().selection().moveTo(selectionRange->endPosition(), TextAffini
ty::Downstream); | 624 frame().selection().moveTo(selectionRange.endPosition(), TextAffinit
y::Downstream); |
627 if (adjustSelectionForParagraphBoundaries) | 625 if (adjustSelectionForParagraphBoundaries) |
628 frame().selection().modify(FrameSelection::AlterationMove, Direc
tionForward, CharacterGranularity); | 626 frame().selection().modify(FrameSelection::AlterationMove, Direc
tionForward, CharacterGranularity); |
629 } else { | 627 } else { |
630 // If this fails for any reason, the fallback is to go one position
beyond the last replacement | 628 // If this fails for any reason, the fallback is to go one position
beyond the last replacement |
631 frame().selection().moveTo(frame().selection().selection().visibleEn
d()); | 629 frame().selection().moveTo(frame().selection().selection().visibleEn
d()); |
632 frame().selection().modify(FrameSelection::AlterationMove, Direction
Forward, CharacterGranularity); | 630 frame().selection().modify(FrameSelection::AlterationMove, Direction
Forward, CharacterGranularity); |
633 } | 631 } |
634 } | 632 } |
635 } | 633 } |
636 | 634 |
637 void SpellChecker::markMisspellingsAndBadGrammar(const VisibleSelection& spellin
gSelection, bool markGrammar, const VisibleSelection& grammarSelection) | 635 void SpellChecker::markMisspellingsAndBadGrammar(const VisibleSelection& spellin
gSelection, bool markGrammar, const VisibleSelection& grammarSelection) |
638 { | 636 { |
639 if (unifiedTextCheckerEnabled()) { | 637 if (unifiedTextCheckerEnabled()) { |
640 if (!isContinuousSpellCheckingEnabled()) | 638 if (!isContinuousSpellCheckingEnabled()) |
641 return; | 639 return; |
642 | 640 |
643 // markMisspellingsAndBadGrammar() is triggered by selection change, in
which case we check spelling and grammar, but don't autocorrect misspellings. | 641 // markMisspellingsAndBadGrammar() is triggered by selection change, in
which case we check spelling and grammar, but don't autocorrect misspellings. |
644 TextCheckingTypeMask textCheckingOptions = TextCheckingTypeSpelling; | 642 TextCheckingTypeMask textCheckingOptions = TextCheckingTypeSpelling; |
645 if (markGrammar && isGrammarCheckingEnabled()) | 643 if (markGrammar && isGrammarCheckingEnabled()) |
646 textCheckingOptions |= TextCheckingTypeGrammar; | 644 textCheckingOptions |= TextCheckingTypeGrammar; |
647 markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, spellingSe
lection.toNormalizedEphemeralRange(), grammarSelection.toNormalizedEphemeralRang
e()); | 645 markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, spellingSe
lection.toNormalizedEphemeralRange(), grammarSelection.toNormalizedEphemeralRang
e()); |
648 return; | 646 return; |
649 } | 647 } |
650 | 648 |
651 RefPtrWillBeRawPtr<Range> firstMisspellingRange = nullptr; | 649 markMisspellings(spellingSelection); |
652 markMisspellings(spellingSelection, firstMisspellingRange); | |
653 if (markGrammar) | 650 if (markGrammar) |
654 markBadGrammar(grammarSelection); | 651 markBadGrammar(grammarSelection); |
655 } | 652 } |
656 | 653 |
657 void SpellChecker::updateMarkersForWordsAffectedByEditing(bool doNotRemoveIfSele
ctionAtWordBoundary) | 654 void SpellChecker::updateMarkersForWordsAffectedByEditing(bool doNotRemoveIfSele
ctionAtWordBoundary) |
658 { | 655 { |
659 if (textChecker().shouldEraseMarkersAfterChangeSelection(TextCheckingTypeSpe
lling)) | 656 if (textChecker().shouldEraseMarkersAfterChangeSelection(TextCheckingTypeSpe
lling)) |
660 return; | 657 return; |
661 | 658 |
662 TRACE_EVENT0("blink", "SpellChecker::updateMarkersForWordsAffectedByEditing"
); | 659 TRACE_EVENT0("blink", "SpellChecker::updateMarkersForWordsAffectedByEditing"
); |
(...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
938 m_spellCheckRequester->requestCheckingFor(SpellCheckRequest::create(TextChec
kingTypeSpelling | TextCheckingTypeGrammar, TextCheckingProcessBatch, rangeToChe
ck, rangeToCheck)); | 935 m_spellCheckRequester->requestCheckingFor(SpellCheckRequest::create(TextChec
kingTypeSpelling | TextCheckingTypeGrammar, TextCheckingProcessBatch, rangeToChe
ck, rangeToCheck)); |
939 } | 936 } |
940 | 937 |
941 DEFINE_TRACE(SpellChecker) | 938 DEFINE_TRACE(SpellChecker) |
942 { | 939 { |
943 visitor->trace(m_frame); | 940 visitor->trace(m_frame); |
944 visitor->trace(m_spellCheckRequester); | 941 visitor->trace(m_spellCheckRequester); |
945 } | 942 } |
946 | 943 |
947 } // namespace blink | 944 } // namespace blink |
OLD | NEW |