[GTK][WK2] Add support for IME Composition
authormrobinson@webkit.org <mrobinson@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 28 Dec 2012 20:32:06 +0000 (20:32 +0000)
committermrobinson@webkit.org <mrobinson@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 28 Dec 2012 20:32:06 +0000 (20:32 +0000)
https://bugs.webkit.org/show_bug.cgi?id=65093

Reviewed by Carlos Garcia Campos.

Source/WebCore:

No new tests. The GtkInputMethodFilter is covered by unit tests in TestWebKitAPI.
Doing functional tests for this behavior is much more complex.

* platform/gtk/GtkInputMethodFilter.cpp:
(WebCore::GtkInputMethodFilter::sendCompositionAndPreeditWithFakeKeyEvents): Now
pass along whether or not an event was faked.
* platform/gtk/GtkInputMethodFilter.h: Ditto.

Source/WebKit/gtk:

Update the method signatures for concrete WebKit1 implementation of
the GtkInputMethodFilter.

* WebCoreSupport/WebViewInputMethodFilter.cpp:
(WebKit::WebViewInputMethodFilter::sendSimpleKeyEvent):
(WebKit::WebViewInputMethodFilter::sendKeyEventWithCompositionResults):
* WebCoreSupport/WebViewInputMethodFilter.h:
(WebViewInputMethodFilter):

Source/WebKit2:

Add a WebKit2 implementation of the GtkInputMethodFilter and provide
the necessary plumbing to pass composition information along with
input method events.

* GNUmakefile.list.am: Add new files to the source list.
* Shared/EditorState.cpp: The cursorRect is now passed for GTK+ as well as
Qt, so update the encode and decode methods to pass that along.
* Shared/EditorState.h: Add the cursorRect member for GTK+ as well.
* Shared/NativeWebKeyboardEvent.h:
(NativeWebKeyboardEvent): Keyboard events should also have knowledge of
the compositionResults and whether or not the event was faked for composition
purposes.
* Shared/gtk/NativeWebKeyboardEventGtk.cpp: Ditto.
* Shared/gtk/WebEventFactory.cpp:
(WebKit::WebEventFactory::createWebKeyboardEvent): Copy the logic of PlatformKeyEvent,
for properly setting the windows key code and the event text from the composition
results.
* Shared/gtk/WebEventFactory.h: The createWebKeyboardEvent factory now takes a
CompositionResults argument.
* UIProcess/API/gtk/PageClientImpl.cpp:
(WebKit::PageClientImpl::doneWithKeyEvent): Don't forward keyboard events that
were faked for composition reasons. These events originated from WebKit and should
never be passed to parent classes.
(WebKit::PageClientImpl::updateTextInputState): Plumb through the updateTextInputState
method to the WebViewBase.
* UIProcess/API/gtk/PageClientImpl.h:
(PageClientImpl): Add a updateTextInputState method.
* UIProcess/API/gtk/WebKitWebViewBase.cpp:
(_WebKitWebViewBasePrivate): Instead of having an input method context as a member
keep a WebViewBaseInputMethodFilter.
(webkitWebViewBaseRealize): Set the filter widget when the WebViewBase is realized.
(webkit_web_view_base_init): No longer create a input method context during init.
(webkitWebViewBaseFocusInEvent): Pass along focus in events to the filter.
(webkitWebViewBaseFocusOutEvent): Pass along focus out events to the filter.
(webkitWebViewBaseKeyPressEvent): Instead of passing key presses directly to the WebProcess,
filter them through the input method filter.
(webkitWebViewBaseKeyReleaseEvent): Ditto.
(webkitWebViewBaseButtonPressEvent): Notify the input method filter about button press events.
(webkitWebViewBaseGetIMContext): The input method filter owns the input method now.
(webkitWebViewBaseSetInputMethodState): Add a bit of plumbing for the PageClient.
(webkitWebViewBaseUpdateTextInputState): Ditto.
* UIProcess/API/gtk/WebKitWebViewBasePrivate.h: Add plumbing declarations.
* UIProcess/API/gtk/WebViewBaseInputMethodFilter.cpp: Added. An implementation of GtkInputMethodFilter for WebKit2.
* UIProcess/API/gtk/WebViewBaseInputMethodFilter.h: Copied from Source/WebKit/gtk/WebCoreSupport/WebViewInputMethodFilter.h.
* UIProcess/PageClient.h:
(PageClient): updateInputMethod state is now for both Qt and GTK+.
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::editorStateChanged): Pass the editor state for GTK+ as well as Qt.
(WebKit::WebPageProxy::setComposition): Moved this method from WebPageProxyQt as it's used for GTK+ now as well.
(WebKit::WebPageProxy::confirmComposition): Ditto.
(WebKit::WebPageProxy::cancelComposition): Ditto.
* UIProcess/WebPageProxy.h:
(WebPageProxy): The setInputMethodState message is for GTK+ as well as Qt now.
* UIProcess/WebPageProxy.messages.in: Ditto.
* UIProcess/gtk/WebPageProxyGtk.cpp:
(WebKit::WebPageProxy::setInputMethodState): Ditto.
* UIProcess/qt/WebPageProxyQt.cpp: Move some methods to the platform-independent file.
* WebProcess/WebCoreSupport/gtk/WebEditorClientGtk.cpp: More closely match the WebKit1
logic for dealing with key events so that composition events will be handled properly.
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::editorState): Properly pass the cursorRect for GTK+.
(WebKit::targetFrameForEditing): Moved from the Qt file, because its used by GTK+ as well. They
now pass along the updated EditorState as well, just like the Mac versions.
(WebKit::WebPage::confirmComposition): Ditto.
(WebKit::WebPage::setComposition): Ditto.
(WebKit::WebPage::cancelComposition): Ditto.
* WebProcess/WebPage/WebPage.h: The above messages are now for GTK+ as well as Qt.
* WebProcess/WebPage/WebPage.messages.in: Ditto.
* WebProcess/WebPage/qt/WebPageQt.cpp: Moved some methods to the platform-independent file.

Tools:

Update unit tests for GtkInputMethodFilter to note whether or not an event
was a fake event synthesized for composition purposes. This is now used
for WebKit2.

* TestWebKitAPI/Tests/gtk/InputMethodFilter.cpp:
(TestWebKitAPI::TestInputMethodFilter::sendSimpleKeyEvent):
(TestWebKitAPI::TestInputMethodFilter::sendKeyEventWithCompositionResults):
(TestWebKitAPI::TEST):
* gtk/generate-gtkdoc:
(get_webkit2_options): Skip new files in the WebKit2 source directory for documentation
generation.

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

34 files changed:
Source/WebCore/ChangeLog
Source/WebCore/platform/gtk/GtkInputMethodFilter.cpp
Source/WebCore/platform/gtk/GtkInputMethodFilter.h
Source/WebKit/gtk/ChangeLog
Source/WebKit/gtk/WebCoreSupport/WebViewInputMethodFilter.cpp
Source/WebKit/gtk/WebCoreSupport/WebViewInputMethodFilter.h
Source/WebKit2/ChangeLog
Source/WebKit2/GNUmakefile.list.am
Source/WebKit2/Shared/EditorState.cpp
Source/WebKit2/Shared/EditorState.h
Source/WebKit2/Shared/NativeWebKeyboardEvent.h
Source/WebKit2/Shared/gtk/NativeWebKeyboardEventGtk.cpp
Source/WebKit2/Shared/gtk/WebEventFactory.cpp
Source/WebKit2/Shared/gtk/WebEventFactory.h
Source/WebKit2/UIProcess/API/gtk/PageClientImpl.cpp
Source/WebKit2/UIProcess/API/gtk/PageClientImpl.h
Source/WebKit2/UIProcess/API/gtk/WebKitWebViewBase.cpp
Source/WebKit2/UIProcess/API/gtk/WebKitWebViewBasePrivate.h
Source/WebKit2/UIProcess/API/gtk/WebViewBaseInputMethodFilter.cpp [new file with mode: 0644]
Source/WebKit2/UIProcess/API/gtk/WebViewBaseInputMethodFilter.h [new file with mode: 0644]
Source/WebKit2/UIProcess/PageClient.h
Source/WebKit2/UIProcess/WebPageProxy.cpp
Source/WebKit2/UIProcess/WebPageProxy.h
Source/WebKit2/UIProcess/WebPageProxy.messages.in
Source/WebKit2/UIProcess/gtk/WebPageProxyGtk.cpp
Source/WebKit2/UIProcess/qt/WebPageProxyQt.cpp
Source/WebKit2/WebProcess/WebCoreSupport/gtk/WebEditorClientGtk.cpp
Source/WebKit2/WebProcess/WebPage/WebPage.cpp
Source/WebKit2/WebProcess/WebPage/WebPage.h
Source/WebKit2/WebProcess/WebPage/WebPage.messages.in
Source/WebKit2/WebProcess/WebPage/qt/WebPageQt.cpp
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/gtk/InputMethodFilter.cpp
Tools/gtk/generate-gtkdoc

