| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |