2011-01-05 Anders Carlsson <andersca@apple.com>
authorandersca@apple.com <andersca@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 5 Jan 2011 19:41:03 +0000 (19:41 +0000)
committerandersca@apple.com <andersca@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 5 Jan 2011 19:41:03 +0000 (19:41 +0000)
        Reviewed by Sam Weinig.

        More work on spelling
        https://bugs.webkit.org/show_bug.cgi?id=51939

        * UIProcess/API/mac/WKView.mm:
        (-[WKView validateUserInterfaceItem:]):
        Handle changeSpelling: as well.

        (-[WKView showGuessPanel:]):
        Show or hide the guess panel.

        (-[WKView checkSpelling:]):
        Pass false to advanceToNextMisspelling.

        (-[WKView changeSpelling:]):
        Call changeSpellingToWord.

        * UIProcess/TextChecker.h:
        * UIProcess/WebPageProxy.cpp:
        (WebKit::WebPageProxy::WebPageProxy):
        Initialize m_pendingLearnOrIgnoreWordMessageCount.

        (WebKit::WebPageProxy::contextMenuItemSelected):
        Handle smart toggles directly in the UI process, keep track of whether
        we're asked to learn or ignore a word.

        (WebKit::WebPageProxy::advanceToNextMisspelling):
        Pass the boolean through.

        (WebKit::WebPageProxy::changeSpellingToWord):
        Send a ChangeSpellingToWord message.

        (WebKit::WebPageProxy::learnWord):
        (WebKit::WebPageProxy::ignoreWord):
        Check that we do have a pending learn or ignore word message. Call through to
        the text checker.

        (WebKit::WebPageProxy::processDidCrash):
        Reset the m_pendingLearnOrIgnoreWordMessageCount variable.

        * UIProcess/WebPageProxy.h:
        * UIProcess/WebPageProxy.messages.in:
        Add new messages.

        * UIProcess/mac/TextCheckerMac.mm:
        (WebKit::TextChecker::learnWord):
        (WebKit::TextChecker::ignoreWord):
        Implement in terms of NSSpellChecker.

        * WebProcess/WebCoreSupport/WebEditorClient.cpp:
        (WebKit::WebEditorClient::ignoreWordInSpellDocument):
        (WebKit::WebEditorClient::learnWord):
        Send IgnoreWord and LearnWord messages.

        * WebProcess/WebCoreSupport/mac/WebEditorClientMac.mm:
        (WebKit::WebEditorClient::toggleAutomaticQuoteSubstitution):
        (WebKit::WebEditorClient::toggleAutomaticLinkDetection):
        (WebKit::WebEditorClient::toggleAutomaticDashSubstitution):
        (WebKit::WebEditorClient::toggleAutomaticTextReplacement):
        Add assertions.

        * WebProcess/WebPage/WebPage.cpp:
        (WebKit::WebPage::advanceToNextMisspelling):
        Pass the bool along to the Editor.

        (WebKit::WebPage::changeSpellingToWord):
        Replace the selected text.

        * WebProcess/WebPage/WebPage.messages.in:
        Add new ChangeSpellingToWord message and add a boolean to AdvanceToNextMisspelling.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@75086 268f45cc-cd09-0410-ab3c-d52691b4dbfc

14 files changed:
WebKit2/ChangeLog
WebKit2/UIProcess/API/mac/WKView.mm
WebKit2/UIProcess/TextChecker.h
WebKit2/UIProcess/WebPageProxy.cpp
WebKit2/UIProcess/WebPageProxy.h
WebKit2/UIProcess/WebPageProxy.messages.in
WebKit2/UIProcess/mac/TextCheckerMac.mm
WebKit2/UIProcess/qt/TextCheckerQt.cpp
WebKit2/UIProcess/win/TextCheckerWin.cpp
WebKit2/WebProcess/WebCoreSupport/WebEditorClient.cpp
WebKit2/WebProcess/WebCoreSupport/mac/WebEditorClientMac.mm
WebKit2/WebProcess/WebPage/WebPage.cpp
WebKit2/WebProcess/WebPage/WebPage.h
WebKit2/WebProcess/WebPage/WebPage.messages.in