index 441c22f..584fdec 100644 (file)
@@ -1,3 +1,18 @@
+2012-12-28  Martin Robinson  <mrobinson@igalia.com>
+
+        [GTK][WK2] Add support for IME Composition
+        https://bugs.webkit.org/show_bug.cgi?id=65093
+
+        Reviewed by Carlos Garcia Campos.
+
+        No new tests. The GtkInputMethodFilter is covered by unit tests in TestWebKitAPI.
+        Doing functional tests for this behavior is much more complex.
+
+        * platform/gtk/GtkInputMethodFilter.cpp:
+        (WebCore::GtkInputMethodFilter::sendCompositionAndPreeditWithFakeKeyEvents): Now
+        pass along whether or not an event was faked.
+        * platform/gtk/GtkInputMethodFilter.h: Ditto.
+
 2012-12-27  Emil A Eklund  <eae@chromium.org>
 
         REGRESSION (r138196): Regions with text-overflow: ellipsis; are being ellipsized unnecessarily
index 8696ef3..b1f4038 100644 (file)
@@ -272,13 +272,13 @@ void GtkInputMethodFilter::sendCompositionAndPreeditWithFakeKeyEvents(ResultsToS
     GOwnPtr<GdkEvent> event(gdk_event_new(GDK_KEY_PRESS));
     event->key.time = GDK_CURRENT_TIME;
     event->key.keyval = gCompositionEventKeyCode;
-    sendKeyEventWithCompositionResults(&event->key, resultsToSend);
+    sendKeyEventWithCompositionResults(&event->key, resultsToSend, EventFaked);
 
     m_confirmedComposition = String();
     m_composingTextCurrently = false;
 
     event->type = GDK_KEY_RELEASE;
-    sendSimpleKeyEvent(&event->key);
+    sendSimpleKeyEvent(&event->key, String(), EventFaked);
     m_justSentFakeKeyUp = true;
 }
 
index 97a7736..0e48253 100644 (file)
@@ -17,6 +17,9 @@
  * Boston, MA 02110-1301, USA.
  */
 
+#ifndef GtkInputMethodFilter_h
+#define GtkInputMethodFilter_h
+
 #include "GRefPtrGtk.h"
 #include "IntRect.h"
 #include <gdk/gdk.h>
@@ -51,6 +54,11 @@ public:
 
     GtkIMContext* context() { return m_context.get(); }
 
+    enum EventFakedForComposition {
+        EventFaked,
+        EventNotFaked
+    };
+
 protected:
     enum ResultsToSend {
         Preedit = 1 << 1,
@@ -60,8 +68,8 @@ protected:
 
     void setWidget(GtkWidget*);
     virtual bool canEdit() = 0;
-    virtual bool sendSimpleKeyEvent(GdkEventKey*, WTF::String eventString = String()) = 0;
-    virtual bool sendKeyEventWithCompositionResults(GdkEventKey*, ResultsToSend = PreeditAndComposition) = 0;
+    virtual bool sendSimpleKeyEvent(GdkEventKey*, WTF::String eventString = String(), EventFakedForComposition = EventNotFaked) = 0;
+    virtual bool sendKeyEventWithCompositionResults(GdkEventKey*, ResultsToSend = PreeditAndComposition, EventFakedForComposition = EventNotFaked) = 0;
     virtual void confirmCompositionText(String composition) = 0;
     virtual void confirmCurrentComposition() = 0;
     virtual void cancelCurrentComposition() = 0;
@@ -88,3 +96,4 @@ private:
 
 } // namespace WebCore
 
+#endif // GtkInputMethodFilter_h
index c29e31f..b7a7ecd 100644 (file)
@@ -1,3 +1,19 @@
+2012-12-28  Martin Robinson  <mrobinson@igalia.com>
+
+        [GTK][WK2] Add support for IME Composition
+        https://bugs.webkit.org/show_bug.cgi?id=65093
+
+        Reviewed by Carlos Garcia Campos.
+
+        Update the method signatures for concrete WebKit1 implementation of
+        the GtkInputMethodFilter.
+
+        * WebCoreSupport/WebViewInputMethodFilter.cpp:
+        (WebKit::WebViewInputMethodFilter::sendSimpleKeyEvent):
+        (WebKit::WebViewInputMethodFilter::sendKeyEventWithCompositionResults):
+        * WebCoreSupport/WebViewInputMethodFilter.h:
+        (WebViewInputMethodFilter):
+
 2012-12-27  ChangSeok Oh  <shivamidow@gmail.com>
 
         [GTK] invalid use of incomplete type WebCore::ResourceResponse in webkitwebviewprivate.h
index 2700d4a..2cca214 100644 (file)
@@ -52,13 +52,13 @@ bool WebViewInputMethodFilter::canEdit()
     return frame && frame->editor()->canEdit();
 }
 
-bool WebViewInputMethodFilter::sendSimpleKeyEvent(GdkEventKey* event, WTF::String simpleString)
+bool WebViewInputMethodFilter::sendSimpleKeyEvent(GdkEventKey* event, WTF::String simpleString, EventFakedForComposition)
 {
     PlatformKeyboardEvent platformEvent(event, CompositionResults(simpleString));
     return focusedOrMainFrame()->eventHandler()->keyEvent(platformEvent);
 }
 
-bool WebViewInputMethodFilter::sendKeyEventWithCompositionResults(GdkEventKey* event, ResultsToSend resultsToSend)
+bool WebViewInputMethodFilter::sendKeyEventWithCompositionResults(GdkEventKey* event, ResultsToSend resultsToSend, EventFakedForComposition)
 {
     PlatformKeyboardEvent platformEvent(event, CompositionResults(CompositionResults::WillSendCompositionResultsSoon));
     if (!focusedOrMainFrame()->eventHandler()->keyEvent(platformEvent))
index fd70edb..b077ae0 100644 (file)
@@ -35,8 +35,8 @@ public:
     void setWebView(WebKitWebView*);
 
 protected:
-    virtual bool sendSimpleKeyEvent(GdkEventKey*, WTF::String eventString);
-    virtual bool sendKeyEventWithCompositionResults(GdkEventKey*, ResultsToSend);
+    virtual bool sendSimpleKeyEvent(GdkEventKey*, WTF::String eventString, EventFakedForComposition);
+    virtual bool sendKeyEventWithCompositionResults(GdkEventKey*, ResultsToSend, EventFakedForComposition);
     virtual bool canEdit();
     virtual void confirmCompositionText(String);
     virtual void confirmCurrentComposition();
index 0d9da0a..a4f4a1b 100644 (file)
@@ -1,3 +1,80 @@
+2012-12-28  Martin Robinson  <mrobinson@igalia.com>
+
+        [GTK][WK2] Add support for IME Composition
+        https://bugs.webkit.org/show_bug.cgi?id=65093
+
+        Reviewed by Carlos Garcia Campos.
+
+        Add a WebKit2 implementation of the GtkInputMethodFilter and provide
+        the necessary plumbing to pass composition information along with
+        input method events.
+
+        * GNUmakefile.list.am: Add new files to the source list.
+        * Shared/EditorState.cpp: The cursorRect is now passed for GTK+ as well as
+        Qt, so update the encode and decode methods to pass that along.
+        * Shared/EditorState.h: Add the cursorRect member for GTK+ as well.
+        * Shared/NativeWebKeyboardEvent.h:
+        (NativeWebKeyboardEvent): Keyboard events should also have knowledge of
+        the compositionResults and whether or not the event was faked for composition
+        purposes.
+        * Shared/gtk/NativeWebKeyboardEventGtk.cpp: Ditto.
+        * Shared/gtk/WebEventFactory.cpp:
+        (WebKit::WebEventFactory::createWebKeyboardEvent): Copy the logic of PlatformKeyEvent,
+        for properly setting the windows key code and the event text from the composition
+        results.
+        * Shared/gtk/WebEventFactory.h: The createWebKeyboardEvent factory now takes a
+        CompositionResults argument.
+        * UIProcess/API/gtk/PageClientImpl.cpp:
+        (WebKit::PageClientImpl::doneWithKeyEvent): Don't forward keyboard events that
+        were faked for composition reasons. These events originated from WebKit and should
+        never be passed to parent classes.
+        (WebKit::PageClientImpl::updateTextInputState): Plumb through the updateTextInputState
+        method to the WebViewBase.
+        * UIProcess/API/gtk/PageClientImpl.h:
+        (PageClientImpl): Add a updateTextInputState method.
+        * UIProcess/API/gtk/WebKitWebViewBase.cpp: 
+        (_WebKitWebViewBasePrivate): Instead of having an input method context as a member
+        keep a WebViewBaseInputMethodFilter.
+        (webkitWebViewBaseRealize): Set the filter widget when the WebViewBase is realized.
+        (webkit_web_view_base_init): No longer create a input method context during init.
+        (webkitWebViewBaseFocusInEvent): Pass along focus in events to the filter.
+        (webkitWebViewBaseFocusOutEvent): Pass along focus out events to the filter.
+        (webkitWebViewBaseKeyPressEvent): Instead of passing key presses directly to the WebProcess,
+        filter them through the input method filter.
+        (webkitWebViewBaseKeyReleaseEvent): Ditto.
+        (webkitWebViewBaseButtonPressEvent): Notify the input method filter about button press events.
+        (webkitWebViewBaseGetIMContext): The input method filter owns the input method now.
+        (webkitWebViewBaseSetInputMethodState): Add a bit of plumbing for the PageClient.
+        (webkitWebViewBaseUpdateTextInputState): Ditto.
+        * UIProcess/API/gtk/WebKitWebViewBasePrivate.h: Add plumbing declarations.
+        * UIProcess/API/gtk/WebViewBaseInputMethodFilter.cpp: Added. An implementation of GtkInputMethodFilter for WebKit2.
+        * UIProcess/API/gtk/WebViewBaseInputMethodFilter.h: Copied from Source/WebKit/gtk/WebCoreSupport/WebViewInputMethodFilter.h.
+        * UIProcess/PageClient.h:
+        (PageClient): updateInputMethod state is now for both Qt and GTK+.
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::editorStateChanged): Pass the editor state for GTK+ as well as Qt.
+        (WebKit::WebPageProxy::setComposition): Moved this method from WebPageProxyQt as it's used for GTK+ now as well.
+        (WebKit::WebPageProxy::confirmComposition): Ditto.
+        (WebKit::WebPageProxy::cancelComposition): Ditto.
+        * UIProcess/WebPageProxy.h:
+        (WebPageProxy): The setInputMethodState message is for GTK+ as well as Qt now.
+        * UIProcess/WebPageProxy.messages.in: Ditto.
+        * UIProcess/gtk/WebPageProxyGtk.cpp:
+        (WebKit::WebPageProxy::setInputMethodState): Ditto.
+        * UIProcess/qt/WebPageProxyQt.cpp: Move some methods to the platform-independent file.
+        * WebProcess/WebCoreSupport/gtk/WebEditorClientGtk.cpp: More closely match the WebKit1
+        logic for dealing with key events so that composition events will be handled properly.
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::editorState): Properly pass the cursorRect for GTK+.
+        (WebKit::targetFrameForEditing): Moved from the Qt file, because its used by GTK+ as well. They
+        now pass along the updated EditorState as well, just like the Mac versions.
+        (WebKit::WebPage::confirmComposition): Ditto.
+        (WebKit::WebPage::setComposition): Ditto.
+        (WebKit::WebPage::cancelComposition): Ditto.
+        * WebProcess/WebPage/WebPage.h: The above messages are now for GTK+ as well as Qt.
+        * WebProcess/WebPage/WebPage.messages.in: Ditto.
+        * WebProcess/WebPage/qt/WebPageQt.cpp: Moved some methods to the platform-independent file.
+
 2012-12-28  Sam Weinig  <sam@webkit.org>
 
         Appease the Windows Gods.
