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

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

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

Powered by Google App Engine
This is Rietveld 408576698