index 147d9cc1074aff77a5525e9fea9de5e59949ffd5..de449af0957e1c2178279fbf92d9b85935219ca0 100644 (file)
@@ -1,3 +1,77 @@
+2011-01-05  Anders Carlsson  <andersca@apple.com>
+
+        Reviewed by Sam Weinig.
+
+        More work on spelling
+        https://bugs.webkit.org/show_bug.cgi?id=51939
+
+        * UIProcess/API/mac/WKView.mm:
+        (-[WKView validateUserInterfaceItem:]):
+        Handle changeSpelling: as well.
+
+        (-[WKView showGuessPanel:]):
+        Show or hide the guess panel.
+
+        (-[WKView checkSpelling:]):
+        Pass false to advanceToNextMisspelling.
+
+        (-[WKView changeSpelling:]):
+        Call changeSpellingToWord.
+
+        * UIProcess/TextChecker.h:
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::WebPageProxy):
+        Initialize m_pendingLearnOrIgnoreWordMessageCount.
+
+        (WebKit::WebPageProxy::contextMenuItemSelected):
+        Handle smart toggles directly in the UI process, keep track of whether
+        we're asked to learn or ignore a word.
+
+        (WebKit::WebPageProxy::advanceToNextMisspelling):
+        Pass the boolean through.
+
+        (WebKit::WebPageProxy::changeSpellingToWord):
+        Send a ChangeSpellingToWord message.
+
+        (WebKit::WebPageProxy::learnWord):
+        (WebKit::WebPageProxy::ignoreWord):
+        Check that we do have a pending learn or ignore word message. Call through to
+        the text checker.
+
+        (WebKit::WebPageProxy::processDidCrash):
+        Reset the m_pendingLearnOrIgnoreWordMessageCount variable.
+
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/WebPageProxy.messages.in:
+        Add new messages.
+
+        * UIProcess/mac/TextCheckerMac.mm:
+        (WebKit::TextChecker::learnWord):
+        (WebKit::TextChecker::ignoreWord):
+        Implement in terms of NSSpellChecker.
+
+        * WebProcess/WebCoreSupport/WebEditorClient.cpp:
+        (WebKit::WebEditorClient::ignoreWordInSpellDocument):
+        (WebKit::WebEditorClient::learnWord):
+        Send IgnoreWord and LearnWord messages.
+
+        * WebProcess/WebCoreSupport/mac/WebEditorClientMac.mm:
+        (WebKit::WebEditorClient::toggleAutomaticQuoteSubstitution):
+        (WebKit::WebEditorClient::toggleAutomaticLinkDetection):
+        (WebKit::WebEditorClient::toggleAutomaticDashSubstitution):
+        (WebKit::WebEditorClient::toggleAutomaticTextReplacement):
+        Add assertions.
+
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::advanceToNextMisspelling):
+        Pass the bool along to the Editor.
+
+        (WebKit::WebPage::changeSpellingToWord):
+        Replace the selected text.
+
+        * WebProcess/WebPage/WebPage.messages.in:
+        Add new ChangeSpellingToWord message and add a boolean to AdvanceToNextMisspelling.
+
 2011-01-05  Anders Carlsson  <andersca@apple.com>
 
         Reviewed by Dan Bernstein.
index e607b5421662c7db772653b94b33dd189ef3b4c7..47f26d037b7729e86dd81888f716dbd6f85fb792 100644 (file)
@@ -355,7 +355,7 @@ static NSToolbarItem *toolbarItem(id <NSValidatedUserInterfaceItem> item)
         return _data->_page->selectionState().isContentEditable;
     }
 
