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

Side by Side Diff: third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.cpp

Issue 2190293002: Stop TextCheckingHelper from checking grammar (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 4 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 Apple Inc. All rights reserved. 2 * Copyright (C) 2006, 2007 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 23 matching lines...) Expand all
34 #include "core/editing/iterators/WordAwareIterator.h" 34 #include "core/editing/iterators/WordAwareIterator.h"
35 #include "core/editing/markers/DocumentMarkerController.h" 35 #include "core/editing/markers/DocumentMarkerController.h"
36 #include "core/frame/LocalFrame.h" 36 #include "core/frame/LocalFrame.h"
37 #include "core/frame/Settings.h" 37 #include "core/frame/Settings.h"
38 #include "core/page/SpellCheckerClient.h" 38 #include "core/page/SpellCheckerClient.h"
39 #include "platform/text/TextBreakIterator.h" 39 #include "platform/text/TextBreakIterator.h"
40 #include "platform/text/TextCheckerClient.h" 40 #include "platform/text/TextCheckerClient.h"
41 41
42 namespace blink { 42 namespace blink {
43 43
44 static void findBadGrammars(TextCheckerClient& client, const UChar* text, int st art, int length, Vector<TextCheckingResult>& results)
45 {
46 int checkLocation = start;
47 int checkLength = length;
48
49 while (0 < checkLength) {
50 int badGrammarLocation = -1;
51 int badGrammarLength = 0;
52 Vector<GrammarDetail> badGrammarDetails;
53 client.checkGrammarOfString(String(text + checkLocation, checkLength), b adGrammarDetails, &badGrammarLocation, &badGrammarLength);
54 if (!badGrammarLength)
55 break;
56 DCHECK_LE(0, badGrammarLocation);
57 DCHECK_LE(badGrammarLocation, checkLength);
58 DCHECK_LT(0, badGrammarLength);
59 DCHECK_LE(badGrammarLocation + badGrammarLength, checkLength);
60 TextCheckingResult badGrammar;
61 badGrammar.decoration = TextDecorationTypeGrammar;
62 badGrammar.location = checkLocation + badGrammarLocation;
63 badGrammar.length = badGrammarLength;
64 badGrammar.details.swap(badGrammarDetails);
65 results.append(badGrammar);
66
67 checkLocation += (badGrammarLocation + badGrammarLength);
68 checkLength -= (badGrammarLocation + badGrammarLength);
69 }
70 }
71
72 static void findMisspellings(TextCheckerClient& client, const UChar* text, int s tart, int length, Vector<TextCheckingResult>& results) 44 static void findMisspellings(TextCheckerClient& client, const UChar* text, int s tart, int length, Vector<TextCheckingResult>& results)
73 { 45 {
74 TextBreakIterator* iterator = wordBreakIterator(text + start, length); 46 TextBreakIterator* iterator = wordBreakIterator(text + start, length);
75 if (!iterator) 47 if (!iterator)
76 return; 48 return;
77 int wordStart = iterator->current(); 49 int wordStart = iterator->current();
78 while (0 <= wordStart) { 50 while (0 <= wordStart) {
79 int wordEnd = iterator->next(); 51 int wordEnd = iterator->next();
80 if (wordEnd < 0) 52 if (wordEnd < 0)
81 break; 53 break;
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after
338 Position paragraphEnd = m_end; 310 Position paragraphEnd = m_end;
339 int totalRangeLength = TextIterator::rangeLength(paragraphStart, paragraphEn d); 311 int totalRangeLength = TextIterator::rangeLength(paragraphStart, paragraphEn d);
340 paragraphEnd = endOfParagraph(createVisiblePosition(m_start)).toParentAnchor edPosition(); 312 paragraphEnd = endOfParagraph(createVisiblePosition(m_start)).toParentAnchor edPosition();
341 313
342 int rangeStartOffset = TextIterator::rangeLength(paragraphStart, m_start); 314 int rangeStartOffset = TextIterator::rangeLength(paragraphStart, m_start);
343 int totalLengthProcessed = 0; 315 int totalLengthProcessed = 0;
344 316
345 bool firstIteration = true; 317 bool firstIteration = true;
346 bool lastIteration = false; 318 bool lastIteration = false;
347 while (totalLengthProcessed < totalRangeLength) { 319 while (totalLengthProcessed < totalRangeLength) {
348 // Iterate through the search range by paragraphs, checking each one for spelling and grammar. 320 // Iterate through the search range by paragraphs, checking each one for spelling.
349 int currentLength = TextIterator::rangeLength(paragraphStart, paragraphE nd); 321 int currentLength = TextIterator::rangeLength(paragraphStart, paragraphE nd);
350 int currentStartOffset = firstIteration ? rangeStartOffset : 0; 322 int currentStartOffset = firstIteration ? rangeStartOffset : 0;
351 int currentEndOffset = currentLength; 323 int currentEndOffset = currentLength;
352 if (inSameParagraph(createVisiblePosition(paragraphStart), createVisible Position(m_end))) { 324 if (inSameParagraph(createVisiblePosition(paragraphStart), createVisible Position(m_end))) {
353 // Determine the character offset from the end of the original searc h range to the end of the paragraph, 325 // Determine the character offset from the end of the original searc h range to the end of the paragraph,
354 // since we will want to ignore results in this area. 326 // since we will want to ignore results in this area.
355 currentEndOffset = TextIterator::rangeLength(paragraphStart, m_end); 327 currentEndOffset = TextIterator::rangeLength(paragraphStart, m_end);
356 lastIteration = true; 328 lastIteration = true;
357 } 329 }
358 if (currentStartOffset < currentEndOffset) { 330 if (currentStartOffset < currentEndOffset) {
359 String paragraphString = plainText(EphemeralRange(paragraphStart, pa ragraphEnd)); 331 String paragraphString = plainText(EphemeralRange(paragraphStart, pa ragraphEnd));
360 if (paragraphString.length() > 0) { 332 if (paragraphString.length() > 0) {
361 bool foundGrammar = false;
362 int spellingLocation = 0; 333 int spellingLocation = 0;
363 int grammarPhraseLocation = 0;
364 int grammarDetailLocation = 0;
365 unsigned grammarDetailIndex = 0;
366 334
367 Vector<TextCheckingResult> results; 335 Vector<TextCheckingResult> results;
368 TextCheckingTypeMask checkingTypes = TextCheckingTypeSpelling | TextCheckingTypeGrammar; 336 TextCheckingTypeMask checkingTypes = TextCheckingTypeSpelling;
369 checkTextOfParagraph(m_client->textChecker(), paragraphString, c heckingTypes, results); 337 checkTextOfParagraph(m_client->textChecker(), paragraphString, c heckingTypes, results);
370 338
371 for (unsigned i = 0; i < results.size(); i++) { 339 for (unsigned i = 0; i < results.size(); i++) {
372 const TextCheckingResult* result = &results[i]; 340 const TextCheckingResult* result = &results[i];
373 if (result->decoration == TextDecorationTypeSpelling && resu lt->location >= currentStartOffset && result->location + result->length <= curre ntEndOffset) { 341 if (result->decoration == TextDecorationTypeSpelling && resu lt->location >= currentStartOffset && result->location + result->length <= curre ntEndOffset) {
374 DCHECK_GT(result->length, 0); 342 DCHECK_GT(result->length, 0);
375 DCHECK_GE(result->location, 0); 343 DCHECK_GE(result->location, 0);
376 spellingLocation = result->location; 344 spellingLocation = result->location;
377 misspelledWord = paragraphString.substring(result->locat ion, result->length); 345 misspelledWord = paragraphString.substring(result->locat ion, result->length);
378 DCHECK(misspelledWord.length()); 346 DCHECK(misspelledWord.length());
379 break; 347 break;
380 } 348 }
381 if (result->decoration == TextDecorationTypeGrammar && resul t->location < currentEndOffset && result->location + result->length > currentSta rtOffset) {
382 DCHECK_GT(result->length, 0);
383 DCHECK_GE(result->location, 0);
384 // We can't stop after the first grammar result, since t here might still be a spelling result after
385 // it begins but before the first detail in it, but we c an stop if we find a second grammar result.
386 if (foundGrammar)
387 break;
388 for (unsigned j = 0; j < result->details.size(); j++) {
389 const GrammarDetail* detail = &result->details[j];
390 DCHECK_GT(detail->length, 0);
391 DCHECK_GE(detail->location, 0);
392 if (result->location + detail->location >= currentSt artOffset && result->location + detail->location + detail->length <= currentEndO ffset && (!foundGrammar || result->location + detail->location < grammarDetailLo cation)) {
393 grammarDetailIndex = j;
394 grammarDetailLocation = result->location + detai l->location;
395 foundGrammar = true;
396 }
397 }
398 if (foundGrammar) {
399 grammarPhraseLocation = result->location;
400 outGrammarDetail = result->details[grammarDetailInde x];
401 badGrammarPhrase = paragraphString.substring(result- >location, result->length);
402 DCHECK(badGrammarPhrase.length());
403 }
404 }
405 } 349 }
406 350
407 if (!misspelledWord.isEmpty() && (badGrammarPhrase.isEmpty() || spellingLocation <= grammarDetailLocation)) { 351 if (!misspelledWord.isEmpty()) {
408 int spellingOffset = spellingLocation - currentStartOffset; 352 int spellingOffset = spellingLocation - currentStartOffset;
409 if (!firstIteration) 353 if (!firstIteration)
410 spellingOffset += TextIterator::rangeLength(m_start, par agraphStart); 354 spellingOffset += TextIterator::rangeLength(m_start, par agraphStart);
411 outIsSpelling = true; 355 outIsSpelling = true;
412 outFirstFoundOffset = spellingOffset; 356 outFirstFoundOffset = spellingOffset;
413 firstFoundItem = misspelledWord; 357 firstFoundItem = misspelledWord;
414 break; 358 break;
415 } 359 }
416 if (!badGrammarPhrase.isEmpty()) {
417 int grammarPhraseOffset = grammarPhraseLocation - currentSta rtOffset;
418 if (!firstIteration)
419 grammarPhraseOffset += TextIterator::rangeLength(m_start , paragraphStart);
420 outIsSpelling = false;
421 outFirstFoundOffset = grammarPhraseOffset;
422 firstFoundItem = badGrammarPhrase;
423 break;
424 }
425 } 360 }
426 } 361 }
427 if (lastIteration || totalLengthProcessed + currentLength >= totalRangeL ength) 362 if (lastIteration || totalLengthProcessed + currentLength >= totalRangeL ength)
428 break; 363 break;
429 VisiblePosition newParagraphStart = startOfNextParagraph(createVisiblePo sition(paragraphEnd)); 364 VisiblePosition newParagraphStart = startOfNextParagraph(createVisiblePo sition(paragraphEnd));
430 paragraphStart = newParagraphStart.toParentAnchoredPosition(); 365 paragraphStart = newParagraphStart.toParentAnchoredPosition();
431 paragraphEnd = endOfParagraph(newParagraphStart).toParentAnchoredPositio n(); 366 paragraphEnd = endOfParagraph(newParagraphStart).toParentAnchoredPositio n();
432 firstIteration = false; 367 firstIteration = false;
433 totalLengthProcessed += currentLength; 368 totalLengthProcessed += currentLength;
434 } 369 }
435 return firstFoundItem; 370 return firstFoundItem;
436 } 371 }
437 372
438 int TextCheckingHelper::findFirstGrammarDetail(const Vector<GrammarDetail>& gram marDetails, int badGrammarPhraseLocation, int startOffset, int endOffset, bool m arkAll) const
439 {
440 // Found some bad grammar. Find the earliest detail range that starts in our search range (if any).
441 // Optionally add a DocumentMarker for each detail in the range.
442 int earliestDetailLocationSoFar = -1;
443 int earliestDetailIndex = -1;
444 for (unsigned i = 0; i < grammarDetails.size(); i++) {
445 const GrammarDetail* detail = &grammarDetails[i];
446 DCHECK_GT(detail->length, 0);
447 DCHECK_GE(detail->location, 0);
448
449 int detailStartOffsetInParagraph = badGrammarPhraseLocation + detail->lo cation;
450
451 // Skip this detail if it starts before the original search range
452 if (detailStartOffsetInParagraph < startOffset)
453 continue;
454
455 // Skip this detail if it starts after the original search range
456 if (detailStartOffsetInParagraph >= endOffset)
457 continue;
458
459 if (markAll) {
460 const EphemeralRange badGrammarRange = calculateCharacterSubrange(Ep hemeralRange(m_start, m_end), badGrammarPhraseLocation - startOffset + detail->l ocation, detail->length);
461 badGrammarRange.document().markers().addMarker(badGrammarRange.start Position(), badGrammarRange.endPosition(), DocumentMarker::Grammar, detail->user Description);
462 }
463
464 // Remember this detail only if it's earlier than our current candidate (the details aren't in a guaranteed order)
465 if (earliestDetailIndex < 0 || earliestDetailLocationSoFar > detail->loc ation) {
466 earliestDetailIndex = i;
467 earliestDetailLocationSoFar = detail->location;
468 }
469 }
470
471 return earliestDetailIndex;
472 }
473
474 String TextCheckingHelper::findFirstBadGrammar(GrammarDetail& outGrammarDetail, int& outGrammarPhraseOffset, bool markAll) 373 String TextCheckingHelper::findFirstBadGrammar(GrammarDetail& outGrammarDetail, int& outGrammarPhraseOffset, bool markAll)
475 { 374 {
476 // Initialize out parameters; these will be updated if we find something to return. 375 // Return empty result since there is no grammar checking.
477 outGrammarDetail.location = -1; 376 outGrammarDetail.location = -1;
478 outGrammarDetail.length = 0; 377 outGrammarDetail.length = 0;
479 outGrammarDetail.guesses.clear(); 378 outGrammarDetail.guesses.clear();
480 outGrammarDetail.userDescription = ""; 379 outGrammarDetail.userDescription = "";
481 outGrammarPhraseOffset = 0; 380 outGrammarPhraseOffset = 0;
482 381 return "";
483 String firstBadGrammarPhrase;
484
485 // Expand the search range to encompass entire paragraphs, since grammar che cking needs that much context.
486 // Determine the character offset from the start of the paragraph to the sta rt of the original search range,
487 // since we will want to ignore results in this area.
488 TextCheckingParagraph paragraph(EphemeralRange(m_start, m_end));
489
490 // Start checking from beginning of paragraph, but skip past results that oc cur before the start of the original search range.
491 int startOffset = 0;
492 while (startOffset < paragraph.checkingEnd()) {
493 Vector<GrammarDetail> grammarDetails;
494 int badGrammarPhraseLocation = -1;
495 int badGrammarPhraseLength = 0;
496 m_client->textChecker().checkGrammarOfString(paragraph.textSubstring(sta rtOffset), grammarDetails, &badGrammarPhraseLocation, &badGrammarPhraseLength);
497
498 if (!badGrammarPhraseLength) {
499 DCHECK_EQ(badGrammarPhraseLocation, -1);
500 return String();
501 }
502
503 DCHECK_GE(badGrammarPhraseLocation, 0);
504 badGrammarPhraseLocation += startOffset;
505
506
507 // Found some bad grammar. Find the earliest detail range that starts in our search range (if any).
508 int badGrammarIndex = findFirstGrammarDetail(grammarDetails, badGrammarP hraseLocation, paragraph.checkingStart(), paragraph.checkingEnd(), markAll);
509 if (badGrammarIndex >= 0) {
510 DCHECK_LT(static_cast<unsigned>(badGrammarIndex), grammarDetails.siz e());
511 outGrammarDetail = grammarDetails[badGrammarIndex];
512 }
513
514 // If we found a detail in range, then we have found the first bad phras e (unless we found one earlier but
515 // kept going so we could mark all instances).
516 if (badGrammarIndex >= 0 && firstBadGrammarPhrase.isEmpty()) {
517 outGrammarPhraseOffset = badGrammarPhraseLocation - paragraph.checki ngStart();
518 firstBadGrammarPhrase = paragraph.textSubstring(badGrammarPhraseLoca tion, badGrammarPhraseLength);
519
520 // Found one. We're done now, unless we're marking each instance.
521 if (!markAll)
522 break;
523 }
524
525 // These results were all between the start of the paragraph and the sta rt of the search range; look
526 // beyond this phrase.
527 startOffset = badGrammarPhraseLocation + badGrammarPhraseLength;
528 }
529
530 return firstBadGrammarPhrase;
531 } 382 }
532 383
533 bool TextCheckingHelper::markAllMisspellings() 384 bool TextCheckingHelper::markAllMisspellings()
534 { 385 {
535 // Use the "markAll" feature of findFirstMisspelling. Ignore the return valu e and the "out parameter"; 386 // Use the "markAll" feature of findFirstMisspelling. Ignore the return valu e and the "out parameter";
536 // all we need to do is mark every instance. 387 // all we need to do is mark every instance.
537 int ignoredOffset; 388 int ignoredOffset;
538 return findFirstMisspelling(ignoredOffset, true).isEmpty(); 389 return findFirstMisspelling(ignoredOffset, true).isEmpty();
539 } 390 }
540 391
541 void TextCheckingHelper::markAllBadGrammar() 392 void TextCheckingHelper::markAllBadGrammar()
542 { 393 {
543 // Use the "markAll" feature of findFirstBadGrammar. Ignore the return value and "out parameters"; all we need to
544 // do is mark every instance.
545 GrammarDetail ignoredGrammarDetail;
546 int ignoredOffset;
547 findFirstBadGrammar(ignoredGrammarDetail, ignoredOffset, true);
548 } 394 }
549 395
550 bool TextCheckingHelper::unifiedTextCheckerEnabled() const 396 bool TextCheckingHelper::unifiedTextCheckerEnabled() const
551 { 397 {
552 DCHECK(m_start.isNotNull()); 398 DCHECK(m_start.isNotNull());
553 Document& doc = m_start.computeContainerNode()->document(); 399 Document& doc = m_start.computeContainerNode()->document();
554 return blink::unifiedTextCheckerEnabled(doc.frame()); 400 return blink::unifiedTextCheckerEnabled(doc.frame());
555 } 401 }
556 402
557 void checkTextOfParagraph(TextCheckerClient& client, const String& text, TextChe ckingTypeMask checkingTypes, Vector<TextCheckingResult>& results) 403 void checkTextOfParagraph(TextCheckerClient& client, const String& text, TextChe ckingTypeMask checkingTypes, Vector<TextCheckingResult>& results)
558 { 404 {
559 Vector<UChar> characters; 405 Vector<UChar> characters;
560 text.appendTo(characters); 406 text.appendTo(characters);
561 unsigned length = text.length(); 407 unsigned length = text.length();
562 408
563 Vector<TextCheckingResult> spellingResult; 409 Vector<TextCheckingResult> spellingResult;
564 if (checkingTypes & TextCheckingTypeSpelling) 410 if (checkingTypes & TextCheckingTypeSpelling)
565 findMisspellings(client, characters.data(), 0, length, spellingResult); 411 findMisspellings(client, characters.data(), 0, length, spellingResult);
566 412
567 Vector<TextCheckingResult> grammarResult; 413 if (spellingResult.size())
568 if (checkingTypes & TextCheckingTypeGrammar) { 414 results.swap(spellingResult);
569 // Only checks grammartical error before the first misspellings
570 int grammarCheckLength = length;
571 for (const auto& spelling : spellingResult) {
572 if (spelling.location < grammarCheckLength)
573 grammarCheckLength = spelling.location;
574 }
575
576 findBadGrammars(client, characters.data(), 0, grammarCheckLength, gramma rResult);
577 }
578
579 if (grammarResult.size())
580 results.swap(grammarResult);
581
582 if (spellingResult.size()) {
583 if (results.isEmpty())
584 results.swap(spellingResult);
585 else
586 results.appendVector(spellingResult);
587 }
588 } 415 }
589 416
590 bool unifiedTextCheckerEnabled(const LocalFrame* frame) 417 bool unifiedTextCheckerEnabled(const LocalFrame* frame)
591 { 418 {
592 if (!frame) 419 if (!frame)
593 return false; 420 return false;
594 421
595 const Settings* settings = frame->settings(); 422 const Settings* settings = frame->settings();
596 if (!settings) 423 if (!settings)
597 return false; 424 return false;
598 425
599 return settings->unifiedTextCheckerEnabled(); 426 return settings->unifiedTextCheckerEnabled();
600 } 427 }
601 428
602 } // namespace blink 429 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698