Changeset 71009 in webkit
- Timestamp:
- Oct 31, 2010 11:35:59 PM (13 years ago)
- Location:
- trunk/WebCore
- Files:
-
- 2 added
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/WebCore/CMakeLists.txt
r70985 r71009 927 927 editing/SplitTextNodeCommand.cpp 928 928 editing/SplitTextNodeContainingElementCommand.cpp 929 editing/TextCheckingHelper.cpp 929 930 editing/TextIterator.cpp 930 931 editing/TypingCommand.cpp -
trunk/WebCore/ChangeLog
r71008 r71009 1 2010-10-26 MORITA Hajime <morrita@google.com> 2 3 Reviewed by Kent Tamura. 4 5 Refactoring: Spellchecking related static functions could form a class 6 https://bugs.webkit.org/show_bug.cgi?id=48287 7 8 Extracted spellcheck related static functions to TextCheckingHelper class, 9 which has EditorClient and Range as its member. 10 11 No new tests. Just a refactoring. 12 13 * CMakeLists.txt: 14 * GNUmakefile.am: 15 * WebCore.gypi: 16 * WebCore.pro: 17 * WebCore.vcproj/WebCore.vcproj: 18 * WebCore.xcodeproj/project.pbxproj: 19 * editing/EditingAllInOne.cpp 20 * editing/Editor.cpp: 21 (WebCore::Editor::advanceToNextMisspelling): 22 (WebCore::Editor::isSelectionUngrammatical): 23 (WebCore::Editor::guessesForUngrammaticalSelection): 24 (WebCore::Editor::guessesForMisspelledOrUngrammaticalSelection): 25 (WebCore::Editor::markMisspellingsAfterTypingToPosition): 26 (WebCore::Editor::markMisspellingsOrBadGrammar): 27 (WebCore::Editor::markMisspellings): 28 (WebCore::Editor::markBadGrammar): 29 (WebCore::Editor::markAllMisspellingsAndBadGrammarInRanges): 30 (WebCore::Editor::changeBackToReplacedString): 31 * editing/Editor.h: 32 * editing/TextCheckingHelper.cpp: Added. 33 (WebCore::TextCheckingHelper::TextCheckingHelper): 34 (WebCore::TextCheckingHelper::~TextCheckingHelper): 35 (WebCore::TextCheckingHelper::paragraphAlignedRange): 36 (WebCore::TextCheckingHelper::findFirstMisspelling): 37 (WebCore::TextCheckingHelper::findFirstMisspellingOrBadGrammar): 38 (WebCore::TextCheckingHelper::findFirstGrammarDetail): 39 (WebCore::TextCheckingHelper::findFirstBadGrammar): 40 (WebCore::TextCheckingHelper::isUngrammatical): 41 (WebCore::TextCheckingHelper::guessesForMisspelledOrUngrammaticalRange): 42 (WebCore::TextCheckingHelper::markAllMisspellings): 43 (WebCore::TextCheckingHelper::markAllBadGrammar): 44 * editing/TextCheckingHelper.h: Added. 45 1 46 2010-10-31 Xan Lopez <xlopez@igalia.com> 2 47 -
trunk/WebCore/GNUmakefile.am
r70985 r71009 1356 1356 WebCore/editing/SplitTextNodeContainingElementCommand.h \ 1357 1357 WebCore/editing/TextAffinity.h \ 1358 WebCore/editing/TextCheckingHelper.cpp \ 1359 WebCore/editing/TextCheckingHelper.h \ 1358 1360 WebCore/editing/TextGranularity.h \ 1359 1361 WebCore/editing/TextIterator.cpp \ -
trunk/WebCore/WebCore.gypi
r70985 r71009 1438 1438 'editing/SplitTextNodeContainingElementCommand.h', 1439 1439 'editing/TextAffinity.h', 1440 'editing/TextCheckingHelper.cpp', 1441 'editing/TextCheckingHelper.h', 1440 1442 'editing/TextGranularity.h', 1441 1443 'editing/TextIterator.cpp', -
trunk/WebCore/WebCore.pro
r70985 r71009 818 818 editing/SplitTextNodeCommand.cpp \ 819 819 editing/SplitTextNodeContainingElementCommand.cpp \ 820 editing/TextCheckingHelper.cpp \ 820 821 editing/TextIterator.cpp \ 821 822 editing/TypingCommand.cpp \ -
trunk/WebCore/WebCore.vcproj/WebCore.vcproj
r70979 r71009 47941 47941 </File> 47942 47942 <File 47943 RelativePath="..\editing\TextCheckingHelper.cpp" 47944 > 47945 <FileConfiguration 47946 Name="Debug|Win32" 47947 ExcludedFromBuild="true" 47948 > 47949 <Tool 47950 Name="VCCLCompilerTool" 47951 /> 47952 </FileConfiguration> 47953 <FileConfiguration 47954 Name="Release|Win32" 47955 ExcludedFromBuild="true" 47956 > 47957 <Tool 47958 Name="VCCLCompilerTool" 47959 /> 47960 </FileConfiguration> 47961 <FileConfiguration 47962 Name="Debug_Internal|Win32" 47963 ExcludedFromBuild="true" 47964 > 47965 <Tool 47966 Name="VCCLCompilerTool" 47967 /> 47968 </FileConfiguration> 47969 <FileConfiguration 47970 Name="Debug_Cairo|Win32" 47971 ExcludedFromBuild="true" 47972 > 47973 <Tool 47974 Name="VCCLCompilerTool" 47975 /> 47976 </FileConfiguration> 47977 <FileConfiguration 47978 Name="Release_Cairo|Win32" 47979 ExcludedFromBuild="true" 47980 > 47981 <Tool 47982 Name="VCCLCompilerTool" 47983 /> 47984 </FileConfiguration> 47985 <FileConfiguration 47986 Name="Debug_All|Win32" 47987 ExcludedFromBuild="true" 47988 > 47989 <Tool 47990 Name="VCCLCompilerTool" 47991 /> 47992 </FileConfiguration> 47993 </File> 47994 <File 47995 RelativePath="..\editing\TextCheckingHelper.h" 47996 > 47997 </File> 47998 <File 47943 47999 RelativePath="..\editing\TextGranularity.h" 47944 48000 > -
trunk/WebCore/WebCore.xcodeproj/project.pbxproj
r70991 r71009 3070 3070 A7D6B3490F61104500B79FD1 /* WorkerScriptLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = A7D6B3470F61104500B79FD1 /* WorkerScriptLoader.h */; }; 3071 3071 A7D6B34A0F61104500B79FD1 /* WorkerScriptLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7D6B3480F61104500B79FD1 /* WorkerScriptLoader.cpp */; }; 3072 A7DBF8DD1276919C006B6008 /* TextCheckingHelper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7DBF8DB1276919C006B6008 /* TextCheckingHelper.cpp */; }; 3073 A7DBF8DE1276919C006B6008 /* TextCheckingHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = A7DBF8DC1276919C006B6008 /* TextCheckingHelper.h */; }; 3072 3074 A7F338A311C0EFCA00A320A7 /* ShadowElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7F338A111C0EFCA00A320A7 /* ShadowElement.cpp */; }; 3073 3075 A7F338A411C0EFCA00A320A7 /* ShadowElement.h in Headers */ = {isa = PBXBuildFile; fileRef = A7F338A211C0EFCA00A320A7 /* ShadowElement.h */; }; … … 9157 9159 A7D6B3470F61104500B79FD1 /* WorkerScriptLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WorkerScriptLoader.h; path = workers/WorkerScriptLoader.h; sourceTree = "<group>"; }; 9158 9160 A7D6B3480F61104500B79FD1 /* WorkerScriptLoader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WorkerScriptLoader.cpp; path = workers/WorkerScriptLoader.cpp; sourceTree = "<group>"; }; 9161 A7DBF8DB1276919C006B6008 /* TextCheckingHelper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TextCheckingHelper.cpp; sourceTree = "<group>"; }; 9162 A7DBF8DC1276919C006B6008 /* TextCheckingHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextCheckingHelper.h; sourceTree = "<group>"; }; 9159 9163 A7F338A111C0EFCA00A320A7 /* ShadowElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ShadowElement.cpp; sourceTree = "<group>"; }; 9160 9164 A7F338A211C0EFCA00A320A7 /* ShadowElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShadowElement.h; sourceTree = "<group>"; }; … … 14547 14551 93309DC8099E64910056E581 /* TextAffinity.h */, 14548 14552 93309DC9099E64910056E581 /* TextGranularity.h */, 14553 A7DBF8DB1276919C006B6008 /* TextCheckingHelper.cpp */, 14554 A7DBF8DC1276919C006B6008 /* TextCheckingHelper.h */, 14549 14555 93309DCC099E64910056E581 /* TextIterator.cpp */, 14550 14556 93309DCD099E64910056E581 /* TextIterator.h */, … … 21013 21019 B2C3DA360D006C1D00EF6F26 /* TextBreakIterator.h in Headers */, 21014 21020 B2C3DA380D006C1D00EF6F26 /* TextBreakIteratorInternalICU.h in Headers */, 21021 A7DBF8DE1276919C006B6008 /* TextCheckingHelper.h in Headers */, 21015 21022 B2C3DA3A0D006C1D00EF6F26 /* TextCodec.h in Headers */, 21016 21023 B2C3DA3C0D006C1D00EF6F26 /* TextCodecICU.h in Headers */, … … 23614 23621 B2C3DA370D006C1D00EF6F26 /* TextBreakIteratorICU.cpp in Sources */, 23615 23622 B2AFFC980D00A5DF0030074D /* TextBreakIteratorInternalICUMac.mm in Sources */, 23623 A7DBF8DD1276919C006B6008 /* TextCheckingHelper.cpp in Sources */, 23616 23624 B2C3DA390D006C1D00EF6F26 /* TextCodec.cpp in Sources */, 23617 23625 B2C3DA3B0D006C1D00EF6F26 /* TextCodecICU.cpp in Sources */, -
trunk/WebCore/editing/EditingAllInOne.cpp
r70970 r71009 66 66 #include <SplitTextNodeCommand.cpp> 67 67 #include <SplitTextNodeContainingElementCommand.cpp> 68 #include <TextCheckingHelper.cpp> 68 69 #include <TextIterator.cpp> 69 70 #include <TypingCommand.cpp> -
trunk/WebCore/editing/Editor.cpp
r70970 r71009 63 63 #include "Page.h" 64 64 #include "Pasteboard.h" 65 #include "TextCheckingHelper.h" 65 66 #include "RemoveFormatCommand.h" 66 67 #include "RenderBlock.h" … … 1660 1661 } 1661 1662 1662 static String findFirstMisspellingInRange(EditorClient* client, Range* searchRange, int& firstMisspellingOffset, bool markAll, RefPtr<Range>& firstMisspellingRange)1663 {1664 ASSERT_ARG(client, client);1665 ASSERT_ARG(searchRange, searchRange);1666 1667 WordAwareIterator it(searchRange);1668 firstMisspellingOffset = 0;1669 1670 String firstMisspelling;1671 int currentChunkOffset = 0;1672 1673 while (!it.atEnd()) {1674 const UChar* chars = it.characters();1675 int len = it.length();1676 1677 // Skip some work for one-space-char hunks1678 if (!(len == 1 && chars[0] == ' ')) {1679 1680 int misspellingLocation = -1;1681 int misspellingLength = 0;1682 client->checkSpellingOfString(chars, len, &misspellingLocation, &misspellingLength);1683 1684 // 5490627 shows that there was some code path here where the String constructor below crashes.1685 // We don't know exactly what combination of bad input caused this, so we're making this much1686 // more robust against bad input on release builds.1687 ASSERT(misspellingLength >= 0);1688 ASSERT(misspellingLocation >= -1);1689 ASSERT(!misspellingLength || misspellingLocation >= 0);1690 ASSERT(misspellingLocation < len);1691 ASSERT(misspellingLength <= len);1692 ASSERT(misspellingLocation + misspellingLength <= len);1693 1694 if (misspellingLocation >= 0 && misspellingLength > 0 && misspellingLocation < len && misspellingLength <= len && misspellingLocation + misspellingLength <= len) {1695 1696 // Compute range of misspelled word1697 RefPtr<Range> misspellingRange = TextIterator::subrange(searchRange, currentChunkOffset + misspellingLocation, misspellingLength);1698 1699 // Remember first-encountered misspelling and its offset.1700 if (!firstMisspelling) {1701 firstMisspellingOffset = currentChunkOffset + misspellingLocation;1702 firstMisspelling = String(chars + misspellingLocation, misspellingLength);1703 firstMisspellingRange = misspellingRange;1704 }1705 1706 // Store marker for misspelled word.1707 ExceptionCode ec = 0;1708 misspellingRange->startContainer(ec)->document()->markers()->addMarker(misspellingRange.get(), DocumentMarker::Spelling);1709 ASSERT(!ec);1710 1711 // Bail out if we're marking only the first misspelling, and not all instances.1712 if (!markAll)1713 break;1714 }1715 }1716 1717 currentChunkOffset += len;1718 it.advance();1719 }1720 1721 return firstMisspelling;1722 }1723 1724 #ifndef BUILDING_ON_TIGER1725 1726 static PassRefPtr<Range> paragraphAlignedRangeForRange(Range* arbitraryRange, int& offsetIntoParagraphAlignedRange, String& paragraphString)1727 {1728 ASSERT_ARG(arbitraryRange, arbitraryRange);1729 1730 ExceptionCode ec = 0;1731 1732 // Expand range to paragraph boundaries1733 RefPtr<Range> paragraphRange = arbitraryRange->cloneRange(ec);1734 setStart(paragraphRange.get(), startOfParagraph(arbitraryRange->startPosition()));1735 setEnd(paragraphRange.get(), endOfParagraph(arbitraryRange->endPosition()));1736 1737 // Compute offset from start of expanded range to start of original range1738 RefPtr<Range> offsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), paragraphRange->startPosition(), arbitraryRange->startPosition());1739 offsetIntoParagraphAlignedRange = TextIterator::rangeLength(offsetAsRange.get());1740 1741 // Fill in out parameter with string representing entire paragraph range.1742 // Someday we might have a caller that doesn't use this, but for now all callers do.1743 paragraphString = plainText(paragraphRange.get());1744 1745 return paragraphRange;1746 }1747 1748 static int findFirstGrammarDetailInRange(const Vector<GrammarDetail>& grammarDetails, int badGrammarPhraseLocation, int /*badGrammarPhraseLength*/, Range *searchRange, int startOffset, int endOffset, bool markAll)1749 {1750 // Found some bad grammar. Find the earliest detail range that starts in our search range (if any).1751 // Optionally add a DocumentMarker for each detail in the range.1752 int earliestDetailLocationSoFar = -1;1753 int earliestDetailIndex = -1;1754 for (unsigned i = 0; i < grammarDetails.size(); i++) {1755 const GrammarDetail* detail = &grammarDetails[i];1756 ASSERT(detail->length > 0 && detail->location >= 0);1757 1758 int detailStartOffsetInParagraph = badGrammarPhraseLocation + detail->location;1759 1760 // Skip this detail if it starts before the original search range1761 if (detailStartOffsetInParagraph < startOffset)1762 continue;1763 1764 // Skip this detail if it starts after the original search range1765 if (detailStartOffsetInParagraph >= endOffset)1766 continue;1767 1768 if (markAll) {1769 RefPtr<Range> badGrammarRange = TextIterator::subrange(searchRange, badGrammarPhraseLocation - startOffset + detail->location, detail->length);1770 ExceptionCode ec = 0;1771 badGrammarRange->startContainer(ec)->document()->markers()->addMarker(badGrammarRange.get(), DocumentMarker::Grammar, detail->userDescription);1772 ASSERT(!ec);1773 }1774 1775 // Remember this detail only if it's earlier than our current candidate (the details aren't in a guaranteed order)1776 if (earliestDetailIndex < 0 || earliestDetailLocationSoFar > detail->location) {1777 earliestDetailIndex = i;1778 earliestDetailLocationSoFar = detail->location;1779 }1780 }1781 1782 return earliestDetailIndex;1783 }1784 1785 static String findFirstBadGrammarInRange(EditorClient* client, Range* searchRange, GrammarDetail& outGrammarDetail, int& outGrammarPhraseOffset, bool markAll)1786 {1787 ASSERT_ARG(client, client);1788 ASSERT_ARG(searchRange, searchRange);1789 1790 // Initialize out parameters; these will be updated if we find something to return.1791 outGrammarDetail.location = -1;1792 outGrammarDetail.length = 0;1793 outGrammarDetail.guesses.clear();1794 outGrammarDetail.userDescription = "";1795 outGrammarPhraseOffset = 0;1796 1797 String firstBadGrammarPhrase;1798 1799 // Expand the search range to encompass entire paragraphs, since grammar checking needs that much context.1800 // Determine the character offset from the start of the paragraph to the start of the original search range,1801 // since we will want to ignore results in this area.1802 int searchRangeStartOffset;1803 String paragraphString;1804 RefPtr<Range> paragraphRange = paragraphAlignedRangeForRange(searchRange, searchRangeStartOffset, paragraphString);1805 1806 // Determine the character offset from the start of the paragraph to the end of the original search range,1807 // since we will want to ignore results in this area also.1808 int searchRangeEndOffset = searchRangeStartOffset + TextIterator::rangeLength(searchRange);1809 1810 // Start checking from beginning of paragraph, but skip past results that occur before the start of the original search range.1811 int startOffset = 0;1812 while (startOffset < searchRangeEndOffset) {1813 Vector<GrammarDetail> grammarDetails;1814 int badGrammarPhraseLocation = -1;1815 int badGrammarPhraseLength = 0;1816 client->checkGrammarOfString(paragraphString.characters() + startOffset, paragraphString.length() - startOffset, grammarDetails, &badGrammarPhraseLocation, &badGrammarPhraseLength);1817 1818 if (!badGrammarPhraseLength) {1819 ASSERT(badGrammarPhraseLocation == -1);1820 return String();1821 }1822 1823 ASSERT(badGrammarPhraseLocation >= 0);1824 badGrammarPhraseLocation += startOffset;1825 1826 1827 // Found some bad grammar. Find the earliest detail range that starts in our search range (if any).1828 int badGrammarIndex = findFirstGrammarDetailInRange(grammarDetails, badGrammarPhraseLocation, badGrammarPhraseLength, searchRange, searchRangeStartOffset, searchRangeEndOffset, markAll);1829 if (badGrammarIndex >= 0) {1830 ASSERT(static_cast<unsigned>(badGrammarIndex) < grammarDetails.size());1831 outGrammarDetail = grammarDetails[badGrammarIndex];1832 }1833 1834 // If we found a detail in range, then we have found the first bad phrase (unless we found one earlier but1835 // kept going so we could mark all instances).1836 if (badGrammarIndex >= 0 && firstBadGrammarPhrase.isEmpty()) {1837 outGrammarPhraseOffset = badGrammarPhraseLocation - searchRangeStartOffset;1838 firstBadGrammarPhrase = paragraphString.substring(badGrammarPhraseLocation, badGrammarPhraseLength);1839 1840 // Found one. We're done now, unless we're marking each instance.1841 if (!markAll)1842 break;1843 }1844 1845 // These results were all between the start of the paragraph and the start of the search range; look1846 // beyond this phrase.1847 startOffset = badGrammarPhraseLocation + badGrammarPhraseLength;1848 }1849 1850 return firstBadGrammarPhrase;1851 }1852 1853 #endif /* not BUILDING_ON_TIGER */1854 1855 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)1856 1857 static String findFirstMisspellingOrBadGrammarInRange(EditorClient* client, Range* searchRange, bool checkGrammar, bool& outIsSpelling, int& outFirstFoundOffset, GrammarDetail& outGrammarDetail)1858 {1859 ASSERT_ARG(client, client);1860 ASSERT_ARG(searchRange, searchRange);1861 1862 String firstFoundItem;1863 String misspelledWord;1864 String badGrammarPhrase;1865 ExceptionCode ec = 0;1866 1867 // Initialize out parameters; these will be updated if we find something to return.1868 outIsSpelling = true;1869 outFirstFoundOffset = 0;1870 outGrammarDetail.location = -1;1871 outGrammarDetail.length = 0;1872 outGrammarDetail.guesses.clear();1873 outGrammarDetail.userDescription = "";1874 1875 // Expand the search range to encompass entire paragraphs, since text checking needs that much context.1876 // Determine the character offset from the start of the paragraph to the start of the original search range,1877 // since we will want to ignore results in this area.1878 RefPtr<Range> paragraphRange = searchRange->cloneRange(ec);1879 setStart(paragraphRange.get(), startOfParagraph(searchRange->startPosition()));1880 int totalRangeLength = TextIterator::rangeLength(paragraphRange.get());1881 setEnd(paragraphRange.get(), endOfParagraph(searchRange->startPosition()));1882 1883 RefPtr<Range> offsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), paragraphRange->startPosition(), searchRange->startPosition());1884 int searchRangeStartOffset = TextIterator::rangeLength(offsetAsRange.get());1885 int totalLengthProcessed = 0;1886 1887 bool firstIteration = true;1888 bool lastIteration = false;1889 while (totalLengthProcessed < totalRangeLength) {1890 // Iterate through the search range by paragraphs, checking each one for spelling and grammar.1891 int currentLength = TextIterator::rangeLength(paragraphRange.get());1892 int currentStartOffset = firstIteration ? searchRangeStartOffset : 0;1893 int currentEndOffset = currentLength;1894 if (inSameParagraph(paragraphRange->startPosition(), searchRange->endPosition())) {1895 // Determine the character offset from the end of the original search range to the end of the paragraph,1896 // since we will want to ignore results in this area.1897 RefPtr<Range> endOffsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), paragraphRange->startPosition(), searchRange->endPosition());1898 currentEndOffset = TextIterator::rangeLength(endOffsetAsRange.get());1899 lastIteration = true;1900 }1901 if (currentStartOffset < currentEndOffset) {1902 String paragraphString = plainText(paragraphRange.get());1903 if (paragraphString.length() > 0) {1904 bool foundGrammar = false;1905 int spellingLocation = 0;1906 int grammarPhraseLocation = 0;1907 int grammarDetailLocation = 0;1908 unsigned grammarDetailIndex = 0;1909 1910 Vector<TextCheckingResult> results;1911 uint64_t checkingTypes = checkGrammar ? (TextCheckingTypeSpelling | TextCheckingTypeGrammar) : TextCheckingTypeSpelling;1912 client->checkTextOfParagraph(paragraphString.characters(), paragraphString.length(), checkingTypes, results);1913 1914 for (unsigned i = 0; i < results.size(); i++) {1915 const TextCheckingResult* result = &results[i];1916 if (result->type == TextCheckingTypeSpelling && result->location >= currentStartOffset && result->location + result->length <= currentEndOffset) {1917 ASSERT(result->length > 0 && result->location >= 0);1918 spellingLocation = result->location;1919 misspelledWord = paragraphString.substring(result->location, result->length);1920 ASSERT(misspelledWord.length());1921 break;1922 }1923 if (checkGrammar && result->type == TextCheckingTypeGrammar && result->location < currentEndOffset && result->location + result->length > currentStartOffset) {1924 ASSERT(result->length > 0 && result->location >= 0);1925 // We can't stop after the first grammar result, since there might still be a spelling result after1926 // it begins but before the first detail in it, but we can stop if we find a second grammar result.1927 if (foundGrammar)1928 break;1929 for (unsigned j = 0; j < result->details.size(); j++) {1930 const GrammarDetail* detail = &result->details[j];1931 ASSERT(detail->length > 0 && detail->location >= 0);1932 if (result->location + detail->location >= currentStartOffset && result->location + detail->location + detail->length <= currentEndOffset && (!foundGrammar || result->location + detail->location < grammarDetailLocation)) {1933 grammarDetailIndex = j;1934 grammarDetailLocation = result->location + detail->location;1935 foundGrammar = true;1936 }1937 }1938 if (foundGrammar) {1939 grammarPhraseLocation = result->location;1940 outGrammarDetail = result->details[grammarDetailIndex];1941 badGrammarPhrase = paragraphString.substring(result->location, result->length);1942 ASSERT(badGrammarPhrase.length());1943 }1944 }1945 }1946 1947 if (!misspelledWord.isEmpty() && (!checkGrammar || badGrammarPhrase.isEmpty() || spellingLocation <= grammarDetailLocation)) {1948 int spellingOffset = spellingLocation - currentStartOffset;1949 if (!firstIteration) {1950 RefPtr<Range> paragraphOffsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), searchRange->startPosition(), paragraphRange->startPosition());1951 spellingOffset += TextIterator::rangeLength(paragraphOffsetAsRange.get());1952 }1953 outIsSpelling = true;1954 outFirstFoundOffset = spellingOffset;1955 firstFoundItem = misspelledWord;1956 break;1957 }1958 if (checkGrammar && !badGrammarPhrase.isEmpty()) {1959 int grammarPhraseOffset = grammarPhraseLocation - currentStartOffset;1960 if (!firstIteration) {1961 RefPtr<Range> paragraphOffsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), searchRange->startPosition(), paragraphRange->startPosition());1962 grammarPhraseOffset += TextIterator::rangeLength(paragraphOffsetAsRange.get());1963 }1964 outIsSpelling = false;1965 outFirstFoundOffset = grammarPhraseOffset;1966 firstFoundItem = badGrammarPhrase;1967 break;1968 }1969 }1970 }1971 if (lastIteration || totalLengthProcessed + currentLength >= totalRangeLength)1972 break;1973 VisiblePosition newParagraphStart = startOfNextParagraph(paragraphRange->endPosition());1974 setStart(paragraphRange.get(), newParagraphStart);1975 setEnd(paragraphRange.get(), endOfParagraph(newParagraphStart));1976 firstIteration = false;1977 totalLengthProcessed += currentLength;1978 }1979 return firstFoundItem;1980 }1981 1982 #endif1983 1984 1663 void Editor::advanceToNextMisspelling(bool startBeforeSelection) 1985 1664 { … … 1993 1672 VisibleSelection selection(frame()->selection()->selection()); 1994 1673 RefPtr<Range> spellingSearchRange(rangeOfContents(frame()->document())); 1674 1995 1675 bool startedWithSelection = false; 1996 1676 if (selection.start().node()) { … … 2058 1738 int foundOffset = 0; 2059 1739 GrammarDetail grammarDetail; 2060 String foundItem = findFirstMisspellingOrBadGrammarInRange(client(), spellingSearchRange.get(),isGrammarCheckingEnabled(), isSpelling, foundOffset, grammarDetail);1740 String foundItem = TextCheckingHelper(client(), spellingSearchRange).findFirstMisspellingOrBadGrammar(isGrammarCheckingEnabled(), isSpelling, foundOffset, grammarDetail); 2061 1741 if (isSpelling) { 2062 1742 misspelledWord = foundItem; … … 2068 1748 #else 2069 1749 RefPtr<Range> firstMisspellingRange; 2070 String misspelledWord = findFirstMisspellingInRange(client(), spellingSearchRange.get(),misspellingOffset, false, firstMisspellingRange);1750 String misspelledWord = TextCheckingHelper(client(), spellingSearchRange).findFirstMisspelling(misspellingOffset, false, firstMisspellingRange); 2071 1751 String badGrammarPhrase; 2072 1752 … … 2085 1765 2086 1766 if (isGrammarCheckingEnabled()) 2087 badGrammarPhrase = findFirstBadGrammarInRange(client(), grammarSearchRange.get(),grammarDetail, grammarPhraseOffset, false);1767 badGrammarPhrase = TextCheckingHelper(client(), grammarSearchRange).findFirstBadGrammar(grammarDetail, grammarPhraseOffset, false); 2088 1768 #endif 2089 1769 #endif … … 2098 1778 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 2099 1779 grammarSearchRange = spellingSearchRange->cloneRange(ec); 2100 foundItem = findFirstMisspellingOrBadGrammarInRange(client(), spellingSearchRange.get(),isGrammarCheckingEnabled(), isSpelling, foundOffset, grammarDetail);1780 foundItem = TextCheckingHelper(client(), spellingSearchRange).findFirstMisspellingOrBadGrammar(isGrammarCheckingEnabled(), isSpelling, foundOffset, grammarDetail); 2101 1781 if (isSpelling) { 2102 1782 misspelledWord = foundItem; … … 2107 1787 } 2108 1788 #else 2109 misspelledWord = findFirstMisspellingInRange(client(), spellingSearchRange.get(),misspellingOffset, false, firstMisspellingRange);1789 misspelledWord = TextCheckingHelper(client(), spellingSearchRange).findFirstMisspelling(misspellingOffset, false, firstMisspellingRange); 2110 1790 2111 1791 #ifndef BUILDING_ON_TIGER … … 2117 1797 grammarSearchRange->setEnd(chars.range()->startContainer(ec), chars.range()->startOffset(ec), ec); 2118 1798 } 1799 2119 1800 if (isGrammarCheckingEnabled()) 2120 badGrammarPhrase = findFirstBadGrammarInRange(client(), grammarSearchRange.get(),grammarDetail, grammarPhraseOffset, false);1801 badGrammarPhrase = TextCheckingHelper(client(), grammarSearchRange).findFirstBadGrammar(grammarDetail, grammarPhraseOffset, false); 2121 1802 #endif 2122 1803 #endif … … 2182 1863 } 2183 1864 2184 #ifndef BUILDING_ON_TIGER2185 static bool isRangeUngrammatical(EditorClient* client, Range *range, Vector<String>& guessesVector)2186 {2187 if (!client)2188 return false;2189 2190 ExceptionCode ec;2191 if (!range || range->collapsed(ec))2192 return false;2193 2194 // Returns true only if the passed range exactly corresponds to a bad grammar detail range. This is analogous2195 // to isSelectionMisspelled. It's not good enough for there to be some bad grammar somewhere in the range,2196 // or overlapping the range; the ranges must exactly match.2197 guessesVector.clear();2198 int grammarPhraseOffset;2199 2200 GrammarDetail grammarDetail;2201 String badGrammarPhrase = findFirstBadGrammarInRange(client, range, grammarDetail, grammarPhraseOffset, false);2202 2203 // No bad grammar in these parts at all.2204 if (badGrammarPhrase.isEmpty())2205 return false;2206 2207 // Bad grammar, but phrase (e.g. sentence) starts beyond start of range.2208 if (grammarPhraseOffset > 0)2209 return false;2210 2211 ASSERT(grammarDetail.location >= 0 && grammarDetail.length > 0);2212 2213 // Bad grammar, but start of detail (e.g. ungrammatical word) doesn't match start of range2214 if (grammarDetail.location + grammarPhraseOffset)2215 return false;2216 2217 // Bad grammar at start of range, but end of bad grammar is before or after end of range2218 if (grammarDetail.length != TextIterator::rangeLength(range))2219 return false;2220 2221 // Update the spelling panel to be displaying this error (whether or not the spelling panel is on screen).2222 // This is necessary to make a subsequent call to [NSSpellChecker ignoreWord:inSpellDocumentWithTag:] work2223 // correctly; that call behaves differently based on whether the spelling panel is displaying a misspelling2224 // or a grammar error.2225 client->updateSpellingUIWithGrammarString(badGrammarPhrase, grammarDetail);2226 2227 return true;2228 }2229 #endif2230 2231 1865 bool Editor::isSelectionUngrammatical() 2232 1866 { … … 2235 1869 #else 2236 1870 Vector<String> ignoredGuesses; 2237 return isRangeUngrammatical(client(), frame()->selection()->toNormalizedRange().get(),ignoredGuesses);1871 return TextCheckingHelper(client(), frame()->selection()->toNormalizedRange()).isUngrammatical(ignoredGuesses); 2238 1872 #endif 2239 1873 } … … 2245 1879 #else 2246 1880 Vector<String> guesses; 2247 // Ignore the result of is RangeUngrammatical; we just want the guesses, whether or not there are any2248 isRangeUngrammatical(client(), frame()->selection()->toNormalizedRange().get(),guesses);1881 // Ignore the result of isUngrammatical; we just want the guesses, whether or not there are any 1882 TextCheckingHelper(client(), frame()->selection()->toNormalizedRange()).isUngrammatical(guesses); 2249 1883 return guesses; 2250 1884 #endif … … 2262 1896 } 2263 1897 1898 Vector<String> Editor::guessesForMisspelledOrUngrammaticalSelection(bool& misspelled, bool& ungrammatical) 1899 { 2264 1900 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 2265 2266 static Vector<String> guessesForMisspelledOrUngrammaticalRange(EditorClient* client, Range *range, bool checkGrammar, bool& misspelled, bool& ungrammatical) 2267 { 2268 Vector<String> guesses; 2269 ExceptionCode ec; 2270 misspelled = false; 2271 ungrammatical = false; 2272 2273 if (!client || !range || range->collapsed(ec)) 2274 return guesses; 2275 2276 // Expand the range to encompass entire paragraphs, since text checking needs that much context. 2277 int rangeStartOffset; 2278 String paragraphString; 2279 RefPtr<Range> paragraphRange = paragraphAlignedRangeForRange(range, rangeStartOffset, paragraphString); 2280 int rangeLength = TextIterator::rangeLength(range); 2281 if (!rangeLength || !paragraphString.length()) 2282 return guesses; 2283 2284 Vector<TextCheckingResult> results; 2285 uint64_t checkingTypes = checkGrammar ? (TextCheckingTypeSpelling | TextCheckingTypeGrammar) : TextCheckingTypeSpelling; 2286 client->checkTextOfParagraph(paragraphString.characters(), paragraphString.length(), checkingTypes, results); 2287 2288 for (unsigned i = 0; i < results.size(); i++) { 2289 const TextCheckingResult* result = &results[i]; 2290 if (result->type == TextCheckingTypeSpelling && result->location == rangeStartOffset && result->length == rangeLength) { 2291 String misspelledWord = paragraphString.substring(rangeStartOffset, rangeLength); 2292 ASSERT(misspelledWord.length()); 2293 client->getGuessesForWord(misspelledWord, guesses); 2294 client->updateSpellingUIWithMisspelledWord(misspelledWord); 2295 misspelled = true; 2296 return guesses; 2297 } 2298 } 2299 2300 if (!checkGrammar) 2301 return guesses; 2302 2303 for (unsigned i = 0; i < results.size(); i++) { 2304 const TextCheckingResult* result = &results[i]; 2305 if (result->type == TextCheckingTypeGrammar && result->location <= rangeStartOffset && result->location + result->length >= rangeStartOffset + rangeLength) { 2306 for (unsigned j = 0; j < result->details.size(); j++) { 2307 const GrammarDetail* detail = &result->details[j]; 2308 ASSERT(detail->length > 0 && detail->location >= 0); 2309 if (result->location + detail->location == rangeStartOffset && detail->length == rangeLength) { 2310 String badGrammarPhrase = paragraphString.substring(result->location, result->length); 2311 ASSERT(badGrammarPhrase.length()); 2312 for (unsigned k = 0; k < detail->guesses.size(); k++) 2313 guesses.append(detail->guesses[k]); 2314 client->updateSpellingUIWithGrammarString(badGrammarPhrase, *detail); 2315 ungrammatical = true; 2316 return guesses; 2317 } 2318 } 2319 } 2320 } 2321 return guesses; 2322 } 2323 2324 #endif 2325 2326 Vector<String> Editor::guessesForMisspelledOrUngrammaticalSelection(bool& misspelled, bool& ungrammatical) 2327 { 2328 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 2329 return guessesForMisspelledOrUngrammaticalRange(client(), frame()->selection()->toNormalizedRange().get(), isGrammarCheckingEnabled(), misspelled, ungrammatical); 1901 return TextCheckingHelper(client(), frame()->selection()->toNormalizedRange()).guessesForMisspelledOrUngrammaticalRange(isGrammarCheckingEnabled(), misspelled, ungrammatical); 2330 1902 #else 2331 1903 misspelled = isSelectionMisspelled(); … … 2504 2076 #endif 2505 2077 } 2506 2507 static void markAllMisspellingsInRange(EditorClient* client, Range* searchRange, RefPtr<Range>& firstMisspellingRange) 2508 { 2509 // Use the "markAll" feature of findFirstMisspellingInRange. Ignore the return value and the "out parameter"; 2510 // all we need to do is mark every instance. 2511 int ignoredOffset; 2512 findFirstMisspellingInRange(client, searchRange, ignoredOffset, true, firstMisspellingRange); 2513 } 2514 2515 #ifndef BUILDING_ON_TIGER 2516 static void markAllBadGrammarInRange(EditorClient* client, Range* searchRange) 2517 { 2518 // Use the "markAll" feature of findFirstBadGrammarInRange. Ignore the return value and "out parameters"; all we need to 2519 // do is mark every instance. 2520 GrammarDetail ignoredGrammarDetail; 2521 int ignoredOffset; 2522 findFirstBadGrammarInRange(client, searchRange, ignoredGrammarDetail, ignoredOffset, true); 2523 } 2524 #endif 2525 2526 static void markMisspellingsOrBadGrammar(Editor* editor, const VisibleSelection& selection, bool checkSpelling, RefPtr<Range>& firstMisspellingRange) 2078 2079 void Editor::markMisspellingsOrBadGrammar(const VisibleSelection& selection, bool checkSpelling, RefPtr<Range>& firstMisspellingRange) 2527 2080 { 2528 2081 // This function is called with a selection already expanded to word boundaries. … … 2531 2084 // This function is used only for as-you-type checking, so if that's off we do nothing. Note that 2532 2085 // grammar checking can only be on if spell checking is also on. 2533 if (! editor->isContinuousSpellCheckingEnabled())2086 if (!isContinuousSpellCheckingEnabled()) 2534 2087 return; 2535 2088 … … 2543 2096 return; 2544 2097 2545 if (! editor->isSpellCheckingEnabledInFocusedNode())2098 if (!isSpellCheckingEnabledInFocusedNode()) 2546 2099 return; 2547 2100 2548 2101 // Get the spell checker if it is available 2549 if (!editor->client()) 2550 return; 2551 2102 if (!client()) 2103 return; 2104 2105 TextCheckingHelper checker(client(), searchRange); 2552 2106 if (checkSpelling) 2553 markAllMisspellingsInRange(editor->client(), searchRange.get(),firstMisspellingRange);2107 checker.markAllMisspellings(firstMisspellingRange); 2554 2108 else { 2555 2109 #ifdef BUILDING_ON_TIGER 2556 2110 ASSERT_NOT_REACHED(); 2557 2111 #else 2558 if ( editor->isGrammarCheckingEnabled())2559 markAllBadGrammarInRange(editor->client(), searchRange.get());2112 if (isGrammarCheckingEnabled()) 2113 checker.markAllBadGrammar(); 2560 2114 #endif 2561 2115 } … … 2577 2131 void Editor::markMisspellings(const VisibleSelection& selection, RefPtr<Range>& firstMisspellingRange) 2578 2132 { 2579 markMisspellingsOrBadGrammar( this,selection, true, firstMisspellingRange);2133 markMisspellingsOrBadGrammar(selection, true, firstMisspellingRange); 2580 2134 } 2581 2135 … … 2584 2138 #ifndef BUILDING_ON_TIGER 2585 2139 RefPtr<Range> firstMisspellingRange; 2586 markMisspellingsOrBadGrammar( this,selection, false, firstMisspellingRange);2140 markMisspellingsOrBadGrammar(selection, false, firstMisspellingRange); 2587 2141 #else 2588 2142 UNUSED_PARAM(selection); … … 2637 2191 if (shouldMarkGrammar) { 2638 2192 // The spelling range should be contained in the paragraph-aligned extension of the grammar range. 2639 paragraphRange = paragraphAlignedRangeForRange(grammarRange,grammarRangeStartOffset, paragraphString);2193 paragraphRange = TextCheckingHelper(client(), grammarRange).paragraphAlignedRange(grammarRangeStartOffset, paragraphString); 2640 2194 RefPtr<Range> offsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), paragraphRange->startPosition(), spellingRange->startPosition()); 2641 2195 spellingRangeStartOffset = TextIterator::rangeLength(offsetAsRange.get()); 2642 2196 grammarRangeEndOffset = grammarRangeStartOffset + TextIterator::rangeLength(grammarRange); 2643 2197 } else { 2644 paragraphRange = paragraphAlignedRangeForRange(spellingRange,spellingRangeStartOffset, paragraphString);2198 paragraphRange = TextCheckingHelper(client(), spellingRange).paragraphAlignedRange(spellingRangeStartOffset, paragraphString); 2645 2199 } 2646 2200 spellingRangeEndOffset = spellingRangeStartOffset + TextIterator::rangeLength(spellingRange); … … 2832 2386 if (!shouldInsertText(replacedString, selection.get(), EditorInsertActionPasted)) 2833 2387 return; 2834 2388 2835 2389 String paragraphString; 2836 2390 int selectionOffset; 2837 RefPtr<Range> paragraphRange = paragraphAlignedRangeForRange(selection.get(),selectionOffset, paragraphString);2391 RefPtr<Range> paragraphRange = TextCheckingHelper(client(), selection).paragraphAlignedRange(selectionOffset, paragraphString); 2838 2392 replaceSelectionWithText(replacedString, false, false); 2839 2393 RefPtr<Range> changedRange = TextIterator::subrange(paragraphRange.get(), selectionOffset, replacedString.length()); -
trunk/WebCore/editing/Editor.h
r70970 r71009 405 405 void writeSelectionToPasteboard(Pasteboard*); 406 406 void revealSelectionAfterEditingOperation(); 407 void markMisspellingsOrBadGrammar(const VisibleSelection&, bool checkSpelling, RefPtr<Range>& firstMisspellingRange); 407 408 408 409 void selectComposition();
Note: See TracChangeset
for help on using the changeset viewer.