index 78c6b2a..c3d34e6 100644 (file)
@@ -763,6 +763,8 @@ webkit2_sources += \
        Source/WebKit2/UIProcess/API/gtk/WebKitWindowProperties.cpp \
        Source/WebKit2/UIProcess/API/gtk/WebKitWindowProperties.h \
        Source/WebKit2/UIProcess/API/gtk/WebKitWindowPropertiesPrivate.h \
+       Source/WebKit2/UIProcess/API/gtk/WebViewBaseInputMethodFilter.h \
+       Source/WebKit2/UIProcess/API/gtk/WebViewBaseInputMethodFilter.cpp \
        Source/WebKit2/UIProcess/API/gtk/webkit2.h \
        Source/WebKit2/UIProcess/Authentication/AuthenticationChallengeProxy.cpp \
        Source/WebKit2/UIProcess/Authentication/AuthenticationChallengeProxy.h \
index f7bde2a..c5c68d8 100644 (file)
@@ -45,12 +45,15 @@ void EditorState::encode(CoreIPC::ArgumentEncoder& encoder) const
     encoder << cursorPosition;
     encoder << anchorPosition;
     encoder << editorRect;
-    encoder << cursorRect;
     encoder << compositionRect;
     encoder << inputMethodHints;
     encoder << selectedText;
     encoder << surroundingText;
 #endif
+
+#if PLATFORM(QT) || PLATFORM(GTK)
+    encoder << cursorRect;
+#endif
 }
 
 bool EditorState::decode(CoreIPC::ArgumentDecoder* decoder, EditorState& result)
@@ -86,9 +89,6 @@ bool EditorState::decode(CoreIPC::ArgumentDecoder* decoder, EditorState& result)
     if (!decoder->decode(result.editorRect))
         return false;
 
-    if (!decoder->decode(result.cursorRect))
-        return false;
-
     if (!decoder->decode(result.compositionRect))
         return false;
 
@@ -102,6 +102,11 @@ bool EditorState::decode(CoreIPC::ArgumentDecoder* decoder, EditorState& result)
         return false;
 #endif
 
+#if PLATFORM(QT) || PLATFORM(GTK)
+    if (!decoder->decode(result.cursorRect))
+        return false;
+#endif
+
     return true;
 }
 
index 06ea087..642dea7 100644 (file)
@@ -65,7 +65,6 @@ struct EditorState {
     unsigned anchorPosition;
 
     WebCore::IntRect editorRect;
-    WebCore::IntRect cursorRect;
     WebCore::IntRect compositionRect;
 
     uint64_t inputMethodHints;
@@ -74,6 +73,10 @@ struct EditorState {
     WTF::String surroundingText;
 #endif
 
+#if PLATFORM(QT) || PLATFORM(GTK)
+    WebCore::IntRect cursorRect;
+#endif
+
     void encode(CoreIPC::ArgumentEncoder&) const;
     static bool decode(CoreIPC::ArgumentDecoder*, EditorState&);
 };
index ff54eda..efb025a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2010 Apple Inc. All rights reserved.
  * Portions Copyright (c) 2010 Motorola Mobility, Inc.  All rights reserved.
- * Copyright (C) 2011 Igalia S.L
+ * Copyright (C) 2011, 2012 Igalia S.L
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -37,6 +37,8 @@ OBJC_CLASS NSView;
 #include <QKeyEvent>
 #elif PLATFORM(GTK)
 #include <GOwnPtrGtk.h>
+#include <WebCore/CompositionResults.h>
+#include <WebCore/GtkInputMethodFilter.h>
 typedef union _GdkEvent GdkEvent;
 #elif PLATFORM(EFL)
 #include <Evas.h>
@@ -54,7 +56,7 @@ public:
     explicit NativeWebKeyboardEvent(QKeyEvent*);
 #elif PLATFORM(GTK)
     NativeWebKeyboardEvent(const NativeWebKeyboardEvent&);
-    NativeWebKeyboardEvent(GdkEvent*);
+    NativeWebKeyboardEvent(GdkEvent*, const WebCore::CompositionResults&, WebCore::GtkInputMethodFilter::EventFakedForComposition);
 #elif PLATFORM(EFL)
     NativeWebKeyboardEvent(const Evas_Event_Key_Down*, bool);
     NativeWebKeyboardEvent(const Evas_Event_Key_Up*);
@@ -68,6 +70,8 @@ public:
     const QKeyEvent* nativeEvent() const { return &m_nativeEvent; }
 #elif PLATFORM(GTK)
     GdkEvent* nativeEvent() const { return m_nativeEvent.get(); }
+    const WebCore::CompositionResults& compositionResults() const  { return m_compositionResults; }
+    bool isFakeEventForComposition() const { return m_fakeEventForComposition; }
 #elif PLATFORM(EFL)
     const void* nativeEvent() const { return m_nativeEvent; }
     bool isFiltered() const { return m_isFiltered; }
@@ -82,6 +86,8 @@ private:
     QKeyEvent m_nativeEvent;
 #elif PLATFORM(GTK)
     GOwnPtr<GdkEvent> m_nativeEvent;
+    WebCore::CompositionResults m_compositionResults;
+    bool m_fakeEventForComposition;
 #elif PLATFORM(EFL)
     const void* m_nativeEvent;
     bool m_isFiltered;
index 0ddb124..424e0b3 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2010 Apple Inc. All rights reserved.
  * Portions Copyright (c) 2010 Motorola Mobility, Inc.  All rights reserved.
- * Copyright (C) 2011 Igalia S.L
+ * Copyright (C) 2011, 2012 Igalia S.L
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #include "WebEventFactory.h"
 #include <gdk/gdk.h>
 
+using namespace WebCore;
+
 namespace WebKit {
 
-NativeWebKeyboardEvent::NativeWebKeyboardEvent(GdkEvent* event)
-    : WebKeyboardEvent(WebEventFactory::createWebKeyboardEvent(event))
+NativeWebKeyboardEvent::NativeWebKeyboardEvent(GdkEvent* event, const WebCore::CompositionResults& compositionResults, GtkInputMethodFilter::EventFakedForComposition faked)
+    : WebKeyboardEvent(WebEventFactory::createWebKeyboardEvent(event, compositionResults))
     , m_nativeEvent(gdk_event_copy(event))
+    , m_compositionResults(compositionResults)
+    , m_fakeEventForComposition(faked == GtkInputMethodFilter::EventFaked)
 {
 }
 
 NativeWebKeyboardEvent::NativeWebKeyboardEvent(const NativeWebKeyboardEvent& event)
-    : WebKeyboardEvent(WebEventFactory::createWebKeyboardEvent(event.nativeEvent()))
+    : WebKeyboardEvent(WebEventFactory::createWebKeyboardEvent(event.nativeEvent(), event.compositionResults()))
     , m_nativeEvent(gdk_event_copy(event.nativeEvent()))
+    , m_compositionResults(event.compositionResults())
+    , m_fakeEventForComposition(event.isFakeEventForComposition())
 {
 }
 
index 687957d..2c73dc7 100644 (file)
@@ -180,17 +180,24 @@ WebWheelEvent WebEventFactory::createWebWheelEvent(const GdkEvent* event)
                          gdk_event_get_time(event));
 }
 
