[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-9427-gc2be6fc

morrita at google.com morrita at google.com
Wed Dec 22 15:47:15 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit 13e1e1cfe7db03c647b54d0fd04541e26f1cf419
Author: morrita at google.com <morrita at google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Fri Nov 12 09:24:11 2010 +0000

    2010-11-05  MORITA Hajime  <morrita at google.com>
    
            Reviewed by Kent Tamura.
    
            Refactoring: Return values of TextCheckingHelper::paragraphAlignedRange should form a class.
            https://bugs.webkit.org/show_bug.cgi?id=49053
    
            Replaced paragraphAlignedRange() function call into
            TextCheckingParagraph class. The class encapsulates a range of a
            paragraph, and its relation within associated checking range.
            Instance variables of the class are computed lazily. So we can save unnecessary
            memory allocation and DOM tree traversal.
    
            No new tests, no behavior change.
    
            * editing/Editor.cpp:
            (WebCore::Editor::markAllMisspellingsAndBadGrammarInRanges): Replaced paragraphAlignedRange() call.
            (WebCore::Editor::changeBackToReplacedString): Replaced paragraphAlignedRange() call.
            * editing/TextCheckingHelper.cpp:
            (WebCore::expandToParagraphBoundary):
            (WebCore::TextCheckingParagraph::TextCheckingParagraph):
            (WebCore::TextCheckingParagraph::~TextCheckingParagraph):
            (WebCore::TextCheckingParagraph::expandRangeToNextEnd):
            (WebCore::TextCheckingParagraph::invalidateParagraphRangeValues):
            (WebCore::TextCheckingParagraph::rangeLength):
            (WebCore::TextCheckingParagraph::paragraphRange):
            (WebCore::TextCheckingParagraph::subrange):
            (WebCore::TextCheckingParagraph::offsetTo):
            (WebCore::TextCheckingParagraph::isEmpty):
            (WebCore::TextCheckingParagraph::offsetAsRange):
            (WebCore::TextCheckingParagraph::text):
            (WebCore::TextCheckingParagraph::checkingStart):
            (WebCore::TextCheckingParagraph::checkingEnd):
            (WebCore::TextCheckingParagraph::checkingLength):
            (WebCore::TextCheckingHelper::findFirstBadGrammar): Replaced paragraphAlignedRange() call.
            (WebCore::TextCheckingHelper::guessesForMisspelledOrUngrammaticalRange): Replaced paragraphAlignedRange() call.
            * editing/TextCheckingHelper.h:
            (WebCore::TextCheckingParagraph::textLength):
            (WebCore::TextCheckingParagraph::textSubstring):
            (WebCore::TextCheckingParagraph::textCharacters):
            (WebCore::TextCheckingParagraph::textCharAt):
            (WebCore::TextCheckingParagraph::checkingSubstring):
            (WebCore::TextCheckingParagraph::checkingRangeMatches):
            (WebCore::TextCheckingParagraph::isCheckingRangeCoveredBy):
            (WebCore::TextCheckingParagraph::checkingRangeCovers):
            (WebCore::TextCheckingParagraph::checkingRange):
            (WebCore::TextCheckingParagraph::isTextEmpty):
            (WebCore::TextCheckingParagraph::isRangeEmpty):
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@71898 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 5aec9b6..d42b9e6 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,52 @@
+2010-11-05  MORITA Hajime  <morrita at google.com>
+
+        Reviewed by Kent Tamura.
+
+        Refactoring: Return values of TextCheckingHelper::paragraphAlignedRange should form a class.
+        https://bugs.webkit.org/show_bug.cgi?id=49053
+
+        Replaced paragraphAlignedRange() function call into
+        TextCheckingParagraph class. The class encapsulates a range of a
+        paragraph, and its relation within associated checking range.
+        Instance variables of the class are computed lazily. So we can save unnecessary
+        memory allocation and DOM tree traversal.
+        
+        No new tests, no behavior change. 
+
+        * editing/Editor.cpp:
+        (WebCore::Editor::markAllMisspellingsAndBadGrammarInRanges): Replaced paragraphAlignedRange() call.
+        (WebCore::Editor::changeBackToReplacedString): Replaced paragraphAlignedRange() call.
+        * editing/TextCheckingHelper.cpp:
+        (WebCore::expandToParagraphBoundary):
+        (WebCore::TextCheckingParagraph::TextCheckingParagraph):
+        (WebCore::TextCheckingParagraph::~TextCheckingParagraph):
+        (WebCore::TextCheckingParagraph::expandRangeToNextEnd):
+        (WebCore::TextCheckingParagraph::invalidateParagraphRangeValues):
+        (WebCore::TextCheckingParagraph::rangeLength):
+        (WebCore::TextCheckingParagraph::paragraphRange):
+        (WebCore::TextCheckingParagraph::subrange):
+        (WebCore::TextCheckingParagraph::offsetTo):
+        (WebCore::TextCheckingParagraph::isEmpty):
+        (WebCore::TextCheckingParagraph::offsetAsRange):
+        (WebCore::TextCheckingParagraph::text):
+        (WebCore::TextCheckingParagraph::checkingStart):
+        (WebCore::TextCheckingParagraph::checkingEnd):
+        (WebCore::TextCheckingParagraph::checkingLength):
+        (WebCore::TextCheckingHelper::findFirstBadGrammar): Replaced paragraphAlignedRange() call.
+        (WebCore::TextCheckingHelper::guessesForMisspelledOrUngrammaticalRange): Replaced paragraphAlignedRange() call.
+        * editing/TextCheckingHelper.h:
+        (WebCore::TextCheckingParagraph::textLength):
+        (WebCore::TextCheckingParagraph::textSubstring):
+        (WebCore::TextCheckingParagraph::textCharacters):
+        (WebCore::TextCheckingParagraph::textCharAt):
+        (WebCore::TextCheckingParagraph::checkingSubstring):
+        (WebCore::TextCheckingParagraph::checkingRangeMatches):
+        (WebCore::TextCheckingParagraph::isCheckingRangeCoveredBy):
+        (WebCore::TextCheckingParagraph::checkingRangeCovers):
+        (WebCore::TextCheckingParagraph::checkingRange):
+        (WebCore::TextCheckingParagraph::isTextEmpty):
+        (WebCore::TextCheckingParagraph::isRangeEmpty):
+
 2010-11-11  Ryosuke Niwa  <rniwa at webkit.org>
 
         Reviewed by Darin Adler.
diff --git a/WebCore/editing/Editor.cpp b/WebCore/editing/Editor.cpp
index 327aa5f..c670e87 100644
--- a/WebCore/editing/Editor.cpp
+++ b/WebCore/editing/Editor.cpp
@@ -2185,46 +2185,30 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
         return;
 
     // Expand the range to encompass entire paragraphs, since text checking needs that much context.
-    int spellingRangeStartOffset = 0;
-    int spellingRangeEndOffset = 0;
-    int grammarRangeStartOffset = 0;
-    int grammarRangeEndOffset = 0;
-    int offsetDueToReplacement = 0;
-    int paragraphLength = 0;
     int selectionOffset = 0;
     int ambiguousBoundaryOffset = -1;
     bool selectionChanged = false;
     bool restoreSelectionAfterChange = false;
     bool adjustSelectionForParagraphBoundaries = false;
-    String paragraphString;
-    RefPtr<Range> paragraphRange;
-
-    if (shouldMarkGrammar) {
-        // The spelling range should be contained in the paragraph-aligned extension of the grammar range.
-        paragraphRange = TextCheckingHelper(client(), grammarRange).paragraphAlignedRange(grammarRangeStartOffset, paragraphString);
-        RefPtr<Range> offsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), paragraphRange->startPosition(), spellingRange->startPosition());
-        spellingRangeStartOffset = TextIterator::rangeLength(offsetAsRange.get());
-        grammarRangeEndOffset = grammarRangeStartOffset + TextIterator::rangeLength(grammarRange);
-    } else {
-        paragraphRange = TextCheckingHelper(client(), spellingRange).paragraphAlignedRange(spellingRangeStartOffset, paragraphString);
-    }
-    spellingRangeEndOffset = spellingRangeStartOffset + TextIterator::rangeLength(spellingRange);
-    paragraphLength = paragraphString.length();
-    if (paragraphLength <= 0 || (spellingRangeStartOffset >= spellingRangeEndOffset && (!shouldMarkGrammar || grammarRangeStartOffset >= grammarRangeEndOffset)))
+
+    TextCheckingParagraph spellingParagraph(spellingRange);
+    TextCheckingParagraph grammarParagraph(shouldMarkGrammar ? grammarRange : 0);
+    TextCheckingParagraph& paragraph = shouldMarkGrammar ? grammarParagraph : spellingParagraph; 
+
+    if (shouldMarkGrammar ? (spellingParagraph.isRangeEmpty() && grammarParagraph.isEmpty()) : spellingParagraph.isEmpty())
         return;
 
     if (shouldPerformReplacement) {
         if (m_frame->selection()->selectionType() == VisibleSelection::CaretSelection) {
             // Attempt to save the caret position so we can restore it later if needed
-            RefPtr<Range> offsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), paragraphRange->startPosition(), paragraphRange->startPosition());
             Position caretPosition = m_frame->selection()->end();