-    if (action == @selector(checkSpelling:))
+    if (action == @selector(checkSpelling:) || action == @selector(changeSpelling:))
         return _data->_page->selectionState().isContentEditable;
 
     if (action == @selector(toggleContinuousSpellChecking:)) {
@@ -460,12 +460,32 @@ static void speakString(WKStringRef string, WKErrorRef error, void*)
 
 - (IBAction)showGuessPanel:(id)sender
 {
-    // FIXME (WebKit2) <rdar://problem/8245958> Make Spelling/Grammar checking work in WebKit2
+    NSSpellChecker *checker = [NSSpellChecker sharedSpellChecker];
+    if (!checker) {
+        LOG_ERROR("No NSSpellChecker");
+        return;
+    }
+    
+    NSPanel *spellingPanel = [checker spellingPanel];
+    if ([spellingPanel isVisible]) {
+        [spellingPanel orderOut:sender];
+        return;
+    }
+    
+    _data->_page->advanceToNextMisspelling(true);
+    [spellingPanel orderFront:sender];
 }
 
 - (IBAction)checkSpelling:(id)sender
 {
-    _data->_page->advanceToNextMisspelling();
+    _data->_page->advanceToNextMisspelling(false);
+}
+
+- (void)changeSpelling:(id)sender
+{
+    NSString *word = [[sender selectedCell] stringValue];
+
+    _data->_page->changeSpellingToWord(word);
 }
 
 - (IBAction)toggleContinuousSpellChecking:(id)sender
index aa5b5cade1cfb2f33f1ae2d3fdfa7b9c5f79b804..2970f3e52bf407b7e3501b5980b58013c9de139a 100644 (file)
@@ -54,6 +54,8 @@ public:
     static Vector<WebCore::TextCheckingResult> checkTextOfParagraph(int64_t spellDocumentTag, const UChar* text, int length, uint64_t checkingTypes);
     static void updateSpellingUIWithMisspelledWord(const String& misspelledWord);
     static void getGuessesForWord(int64_t spellDocumentTag, const String& word, const String& context, Vector<String>& guesses);
+    static void learnWord(const String& word);
+    static void ignoreWord(int64_t spellDocumentTag, const String& word);
 };
 
 } // namespace WebKit
index ba5c1803d9d68116b1453e72654a4c2e7eb63bf6..177c3c7dfa307ca42110e3d78d2da3725743fb09 100644 (file)
@@ -35,6 +35,7 @@
 #include "PageClient.h"
 #include "StringPairVector.h"
 #include "TextChecker.h"
+#include "TextCheckerState.h"
 #include "WKContextPrivate.h"
 #include "WebBackForwardList.h"
 #include "WebBackForwardListItem.h"
@@ -114,6 +115,7 @@ WebPageProxy::WebPageProxy(WebContext* context, WebPageGroup* pageGroup, uint64_
     , m_pageID(pageID)
     , m_spellDocumentTag(0)
     , m_hasSpellDocumentTag(false)
+    , m_pendingLearnOrIgnoreWordMessageCount(0)
     , m_mainFrameHasCustomRepresentation(false)
 {
 #ifndef NDEBUG
@@ -1704,7 +1706,33 @@ void WebPageProxy::contextMenuItemSelected(const WebContextMenuItemData& item)
         m_contextMenuClient.customContextMenuItemSelected(this, item);
         return;
     }
-    
+
+#if PLATFORM(MAC)
+    if (item.action() == ContextMenuItemTagSmartQuotes) {
+        TextChecker::setAutomaticQuoteSubstitutionEnabled(!TextChecker::state().isAutomaticQuoteSubstitutionEnabled);
+        process()->updateTextCheckerState();
+        return;
+    }
+    if (item.action() == ContextMenuItemTagSmartDashes) {
+        TextChecker::setAutomaticDashSubstitutionEnabled(!TextChecker::state().isAutomaticDashSubstitutionEnabled);
+        process()->updateTextCheckerState();
+        return;
+    }
+    if (item.action() == ContextMenuItemTagSmartLinks) {
+        TextChecker::setAutomaticLinkDetectionEnabled(!TextChecker::state().isAutomaticLinkDetectionEnabled);
+        process()->updateTextCheckerState();
+        return;
+    }
+    if (item.action() == ContextMenuItemTagTextReplacement) {
+        TextChecker::setAutomaticTextReplacementEnabled(!TextChecker::state().isAutomaticTextReplacementEnabled);
+        process()->updateTextCheckerState();
+        return;
+    }
+#endif
+
+    if (item.action() == ContextMenuItemTagLearnSpelling || item.action() == ContextMenuItemTagIgnoreSpelling)
+        ++m_pendingLearnOrIgnoreWordMessageCount;
+
     process()->send(Messages::WebPage::DidSelectItemFromActiveContextMenu(item), m_pageID);
 }
 