-WebKeyboardEvent WebEventFactory::createWebKeyboardEvent(const GdkEvent* event)
+WebKeyboardEvent WebEventFactory::createWebKeyboardEvent(const GdkEvent* event, const WebCore::CompositionResults& compositionResults)
 {
+    unsigned int keyValue = event->key.keyval;
+    String text = compositionResults.simpleString.length() ?
+         compositionResults.simpleString : PlatformKeyboardEvent::singleCharacterString(keyValue);
+
+    int windowsVirtualKeyCode = compositionResults.compositionUpdated() ?
+         VK_PROCESSKEY : PlatformKeyboardEvent::windowsKeyCodeForGdkKeyCode(event->key.keyval);
+
     return WebKeyboardEvent((event->type == GDK_KEY_RELEASE) ? WebEvent::KeyUp : WebEvent::KeyDown,
-                            PlatformKeyboardEvent::singleCharacterString(event->key.keyval),
-                            PlatformKeyboardEvent::singleCharacterString(event->key.keyval),
-                            PlatformKeyboardEvent::keyIdentifierForGdkKeyCode(event->key.keyval),
-                            PlatformKeyboardEvent::windowsKeyCodeForGdkKeyCode(event->key.keyval),
-                            static_cast<int>(event->key.keyval),
+                            text,
+                            text,
+                            PlatformKeyboardEvent::keyIdentifierForGdkKeyCode(keyValue),
+                            windowsVirtualKeyCode,
+                            static_cast<int>(keyValue),
                             0 /* macCharCode */,
                             false /* isAutoRepeat */,
-                            isGdkKeyCodeFromKeyPad(event->key.keyval),
+                            isGdkKeyCodeFromKeyPad(keyValue),
                             false /* isSystemKey */,
                             modifiersForEvent(event),
                             gdk_event_get_time(event));
index 097be08..085815c 100644 (file)
@@ -28,6 +28,7 @@
 #define WebEventFactory_h
 
 #include "WebEvent.h"
+#include <WebCore/CompositionResults.h>
 
 typedef union _GdkEvent GdkEvent;
 
@@ -37,7 +38,7 @@ class WebEventFactory {
 public:
     static WebMouseEvent createWebMouseEvent(const GdkEvent*, int);
     static WebWheelEvent createWebWheelEvent(const GdkEvent*);
-    static WebKeyboardEvent createWebKeyboardEvent(const GdkEvent*);
+    static WebKeyboardEvent createWebKeyboardEvent(const GdkEvent*, const WebCore::CompositionResults&);
 };
 
 } // namespace WebKit