-            offsetAsRange->setEnd(caretPosition.containerNode(), caretPosition.computeOffsetInContainerNode(), ec);
+            int offset = paragraph.offsetTo(caretPosition, ec);
             if (!ec) {
-                selectionOffset = TextIterator::rangeLength(offsetAsRange.get());
+                selectionOffset = offset;
                 restoreSelectionAfterChange = true;
-                if (selectionOffset > 0 && (selectionOffset > paragraphLength || paragraphString[selectionOffset - 1] == newlineCharacter))
+                if (selectionOffset > 0 && (selectionOffset > paragraph.textLength() || paragraph.textCharAt(selectionOffset - 1) == newlineCharacter))
                     adjustSelectionForParagraphBoundaries = true;
-                if (selectionOffset > 0 && selectionOffset <= paragraphLength && isAmbiguousBoundaryCharacter(paragraphString[selectionOffset - 1]))
+                if (selectionOffset > 0 && selectionOffset <= paragraph.textLength() && isAmbiguousBoundaryCharacter(paragraph.textCharAt(selectionOffset - 1)))
                     ambiguousBoundaryOffset = selectionOffset - 1;
             }
         }
@@ -2250,7 +2234,7 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
         if (shouldMarkSpelling && isAutomaticSpellingCorrectionEnabled())
             checkingTypes |= TextCheckingTypeCorrection;
     }
