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

Side by Side Diff: Source/core/editing/TextCheckingHelper.cpp

Issue 1287263004: Move spell checker in core/editing/ related files into core/editing/spellcheck/ (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: 2015-08-17T10:33:57 Created 5 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
« no previous file with comments | « Source/core/editing/TextCheckingHelper.h ('k') | Source/core/editing/TypingCommand.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include "config.h"
28 #include "core/editing/TextCheckingHelper.h"
29
30 #include "bindings/core/v8/ExceptionState.h"
31 #include "bindings/core/v8/ExceptionStatePlaceholder.h"
32 #include "core/dom/Document.h"
33 #include "core/dom/Range.h"
34 #include "core/editing/VisiblePosition.h"
35 #include "core/editing/VisibleUnits.h"
36 #include "core/editing/iterators/CharacterIterator.h"
37 #include "core/editing/iterators/WordAwareIterator.h"
38 #include "core/editing/markers/DocumentMarkerController.h"
39 #include "core/frame/LocalFrame.h"
40 #include "core/frame/Settings.h"
41 #include "core/page/SpellCheckerClient.h"
42 #include "platform/text/TextBreakIterator.h"
43 #include "platform/text/TextCheckerClient.h"
44
45 namespace blink {
46
47 static void findBadGrammars(TextCheckerClient& client, const UChar* text, int st art, int length, Vector<TextCheckingResult>& results)
48 {
49 int checkLocation = start;
50 int checkLength = length;
51
52 while (0 < checkLength) {
53 int badGrammarLocation = -1;
54 int badGrammarLength = 0;
55 Vector<GrammarDetail> badGrammarDetails;
56 client.checkGrammarOfString(String(text + checkLocation, checkLength), b adGrammarDetails, &badGrammarLocation, &badGrammarLength);
57 if (!badGrammarLength)
58 break;
59 ASSERT(0 <= badGrammarLocation && badGrammarLocation <= checkLength);
60 ASSERT(0 < badGrammarLength && badGrammarLocation + badGrammarLength <= checkLength);
61 TextCheckingResult badGrammar;
62 badGrammar.decoration = TextDecorationTypeGrammar;
63 badGrammar.location = checkLocation + badGrammarLocation;
64 badGrammar.length = badGrammarLength;
65 badGrammar.details.swap(badGrammarDetails);
66 results.append(badGrammar);
67
68 checkLocation += (badGrammarLocation + badGrammarLength);
69 checkLength -= (badGrammarLocation + badGrammarLength);
70 }
71 }
72
73 static void findMisspellings(TextCheckerClient& client, const UChar* text, int s tart, int length, Vector<TextCheckingResult>& results)
74 {
75 TextBreakIterator* iterator = wordBreakIterator(text + start, length);
76 if (!iterator)
77 return;
78 int wordStart = iterator->current();
79 while (0 <= wordStart) {
80 int wordEnd = iterator->next();
81 if (wordEnd < 0)
82 break;
83 int wordLength = wordEnd - wordStart;
84 int misspellingLocation = -1;
85 int misspellingLength = 0;
86 client.checkSpellingOfString(String(text + start + wordStart, wordLength ), &misspellingLocation, &misspellingLength);
87 if (0 < misspellingLength) {
88 ASSERT(0 <= misspellingLocation && misspellingLocation <= wordLength );
89 ASSERT(0 < misspellingLength && misspellingLocation + misspellingLen gth <= wordLength);
90 TextCheckingResult misspelling;
91 misspelling.decoration = TextDecorationTypeSpelling;
92 misspelling.location = start + wordStart + misspellingLocation;
93 misspelling.length = misspellingLength;
94 misspelling.replacement = client.getAutoCorrectSuggestionForMisspell edWord(String(text + misspelling.location, misspelling.length));
95 results.append(misspelling);
96 }
97
98 wordStart = wordEnd;
99 }
100 }
101
102 void expandRangeToSentenceBoundary(Range& range)
103 {
104 range.setStart(startOfSentence(VisiblePosition(range.startPosition())).deepE quivalent());
105 range.setEnd(endOfSentence(VisiblePosition(range.endPosition())).deepEquival ent());
106 }
107
108 static PassRefPtrWillBeRawPtr<Range> expandToParagraphBoundary(PassRefPtrWillBeR awPtr<Range> range)
109 {
110 RefPtrWillBeRawPtr<Range> paragraphRange = range->cloneRange();
111 paragraphRange->setStart(startOfParagraph(VisiblePosition(range->startPositi on())).deepEquivalent());
112 paragraphRange->setEnd(endOfParagraph(VisiblePosition(range->endPosition())) .deepEquivalent());
113 return paragraphRange;
114 }
115
116 TextCheckingParagraph::TextCheckingParagraph(PassRefPtrWillBeRawPtr<Range> check ingRange)
117 : m_checkingRange(checkingRange)
118 , m_checkingStart(-1)
119 , m_checkingEnd(-1)
120 , m_checkingLength(-1)
121 {
122 }
123
124 TextCheckingParagraph::TextCheckingParagraph(PassRefPtrWillBeRawPtr<Range> check ingRange, PassRefPtrWillBeRawPtr<Range> paragraphRange)
125 : m_checkingRange(checkingRange)
126 , m_paragraphRange(paragraphRange)
127 , m_checkingStart(-1)
128 , m_checkingEnd(-1)
129 , m_checkingLength(-1)
130 {
131 }
132
133 TextCheckingParagraph::~TextCheckingParagraph()
134 {
135 }
136
137 void TextCheckingParagraph::expandRangeToNextEnd()
138 {
139 ASSERT(m_checkingRange);
140 paragraphRange()->setEnd(endOfParagraph(startOfNextParagraph(VisiblePosition (paragraphRange()->startPosition()))).deepEquivalent());
141 invalidateParagraphRangeValues();
142 }
143
144 void TextCheckingParagraph::invalidateParagraphRangeValues()
145 {
146 m_checkingStart = m_checkingEnd = -1;
147 m_offsetAsRange = nullptr;
148 m_text = String();
149 }
150
151 int TextCheckingParagraph::rangeLength() const
152 {
153 ASSERT(m_checkingRange);
154 return TextIterator::rangeLength(paragraphRange()->startPosition(), paragrap hRange()->endPosition());
155 }
156
157 PassRefPtrWillBeRawPtr<Range> TextCheckingParagraph::paragraphRange() const
158 {
159 ASSERT(m_checkingRange);
160 if (!m_paragraphRange)
161 m_paragraphRange = expandToParagraphBoundary(checkingRange());
162 return m_paragraphRange;
163 }
164
165 PassRefPtrWillBeRawPtr<Range> TextCheckingParagraph::subrange(int characterOffse t, int characterCount) const
166 {
167 ASSERT(m_checkingRange);
168 EphemeralRange range = calculateCharacterSubrange(EphemeralRange(paragraphRa nge().get()), characterOffset, characterCount);
169 if (range.isNull())
170 return nullptr;
171 return Range::create(range.document(), range.startPosition(), range.endPosit ion());
172 }
173
174 int TextCheckingParagraph::offsetTo(const Position& position, ExceptionState& ex ceptionState) const
175 {
176 ASSERT(m_checkingRange);
177 RefPtrWillBeRawPtr<Range> range = offsetAsRange()->cloneRange();
178 range->setEnd(position.computeContainerNode(), position.computeOffsetInConta inerNode(), exceptionState);
179 if (exceptionState.hadException())
180 return 0;
181 return TextIterator::rangeLength(range->startPosition(), range->endPosition( ));
182 }
183
184 bool TextCheckingParagraph::isEmpty() const
185 {
186 // Both predicates should have same result, but we check both just for sure.
187 // We need to investigate to remove this redundancy.
188 return isRangeEmpty() || isTextEmpty();
189 }
190
191 PassRefPtrWillBeRawPtr<Range> TextCheckingParagraph::offsetAsRange() const
192 {
193 ASSERT(m_checkingRange);
194 if (!m_offsetAsRange)
195 m_offsetAsRange = Range::create(paragraphRange()->startContainer()->docu ment(), paragraphRange()->startPosition(), checkingRange()->startPosition());
196
197 return m_offsetAsRange;
198 }
199
200 const String& TextCheckingParagraph::text() const
201 {
202 ASSERT(m_checkingRange);
203 if (m_text.isEmpty())
204 m_text = plainText(EphemeralRange(paragraphRange().get()));
205 return m_text;
206 }
207
208 int TextCheckingParagraph::checkingStart() const
209 {
210 ASSERT(m_checkingRange);
211 if (m_checkingStart == -1)
212 m_checkingStart = TextIterator::rangeLength(offsetAsRange()->startPositi on(), offsetAsRange()->endPosition());
213 return m_checkingStart;
214 }
215
216 int TextCheckingParagraph::checkingEnd() const
217 {
218 ASSERT(m_checkingRange);
219 if (m_checkingEnd == -1)
220 m_checkingEnd = checkingStart() + TextIterator::rangeLength(checkingRang e()->startPosition(), checkingRange()->endPosition());
221 return m_checkingEnd;
222 }
223
224 int TextCheckingParagraph::checkingLength() const
225 {
226 ASSERT(m_checkingRange);
227 if (-1 == m_checkingLength)
228 m_checkingLength = TextIterator::rangeLength(checkingRange()->startPosit ion(), checkingRange()->endPosition());
229 return m_checkingLength;
230 }
231
232 TextCheckingHelper::TextCheckingHelper(SpellCheckerClient& client, const Positio n& start, const Position& end)
233 : m_client(&client)
234 , m_start(start)
235 , m_end(end)
236 {
237 }
238
239 TextCheckingHelper::~TextCheckingHelper()
240 {
241 }
242
243 String TextCheckingHelper::findFirstMisspelling(int& firstMisspellingOffset, boo l markAll, RefPtrWillBeRawPtr<Range>& firstMisspellingRange)
244 {
245 WordAwareIterator it(m_start, m_end);
246 firstMisspellingOffset = 0;
247
248 String firstMisspelling;
249 int currentChunkOffset = 0;
250
251 while (!it.atEnd()) {
252 int length = it.length();
253
254 // Skip some work for one-space-char hunks
255 if (!(length == 1 && it.characterAt(0) == ' ')) {
256
257 int misspellingLocation = -1;
258 int misspellingLength = 0;
259 m_client->textChecker().checkSpellingOfString(it.substring(0, length ), &misspellingLocation, &misspellingLength);
260
261 // 5490627 shows that there was some code path here where the String constructor below crashes.
262 // We don't know exactly what combination of bad input caused this, so we're making this much
263 // more robust against bad input on release builds.
264 ASSERT(misspellingLength >= 0);
265 ASSERT(misspellingLocation >= -1);
266 ASSERT(!misspellingLength || misspellingLocation >= 0);
267 ASSERT(misspellingLocation < length);
268 ASSERT(misspellingLength <= length);
269 ASSERT(misspellingLocation + misspellingLength <= length);
270
271 if (misspellingLocation >= 0 && misspellingLength > 0 && misspelling Location < length && misspellingLength <= length && misspellingLocation + misspe llingLength <= length) {
272
273 // Compute range of misspelled word
274 const EphemeralRange misspellingRange = calculateCharacterSubran ge(EphemeralRange(m_start, m_end), currentChunkOffset + misspellingLocation, mis spellingLength);
275
276 // Remember first-encountered misspelling and its offset.
277 if (!firstMisspelling) {
278 firstMisspellingOffset = currentChunkOffset + misspellingLoc ation;
279 firstMisspelling = it.substring(misspellingLocation, misspel lingLength);
280 firstMisspellingRange = Range::create(misspellingRange.docum ent(), m_start, m_end);
281 }
282
283 // Store marker for misspelled word.
284 misspellingRange.document().markers().addMarker(misspellingRange .startPosition(), misspellingRange.endPosition(), DocumentMarker::Spelling);
285
286 // Bail out if we're marking only the first misspelling, and not all instances.
287 if (!markAll)
288 break;
289 }
290 }
291
292 currentChunkOffset += length;
293 it.advance();
294 }
295
296 return firstMisspelling;
297 }
298
299 String TextCheckingHelper::findFirstMisspellingOrBadGrammar(bool checkGrammar, b ool& outIsSpelling, int& outFirstFoundOffset, GrammarDetail& outGrammarDetail)
300 {
301 if (!unifiedTextCheckerEnabled())
302 return "";
303
304 String firstFoundItem;
305 String misspelledWord;
306 String badGrammarPhrase;
307
308 // Initialize out parameters; these will be updated if we find something to return.
309 outIsSpelling = true;
310 outFirstFoundOffset = 0;
311 outGrammarDetail.location = -1;
312 outGrammarDetail.length = 0;
313 outGrammarDetail.guesses.clear();
314 outGrammarDetail.userDescription = "";
315
316 // Expand the search range to encompass entire paragraphs, since text checki ng needs that much context.
317 // Determine the character offset from the start of the paragraph to the sta rt of the original search range,
318 // since we will want to ignore results in this area.
319 Position paragraphStart = startOfParagraph(VisiblePosition(m_start)).toParen tAnchoredPosition();
320 Position paragraphEnd = m_end;
321 int totalRangeLength = TextIterator::rangeLength(paragraphStart, paragraphEn d);
322 paragraphEnd = endOfParagraph(VisiblePosition(m_start)).toParentAnchoredPosi tion();
323
324 int rangeStartOffset = TextIterator::rangeLength(paragraphStart, m_start);
325 int totalLengthProcessed = 0;
326
327 bool firstIteration = true;
328 bool lastIteration = false;
329 while (totalLengthProcessed < totalRangeLength) {
330 // Iterate through the search range by paragraphs, checking each one for spelling and grammar.
331 int currentLength = TextIterator::rangeLength(paragraphStart, paragraphE nd);
332 int currentStartOffset = firstIteration ? rangeStartOffset : 0;
333 int currentEndOffset = currentLength;
334 if (inSameParagraph(VisiblePosition(paragraphStart), VisiblePosition(m_e nd))) {
335 // Determine the character offset from the end of the original searc h range to the end of the paragraph,
336 // since we will want to ignore results in this area.
337 currentEndOffset = TextIterator::rangeLength(paragraphStart, m_end);
338 lastIteration = true;
339 }
340 if (currentStartOffset < currentEndOffset) {
341 String paragraphString = plainText(EphemeralRange(paragraphStart, pa ragraphEnd));
342 if (paragraphString.length() > 0) {
343 bool foundGrammar = false;
344 int spellingLocation = 0;
345 int grammarPhraseLocation = 0;
346 int grammarDetailLocation = 0;
347 unsigned grammarDetailIndex = 0;
348
349 Vector<TextCheckingResult> results;
350 TextCheckingTypeMask checkingTypes = checkGrammar ? (TextCheckin gTypeSpelling | TextCheckingTypeGrammar) : TextCheckingTypeSpelling;
351 checkTextOfParagraph(m_client->textChecker(), paragraphString, c heckingTypes, results);
352
353 for (unsigned i = 0; i < results.size(); i++) {
354 const TextCheckingResult* result = &results[i];
355 if (result->decoration == TextDecorationTypeSpelling && resu lt->location >= currentStartOffset && result->location + result->length <= curre ntEndOffset) {
356 ASSERT(result->length > 0 && result->location >= 0);
357 spellingLocation = result->location;
358 misspelledWord = paragraphString.substring(result->locat ion, result->length);
359 ASSERT(misspelledWord.length());
360 break;
361 }
362 if (checkGrammar && result->decoration == TextDecorationType Grammar && result->location < currentEndOffset && result->location + result->len gth > currentStartOffset) {
363 ASSERT(result->length > 0 && result->location >= 0);
364 // We can't stop after the first grammar result, since t here might still be a spelling result after
365 // it begins but before the first detail in it, but we c an stop if we find a second grammar result.
366 if (foundGrammar)
367 break;
368 for (unsigned j = 0; j < result->details.size(); j++) {
369 const GrammarDetail* detail = &result->details[j];
370 ASSERT(detail->length > 0 && detail->location >= 0);
371 if (result->location + detail->location >= currentSt artOffset && result->location + detail->location + detail->length <= currentEndO ffset && (!foundGrammar || result->location + detail->location < grammarDetailLo cation)) {
372 grammarDetailIndex = j;
373 grammarDetailLocation = result->location + detai l->location;
374 foundGrammar = true;
375 }
376 }
377 if (foundGrammar) {
378 grammarPhraseLocation = result->location;
379 outGrammarDetail = result->details[grammarDetailInde x];
380 badGrammarPhrase = paragraphString.substring(result- >location, result->length);
381 ASSERT(badGrammarPhrase.length());
382 }
383 }
384 }
385
386 if (!misspelledWord.isEmpty() && (!checkGrammar || badGrammarPhr ase.isEmpty() || spellingLocation <= grammarDetailLocation)) {
387 int spellingOffset = spellingLocation - currentStartOffset;
388 if (!firstIteration)
389 spellingOffset += TextIterator::rangeLength(m_start, par agraphStart);
390 outIsSpelling = true;
391 outFirstFoundOffset = spellingOffset;
392 firstFoundItem = misspelledWord;
393 break;
394 }
395 if (checkGrammar && !badGrammarPhrase.isEmpty()) {
396 int grammarPhraseOffset = grammarPhraseLocation - currentSta rtOffset;
397 if (!firstIteration)
398 grammarPhraseOffset += TextIterator::rangeLength(m_start , paragraphStart);
399 outIsSpelling = false;
400 outFirstFoundOffset = grammarPhraseOffset;
401 firstFoundItem = badGrammarPhrase;
402 break;
403 }
404 }
405 }
406 if (lastIteration || totalLengthProcessed + currentLength >= totalRangeL ength)
407 break;
408 VisiblePosition newParagraphStart = startOfNextParagraph(VisiblePosition (paragraphEnd));
409 paragraphStart = newParagraphStart.toParentAnchoredPosition();
410 paragraphEnd = endOfParagraph(newParagraphStart).toParentAnchoredPositio n();
411 firstIteration = false;
412 totalLengthProcessed += currentLength;
413 }
414 return firstFoundItem;
415 }
416
417 int TextCheckingHelper::findFirstGrammarDetail(const Vector<GrammarDetail>& gram marDetails, int badGrammarPhraseLocation, int startOffset, int endOffset, bool m arkAll) const
418 {
419 // Found some bad grammar. Find the earliest detail range that starts in our search range (if any).
420 // Optionally add a DocumentMarker for each detail in the range.
421 int earliestDetailLocationSoFar = -1;
422 int earliestDetailIndex = -1;
423 for (unsigned i = 0; i < grammarDetails.size(); i++) {
424 const GrammarDetail* detail = &grammarDetails[i];
425 ASSERT(detail->length > 0 && detail->location >= 0);
426
427 int detailStartOffsetInParagraph = badGrammarPhraseLocation + detail->lo cation;
428
429 // Skip this detail if it starts before the original search range
430 if (detailStartOffsetInParagraph < startOffset)
431 continue;
432
433 // Skip this detail if it starts after the original search range
434 if (detailStartOffsetInParagraph >= endOffset)
435 continue;
436
437 if (markAll) {
438 const EphemeralRange badGrammarRange = calculateCharacterSubrange(Ep hemeralRange(m_start, m_end), badGrammarPhraseLocation - startOffset + detail->l ocation, detail->length);
439 badGrammarRange.document().markers().addMarker(badGrammarRange.start Position(), badGrammarRange.endPosition(), DocumentMarker::Grammar, detail->user Description);
440 }
441
442 // Remember this detail only if it's earlier than our current candidate (the details aren't in a guaranteed order)
443 if (earliestDetailIndex < 0 || earliestDetailLocationSoFar > detail->loc ation) {
444 earliestDetailIndex = i;
445 earliestDetailLocationSoFar = detail->location;
446 }
447 }
448
449 return earliestDetailIndex;
450 }
451
452 String TextCheckingHelper::findFirstBadGrammar(GrammarDetail& outGrammarDetail, int& outGrammarPhraseOffset, bool markAll)
453 {
454 // Initialize out parameters; these will be updated if we find something to return.
455 outGrammarDetail.location = -1;
456 outGrammarDetail.length = 0;
457 outGrammarDetail.guesses.clear();
458 outGrammarDetail.userDescription = "";
459 outGrammarPhraseOffset = 0;
460
461 String firstBadGrammarPhrase;
462
463 // Expand the search range to encompass entire paragraphs, since grammar che cking needs that much context.
464 // Determine the character offset from the start of the paragraph to the sta rt of the original search range,
465 // since we will want to ignore results in this area.
466 TextCheckingParagraph paragraph(Range::create(m_start.computeContainerNode() ->document(), m_start, m_end));
467
468 // Start checking from beginning of paragraph, but skip past results that oc cur before the start of the original search range.
469 int startOffset = 0;
470 while (startOffset < paragraph.checkingEnd()) {
471 Vector<GrammarDetail> grammarDetails;
472 int badGrammarPhraseLocation = -1;
473 int badGrammarPhraseLength = 0;
474 m_client->textChecker().checkGrammarOfString(paragraph.textSubstring(sta rtOffset), grammarDetails, &badGrammarPhraseLocation, &badGrammarPhraseLength);
475
476 if (!badGrammarPhraseLength) {
477 ASSERT(badGrammarPhraseLocation == -1);
478 return String();
479 }
480
481 ASSERT(badGrammarPhraseLocation >= 0);
482 badGrammarPhraseLocation += startOffset;
483
484
485 // Found some bad grammar. Find the earliest detail range that starts in our search range (if any).
486 int badGrammarIndex = findFirstGrammarDetail(grammarDetails, badGrammarP hraseLocation, paragraph.checkingStart(), paragraph.checkingEnd(), markAll);
487 if (badGrammarIndex >= 0) {
488 ASSERT(static_cast<unsigned>(badGrammarIndex) < grammarDetails.size( ));
489 outGrammarDetail = grammarDetails[badGrammarIndex];
490 }
491
492 // If we found a detail in range, then we have found the first bad phras e (unless we found one earlier but
493 // kept going so we could mark all instances).
494 if (badGrammarIndex >= 0 && firstBadGrammarPhrase.isEmpty()) {
495 outGrammarPhraseOffset = badGrammarPhraseLocation - paragraph.checki ngStart();
496 firstBadGrammarPhrase = paragraph.textSubstring(badGrammarPhraseLoca tion, badGrammarPhraseLength);
497
498 // Found one. We're done now, unless we're marking each instance.
499 if (!markAll)
500 break;
501 }
502
503 // These results were all between the start of the paragraph and the sta rt of the search range; look
504 // beyond this phrase.
505 startOffset = badGrammarPhraseLocation + badGrammarPhraseLength;
506 }
507
508 return firstBadGrammarPhrase;
509 }
510
511 void TextCheckingHelper::markAllMisspellings(RefPtrWillBeRawPtr<Range>& firstMis spellingRange)
512 {
513 // Use the "markAll" feature of findFirstMisspelling. Ignore the return valu e and the "out parameter";
514 // all we need to do is mark every instance.
515 int ignoredOffset;
516 findFirstMisspelling(ignoredOffset, true, firstMisspellingRange);
517 }
518
519 void TextCheckingHelper::markAllBadGrammar()
520 {
521 // Use the "markAll" feature of ofindFirstBadGrammar. Ignore the return valu e and "out parameters"; all we need to
522 // do is mark every instance.
523 GrammarDetail ignoredGrammarDetail;
524 int ignoredOffset;
525 findFirstBadGrammar(ignoredGrammarDetail, ignoredOffset, true);
526 }
527
528 bool TextCheckingHelper::unifiedTextCheckerEnabled() const
529 {
530 ASSERT(m_start.isNotNull());
531 Document& doc = m_start.computeContainerNode()->document();
532 return blink::unifiedTextCheckerEnabled(doc.frame());
533 }
534
535 void checkTextOfParagraph(TextCheckerClient& client, const String& text, TextChe ckingTypeMask checkingTypes, Vector<TextCheckingResult>& results)
536 {
537 Vector<UChar> characters;
538 text.appendTo(characters);
539 unsigned length = text.length();
540
541 Vector<TextCheckingResult> spellingResult;
542 if (checkingTypes & TextCheckingTypeSpelling)
543 findMisspellings(client, characters.data(), 0, length, spellingResult);
544
545 Vector<TextCheckingResult> grammarResult;
546 if (checkingTypes & TextCheckingTypeGrammar) {
547 // Only checks grammartical error before the first misspellings
548 int grammarCheckLength = length;
549 for (const auto& spelling : spellingResult) {
550 if (spelling.location < grammarCheckLength)
551 grammarCheckLength = spelling.location;
552 }
553
554 findBadGrammars(client, characters.data(), 0, grammarCheckLength, gramma rResult);
555 }
556
557 if (grammarResult.size())
558 results.swap(grammarResult);
559
560 if (spellingResult.size()) {
561 if (results.isEmpty())
562 results.swap(spellingResult);
563 else
564 results.appendVector(spellingResult);
565 }
566 }
567
568 bool unifiedTextCheckerEnabled(const LocalFrame* frame)
569 {
570 if (!frame)
571 return false;
572
573 const Settings* settings = frame->settings();
574 if (!settings)
575 return false;
576
577 return settings->unifiedTextCheckerEnabled();
578 }
579
580 }
OLDNEW
« no previous file with comments | « Source/core/editing/TextCheckingHelper.h ('k') | Source/core/editing/TypingCommand.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698