@@ -1731,9 +1759,17 @@ void WebPageProxy::didCancelForOpenPanel()
     m_openPanelResultListener = 0;
 }
 
-void WebPageProxy::advanceToNextMisspelling()
+void WebPageProxy::advanceToNextMisspelling(bool startBeforeSelection)
 {
-    process()->send(Messages::WebPage::AdvanceToNextMisspelling(), m_pageID);
+    process()->send(Messages::WebPage::AdvanceToNextMisspelling(startBeforeSelection), m_pageID);
+}
+
+void WebPageProxy::changeSpellingToWord(const String& word)
+{
+    if (word.isEmpty())
+        return;
+
+    process()->send(Messages::WebPage::ChangeSpellingToWord(word), m_pageID);
 }
 
 void WebPageProxy::unmarkAllMisspellings()
@@ -1790,6 +1826,22 @@ void WebPageProxy::getGuessesForWord(const String& word, const String& context,
     TextChecker::getGuessesForWord(spellDocumentTag(), word, context, guesses);
 }
 
+void WebPageProxy::learnWord(const String& word)
+{
+    MESSAGE_CHECK(m_pendingLearnOrIgnoreWordMessageCount);
+    --m_pendingLearnOrIgnoreWordMessageCount;
+
+    TextChecker::learnWord(word);
+}
+
+void WebPageProxy::ignoreWord(const String& word)
+{
+    MESSAGE_CHECK(m_pendingLearnOrIgnoreWordMessageCount);
+    --m_pendingLearnOrIgnoreWordMessageCount;
+
+    TextChecker::ignoreWord(spellDocumentTag(), word);
+}
+
 // Other
 
 void WebPageProxy::takeFocus(bool direction)
@@ -1992,6 +2044,8 @@ void WebPageProxy::processDidCrash()
 
     m_estimatedProgress = 0.0;
 
+    m_pendingLearnOrIgnoreWordMessageCount = 0;
+
     m_pageClient->processDidCrash();
     m_loaderClient.processDidCrash(this);
 }
index 330af639cc6229d27db07e2aeadc3a44c207df02..2e2ef03fa0548aff3bf41cff1c90988f7c602564 100644 (file)
@@ -299,7 +299,8 @@ public:
     void findZoomableAreaForPoint(const WebCore::IntPoint&);
 #endif
 
-    void advanceToNextMisspelling();
+    void advanceToNextMisspelling(bool startBeforeSelection);
+    void changeSpellingToWord(const String& word);
     void unmarkAllMisspellings();
     void unmarkAllBadGrammar();
 
@@ -435,6 +436,8 @@ private:
     void checkTextOfParagraph(const String& text, uint64_t checkingTypes, Vector<WebCore::TextCheckingResult>& results);
     void updateSpellingUIWithMisspelledWord(const String& misspelledWord);
     void getGuessesForWord(const String& word, const String& context, Vector<String>& guesses);
+    void learnWord(const String& word);
+    void ignoreWord(const String& word);
 
     void takeFocus(bool direction);
     void setToolTip(const String&);
@@ -543,6 +546,7 @@ private:
 
     int64_t m_spellDocumentTag;
     bool m_hasSpellDocumentTag;
+    unsigned m_pendingLearnOrIgnoreWordMessageCount;
 
     bool m_mainFrameHasCustomRepresentation;
 };
index b95d6b4b6f998a54093ab25f5af3db30614fc578..91eed431c6f15dad570e98aa4d16f54174ae100e 100644 (file)
@@ -181,4 +181,6 @@ messages -> WebPageProxy {
     CheckTextOfParagraph(WTF::String text, uint64_t checkingTypes) -> (Vector<WebCore::TextCheckingResult> results)
     UpdateSpellingUIWithMisspelledWord(WTF::String misspelledWord)
     GetGuessesForWord(WTF::String word, WTF::String context) -> (Vector<WTF::String> guesses)
+    LearnWord(WTF::String word);
+    IgnoreWord(WTF::String word);
 }
