[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:19:42 UTC 2010
The following commit has been merged in the debian/experimental branch:
commit dc25904a0960a71c1083bd9a7ffaaf730e0e73c3
Author: morrita at google.com <morrita at google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date: Mon Nov 1 06:35:59 2010 +0000
2010-10-26 MORITA Hajime <morrita at google.com>
Reviewed by Kent Tamura.
Refactoring: Spellchecking related static functions could form a class
https://bugs.webkit.org/show_bug.cgi?id=48287
Extracted spellcheck related static functions to TextCheckingHelper class,
which has EditorClient and Range as its member.
No new tests. Just a refactoring.
* CMakeLists.txt:
* GNUmakefile.am:
* WebCore.gypi:
* WebCore.pro:
* WebCore.vcproj/WebCore.vcproj:
* WebCore.xcodeproj/project.pbxproj:
* editing/EditingAllInOne.cpp
* editing/Editor.cpp:
(WebCore::Editor::advanceToNextMisspelling):
(WebCore::Editor::isSelectionUngrammatical):
(WebCore::Editor::guessesForUngrammaticalSelection):
(WebCore::Editor::guessesForMisspelledOrUngrammaticalSelection):
(WebCore::Editor::markMisspellingsAfterTypingToPosition):
(WebCore::Editor::markMisspellingsOrBadGrammar):
(WebCore::Editor::markMisspellings):
(WebCore::Editor::markBadGrammar):
(WebCore::Editor::markAllMisspellingsAndBadGrammarInRanges):
(WebCore::Editor::changeBackToReplacedString):
* editing/Editor.h:
* editing/TextCheckingHelper.cpp: Added.
(WebCore::TextCheckingHelper::TextCheckingHelper):
(WebCore::TextCheckingHelper::~TextCheckingHelper):
(WebCore::TextCheckingHelper::paragraphAlignedRange):
(WebCore::TextCheckingHelper::findFirstMisspelling):
(WebCore::TextCheckingHelper::findFirstMisspellingOrBadGrammar):
(WebCore::TextCheckingHelper::findFirstGrammarDetail):
(WebCore::TextCheckingHelper::findFirstBadGrammar):
(WebCore::TextCheckingHelper::isUngrammatical):
(WebCore::TextCheckingHelper::guessesForMisspelledOrUngrammaticalRange):
(WebCore::TextCheckingHelper::markAllMisspellings):
(WebCore::TextCheckingHelper::markAllBadGrammar):
* editing/TextCheckingHelper.h: Added.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@71009 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/WebCore/CMakeLists.txt b/WebCore/CMakeLists.txt
index c1a8e11..4b05477 100644
--- a/WebCore/CMakeLists.txt
+++ b/WebCore/CMakeLists.txt
@@ -926,6 +926,7 @@ SET(WebCore_SOURCES
editing/SplitElementCommand.cpp
editing/SplitTextNodeCommand.cpp
editing/SplitTextNodeContainingElementCommand.cpp
+ editing/TextCheckingHelper.cpp
editing/TextIterator.cpp
editing/TypingCommand.cpp
editing/UnlinkCommand.cpp
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 90df85d..af76c10 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,48 @@
+2010-10-26 MORITA Hajime <morrita at google.com>
+
+ Reviewed by Kent Tamura.
+
+ Refactoring: Spellchecking related static functions could form a class
+ https://bugs.webkit.org/show_bug.cgi?id=48287
+
+ Extracted spellcheck related static functions to TextCheckingHelper class,
+ which has EditorClient and Range as its member.
+
+ No new tests. Just a refactoring.
+
+ * CMakeLists.txt:
+ * GNUmakefile.am:
+ * WebCore.gypi:
+ * WebCore.pro:
+ * WebCore.vcproj/WebCore.vcproj:
+ * WebCore.xcodeproj/project.pbxproj:
+ * editing/EditingAllInOne.cpp
+ * editing/Editor.cpp:
+ (WebCore::Editor::advanceToNextMisspelling):
+ (WebCore::Editor::isSelectionUngrammatical):
+ (WebCore::Editor::guessesForUngrammaticalSelection):
+ (WebCore::Editor::guessesForMisspelledOrUngrammaticalSelection):
+ (WebCore::Editor::markMisspellingsAfterTypingToPosition):
+ (WebCore::Editor::markMisspellingsOrBadGrammar):
+ (WebCore::Editor::markMisspellings):
+ (WebCore::Editor::markBadGrammar):
+ (WebCore::Editor::markAllMisspellingsAndBadGrammarInRanges):
+ (WebCore::Editor::changeBackToReplacedString):
+ * editing/Editor.h:
+ * editing/TextCheckingHelper.cpp: Added.
+ (WebCore::TextCheckingHelper::TextCheckingHelper):
+ (WebCore::TextCheckingHelper::~TextCheckingHelper):
+ (WebCore::TextCheckingHelper::paragraphAlignedRange):
+ (WebCore::TextCheckingHelper::findFirstMisspelling):
+ (WebCore::TextCheckingHelper::findFirstMisspellingOrBadGrammar):
+ (WebCore::TextCheckingHelper::findFirstGrammarDetail):
+ (WebCore::TextCheckingHelper::findFirstBadGrammar):
+ (WebCore::TextCheckingHelper::isUngrammatical):
+ (WebCore::TextCheckingHelper::guessesForMisspelledOrUngrammaticalRange):
+ (WebCore::TextCheckingHelper::markAllMisspellings):
+ (WebCore::TextCheckingHelper::markAllBadGrammar):
+ * editing/TextCheckingHelper.h: Added.
+
2010-10-31 Xan Lopez <xlopez at igalia.com>
Try to fix the GTK+ build.
diff --git a/WebCore/GNUmakefile.am b/WebCore/GNUmakefile.am
index f721608..7fe1dac 100644
--- a/WebCore/GNUmakefile.am
+++ b/WebCore/GNUmakefile.am
@@ -1355,6 +1355,8 @@ webcore_sources += \
WebCore/editing/SplitTextNodeContainingElementCommand.cpp \
WebCore/editing/SplitTextNodeContainingElementCommand.h \
WebCore/editing/TextAffinity.h \
+ WebCore/editing/TextCheckingHelper.cpp \
+ WebCore/editing/TextCheckingHelper.h \
WebCore/editing/TextGranularity.h \
WebCore/editing/TextIterator.cpp \
WebCore/editing/TextIterator.h \
diff --git a/WebCore/WebCore.gypi b/WebCore/WebCore.gypi
index a0c3d52..d9c5e39 100644
--- a/WebCore/WebCore.gypi
+++ b/WebCore/WebCore.gypi
@@ -1437,6 +1437,8 @@
'editing/SplitTextNodeContainingElementCommand.cpp',
'editing/SplitTextNodeContainingElementCommand.h',
'editing/TextAffinity.h',
+ 'editing/TextCheckingHelper.cpp',
+ 'editing/TextCheckingHelper.h',
'editing/TextGranularity.h',
'editing/TextIterator.cpp',
'editing/TextIterator.h',
diff --git a/WebCore/WebCore.pro b/WebCore/WebCore.pro
index 34697df..4f3ecc0 100644
--- a/WebCore/WebCore.pro
+++ b/WebCore/WebCore.pro
@@ -817,6 +817,7 @@ SOURCES += \
editing/SplitElementCommand.cpp \
editing/SplitTextNodeCommand.cpp \
editing/SplitTextNodeContainingElementCommand.cpp \
+ editing/TextCheckingHelper.cpp \
editing/TextIterator.cpp \
editing/TypingCommand.cpp \
editing/UnlinkCommand.cpp \
diff --git a/WebCore/WebCore.vcproj/WebCore.vcproj b/WebCore/WebCore.vcproj/WebCore.vcproj
index 743228b..65056f7 100644
--- a/WebCore/WebCore.vcproj/WebCore.vcproj
+++ b/WebCore/WebCore.vcproj/WebCore.vcproj
@@ -47940,6 +47940,62 @@
>
</File>
<File
+ RelativePath="..\editing\TextCheckingHelper.cpp"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug_Internal|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug_Cairo|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release_Cairo|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug_All|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\editing\TextCheckingHelper.h"
+ >
+ </File>
+ <File
RelativePath="..\editing\TextGranularity.h"
>
</File>
diff --git a/WebCore/WebCore.xcodeproj/project.pbxproj b/WebCore/WebCore.xcodeproj/project.pbxproj
index 15dfd62..c1bf23b 100644
--- a/WebCore/WebCore.xcodeproj/project.pbxproj
+++ b/WebCore/WebCore.xcodeproj/project.pbxproj
@@ -3069,6 +3069,8 @@
A7D3C5240B576B4B002CA450 /* PasteboardHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = A7D3C5230B576B4B002CA450 /* PasteboardHelper.h */; settings = {ATTRIBUTES = (Private, ); }; };
A7D6B3490F61104500B79FD1 /* WorkerScriptLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = A7D6B3470F61104500B79FD1 /* WorkerScriptLoader.h */; };
A7D6B34A0F61104500B79FD1 /* WorkerScriptLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7D6B3480F61104500B79FD1 /* WorkerScriptLoader.cpp */; };
+ A7DBF8DD1276919C006B6008 /* TextCheckingHelper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7DBF8DB1276919C006B6008 /* TextCheckingHelper.cpp */; };
+ A7DBF8DE1276919C006B6008 /* TextCheckingHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = A7DBF8DC1276919C006B6008 /* TextCheckingHelper.h */; };
A7F338A311C0EFCA00A320A7 /* ShadowElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7F338A111C0EFCA00A320A7 /* ShadowElement.cpp */; };
A7F338A411C0EFCA00A320A7 /* ShadowElement.h in Headers */ = {isa = PBXBuildFile; fileRef = A7F338A211C0EFCA00A320A7 /* ShadowElement.h */; };
A809F1470B73793A002E4D7F /* RenderSVGGradientStop.h in Headers */ = {isa = PBXBuildFile; fileRef = A809F1450B73793A002E4D7F /* RenderSVGGradientStop.h */; };
@@ -9156,6 +9158,8 @@
A7D3C5230B576B4B002CA450 /* PasteboardHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PasteboardHelper.h; sourceTree = "<group>"; };
A7D6B3470F61104500B79FD1 /* WorkerScriptLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WorkerScriptLoader.h; path = workers/WorkerScriptLoader.h; sourceTree = "<group>"; };
A7D6B3480F61104500B79FD1 /* WorkerScriptLoader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WorkerScriptLoader.cpp; path = workers/WorkerScriptLoader.cpp; sourceTree = "<group>"; };
+ A7DBF8DB1276919C006B6008 /* TextCheckingHelper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TextCheckingHelper.cpp; sourceTree = "<group>"; };
+ A7DBF8DC1276919C006B6008 /* TextCheckingHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextCheckingHelper.h; sourceTree = "<group>"; };
A7F338A111C0EFCA00A320A7 /* ShadowElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ShadowElement.cpp; sourceTree = "<group>"; };
A7F338A211C0EFCA00A320A7 /* ShadowElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShadowElement.h; sourceTree = "<group>"; };
A809F1450B73793A002E4D7F /* RenderSVGGradientStop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderSVGGradientStop.h; sourceTree = "<group>"; };
@@ -14546,6 +14550,8 @@
93309DC7099E64910056E581 /* SplitTextNodeContainingElementCommand.h */,
93309DC8099E64910056E581 /* TextAffinity.h */,
93309DC9099E64910056E581 /* TextGranularity.h */,
+ A7DBF8DB1276919C006B6008 /* TextCheckingHelper.cpp */,
+ A7DBF8DC1276919C006B6008 /* TextCheckingHelper.h */,
93309DCC099E64910056E581 /* TextIterator.cpp */,
93309DCD099E64910056E581 /* TextIterator.h */,
93309DCA099E64910056E581 /* TypingCommand.cpp */,
@@ -21012,6 +21018,7 @@
B2C3DA340D006C1D00EF6F26 /* TextBoundaries.h in Headers */,
B2C3DA360D006C1D00EF6F26 /* TextBreakIterator.h in Headers */,
B2C3DA380D006C1D00EF6F26 /* TextBreakIteratorInternalICU.h in Headers */,
+ A7DBF8DE1276919C006B6008 /* TextCheckingHelper.h in Headers */,
B2C3DA3A0D006C1D00EF6F26 /* TextCodec.h in Headers */,
B2C3DA3C0D006C1D00EF6F26 /* TextCodecICU.h in Headers */,
B2C3DA3E0D006C1D00EF6F26 /* TextCodecLatin1.h in Headers */,
@@ -23613,6 +23620,7 @@
B2AFFC970D00A5DF0030074D /* TextBoundaries.mm in Sources */,
B2C3DA370D006C1D00EF6F26 /* TextBreakIteratorICU.cpp in Sources */,
B2AFFC980D00A5DF0030074D /* TextBreakIteratorInternalICUMac.mm in Sources */,
+ A7DBF8DD1276919C006B6008 /* TextCheckingHelper.cpp in Sources */,
B2C3DA390D006C1D00EF6F26 /* TextCodec.cpp in Sources */,
B2C3DA3B0D006C1D00EF6F26 /* TextCodecICU.cpp in Sources */,
B2C3DA3D0D006C1D00EF6F26 /* TextCodecLatin1.cpp in Sources */,
diff --git a/WebCore/editing/EditingAllInOne.cpp b/WebCore/editing/EditingAllInOne.cpp
index ba484be..81483f8 100644
--- a/WebCore/editing/EditingAllInOne.cpp
+++ b/WebCore/editing/EditingAllInOne.cpp
@@ -65,6 +65,7 @@
#include <SplitElementCommand.cpp>
#include <SplitTextNodeCommand.cpp>
#include <SplitTextNodeContainingElementCommand.cpp>
+#include <TextCheckingHelper.cpp>
#include <TextIterator.cpp>
#include <TypingCommand.cpp>
#include <UnlinkCommand.cpp>
diff --git a/WebCore/editing/Editor.cpp b/WebCore/editing/Editor.cpp
index 169b765..8a4ef59 100644
--- a/WebCore/editing/Editor.cpp
+++ b/WebCore/editing/Editor.cpp
@@ -62,6 +62,7 @@
#include "NodeList.h"
#include "Page.h"
#include "Pasteboard.h"
+#include "TextCheckingHelper.h"
#include "RemoveFormatCommand.h"
#include "RenderBlock.h"
#include "RenderPart.h"
@@ -1659,328 +1660,6 @@ void Editor::learnSpelling()
client()->learnWord(text);
}
-static String findFirstMisspellingInRange(EditorClient* client, Range* searchRange, int& firstMisspellingOffset, bool markAll, RefPtr<Range>& firstMisspellingRange)
-{
- ASSERT_ARG(client, client);
- ASSERT_ARG(searchRange, searchRange);
-
- WordAwareIterator it(searchRange);
- 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;
- client->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(searchRange, currentChunkOffset + misspellingLocation, misspellingLength);
-
- // Remember first-encountered misspelling and its offset.
- if (!firstMisspelling) {
- firstMisspellingOffset = currentChunkOffset + misspellingLocation;
- firstMisspelling = String(chars + misspellingLocation, misspellingLength);
- firstMisspellingRange = misspellingRange;
- }
-
- // Store marker for misspelled word.
- ExceptionCode ec = 0;
- misspellingRange->startContainer(ec)->document()->markers()->addMarker(misspellingRange.get(), DocumentMarker::Spelling);
- ASSERT(!ec);
-
- // Bail out if we're marking only the first misspelling, and not all instances.
- if (!markAll)
- break;
- }
- }
-
- currentChunkOffset += len;
- it.advance();
- }
-
- return firstMisspelling;
-}
-
-#ifndef BUILDING_ON_TIGER
-
-static PassRefPtr<Range> paragraphAlignedRangeForRange(Range* arbitraryRange, int& offsetIntoParagraphAlignedRange, String& paragraphString)
-{
- ASSERT_ARG(arbitraryRange, arbitraryRange);
-
- ExceptionCode ec = 0;
-
- // Expand range to paragraph boundaries
- RefPtr<Range> paragraphRange = arbitraryRange->cloneRange(ec);
- setStart(paragraphRange.get(), startOfParagraph(arbitraryRange->startPosition()));
- setEnd(paragraphRange.get(), endOfParagraph(arbitraryRange->endPosition()));
-
- // Compute offset from start of expanded range to start of original range
- RefPtr<Range> offsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), paragraphRange->startPosition(), arbitraryRange->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;
-}
-
-static int findFirstGrammarDetailInRange(const Vector<GrammarDetail>& grammarDetails, int badGrammarPhraseLocation, int /*badGrammarPhraseLength*/, Range *searchRange, int startOffset, int endOffset, bool markAll)
-{
- // 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.
- int earliestDetailLocationSoFar = -1;
- int earliestDetailIndex = -1;
- for (unsigned i = 0; i < grammarDetails.size(); i++) {
- const GrammarDetail* detail = &grammarDetails[i];
- ASSERT(detail->length > 0 && detail->location >= 0);
-
- int detailStartOffsetInParagraph = badGrammarPhraseLocation + detail->location;
-
- // Skip this detail if it starts before the original search range
- if (detailStartOffsetInParagraph < startOffset)
- continue;
-
- // Skip this detail if it starts after the original search range
- if (detailStartOffsetInParagraph >= endOffset)
- continue;
-
- if (markAll) {
- RefPtr<Range> badGrammarRange = TextIterator::subrange(searchRange, badGrammarPhraseLocation - startOffset + detail->location, detail->length);
- ExceptionCode ec = 0;
- badGrammarRange->startContainer(ec)->document()->markers()->addMarker(badGrammarRange.get(), DocumentMarker::Grammar, detail->userDescription);
- ASSERT(!ec);
- }
-
- // Remember this detail only if it's earlier than our current candidate (the details aren't in a guaranteed order)
- if (earliestDetailIndex < 0 || earliestDetailLocationSoFar > detail->location) {
- earliestDetailIndex = i;
- earliestDetailLocationSoFar = detail->location;
- }
- }
-
- return earliestDetailIndex;
-}
-
-static String findFirstBadGrammarInRange(EditorClient* client, Range* searchRange, GrammarDetail& outGrammarDetail, int& outGrammarPhraseOffset, bool markAll)
-{
- ASSERT_ARG(client, client);
- ASSERT_ARG(searchRange, searchRange);
-
- // Initialize out parameters; these will be updated if we find something to return.
- outGrammarDetail.location = -1;
- outGrammarDetail.length = 0;
- outGrammarDetail.guesses.clear();
- outGrammarDetail.userDescription = "";
- outGrammarPhraseOffset = 0;
-
- String firstBadGrammarPhrase;
-
- // 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 = paragraphAlignedRangeForRange(searchRange, 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(searchRange);
-
- // 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) {
- Vector<GrammarDetail> grammarDetails;
- int badGrammarPhraseLocation = -1;
- int badGrammarPhraseLength = 0;
- client->checkGrammarOfString(paragraphString.characters() + startOffset, paragraphString.length() - startOffset, grammarDetails, &badGrammarPhraseLocation, &badGrammarPhraseLength);
-
- if (!badGrammarPhraseLength) {
- ASSERT(badGrammarPhraseLocation == -1);
- return String();
- }
-
- ASSERT(badGrammarPhraseLocation >= 0);
- badGrammarPhraseLocation += startOffset;
-
-
- // Found some bad grammar. Find the earliest detail range that starts in our search range (if any).
- int badGrammarIndex = findFirstGrammarDetailInRange(grammarDetails, badGrammarPhraseLocation, badGrammarPhraseLength, searchRange, searchRangeStartOffset, searchRangeEndOffset, markAll);
- if (badGrammarIndex >= 0) {
- ASSERT(static_cast<unsigned>(badGrammarIndex) < grammarDetails.size());
- outGrammarDetail = grammarDetails[badGrammarIndex];
- }
-
- // 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);
-
- // Found one. We're done now, unless we're marking each instance.
- if (!markAll)
- break;
- }
-
- // These results were all between the start of the paragraph and the start of the search range; look
- // beyond this phrase.
- startOffset = badGrammarPhraseLocation + badGrammarPhraseLength;
- }
-
- return firstBadGrammarPhrase;
-}
-
-#endif /* not BUILDING_ON_TIGER */
-
-#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
-
-static String findFirstMisspellingOrBadGrammarInRange(EditorClient* client, Range* searchRange, bool checkGrammar, bool& outIsSpelling, int& outFirstFoundOffset, GrammarDetail& outGrammarDetail)
-{
- ASSERT_ARG(client, client);
- ASSERT_ARG(searchRange, searchRange);
-
- String firstFoundItem;
- String misspelledWord;
- String badGrammarPhrase;
- ExceptionCode ec = 0;
-
- // Initialize out parameters; these will be updated if we find something to return.
- outIsSpelling = true;
- outFirstFoundOffset = 0;
- outGrammarDetail.location = -1;
- outGrammarDetail.length = 0;
- outGrammarDetail.guesses.clear();
- outGrammarDetail.userDescription = "";
-
- // 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 = searchRange->cloneRange(ec);
- setStart(paragraphRange.get(), startOfParagraph(searchRange->startPosition()));
- int totalRangeLength = TextIterator::rangeLength(paragraphRange.get());
- setEnd(paragraphRange.get(), endOfParagraph(searchRange->startPosition()));
-
- RefPtr<Range> offsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), paragraphRange->startPosition(), searchRange->startPosition());
- int searchRangeStartOffset = TextIterator::rangeLength(offsetAsRange.get());
- 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 currentStartOffset = firstIteration ? searchRangeStartOffset : 0;
- int currentEndOffset = currentLength;
- if (inSameParagraph(paragraphRange->startPosition(), searchRange->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(ec)->document(), paragraphRange->startPosition(), searchRange->endPosition());
- currentEndOffset = TextIterator::rangeLength(endOffsetAsRange.get());
- lastIteration = true;
- }
- if (currentStartOffset < currentEndOffset) {
- String paragraphString = plainText(paragraphRange.get());
- if (paragraphString.length() > 0) {
- bool foundGrammar = false;
- int spellingLocation = 0;
- int grammarPhraseLocation = 0;
- int grammarDetailLocation = 0;
- unsigned grammarDetailIndex = 0;
-
- Vector<TextCheckingResult> results;
- uint64_t checkingTypes = checkGrammar ? (TextCheckingTypeSpelling | TextCheckingTypeGrammar) : TextCheckingTypeSpelling;
- client->checkTextOfParagraph(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);
- ASSERT(misspelledWord.length());
- break;
- }
- if (checkGrammar && result->type == TextCheckingTypeGrammar && result->location < currentEndOffset && result->location + result->length > currentStartOffset) {
- ASSERT(result->length > 0 && 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)) {
- grammarDetailIndex = j;
- grammarDetailLocation = result->location + detail->location;
- foundGrammar = true;
- }
- }
- if (foundGrammar) {
- grammarPhraseLocation = result->location;
- outGrammarDetail = result->details[grammarDetailIndex];
- badGrammarPhrase = paragraphString.substring(result->location, result->length);
- ASSERT(badGrammarPhrase.length());
- }
- }
- }
-
- if (!misspelledWord.isEmpty() && (!checkGrammar || badGrammarPhrase.isEmpty() || spellingLocation <= grammarDetailLocation)) {
- int spellingOffset = spellingLocation - currentStartOffset;
- if (!firstIteration) {
- RefPtr<Range> paragraphOffsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), searchRange->startPosition(), paragraphRange->startPosition());
- spellingOffset += TextIterator::rangeLength(paragraphOffsetAsRange.get());
- }
- outIsSpelling = true;
- outFirstFoundOffset = spellingOffset;
- firstFoundItem = misspelledWord;
- break;
- }
- if (checkGrammar && !badGrammarPhrase.isEmpty()) {
- int grammarPhraseOffset = grammarPhraseLocation - currentStartOffset;
- if (!firstIteration) {
- RefPtr<Range> paragraphOffsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), searchRange->startPosition(), paragraphRange->startPosition());
- grammarPhraseOffset += TextIterator::rangeLength(paragraphOffsetAsRange.get());
- }
- outIsSpelling = false;
- outFirstFoundOffset = grammarPhraseOffset;
- firstFoundItem = badGrammarPhrase;
- break;
- }
- }
- }
- if (lastIteration || totalLengthProcessed + currentLength >= totalRangeLength)
- break;
- VisiblePosition newParagraphStart = startOfNextParagraph(paragraphRange->endPosition());
- setStart(paragraphRange.get(), newParagraphStart);
- setEnd(paragraphRange.get(), endOfParagraph(newParagraphStart));
- firstIteration = false;
- totalLengthProcessed += currentLength;
- }
- return firstFoundItem;
-}
-
-#endif
-
void Editor::advanceToNextMisspelling(bool startBeforeSelection)
{
ExceptionCode ec = 0;
@@ -1992,6 +1671,7 @@ void Editor::advanceToNextMisspelling(bool startBeforeSelection)
// repeated "check spelling" commands work.
VisibleSelection selection(frame()->selection()->selection());
RefPtr<Range> spellingSearchRange(rangeOfContents(frame()->document()));
+
bool startedWithSelection = false;
if (selection.start().node()) {
startedWithSelection = true;
@@ -2057,7 +1737,7 @@ void Editor::advanceToNextMisspelling(bool startBeforeSelection)
bool isSpelling = true;
int foundOffset = 0;
GrammarDetail grammarDetail;
- String foundItem = findFirstMisspellingOrBadGrammarInRange(client(), spellingSearchRange.get(), isGrammarCheckingEnabled(), isSpelling, foundOffset, grammarDetail);
+ String foundItem = TextCheckingHelper(client(), spellingSearchRange).findFirstMisspellingOrBadGrammar(isGrammarCheckingEnabled(), isSpelling, foundOffset, grammarDetail);
if (isSpelling) {
misspelledWord = foundItem;
misspellingOffset = foundOffset;
@@ -2067,7 +1747,7 @@ void Editor::advanceToNextMisspelling(bool startBeforeSelection)
}
#else
RefPtr<Range> firstMisspellingRange;
- String misspelledWord = findFirstMisspellingInRange(client(), spellingSearchRange.get(), misspellingOffset, false, firstMisspellingRange);
+ String misspelledWord = TextCheckingHelper(client(), spellingSearchRange).findFirstMisspelling(misspellingOffset, false, firstMisspellingRange);
String badGrammarPhrase;
#ifndef BUILDING_ON_TIGER
@@ -2084,7 +1764,7 @@ void Editor::advanceToNextMisspelling(bool startBeforeSelection)
}
if (isGrammarCheckingEnabled())
- badGrammarPhrase = findFirstBadGrammarInRange(client(), grammarSearchRange.get(), grammarDetail, grammarPhraseOffset, false);
+ badGrammarPhrase = TextCheckingHelper(client(), grammarSearchRange).findFirstBadGrammar(grammarDetail, grammarPhraseOffset, false);
#endif
#endif
@@ -2097,7 +1777,7 @@ void Editor::advanceToNextMisspelling(bool startBeforeSelection)
#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
grammarSearchRange = spellingSearchRange->cloneRange(ec);
- foundItem = findFirstMisspellingOrBadGrammarInRange(client(), spellingSearchRange.get(), isGrammarCheckingEnabled(), isSpelling, foundOffset, grammarDetail);
+ foundItem = TextCheckingHelper(client(), spellingSearchRange).findFirstMisspellingOrBadGrammar(isGrammarCheckingEnabled(), isSpelling, foundOffset, grammarDetail);
if (isSpelling) {
misspelledWord = foundItem;
misspellingOffset = foundOffset;
@@ -2106,7 +1786,7 @@ void Editor::advanceToNextMisspelling(bool startBeforeSelection)
grammarPhraseOffset = foundOffset;
}
#else
- misspelledWord = findFirstMisspellingInRange(client(), spellingSearchRange.get(), misspellingOffset, false, firstMisspellingRange);
+ misspelledWord = TextCheckingHelper(client(), spellingSearchRange).findFirstMisspelling(misspellingOffset, false, firstMisspellingRange);
#ifndef BUILDING_ON_TIGER
grammarSearchRange = spellingSearchRange->cloneRange(ec);
@@ -2116,8 +1796,9 @@ void Editor::advanceToNextMisspelling(bool startBeforeSelection)
chars.advance(misspellingOffset);
grammarSearchRange->setEnd(chars.range()->startContainer(ec), chars.range()->startOffset(ec), ec);
}
+
if (isGrammarCheckingEnabled())
- badGrammarPhrase = findFirstBadGrammarInRange(client(), grammarSearchRange.get(), grammarDetail, grammarPhraseOffset, false);
+ badGrammarPhrase = TextCheckingHelper(client(), grammarSearchRange).findFirstBadGrammar(grammarDetail, grammarPhraseOffset, false);
#endif
#endif
}
@@ -2181,60 +1862,13 @@ bool Editor::isSelectionMisspelled()
return true;
}
-#ifndef BUILDING_ON_TIGER
-static bool isRangeUngrammatical(EditorClient* client, Range *range, Vector<String>& guessesVector)
-{
- if (!client)
- return false;
-
- ExceptionCode ec;
- if (!range || range->collapsed(ec))
- 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 = findFirstBadGrammarInRange(client, range, grammarDetail, grammarPhraseOffset, false);
-
- // No bad grammar in these parts at all.
- if (badGrammarPhrase.isEmpty())
- return false;
-
- // Bad grammar, but phrase (e.g. sentence) starts beyond start of range.
- if (grammarPhraseOffset > 0)
- return false;
-
- ASSERT(grammarDetail.location >= 0 && 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;
-
- // Bad grammar at start of range, but end of bad grammar is before or after end of range
- if (grammarDetail.length != TextIterator::rangeLength(range))
- return false;
-
- // Update the spelling panel to be displaying this error (whether or not the spelling panel is on screen).
- // This is necessary to make a subsequent call to [NSSpellChecker ignoreWord:inSpellDocumentWithTag:] work
- // correctly; that call behaves differently based on whether the spelling panel is displaying a misspelling
- // or a grammar error.
- client->updateSpellingUIWithGrammarString(badGrammarPhrase, grammarDetail);
-
- return true;
-}
-#endif
-
bool Editor::isSelectionUngrammatical()
{
#ifdef BUILDING_ON_TIGER
return false;
#else
Vector<String> ignoredGuesses;
- return isRangeUngrammatical(client(), frame()->selection()->toNormalizedRange().get(), ignoredGuesses);
+ return TextCheckingHelper(client(), frame()->selection()->toNormalizedRange()).isUngrammatical(ignoredGuesses);
#endif
}
@@ -2244,8 +1878,8 @@ Vector<String> Editor::guessesForUngrammaticalSelection()
return Vector<String>();
#else
Vector<String> guesses;
- // Ignore the result of isRangeUngrammatical; we just want the guesses, whether or not there are any
- isRangeUngrammatical(client(), frame()->selection()->toNormalizedRange().get(), guesses);
+ // Ignore the result of isUngrammatical; we just want the guesses, whether or not there are any
+ TextCheckingHelper(client(), frame()->selection()->toNormalizedRange()).isUngrammatical(guesses);
return guesses;
#endif
}
@@ -2261,72 +1895,10 @@ Vector<String> Editor::guessesForMisspelledSelection()
return guesses;
}
-#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
-
-static Vector<String> guessesForMisspelledOrUngrammaticalRange(EditorClient* client, Range *range, bool checkGrammar, bool& misspelled, bool& ungrammatical)
-{
- Vector<String> guesses;
- ExceptionCode ec;
- misspelled = false;
- ungrammatical = false;
-
- if (!client || !range || range->collapsed(ec))
- return guesses;
-
- // Expand the range to encompass entire paragraphs, since text checking needs that much context.
- int rangeStartOffset;
- String paragraphString;
- RefPtr<Range> paragraphRange = paragraphAlignedRangeForRange(range, rangeStartOffset, paragraphString);
- int rangeLength = TextIterator::rangeLength(range);
- if (!rangeLength || !paragraphString.length())
- return guesses;
-
- Vector<TextCheckingResult> results;
- uint64_t checkingTypes = checkGrammar ? (TextCheckingTypeSpelling | TextCheckingTypeGrammar) : TextCheckingTypeSpelling;
- client->checkTextOfParagraph(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 == rangeStartOffset && result->length == rangeLength) {
- String misspelledWord = paragraphString.substring(rangeStartOffset, rangeLength);
- ASSERT(misspelledWord.length());
- client->getGuessesForWord(misspelledWord, guesses);
- client->updateSpellingUIWithMisspelledWord(misspelledWord);
- misspelled = true;
- return guesses;
- }
- }
-
- if (!checkGrammar)
- return guesses;
-
- 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) {
- 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);
- ASSERT(badGrammarPhrase.length());
- for (unsigned k = 0; k < detail->guesses.size(); k++)
- guesses.append(detail->guesses[k]);
- client->updateSpellingUIWithGrammarString(badGrammarPhrase, *detail);
- ungrammatical = true;
- return guesses;
- }
- }
- }
- }
- return guesses;
-}
-
-#endif
-
Vector<String> Editor::guessesForMisspelledOrUngrammaticalSelection(bool& misspelled, bool& ungrammatical)
{
#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
- return guessesForMisspelledOrUngrammaticalRange(client(), frame()->selection()->toNormalizedRange().get(), isGrammarCheckingEnabled(), misspelled, ungrammatical);
+ return TextCheckingHelper(client(), frame()->selection()->toNormalizedRange()).guessesForMisspelledOrUngrammaticalRange(isGrammarCheckingEnabled(), misspelled, ungrammatical);
#else
misspelled = isSelectionMisspelled();
if (misspelled) {
@@ -2503,34 +2075,15 @@ void Editor::markMisspellingsAfterTypingToPosition(const VisiblePosition &p)
markBadGrammar(VisibleSelection(startOfSentence(p), endOfSentence(p)));
#endif
}
-
-static void markAllMisspellingsInRange(EditorClient* client, Range* searchRange, RefPtr<Range>& firstMisspellingRange)
-{
- // Use the "markAll" feature of findFirstMisspellingInRange. Ignore the return value and the "out parameter";
- // all we need to do is mark every instance.
- int ignoredOffset;
- findFirstMisspellingInRange(client, searchRange, ignoredOffset, true, firstMisspellingRange);
-}
-
-#ifndef BUILDING_ON_TIGER
-static void markAllBadGrammarInRange(EditorClient* client, Range* searchRange)
-{
- // Use the "markAll" feature of findFirstBadGrammarInRange. Ignore the return value and "out parameters"; all we need to
- // do is mark every instance.
- GrammarDetail ignoredGrammarDetail;
- int ignoredOffset;
- findFirstBadGrammarInRange(client, searchRange, ignoredGrammarDetail, ignoredOffset, true);
-}
-#endif
-static void markMisspellingsOrBadGrammar(Editor* editor, const VisibleSelection& selection, bool checkSpelling, RefPtr<Range>& firstMisspellingRange)
+void Editor::markMisspellingsOrBadGrammar(const VisibleSelection& selection, bool checkSpelling, RefPtr<Range>& firstMisspellingRange)
{
// This function is called with a selection already expanded to word boundaries.
// Might be nice to assert that here.
// This function is used only for as-you-type checking, so if that's off we do nothing. Note that
// grammar checking can only be on if spell checking is also on.
- if (!editor->isContinuousSpellCheckingEnabled())
+ if (!isContinuousSpellCheckingEnabled())
return;
RefPtr<Range> searchRange(selection.toNormalizedRange());
@@ -2542,21 +2095,22 @@ static void markMisspellingsOrBadGrammar(Editor* editor, const VisibleSelection&
if (!editableNode || !editableNode->isContentEditable())
return;
- if (!editor->isSpellCheckingEnabledInFocusedNode())
+ if (!isSpellCheckingEnabledInFocusedNode())
return;
// Get the spell checker if it is available
- if (!editor->client())
+ if (!client())
return;
+ TextCheckingHelper checker(client(), searchRange);
if (checkSpelling)
- markAllMisspellingsInRange(editor->client(), searchRange.get(), firstMisspellingRange);
+ checker.markAllMisspellings(firstMisspellingRange);
else {
#ifdef BUILDING_ON_TIGER
ASSERT_NOT_REACHED();
#else
- if (editor->isGrammarCheckingEnabled())
- markAllBadGrammarInRange(editor->client(), searchRange.get());
+ if (isGrammarCheckingEnabled())
+ checker.markAllBadGrammar();
#endif
}
}
@@ -2576,14 +2130,14 @@ bool Editor::isSpellCheckingEnabledInFocusedNode() const
void Editor::markMisspellings(const VisibleSelection& selection, RefPtr<Range>& firstMisspellingRange)
{
- markMisspellingsOrBadGrammar(this, selection, true, firstMisspellingRange);
+ markMisspellingsOrBadGrammar(selection, true, firstMisspellingRange);
}
void Editor::markBadGrammar(const VisibleSelection& selection)
{
#ifndef BUILDING_ON_TIGER
RefPtr<Range> firstMisspellingRange;
- markMisspellingsOrBadGrammar(this, selection, false, firstMisspellingRange);
+ markMisspellingsOrBadGrammar(selection, false, firstMisspellingRange);
#else
UNUSED_PARAM(selection);
#endif
@@ -2636,12 +2190,12 @@ void Editor::markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions textCh
if (shouldMarkGrammar) {
// The spelling range should be contained in the paragraph-aligned extension of the grammar range.
- paragraphRange = paragraphAlignedRangeForRange(grammarRange, grammarRangeStartOffset, paragraphString);
+ 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 = paragraphAlignedRangeForRange(spellingRange, spellingRangeStartOffset, paragraphString);
+ paragraphRange = TextCheckingHelper(client(), spellingRange).paragraphAlignedRange(spellingRangeStartOffset, paragraphString);
}
spellingRangeEndOffset = spellingRangeStartOffset + TextIterator::rangeLength(spellingRange);
paragraphLength = paragraphString.length();
@@ -2831,10 +2385,10 @@ void Editor::changeBackToReplacedString(const String& replacedString)
RefPtr<Range> selection = selectedRange();
if (!shouldInsertText(replacedString, selection.get(), EditorInsertActionPasted))
return;
-
+
String paragraphString;
int selectionOffset;
- RefPtr<Range> paragraphRange = paragraphAlignedRangeForRange(selection.get(), selectionOffset, paragraphString);
+ RefPtr<Range> paragraphRange = TextCheckingHelper(client(), selection).paragraphAlignedRange(selectionOffset, paragraphString);
replaceSelectionWithText(replacedString, false, false);
RefPtr<Range> changedRange = TextIterator::subrange(paragraphRange.get(), selectionOffset, replacedString.length());
changedRange->startContainer()->document()->markers()->addMarker(changedRange.get(), DocumentMarker::Replacement, String());
diff --git a/WebCore/editing/Editor.h b/WebCore/editing/Editor.h
index e942560..110e3f9 100644
--- a/WebCore/editing/Editor.h
+++ b/WebCore/editing/Editor.h
@@ -404,6 +404,7 @@ private:
void replaceSelectionWithText(const String&, bool selectReplacement, bool smartReplace);
void writeSelectionToPasteboard(Pasteboard*);
void revealSelectionAfterEditingOperation();
+ void markMisspellingsOrBadGrammar(const VisibleSelection&, bool checkSpelling, RefPtr<Range>& firstMisspellingRange);
void selectComposition();
void confirmComposition(const String&, bool preserveSelection);
diff --git a/WebCore/editing/TextCheckingHelper.cpp b/WebCore/editing/TextCheckingHelper.cpp
new file mode 100644
index 0000000..49674ff
--- /dev/null
+++ b/WebCore/editing/TextCheckingHelper.cpp
@@ -0,0 +1,525 @@
+/*
+ * Copyright (C) 2006, 2007 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
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * 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
+ * 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
+ * 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
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "TextCheckingHelper.h"
+
+#include "Range.h"
+#include "TextIterator.h"
+#include "VisiblePosition.h"
+#include "visible_units.h"
+
+namespace WebCore {
+
+TextCheckingHelper::TextCheckingHelper(EditorClient* client, PassRefPtr<Range> range)
+ : m_client(client)
+ , m_range(range)
+{
+ ASSERT_ARG(m_client, m_client);
+ ASSERT_ARG(m_range, m_range);
+}
+
+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());
+ 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->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;
+ }
+
+ // Store marker for misspelled word.
+ ExceptionCode ec = 0;
+ misspellingRange->startContainer(ec)->document()->markers()->addMarker(misspellingRange.get(), DocumentMarker::Spelling);
+ ASSERT(!ec);
+
+ // Bail out if we're marking only the first misspelling, and not all instances.
+ if (!markAll)
+ break;
+ }
+ }
+
+ currentChunkOffset += len;
+ it.advance();
+ }
+
+ return firstMisspelling;
+}
+
+String TextCheckingHelper::findFirstMisspellingOrBadGrammar(bool checkGrammar, bool& outIsSpelling, int& outFirstFoundOffset, GrammarDetail& outGrammarDetail)
+{
+#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+ String firstFoundItem;
+ String misspelledWord;
+ String badGrammarPhrase;
+ ExceptionCode ec = 0;
+
+ // Initialize out parameters; these will be updated if we find something to return.
+ outIsSpelling = true;
+ outFirstFoundOffset = 0;
+ outGrammarDetail.location = -1;
+ outGrammarDetail.length = 0;
+ outGrammarDetail.guesses.clear();
+ outGrammarDetail.userDescription = "";
+
+ // 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(ec);
+ setStart(paragraphRange.get(), startOfParagraph(m_range->startPosition()));
+ int totalRangeLength = TextIterator::rangeLength(paragraphRange.get());
+ setEnd(paragraphRange.get(), endOfParagraph(m_range->startPosition()));
+
+ RefPtr<Range> offsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), paragraphRange->startPosition(), m_range->startPosition());
+ int rangeStartOffset = TextIterator::rangeLength(offsetAsRange.get());
+ 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 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(ec)->document(), paragraphRange->startPosition(), m_range->endPosition());
+ currentEndOffset = TextIterator::rangeLength(endOffsetAsRange.get());
+ lastIteration = true;
+ }
+ if (currentStartOffset < currentEndOffset) {
+ String paragraphString = plainText(paragraphRange.get());
+ if (paragraphString.length() > 0) {
+ bool foundGrammar = false;
+ int spellingLocation = 0;
+ int grammarPhraseLocation = 0;
+ int grammarDetailLocation = 0;
+ unsigned grammarDetailIndex = 0;
+
+ Vector<TextCheckingResult> results;
+ uint64_t checkingTypes = checkGrammar ? (TextCheckingTypeSpelling | TextCheckingTypeGrammar) : TextCheckingTypeSpelling;
+ m_client->checkTextOfParagraph(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);
+ ASSERT(misspelledWord.length());
+ break;
+ }
+ if (checkGrammar && result->type == TextCheckingTypeGrammar && result->location < currentEndOffset && result->location + result->length > currentStartOffset) {
+ ASSERT(result->length > 0 && 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)) {
+ grammarDetailIndex = j;
+ grammarDetailLocation = result->location + detail->location;
+ foundGrammar = true;
+ }
+ }
+ if (foundGrammar) {
+ grammarPhraseLocation = result->location;
+ outGrammarDetail = result->details[grammarDetailIndex];
+ badGrammarPhrase = paragraphString.substring(result->location, result->length);
+ ASSERT(badGrammarPhrase.length());
+ }
+ }
+ }
+
+ if (!misspelledWord.isEmpty() && (!checkGrammar || badGrammarPhrase.isEmpty() || spellingLocation <= grammarDetailLocation)) {
+ int spellingOffset = spellingLocation - currentStartOffset;
+ if (!firstIteration) {
+ RefPtr<Range> paragraphOffsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), m_range->startPosition(), paragraphRange->startPosition());
+ spellingOffset += TextIterator::rangeLength(paragraphOffsetAsRange.get());
+ }
+ outIsSpelling = true;
+ outFirstFoundOffset = spellingOffset;
+ firstFoundItem = misspelledWord;
+ break;
+ }
+ if (checkGrammar && !badGrammarPhrase.isEmpty()) {
+ int grammarPhraseOffset = grammarPhraseLocation - currentStartOffset;
+ if (!firstIteration) {
+ RefPtr<Range> paragraphOffsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), m_range->startPosition(), paragraphRange->startPosition());
+ grammarPhraseOffset += TextIterator::rangeLength(paragraphOffsetAsRange.get());
+ }
+ outIsSpelling = false;
+ outFirstFoundOffset = grammarPhraseOffset;
+ firstFoundItem = badGrammarPhrase;
+ break;
+ }
+ }
+ }
+ if (lastIteration || totalLengthProcessed + currentLength >= totalRangeLength)
+ break;
+ VisiblePosition newParagraphStart = startOfNextParagraph(paragraphRange->endPosition());
+ setStart(paragraphRange.get(), newParagraphStart);
+ setEnd(paragraphRange.get(), endOfParagraph(newParagraphStart));
+ firstIteration = false;
+ totalLengthProcessed += currentLength;
+ }
+ return firstFoundItem;
+#else
+ ASSERT_NOT_REACHED();
+ UNUSED_PARAM(checkGrammar);
+ UNUSED_PARAM(outIsSpelling);
+ UNUSED_PARAM(outFirstFoundOffset);
+ UNUSED_PARAM(outGrammarDetail);
+ return "";
+#endif
+}
+
+int TextCheckingHelper::findFirstGrammarDetail(const Vector<GrammarDetail>& grammarDetails, int badGrammarPhraseLocation, int /*badGrammarPhraseLength*/, int startOffset, int endOffset, bool markAll)
+{
+#ifndef BUILDING_ON_TIGER
+ // 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.
+ int earliestDetailLocationSoFar = -1;
+ int earliestDetailIndex = -1;
+ for (unsigned i = 0; i < grammarDetails.size(); i++) {
+ const GrammarDetail* detail = &grammarDetails[i];
+ ASSERT(detail->length > 0 && detail->location >= 0);
+
+ int detailStartOffsetInParagraph = badGrammarPhraseLocation + detail->location;
+
+ // Skip this detail if it starts before the original search range
+ if (detailStartOffsetInParagraph < startOffset)
+ continue;
+
+ // Skip this detail if it starts after the original search range
+ if (detailStartOffsetInParagraph >= endOffset)
+ continue;
+
+ if (markAll) {
+ RefPtr<Range> badGrammarRange = TextIterator::subrange(m_range.get(), badGrammarPhraseLocation - startOffset + detail->location, detail->length);
+ ExceptionCode ec = 0;
+ badGrammarRange->startContainer(ec)->document()->markers()->addMarker(badGrammarRange.get(), DocumentMarker::Grammar, detail->userDescription);
+ ASSERT(!ec);
+ }
+
+ // Remember this detail only if it's earlier than our current candidate (the details aren't in a guaranteed order)
+ if (earliestDetailIndex < 0 || earliestDetailLocationSoFar > detail->location) {
+ earliestDetailIndex = i;
+ earliestDetailLocationSoFar = detail->location;
+ }
+ }
+
+ return earliestDetailIndex;
+#else
+ ASSERT_NOT_REACHED();
+ UNUSED_PARAM(grammarDetails);
+ UNUSED_PARAM(badGrammarPhraseLocation);
+ UNUSED_PARAM(startOffset);
+ UNUSED_PARAM(endOffset);
+ UNUSED_PARAM(markAll);
+ return 0;
+#endif
+}
+
+String TextCheckingHelper::findFirstBadGrammar(GrammarDetail& outGrammarDetail, int& outGrammarPhraseOffset, bool markAll)
+{
+#ifndef BUILDING_ON_TIGER
+ // Initialize out parameters; these will be updated if we find something to return.
+ outGrammarDetail.location = -1;
+ outGrammarDetail.length = 0;
+ outGrammarDetail.guesses.clear();
+ outGrammarDetail.userDescription = "";
+ outGrammarPhraseOffset = 0;
+
+ String firstBadGrammarPhrase;
+
+ // 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());
+
+ // 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) {
+ Vector<GrammarDetail> grammarDetails;
+ int badGrammarPhraseLocation = -1;
+ int badGrammarPhraseLength = 0;
+ m_client->checkGrammarOfString(paragraphString.characters() + startOffset, paragraphString.length() - startOffset, grammarDetails, &badGrammarPhraseLocation, &badGrammarPhraseLength);
+
+ if (!badGrammarPhraseLength) {
+ ASSERT(badGrammarPhraseLocation == -1);
+ return String();
+ }
+
+ 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, searchRangeStartOffset, searchRangeEndOffset, markAll);
+ if (badGrammarIndex >= 0) {
+ ASSERT(static_cast<unsigned>(badGrammarIndex) < grammarDetails.size());
+ outGrammarDetail = grammarDetails[badGrammarIndex];
+ }
+
+ // 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);
+
+ // Found one. We're done now, unless we're marking each instance.
+ if (!markAll)
+ break;
+ }
+
+ // These results were all between the start of the paragraph and the start of the search range; look
+ // beyond this phrase.
+ startOffset = badGrammarPhraseLocation + badGrammarPhraseLength;
+ }
+
+ return firstBadGrammarPhrase;
+#else
+ ASSERT_NOT_REACHED();
+ UNUSED_PARAM(outGrammarDetail);
+ UNUSED_PARAM(outGrammarPhraseOffset);
+ UNUSED_PARAM(markAll);
+#endif
+}
+
+
+bool TextCheckingHelper::isUngrammatical(Vector<String>& guessesVector) const
+{
+#ifndef BUILDING_ON_TIGER
+ if (!m_client)
+ return false;
+
+ ExceptionCode ec;
+ if (!m_range || m_range->collapsed(ec))
+ 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);
+
+ // No bad grammar in these parts at all.
+ if (badGrammarPhrase.isEmpty())
+ return false;
+
+ // Bad grammar, but phrase (e.g. sentence) starts beyond start of range.
+ if (grammarPhraseOffset > 0)
+ return false;
+
+ ASSERT(grammarDetail.location >= 0 && 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;
+
+ // Bad grammar at start of range, but end of bad grammar is before or after end of range
+ if (grammarDetail.length != TextIterator::rangeLength(m_range.get()))
+ return false;
+
+ // Update the spelling panel to be displaying this error (whether or not the spelling panel is on screen).
+ // This is necessary to make a subsequent call to [NSSpellChecker ignoreWord:inSpellDocumentWithTag:] work
+ // correctly; that call behaves differently based on whether the spelling panel is displaying a misspelling
+ // or a grammar error.
+ m_client->updateSpellingUIWithGrammarString(badGrammarPhrase, grammarDetail);
+
+ return true;
+#else
+ ASSERT_NOT_REACHED();
+ UNUSED_PARAM(guessesVector);
+ return true;
+#endif
+}
+
+Vector<String> TextCheckingHelper::guessesForMisspelledOrUngrammaticalRange(bool checkGrammar, bool& misspelled, bool& ungrammatical) const
+{
+#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+ Vector<String> guesses;
+ ExceptionCode ec;
+ misspelled = false;
+ ungrammatical = false;
+
+ if (!m_client || !m_range || m_range->collapsed(ec))
+ 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())
+ return guesses;
+
+ Vector<TextCheckingResult> results;
+ uint64_t checkingTypes = checkGrammar ? (TextCheckingTypeSpelling | TextCheckingTypeGrammar) : TextCheckingTypeSpelling;
+ m_client->checkTextOfParagraph(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 == rangeStartOffset && result->length == rangeLength) {
+ String misspelledWord = paragraphString.substring(rangeStartOffset, rangeLength);
+ ASSERT(misspelledWord.length());
+ m_client->getGuessesForWord(misspelledWord, guesses);
+ m_client->updateSpellingUIWithMisspelledWord(misspelledWord);
+ misspelled = true;
+ return guesses;
+ }
+ }
+
+ if (!checkGrammar)
+ return guesses;
+
+ 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) {
+ 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);
+ ASSERT(badGrammarPhrase.length());
+ for (unsigned k = 0; k < detail->guesses.size(); k++)
+ guesses.append(detail->guesses[k]);
+ m_client->updateSpellingUIWithGrammarString(badGrammarPhrase, *detail);
+ ungrammatical = true;
+ return guesses;
+ }
+ }
+ }
+ }
+ return guesses;
+#else
+ ASSERT_NOT_REACHED();
+ UNUSED_PARAM(checkGrammar);
+ UNUSED_PARAM(misspelled);
+ UNUSED_PARAM(ungrammatical);
+ return Vector<String>();
+#endif
+}
+
+
+void TextCheckingHelper::markAllMisspellings(RefPtr<Range>& firstMisspellingRange)
+{
+ // Use the "markAll" feature of findFirstMisspelling. Ignore the return value and the "out parameter";
+ // all we need to do is mark every instance.
+ int ignoredOffset;
+ findFirstMisspelling(ignoredOffset, true, firstMisspellingRange);
+}
+
+void TextCheckingHelper::markAllBadGrammar()
+{
+#ifndef BUILDING_ON_TIGER
+ // Use the "markAll" feature of findFirstBadGrammar. Ignore the return value and "out parameters"; all we need to
+ // do is mark every instance.
+ GrammarDetail ignoredGrammarDetail;
+ int ignoredOffset;
+ findFirstBadGrammar(ignoredGrammarDetail, ignoredOffset, true);
+#else
+ ASSERT_NOT_REACHED();
+#endif
+}
+
+}
diff --git a/WebCore/editing/TextCheckingHelper.h b/WebCore/editing/TextCheckingHelper.h
new file mode 100644
index 0000000..1dd3b3d
--- /dev/null
+++ b/WebCore/editing/TextCheckingHelper.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef TextCheckingHelper_h
+#define TextCheckingHelper_h
+
+#include "EditorClient.h"
+
+namespace WebCore {
+
+class Range;
+
+class TextCheckingHelper : public Noncopyable {
+public:
+ TextCheckingHelper(EditorClient*, PassRefPtr<Range>);
+ ~TextCheckingHelper();
+
+ String findFirstMisspelling(int& firstMisspellingOffset, bool markAll, RefPtr<Range>& firstMisspellingRange);
+ String findFirstMisspellingOrBadGrammar(bool checkGrammar, bool& outIsSpelling, int& outFirstFoundOffset, GrammarDetail& outGrammarDetail);
+ String findFirstBadGrammar(GrammarDetail& outGrammarDetail, int& outGrammarPhraseOffset, bool markAll);
+ int findFirstGrammarDetail(const Vector<GrammarDetail>& grammarDetails, int badGrammarPhraseLocation, int badGrammarPhraseLength, int startOffset, int endOffset, bool markAll);
+ void markAllMisspellings(RefPtr<Range>& firstMisspellingRange);
+ void markAllBadGrammar();
+
+ 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;
+};
+
+} // namespace WebCore
+
+#endif // TextCheckingHelper_h
--
WebKit Debian packaging
More information about the Pkg-webkit-commits
mailing list