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

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

Issue 1331893002: Switch TextCheckingParagraph&Helper over to EphemeralRanges. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: rebased Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2006, 2007, 2008, 2011 Apple Inc. All rights reserved. 2 * Copyright (C) 2006, 2007, 2008, 2011 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) 3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 6 * modification, are permitted provided that the following conditions
7 * are met: 7 * are met:
8 * 1. Redistributions of source code must retain the above copyright 8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright 10 * 2. Redistributions in binary form must reproduce the above copyright
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
OLDNEW
« no previous file with comments | « Source/core/editing/spellcheck/SpellChecker.h ('k') | Source/core/editing/spellcheck/TextCheckingHelper.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698