index fd28a8d2da3023c0408a95f3939715fa23116c91..ccfce4a7d5f169d292186ed74af16d9299aed2e8 100644 (file)
@@ -289,4 +289,14 @@ void TextChecker::getGuessesForWord(int64_t spellDocumentTag, const String& word
         guesses.append(guess);
 }
 
+void TextChecker::learnWord(const String& word)
+{
+    [[NSSpellChecker sharedSpellChecker] learnWord:word];
+}
+
+void TextChecker::ignoreWord(int64_t spellDocumentTag, const String& word)
+{
+    [[NSSpellChecker sharedSpellChecker] ignoreWord:word inSpellDocumentWithTag:spellDocumentTag];
+}
+
 } // namespace WebKit
index 78fc9cc748ebd3fc41c6ba5a26dfee304407473d..9ab629765b2ffd04bb3c2342420f17672f443c92 100644 (file)
@@ -85,4 +85,14 @@ void TextChecker::getGuessesForWord(int64_t spellDocumentTag, const String& word
     notImplemented();
 }
 
+void TextChecker::learnWord(const String& word)
+{
+    notImplemented();
+}
+
+void TextChecker::ignoreWord(int64_t spellDocumentTag, const String& word)
+{
+    notImplemented();
+}
+
 } // namespace WebKit
index 95ab2afa0ea8fda5e4e8dd57efd0211d83423252..3c4b1eb2b6f23e7c33825ed6ab105f4f39f1c32f 100644 (file)
@@ -85,4 +85,14 @@ void TextChecker::getGuessesForWord(int64_t spellDocumentTag, const String& word
     notImplemented();
 }
 
+void TextChecker::learnWord(const String& word)
+{
+    notImplemented();
+}
+
+void TextChecker::ignoreWord(int64_t spellDocumentTag, const String& word)
+{
+    notImplemented();
+}
+
 } // namespace WebKit
index 3d7c5a934efe7a92ed25d4ccb3213ff21caab41d..cf34674b834c1269430492ef7bbc7b6cc600714a 100644 (file)
@@ -364,14 +364,14 @@ void WebEditorClient::textWillBeDeletedInTextField(Element* element)
     m_page->injectedBundleFormClient().shouldPerformActionInTextField(m_page, static_cast<HTMLInputElement*>(element), WKInputFieldActionTypeInsertDelete, webFrame);
 }
 
-void WebEditorClient::ignoreWordInSpellDocument(const String&)
+void WebEditorClient::ignoreWordInSpellDocument(const String& word)
 {
-    notImplemented();
+    m_page->send(Messages::WebPageProxy::IgnoreWord(word));
 }
 
-void WebEditorClient::learnWord(const String&)
+void WebEditorClient::learnWord(const String& word)
 {
-    notImplemented();
+    m_page->send(Messages::WebPageProxy::LearnWord(word));
 }
 
 void WebEditorClient::checkSpellingOfString(const UChar*, int, int*, int*)
index f3b7c0ba27feabeeb00af92647add06ef8ecee2b..2c4110dc08d6f812dfc37b6ecc50936300e97348 100644 (file)
@@ -169,7 +169,8 @@ bool WebEditorClient::isAutomaticQuoteSubstitutionEnabled()
 
 void WebEditorClient::toggleAutomaticQuoteSubstitution()
 {
-    notImplemented();
+    // This should be handled in the UI process.
+    ASSERT_NOT_REACHED();
 }
 
 bool WebEditorClient::isAutomaticLinkDetectionEnabled()
@@ -179,7 +180,8 @@ bool WebEditorClient::isAutomaticLinkDetectionEnabled()
 
 void WebEditorClient::toggleAutomaticLinkDetection()
 {
-    notImplemented();
+    // This should be handled in the UI process.
+    ASSERT_NOT_REACHED();
 }
 
 bool WebEditorClient::isAutomaticDashSubstitutionEnabled()
