diff options
| author | Konstantin Tokarev <annulen@yandex.ru> | 2016-08-25 19:20:41 +0300 |
|---|---|---|
| committer | Konstantin Tokarev <annulen@yandex.ru> | 2017-02-02 12:30:55 +0000 |
| commit | 6882a04fb36642862b11efe514251d32070c3d65 (patch) | |
| tree | b7959826000b061fd5ccc7512035c7478742f7b0 /Source/WebCore/editing/TextCheckingHelper.cpp | |
| parent | ab6df191029eeeb0b0f16f127d553265659f739e (diff) | |
| download | qtwebkit-6882a04fb36642862b11efe514251d32070c3d65.tar.gz | |
Imported QtWebKit TP3 (git b57bc6801f1876c3220d5a4bfea33d620d477443)
Change-Id: I3b1d8a2808782c9f34d50240000e20cb38d3680f
Reviewed-by: Konstantin Tokarev <annulen@yandex.ru>
Diffstat (limited to 'Source/WebCore/editing/TextCheckingHelper.cpp')
| -rw-r--r-- | Source/WebCore/editing/TextCheckingHelper.cpp | 346 |
1 files changed, 164 insertions, 182 deletions
diff --git a/Source/WebCore/editing/TextCheckingHelper.cpp b/Source/WebCore/editing/TextCheckingHelper.cpp index 27c442c18..900ece54f 100644 --- a/Source/WebCore/editing/TextCheckingHelper.cpp +++ b/Source/WebCore/editing/TextCheckingHelper.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2014 Apple Inc. All rights reserved. * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) * * Redistribution and use in source and binary forms, with or without @@ -11,10 +11,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -30,81 +30,88 @@ #include "Document.h" #include "DocumentMarkerController.h" #include "Frame.h" -#include "Range.h" #include "Settings.h" #include "TextBreakIterator.h" #include "TextCheckerClient.h" #include "TextIterator.h" #include "VisiblePosition.h" #include "VisibleUnits.h" +#include <wtf/text/StringView.h> namespace WebCore { #if !USE(UNIFIED_TEXT_CHECKING) #if USE(GRAMMAR_CHECKING) -static void findBadGrammars(TextCheckerClient* client, const UChar* text, int start, int length, Vector<TextCheckingResult>& results) -{ - int checkLocation = start; - int checkLength = length; - while (0 < checkLength) { +static void findGrammaticalErrors(TextCheckerClient& client, StringView text, Vector<TextCheckingResult>& results) +{ + for (unsigned checkLocation = 0; checkLocation < text.length(); ) { int badGrammarLocation = -1; int badGrammarLength = 0; Vector<GrammarDetail> badGrammarDetails; - client->checkGrammarOfString(text + checkLocation, checkLength, badGrammarDetails, &badGrammarLocation, &badGrammarLength); + client.checkGrammarOfString(text.substring(checkLocation), badGrammarDetails, &badGrammarLocation, &badGrammarLength); if (!badGrammarLength) break; - ASSERT(0 <= badGrammarLocation && badGrammarLocation <= checkLength); - ASSERT(0 < badGrammarLength && badGrammarLocation + badGrammarLength <= checkLength); + + ASSERT(badGrammarLocation >= 0); + ASSERT(static_cast<unsigned>(badGrammarLocation) <= text.length() - checkLocation); + ASSERT(badGrammarLength > 0); + ASSERT(static_cast<unsigned>(badGrammarLength) <= text.length() - checkLocation - badGrammarLocation); + TextCheckingResult badGrammar; badGrammar.type = TextCheckingTypeGrammar; badGrammar.location = checkLocation + badGrammarLocation; badGrammar.length = badGrammarLength; - badGrammar.details.swap(badGrammarDetails); + badGrammar.details = WTFMove(badGrammarDetails); results.append(badGrammar); - checkLocation += (badGrammarLocation + badGrammarLength); - checkLength -= (badGrammarLocation + badGrammarLength); + checkLocation += badGrammarLocation + badGrammarLength; } } + #endif -static void findMisspellings(TextCheckerClient* client, const UChar* text, int start, int length, Vector<TextCheckingResult>& results) +static void findMisspellings(TextCheckerClient& client, StringView text, Vector<TextCheckingResult>& results) { - TextBreakIterator* iterator = wordBreakIterator(text + start, length); + TextBreakIterator* iterator = wordBreakIterator(text); if (!iterator) return; - int wordStart = textBreakCurrent(iterator); - while (0 <= wordStart) { + for (int wordStart = textBreakCurrent(iterator); wordStart >= 0; ) { int wordEnd = textBreakNext(iterator); if (wordEnd < 0) break; + int wordLength = wordEnd - wordStart; int misspellingLocation = -1; int misspellingLength = 0; - client->checkSpellingOfString(text + start + wordStart, wordLength, &misspellingLocation, &misspellingLength); - if (0 < misspellingLength) { - ASSERT(0 <= misspellingLocation && misspellingLocation <= wordLength); - ASSERT(0 < misspellingLength && misspellingLocation + misspellingLength <= wordLength); + client.checkSpellingOfString(text.substring(wordStart, wordLength), &misspellingLocation, &misspellingLength); + + if (misspellingLength > 0) { + ASSERT(misspellingLocation >= 0); + ASSERT(misspellingLocation <= wordLength); + ASSERT(misspellingLength > 0); + ASSERT(misspellingLocation + misspellingLength <= wordLength); + TextCheckingResult misspelling; misspelling.type = TextCheckingTypeSpelling; - misspelling.location = start + wordStart + misspellingLocation; + misspelling.location = wordStart + misspellingLocation; misspelling.length = misspellingLength; - misspelling.replacement = client->getAutoCorrectSuggestionForMisspelledWord(String(text + misspelling.location, misspelling.length)); + misspelling.replacement = client.getAutoCorrectSuggestionForMisspelledWord(text.substring(misspelling.location, misspelling.length).toStringWithoutCopying()); results.append(misspelling); } wordStart = wordEnd; } } + #endif -static PassRefPtr<Range> expandToParagraphBoundary(PassRefPtr<Range> range) +static Ref<Range> expandToParagraphBoundary(PassRefPtr<Range> range) { - RefPtr<Range> paragraphRange = range->cloneRange(IGNORE_EXCEPTION); - setStart(paragraphRange.get(), startOfParagraph(range->startPosition())); - setEnd(paragraphRange.get(), endOfParagraph(range->endPosition())); + Ref<Range> paragraphRange = range->cloneRange(); + setStart(paragraphRange.ptr(), startOfParagraph(range->startPosition())); + setEnd(paragraphRange.ptr(), endOfParagraph(range->endPosition())); return paragraphRange; } @@ -139,7 +146,7 @@ void TextCheckingParagraph::expandRangeToNextEnd() void TextCheckingParagraph::invalidateParagraphRangeValues() { m_checkingStart = m_checkingEnd = -1; - m_offsetAsRange = 0; + m_offsetAsRange = nullptr; m_text = String(); } @@ -166,25 +173,25 @@ PassRefPtr<Range> TextCheckingParagraph::subrange(int characterOffset, int chara int TextCheckingParagraph::offsetTo(const Position& position, ExceptionCode& ec) const { ASSERT(m_checkingRange); - RefPtr<Range> range = offsetAsRange()->cloneRange(ASSERT_NO_EXCEPTION); + Ref<Range> range = offsetAsRange()->cloneRange(); range->setEnd(position.containerNode(), position.computeOffsetInContainerNode(), ec); if (ec) return 0; - return TextIterator::rangeLength(range.get()); + return TextIterator::rangeLength(range.ptr()); } bool TextCheckingParagraph::isEmpty() const { // Both predicates should have same result, but we check both just for sure. // We need to investigate to remove this redundancy. - return isRangeEmpty() || isTextEmpty(); + return checkingStart() >= checkingEnd() || text().isEmpty(); } PassRefPtr<Range> TextCheckingParagraph::offsetAsRange() const { ASSERT(m_checkingRange); if (!m_offsetAsRange) - m_offsetAsRange = Range::create(paragraphRange()->startContainer()->document(), paragraphRange()->startPosition(), checkingRange()->startPosition()); + m_offsetAsRange = Range::create(paragraphRange()->startContainer().document(), paragraphRange()->startPosition(), checkingRange()->startPosition()); return m_offsetAsRange; } @@ -235,58 +242,53 @@ TextCheckingHelper::~TextCheckingHelper() String TextCheckingHelper::findFirstMisspelling(int& firstMisspellingOffset, bool markAll, RefPtr<Range>& firstMisspellingRange) { - WordAwareIterator it(m_range.get()); firstMisspellingOffset = 0; - + String firstMisspelling; int currentChunkOffset = 0; - while (!it.atEnd()) { - const UChar* chars = it.characters(); - int len = it.length(); - - // Skip some work for one-space-char hunks - if (!(len == 1 && chars[0] == ' ')) { - - int misspellingLocation = -1; - int misspellingLength = 0; - m_client->textChecker()->checkSpellingOfString(chars, len, &misspellingLocation, &misspellingLength); - - // 5490627 shows that there was some code path here where the String constructor below crashes. - // We don't know exactly what combination of bad input caused this, so we're making this much - // more robust against bad input on release builds. - ASSERT(misspellingLength >= 0); - ASSERT(misspellingLocation >= -1); - ASSERT(!misspellingLength || misspellingLocation >= 0); - ASSERT(misspellingLocation < len); - ASSERT(misspellingLength <= len); - ASSERT(misspellingLocation + misspellingLength <= len); - - if (misspellingLocation >= 0 && misspellingLength > 0 && misspellingLocation < len && misspellingLength <= len && misspellingLocation + misspellingLength <= len) { - - // Compute range of misspelled word - RefPtr<Range> misspellingRange = TextIterator::subrange(m_range.get(), currentChunkOffset + misspellingLocation, misspellingLength); - - // Remember first-encountered misspelling and its offset. - if (!firstMisspelling) { - firstMisspellingOffset = currentChunkOffset + misspellingLocation; - firstMisspelling = String(chars + misspellingLocation, misspellingLength); - firstMisspellingRange = misspellingRange; - } + for (WordAwareIterator it(*m_range); !it.atEnd(); currentChunkOffset += it.text().length(), it.advance()) { + StringView text = it.text(); + int textLength = text.length(); - // Store marker for misspelled word. - misspellingRange->startContainer()->document()->markers()->addMarker(misspellingRange.get(), DocumentMarker::Spelling); + // Skip some work for one-space-char hunks. + if (textLength == 1 && text[0] == ' ') + continue; - // Bail out if we're marking only the first misspelling, and not all instances. - if (!markAll) - break; + int misspellingLocation = -1; + int misspellingLength = 0; + m_client->textChecker()->checkSpellingOfString(text, &misspellingLocation, &misspellingLength); + + // 5490627 shows that there was some code path here where the String constructor below crashes. + // We don't know exactly what combination of bad input caused this, so we're making this much + // more robust against bad input on release builds. + ASSERT(misspellingLength >= 0); + ASSERT(misspellingLocation >= -1); + ASSERT(!misspellingLength || misspellingLocation >= 0); + ASSERT(misspellingLocation < textLength); + ASSERT(misspellingLength <= textLength); + ASSERT(misspellingLocation + misspellingLength <= textLength); + + if (misspellingLocation >= 0 && misspellingLength > 0 && misspellingLocation < textLength && misspellingLength <= textLength && misspellingLocation + misspellingLength <= textLength) { + // Compute range of misspelled word + RefPtr<Range> misspellingRange = TextIterator::subrange(m_range.get(), currentChunkOffset + misspellingLocation, misspellingLength); + + // Remember first-encountered misspelling and its offset. + if (!firstMisspelling) { + firstMisspellingOffset = currentChunkOffset + misspellingLocation; + firstMisspelling = text.substring(misspellingLocation, misspellingLength).toString(); + firstMisspellingRange = misspellingRange; } + + // Store marker for misspelled word. + misspellingRange->startContainer().document().markers().addMarker(misspellingRange.get(), DocumentMarker::Spelling); + + // Bail out if we're marking only the first misspelling, and not all instances. + if (!markAll) + break; } - - currentChunkOffset += len; - it.advance(); } - + return firstMisspelling; } @@ -310,31 +312,31 @@ String TextCheckingHelper::findFirstMisspellingOrBadGrammar(bool checkGrammar, b // Expand the search range to encompass entire paragraphs, since text checking needs that much context. // Determine the character offset from the start of the paragraph to the start of the original search range, // since we will want to ignore results in this area. - RefPtr<Range> paragraphRange = m_range->cloneRange(IGNORE_EXCEPTION); - setStart(paragraphRange.get(), startOfParagraph(m_range->startPosition())); - int totalRangeLength = TextIterator::rangeLength(paragraphRange.get()); - setEnd(paragraphRange.get(), endOfParagraph(m_range->startPosition())); + Ref<Range> paragraphRange = m_range->cloneRange(); + setStart(paragraphRange.ptr(), startOfParagraph(m_range->startPosition())); + int totalRangeLength = TextIterator::rangeLength(paragraphRange.ptr()); + setEnd(paragraphRange.ptr(), endOfParagraph(m_range->startPosition())); - RefPtr<Range> offsetAsRange = Range::create(paragraphRange->startContainer()->document(), paragraphRange->startPosition(), m_range->startPosition()); - int rangeStartOffset = TextIterator::rangeLength(offsetAsRange.get()); + Ref<Range> offsetAsRange = Range::create(paragraphRange->startContainer().document(), paragraphRange->startPosition(), m_range->startPosition()); + int rangeStartOffset = TextIterator::rangeLength(offsetAsRange.ptr()); int totalLengthProcessed = 0; bool firstIteration = true; bool lastIteration = false; while (totalLengthProcessed < totalRangeLength) { // Iterate through the search range by paragraphs, checking each one for spelling and grammar. - int currentLength = TextIterator::rangeLength(paragraphRange.get()); + int currentLength = TextIterator::rangeLength(paragraphRange.ptr()); int currentStartOffset = firstIteration ? rangeStartOffset : 0; int currentEndOffset = currentLength; if (inSameParagraph(paragraphRange->startPosition(), m_range->endPosition())) { // Determine the character offset from the end of the original search range to the end of the paragraph, // since we will want to ignore results in this area. - RefPtr<Range> endOffsetAsRange = Range::create(paragraphRange->startContainer()->document(), paragraphRange->startPosition(), m_range->endPosition()); + RefPtr<Range> endOffsetAsRange = Range::create(paragraphRange->startContainer().document(), paragraphRange->startPosition(), m_range->endPosition()); currentEndOffset = TextIterator::rangeLength(endOffsetAsRange.get()); lastIteration = true; } if (currentStartOffset < currentEndOffset) { - String paragraphString = plainText(paragraphRange.get()); + String paragraphString = plainText(paragraphRange.ptr()); if (paragraphString.length() > 0) { bool foundGrammar = false; int spellingLocation = 0; @@ -344,36 +346,38 @@ String TextCheckingHelper::findFirstMisspellingOrBadGrammar(bool checkGrammar, b Vector<TextCheckingResult> results; TextCheckingTypeMask checkingTypes = checkGrammar ? (TextCheckingTypeSpelling | TextCheckingTypeGrammar) : TextCheckingTypeSpelling; - checkTextOfParagraph(m_client->textChecker(), paragraphString.characters(), paragraphString.length(), checkingTypes, results); - - for (unsigned i = 0; i < results.size(); i++) { - const TextCheckingResult* result = &results[i]; - if (result->type == TextCheckingTypeSpelling && result->location >= currentStartOffset && result->location + result->length <= currentEndOffset) { - ASSERT(result->length > 0 && result->location >= 0); - spellingLocation = result->location; - misspelledWord = paragraphString.substring(result->location, result->length); + checkTextOfParagraph(*m_client->textChecker(), paragraphString, checkingTypes, results); + + for (auto& result : results) { + if (result.type == TextCheckingTypeSpelling && result.location >= currentStartOffset && result.location + result.length <= currentEndOffset) { + ASSERT(result.length > 0); + ASSERT(result.location >= 0); + spellingLocation = result.location; + misspelledWord = paragraphString.substring(result.location, result.length); ASSERT(misspelledWord.length()); break; } - if (checkGrammar && result->type == TextCheckingTypeGrammar && result->location < currentEndOffset && result->location + result->length > currentStartOffset) { - ASSERT(result->length > 0 && result->location >= 0); + if (checkGrammar && result.type == TextCheckingTypeGrammar && result.location < currentEndOffset && result.location + result.length > currentStartOffset) { + ASSERT(result.length > 0); + ASSERT(result.location >= 0); // We can't stop after the first grammar result, since there might still be a spelling result after // it begins but before the first detail in it, but we can stop if we find a second grammar result. if (foundGrammar) break; - for (unsigned j = 0; j < result->details.size(); j++) { - const GrammarDetail* detail = &result->details[j]; - ASSERT(detail->length > 0 && detail->location >= 0); - if (result->location + detail->location >= currentStartOffset && result->location + detail->location + detail->length <= currentEndOffset && (!foundGrammar || result->location + detail->location < grammarDetailLocation)) { + for (unsigned j = 0; j < result.details.size(); j++) { + const GrammarDetail* detail = &result.details[j]; + ASSERT(detail->length > 0); + ASSERT(detail->location >= 0); + if (result.location + detail->location >= currentStartOffset && result.location + detail->location + detail->length <= currentEndOffset && (!foundGrammar || result.location + detail->location < grammarDetailLocation)) { grammarDetailIndex = j; - grammarDetailLocation = result->location + detail->location; + grammarDetailLocation = result.location + detail->location; foundGrammar = true; } } if (foundGrammar) { - grammarPhraseLocation = result->location; - outGrammarDetail = result->details[grammarDetailIndex]; - badGrammarPhrase = paragraphString.substring(result->location, result->length); + grammarPhraseLocation = result.location; + outGrammarDetail = result.details[grammarDetailIndex]; + badGrammarPhrase = paragraphString.substring(result.location, result.length); ASSERT(badGrammarPhrase.length()); } } @@ -382,7 +386,7 @@ String TextCheckingHelper::findFirstMisspellingOrBadGrammar(bool checkGrammar, b if (!misspelledWord.isEmpty() && (!checkGrammar || badGrammarPhrase.isEmpty() || spellingLocation <= grammarDetailLocation)) { int spellingOffset = spellingLocation - currentStartOffset; if (!firstIteration) { - RefPtr<Range> paragraphOffsetAsRange = Range::create(paragraphRange->startContainer()->document(), m_range->startPosition(), paragraphRange->startPosition()); + RefPtr<Range> paragraphOffsetAsRange = Range::create(paragraphRange->startContainer().document(), m_range->startPosition(), paragraphRange->startPosition()); spellingOffset += TextIterator::rangeLength(paragraphOffsetAsRange.get()); } outIsSpelling = true; @@ -393,7 +397,7 @@ String TextCheckingHelper::findFirstMisspellingOrBadGrammar(bool checkGrammar, b if (checkGrammar && !badGrammarPhrase.isEmpty()) { int grammarPhraseOffset = grammarPhraseLocation - currentStartOffset; if (!firstIteration) { - RefPtr<Range> paragraphOffsetAsRange = Range::create(paragraphRange->startContainer()->document(), m_range->startPosition(), paragraphRange->startPosition()); + RefPtr<Range> paragraphOffsetAsRange = Range::create(paragraphRange->startContainer().document(), m_range->startPosition(), paragraphRange->startPosition()); grammarPhraseOffset += TextIterator::rangeLength(paragraphOffsetAsRange.get()); } outIsSpelling = false; @@ -406,8 +410,8 @@ String TextCheckingHelper::findFirstMisspellingOrBadGrammar(bool checkGrammar, b if (lastIteration || totalLengthProcessed + currentLength >= totalRangeLength) break; VisiblePosition newParagraphStart = startOfNextParagraph(paragraphRange->endPosition()); - setStart(paragraphRange.get(), newParagraphStart); - setEnd(paragraphRange.get(), endOfParagraph(newParagraphStart)); + setStart(paragraphRange.ptr(), newParagraphStart); + setEnd(paragraphRange.ptr(), endOfParagraph(newParagraphStart)); firstIteration = false; totalLengthProcessed += currentLength; } @@ -415,7 +419,8 @@ String TextCheckingHelper::findFirstMisspellingOrBadGrammar(bool checkGrammar, b } #if USE(GRAMMAR_CHECKING) -int TextCheckingHelper::findFirstGrammarDetail(const Vector<GrammarDetail>& grammarDetails, int badGrammarPhraseLocation, int /*badGrammarPhraseLength*/, int startOffset, int endOffset, bool markAll) + +int TextCheckingHelper::findFirstGrammarDetail(const Vector<GrammarDetail>& grammarDetails, int badGrammarPhraseLocation, int startOffset, int endOffset, bool markAll) const { // Found some bad grammar. Find the earliest detail range that starts in our search range (if any). // Optionally add a DocumentMarker for each detail in the range. @@ -423,7 +428,8 @@ int TextCheckingHelper::findFirstGrammarDetail(const Vector<GrammarDetail>& gram int earliestDetailIndex = -1; for (unsigned i = 0; i < grammarDetails.size(); i++) { const GrammarDetail* detail = &grammarDetails[i]; - ASSERT(detail->length > 0 && detail->location >= 0); + ASSERT(detail->length > 0); + ASSERT(detail->location >= 0); int detailStartOffsetInParagraph = badGrammarPhraseLocation + detail->location; @@ -437,7 +443,7 @@ int TextCheckingHelper::findFirstGrammarDetail(const Vector<GrammarDetail>& gram if (markAll) { RefPtr<Range> badGrammarRange = TextIterator::subrange(m_range.get(), badGrammarPhraseLocation - startOffset + detail->location, detail->length); - badGrammarRange->startContainer()->document()->markers()->addMarker(badGrammarRange.get(), DocumentMarker::Grammar, detail->userDescription); + badGrammarRange->startContainer().document().markers().addMarker(badGrammarRange.get(), DocumentMarker::Grammar, detail->userDescription); } // Remember this detail only if it's earlier than our current candidate (the details aren't in a guaranteed order) @@ -450,7 +456,7 @@ int TextCheckingHelper::findFirstGrammarDetail(const Vector<GrammarDetail>& gram return earliestDetailIndex; } -String TextCheckingHelper::findFirstBadGrammar(GrammarDetail& outGrammarDetail, int& outGrammarPhraseOffset, bool markAll) +String TextCheckingHelper::findFirstBadGrammar(GrammarDetail& outGrammarDetail, int& outGrammarPhraseOffset, bool markAll) const { // Initialize out parameters; these will be updated if we find something to return. outGrammarDetail.location = -1; @@ -467,12 +473,11 @@ String TextCheckingHelper::findFirstBadGrammar(GrammarDetail& outGrammarDetail, TextCheckingParagraph paragraph(m_range); // Start checking from beginning of paragraph, but skip past results that occur before the start of the original search range. - int startOffset = 0; - while (startOffset < paragraph.checkingEnd()) { + for (int startOffset = 0; startOffset < paragraph.checkingEnd(); ) { Vector<GrammarDetail> grammarDetails; int badGrammarPhraseLocation = -1; int badGrammarPhraseLength = 0; - m_client->textChecker()->checkGrammarOfString(paragraph.textCharacters() + startOffset, paragraph.textLength() - startOffset, grammarDetails, &badGrammarPhraseLocation, &badGrammarPhraseLength); + m_client->textChecker()->checkGrammarOfString(StringView(paragraph.text()).substring(startOffset), grammarDetails, &badGrammarPhraseLocation, &badGrammarPhraseLength); if (!badGrammarPhraseLength) { ASSERT(badGrammarPhraseLocation == -1); @@ -482,9 +487,8 @@ String TextCheckingHelper::findFirstBadGrammar(GrammarDetail& outGrammarDetail, ASSERT(badGrammarPhraseLocation >= 0); badGrammarPhraseLocation += startOffset; - // Found some bad grammar. Find the earliest detail range that starts in our search range (if any). - int badGrammarIndex = findFirstGrammarDetail(grammarDetails, badGrammarPhraseLocation, badGrammarPhraseLength, paragraph.checkingStart(), paragraph.checkingEnd(), markAll); + int badGrammarIndex = findFirstGrammarDetail(grammarDetails, badGrammarPhraseLocation, paragraph.checkingStart(), paragraph.checkingEnd(), markAll); if (badGrammarIndex >= 0) { ASSERT(static_cast<unsigned>(badGrammarIndex) < grammarDetails.size()); outGrammarDetail = grammarDetails[badGrammarIndex]; @@ -509,23 +513,21 @@ String TextCheckingHelper::findFirstBadGrammar(GrammarDetail& outGrammarDetail, return firstBadGrammarPhrase; } - -bool TextCheckingHelper::isUngrammatical(Vector<String>& guessesVector) const +bool TextCheckingHelper::isUngrammatical() const { if (!m_client) return false; - if (!m_range || m_range->collapsed(IGNORE_EXCEPTION)) + if (!m_range || m_range->collapsed()) return false; // Returns true only if the passed range exactly corresponds to a bad grammar detail range. This is analogous // to isSelectionMisspelled. It's not good enough for there to be some bad grammar somewhere in the range, // or overlapping the range; the ranges must exactly match. - guessesVector.clear(); int grammarPhraseOffset; GrammarDetail grammarDetail; - String badGrammarPhrase = const_cast<TextCheckingHelper*>(this)->findFirstBadGrammar(grammarDetail, grammarPhraseOffset, false); + String badGrammarPhrase = findFirstBadGrammar(grammarDetail, grammarPhraseOffset, false); // No bad grammar in these parts at all. if (badGrammarPhrase.isEmpty()) @@ -534,9 +536,10 @@ bool TextCheckingHelper::isUngrammatical(Vector<String>& guessesVector) const // Bad grammar, but phrase (e.g. sentence) starts beyond start of range. if (grammarPhraseOffset > 0) return false; - - ASSERT(grammarDetail.location >= 0 && grammarDetail.length > 0); - + + ASSERT(grammarDetail.location >= 0); + ASSERT(grammarDetail.length > 0); + // Bad grammar, but start of detail (e.g. ungrammatical word) doesn't match start of range if (grammarDetail.location + grammarPhraseOffset) return false; @@ -553,7 +556,8 @@ bool TextCheckingHelper::isUngrammatical(Vector<String>& guessesVector) const return true; } -#endif + +#endif // USE(GRAMMAR_CHECKING) Vector<String> TextCheckingHelper::guessesForMisspelledOrUngrammaticalRange(bool checkGrammar, bool& misspelled, bool& ungrammatical) const { @@ -564,7 +568,7 @@ Vector<String> TextCheckingHelper::guessesForMisspelledOrUngrammaticalRange(bool misspelled = false; ungrammatical = false; - if (!m_client || !m_range || m_range->collapsed(IGNORE_EXCEPTION)) + if (!m_client || !m_range || m_range->collapsed()) return guesses; // Expand the range to encompass entire paragraphs, since text checking needs that much context. @@ -574,11 +578,10 @@ Vector<String> TextCheckingHelper::guessesForMisspelledOrUngrammaticalRange(bool Vector<TextCheckingResult> results; TextCheckingTypeMask checkingTypes = checkGrammar ? (TextCheckingTypeSpelling | TextCheckingTypeGrammar) : TextCheckingTypeSpelling; - checkTextOfParagraph(m_client->textChecker(), paragraph.textCharacters(), paragraph.textLength(), checkingTypes, results); - - for (unsigned i = 0; i < results.size(); i++) { - const TextCheckingResult* result = &results[i]; - if (result->type == TextCheckingTypeSpelling && paragraph.checkingRangeMatches(result->location, result->length)) { + checkTextOfParagraph(*m_client->textChecker(), paragraph.text(), checkingTypes, results); + + for (auto& result : results) { + if (result.type == TextCheckingTypeSpelling && paragraph.checkingRangeMatches(result.location, result.length)) { String misspelledWord = paragraph.checkingSubstring(); ASSERT(misspelledWord.length()); m_client->textChecker()->getGuessesForWord(misspelledWord, String(), guesses); @@ -590,19 +593,18 @@ Vector<String> TextCheckingHelper::guessesForMisspelledOrUngrammaticalRange(bool if (!checkGrammar) return guesses; - - for (unsigned i = 0; i < results.size(); i++) { - const TextCheckingResult* result = &results[i]; - if (result->type == TextCheckingTypeGrammar && paragraph.isCheckingRangeCoveredBy(result->location, result->length)) { - for (unsigned j = 0; j < result->details.size(); j++) { - const GrammarDetail* detail = &result->details[j]; - ASSERT(detail->length > 0 && detail->location >= 0); - if (paragraph.checkingRangeMatches(result->location + detail->location, detail->length)) { - String badGrammarPhrase = paragraph.textSubstring(result->location, result->length); + + for (auto& result : results) { + if (result.type == TextCheckingTypeGrammar && paragraph.isCheckingRangeCoveredBy(result.location, result.length)) { + for (auto& detail : result.details) { + ASSERT(detail.length > 0); + ASSERT(detail.location >= 0); + if (paragraph.checkingRangeMatches(result.location + detail.location, detail.length)) { + String badGrammarPhrase = paragraph.textSubstring(result.location, result.length); ASSERT(badGrammarPhrase.length()); - for (unsigned k = 0; k < detail->guesses.size(); k++) - guesses.append(detail->guesses[k]); - m_client->updateSpellingUIWithGrammarString(badGrammarPhrase, *detail); + for (auto& guess : detail.guesses) + guesses.append(guess); + m_client->updateSpellingUIWithGrammarString(badGrammarPhrase, detail); ungrammatical = true; return guesses; } @@ -612,7 +614,6 @@ Vector<String> TextCheckingHelper::guessesForMisspelledOrUngrammaticalRange(bool return guesses; } - void TextCheckingHelper::markAllMisspellings(RefPtr<Range>& firstMisspellingRange) { // Use the "markAll" feature of findFirstMisspelling. Ignore the return value and the "out parameter"; @@ -634,62 +635,43 @@ void TextCheckingHelper::markAllBadGrammar() bool TextCheckingHelper::unifiedTextCheckerEnabled() const { - if (!m_range) - return false; - - Document* doc = m_range->ownerDocument(); - if (!doc) - return false; - - return WebCore::unifiedTextCheckerEnabled(doc->frame()); + return m_range && WebCore::unifiedTextCheckerEnabled(m_range->ownerDocument().frame()); } -void checkTextOfParagraph(TextCheckerClient* client, const UChar* text, int length, - TextCheckingTypeMask checkingTypes, Vector<TextCheckingResult>& results) +void checkTextOfParagraph(TextCheckerClient& client, StringView text, TextCheckingTypeMask checkingTypes, Vector<TextCheckingResult>& results) { #if USE(UNIFIED_TEXT_CHECKING) - client->checkTextOfParagraph(text, length, checkingTypes, results); + results = client.checkTextOfParagraph(text, checkingTypes); #else - Vector<TextCheckingResult> spellingResult; + Vector<TextCheckingResult> mispellings; if (checkingTypes & TextCheckingTypeSpelling) - findMisspellings(client, text, 0, length, spellingResult); + findMisspellings(client, text, mispellings); #if USE(GRAMMAR_CHECKING) - Vector<TextCheckingResult> grammarResult; + // Look for grammatical errors that occur before the first misspelling. + Vector<TextCheckingResult> grammaticalErrors; if (checkingTypes & TextCheckingTypeGrammar) { - // Only checks grammartical error before the first misspellings - int grammarCheckLength = length; - for (size_t i = 0; i < spellingResult.size(); ++i) { - if (spellingResult[i].location < grammarCheckLength) - grammarCheckLength = spellingResult[i].location; - } - - findBadGrammars(client, text, 0, grammarCheckLength, grammarResult); + unsigned grammarCheckLength = text.length(); + for (auto& mispelling : mispellings) + grammarCheckLength = std::min<unsigned>(grammarCheckLength, mispelling.location); + findGrammaticalErrors(client, text.substring(0, grammarCheckLength), grammaticalErrors); } - if (grammarResult.size()) - results.swap(grammarResult); + results = WTFMove(grammaticalErrors); #endif - if (spellingResult.size()) { - if (results.isEmpty()) - results.swap(spellingResult); - else - results.appendVector(spellingResult); - } -#endif + if (results.isEmpty()) + results = WTFMove(mispellings); + else + results.appendVector(mispellings); +#endif // USE(UNIFIED_TEXT_CHECKING) } bool unifiedTextCheckerEnabled(const Frame* frame) { if (!frame) return false; - - const Settings* settings = frame->settings(); - if (!settings) - return false; - - return settings->unifiedTextCheckerEnabled(); + return frame->settings().unifiedTextCheckerEnabled(); } } |
