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 |