@@ -189,7 +191,8 @@ bool WebEditorClient::isAutomaticDashSubstitutionEnabled()
 
 void WebEditorClient::toggleAutomaticDashSubstitution()
 {
-    notImplemented();
+    // This should be handled in the UI process.
+    ASSERT_NOT_REACHED();
 }
 
 bool WebEditorClient::isAutomaticTextReplacementEnabled()
@@ -199,7 +202,8 @@ bool WebEditorClient::isAutomaticTextReplacementEnabled()
 
 void WebEditorClient::toggleAutomaticTextReplacement()
 {
-    notImplemented();
+    // This should be handled in the UI process.
+    ASSERT_NOT_REACHED();
 }
 
 bool WebEditorClient::isAutomaticSpellingCorrectionEnabled()
index f636ee2710822a72c07d7438a94a43810a1222a3..3841185d6f4f3225976663aca6c96115b38c5ebb 100644 (file)
@@ -62,6 +62,7 @@
 #include <WebCore/ArchiveResource.h>
 #include <WebCore/Chrome.h>
 #include <WebCore/ContextMenuController.h>
+#include <WebCore/DocumentFragment.h>
 #include <WebCore/DocumentLoader.h>
 #include <WebCore/DocumentMarkerController.h>
 #include <WebCore/EventHandler.h>
 #include <WebCore/Page.h>
 #include <WebCore/PlatformKeyboardEvent.h>
 #include <WebCore/RenderTreeAsText.h>
+#include <WebCore/ReplaceSelectionCommand.h>
 #include <WebCore/ResourceRequest.h>
 #include <WebCore/Settings.h>
 #include <WebCore/SharedBuffer.h>
 #include <WebCore/SubstituteData.h>
 #include <WebCore/TextIterator.h>
+#include <WebCore/markup.h>
 #include <runtime/JSLock.h>
 #include <runtime/JSValue.h>
 
@@ -1256,10 +1259,21 @@ void WebPage::didCancelForOpenPanel()
     m_activeOpenPanelResultListener = 0;
 }
 
-void WebPage::advanceToNextMisspelling()
+void WebPage::advanceToNextMisspelling(bool startBeforeSelection)
 {
-    if (Frame* frame = m_page->focusController()->focusedOrMainFrame())
-        frame->editor()->advanceToNextMisspelling();
+    Frame* frame = m_page->focusController()->focusedOrMainFrame();
+    frame->editor()->advanceToNextMisspelling(startBeforeSelection);
+}
+
+void WebPage::changeSpellingToWord(const String& word)
+{
+    Frame* frame = m_page->focusController()->focusedOrMainFrame();
+    if (frame->selection()->isNone())
+        return;
+
+    RefPtr<DocumentFragment> textFragment = createFragmentFromText(frame->selection()->toNormalizedRange().get(), word);
+    applyCommand(ReplaceSelectionCommand::create(frame->document(), textFragment.release(), true, false, true));
+    frame->selection()->revealSelection(ScrollAlignment::alignToEdgeIfNeeded);
 }
 
 void WebPage::unmarkAllMisspellings()
index 12633f0809032c3adda7a7466a9ca6e1133315a4..864d60f24f8d5a2ffe21c008efc42d6d5e952e0a 100644 (file)
@@ -374,7 +374,8 @@ private:
     void didChooseFilesForOpenPanel(const Vector<String>&);
     void didCancelForOpenPanel();
 
-    void advanceToNextMisspelling();
+    void advanceToNextMisspelling(bool startBeforeSelection);
+    void changeSpellingToWord(const String& word);
     void unmarkAllMisspellings();
     void unmarkAllBadGrammar();
 
index baa5ae8a915154304f8f2a61b96ebcfb71db989a..cf1fdc6bd6854ed314ebf88bcf48f015434a79c8 100644 (file)
@@ -101,7 +101,8 @@ messages -> WebPage {
     DidCancelForOpenPanel()
 
     # Speling and grammer.
-    AdvanceToNextMisspelling()
+    AdvanceToNextMisspelling(bool startBeforeSelection)
+    ChangeSpellingToWord(WTF::String word)
     UnmarkAllMisspellings()
     UnmarkAllBadGrammar()