Changeset 70970 in webkit


Ignore:
Timestamp:
Oct 29, 2010 8:42:11 PM (13 years ago)
Author:
mrowe@apple.com
Message:

Roll out r70847 as it causes crashes when typing text in both Safari and Mail: <http://webkit.org/b/48708>.

Location:
trunk/WebCore
Files:
2 deleted
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/CMakeLists.txt

    r70956 r70970  
    927927    editing/SplitTextNodeCommand.cpp
    928928    editing/SplitTextNodeContainingElementCommand.cpp
    929     editing/TextCheckingHelper.cpp
    930929    editing/TextIterator.cpp
    931930    editing/TypingCommand.cpp
  • trunk/WebCore/GNUmakefile.am

    r70960 r70970  
    13561356        WebCore/editing/SplitTextNodeContainingElementCommand.h \
    13571357        WebCore/editing/TextAffinity.h \
    1358         WebCore/editing/TextCheckingHelper.cpp \
    1359         WebCore/editing/TextCheckingHelper.h \
    13601358        WebCore/editing/TextGranularity.h \
    13611359        WebCore/editing/TextIterator.cpp \
  • trunk/WebCore/WebCore.gypi

    r70960 r70970  
    14381438            'editing/SplitTextNodeContainingElementCommand.h',
    14391439            'editing/TextAffinity.h',
    1440             'editing/TextCheckingHelper.cpp',
    1441             'editing/TextCheckingHelper.h',
    14421440            'editing/TextGranularity.h',
    14431441            'editing/TextIterator.cpp',
  • trunk/WebCore/WebCore.pro

    r70960 r70970  
    818818    editing/SplitTextNodeCommand.cpp \
    819819    editing/SplitTextNodeContainingElementCommand.cpp \
    820     editing/TextCheckingHelper.cpp \
    821820    editing/TextIterator.cpp \
    822821    editing/TypingCommand.cpp \
  • trunk/WebCore/WebCore.vcproj/WebCore.vcproj

    r70960 r70970  
    4794147941                        </File>
    4794247942                        <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
    4799947943                                RelativePath="..\editing\TextGranularity.h"
    4800047944                                >
  • trunk/WebCore/WebCore.xcodeproj/project.pbxproj

    r70960 r70970  
    30683068                A7D6B3490F61104500B79FD1 /* WorkerScriptLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = A7D6B3470F61104500B79FD1 /* WorkerScriptLoader.h */; };
    30693069                A7D6B34A0F61104500B79FD1 /* WorkerScriptLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7D6B3480F61104500B79FD1 /* WorkerScriptLoader.cpp */; };
    3070                 A7DBF8DD1276919C006B6008 /* TextCheckingHelper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7DBF8DB1276919C006B6008 /* TextCheckingHelper.cpp */; };
    3071                 A7DBF8DE1276919C006B6008 /* TextCheckingHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = A7DBF8DC1276919C006B6008 /* TextCheckingHelper.h */; };
    30723070                A7F338A311C0EFCA00A320A7 /* ShadowElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7F338A111C0EFCA00A320A7 /* ShadowElement.cpp */; };
    30733071                A7F338A411C0EFCA00A320A7 /* ShadowElement.h in Headers */ = {isa = PBXBuildFile; fileRef = A7F338A211C0EFCA00A320A7 /* ShadowElement.h */; };
     
    91559153                A7D6B3470F61104500B79FD1 /* WorkerScriptLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WorkerScriptLoader.h; path = workers/WorkerScriptLoader.h; sourceTree = "<group>"; };
    91569154                A7D6B3480F61104500B79FD1 /* WorkerScriptLoader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WorkerScriptLoader.cpp; path = workers/WorkerScriptLoader.cpp; sourceTree = "<group>"; };
    9157                 A7DBF8DB1276919C006B6008 /* TextCheckingHelper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TextCheckingHelper.cpp; sourceTree = "<group>"; };
    9158                 A7DBF8DC1276919C006B6008 /* TextCheckingHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextCheckingHelper.h; sourceTree = "<group>"; };
    91599155                A7F338A111C0EFCA00A320A7 /* ShadowElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ShadowElement.cpp; sourceTree = "<group>"; };
    91609156                A7F338A211C0EFCA00A320A7 /* ShadowElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShadowElement.h; sourceTree = "<group>"; };
     
    1454614542                                93309DC7099E64910056E581 /* SplitTextNodeContainingElementCommand.h */,
    1454714543                                93309DC8099E64910056E581 /* TextAffinity.h */,
    14548                                 A7DBF8DB1276919C006B6008 /* TextCheckingHelper.cpp */,
    14549                                 A7DBF8DC1276919C006B6008 /* TextCheckingHelper.h */,
    1455014544                                93309DC9099E64910056E581 /* TextGranularity.h */,
    1455114545                                93309DCC099E64910056E581 /* TextIterator.cpp */,
     
    2101321007                                B2C3DA360D006C1D00EF6F26 /* TextBreakIterator.h in Headers */,
    2101421008                                B2C3DA380D006C1D00EF6F26 /* TextBreakIteratorInternalICU.h in Headers */,
    21015                                 A7DBF8DE1276919C006B6008 /* TextCheckingHelper.h in Headers */,
    2101621009                                B2C3DA3A0D006C1D00EF6F26 /* TextCodec.h in Headers */,
    2101721010                                B2C3DA3C0D006C1D00EF6F26 /* TextCodecICU.h in Headers */,
     
    2361423607                                B2C3DA370D006C1D00EF6F26 /* TextBreakIteratorICU.cpp in Sources */,
    2361523608                                B2AFFC980D00A5DF0030074D /* TextBreakIteratorInternalICUMac.mm in Sources */,
    23616                                 A7DBF8DD1276919C006B6008 /* TextCheckingHelper.cpp in Sources */,
    2361723609                                B2C3DA390D006C1D00EF6F26 /* TextCodec.cpp in Sources */,
    2361823610                                B2C3DA3B0D006C1D00EF6F26 /* TextCodecICU.cpp in Sources */,
  • trunk/WebCore/editing/EditingAllInOne.cpp

    r70852 r70970  
    6666#include <SplitTextNodeCommand.cpp>
    6767#include <SplitTextNodeContainingElementCommand.cpp>
    68 #include <TextCheckingHelper.cpp>
    6968#include <TextIterator.cpp>
    7069#include <TypingCommand.cpp>
  • trunk/WebCore/editing/Editor.cpp

    r70847 r70970  
    6363#include "Page.h"
    6464#include "Pasteboard.h"
    65 #include "TextCheckingHelper.h"
    6665#include "RemoveFormatCommand.h"
    6766#include "RenderBlock.h"
     
    16611660}
    16621661
     1662static 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 hunks
     1678        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 much
     1686            // 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 word
     1697                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_TIGER
     1725
     1726static 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 boundaries
     1733    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 range
     1738    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
     1748static 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 range
     1761        if (detailStartOffsetInParagraph < startOffset)
     1762            continue;
     1763       
     1764        // Skip this detail if it starts after the original search range
     1765        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   
     1785static 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 but
     1835        // 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; look
     1846        // 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
     1857static 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 after
     1926                        // 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#endif
     1983
    16631984void Editor::advanceToNextMisspelling(bool startBeforeSelection)
    16641985{
     
    16721993    VisibleSelection selection(frame()->selection()->selection());
    16731994    RefPtr<Range> spellingSearchRange(rangeOfContents(frame()->document()));
    1674     TextCheckingHelper checker(client(), spellingSearchRange);
    1675 
    16761995    bool startedWithSelection = false;
    16771996    if (selection.start().node()) {
     
    17392058    int foundOffset = 0;
    17402059    GrammarDetail grammarDetail;
    1741     String foundItem = checker.findFirstMisspellingOrBadGrammar(isGrammarCheckingEnabled(), isSpelling, foundOffset, grammarDetail);
     2060    String foundItem = findFirstMisspellingOrBadGrammarInRange(client(), spellingSearchRange.get(), isGrammarCheckingEnabled(), isSpelling, foundOffset, grammarDetail);
    17422061    if (isSpelling) {
    17432062        misspelledWord = foundItem;
     
    17492068#else
    17502069    RefPtr<Range> firstMisspellingRange;
    1751     String misspelledWord = checker.findFirstMisspelling(misspellingOffset, false, firstMisspellingRange);
     2070    String misspelledWord = findFirstMisspellingInRange(client(), spellingSearchRange.get(), misspellingOffset, false, firstMisspellingRange);
    17522071    String badGrammarPhrase;
    17532072
     
    17662085   
    17672086    if (isGrammarCheckingEnabled())
    1768         badGrammarPhrase = checker.findFirstBadGrammar(grammarDetail, grammarPhraseOffset, false);
     2087        badGrammarPhrase = findFirstBadGrammarInRange(client(), grammarSearchRange.get(), grammarDetail, grammarPhraseOffset, false);
    17692088#endif
    17702089#endif
     
    17792098#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
    17802099        grammarSearchRange = spellingSearchRange->cloneRange(ec);
    1781         foundItem = checker.findFirstMisspellingOrBadGrammar(isGrammarCheckingEnabled(), isSpelling, foundOffset, grammarDetail);
     2100        foundItem = findFirstMisspellingOrBadGrammarInRange(client(), spellingSearchRange.get(), isGrammarCheckingEnabled(), isSpelling, foundOffset, grammarDetail);
    17822101        if (isSpelling) {
    17832102            misspelledWord = foundItem;
     
    17882107        }
    17892108#else
    1790         misspelledWord = checker.findFirstMisspelling(misspellingOffset, false, firstMisspellingRange);
     2109        misspelledWord = findFirstMisspellingInRange(client(), spellingSearchRange.get(), misspellingOffset, false, firstMisspellingRange);
    17912110
    17922111#ifndef BUILDING_ON_TIGER
     
    17992118        }
    18002119        if (isGrammarCheckingEnabled())
    1801             badGrammarPhrase = checker.findFirstBadGrammar(grammarDetail, grammarPhraseOffset, false);
     2120            badGrammarPhrase = findFirstBadGrammarInRange(client(), grammarSearchRange.get(), grammarDetail, grammarPhraseOffset, false);
    18022121#endif
    18032122#endif
     
    18632182}
    18642183
     2184#ifndef BUILDING_ON_TIGER
     2185static 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 analogous
     2195    // 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 range
     2214    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 range
     2218    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:] work
     2223    // correctly; that call behaves differently based on whether the spelling panel is displaying a misspelling
     2224    // or a grammar error.
     2225    client->updateSpellingUIWithGrammarString(badGrammarPhrase, grammarDetail);
     2226   
     2227    return true;
     2228}
     2229#endif
     2230
    18652231bool Editor::isSelectionUngrammatical()
    18662232{
     
    18692235#else
    18702236    Vector<String> ignoredGuesses;
    1871     return TextCheckingHelper(client(), frame()->selection()->toNormalizedRange()).isUngrammatical(ignoredGuesses);
     2237    return isRangeUngrammatical(client(), frame()->selection()->toNormalizedRange().get(), ignoredGuesses);
    18722238#endif
    18732239}
     
    18792245#else
    18802246    Vector<String> 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);
     2247    // Ignore the result of isRangeUngrammatical; we just want the guesses, whether or not there are any
     2248    isRangeUngrammatical(client(), frame()->selection()->toNormalizedRange().get(), guesses);
    18832249    return guesses;
    18842250#endif
     
    18962262}
    18972263
     2264#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
     2265
     2266static 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
    18982326Vector<String> Editor::guessesForMisspelledOrUngrammaticalSelection(bool& misspelled, bool& ungrammatical)
    18992327{
    19002328#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
    1901     return TextCheckingHelper(client(), frame()->selection()->toNormalizedRange()).guessesForMisspelledOrUngrammaticalRange(isGrammarCheckingEnabled(), misspelled, ungrammatical);
     2329    return guessesForMisspelledOrUngrammaticalRange(client(), frame()->selection()->toNormalizedRange().get(), isGrammarCheckingEnabled(), misspelled, ungrammatical);
    19022330#else
    19032331    misspelled = isSelectionMisspelled();
     
    20762504#endif
    20772505}
    2078    
    2079 void Editor::markMisspellingsOrBadGrammar(const VisibleSelection& selection, bool checkSpelling, RefPtr<Range>& firstMisspellingRange)
     2506
     2507static 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
     2516static 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   
     2526static void markMisspellingsOrBadGrammar(Editor* editor, const VisibleSelection& selection, bool checkSpelling, RefPtr<Range>& firstMisspellingRange)
    20802527{
    20812528    // This function is called with a selection already expanded to word boundaries.
     
    20842531    // This function is used only for as-you-type checking, so if that's off we do nothing. Note that
    20852532    // grammar checking can only be on if spell checking is also on.
    2086     if (!isContinuousSpellCheckingEnabled())
     2533    if (!editor->isContinuousSpellCheckingEnabled())
    20872534        return;
    20882535   
     
    20962543        return;
    20972544
    2098     if (!isSpellCheckingEnabledInFocusedNode())
     2545    if (!editor->isSpellCheckingEnabledInFocusedNode())
    20992546        return;
    21002547
    21012548    // Get the spell checker if it is available
    2102     if (!client())
    2103         return;
    2104    
    2105     TextCheckingHelper checker(client(), searchRange);
     2549    if (!editor->client())
     2550        return;
     2551   
    21062552    if (checkSpelling)
    2107         checker.markAllMisspellings(firstMisspellingRange);
     2553        markAllMisspellingsInRange(editor->client(), searchRange.get(), firstMisspellingRange);
    21082554    else {
    21092555#ifdef BUILDING_ON_TIGER
    21102556        ASSERT_NOT_REACHED();
    21112557#else
    2112         if (isGrammarCheckingEnabled())
    2113             checker.markAllBadGrammar();
     2558        if (editor->isGrammarCheckingEnabled())
     2559            markAllBadGrammarInRange(editor->client(), searchRange.get());
    21142560#endif
    21152561    }   
     
    21312577void Editor::markMisspellings(const VisibleSelection& selection, RefPtr<Range>& firstMisspellingRange)
    21322578{
    2133     markMisspellingsOrBadGrammar(selection, true, firstMisspellingRange);
     2579    markMisspellingsOrBadGrammar(this, selection, true, firstMisspellingRange);
    21342580}
    21352581   
     
    21382584#ifndef BUILDING_ON_TIGER
    21392585    RefPtr<Range> firstMisspellingRange;
    2140     markMisspellingsOrBadGrammar(selection, false, firstMisspellingRange);
     2586    markMisspellingsOrBadGrammar(this, selection, false, firstMisspellingRange);
    21412587#else
    21422588    UNUSED_PARAM(selection);
     
    21882634    String paragraphString;
    21892635    RefPtr<Range> paragraphRange;
    2190     TextCheckingHelper checker(client(), grammarRange);
    21912636
    21922637    if (shouldMarkGrammar) {
    21932638        // The spelling range should be contained in the paragraph-aligned extension of the grammar range.
    2194         paragraphRange = checker.paragraphAlignedRange(grammarRangeStartOffset, paragraphString);
     2639        paragraphRange = paragraphAlignedRangeForRange(grammarRange, grammarRangeStartOffset, paragraphString);
    21952640        RefPtr<Range> offsetAsRange = Range::create(paragraphRange->startContainer(ec)->document(), paragraphRange->startPosition(), spellingRange->startPosition());
    21962641        spellingRangeStartOffset = TextIterator::rangeLength(offsetAsRange.get());
    21972642        grammarRangeEndOffset = grammarRangeStartOffset + TextIterator::rangeLength(grammarRange);
    21982643    } else {
    2199         paragraphRange = checker.paragraphAlignedRange(spellingRangeStartOffset, paragraphString);
     2644        paragraphRange = paragraphAlignedRangeForRange(spellingRange, spellingRangeStartOffset, paragraphString);
    22002645    }
    22012646    spellingRangeEndOffset = spellingRangeStartOffset + TextIterator::rangeLength(spellingRange);
     
    23872832    if (!shouldInsertText(replacedString, selection.get(), EditorInsertActionPasted))
    23882833        return;
    2389    
     2834       
    23902835    String paragraphString;
    23912836    int selectionOffset;
    2392     RefPtr<Range> paragraphRange = TextCheckingHelper(client(), selection).paragraphAlignedRange(selectionOffset, paragraphString);
     2837    RefPtr<Range> paragraphRange = paragraphAlignedRangeForRange(selection.get(), selectionOffset, paragraphString);
    23932838    replaceSelectionWithText(replacedString, false, false);
    23942839    RefPtr<Range> changedRange = TextIterator::subrange(paragraphRange.get(), selectionOffset, replacedString.length());
  • trunk/WebCore/editing/Editor.h

    r70847 r70970  
    405405    void writeSelectionToPasteboard(Pasteboard*);
    406406    void revealSelectionAfterEditingOperation();
    407     void markMisspellingsOrBadGrammar(const VisibleSelection&, bool checkSpelling, RefPtr<Range>& firstMisspellingRange);
    408407
    409408    void selectComposition();
Note: See TracChangeset for help on using the changeset viewer.