-    client()->checkTextOfParagraph(paragraphString.characters(), paragraphLength, checkingTypes, results);
+    client()->checkTextOfParagraph(paragraph.textCharacters(), paragraph.textLength(), checkingTypes, results);
 
 #if SUPPORT_AUTOCORRECTION_PANEL
     // If this checking is only for showing correction panel, we shouldn't bother to mark misspellings.
@@ -2258,25 +2242,28 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
         shouldMarkSpelling = false;
 #endif
 
+    int offsetDueToReplacement = 0;
+
     for (unsigned i = 0; i < results.size(); i++) {
+        int spellingRangeEndOffset = spellingParagraph.checkingEnd() + offsetDueToReplacement;
         const TextCheckingResult* result = &results[i];
         int resultLocation = result->location + offsetDueToReplacement;
         int resultLength = result->length;
-        if (shouldMarkSpelling && result->type == TextCheckingTypeSpelling && resultLocation >= spellingRangeStartOffset && resultLocation + resultLength <= spellingRangeEndOffset) {
+        if (shouldMarkSpelling && result->type == TextCheckingTypeSpelling && resultLocation >= spellingParagraph.checkingStart() && resultLocation + resultLength <= spellingRangeEndOffset) {
             ASSERT(resultLength > 0 && resultLocation >= 0);
-            RefPtr<Range> misspellingRange = TextIterator::subrange(spellingRange, resultLocation - spellingRangeStartOffset, resultLength);
+            RefPtr<Range> misspellingRange = spellingParagraph.subrange(resultLocation, resultLength);
             misspellingRange->startContainer(ec)->document()->markers()->addMarker(misspellingRange.get(), DocumentMarker::Spelling);
-        } else if (shouldMarkGrammar && result->type == TextCheckingTypeGrammar && resultLocation < grammarRangeEndOffset && resultLocation + resultLength > grammarRangeStartOffset) {
+        } else if (shouldMarkGrammar && result->type == TextCheckingTypeGrammar && grammarParagraph.checkingRangeCovers(resultLocation, resultLength)) {
             ASSERT(resultLength > 0 && resultLocation >= 0);
             for (unsigned j = 0; j < result->details.size(); j++) {
                 const GrammarDetail* detail = &result->details[j];
                 ASSERT(detail->length > 0 && detail->location >= 0);
-                if (resultLocation + detail->location >= grammarRangeStartOffset && resultLocation + detail->location + detail->length <= grammarRangeEndOffset) {
-                    RefPtr<Range> badGrammarRange = TextIterator::subrange(grammarRange, resultLocation + detail->location - grammarRangeStartOffset, detail->length);
+                if (grammarParagraph.checkingRangeCovers(resultLocation + detail->location, detail->length)) {
+                    RefPtr<Range> badGrammarRange = grammarParagraph.subrange(resultLocation + detail->location, detail->length);
                     grammarRange->startContainer(ec)->document()->markers()->addMarker(badGrammarRange.get(), DocumentMarker::Grammar, detail->userDescription);
                 }
             }
-        } else if ((shouldPerformReplacement || shouldShowCorrectionPanel) && resultLocation + resultLength <= spellingRangeEndOffset && resultLocation + resultLength >= spellingRangeStartOffset
+        } else if ((shouldPerformReplacement || shouldShowCorrectionPanel) && resultLocation + resultLength <= spellingRangeEndOffset && resultLocation + resultLength >= spellingParagraph.checkingStart()
                     && (result->type == TextCheckingTypeLink
                     || result->type == TextCheckingTypeQuote
                     || result->type == TextCheckingTypeDash
@@ -2290,7 +2277,7 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
 
             int replacementLength = result->replacement.length();
             bool doReplacement = (replacementLength > 0);
-            RefPtr<Range> rangeToReplace = TextIterator::subrange(paragraphRange.get(), resultLocation, resultLength);
+            RefPtr<Range> rangeToReplace = paragraph.subrange(resultLocation, resultLength);
             VisibleSelection selectionToReplace(rangeToReplace.get(), DOWNSTREAM);
         
             // avoid correcting text after an ambiguous boundary character has been typed
@@ -2356,13 +2343,12 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
 #endif
                     if (doReplacement) {
                         replaceSelectionWithText(result->replacement, false, false);
-                        spellingRangeEndOffset += replacementLength - resultLength;
                         offsetDueToReplacement += replacementLength - resultLength;
                         if (resultLocation < selectionOffset)
                             selectionOffset += replacementLength - resultLength;
                         if (result->type == TextCheckingTypeCorrection) {
                             // Add a marker so that corrections can easily be undone and won't be re-corrected.
-                            RefPtr<Range> replacedRange = TextIterator::subrange(paragraphRange.get(), resultLocation, replacementLength);
+                            RefPtr<Range> replacedRange = paragraph.subrange(resultLocation, replacementLength);
                             replacedRange->startContainer()->document()->markers()->addMarker(replacedRange.get(), DocumentMarker::Replacement, replacedString);
                             replacedRange->startContainer()->document()->markers()->addMarker(replacedRange.get(), DocumentMarker::CorrectionIndicator, replacedString);
                         }
@@ -2374,10 +2360,9 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
 
     if (selectionChanged) {
         // Restore the caret position if we have made any replacements
-        setEnd(paragraphRange.get(), endOfParagraph(startOfNextParagraph(paragraphRange->startPosition())));
-        int newLength = TextIterator::rangeLength(paragraphRange.get());
-        if (restoreSelectionAfterChange && selectionOffset >= 0 && selectionOffset <= newLength) {
-            RefPtr<Range> selectionRange = TextIterator::subrange(paragraphRange.get(), 0, selectionOffset);
+        paragraph.expandRangeToNextEnd();
+        if (restoreSelectionAfterChange && selectionOffset >= 0 && selectionOffset <= paragraph.rangeLength()) {
+            RefPtr<Range> selectionRange = paragraph.subrange(0, selectionOffset);
             m_frame->selection()->moveTo(selectionRange->endPosition(), DOWNSTREAM);
             if (adjustSelectionForParagraphBoundaries)
                 m_frame->selection()->modify(SelectionController::AlterationMove, SelectionController::DirectionForward, CharacterGranularity);
@@ -2398,11 +2383,9 @@ void Editor::changeBackToReplacedString(const String& replacedString)
     if (!shouldInsertText(replacedString, selection.get(), EditorInsertActionPasted))
         return;
     
-    String paragraphString;
-    int selectionOffset;
-    RefPtr<Range> paragraphRange = TextCheckingHelper(client(), selection).paragraphAlignedRange(selectionOffset, paragraphString);
+    TextCheckingParagraph paragraph(selection);
     replaceSelectionWithText(replacedString, false, false);
-    RefPtr<Range> changedRange = TextIterator::subrange(paragraphRange.get(), selectionOffset, replacedString.length());
+    RefPtr<Range> changedRange = paragraph.subrange(paragraph.checkingStart(), replacedString.length());
     changedRange->startContainer()->document()->markers()->addMarker(changedRange.get(), DocumentMarker::Replacement, String());
 }
 
diff --git a/WebCore/editing/TextCheckingHelper.cpp b/WebCore/editing/TextCheckingHelper.cpp
index 49674ff..d524cf3 100644
--- a/WebCore/editing/TextCheckingHelper.cpp
+++ b/WebCore/editing/TextCheckingHelper.cpp
@@ -34,6 +34,121 @@
 
 namespace WebCore {
 
+static PassRefPtr<Range> expandToParagraphBoundary(PassRefPtr<Range> range)
+{
+    ExceptionCode ec = 0;
+    RefPtr<Range> paragraphRange = range->cloneRange(ec);
+    setStart(paragraphRange.get(), startOfParagraph(range->startPosition()));
+    setEnd(paragraphRange.get(), endOfParagraph(range->endPosition()));
+    return paragraphRange;
+}
+
+TextCheckingParagraph::TextCheckingParagraph(PassRefPtr<Range> checkingRange)
+    : m_checkingRange(checkingRange)
+    , m_checkingStart(-1)
+    , m_checkingEnd(-1)
+    , m_checkingLength(-1)
+{
+}
+
+TextCheckingParagraph::~TextCheckingParagraph()
+{
+}
+
+void TextCheckingParagraph::expandRangeToNextEnd()
+{
+    ASSERT(m_checkingRange);
+    setEnd(paragraphRange().get(), endOfParagraph(startOfNextParagraph(paragraphRange()->startPosition())));
+    invalidateParagraphRangeValues();
+}
+
+void TextCheckingParagraph::invalidateParagraphRangeValues()
+{
+    m_checkingStart = m_checkingEnd = -1;
+    m_offsetAsRange = 0;
+    m_text = String();
+}
+
+int TextCheckingParagraph::rangeLength() const
+{
+    ASSERT(m_checkingRange);
+    return TextIterator::rangeLength(paragraphRange().get());
+}
+
+PassRefPtr<Range> TextCheckingParagraph::paragraphRange() const
+{
+    ASSERT(m_checkingRange);
+    if (!m_paragraphRange)
+        m_paragraphRange = expandToParagraphBoundary(checkingRange());
+    return m_paragraphRange;
+}
+
+PassRefPtr<Range> TextCheckingParagraph::subrange(int characterOffset, int characterCount) const
+{
+    ASSERT(m_checkingRange);
+    return TextIterator::subrange(paragraphRange().get(), characterOffset, characterCount);
+}
+
+int TextCheckingParagraph::offsetTo(const Position& position, ExceptionCode& ec) const
+{
+    ASSERT(m_checkingRange);
+    RefPtr<Range> range = offsetAsRange();
+    range->setEnd(position.containerNode(), position.computeOffsetInContainerNode(), ec);
+    if (ec)
+        return 0;
+    return TextIterator::rangeLength(range.get());
+}
+
+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();
+}
+
+PassRefPtr<Range> TextCheckingParagraph::offsetAsRange() const
+{
+    ASSERT(m_checkingRange);
+    if (!m_offsetAsRange) {
+        ExceptionCode ec = 0;
+        m_offsetAsRange = Range::create(paragraphRange()->startContainer(ec)->document(), paragraphRange()->startPosition(), checkingRange()->startPosition());
+    }
+
+    return m_offsetAsRange;
+}
+
+const String& TextCheckingParagraph::text() const
+{
+    ASSERT(m_checkingRange);
+    if (m_text.isEmpty())
+        m_text = plainText(paragraphRange().get());
+    return m_text; 
+}
+
+int TextCheckingParagraph::checkingStart() const
+{
+    ASSERT(m_checkingRange);
+    if (m_checkingStart == -1)
+        m_checkingStart = TextIterator::rangeLength(offsetAsRange().get());
+    return m_checkingStart;
+}
+
+int TextCheckingParagraph::checkingEnd() const
+{
+    ASSERT(m_checkingRange);
+    if (m_checkingEnd == -1)
+        m_checkingEnd = checkingStart() + TextIterator::rangeLength(checkingRange().get());
+    return m_checkingEnd;
+}
+
+int TextCheckingParagraph::checkingLength() const
+{
+    ASSERT(m_checkingRange);
+    if (-1 == m_checkingLength)
+        m_checkingLength = TextIterator::rangeLength(checkingRange().get());
+    return m_checkingLength;
+}
+
 TextCheckingHelper::TextCheckingHelper(EditorClient* client, PassRefPtr<Range> range)
     : m_client(client)
     , m_range(range)
@@ -46,33 +161,6 @@ TextCheckingHelper::~TextCheckingHelper()
 {
 }
 
-PassRefPtr<Range> TextCheckingHelper::paragraphAlignedRange(int& offsetIntoParagraphAlignedRange, String& paragraphString) const
-{
-#ifndef BUILDING_ON_TIGER
-    ExceptionCode ec = 0;
-    
-    // Expand range to paragraph boundaries
-    RefPtr<Range> paragraphRange = m_range->cloneRange(ec);
-    setStart(paragraphRange.get(), startOfParagraph(m_range->startPosition()));
-    setEnd(paragraphRange.get(), endOfParagraph(m_range->endPosition()));
-    
-    // Compute offset from start of expanded range to start of original range
-    RefPtr<Range> offsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), paragraphRange->startPosition(), m_range->startPosition());
-    offsetIntoParagraphAlignedRange = TextIterator::rangeLength(offsetAsRange.get());
-    
-    // Fill in out parameter with string representing entire paragraph range.
-    // Someday we might have a caller that doesn't use this, but for now all callers do.
-    paragraphString = plainText(paragraphRange.get());
-
-    return paragraphRange;
-#else
-    ASSERT_NOT_REACHED();
-    UNUSED_PARAM(offsetIntoParagraphAlignedRange);
-    UNUSED_PARAM(paragraphString);
-    return PassRefPtr<Range>(0);
-#endif
-}
-
 String TextCheckingHelper::findFirstMisspelling(int& firstMisspellingOffset, bool markAll, RefPtr<Range>& firstMisspellingRange)
 {
     WordAwareIterator it(m_range.get());
@@ -325,21 +413,15 @@ String TextCheckingHelper::findFirstBadGrammar(GrammarDetail& outGrammarDetail,
     // Expand the search range to encompass entire paragraphs, since grammar 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.
-    int searchRangeStartOffset;
-    String paragraphString;
-    RefPtr<Range> paragraphRange = paragraphAlignedRange(searchRangeStartOffset, paragraphString);
-        
-    // Determine the character offset from the start of the paragraph to the end of the original search range, 
-    // since we will want to ignore results in this area also.
-    int searchRangeEndOffset = searchRangeStartOffset + TextIterator::rangeLength(m_range.get());
-        
+    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 < searchRangeEndOffset) {
+    while (startOffset < paragraph.checkingEnd()) {
         Vector<GrammarDetail> grammarDetails;
         int badGrammarPhraseLocation = -1;
         int badGrammarPhraseLength = 0;
-        m_client->checkGrammarOfString(paragraphString.characters() + startOffset, paragraphString.length() - startOffset, grammarDetails, &badGrammarPhraseLocation, &badGrammarPhraseLength);
+        m_client->checkGrammarOfString(paragraph.textCharacters() + startOffset, paragraph.textLength() - startOffset, grammarDetails, &badGrammarPhraseLocation, &badGrammarPhraseLength);
         
         if (!badGrammarPhraseLength) {
             ASSERT(badGrammarPhraseLocation == -1);
@@ -351,7 +433,7 @@ String TextCheckingHelper::findFirstBadGrammar(GrammarDetail& outGrammarDetail,
 
         
         // Found some bad grammar. Find the earliest detail range that starts in our search range (if any).
-        int badGrammarIndex = findFirstGrammarDetail(grammarDetails, badGrammarPhraseLocation, badGrammarPhraseLength, searchRangeStartOffset, searchRangeEndOffset, markAll);
+        int badGrammarIndex = findFirstGrammarDetail(grammarDetails, badGrammarPhraseLocation, badGrammarPhraseLength, paragraph.checkingStart(), paragraph.checkingEnd(), markAll);
         if (badGrammarIndex >= 0) {
             ASSERT(static_cast<unsigned>(badGrammarIndex) < grammarDetails.size());
             outGrammarDetail = grammarDetails[badGrammarIndex];
@@ -360,8 +442,8 @@ String TextCheckingHelper::findFirstBadGrammar(GrammarDetail& outGrammarDetail,
         // If we found a detail in range, then we have found the first bad phrase (unless we found one earlier but
         // kept going so we could mark all instances).
         if (badGrammarIndex >= 0 && firstBadGrammarPhrase.isEmpty()) {
-            outGrammarPhraseOffset = badGrammarPhraseLocation - searchRangeStartOffset;
-            firstBadGrammarPhrase = paragraphString.substring(badGrammarPhraseLocation, badGrammarPhraseLength);
+            outGrammarPhraseOffset = badGrammarPhraseLocation - paragraph.checkingStart();
+            firstBadGrammarPhrase = paragraph.textSubstring(badGrammarPhraseLocation, badGrammarPhraseLength);
             
             // Found one. We're done now, unless we're marking each instance.
             if (!markAll)
@@ -446,21 +528,18 @@ Vector<String> TextCheckingHelper::guessesForMisspelledOrUngrammaticalRange(bool
         return guesses;
 
     // Expand the range to encompass entire paragraphs, since text checking needs that much context.
-    int rangeStartOffset;
-    String paragraphString;
-    RefPtr<Range> paragraphRange = paragraphAlignedRange(rangeStartOffset, paragraphString);
-    int rangeLength = TextIterator::rangeLength(m_range.get());
-    if (!rangeLength || !paragraphString.length())
+    TextCheckingParagraph paragraph(m_range);
+    if (paragraph.isEmpty())
         return guesses;
 
     Vector<TextCheckingResult> results;
     uint64_t checkingTypes = checkGrammar ? (TextCheckingTypeSpelling | TextCheckingTypeGrammar) : TextCheckingTypeSpelling;
-    m_client->checkTextOfParagraph(paragraphString.characters(), paragraphString.length(), checkingTypes, results);
+    m_client->checkTextOfParagraph(paragraph.textCharacters(), paragraph.textLength(), checkingTypes, results);
     
     for (unsigned i = 0; i < results.size(); i++) {
         const TextCheckingResult* result = &results[i];
-        if (result->type == TextCheckingTypeSpelling && result->location == rangeStartOffset && result->length == rangeLength) {
-            String misspelledWord = paragraphString.substring(rangeStartOffset, rangeLength);
+        if (result->type == TextCheckingTypeSpelling && paragraph.checkingRangeMatches(result->location, result->length)) {
+            String misspelledWord = paragraph.checkingSubstring();
             ASSERT(misspelledWord.length());
             m_client->getGuessesForWord(misspelledWord, guesses);
             m_client->updateSpellingUIWithMisspelledWord(misspelledWord);
@@ -474,12 +553,12 @@ Vector<String> TextCheckingHelper::guessesForMisspelledOrUngrammaticalRange(bool
         
     for (unsigned i = 0; i < results.size(); i++) {
         const TextCheckingResult* result = &results[i];
-        if (result->type == TextCheckingTypeGrammar && result->location <= rangeStartOffset && result->location + result->length >= rangeStartOffset + rangeLength) {
+        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 (result->location + detail->location == rangeStartOffset && detail->length == rangeLength) {
-                    String badGrammarPhrase = paragraphString.substring(result->location, result->length);
+                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]);
diff --git a/WebCore/editing/TextCheckingHelper.h b/WebCore/editing/TextCheckingHelper.h
index 1dd3b3d..4dced05 100644
--- a/WebCore/editing/TextCheckingHelper.h
+++ b/WebCore/editing/TextCheckingHelper.h
@@ -26,6 +26,51 @@
 namespace WebCore {
 
 class Range;
+class Position;
+
+class TextCheckingParagraph {
+public:
+    explicit TextCheckingParagraph(PassRefPtr<Range> checkingRange);
+    ~TextCheckingParagraph();
+
+    int rangeLength() const;
+    PassRefPtr<Range> subrange(int characterOffset, int characterCount) const;
+    int offsetTo(const Position&, ExceptionCode&) const;
+    void expandRangeToNextEnd();
+
+    int textLength() const { return text().length(); }
+    String textSubstring(unsigned pos, unsigned len = UINT_MAX) const { return text().substring(pos, len); }
+    const UChar* textCharacters() const { return text().characters(); }
+    UChar textCharAt(int index) const { return text()[index]; }
+
+    bool isEmpty() const;
+    bool isTextEmpty() const { return text().isEmpty(); }
+    bool isRangeEmpty() const { return checkingStart() >= checkingEnd(); }
+
+    int checkingStart() const;
+    int checkingEnd() const;
+    int checkingLength() const;
+    String checkingSubstring() const { return textSubstring(checkingStart(), checkingLength()); }
+
+    bool checkingRangeMatches(int location, int length) const { return location == checkingStart() && length == checkingLength(); }
+    bool isCheckingRangeCoveredBy(int location, int length) const { return location <= checkingStart() && location + length >= checkingStart() + checkingLength(); }
+    bool checkingRangeCovers(int location, int length) const { return location < checkingEnd() && location + length > checkingStart(); }
+
+private:
+    void invalidateParagraphRangeValues();
+    PassRefPtr<Range> checkingRange() const { return m_checkingRange; }
+    PassRefPtr<Range> paragraphRange() const;
+    PassRefPtr<Range> offsetAsRange() const;
+    const String& text() const;
+
+    RefPtr<Range> m_checkingRange;
+    mutable RefPtr<Range> m_paragraphRange;
+    mutable RefPtr<Range> m_offsetAsRange;
+    mutable String m_text;
+    mutable int m_checkingStart;
+    mutable int m_checkingEnd;
+    mutable int m_checkingLength;
+};
 
 class TextCheckingHelper : public Noncopyable {
 public:
@@ -41,7 +86,6 @@ public:
 
     bool isUngrammatical(Vector<String>& guessesVector) const;
     Vector<String> guessesForMisspelledOrUngrammaticalRange(bool checkGrammar, bool& misspelled, bool& ungrammatical) const;
-    PassRefPtr<Range> paragraphAlignedRange(int& offsetIntoParagraphAlignedRange, String& paragraphString) const;
 private:
     EditorClient* m_client;
     RefPtr<Range> m_range;

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list