index 92b3188..bf61624 100644 (file)
@@ -212,6 +212,8 @@ void PageClientImpl::doneWithKeyEvent(const NativeWebKeyboardEvent& event, bool
 {
     if (wasEventHandled)
         return;
+    if (event.isFakeEventForComposition())
+        return;
 
     WebKitWebViewBase* webkitWebViewBase = WEBKIT_WEB_VIEW_BASE(m_viewWidget);
     webkitWebViewBaseForwardNextKeyEvent(webkitWebViewBase);
@@ -297,6 +299,11 @@ void PageClientImpl::countStringMatchesInCustomRepresentation(const String&, Fin
     notImplemented();
 }
 
+void PageClientImpl::updateTextInputState()
+{
+    webkitWebViewBaseUpdateTextInputState(WEBKIT_WEB_VIEW_BASE(m_viewWidget));
+}
+
 void PageClientImpl::startDrag(const WebCore::DragData& dragData, PassRefPtr<ShareableBitmap> dragImage)
 {
     webkitWebViewBaseStartDrag(WEBKIT_WEB_VIEW_BASE(m_viewWidget), dragData, dragImage);
index fc1cca0..bc6cdda 100644 (file)
@@ -89,6 +89,7 @@ private:
     virtual void getEditorCommandsForKeyEvent(const NativeWebKeyboardEvent&, const AtomicString&, Vector<WTF::String>&);
     virtual void findStringInCustomRepresentation(const String&, FindOptions, unsigned);
     virtual void countStringMatchesInCustomRepresentation(const String&, FindOptions, unsigned);
+    virtual void updateTextInputState();
     virtual void startDrag(const WebCore::DragData&, PassRefPtr<ShareableBitmap> dragImage);
 
 #if USE(ACCELERATED_COMPOSITING)
index 1ec0ae3..290f44f 100644 (file)
@@ -29,7 +29,6 @@
 #include "WebKitWebViewBase.h"
 
 #include "DrawingAreaProxyImpl.h"
-#include "NativeWebKeyboardEvent.h"
 #include "NativeWebMouseEvent.h"
 #include "NativeWebWheelEvent.h"
 #include "PageClientImpl.h"
@@ -41,6 +40,7 @@
 #include "WebKitWebViewBaseAccessible.h"
 #include "WebKitWebViewBasePrivate.h"
 #include "WebPageProxy.h"
+#include "WebViewBaseInputMethodFilter.h"
 #include <WebCore/ClipboardGtk.h>
 #include <WebCore/ClipboardUtilitiesGtk.h>
 #include <WebCore/DataObjectGtk.h>
@@ -81,9 +81,8 @@ void redirectedWindowDamagedCallback(void* data);
 
 struct _WebKitWebViewBasePrivate {
     _WebKitWebViewBasePrivate()
-        : imContext(adoptGRef(gtk_im_multicontext_new()))
 #if USE(TEXTURE_MAPPER_GL)
-        , redirectedWindow(RedirectedXCompositeWindow::create(IntSize(1, 1), RedirectedXCompositeWindow::DoNotCreateGLContext))
+        : redirectedWindow(RedirectedXCompositeWindow::create(IntSize(1, 1), RedirectedXCompositeWindow::DoNotCreateGLContext))
 #endif
     {
     }
@@ -97,7 +96,6 @@ struct _WebKitWebViewBasePrivate {
     OwnPtr<PageClientImpl> pageClient;
     RefPtr<WebPageProxy> pageProxy;
     bool shouldForwardNextKeyEvent;
-    GRefPtr<GtkIMContext> imContext;
     GtkClickCounter clickCounter;
     CString tooltipText;
     IntRect tooltipArea;
@@ -111,6 +109,7 @@ struct _WebKitWebViewBasePrivate {
     unsigned inspectorViewHeight;
     GOwnPtr<GdkEvent> contextMenuEvent;
     WebContextMenuProxyGtk* activeContextMenuProxy;
+    WebViewBaseInputMethodFilter inputMethodFilter;
 
     GtkWindow* toplevelOnScreenWindow;
     unsigned long toplevelResizeGripVisibilityID;
@@ -265,9 +264,6 @@ static void webkitWebViewBaseRealize(GtkWidget* widget)
     gtk_style_context_set_background(gtk_widget_get_style_context(widget), window);
 
     WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(widget);
-    WebKitWebViewBasePrivate* priv = webView->priv;
-    gtk_im_context_set_client_window(priv->imContext.get(), window);
-
     GtkWidget* toplevel = gtk_widget_get_toplevel(widget);
     if (widgetIsOnscreenToplevelWindow(toplevel))
         webkitWebViewBaseSetToplevelOnScreenWindow(webView, GTK_WINDOW(toplevel));
@@ -549,7 +545,7 @@ static gboolean webkitWebViewBaseFocusInEvent(GtkWidget* widget, GdkEventFocus*
 {
     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
     webkitWebViewBaseSetFocus(webViewBase, true);
-    gtk_im_context_focus_in(webViewBase->priv->imContext.get());
+    webViewBase->priv->inputMethodFilter.notifyFocusedIn();
 
     return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->focus_in_event(widget, event);
 }
@@ -558,7 +554,7 @@ static gboolean webkitWebViewBaseFocusOutEvent(GtkWidget* widget, GdkEventFocus*
 {
     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
     webkitWebViewBaseSetFocus(webViewBase, false);
-    gtk_im_context_focus_out(webViewBase->priv->imContext.get());
+    webViewBase->priv->inputMethodFilter.notifyFocusedOut();
 
     return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->focus_out_event(widget, event);
 }
@@ -593,7 +589,7 @@ static gboolean webkitWebViewBaseKeyPressEvent(GtkWidget* widget, GdkEventKey* e
         priv->shouldForwardNextKeyEvent = FALSE;
         return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->key_press_event(widget, event);
     }
-    priv->pageProxy->handleKeyboardEvent(NativeWebKeyboardEvent(reinterpret_cast<GdkEvent*>(event)));
+    priv->inputMethodFilter.filterKeyEvent(event);
     return TRUE;
 }
 
@@ -602,14 +598,11 @@ static gboolean webkitWebViewBaseKeyReleaseEvent(GtkWidget* widget, GdkEventKey*
     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
     WebKitWebViewBasePrivate* priv = webViewBase->priv;
 
-    if (gtk_im_context_filter_keypress(priv->imContext.get(), event))
-        return TRUE;
-
     if (priv->shouldForwardNextKeyEvent) {
         priv->shouldForwardNextKeyEvent = FALSE;
         return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->key_release_event(widget, event);
     }
-    priv->pageProxy->handleKeyboardEvent(NativeWebKeyboardEvent(reinterpret_cast<GdkEvent*>(event)));
+    priv->inputMethodFilter.filterKeyEvent(event);
     return TRUE;
 }
 
@@ -623,6 +616,8 @@ static gboolean webkitWebViewBaseButtonPressEvent(GtkWidget* widget, GdkEventBut
 
     gtk_widget_grab_focus(widget);
 
+    priv->inputMethodFilter.notifyMouseButtonPress();
+
     if (!priv->clickCounter.shouldProcessButtonEvent(buttonEvent))
         return TRUE;
 
@@ -874,7 +869,7 @@ WebKitWebViewBase* webkitWebViewBaseCreate(WebContext* context, WebPageGroup* pa
 
 GtkIMContext* webkitWebViewBaseGetIMContext(WebKitWebViewBase* webkitWebViewBase)
 {
-    return webkitWebViewBase->priv->imContext.get();
+    return webkitWebViewBase->priv->inputMethodFilter.context();
 }
 
 WebPageProxy* webkitWebViewBaseGetPage(WebKitWebViewBase* webkitWebViewBase)
@@ -897,6 +892,10 @@ void webkitWebViewBaseCreateWebPage(WebKitWebViewBase* webkitWebViewBase, WebCon
     if (priv->redirectedWindow)
         priv->pageProxy->setAcceleratedCompositingWindowId(priv->redirectedWindow->windowId());
 #endif
+
+    // This must happen here instead of the instance initializer, because the input method
+    // filter must have access to the page.
+    priv->inputMethodFilter.setWebView(webkitWebViewBase);
 }
 
 void webkitWebViewBaseSetTooltipText(WebKitWebViewBase* webViewBase, const char* tooltip)
@@ -1079,3 +1078,13 @@ void webkitWebViewBaseHandleDownloadRequest(WebKitWebViewBase* webViewBase, Down
     if (webViewBase->priv->downloadHandler)
         webViewBase->priv->downloadHandler(webViewBase, download);
 }
+
+void webkitWebViewBaseSetInputMethodState(WebKitWebViewBase* webkitWebViewBase, bool enabled)
+{
+    webkitWebViewBase->priv->inputMethodFilter.setEnabled(enabled);
+}
+
+void webkitWebViewBaseUpdateTextInputState(WebKitWebViewBase* webkitWebViewBase)
+{
+    webkitWebViewBase->priv->inputMethodFilter.setCursorRect(webkitWebViewBase->priv->pageProxy->editorState().cursorRect);
+}
index 2bd0bc0..3d88641 100644 (file)
@@ -50,6 +50,8 @@ void webkitWebViewBaseSetInspectorViewHeight(WebKitWebViewBase*, unsigned height
 void webkitWebViewBaseSetActiveContextMenuProxy(WebKitWebViewBase*, WebKit::WebContextMenuProxyGtk*);
 WebKit::WebContextMenuProxyGtk* webkitWebViewBaseGetActiveContextMenuProxy(WebKitWebViewBase*);
 GdkEvent* webkitWebViewBaseTakeContextMenuEvent(WebKitWebViewBase*);
+void webkitWebViewBaseSetInputMethodState(WebKitWebViewBase*, bool enabled);
+void webkitWebViewBaseUpdateTextInputState(WebKitWebViewBase*);
 
 #if USE(TEXTURE_MAPPER_GL)
 void webkitWebViewBaseQueueDrawOfAcceleratedCompositingResults(WebKitWebViewBase*);
diff --git a/Source/WebKit2/UIProcess/API/gtk/WebViewBaseInputMethodFilter.cpp b/Source/WebKit2/UIProcess/API/gtk/WebViewBaseInputMethodFilter.cpp
new file mode 100644 (file)
index 0000000..8b87c15
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2012 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "WebViewBaseInputMethodFilter.h"
+
+#include "NativeWebKeyboardEvent.h"
+#include "WebKitWebViewBasePrivate.h"
+#include "WebPageProxy.h"
+#include <WebCore/Color.h>
+#include <WebCore/CompositionResults.h>
+#include <WebCore/Editor.h>
+
+using namespace WebCore;
+
+namespace WebKit {
+
+void WebViewBaseInputMethodFilter::setWebView(WebKitWebViewBase* webView)
+{
+    GtkInputMethodFilter::setWidget(GTK_WIDGET(webView));
+
+    m_webPageProxy = webkitWebViewBaseGetPage(webView);
+    ASSERT(m_webPageProxy);
+}
+
+bool WebViewBaseInputMethodFilter::canEdit()
+{
+    return true;
+}
+
+bool WebViewBaseInputMethodFilter::sendSimpleKeyEvent(GdkEventKey* event, WTF::String simpleString, EventFakedForComposition faked)
+{
+    ASSERT(m_webPageProxy);
+    m_webPageProxy->handleKeyboardEvent(NativeWebKeyboardEvent(reinterpret_cast<GdkEvent*>(event),
+                                       CompositionResults(simpleString), faked));
+    return true;
+}
+
+bool WebViewBaseInputMethodFilter::sendKeyEventWithCompositionResults(GdkEventKey* event, ResultsToSend resultsToSend, EventFakedForComposition faked)
+{
+    ASSERT(m_webPageProxy);
+    m_webPageProxy->handleKeyboardEvent(NativeWebKeyboardEvent(reinterpret_cast<GdkEvent*>(event),
+                                        CompositionResults(CompositionResults::WillSendCompositionResultsSoon),
+                                        faked));
+
+    if (resultsToSend & Composition && !m_confirmedComposition.isNull())
+        confirmCompositionText(m_confirmedComposition);
+    if (resultsToSend & Preedit && !m_preedit.isNull())
+        setPreedit(m_preedit, m_cursorOffset);
+    return true;
+}
+
+void WebViewBaseInputMethodFilter::confirmCompositionText(String text)
+{
+    ASSERT(m_webPageProxy);
+    m_webPageProxy->confirmComposition(text, -1, 0);
+}
+
+void WebViewBaseInputMethodFilter::confirmCurrentComposition()
+{
+    ASSERT(m_webPageProxy);
+    m_webPageProxy->confirmComposition(String(), -1, 0);
+}
+
+void WebViewBaseInputMethodFilter::cancelCurrentComposition()
+{
+    ASSERT(m_webPageProxy);
+    m_webPageProxy->cancelComposition();
+}
+
+void WebViewBaseInputMethodFilter::setPreedit(String newPreedit, int cursorOffset)
+{
+    // TODO: We should parse the PangoAttrList that we get from the IM context here.
+    Vector<CompositionUnderline> underlines;
+    underlines.append(CompositionUnderline(0, newPreedit.length(), Color(1, 1, 1), false));
+
+    ASSERT(m_webPageProxy);
+    m_webPageProxy->setComposition(newPreedit, underlines,
+                                   m_cursorOffset, m_cursorOffset,
+                                   0 /* replacement start */,
+                                   0 /* replacement end */);
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit2/UIProcess/API/gtk/WebViewBaseInputMethodFilter.h b/Source/WebKit2/UIProcess/API/gtk/WebViewBaseInputMethodFilter.h
new file mode 100644 (file)
index 0000000..9cde8b1
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2012 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef WebViewBaseInputMethodFilter_h
+#define WebViewBaseInputMethodFilter_h
+
+#include "GtkInputMethodFilter.h"
+#include "WebPageProxy.h"
+
+typedef struct _WebKitWebViewBase WebKitWebViewBase;
+
+namespace WebKit {
+
+class WebViewBaseInputMethodFilter : public WebCore::GtkInputMethodFilter {
+public:
+    void setWebView(WebKitWebViewBase*);
+
+protected:
+    virtual bool sendSimpleKeyEvent(GdkEventKey*, WTF::String eventString, EventFakedForComposition);
+    virtual bool sendKeyEventWithCompositionResults(GdkEventKey*, ResultsToSend, EventFakedForComposition);
+    virtual bool canEdit();
+    virtual void confirmCompositionText(String);
+    virtual void confirmCurrentComposition();
+    virtual void cancelCurrentComposition();
+    virtual void setPreedit(String, int cursorOffset);
+
+private:
+    WebPageProxy* m_webPageProxy;
+};
+
+} // namespace WebKit
+
+#endif // WebViewBaseInputMethodFilter_h
index 1012f4a..e97d2cb 100644 (file)
@@ -130,9 +130,9 @@ public:
     virtual void handleWillSetInputMethodState() = 0;
 #endif // PLATFORM(QT).
 
-#if PLATFORM(QT) || PLATFORM(EFL)
+#if PLATFORM(QT) || PLATFORM(EFL) || PLATFORM(GTK)
     virtual void updateTextInputState() = 0;
-#endif // PLATFORM(QT) || PLATFORM(EFL)
+#endif // PLATFORM(QT) || PLATFORM(EFL) || PLATOFRM(GTK)
 
 #if PLATFORM(QT) || PLATFORM(EFL) || PLATFORM(GTK)
     virtual void handleDownloadRequest(DownloadProxy*) = 0;
index 44e1f70..2f12652 100644 (file)
@@ -2978,7 +2978,7 @@ void WebPageProxy::editorStateChanged(const EditorState& editorState)
 
 #if PLATFORM(MAC)
     m_pageClient->updateTextInputState(couldChangeSecureInputState);
-#elif PLATFORM(QT) || PLATFORM(EFL)
+#elif PLATFORM(QT) || PLATFORM(EFL) || PLATFORM(GTK)
     m_pageClient->updateTextInputState();
 #endif
 }
@@ -4230,4 +4230,31 @@ void WebPageProxy::didReceiveURIRequest(String uriString, uint64_t requestID)
 }
 #endif
 
+#if PLATFORM(QT) || PLATFORM(GTK)
+void WebPageProxy::setComposition(const String& text, Vector<CompositionUnderline> underlines, uint64_t selectionStart, uint64_t selectionEnd, uint64_t replacementRangeStart, uint64_t replacementRangeEnd)
+{
+    // FIXME: We need to find out how to proper handle the crashes case.
+    if (!isValid())
+        return;
+
+    process()->sendSync(Messages::WebPage::SetComposition(text, underlines, selectionStart, selectionEnd, replacementRangeStart, replacementRangeEnd), Messages::WebPage::SetComposition::Reply(m_editorState), m_pageID);
+}
+
+void WebPageProxy::confirmComposition(const String& compositionString, int64_t selectionStart, int64_t selectionLength)
+{
+    if (!isValid())
+        return;
+
+    process()->sendSync(Messages::WebPage::ConfirmComposition(compositionString, selectionStart, selectionLength), Messages::WebPage::ConfirmComposition::Reply(m_editorState), m_pageID);
+}
+
+void WebPageProxy::cancelComposition()
+{
+    if (!isValid())
+        return;
+
+    process()->sendSync(Messages::WebPage::CancelComposition(), Messages::WebPage::CancelComposition::Reply(m_editorState), m_pageID);
+}
+#endif // PLATFORM(QT) || PLATFORM(GTK)
+
 } // namespace WebKit
index 6c2e201..018ed24 100644 (file)
@@ -379,11 +379,16 @@ public:
     void setThemePath(const String&);
 #endif
 
-#if PLATFORM(QT)
+#if PLATFORM(QT) || PLATFORM(GTK)
     void setComposition(const String& text, Vector<WebCore::CompositionUnderline> underlines, uint64_t selectionStart, uint64_t selectionEnd, uint64_t replacementRangeStart, uint64_t replacementRangeEnd);
     void confirmComposition(const String& compositionString, int64_t selectionStart, int64_t selectionLength);
     void cancelComposition();
 #endif
+
+#if PLATFORM(GTK)
+    void setInputMethodState(bool enabled);
+#endif
+
 #if PLATFORM(MAC)
     void updateWindowIsVisible(bool windowIsVisible);
     void windowAndViewFramesChanged(const WebCore::IntRect& windowFrameInScreenCoordinates, const WebCore::IntRect& viewFrameInWindowCoordinates, const WebCore::IntPoint& accessibilityViewCoordinates);
index 47421d4..0edcd9d 100644 (file)
@@ -182,6 +182,8 @@ messages -> WebPageProxy {
 
     # Support for connecting the Accessibility worlds of the UI and the Web processes
     BindAccessibilityTree(WTF::String plugID)
+
+    SetInputMethodState(bool enabled);
 #endif
 
     # BackForward messages
index 6b01bb0..f45d7e3 100644 (file)
@@ -109,6 +109,11 @@ void WebPageProxy::windowedPluginGeometryDidChange(const WebCore::IntRect& frame
     webkitWebViewBaseChildMoveResize(WEBKIT_WEB_VIEW_BASE(viewWidget()), plugin, frameRect);
 }
 
+void WebPageProxy::setInputMethodState(bool enabled)
+{
+    webkitWebViewBaseSetInputMethodState(WEBKIT_WEB_VIEW_BASE(viewWidget()), enabled);
+}
+
 #if USE(TEXTURE_MAPPER_GL)
 void WebPageProxy::setAcceleratedCompositingWindowId(uint64_t nativeWindowId)
 {
index 8a205f9..6d1b7fd 100644 (file)
@@ -60,31 +60,6 @@ void WebPageProxy::loadRecentSearches(const String&, Vector<String>&)
     notImplemented();
 }
 
-void WebPageProxy::setComposition(const String& text, Vector<CompositionUnderline> underlines, uint64_t selectionStart, uint64_t selectionEnd, uint64_t replacementRangeStart, uint64_t replacementRangeEnd)
-{
-    // FIXME: We need to find out how to proper handle the crashes case.
-    if (!isValid())
-        return;
-
-    process()->send(Messages::WebPage::SetComposition(text, underlines, selectionStart, selectionEnd, replacementRangeStart, replacementRangeEnd), m_pageID);
-}
-
-void WebPageProxy::confirmComposition(const String& compositionString, int64_t selectionStart, int64_t selectionLength)
-{
-    if (!isValid())
-        return;
-
-    process()->send(Messages::WebPage::ConfirmComposition(compositionString, selectionStart, selectionLength), m_pageID);
-}
-
-void WebPageProxy::cancelComposition()
-{
-    if (!isValid())
-        return;
-
-    process()->send(Messages::WebPage::CancelComposition(), m_pageID);
-}
-
 void WebPageProxy::registerApplicationScheme(const String& scheme)
 {
     process()->send(Messages::WebPage::RegisterApplicationScheme(scheme), m_pageID);
index 5f96352..67fdc1f 100644 (file)
@@ -29,7 +29,7 @@
 #include <WebCore/DataObjectGtk.h>
 #include <WebCore/KeyboardEvent.h>
 #include <WebCore/PasteboardHelper.h>
-#include <WebCore/NotImplemented.h>
+#include <WebCore/WindowsKeyboardCodes.h>
 
 using namespace WebCore;
 
@@ -76,6 +76,10 @@ void WebEditorClient::handleKeyboardEvent(KeyboardEvent* event)
     if (!platformEvent)
         return;
 
+    // If this was an IME event don't do anything.
+    if (platformEvent->windowsVirtualKeyCode() == VK_PROCESSKEY)
+        return;
+
     Vector<WTF::String> pendingEditorCommands;
     getEditorCommandsForKeyEvent(event, pendingEditorCommands);
     if (!pendingEditorCommands.isEmpty()) {
@@ -104,30 +108,26 @@ void WebEditorClient::handleKeyboardEvent(KeyboardEvent* event)
     // This is just a normal text insertion, so wait to execute the insertion
     // until a keypress event happens. This will ensure that the insertion will not
     // be reflected in the contents of the field until the keyup DOM event.
-    if (event->type() == eventNames().keypressEvent) {
-
-        // FIXME: Add IM support
-        // https://bugs.webkit.org/show_bug.cgi?id=55946
-        frame->editor()->insertText(platformEvent->text(), event);
-        event->setDefaultHandled();
+    if (event->type() != eventNames().keypressEvent)
+        return;
 
-    } else {
-        // Don't insert null or control characters as they can result in unexpected behaviour
-        if (event->charCode() < ' ')
-            return;
+    // Don't insert null or control characters as they can result in unexpected behaviour
+    if (event->charCode() < ' ')
+        return;
 
-        // Don't insert anything if a modifier is pressed
-        if (platformEvent->ctrlKey() || platformEvent->altKey())
-            return;
+    // Don't insert anything if a modifier is pressed
+    if (platformEvent->ctrlKey() || platformEvent->altKey())
+        return;
 
-        if (frame->editor()->insertText(platformEvent->text(), event))
-            event->setDefaultHandled();
-    }
+    if (frame->editor()->insertText(platformEvent->text(), event))
+        event->setDefaultHandled();
 }
 
-void WebEditorClient::handleInputMethodKeydown(KeyboardEvent*)
+void WebEditorClient::handleInputMethodKeydown(KeyboardEvent* event)
 {
-    notImplemented();
+    const PlatformKeyboardEvent* platformEvent = event->keyEvent();
+    if (platformEvent && platformEvent->windowsVirtualKeyCode() == VK_PROCESSKEY)
+        event->preventDefault();
 }
 
 #if PLATFORM(X11)
index 9bb4820..0e96e92 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Copyright (C) 2010, 2011, 2012 Apple Inc. All rights reserved.
  * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -630,6 +631,10 @@ EditorState WebPage::editorState() const
     }
 #endif
 
+#if PLATFORM(GTK)
+    result.cursorRect = frame->selection()->absoluteCaretBounds();
+#endif
+
     return result;
 }
 
@@ -3664,4 +3669,98 @@ bool WebPage::shouldUseCustomRepresentationForResponse(const ResourceResponse& r
     return !canPluginHandleResponse(response);
 }
 
+#if PLATFORM(QT) || PLATFORM(GTK)
+static Frame* targetFrameForEditing(WebPage* page)
+{
+    Frame* targetFrame = page->corePage()->focusController()->focusedOrMainFrame();
+
+    if (!targetFrame || !targetFrame->editor())
+        return 0;
+
+    Editor* editor = targetFrame->editor();
+    if (!editor->canEdit())
+        return 0;
+
+    if (editor->hasComposition()) {
+        // We should verify the parent node of this IME composition node are
+        // editable because JavaScript may delete a parent node of the composition
+        // node. In this case, WebKit crashes while deleting texts from the parent
+        // node, which doesn't exist any longer.
+        if (PassRefPtr<Range> range = editor->compositionRange()) {
+            Node* node = range->startContainer();
+            if (!node || !node->isContentEditable())
+                return 0;
+        }
+    }
+    return targetFrame;
+}
+
+void WebPage::confirmComposition(const String& compositionString, int64_t selectionStart, int64_t selectionLength, EditorState& newState)
+{
+    Frame* targetFrame = targetFrameForEditing(this);
+    if (!targetFrame) {
+        newState = editorState();
+        return;
+    }
+
+    Editor* editor = targetFrame->editor();
+    editor->confirmComposition(compositionString);
+
+    if (selectionStart == -1) {
+        newState = editorState();
+        return;
+    }
+
+    Element* scope = targetFrame->selection()->rootEditableElement();
+    RefPtr<Range> selectionRange = TextIterator::rangeFromLocationAndLength(scope, selectionStart, selectionLength);
+    ASSERT_WITH_MESSAGE(selectionRange, "Invalid selection: [%lld:%lld] in text of length %d", static_cast<long long>(selectionStart), static_cast<long long>(selectionLength), scope->innerText().length());
+
+    if (selectionRange) {
+        VisibleSelection selection(selectionRange.get(), SEL_DEFAULT_AFFINITY);
+        targetFrame->selection()->setSelection(selection);
+    }
+    newState = editorState();
+}
+
+void WebPage::setComposition(const String& text, Vector<CompositionUnderline> underlines, uint64_t selectionStart, uint64_t selectionEnd, uint64_t replacementStart, uint64_t replacementLength, EditorState& newState)
+{
+    Frame* targetFrame = targetFrameForEditing(this);
+    if (!targetFrame) {
+        newState = editorState();
+        return;
+    }
+
+    if (!targetFrame->selection()->isContentEditable()) {
+        newState = editorState();
+        return;
+    }
+
+    if (replacementLength > 0) {
+        // The layout needs to be uptodate before setting a selection
+        targetFrame->document()->updateLayout();
+
+        Element* scope = targetFrame->selection()->rootEditableElement();
+        RefPtr<Range> replacementRange = TextIterator::rangeFromLocationAndLength(scope, replacementStart, replacementLength);
+        targetFrame->editor()->setIgnoreCompositionSelectionChange(true);
+        targetFrame->selection()->setSelection(VisibleSelection(replacementRange.get(), SEL_DEFAULT_AFFINITY));
+        targetFrame->editor()->setIgnoreCompositionSelectionChange(false);
+    }
+
+    targetFrame->editor()->setComposition(text, underlines, selectionStart, selectionEnd);
+    newState = editorState();
+}
+
+void WebPage::cancelComposition(EditorState& newState)
+{
+    Frame* targetFrame = targetFrameForEditing(this);
+    if (!targetFrame) {
+        newState = editorState();
+        return;
+    }
+
+    targetFrame->editor()->cancelComposition();
+    newState = editorState();
+}
+#endif
+
 } // namespace WebKit
index 8ad65a1..3cd1dff 100644 (file)
@@ -427,10 +427,10 @@ public:
     void commitPageTransitionViewport();
 #endif
 
-#if PLATFORM(QT)
-    void setComposition(const String& text, Vector<WebCore::CompositionUnderline> underlines, uint64_t selectionStart, uint64_t selectionEnd, uint64_t replacementRangeStart, uint64_t replacementRangeEnd);
-    void confirmComposition(const String& text, int64_t selectionStart, int64_t selectionLength);
-    void cancelComposition();
+#if PLATFORM(QT) || PLATFORM(GTK)
+    void setComposition(const String& text, Vector<WebCore::CompositionUnderline> underlines, uint64_t selectionStart, uint64_t selectionEnd, uint64_t replacementRangeStart, uint64_t replacementRangeEnd, EditorState&);
+    void confirmComposition(const String& text, int64_t selectionStart, int64_t selectionLength, EditorState&);
+    void cancelComposition(EditorState&);
 #endif
 
 #if PLATFORM(MAC)
index 008c6e0..bed9e65 100644 (file)
@@ -251,10 +251,10 @@ messages -> WebPage {
     CommitPageTransitionViewport()
 #endif
 
-#if PLATFORM(QT)
-    SetComposition(WTF::String text, WTF::Vector<WebCore::CompositionUnderline> underlines, uint64_t selectionStart, uint64_t selectionEnd, uint64_t replacementRangeStart, uint64_t replacementRangeEnd)
-    ConfirmComposition(WTF::String text, int64_t selectionStart, int64_t selectionLength)
-    CancelComposition()
+#if PLATFORM(QT) || PLATFORM(GTK)
+    SetComposition(WTF::String text, WTF::Vector<WebCore::CompositionUnderline> underlines, uint64_t selectionStart, uint64_t selectionEnd, uint64_t replacementRangeStart, uint64_t replacementRangeEnd) -> (WebKit::EditorState newState)
+    ConfirmComposition(WTF::String text, int64_t selectionStart, int64_t selectionLength) -> (WebKit::EditorState newState)
+    CancelComposition() -> (WebKit::EditorState newState)
 #endif
 
 #if PLATFORM(MAC)
index 81f10d8..94ac02b 100644 (file)
@@ -309,90 +309,6 @@ PassRefPtr<SharedBuffer> WebPage::cachedResponseDataForURL(const KURL&)
     return 0;
 }
 
-static Frame* targetFrameForEditing(WebPage* page)
-{
-    Frame* targetFrame = page->corePage()->focusController()->focusedOrMainFrame();
-
-    if (!targetFrame || !targetFrame->editor())
-        return 0;
-
-    Editor* editor = targetFrame->editor();
-    if (!editor->canEdit())
-        return 0;
-
-    if (editor->hasComposition()) {
-        // We should verify the parent node of this IME composition node are
-        // editable because JavaScript may delete a parent node of the composition
-        // node. In this case, WebKit crashes while deleting texts from the parent
-        // node, which doesn't exist any longer.
-        if (PassRefPtr<Range> range = editor->compositionRange()) {
-            Node* node = range->startContainer();
-            if (!node || !node->isContentEditable())
-                return 0;
-        }
-    }
-    return targetFrame;
-}
-
-void WebPage::confirmComposition(const String& compositionString, int64_t selectionStart, int64_t selectionLength)
-{
-    Frame* targetFrame = targetFrameForEditing(this);
-    if (!targetFrame)
-        return;
-
-    Editor* editor = targetFrame->editor();
-    editor->confirmComposition(compositionString);
-
-    if (selectionStart == -1)
-        return;
-
-    Element* scope = targetFrame->selection()->rootEditableElement();
-    RefPtr<Range> selectionRange = TextIterator::rangeFromLocationAndLength(scope, selectionStart, selectionLength);
-    ASSERT_WITH_MESSAGE(selectionRange, "Invalid selection: [%lld:%lld] in text of length %d", static_cast<long long>(selectionStart), static_cast<long long>(selectionLength), scope->innerText().length());
-
-    if (selectionRange) {
-        VisibleSelection selection(selectionRange.get(), SEL_DEFAULT_AFFINITY);
-        targetFrame->selection()->setSelection(selection);
-    }
-
-    // FIXME: static_cast<WebEditorClient*>(editor->client())->sendSelectionChangedMessage();
-}
-
-void WebPage::setComposition(const String& text, Vector<CompositionUnderline> underlines, uint64_t selectionStart, uint64_t selectionEnd, uint64_t replacementStart, uint64_t replacementLength)
-{
-    Frame* targetFrame = targetFrameForEditing(this);
-    if (!targetFrame)
-        return;
-
-    Element* scope = targetFrame->selection()->rootEditableElement();
-
-    if (targetFrame->selection()->isContentEditable()) {
-        if (replacementLength > 0) {
-            // The layout needs to be uptodate before setting a selection
-            targetFrame->document()->updateLayout();
-
-            RefPtr<Range> replacementRange = TextIterator::rangeFromLocationAndLength(scope, replacementStart, replacementLength);
-
-            targetFrame->editor()->setIgnoreCompositionSelectionChange(true);
-            targetFrame->selection()->setSelection(VisibleSelection(replacementRange.get(), SEL_DEFAULT_AFFINITY));
-            targetFrame->editor()->setIgnoreCompositionSelectionChange(false);
-        }
-
-        targetFrame->editor()->setComposition(text, underlines, selectionStart, selectionEnd);
-
-        // FIXME: static_cast<WebEditorClient*>(targetFrame->editor()->client())->sendSelectionChangedMessage();
-    }
-}
-
-void WebPage::cancelComposition()
-{
-    Frame* frame = targetFrameForEditing(this);
-
-    frame->editor()->cancelComposition();
-
-    // FIXME: static_cast<WebEditorClient*>(targetFrame->editor()->client())->sendSelectionChangedMessage();
-}
-
 void WebPage::registerApplicationScheme(const String& scheme)
 {
     QtNetworkAccessManager* qnam = qobject_cast<QtNetworkAccessManager*>(WebProcess::shared().networkAccessManager());
index 37ce078..a359ff7 100644 (file)
@@ -1,3 +1,22 @@
+2012-12-28  Martin Robinson  <mrobinson@igalia.com>
+
+        [GTK][WK2] Add support for IME Composition
+        https://bugs.webkit.org/show_bug.cgi?id=65093
+
+        Reviewed by Carlos Garcia Campos.
+
+        Update unit tests for GtkInputMethodFilter to note whether or not an event
+        was a fake event synthesized for composition purposes. This is now used
+        for WebKit2.
+
+        * TestWebKitAPI/Tests/gtk/InputMethodFilter.cpp:
+        (TestWebKitAPI::TestInputMethodFilter::sendSimpleKeyEvent):
+        (TestWebKitAPI::TestInputMethodFilter::sendKeyEventWithCompositionResults):
+        (TestWebKitAPI::TEST):
+        * gtk/generate-gtkdoc:
+        (get_webkit2_options): Skip new files in the WebKit2 source directory for documentation
+        generation.
+
 2012-12-27  Ilya Tikhonovsky  <loislo@chromium.org>
 
         Web Inspector: Native Memory Instrumentation. Update clang plugin according to the current state of memory instrumentation code.
index de40883..62dbb07 100644 (file)
@@ -80,21 +80,23 @@ public:
     }
 
 protected:
-    virtual bool sendSimpleKeyEvent(GdkEventKey* event, WTF::String eventString)
+    virtual bool sendSimpleKeyEvent(GdkEventKey* event, WTF::String eventString, EventFakedForComposition faked)
     {
         const char* eventType = event->type == GDK_KEY_RELEASE ? "release" : "press";
+        const char* fakedString = faked == EventFaked ? " (faked)" : "";
         if (!eventString.isNull())
-            m_events.append(String::format("sendSimpleKeyEvent type=%s keycode=%x text='%s'", eventType, event->keyval, eventString.utf8().data()));
+            m_events.append(String::format("sendSimpleKeyEvent type=%s keycode=%x text='%s'%s", eventType, event->keyval, eventString.utf8().data(), fakedString));
         else
-            m_events.append(String::format("sendSimpleKeyEvent type=%s keycode=%x", eventType, event->keyval));
+            m_events.append(String::format("sendSimpleKeyEvent type=%s keycode=%x%s", eventType, event->keyval, fakedString));
 
         return true;
     }
 
-    virtual bool sendKeyEventWithCompositionResults(GdkEventKey* event, ResultsToSend resultsToSend)
+    virtual bool sendKeyEventWithCompositionResults(GdkEventKey* event, ResultsToSend resultsToSend, EventFakedForComposition faked)
     {
         const char* eventType = event->type == GDK_KEY_RELEASE ? "release" : "press";
-        m_events.append(String::format("sendKeyEventWithCompositionResults type=%s keycode=%u", eventType, event->keyval));
+        const char* fakedString = faked == EventFaked ? " (faked)" : "";
+        m_events.append(String::format("sendKeyEventWithCompositionResults type=%s keycode=%u%s", eventType, event->keyval, fakedString));
 
         if (resultsToSend & Composition && !m_confirmedComposition.isNull())
             confirmCompositionText(m_confirmedComposition);
@@ -241,12 +243,12 @@ TEST(GTK, GtkInputMethodFilterContextEventsWithoutKeyEvents)
 
     const Vector<String>& events = inputMethodFilter.events();
     ASSERT_EQ(6, events.size());
-    ASSERT_EQ(String("sendKeyEventWithCompositionResults type=press keycode=16777215"), events[0]);
+    ASSERT_EQ(String("sendKeyEventWithCompositionResults type=press keycode=16777215 (faked)"), events[0]);
     ASSERT_EQ(String("setPreedit text='preedit of doom, bringer of cheese' cursorOffset=3"), events[1]);
-    ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=ffffff"), events[2]);
-    ASSERT_EQ(String("sendKeyEventWithCompositionResults type=press keycode=16777215"), events[3]);
+    ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=ffffff (faked)"), events[2]);
+    ASSERT_EQ(String("sendKeyEventWithCompositionResults type=press keycode=16777215 (faked)"), events[3]);
     ASSERT_EQ(String("confirmComposition 'commit text'"), events[4]);
-    ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=ffffff"), events[5]);
+    ASSERT_EQ(String("sendSimpleKeyEvent type=release keycode=ffffff (faked)"), events[5]);
 }
 
 static bool gSawContextReset = false;
index fd84879..4fd44bc 100755 (executable)
@@ -97,10 +97,11 @@ def get_webkit2_options():
         'cross_reference_deps' : get_gtkdoc_module_paths(xref_deps),
         'ignored_files': glob.glob(src_path('*Private.h')) + \
                          glob.glob(src_path('*Client*')) + \
-                         glob.glob(src_path('WebKitWebViewBaseAccessible.*')) + \
                          glob.glob(src_path('WebKit2GtkAuthenticationDialog.*')) + \
                          glob.glob(src_path('WebKitGeolocationProvider.*')) + \
                          glob.glob(src_path('WebKitTextChecker.*')) + \
+                         glob.glob(src_path('WebKitWebViewBaseAccessible.*')) + \
+                         glob.glob(src_path('WebViewBaseInputMethodFilter.*')) + \
                          glob.glob(derived_sources_path('webkit2gtk', 'webkit2', 'WebKitMarshal.*')) + \
                          glob.glob(derived_sources_path('webkit2gtk', 'webkit2', 'WebKitEnumTypes.*')) + \
                          glob.glob(src_path('tests/*.h'))