[GTK][WPE] Add API to set purpose and hints of active editable element to input methods
authorcarlosgc@webkit.org <carlosgc@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 7 Jan 2020 10:48:45 +0000 (10:48 +0000)
committercarlosgc@webkit.org <carlosgc@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 7 Jan 2020 10:48:45 +0000 (10:48 +0000)
https://bugs.webkit.org/show_bug.cgi?id=205605

Reviewed by Žan Doberšek.

.:

Add ENABLE_AUTOCAPITALIZE build flag. It's private and disabled by default, enabled in GTK and WPE ports.

* Source/cmake/OptionsGTK.cmake:
* Source/cmake/OptionsWPE.cmake:
* Source/cmake/WebKitFeatures.cmake:

PerformanceTests:

Split ENABLE_IOS_AUTOCORRECT_AND_AUTOCAPITALIZE and remove the IOS prefix.

* StitchMarker/wtf/FeatureDefines.h:

Source/WebCore:

Use ENABLE(AUTOCAPITALIZE) and ENABLE(AUTOCORRECT) instead of ENABLE(IOS_AUTOCORRECT_AND_AUTOCAPITALIZE).

* Sources.txt: Add Autocapitalize.cpp to the build.
* html/Autocapitalize.cpp: Add ENABLE(AUTOCAPITALIZE) guards.
* html/Autocapitalize.h: Ditto.
* html/HTMLElement.cpp:
* html/HTMLElement.h:
* html/HTMLElement.idl:
* html/HTMLFormControlElement.cpp:
* html/HTMLFormControlElement.h:
* html/HTMLFormElement.cpp:
* html/HTMLFormElement.h:
* loader/EmptyClients.cpp: Update to new API of EditorClient::setInputMethodState
* page/EditorClient.h: The focused element or nullptr is now received by setInputMethodState() instead of enabled/disabled boolean.
* page/FocusController.cpp:
(WebCore::FocusController::setFocusedElement): Pass the focused element or nullptr to setInputMethodState().

Source/WebKit:

Add input-purpose and input-hints properties to WebKitInputMethodContext. The message SetInputMethodState now
receives an optional InputMethodState struct with information about the purpose and hints of the active editable
element.

* Scripts/webkit/messages.py: Only include InputMethodState.h for GTK and WPE.
* Shared/glib/InputMethodState.cpp: Added.
(WebKit::InputMethodState::setPurposeOrHintForInputMode):
(WebKit::inputElementHasDigitsPattern):
(WebKit::InputMethodState::setPurposeForInputElement):
(WebKit::InputMethodState::addHintsForAutocapitalizeType):
(WebKit::InputMethodState::encode const):
(WebKit::InputMethodState::decode):
* Shared/glib/InputMethodState.h: Added.
(WebKit::operator==):
* SourcesGTK.txt:
* SourcesWPE.txt:
* UIProcess/API/glib/InputMethodFilter.cpp:
(WebKit::InputMethodFilter::setContext): Use isEnabled() instead of m_enabled.
(WebKit::InputMethodFilter::setState): Now receives an optional InputMethodState struct.
(WebKit::InputMethodFilter::filterKeyEvent): Use isEnabled() instead of m_enabled.
(WebKit::InputMethodFilter::isViewFocused const): Ditto.
(WebKit::toWebKitPurpose): Helper to convert InputMethodState::Purpose to WebKitInputPurpose.
(WebKit::toWebKitHints): Helper to convert InputMethodState::Hint to WebKitInputHints.
(WebKit::InputMethodFilter::notifyFocusedIn): Set the purpose and hints to the context.
(WebKit::InputMethodFilter::notifyFocusedOut): Use isEnabled() instead of m_enabled.
(WebKit::InputMethodFilter::notifyCursorRect): Ditto.
(WebKit::InputMethodFilter::preeditStarted): Ditto.
(WebKit::InputMethodFilter::preeditChanged): Ditto.
(WebKit::InputMethodFilter::preeditFinished): Ditto.
(WebKit::InputMethodFilter::committed): Ditto.
* UIProcess/API/glib/InputMethodFilter.h:
(WebKit::InputMethodFilter::isEnabled const): Return true if we have a state.
* UIProcess/API/glib/WebKitInputMethodContext.cpp:
(webkitInputMethodContextSetProperty): Properties setter.
(webkitInputMethodContextGetProperty): Properties getter.
(webkit_input_method_context_class_init): Add implementation for properties getter and setter.
(webkit_input_method_context_get_input_purpose):
(webkit_input_method_context_set_input_purpose):
(webkit_input_method_context_get_input_hints):
(webkit_input_method_context_set_input_hints):
* UIProcess/API/gtk/WebKitInputMethodContext.h:
* UIProcess/API/gtk/WebKitInputMethodContextImplGtk.cpp:
(toGtkInputPurpose): Helper to convert WebKitInputPurpose to GtkInputPurpose.
(toGtkInputHints): Helper to convert WebKitInputHints to GtkInputHints.
(inputPurposeChangedCallback): Set the purpose on GtkIMContext.
(inputHintsChangedCallback): Set the hints on GtkIMContext.
(webkitInputMethodContextImplGtkConstructed): Connect to notify signal for input-purpose and input-hints
properties of the context.
* UIProcess/API/gtk/WebKitWebViewBase.cpp:
(webkitWebViewBaseSetInputMethodState):
* UIProcess/API/gtk/WebKitWebViewBasePrivate.h:
* UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt:
* UIProcess/API/wpe/PageClientImpl.cpp:
(WebKit::PageClientImpl::setInputMethodState):
* UIProcess/API/wpe/PageClientImpl.h:
* UIProcess/API/wpe/WPEView.cpp:
(WKWPE::View::setInputMethodState):
* UIProcess/API/wpe/WPEView.h:
* UIProcess/API/wpe/WebKitInputMethodContext.h:
* UIProcess/API/wpe/docs/wpe-1.0-sections.txt:
* UIProcess/WebPageProxy.h:
* UIProcess/WebPageProxy.messages.in:
* UIProcess/gtk/WebPageProxyGtk.cpp:
(WebKit::WebPageProxy::setInputMethodState):
* UIProcess/wpe/WebPageProxyWPE.cpp:
(WebKit::WebPageProxy::setInputMethodState):
* WebProcess/WebCoreSupport/WebEditorClient.cpp:
(WebKit::WebEditorClient::setInputMethodState):
* WebProcess/WebCoreSupport/WebEditorClient.h:
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/glib/WebPageGLib.cpp:
(WebKit::inputMethodSateForElement): Build an InputMethodState for the given element.
(WebKit::WebPage::setInputMethodState):

Source/WebKitLegacy/mac:

* DOM/DOMHTMLElement.mm: Use ENABLE(AUTOCORRECT) and ENABLE(AUTOCAPITALIZE).
* WebCoreSupport/WebEditorClient.h: Update tom the new API to WebEditorClient::setInputMethodState.
* WebCoreSupport/WebEditorClient.mm:
(WebEditorClient::setInputMethodState): Ditto.

Source/WebKitLegacy/win:

Update to the new API of WebEditorClient::setInputMethodState.

* WebCoreSupport/WebEditorClient.cpp:
(WebEditorClient::setInputMethodState):
* WebCoreSupport/WebEditorClient.h:

Source/WTF:

Split ENABLE_IOS_AUTOCORRECT_AND_AUTOCAPITALIZE and remove the IOS prefix.

* wtf/FeatureDefines.h:

Tools:

Add new test case to check the purpose and hints API.

* TestWebKitAPI/Tests/WebKitGLib/TestInputMethodContext.cpp:
(testWebKitInputMethodContextContentType):
(beforeAll):

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

60 files changed:
ChangeLog
PerformanceTests/ChangeLog
PerformanceTests/StitchMarker/wtf/FeatureDefines.h
Source/WTF/ChangeLog
Source/WTF/wtf/FeatureDefines.h
Source/WebCore/ChangeLog
Source/WebCore/Sources.txt
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/html/Autocapitalize.cpp
Source/WebCore/html/Autocapitalize.h
Source/WebCore/html/HTMLElement.cpp
Source/WebCore/html/HTMLElement.h
Source/WebCore/html/HTMLElement.idl
Source/WebCore/html/HTMLFormControlElement.cpp
Source/WebCore/html/HTMLFormControlElement.h
Source/WebCore/html/HTMLFormElement.cpp
Source/WebCore/html/HTMLFormElement.h
Source/WebCore/loader/EmptyClients.cpp
Source/WebCore/page/EditorClient.h
Source/WebCore/page/FocusController.cpp
Source/WebKit/ChangeLog
Source/WebKit/Scripts/webkit/messages.py
Source/WebKit/Shared/glib/InputMethodState.cpp [new file with mode: 0644]
Source/WebKit/Shared/glib/InputMethodState.h [new file with mode: 0644]
Source/WebKit/SourcesGTK.txt
Source/WebKit/SourcesWPE.txt
Source/WebKit/UIProcess/API/glib/InputMethodFilter.cpp
Source/WebKit/UIProcess/API/glib/InputMethodFilter.h
Source/WebKit/UIProcess/API/glib/WebKitInputMethodContext.cpp
Source/WebKit/UIProcess/API/gtk/WebKitInputMethodContext.h
Source/WebKit/UIProcess/API/gtk/WebKitInputMethodContextImplGtk.cpp
Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp
Source/WebKit/UIProcess/API/gtk/WebKitWebViewBasePrivate.h
Source/WebKit/UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt
Source/WebKit/UIProcess/API/wpe/PageClientImpl.cpp
Source/WebKit/UIProcess/API/wpe/PageClientImpl.h
Source/WebKit/UIProcess/API/wpe/WPEView.cpp
Source/WebKit/UIProcess/API/wpe/WPEView.h
Source/WebKit/UIProcess/API/wpe/WebKitInputMethodContext.h
Source/WebKit/UIProcess/API/wpe/docs/wpe-1.0-sections.txt
Source/WebKit/UIProcess/WebPageProxy.h
Source/WebKit/UIProcess/WebPageProxy.messages.in
Source/WebKit/UIProcess/gtk/WebPageProxyGtk.cpp
Source/WebKit/UIProcess/wpe/WebPageProxyWPE.cpp
Source/WebKit/WebProcess/WebCoreSupport/WebEditorClient.cpp
Source/WebKit/WebProcess/WebCoreSupport/WebEditorClient.h
Source/WebKit/WebProcess/WebPage/WebPage.h
Source/WebKit/WebProcess/WebPage/glib/WebPageGLib.cpp
Source/WebKitLegacy/mac/ChangeLog
Source/WebKitLegacy/mac/DOM/DOMHTMLElement.mm
Source/WebKitLegacy/mac/WebCoreSupport/WebEditorClient.h
Source/WebKitLegacy/mac/WebCoreSupport/WebEditorClient.mm
Source/WebKitLegacy/win/ChangeLog
Source/WebKitLegacy/win/WebCoreSupport/WebEditorClient.cpp
Source/WebKitLegacy/win/WebCoreSupport/WebEditorClient.h
Source/cmake/OptionsGTK.cmake
Source/cmake/OptionsWPE.cmake
Source/cmake/WebKitFeatures.cmake
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WebKitGLib/TestInputMethodContext.cpp

index 0c905f4..91a11ec 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2020-01-07  Carlos Garcia Campos  <cgarcia@igalia.com>
+
+        [GTK][WPE] Add API to set purpose and hints of active editable element to input methods
+        https://bugs.webkit.org/show_bug.cgi?id=205605
+
+        Reviewed by Žan Doberšek.
+
+        Add ENABLE_AUTOCAPITALIZE build flag. It's private and disabled by default, enabled in GTK and WPE ports.
+
+        * Source/cmake/OptionsGTK.cmake:
+        * Source/cmake/OptionsWPE.cmake:
+        * Source/cmake/WebKitFeatures.cmake:
+
 2020-01-06  Yoshiaki Jitsukawa  <yoshiaki.jitsukawa@sony.com>
 
         [PlayStation] Update port cmake
index f6260b3..baf204e 100644 (file)
@@ -1,3 +1,14 @@
+2020-01-07  Carlos Garcia Campos  <cgarcia@igalia.com>
+
+        [GTK][WPE] Add API to set purpose and hints of active editable element to input methods
+        https://bugs.webkit.org/show_bug.cgi?id=205605
+
+        Reviewed by Žan Doberšek.
+
+        Split ENABLE_IOS_AUTOCORRECT_AND_AUTOCAPITALIZE and remove the IOS prefix.
+
+        * StitchMarker/wtf/FeatureDefines.h:
+
 2020-01-06  Mark Lam  <mark.lam@apple.com>
 
         Convert ASSERT_DISABLED to ASSERT_ENABLED, and fix some tests of NDEBUG that should actually test for ASSERT_ENABLED.
index e1b6ffe..27a6176 100644 (file)
 #define ENABLE_LETTERPRESS 1
 #endif
 
-#if !defined(ENABLE_IOS_AUTOCORRECT_AND_AUTOCAPITALIZE)
-#define ENABLE_IOS_AUTOCORRECT_AND_AUTOCAPITALIZE 1
+#if !defined(ENABLE_AUTOCORRECT)
+#define ENABLE_AUTOCORRECT 1
+#endif
+
+#if !defined(ENABLE_AUTOCAPITALIZE)
+#define ENABLE_AUTOCAPITALIZE 1
 #endif
 
 #if !defined(ENABLE_IOS_GESTURE_EVENTS) && USE(APPLE_INTERNAL_SDK)
index cb566f6..9b3210c 100644 (file)
@@ -1,3 +1,14 @@
+2020-01-07  Carlos Garcia Campos  <cgarcia@igalia.com>
+
+        [GTK][WPE] Add API to set purpose and hints of active editable element to input methods
+        https://bugs.webkit.org/show_bug.cgi?id=205605
+
+        Reviewed by Žan Doberšek.
+
+        Split ENABLE_IOS_AUTOCORRECT_AND_AUTOCAPITALIZE and remove the IOS prefix.
+
+        * wtf/FeatureDefines.h:
+
 2020-01-06  Don Olmstead  <don.olmstead@sony.com>
 
         Rename GraphicsContext3D to GraphicsContextGL
index 9804593..66d7fd5 100644 (file)
 #define ENABLE_LETTERPRESS 1
 #endif
 
-#if !defined(ENABLE_IOS_AUTOCORRECT_AND_AUTOCAPITALIZE)
-#define ENABLE_IOS_AUTOCORRECT_AND_AUTOCAPITALIZE 1
+#if !defined(ENABLE_AUTOCORRECT)
+#define ENABLE_AUTOCORRECT 1
+#endif
+
+#if !defined(ENABLE_AUTOCAPITALIZE)
+#define ENABLE_AUTOCAPITALIZE 1
 #endif
 
 #if !defined(ENABLE_IOS_GESTURE_EVENTS) && USE(APPLE_INTERNAL_SDK)
index da3ab8d..dc32af9 100644 (file)
@@ -1,3 +1,27 @@
+2020-01-07  Carlos Garcia Campos  <cgarcia@igalia.com>
+
+        [GTK][WPE] Add API to set purpose and hints of active editable element to input methods
+        https://bugs.webkit.org/show_bug.cgi?id=205605
+
+        Reviewed by Žan Doberšek.
+
+        Use ENABLE(AUTOCAPITALIZE) and ENABLE(AUTOCORRECT) instead of ENABLE(IOS_AUTOCORRECT_AND_AUTOCAPITALIZE).
+
+        * Sources.txt: Add Autocapitalize.cpp to the build.
+        * html/Autocapitalize.cpp: Add ENABLE(AUTOCAPITALIZE) guards.
+        * html/Autocapitalize.h: Ditto.
+        * html/HTMLElement.cpp:
+        * html/HTMLElement.h:
+        * html/HTMLElement.idl:
+        * html/HTMLFormControlElement.cpp:
+        * html/HTMLFormControlElement.h:
+        * html/HTMLFormElement.cpp:
+        * html/HTMLFormElement.h:
+        * loader/EmptyClients.cpp: Update to new API of EditorClient::setInputMethodState
+        * page/EditorClient.h: The focused element or nullptr is now received by setInputMethodState() instead of enabled/disabled boolean.
+        * page/FocusController.cpp:
+        (WebCore::FocusController::setFocusedElement): Pass the focused element or nullptr to setInputMethodState().
+
 2020-01-07  Philippe Normand  <pnormand@igalia.com>
 
         [GStreamer] mediastreamsrc ref sinked triggers critical warning in gst 1.17
index acae6fe..60bbbfd 100644 (file)
@@ -1095,6 +1095,7 @@ history/CachedFrame.cpp
 history/CachedPage.cpp
 history/HistoryItem.cpp
 
+html/Autocapitalize.cpp
 html/Autofill.cpp
 html/BaseButtonInputType.cpp
 html/BaseCheckableInputType.cpp
index d4fb0d3..ec4084d 100644 (file)
                A5CE9F3F1E4C4174001BBE7C /* ResourceTiming.h in Headers */ = {isa = PBXBuildFile; fileRef = A5CE9F3C1E4BC586001BBE7C /* ResourceTiming.h */; };
                A5DEBDA416FB908700836FE0 /* WebKitPlaybackTargetAvailabilityEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = A5DEBDA016FB908700836FE0 /* WebKitPlaybackTargetAvailabilityEvent.h */; };
                A5F36D3B18F758720054C024 /* PageScriptDebugServer.h in Headers */ = {isa = PBXBuildFile; fileRef = A5F36D3918F758720054C024 /* PageScriptDebugServer.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               A5F6E16B132ED46E008EDAE3 /* Autocapitalize.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5F6E16C132ED46E008EDAE3 /* Autocapitalize.cpp */; };
                A6148A7912E41E3B0044A784 /* JSHTMLKeygenElement.h in Headers */ = {isa = PBXBuildFile; fileRef = A6148A7712E41E3B0044A784 /* JSHTMLKeygenElement.h */; };
                A6D169641346B4C1000EB770 /* ShadowRoot.h in Headers */ = {isa = PBXBuildFile; fileRef = A6D169631346B4C1000EB770 /* ShadowRoot.h */; settings = {ATTRIBUTES = (Private, ); }; };
                A6D5A99C1629D70000297330 /* ScrollingTreeScrollingNodeDelegate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A6D5A99A1629D6FF00297330 /* ScrollingTreeScrollingNodeDelegate.cpp */; };
                                BE88E0DB1715D2A200658D98 /* AudioTrackList.cpp in Sources */,
                                CDE3A85717F6020400C5BE20 /* AudioTrackPrivateAVFObjC.mm in Sources */,
                                CD54A762180F9F7000B076C9 /* AudioTrackPrivateMediaSourceAVFObjC.cpp in Sources */,
-                               A5F6E16B132ED46E008EDAE3 /* Autocapitalize.cpp in Sources */,
                                0719427F1D088F21002AA51D /* AVAssetMIMETypeCache.mm in Sources */,
                                CDECA89A1EDF447D00DCB08B /* AVAssetTrackUtilities.mm in Sources */,
                                CDC675221EAEA9B700727C84 /* AVAudioSessionCaptureDeviceManager.mm in Sources */,
index 218f3db..3a0f911 100644 (file)
@@ -26,6 +26,8 @@
 #include "config.h"
 #include "Autocapitalize.h"
 
+#if ENABLE(AUTOCAPITALIZE)
+
 #include <wtf/NeverDestroyed.h>
 
 namespace WebCore {
@@ -77,3 +79,5 @@ const AtomString& stringForAutocapitalizeType(AutocapitalizeType type)
 }
 
 } // namespace WebCore
+
+#endif // ENABLE(AUTOCAPITALIZE)
index 9151bc1..1c052fe 100644 (file)
@@ -25,6 +25,8 @@
 
 #pragma once
 
+#if ENABLE(AUTOCAPITALIZE)
+
 #include "AutocapitalizeTypes.h"
 #include <wtf/text/AtomString.h>
 
@@ -34,3 +36,5 @@ AutocapitalizeType autocapitalizeTypeForAttributeValue(const AtomString&);
 const AtomString& stringForAutocapitalizeType(AutocapitalizeType);
 
 } // namespace WebCore
+
+#endif // ENABLE(AUTOCAPITALIZE)
index 7ab1ff5..0a0cb09 100644 (file)
@@ -1069,7 +1069,7 @@ bool HTMLElement::isActuallyDisabled() const
     return canBeActuallyDisabled() && isDisabledFormControl();
 }
 
-#if ENABLE(IOS_AUTOCORRECT_AND_AUTOCAPITALIZE)
+#if ENABLE(AUTOCAPITALIZE)
 
 const AtomString& HTMLElement::autocapitalize() const
 {
@@ -1086,6 +1086,10 @@ void HTMLElement::setAutocapitalize(const AtomString& value)
     setAttributeWithoutSynchronization(autocapitalizeAttr, value);
 }
 
+#endif
+
+#if ENABLE(AUTOCORRECT)
+
 bool HTMLElement::shouldAutocorrect() const
 {
     auto& autocorrectValue = attributeWithoutSynchronization(HTMLNames::autocorrectAttr);
index d2cf695..f1020bb 100644 (file)
@@ -22,7 +22,7 @@
 
 #pragma once
 
-#if ENABLE(IOS_AUTOCORRECT_AND_AUTOCAPITALIZE)
+#if ENABLE(AUTOCAPITALIZE)
 #include "Autocapitalize.h"
 #endif
 
@@ -102,11 +102,13 @@ public:
     bool canBeActuallyDisabled() const;
     bool isActuallyDisabled() const;
 
-#if ENABLE(IOS_AUTOCORRECT_AND_AUTOCAPITALIZE)
+#if ENABLE(AUTOCAPITALIZE)
     WEBCORE_EXPORT virtual AutocapitalizeType autocapitalizeType() const;
     WEBCORE_EXPORT const AtomString& autocapitalize() const;
     WEBCORE_EXPORT void setAutocapitalize(const AtomString& value);
+#endif
 
+#if ENABLE(AUTOCORRECT)
     bool autocorrect() const { return shouldAutocorrect(); }
     WEBCORE_EXPORT virtual bool shouldAutocorrect() const;
     WEBCORE_EXPORT void setAutocorrect(bool);
index a1f843d..6292cfa 100644 (file)
@@ -58,8 +58,8 @@
     [CEReactions] attribute [TreatNullAs=EmptyString] DOMString outerText;
 
     // iOS autocorrect / autocapitalization extensions.
-    [Conditional=IOS_AUTOCORRECT_AND_AUTOCAPITALIZE, CEReactions] attribute boolean autocorrect;
-    [Conditional=IOS_AUTOCORRECT_AND_AUTOCAPITALIZE, CEReactions] attribute [TreatNullAs=EmptyString] DOMString autocapitalize;
+    [Conditional=AUTOCORRECT, CEReactions] attribute boolean autocorrect;
+    [Conditional=AUTOCAPITALIZE, CEReactions] attribute [TreatNullAs=EmptyString] DOMString autocapitalize;
 
     // FIXME: We are the only browser to support this now that Blink dropped it (http://crbug.com/688943).
     [CEReactions, Reflect] attribute DOMString webkitdropzone;
index e0c2e0f..d611bc1 100644 (file)
@@ -615,7 +615,7 @@ void HTMLFormControlElement::dispatchBlurEvent(RefPtr<Element>&& newFocusedEleme
     hideVisibleValidationMessage();
 }
 
-#if ENABLE(IOS_AUTOCORRECT_AND_AUTOCAPITALIZE)
+#if ENABLE(AUTOCORRECT)
 
 // FIXME: We should look to share this code with class HTMLFormElement instead of duplicating the logic.
 
@@ -629,6 +629,10 @@ bool HTMLFormControlElement::shouldAutocorrect() const
     return true;
 }
 
+#endif
+
+#if ENABLE(AUTOCAPITALIZE)
+
 AutocapitalizeType HTMLFormControlElement::autocapitalizeType() const
 {
     AutocapitalizeType type = HTMLElement::autocapitalizeType();
index cfc978e..61340bf 100644 (file)
@@ -27,7 +27,7 @@
 #include "FormAssociatedElement.h"
 #include "LabelableElement.h"
 
-#if ENABLE(IOS_AUTOCORRECT_AND_AUTOCAPITALIZE)
+#if ENABLE(AUTOCAPITALIZE)
 #include "Autocapitalize.h"
 #endif
 
@@ -91,8 +91,11 @@ public:
     virtual bool isActivatedSubmit() const { return false; }
     virtual void setActivatedSubmit(bool) { }
 
-#if ENABLE(IOS_AUTOCORRECT_AND_AUTOCAPITALIZE)
+#if ENABLE(AUTOCORRECT)
     WEBCORE_EXPORT bool shouldAutocorrect() const final;
+#endif
+
+#if ENABLE(AUTOCAPITALIZE)
     WEBCORE_EXPORT AutocapitalizeType autocapitalizeType() const final;
 #endif
 
index 15ad57f..e7e414c 100644 (file)
@@ -406,7 +406,7 @@ void HTMLFormElement::resetAssociatedFormControlElements()
         associatedFormControlElement->reset();
 }
 
-#if ENABLE(IOS_AUTOCORRECT_AND_AUTOCAPITALIZE)
+#if ENABLE(AUTOCORRECT)
 
 // FIXME: We should look to share this code with class HTMLFormControlElement instead of duplicating the logic.
 
index b2171d7..47e39fd 100644 (file)
 #include <wtf/IsoMalloc.h>
 #include <wtf/WeakHashSet.h>
 
-#if ENABLE(IOS_AUTOCORRECT_AND_AUTOCAPITALIZE)
-#include "Autocapitalize.h"
-#endif
-
 namespace WebCore {
 
 class Event;
@@ -67,7 +63,7 @@ public:
     WEBCORE_EXPORT void setAutocomplete(const AtomString&);
     WEBCORE_EXPORT const AtomString& autocomplete() const;
 
-#if ENABLE(IOS_AUTOCORRECT_AND_AUTOCAPITALIZE)
+#if ENABLE(AUTOCORRECT)
     WEBCORE_EXPORT bool shouldAutocorrect() const final;
 #endif
 
index 0eb5a12..84e4e18 100644 (file)
@@ -299,7 +299,7 @@ private:
     bool spellingUIIsShowing() final { return false; }
 
     void willSetInputMethodState() final { }
-    void setInputMethodState(bool) final { }
+    void setInputMethodState(Element*) final { }
 
     bool canShowFontPanel() const final { return false; }
 
index ca7b686..936730f 100644 (file)
@@ -179,7 +179,7 @@ public:
     virtual void showSpellingUI(bool show) = 0;
     virtual bool spellingUIIsShowing() = 0;
     virtual void willSetInputMethodState() = 0;
-    virtual void setInputMethodState(bool enabled) = 0;
+    virtual void setInputMethodState(Element*) = 0;
 
     // Support for global selections, used on platforms like the X Window System that treat
     // selection as a type of clipboard.
index e5940dd..e79f785 100644 (file)
@@ -835,14 +835,14 @@ bool FocusController::setFocusedElement(Element* element, Frame& newFocusedFrame
     if (!element) {
         if (oldDocument)
             oldDocument->setFocusedElement(nullptr);
-        m_page.editorClient().setInputMethodState(false);
+        m_page.editorClient().setInputMethodState(nullptr);
         return true;
     }
 
     Ref<Document> newDocument(element->document());
 
     if (newDocument->focusedElement() == element) {
-        m_page.editorClient().setInputMethodState(element->shouldUseInputMethod());
+        m_page.editorClient().setInputMethodState(element);
         return true;
     }
     
@@ -862,7 +862,7 @@ bool FocusController::setFocusedElement(Element* element, Frame& newFocusedFrame
         return false;
 
     if (newDocument->focusedElement() == element)
-        m_page.editorClient().setInputMethodState(element->shouldUseInputMethod());
+        m_page.editorClient().setInputMethodState(element);
 
     m_focusSetTime = MonotonicTime::now();
     m_focusRepaintTimer.stop();
index 53fd6c2..52d2398 100644 (file)
@@ -1,5 +1,86 @@
 2020-01-07  Carlos Garcia Campos  <cgarcia@igalia.com>
 
+        [GTK][WPE] Add API to set purpose and hints of active editable element to input methods
+        https://bugs.webkit.org/show_bug.cgi?id=205605
+
+        Reviewed by Žan Doberšek.
+
+        Add input-purpose and input-hints properties to WebKitInputMethodContext. The message SetInputMethodState now
+        receives an optional InputMethodState struct with information about the purpose and hints of the active editable
+        element.
+
+        * Scripts/webkit/messages.py: Only include InputMethodState.h for GTK and WPE.
+        * Shared/glib/InputMethodState.cpp: Added.
+        (WebKit::InputMethodState::setPurposeOrHintForInputMode):
+        (WebKit::inputElementHasDigitsPattern):
+        (WebKit::InputMethodState::setPurposeForInputElement):
+        (WebKit::InputMethodState::addHintsForAutocapitalizeType):
+        (WebKit::InputMethodState::encode const):
+        (WebKit::InputMethodState::decode):
+        * Shared/glib/InputMethodState.h: Added.
+        (WebKit::operator==):
+        * SourcesGTK.txt:
+        * SourcesWPE.txt:
+        * UIProcess/API/glib/InputMethodFilter.cpp:
+        (WebKit::InputMethodFilter::setContext): Use isEnabled() instead of m_enabled.
+        (WebKit::InputMethodFilter::setState): Now receives an optional InputMethodState struct.
+        (WebKit::InputMethodFilter::filterKeyEvent): Use isEnabled() instead of m_enabled.
+        (WebKit::InputMethodFilter::isViewFocused const): Ditto.
+        (WebKit::toWebKitPurpose): Helper to convert InputMethodState::Purpose to WebKitInputPurpose.
+        (WebKit::toWebKitHints): Helper to convert InputMethodState::Hint to WebKitInputHints.
+        (WebKit::InputMethodFilter::notifyFocusedIn): Set the purpose and hints to the context.
+        (WebKit::InputMethodFilter::notifyFocusedOut): Use isEnabled() instead of m_enabled.
+        (WebKit::InputMethodFilter::notifyCursorRect): Ditto.
+        (WebKit::InputMethodFilter::preeditStarted): Ditto.
+        (WebKit::InputMethodFilter::preeditChanged): Ditto.
+        (WebKit::InputMethodFilter::preeditFinished): Ditto.
+        (WebKit::InputMethodFilter::committed): Ditto.
+        * UIProcess/API/glib/InputMethodFilter.h:
+        (WebKit::InputMethodFilter::isEnabled const): Return true if we have a state.
+        * UIProcess/API/glib/WebKitInputMethodContext.cpp:
+        (webkitInputMethodContextSetProperty): Properties setter.
+        (webkitInputMethodContextGetProperty): Properties getter.
+        (webkit_input_method_context_class_init): Add implementation for properties getter and setter.
+        (webkit_input_method_context_get_input_purpose):
+        (webkit_input_method_context_set_input_purpose):
+        (webkit_input_method_context_get_input_hints):
+        (webkit_input_method_context_set_input_hints):
+        * UIProcess/API/gtk/WebKitInputMethodContext.h:
+        * UIProcess/API/gtk/WebKitInputMethodContextImplGtk.cpp:
+        (toGtkInputPurpose): Helper to convert WebKitInputPurpose to GtkInputPurpose.
+        (toGtkInputHints): Helper to convert WebKitInputHints to GtkInputHints.
+        (inputPurposeChangedCallback): Set the purpose on GtkIMContext.
+        (inputHintsChangedCallback): Set the hints on GtkIMContext.
+        (webkitInputMethodContextImplGtkConstructed): Connect to notify signal for input-purpose and input-hints
+        properties of the context.
+        * UIProcess/API/gtk/WebKitWebViewBase.cpp:
+        (webkitWebViewBaseSetInputMethodState):
+        * UIProcess/API/gtk/WebKitWebViewBasePrivate.h:
+        * UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt:
+        * UIProcess/API/wpe/PageClientImpl.cpp:
+        (WebKit::PageClientImpl::setInputMethodState):
+        * UIProcess/API/wpe/PageClientImpl.h:
+        * UIProcess/API/wpe/WPEView.cpp:
+        (WKWPE::View::setInputMethodState):
+        * UIProcess/API/wpe/WPEView.h:
+        * UIProcess/API/wpe/WebKitInputMethodContext.h:
+        * UIProcess/API/wpe/docs/wpe-1.0-sections.txt:
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/WebPageProxy.messages.in:
+        * UIProcess/gtk/WebPageProxyGtk.cpp:
+        (WebKit::WebPageProxy::setInputMethodState):
+        * UIProcess/wpe/WebPageProxyWPE.cpp:
+        (WebKit::WebPageProxy::setInputMethodState):
+        * WebProcess/WebCoreSupport/WebEditorClient.cpp:
+        (WebKit::WebEditorClient::setInputMethodState):
+        * WebProcess/WebCoreSupport/WebEditorClient.h:
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/glib/WebPageGLib.cpp:
+        (WebKit::inputMethodSateForElement): Build an InputMethodState for the given element.
+        (WebKit::WebPage::setInputMethodState):
+
+2020-01-07  Carlos Garcia Campos  <cgarcia@igalia.com>
+
         WebDriver: several w3c collections tests added in r230953 are failing
         https://bugs.webkit.org/show_bug.cgi?id=184966
 
index c9d0e7c..5d84471 100644 (file)
@@ -234,6 +234,7 @@ def types_that_cannot_be_forward_declared():
 
 def conditions_for_header(header):
     conditions = {
+        '"InputMethodState.h"': ["PLATFORM(GTK)", "PLATFORM(WPE)"],
         '"LayerHostingContext.h"': ["PLATFORM(COCOA)", ],
     }
     if not header in conditions:
diff --git a/Source/WebKit/Shared/glib/InputMethodState.cpp b/Source/WebKit/Shared/glib/InputMethodState.cpp
new file mode 100644 (file)
index 0000000..6a19962
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2019 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "InputMethodState.h"
+
+#include "ArgumentCoders.h"
+#include <WebCore/HTMLInputElement.h>
+
+namespace WebKit {
+
+void InputMethodState::setPurposeOrHintForInputMode(WebCore::InputMode inputMode)
+{
+    switch (inputMode) {
+    case WebCore::InputMode::None:
+        hints.add(InputMethodState::Hint::InhibitOnScreenKeyboard);
+        break;
+    case WebCore::InputMode::Unspecified:
+    case WebCore::InputMode::Text:
+        purpose = Purpose::FreeForm;
+        break;
+    case WebCore::InputMode::Telephone:
+        purpose = Purpose::Phone;
+        break;
+    case WebCore::InputMode::Url:
+        purpose = Purpose::Url;
+        break;
+    case WebCore::InputMode::Email:
+        purpose = Purpose::Email;
+        break;
+    case WebCore::InputMode::Numeric:
+        purpose = Purpose::Digits;
+        break;
+    case WebCore::InputMode::Decimal:
+        purpose = Purpose::Number;
+        break;
+    case WebCore::InputMode::Search:
+        break;
+    }
+}
+
+static bool inputElementHasDigitsPattern(WebCore::HTMLInputElement& element)
+{
+    const auto& pattern = element.attributeWithoutSynchronization(WebCore::HTMLNames::patternAttr);
+    return pattern == "\\d*" || pattern == "[0-9]*";
+}
+
+void InputMethodState::setPurposeForInputElement(WebCore::HTMLInputElement& element)
+{
+    if (element.isPasswordField())
+        purpose = Purpose::Password;
+    else if (element.isEmailField())
+        purpose = Purpose::Email;
+    else if (element.isTelephoneField())
+        purpose = Purpose::Phone;
+    else if (element.isNumberField())
+        purpose = inputElementHasDigitsPattern(element) ? Purpose::Digits : Purpose::Number;
+    else if (element.isURLField())
+        purpose = Purpose::Url;
+    else if (element.isText() && inputElementHasDigitsPattern(element))
+        purpose = Purpose::Digits;
+}
+
+void InputMethodState::addHintsForAutocapitalizeType(AutocapitalizeType autocapitalizeType)
+{
+    switch (autocapitalizeType) {
+    case AutocapitalizeTypeDefault:
+        break;
+    case AutocapitalizeTypeNone:
+        hints.add(InputMethodState::Hint::Lowercase);
+        break;
+    case AutocapitalizeTypeWords:
+        hints.add(InputMethodState::Hint::UppercaseWords);
+        break;
+    case AutocapitalizeTypeSentences:
+        hints.add(InputMethodState::Hint::UppercaseSentences);
+        break;
+    case AutocapitalizeTypeAllCharacters:
+        hints.add(InputMethodState::Hint::UppercaseChars);
+        break;
+    }
+}
+
+void InputMethodState::encode(IPC::Encoder& encoder) const
+{
+    encoder.encodeEnum(purpose);
+    encoder << hints;
+}
+
+Optional<InputMethodState> InputMethodState::decode(IPC::Decoder& decoder)
+{
+    InputMethodState state;
+    if (!decoder.decodeEnum(state.purpose))
+        return WTF::nullopt;
+    if (!decoder.decode(state.hints))
+        return WTF::nullopt;
+    return state;
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit/Shared/glib/InputMethodState.h b/Source/WebKit/Shared/glib/InputMethodState.h
new file mode 100644 (file)
index 0000000..dfbf054
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2019 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <WebCore/AutocapitalizeTypes.h>
+#include <WebCore/InputMode.h>
+#include <wtf/OptionSet.h>
+#include <wtf/Optional.h>
+
+namespace IPC {
+class Decoder;
+class Encoder;
+}
+
+namespace WebCore {
+class HTMLInputElement;
+}
+
+namespace WebKit {
+
+struct InputMethodState {
+    enum class Purpose {
+        FreeForm,
+        Digits,
+        Number,
+        Phone,
+        Url,
+        Email,
+        Password
+    };
+
+    enum class Hint {
+        None = 0,
+        Spellcheck = 1 << 0,
+        Lowercase = 1 << 1,
+        UppercaseChars = 1 << 2,
+        UppercaseWords = 1 << 3,
+        UppercaseSentences = 1 << 4,
+        InhibitOnScreenKeyboard = 1 << 5
+    };
+
+    void setPurposeOrHintForInputMode(WebCore::InputMode);
+    void setPurposeForInputElement(WebCore::HTMLInputElement&);
+    void addHintsForAutocapitalizeType(AutocapitalizeType);
+
+    void encode(IPC::Encoder&) const;
+    static Optional<InputMethodState> decode(IPC::Decoder&);
+
+    Purpose purpose { Purpose::FreeForm };
+    OptionSet<Hint> hints;
+};
+
+inline bool operator==(const InputMethodState& a, const InputMethodState& b)
+{
+    return a.purpose == b.purpose && a.hints == b.hints;
+}
+
+} // namespace WebKit
index 5f68ab1..97cca34 100644 (file)
@@ -83,6 +83,7 @@ Shared/Plugins/unix/PluginSearchPath.cpp
 Shared/cairo/ShareableBitmapCairo.cpp
 
 Shared/glib/ArgumentCodersGLib.cpp
+Shared/glib/InputMethodState.cpp
 Shared/glib/ProcessExecutablePathGLib.cpp
 Shared/glib/UserMessage.cpp
 Shared/glib/WebContextMenuItemGlib.cpp
index f788d84..0c9dfe1 100644 (file)
@@ -81,6 +81,7 @@ Shared/Plugins/Netscape/unix/NetscapePluginModuleUnix.cpp
 Shared/cairo/ShareableBitmapCairo.cpp
 
 Shared/glib/ArgumentCodersGLib.cpp
+Shared/glib/InputMethodState.cpp
 Shared/glib/ProcessExecutablePathGLib.cpp
 Shared/glib/UserMessage.cpp
 Shared/glib/WebContextMenuItemGlib.cpp
index 769f41d..59f413a 100644 (file)
@@ -71,23 +71,23 @@ void InputMethodFilter::setContext(WebKitInputMethodContext* context)
     g_signal_connect_swapped(m_context.get(), "preedit-finished", G_CALLBACK(preeditFinishedCallback), this);
     g_signal_connect_swapped(m_context.get(), "committed", G_CALLBACK(committedCallback), this);
 
-    if (m_enabled && isViewFocused())
+    if (isEnabled() && isViewFocused())
         notifyFocusedIn();
 }
 
-void InputMethodFilter::setEnabled(bool enabled)
+void InputMethodFilter::setState(Optional<InputMethodState>&& state)
 {
-    if (!enabled)
+    if (!state)
         notifyFocusedOut();
 
-    m_enabled = enabled;
-    if (m_enabled && isViewFocused())
+    m_state = WTFMove(state);
+    if (isEnabled() && isViewFocused())
         notifyFocusedIn();
 }
 
 InputMethodFilter::FilterResult InputMethodFilter::filterKeyEvent(PlatformEventKey* keyEvent)
 {
-    if (!m_enabled || !m_context)
+    if (!isEnabled() || !m_context)
         return { };
 
     SetForScope<bool> filteringContextIsAcive(m_filteringContext.isActive, true);
@@ -110,7 +110,7 @@ InputMethodFilter::FilterResult InputMethodFilter::filterKeyEvent(PlatformEventK
 
 bool InputMethodFilter::isViewFocused() const
 {
-    if (!m_enabled || !m_context)
+    if (!isEnabled() || !m_context)
         return false;
 
 #if ENABLE(DEVELOPER_MODE) && PLATFORM(X11)
@@ -127,17 +127,60 @@ bool InputMethodFilter::isViewFocused() const
     return webkitWebViewGetPage(webView).isViewFocused();
 }
 
+static WebKitInputPurpose toWebKitPurpose(InputMethodState::Purpose purpose)
+{
+    switch (purpose) {
+    case InputMethodState::Purpose::FreeForm:
+        return WEBKIT_INPUT_PURPOSE_FREE_FORM;
+    case InputMethodState::Purpose::Digits:
+        return WEBKIT_INPUT_PURPOSE_DIGITS;
+    case InputMethodState::Purpose::Number:
+        return WEBKIT_INPUT_PURPOSE_NUMBER;
+    case InputMethodState::Purpose::Phone:
+        return WEBKIT_INPUT_PURPOSE_PHONE;
+    case InputMethodState::Purpose::Url:
+        return WEBKIT_INPUT_PURPOSE_URL;
+    case InputMethodState::Purpose::Email:
+        return WEBKIT_INPUT_PURPOSE_EMAIL;
+    case InputMethodState::Purpose::Password:
+        return WEBKIT_INPUT_PURPOSE_PASSWORD;
+    }
+
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
+static WebKitInputHints toWebKitHints(const OptionSet<InputMethodState::Hint>& hints)
+{
+    unsigned wkHints = 0;
+    if (hints.contains(InputMethodState::Hint::Spellcheck))
+        wkHints |= WEBKIT_INPUT_HINT_SPELLCHECK;
+    if (hints.contains(InputMethodState::Hint::Lowercase))
+        wkHints |= WEBKIT_INPUT_HINT_LOWERCASE;
+    if (hints.contains(InputMethodState::Hint::UppercaseChars))
+        wkHints |= WEBKIT_INPUT_HINT_UPPERCASE_CHARS;
+    if (hints.contains(InputMethodState::Hint::UppercaseWords))
+        wkHints |= WEBKIT_INPUT_HINT_UPPERCASE_WORDS;
+    if (hints.contains(InputMethodState::Hint::UppercaseSentences))
+        wkHints |= WEBKIT_INPUT_HINT_UPPERCASE_SENTENCES;
+    if (hints.contains(InputMethodState::Hint::InhibitOnScreenKeyboard))
+        wkHints |= WEBKIT_INPUT_HINT_INHIBIT_OSK;
+    return static_cast<WebKitInputHints>(wkHints);
+}
 void InputMethodFilter::notifyFocusedIn()
 {
-    if (!m_enabled || !m_context)
+    if (!isEnabled() || !m_context)
         return;
 
+    g_object_freeze_notify(G_OBJECT(m_context.get()));
+    webkit_input_method_context_set_input_purpose(m_context.get(), toWebKitPurpose(m_state->purpose));
+    webkit_input_method_context_set_input_hints(m_context.get(), toWebKitHints(m_state->hints));
+    g_object_thaw_notify(G_OBJECT(m_context.get()));
     webkit_input_method_context_notify_focus_in(m_context.get());
 }
 
 void InputMethodFilter::notifyFocusedOut()
 {
-    if (!m_enabled || !m_context)
+    if (!isEnabled() || !m_context)
         return;
 
     cancelComposition();
@@ -146,7 +189,7 @@ void InputMethodFilter::notifyFocusedOut()
 
 void InputMethodFilter::notifyCursorRect(const IntRect& cursorRect)
 {
-    if (!m_enabled || !m_context)
+    if (!isEnabled() || !m_context)
         return;
 
     // Don't move the window unless the cursor actually moves more than 10
@@ -163,7 +206,7 @@ void InputMethodFilter::notifyCursorRect(const IntRect& cursorRect)
 
 void InputMethodFilter::preeditStarted()
 {
-    if (!m_enabled)
+    if (!isEnabled())
         return;
 
     if (m_filteringContext.isActive)
@@ -174,7 +217,7 @@ void InputMethodFilter::preeditStarted()
 
 void InputMethodFilter::preeditChanged()
 {
-    if (!m_enabled)
+    if (!isEnabled())
         return;
 
     if (m_filteringContext.isActive)
@@ -208,7 +251,7 @@ void InputMethodFilter::preeditChanged()
 
 void InputMethodFilter::preeditFinished()
 {
-    if (!m_enabled)
+    if (!isEnabled())
         return;
 
     if (m_filteringContext.isActive)
@@ -227,7 +270,7 @@ void InputMethodFilter::preeditFinished()
 
 void InputMethodFilter::committed(const char* compositionString)
 {
-    if (!m_enabled)
+    if (!isEnabled())
         return;
 
     m_compositionResult = String::fromUTF8(compositionString);
index d723f35..1231038 100644 (file)
@@ -19,6 +19,7 @@
 
 #pragma once
 
+#include "InputMethodState.h"
 #include <WebCore/CompositionUnderline.h>
 #include <WebCore/IntPoint.h>
 #include <wtf/Noncopyable.h>
@@ -49,7 +50,7 @@ public:
     void setContext(WebKitInputMethodContext*);
     WebKitInputMethodContext* context() const { return m_context.get(); }
 
-    void setEnabled(bool);
+    void setState(Optional<InputMethodState>&&);
 
 #if PLATFORM(GTK)
     using PlatformEventKey = GdkEventKey;
@@ -80,12 +81,13 @@ private:
     void preeditFinished();
     void committed(const char*);
 
+    bool isEnabled() const { return !!m_state; }
     bool isViewFocused() const;
 
     WebCore::IntRect platformTransformCursorRectToViewCoordinates(const WebCore::IntRect&);
     bool platformEventKeyIsKeyPress(PlatformEventKey*) const;
 
-    bool m_enabled { false };
+    Optional<InputMethodState> m_state;
     GRefPtr<WebKitInputMethodContext> m_context;
 
     struct {
index caf7721..17cc3c9 100644 (file)
 #include "config.h"
 #include "WebKitInputMethodContext.h"
 
+#include "WebKitEnumTypes.h"
 #include "WebKitInputMethodContextPrivate.h"
 #include "WebKitWebView.h"
+#include <glib/gi18n-lib.h>
 #include <wtf/glib/WTFGType.h>
 
 using namespace WebCore;
@@ -45,6 +47,13 @@ using namespace WebCore;
  */
 
 enum {
+    PROP_0,
+
+    PROP_INPUT_PURPOSE,
+    PROP_INPUT_HINTS
+};
+
+enum {
     PREEDIT_STARTED,
     PREEDIT_CHANGED,
     PREEDIT_FINISHED,
@@ -116,6 +125,8 @@ void webkit_input_method_underline_free(WebKitInputMethodUnderline* underline)
 
 struct _WebKitInputMethodContextPrivate {
     WebKitWebView* webView;
+    WebKitInputPurpose purpose;
+    WebKitInputHints hints;
 };
 
 static guint signals[LAST_SIGNAL] = { 0, };
@@ -153,8 +164,80 @@ WEBKIT_DEFINE_ABSTRACT_TYPE(WebKitInputMethodContext, webkit_input_method_contex
  * Since: 2.28
  */
 
+static void webkitInputMethodContextSetProperty(GObject* object, guint propId, const GValue* value, GParamSpec* paramSpec)
+{
+    WebKitInputMethodContext* context = WEBKIT_INPUT_METHOD_CONTEXT(object);
+
+    switch (propId) {
+    case PROP_INPUT_PURPOSE:
+        webkit_input_method_context_set_input_purpose(context, static_cast<WebKitInputPurpose>(g_value_get_enum(value)));
+        break;
+    case PROP_INPUT_HINTS:
+        webkit_input_method_context_set_input_hints(context, static_cast<WebKitInputHints>(g_value_get_flags(value)));
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec);
+    }
+}
+
+static void webkitInputMethodContextGetProperty(GObject* object, guint propId, GValue* value, GParamSpec* paramSpec)
+{
+    WebKitInputMethodContext* context = WEBKIT_INPUT_METHOD_CONTEXT(object);
+
+    switch (propId) {
+    case PROP_INPUT_PURPOSE:
+        g_value_set_enum(value, webkit_input_method_context_get_input_purpose(context));
+        break;
+    case PROP_INPUT_HINTS:
+        g_value_set_flags(value, webkit_input_method_context_get_input_hints(context));
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec);
+    }
+}
+
 static void webkit_input_method_context_class_init(WebKitInputMethodContextClass* klass)
 {
+    GObjectClass* gObjectClass = G_OBJECT_CLASS(klass);
+    gObjectClass->set_property = webkitInputMethodContextSetProperty;
+    gObjectClass->get_property = webkitInputMethodContextGetProperty;
+
+    /**
+     * WebKitInputMethodContext::input-purpose:
+     *
+     * The #WebKitInputPurpose of the input associated with this context.
+     *
+     * Since: 2.28
+     */
+    g_object_class_install_property(
+        gObjectClass,
+        PROP_INPUT_PURPOSE,
+        g_param_spec_enum(
+            "input-purpose",
+            _("Input Purpose"),
+            _("The purpose of the input associated"),
+            WEBKIT_TYPE_INPUT_PURPOSE,
+            WEBKIT_INPUT_PURPOSE_FREE_FORM,
+            WEBKIT_PARAM_READWRITE));
+
+    /**
+     * WebKitInputMethodContext::input-hints:
+     *
+     * The #WebKitInputHints of the input associated with this context.
+     *
+     * Since: 2.28
+     */
+    g_object_class_install_property(
+        gObjectClass,
+        PROP_INPUT_HINTS,
+        g_param_spec_flags(
+            "input-hints",
+            _("Input Hints"),
+            _("The hints of the input associated"),
+            WEBKIT_TYPE_INPUT_HINTS,
+            WEBKIT_INPUT_HINT_NONE,
+            WEBKIT_PARAM_READWRITE));
+
     /**
      * WebKitInputMethodContext::preedit-started
      * @context: the #WebKitInputMethodContext on which the signal is emitted
@@ -359,3 +442,77 @@ void webkit_input_method_context_reset(WebKitInputMethodContext* context)
     if (imClass->reset)
         imClass->reset(context);
 }
+
+/**
+ * webkit_input_method_context_get_input_purpose:
+ * @context: a #WebKitInputMethodContext
+ *
+ * Get the value of the #WebKitInputMethodContext:input-purpose property.
+ *
+ * Returns: the #WebKitInputPurpose of the input associated with @context
+ *
+ * Since: 2.28
+ */
+WebKitInputPurpose webkit_input_method_context_get_input_purpose(WebKitInputMethodContext* context)
+{
+    g_return_val_if_fail(WEBKIT_IS_INPUT_METHOD_CONTEXT(context), WEBKIT_INPUT_PURPOSE_FREE_FORM);
+
+    return context->priv->purpose;
+}
+
+/**
+ * webkit_input_method_context_set_input_purpose:
+ * @context: a #WebKitInputMethodContext
+ * @purpose: a #WebKitInputPurpose
+ *
+ * Set the value of the #WebKitInputMethodContext:input-purpose property.
+ *
+ * Since: 2.28
+ */
+void webkit_input_method_context_set_input_purpose(WebKitInputMethodContext* context, WebKitInputPurpose purpose)
+{
+    g_return_if_fail(WEBKIT_IS_INPUT_METHOD_CONTEXT(context));
+
+    if (context->priv->purpose == purpose)
+        return;
+
+    context->priv->purpose = purpose;
+    g_object_notify(G_OBJECT(context), "input-purpose");
+}
+
+/**
+ * webkit_input_method_context_get_input_hints:
+ * @context: a #WebKitInputMethodContext
+ *
+ * Get the value of the #WebKitInputMethodContext:input-hints property.
+ *
+ * Returns: the #WebKitInputHints of the input associated with @context
+ *
+ * Since: 2.28
+ */
+WebKitInputHints webkit_input_method_context_get_input_hints(WebKitInputMethodContext* context)
+{
+    g_return_val_if_fail(WEBKIT_IS_INPUT_METHOD_CONTEXT(context), WEBKIT_INPUT_HINT_NONE);
+
+    return context->priv->hints;
+}
+
+/*
+ * webkit_input_method_context_set_input_hints:
+ * @context: a #WebKitInputMethodContext
+ * @hints: a #WebKitInputHints
+ *
+ * Set the value of the #WebKitInputMethodContext:input-hints property.
+ *
+ * Since: 2.28
+ */
+void webkit_input_method_context_set_input_hints(WebKitInputMethodContext* context, WebKitInputHints hints)
+{
+    g_return_if_fail(WEBKIT_IS_INPUT_METHOD_CONTEXT(context));
+
+    if (context->priv->hints == hints)
+        return;
+
+    context->priv->hints = hints;
+    g_object_notify(G_OBJECT(context), "input-hints");
+}
index b69f310..cf211af 100644 (file)
@@ -39,6 +39,54 @@ G_BEGIN_DECLS
 
 #define WEBKIT_TYPE_INPUT_METHOD_UNDERLINE          (webkit_input_method_underline_get_type())
 
+/**
+ * WebKitInputPurpose:
+ * @WEBKIT_INPUT_PURPOSE_FREE_FORM: Editable element expects any characters
+ * @WEBKIT_INPUT_PURPOSE_DIGITS: Editable element expects digits
+ * @WEBKIT_INPUT_PURPOSE_NUMBER: Editable element expects a number
+ * @WEBKIT_INPUT_PURPOSE_PHONE: Editable element expects a telephone
+ * @WEBKIT_INPUT_PURPOSE_URL: Editable element expects a URL
+ * @WEBKIT_INPUT_PURPOSE_EMAIL: Editable element expects an email
+ * @WEBKIT_INPUT_PURPOSE_PASSWORD: Editable element expects a password
+ *
+ * Enum values used to describe the primary purpose of the active editable element.
+ *
+ * Since: 2.28
+ */
+typedef enum {
+    WEBKIT_INPUT_PURPOSE_FREE_FORM,
+    WEBKIT_INPUT_PURPOSE_DIGITS,
+    WEBKIT_INPUT_PURPOSE_NUMBER,
+    WEBKIT_INPUT_PURPOSE_PHONE,
+    WEBKIT_INPUT_PURPOSE_URL,
+    WEBKIT_INPUT_PURPOSE_EMAIL,
+    WEBKIT_INPUT_PURPOSE_PASSWORD
+} WebKitInputPurpose;
+
+/**
+ * WebKitInputHints:
+ * @WEBKIT_INPUT_HINT_NONE: No special behavior suggested
+ * @WEBKIT_INPUT_HINT_SPELLCHECK: Suggest spell checking
+ * @WEBKIT_INPUT_HINT_LOWERCASE: Suggest to not autocapitlize
+ * @WEBKIT_INPUT_HINT_UPPERCASE_CHARS: Suggest to capitalize all text
+ * @WEBKIT_INPUT_HINT_UPPERCASE_WORDS: Suggest to capitalize the first character of each word
+ * @WEBKIT_INPUT_HINT_UPPERCASE_SENTENCES: Suggest to capitalize the first word of each sentence
+ * @WEBKIT_INPUT_HINT_INHIBIT_OSK: Suggest to not show an onscreen keyboard
+ *
+ * Enum values used to describe hints that might be taken into account by input methods.
+ *
+ * Since: 2.28
+ */
+typedef enum {
+    WEBKIT_INPUT_HINT_NONE                = 0,
+    WEBKIT_INPUT_HINT_SPELLCHECK          = 1 << 0,
+    WEBKIT_INPUT_HINT_LOWERCASE           = 1 << 1,
+    WEBKIT_INPUT_HINT_UPPERCASE_CHARS     = 1 << 2,
+    WEBKIT_INPUT_HINT_UPPERCASE_WORDS     = 1 << 3,
+    WEBKIT_INPUT_HINT_UPPERCASE_SENTENCES = 1 << 4,
+    WEBKIT_INPUT_HINT_INHIBIT_OSK         = 1 << 5
+} WebKitInputHints;
+
 typedef struct _WebKitInputMethodContext        WebKitInputMethodContext;
 typedef struct _WebKitInputMethodContextClass   WebKitInputMethodContextClass;
 typedef struct _WebKitInputMethodContextPrivate WebKitInputMethodContextPrivate;
@@ -140,6 +188,20 @@ WEBKIT_API void
 webkit_input_method_underline_set_color        (WebKitInputMethodUnderline *underline,
                                                 const GdkRGBA              *rgba);
 
+WEBKIT_API WebKitInputPurpose
+webkit_input_method_context_get_input_purpose  (WebKitInputMethodContext   *context);
+
+WEBKIT_API void
+webkit_input_method_context_set_input_purpose  (WebKitInputMethodContext   *context,
+                                                WebKitInputPurpose          purpose);
+
+WEBKIT_API WebKitInputHints
+webkit_input_method_context_get_input_hints    (WebKitInputMethodContext   *context);
+
+WEBKIT_API void
+webkit_input_method_context_set_input_hints    (WebKitInputMethodContext   *context,
+                                                WebKitInputHints            hints);
+
 
 G_END_DECLS
 
index 9453860..191f98d 100644 (file)
@@ -31,6 +31,56 @@ struct _WebKitInputMethodContextImplGtkPrivate {
 
 WEBKIT_DEFINE_TYPE(WebKitInputMethodContextImplGtk, webkit_input_method_context_impl_gtk, WEBKIT_TYPE_INPUT_METHOD_CONTEXT)
 
+static GtkInputPurpose toGtkInputPurpose(WebKitInputPurpose purpose)
+{
+    switch (purpose) {
+    case WEBKIT_INPUT_PURPOSE_FREE_FORM:
+        return GTK_INPUT_PURPOSE_FREE_FORM;
+    case WEBKIT_INPUT_PURPOSE_DIGITS:
+        return GTK_INPUT_PURPOSE_DIGITS;
+    case WEBKIT_INPUT_PURPOSE_NUMBER:
+        return GTK_INPUT_PURPOSE_NUMBER;
+    case WEBKIT_INPUT_PURPOSE_PHONE:
+        return GTK_INPUT_PURPOSE_PHONE;
+    case WEBKIT_INPUT_PURPOSE_URL:
+        return GTK_INPUT_PURPOSE_URL;
+    case WEBKIT_INPUT_PURPOSE_EMAIL:
+        return GTK_INPUT_PURPOSE_EMAIL;
+    case WEBKIT_INPUT_PURPOSE_PASSWORD:
+        return GTK_INPUT_PURPOSE_PASSWORD;
+    }
+
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
+static GtkInputHints toGtkInputHints(WebKitInputHints hints)
+{
+    unsigned gtkHints = 0;
+    if (hints & WEBKIT_INPUT_HINT_SPELLCHECK)
+        gtkHints |= GTK_INPUT_HINT_SPELLCHECK;
+    if (hints & WEBKIT_INPUT_HINT_LOWERCASE)
+        gtkHints |= GTK_INPUT_HINT_LOWERCASE;
+    if (hints & WEBKIT_INPUT_HINT_UPPERCASE_CHARS)
+        gtkHints |= GTK_INPUT_HINT_UPPERCASE_CHARS;
+    if (hints & WEBKIT_INPUT_HINT_UPPERCASE_WORDS)
+        gtkHints |= GTK_INPUT_HINT_UPPERCASE_WORDS;
+    if (hints & WEBKIT_INPUT_HINT_UPPERCASE_SENTENCES)
+        gtkHints |= GTK_INPUT_HINT_UPPERCASE_SENTENCES;
+    if (hints & WEBKIT_INPUT_HINT_INHIBIT_OSK)
+        gtkHints |= GTK_INPUT_HINT_INHIBIT_OSK;
+    return static_cast<GtkInputHints>(gtkHints);
+}
+
+static void inputPurposeChangedCallback(WebKitInputMethodContextImplGtk* context)
+{
+    g_object_set(context->priv->context.get(), "input-purpose", toGtkInputPurpose(webkit_input_method_context_get_input_purpose(WEBKIT_INPUT_METHOD_CONTEXT(context))), nullptr);
+}
+
+static void inputHintsChangedCallback(WebKitInputMethodContextImplGtk* context)
+{
+    g_object_set(context->priv->context.get(), "input-hints", toGtkInputHints(webkit_input_method_context_get_input_hints(WEBKIT_INPUT_METHOD_CONTEXT(context))), nullptr);
+}
+
 static void contextPreeditStartCallback(WebKitInputMethodContextImplGtk* context)
 {
     g_signal_emit_by_name(context, "preedit-started", nullptr);
@@ -55,6 +105,9 @@ static void webkitInputMethodContextImplGtkConstructed(GObject* object)
 {
     G_OBJECT_CLASS(webkit_input_method_context_impl_gtk_parent_class)->constructed(object);
 
+    g_signal_connect_swapped(object, "notify::input-purpose", G_CALLBACK(inputPurposeChangedCallback), object);
+    g_signal_connect_swapped(object, "notify::input-hints", G_CALLBACK(inputHintsChangedCallback), object);
+
     auto* priv = WEBKIT_INPUT_METHOD_CONTEXT_IMPL_GTK(object)->priv;
     priv->context = adoptGRef(gtk_im_multicontext_new());
     g_signal_connect_object(priv->context.get(), "preedit-start", G_CALLBACK(contextPreeditStartCallback), object, G_CONNECT_SWAPPED);
index 944db2e..0f147ed 100644 (file)
@@ -1666,9 +1666,9 @@ bool webkitWebViewBaseIsInWindow(WebKitWebViewBase* webViewBase)
     return webViewBase->priv->activityState.contains(ActivityState::IsInWindow);
 }
 
-void webkitWebViewBaseSetInputMethodState(WebKitWebViewBase* webkitWebViewBase, bool enabled)
+void webkitWebViewBaseSetInputMethodState(WebKitWebViewBase* webkitWebViewBase, Optional<InputMethodState>&& state)
 {
-    webkitWebViewBase->priv->inputMethodFilter.setEnabled(enabled);
+    webkitWebViewBase->priv->inputMethodFilter.setState(WTFMove(state));
 }
 
 void webkitWebViewBaseUpdateTextInputState(WebKitWebViewBase* webkitWebViewBase)
index d65a63c..1dfe181 100644 (file)
@@ -30,6 +30,7 @@
 #include "APIPageConfiguration.h"
 #include "DragAndDropHandler.h"
 #include "GestureController.h"
+#include "InputMethodState.h"
 #include "SameDocumentNavigationType.h"
 #include "ViewGestureController.h"
 #include "ViewSnapshotStore.h"
@@ -55,7 +56,7 @@ void webkitWebViewBaseSetInspectorViewSize(WebKitWebViewBase*, unsigned size);
 void webkitWebViewBaseSetActiveContextMenuProxy(WebKitWebViewBase*, WebKit::WebContextMenuProxyGtk*);
 WebKit::WebContextMenuProxyGtk* webkitWebViewBaseGetActiveContextMenuProxy(WebKitWebViewBase*);
 GdkEvent* webkitWebViewBaseTakeContextMenuEvent(WebKitWebViewBase*);
-void webkitWebViewBaseSetInputMethodState(WebKitWebViewBase*, bool enabled);
+void webkitWebViewBaseSetInputMethodState(WebKitWebViewBase*, Optional<WebKit::InputMethodState>&&);
 void webkitWebViewBaseUpdateTextInputState(WebKitWebViewBase*);
 void webkitWebViewBaseSetContentsSize(WebKitWebViewBase*, const WebCore::IntSize&);
 
index f1471b5..5206980 100644 (file)
@@ -1560,6 +1560,8 @@ WEBKIT_TYPE_GEOLOCATION_POSITION
 <SECTION>
 <FILE>WebKitInputMethodContext</FILE>
 WebKitInputMethodContext
+WebKitInputPurpose
+WebKitInputHints
 webkit_input_method_context_set_enable_preedit
 webkit_input_method_context_get_preedit
 webkit_input_method_context_filter_key_event
@@ -1567,6 +1569,10 @@ webkit_input_method_context_notify_focus_in
 webkit_input_method_context_notify_focus_out
 webkit_input_method_context_notify_cursor_area
 webkit_input_method_context_reset
+webkit_input_method_context_get_input_purpose
+webkit_input_method_context_set_input_purpose
+webkit_input_method_context_get_input_hints
+webkit_input_method_context_set_input_hints
 
 <SUBSECTION Underline>
 WebKitInputMethodUnderline
index da4a952..592d733 100644 (file)
@@ -430,9 +430,9 @@ void PageClientImpl::sendMessageToWebView(UserMessage&& message, CompletionHandl
     m_view.didReceiveUserMessage(WTFMove(message), WTFMove(completionHandler));
 }
 
-void PageClientImpl::setInputMethodState(bool enabled)
+void PageClientImpl::setInputMethodState(Optional<InputMethodState>&& state)
 {
-    m_view.setInputMethodState(enabled);
+    m_view.setInputMethodState(WTFMove(state));
 }
 
 void PageClientImpl::selectionDidChange()
index 7dcd8a1..a2f88f8 100644 (file)
@@ -42,6 +42,7 @@ enum class DOMPasteAccessResponse : uint8_t;
 namespace WebKit {
 
 class ScrollGestureController;
+struct InputMethodState;
 struct UserMessage;
 
 enum class UndoOrRedo : bool;
@@ -62,7 +63,7 @@ public:
 #endif
 
     void sendMessageToWebView(UserMessage&&, CompletionHandler<void(UserMessage&&)>&&);
-    void setInputMethodState(bool enabled);
+    void setInputMethodState(Optional<InputMethodState>&&);
 
 private:
     // PageClient
index ef65b7a..275bb0b 100644 (file)
@@ -231,9 +231,9 @@ WebKitInputMethodContext* View::inputMethodContext() const
     return m_inputMethodFilter.context();
 }
 
-void View::setInputMethodState(bool enabled)
+void View::setInputMethodState(Optional<InputMethodState>&& state)
 {
-    m_inputMethodFilter.setEnabled(enabled);
+    m_inputMethodFilter.setState(WTFMove(state));
 }
 
 void View::selectionDidChange()
index aa87072..f23dfc2 100644 (file)
@@ -81,7 +81,7 @@ public:
 
     void setInputMethodContext(WebKitInputMethodContext*);
     WebKitInputMethodContext* inputMethodContext() const;
-    void setInputMethodState(bool);
+    void setInputMethodState(Optional<WebKit::InputMethodState>&&);
     void synthesizeCompositionKeyPress(const String&, Optional<Vector<WebCore::CompositionUnderline>>&&, Optional<WebKit::EditingRange>&&);
 
     void selectionDidChange();
index 464e352..8285594 100644 (file)
@@ -40,6 +40,54 @@ G_BEGIN_DECLS
 
 #define WEBKIT_TYPE_INPUT_METHOD_UNDERLINE          (webkit_input_method_underline_get_type())
 
+/**
+ * WebKitInputPurpose:
+ * @WEBKIT_INPUT_PURPOSE_FREE_FORM: Editable element expects any characters
+ * @WEBKIT_INPUT_PURPOSE_DIGITS: Editable element expects digits
+ * @WEBKIT_INPUT_PURPOSE_NUMBER: Editable element expects a number
+ * @WEBKIT_INPUT_PURPOSE_PHONE: Editable element expects a telephone
+ * @WEBKIT_INPUT_PURPOSE_URL: Editable element expects a URL
+ * @WEBKIT_INPUT_PURPOSE_EMAIL: Editable element expects an email
+ * @WEBKIT_INPUT_PURPOSE_PASSWORD: Editable element expects a password
+ *
+ * Enum values used to describe the primary purpose of the active editable element.
+ *
+ * Since: 2.28
+ */
+typedef enum {
+    WEBKIT_INPUT_PURPOSE_FREE_FORM,
+    WEBKIT_INPUT_PURPOSE_DIGITS,
+    WEBKIT_INPUT_PURPOSE_NUMBER,
+    WEBKIT_INPUT_PURPOSE_PHONE,
+    WEBKIT_INPUT_PURPOSE_URL,
+    WEBKIT_INPUT_PURPOSE_EMAIL,
+    WEBKIT_INPUT_PURPOSE_PASSWORD
+} WebKitInputPurpose;
+
+/**
+ * WebKitInputHints:
+ * @WEBKIT_INPUT_HINT_NONE: No special behavior suggested
+ * @WEBKIT_INPUT_HINT_SPELLCHECK: Suggest spell checking
+ * @WEBKIT_INPUT_HINT_LOWERCASE: Suggest to not autocapitlize
+ * @WEBKIT_INPUT_HINT_UPPERCASE_CHARS: Suggest to capitalize all text
+ * @WEBKIT_INPUT_HINT_UPPERCASE_WORDS: Suggest to capitalize the first character of each word
+ * @WEBKIT_INPUT_HINT_UPPERCASE_SENTENCES: Suggest to capitalize the first word of each sentence
+ * @WEBKIT_INPUT_HINT_INHIBIT_OSK: Suggest to not show an onscreen keyboard
+ *
+ * Enum values used to describe hints that might be taken into account by input methods.
+ *
+ * Since: 2.28
+ */
+typedef enum {
+    WEBKIT_INPUT_HINT_NONE                = 0,
+    WEBKIT_INPUT_HINT_SPELLCHECK          = 1 << 0,
+    WEBKIT_INPUT_HINT_LOWERCASE           = 1 << 1,
+    WEBKIT_INPUT_HINT_UPPERCASE_CHARS     = 1 << 2,
+    WEBKIT_INPUT_HINT_UPPERCASE_WORDS     = 1 << 3,
+    WEBKIT_INPUT_HINT_UPPERCASE_SENTENCES = 1 << 4,
+    WEBKIT_INPUT_HINT_INHIBIT_OSK         = 1 << 5
+} WebKitInputHints;
+
 typedef struct _WebKitInputMethodContext        WebKitInputMethodContext;
 typedef struct _WebKitInputMethodContextClass   WebKitInputMethodContextClass;
 typedef struct _WebKitInputMethodContextPrivate WebKitInputMethodContextPrivate;
@@ -141,6 +189,20 @@ WEBKIT_API void
 webkit_input_method_underline_set_color        (WebKitInputMethodUnderline      *underline,
                                                 WebKitColor                     *color);
 
+WEBKIT_API WebKitInputPurpose
+webkit_input_method_context_get_input_purpose  (WebKitInputMethodContext        *context);
+
+WEBKIT_API void
+webkit_input_method_context_set_input_purpose  (WebKitInputMethodContext        *context,
+                                                WebKitInputPurpose               purpose);
+
+WEBKIT_API WebKitInputHints
+webkit_input_method_context_get_input_hints    (WebKitInputMethodContext        *context);
+
+WEBKIT_API void
+webkit_input_method_context_set_input_hints    (WebKitInputMethodContext        *context,
+                                                WebKitInputHints                 hints);
+
 
 G_END_DECLS
 
index f0b0a75..df4f846 100644 (file)
@@ -1445,6 +1445,8 @@ WEBKIT_TYPE_GEOLOCATION_POSITION
 <SECTION>
 <FILE>WebKitInputMethodContext</FILE>
 WebKitInputMethodContext
+WebKitInputPurpose
+WebKitInputHints
 webkit_input_method_context_set_enable_preedit
 webkit_input_method_context_get_preedit
 webkit_input_method_context_filter_key_event
@@ -1452,6 +1454,10 @@ webkit_input_method_context_notify_focus_in
 webkit_input_method_context_notify_focus_out
 webkit_input_method_context_notify_cursor_area
 webkit_input_method_context_reset
+webkit_input_method_context_get_input_purpose
+webkit_input_method_context_set_input_purpose
+webkit_input_method_context_get_input_hints
+webkit_input_method_context_set_input_hints
 
 <SUBSECTION Underline>
 WebKitInputMethodUnderline
index 2c87b48..0f266f3 100644 (file)
@@ -312,6 +312,7 @@ struct EditorState;
 struct FocusedElementInformation;
 struct FontInfo;
 struct FrameInfoData;
+struct InputMethodState;
 struct InsertTextOptions;
 struct InteractionInformationAtPosition;
 struct InteractionInformationRequest;
@@ -791,7 +792,7 @@ public:
 #if PLATFORM(GTK) || PLATFORM(WPE)
     void cancelComposition(const String& compositionString);
 
-    void setInputMethodState(bool enabled);
+    void setInputMethodState(Optional<InputMethodState>&&);
 #endif
 
 #if PLATFORM(GTK)
index 025fb2c..954f974 100644 (file)
@@ -219,7 +219,7 @@ messages -> WebPageProxy {
 #endif
 
 #if PLATFORM(GTK) || PLATFORM(WPE)
-    SetInputMethodState(bool enabled);
+    SetInputMethodState(Optional<WebKit::InputMethodState> state);
 #endif
 
     # BackForward messages
index 540e3bc..8ee86fa 100644 (file)
@@ -27,6 +27,7 @@
 #include "config.h"
 #include "WebPageProxy.h"
 
+#include "InputMethodState.h"
 #include "PageClientImpl.h"
 #include "WebKitUserMessage.h"
 #include "WebKitWebViewBasePrivate.h"
@@ -148,9 +149,9 @@ void WebPageProxy::windowedPluginVisibilityDidChange(bool isVisible, uint64_t wi
 }
 #endif // PLATFORM(X11)
 
-void WebPageProxy::setInputMethodState(bool enabled)
+void WebPageProxy::setInputMethodState(Optional<InputMethodState>&& state)
 {
-    webkitWebViewBaseSetInputMethodState(WEBKIT_WEB_VIEW_BASE(viewWidget()), enabled);
+    webkitWebViewBaseSetInputMethodState(WEBKIT_WEB_VIEW_BASE(viewWidget()), WTFMove(state));
 }
 
 void WebPageProxy::getCenterForZoomGesture(const WebCore::IntPoint& centerInViewCoordinates, WebCore::IntPoint& center)
index 718f212..8f640db 100644 (file)
@@ -27,6 +27,7 @@
 #include "WebPageProxy.h"
 
 #include "EditorState.h"
+#include "InputMethodState.h"
 #include "PageClientImpl.h"
 #include "WebsiteDataStore.h"
 #include <WebCore/NotImplemented.h>
@@ -95,9 +96,9 @@ void WebPageProxy::sendMessageToWebView(UserMessage&& message)
     sendMessageToWebViewWithReply(WTFMove(message), [](UserMessage&&) { });
 }
 
-void WebPageProxy::setInputMethodState(bool enabled)
+void WebPageProxy::setInputMethodState(Optional<InputMethodState>&& state)
 {
-    static_cast<PageClientImpl&>(pageClient()).setInputMethodState(enabled);
+    static_cast<PageClientImpl&>(pageClient()).setInputMethodState(WTFMove(state));
 }
 
 } // namespace WebKit
index da83e98..7e57aed 100644 (file)
@@ -604,13 +604,13 @@ void WebEditorClient::willSetInputMethodState()
 {
 }
 
-void WebEditorClient::setInputMethodState(bool enabled)
+void WebEditorClient::setInputMethodState(Element* element)
 {
 #if PLATFORM(GTK) || PLATFORM(WPE)
-    m_page->setInputMethodState(enabled);
+    m_page->setInputMethodState(element);
 #else
     notImplemented();
-    UNUSED_PARAM(enabled);
+    UNUSED_PARAM(element);
 #endif
 }
 
index a72ee2a..7281fb4 100644 (file)
@@ -167,7 +167,7 @@ private:
     bool spellingUIIsShowing() final;
     void getGuessesForWord(const String& word, const String& context, const WebCore::VisibleSelection& currentSelection, Vector<String>& guesses) final;
     void willSetInputMethodState() final;
-    void setInputMethodState(bool enabled) final;
+    void setInputMethodState(WebCore::Element*) final;
     void requestCheckingOfString(WebCore::TextCheckingRequest&, const WebCore::VisibleSelection& currentSelection) final;
 
 #if PLATFORM(GTK)
index b07cf17..9a94347 100644 (file)
@@ -100,6 +100,10 @@ typedef struct _AtkObject AtkObject;
 #include "WebPrintOperationGtk.h"
 #endif
 
+#if PLATFORM(GTK) || PLATFORM(WPE)
+#include "InputMethodState.h"
+#endif
+
 #if PLATFORM(IOS_FAMILY)
 #include "GestureTypes.h"
 #include <WebCore/IntPointHash.h>
@@ -1087,7 +1091,7 @@ public:
     void postMessageIgnoringFullySynchronousMode(const String& messageName, API::Object* messageBody);
 
 #if PLATFORM(GTK) || PLATFORM(WPE)
-    void setInputMethodState(bool);
+    void setInputMethodState(WebCore::Element*);
 #endif
 
     void imageOrMediaDocumentSizeChanged(const WebCore::IntSize&);
@@ -1960,7 +1964,7 @@ private:
     mutable EditorStateIsContentEditable m_lastEditorStateWasContentEditable { EditorStateIsContentEditable::Unset };
 
 #if PLATFORM(GTK) || PLATFORM(WPE)
-    bool m_inputMethodEnabled { false };
+    Optional<InputMethodState> m_inputMethodState;
 #endif
 
 #if ENABLE(VIDEO) && USE(GSTREAMER)
index 6d3980a..5d82c7d 100644 (file)
 #include "config.h"
 #include "WebPage.h"
 
+#include "InputMethodState.h"
 #include "UserMessage.h"
 #include "WebKitExtensionManager.h"
 #include "WebKitUserMessage.h"
 #include "WebKitWebExtension.h"
 #include "WebKitWebPagePrivate.h"
 #include "WebPageProxyMessages.h"
+#include <WebCore/HTMLInputElement.h>
+#include <WebCore/HTMLTextAreaElement.h>
 
 namespace WebKit {
+using namespace WebCore;
 
 void WebPage::sendMessageToWebExtensionWithReply(UserMessage&& message, CompletionHandler<void(UserMessage&&)>&& completionHandler)
 {
@@ -57,13 +61,36 @@ void WebPage::sendMessageToWebExtension(UserMessage&& message)
     sendMessageToWebExtensionWithReply(WTFMove(message), [](UserMessage&&) { });
 }
 
-void WebPage::setInputMethodState(bool enabled)
+static Optional<InputMethodState> inputMethodSateForElement(Element* element)
 {
-    if (m_inputMethodEnabled == enabled)
+    if (!element || !element->shouldUseInputMethod())
+        return WTF::nullopt;
+
+    InputMethodState state;
+    if (is<HTMLInputElement>(*element)) {
+        auto& inputElement = downcast<HTMLInputElement>(*element);
+        state.setPurposeForInputElement(inputElement);
+        state.addHintsForAutocapitalizeType(inputElement.autocapitalizeType());
+    } else if (is<HTMLTextAreaElement>(*element) || (element->hasEditableStyle() && is<HTMLElement>(*element))) {
+        auto& htmlElement = downcast<HTMLElement>(*element);
+        state.setPurposeOrHintForInputMode(htmlElement.canonicalInputMode());
+        state.addHintsForAutocapitalizeType(htmlElement.autocapitalizeType());
+    }
+
+    if (element->isSpellCheckingEnabled())
+        state.hints.add(InputMethodState::Hint::Spellcheck);
+
+    return state;
+}
+
+void WebPage::setInputMethodState(Element* element)
+{
+    auto state = inputMethodSateForElement(element);
+    if (m_inputMethodState == state)
         return;
 
-    m_inputMethodEnabled = enabled;
-    send(Messages::WebPageProxy::SetInputMethodState(enabled));
+    m_inputMethodState = state;
+    send(Messages::WebPageProxy::SetInputMethodState(state));
 }
 
 } // namespace WebKit
index 28721db..4c44cde 100644 (file)
@@ -1,3 +1,15 @@
+2020-01-07  Carlos Garcia Campos  <cgarcia@igalia.com>
+
+        [GTK][WPE] Add API to set purpose and hints of active editable element to input methods
+        https://bugs.webkit.org/show_bug.cgi?id=205605
+
+        Reviewed by Žan Doberšek.
+
+        * DOM/DOMHTMLElement.mm: Use ENABLE(AUTOCORRECT) and ENABLE(AUTOCAPITALIZE).
+        * WebCoreSupport/WebEditorClient.h: Update tom the new API to WebEditorClient::setInputMethodState.
+        * WebCoreSupport/WebEditorClient.mm:
+        (WebEditorClient::setInputMethodState): Ditto.
+
 2020-01-07  Chris Fleizach  <cfleizach@apple.com>
 
         AX: Enable ACCESSIBILITY_ISOLATED_TREE
index d03082f..77eef05 100644 (file)
     IMPL->click();
 }
 
-#if ENABLE(IOS_AUTOCORRECT_AND_AUTOCAPITALIZE)
+#if ENABLE(AUTOCORRECT)
 
 - (BOOL)autocorrect
 {
     IMPL->setAutocorrect(newAutocorrect);
 }
 
+#endif
+
+#if ENABLE(AUTOCAPITALIZE)
+
 - (NSString *)autocapitalize
 {
     WebCore::JSMainThreadNullState state;
index 138ffb8..c658b19 100644 (file)
@@ -166,7 +166,7 @@ private:
     void getGuessesForWord(const String& word, const String& context, const WebCore::VisibleSelection& currentSelection, Vector<String>& guesses) final;
 
     void willSetInputMethodState() final;
-    void setInputMethodState(bool enabled) final;
+    void setInputMethodState(WebCore::Element*) final;
     void requestCheckingOfString(WebCore::TextCheckingRequest&, const WebCore::VisibleSelection& currentSelection) final;
 
 #if PLATFORM(MAC)
index 13c8def..33b689d 100644 (file)
@@ -1098,7 +1098,7 @@ void WebEditorClient::willSetInputMethodState()
 {
 }
 
-void WebEditorClient::setInputMethodState(bool)
+void WebEditorClient::setInputMethodState(WebCore::Element*)
 {
 }
 
index 3ee9290..1955823 100644 (file)
@@ -1,3 +1,16 @@
+2020-01-07  Carlos Garcia Campos  <cgarcia@igalia.com>
+
+        [GTK][WPE] Add API to set purpose and hints of active editable element to input methods
+        https://bugs.webkit.org/show_bug.cgi?id=205605
+
+        Reviewed by Žan Doberšek.
+
+        Update to the new API of WebEditorClient::setInputMethodState.
+
+        * WebCoreSupport/WebEditorClient.cpp:
+        (WebEditorClient::setInputMethodState):
+        * WebCoreSupport/WebEditorClient.h:
+
 2020-01-06  Mark Lam  <mark.lam@apple.com>
 
         Convert ASSERT_DISABLED to ASSERT_ENABLED, and fix some tests of NDEBUG that should actually test for ASSERT_ENABLED.
index 8f9a29d..8df1c72 100644 (file)
@@ -887,7 +887,7 @@ void WebEditorClient::willSetInputMethodState()
 {
 }
 
-void WebEditorClient::setInputMethodState(bool enabled)
+void WebEditorClient::setInputMethodState(WebCore::Element* element)
 {
-    m_webView->setInputMethodState(enabled);
+    m_webView->setInputMethodState(element && element->shouldUseInputMethod());
 }
index 57ecf77..77f6436 100644 (file)
@@ -113,7 +113,7 @@ private:
     void getGuessesForWord(const WTF::String& word, const WTF::String& context, const WebCore::VisibleSelection& currentSelection, WTF::Vector<WTF::String>& guesses) final;
 
     void willSetInputMethodState() final;
-    void setInputMethodState(bool) final;
+    void setInputMethodState(WebCore::Element*) final;
     void requestCheckingOfString(WebCore::TextCheckingRequest&, const WebCore::VisibleSelection&) final { }
     bool performTwoStepDrop(WebCore::DocumentFragment&, WebCore::Range&, bool) final { return false; }
 
index ba7f352..bf3deac 100644 (file)
@@ -150,6 +150,7 @@ WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_WEBDRIVER PUBLIC ON)
 # Private options shared with other WebKit ports. Add options here when
 # we need a value different from the default defined in WebKitFeatures.cmake.
 # Changing these options is completely unsupported.
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_AUTOCAPITALIZE PRIVATE ON)
 WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_CONTENT_EXTENSIONS PRIVATE ON)
 WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_DARK_MODE_CSS PRIVATE ON)
 WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_DATALIST_ELEMENT PRIVATE ON)
index 8d2fd41..685a8c4 100644 (file)
@@ -48,6 +48,7 @@ WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_XSLT PUBLIC ON)
 # we need a value different from the default defined in WebKitFeatures.cmake.
 # Changing these options is completely unsupported.
 WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_ASYNC_SCROLLING PRIVATE ON)
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_AUTOCAPITALIZE PRIVATE ON)
 WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_CONTENT_EXTENSIONS PRIVATE ON)
 WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_MEDIA_STREAM PRIVATE ${ENABLE_EXPERIMENTAL_FEATURES})
 WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_MHTML PRIVATE ON)
index 31cb582..8b2e253 100644 (file)
@@ -99,6 +99,7 @@ macro(WEBKIT_OPTION_BEGIN)
     WEBKIT_OPTION_DEFINE(ENABLE_APPLICATION_MANIFEST "Toggle Application Manifest support" PRIVATE OFF)
     WEBKIT_OPTION_DEFINE(ENABLE_ASYNC_SCROLLING "Enable asynchronous scrolling" PRIVATE OFF)
     WEBKIT_OPTION_DEFINE(ENABLE_ATTACHMENT_ELEMENT "Toggle Attachment Element support" PRIVATE OFF)
+    WEBKIT_OPTION_DEFINE(ENABLE_AUTOCAPITALIZE "Toggle autocapitalize support" PRIVATE OFF)
     WEBKIT_OPTION_DEFINE(ENABLE_AVF_CAPTIONS "Toggle AVFoundation caption support" PRIVATE OFF)
     WEBKIT_OPTION_DEFINE(ENABLE_BUBBLEWRAP_SANDBOX "Toggle Bubblewrap sandboxing support" PRIVATE OFF)
     WEBKIT_OPTION_DEFINE(ENABLE_CACHE_PARTITIONING "Toggle cache partitioning support" PRIVATE OFF)
index 9a27cfd..a72f659 100644 (file)
@@ -1,3 +1,16 @@
+2020-01-07  Carlos Garcia Campos  <cgarcia@igalia.com>
+
+        [GTK][WPE] Add API to set purpose and hints of active editable element to input methods
+        https://bugs.webkit.org/show_bug.cgi?id=205605
+
+        Reviewed by Žan Doberšek.
+
+        Add new test case to check the purpose and hints API.
+
+        * TestWebKitAPI/Tests/WebKitGLib/TestInputMethodContext.cpp:
+        (testWebKitInputMethodContextContentType):
+        (beforeAll):
+
 2020-01-06  Jonathan Bedard  <jbedard@apple.com>
 
         results.webkit.org: Tweak processing constants
index 5961fac..5086671 100644 (file)
@@ -338,6 +338,26 @@ public:
         g_assert_true(m_context->enabled);
     }
 
+    void unfocusEditableAndWaitUntilInputMethodDisabled()
+    {
+        g_assert_true(m_context->enabled);
+        runJavaScriptAndWaitUntilFinished("document.getElementById('editable').blur()", nullptr);
+        if (!m_context->enabled)
+            return;
+
+        g_idle_add([](gpointer userData) -> gboolean {
+            auto* test = static_cast<InputMethodTest*>(userData);
+            if (!test->m_context->enabled) {
+                test->quitMainLoop();
+                return FALSE;
+            }
+
+            return TRUE;
+        }, this);
+        g_main_loop_run(m_mainLoop);
+        g_assert_false(m_context->enabled);
+    }
+
     void resetEditable()
     {
         runJavaScriptAndWaitUntilFinished("document.getElementById('editable').value = ''", nullptr);
@@ -373,6 +393,16 @@ public:
         m_eventsExpected = 0;
     }
 
+    WebKitInputPurpose purpose() const
+    {
+        return webkit_input_method_context_get_input_purpose(WEBKIT_INPUT_METHOD_CONTEXT(m_context.get()));
+    }
+
+    WebKitInputHints hints() const
+    {
+        return webkit_input_method_context_get_input_hints(WEBKIT_INPUT_METHOD_CONTEXT(m_context.get()));
+    }
+
     GRefPtr<WebKitInputMethodContextMock> m_context;
     Vector<Event> m_events;
     unsigned m_eventsExpected { 0 };
@@ -692,6 +722,159 @@ static void testWebKitInputMethodContextReset(InputMethodTest* test, gconstpoint
     test->resetEditable();
 }
 
+static void testWebKitInputMethodContextContentType(InputMethodTest* test, gconstpointer)
+{
+    test->loadHtml("<input id='editable' spellcheck='false'></input>", nullptr);
+    test->waitUntilLoadFinished();
+    test->focusEditableAndWaitUntilInputMethodEnabled();
+    g_assert_cmpuint(test->purpose(), ==, WEBKIT_INPUT_PURPOSE_FREE_FORM);
+    g_assert_cmpuint(test->hints(), ==, WEBKIT_INPUT_HINT_NONE);
+    test->unfocusEditableAndWaitUntilInputMethodDisabled();
+
+    test->loadHtml("<input id='editable' type='number' spellcheck='false'>", nullptr);
+    test->waitUntilLoadFinished();
+    test->focusEditableAndWaitUntilInputMethodEnabled();
+    g_assert_cmpuint(test->purpose(), ==, WEBKIT_INPUT_PURPOSE_NUMBER);
+    g_assert_cmpuint(test->hints(), ==, WEBKIT_INPUT_HINT_NONE);
+    test->unfocusEditableAndWaitUntilInputMethodDisabled();
+
+    test->loadHtml("<input id='editable' type='number' spellcheck='false' pattern='[0-9]*'>", nullptr);
+    test->waitUntilLoadFinished();
+    test->focusEditableAndWaitUntilInputMethodEnabled();
+    g_assert_cmpuint(test->purpose(), ==, WEBKIT_INPUT_PURPOSE_DIGITS);
+    g_assert_cmpuint(test->hints(), ==, WEBKIT_INPUT_HINT_NONE);
+    test->unfocusEditableAndWaitUntilInputMethodDisabled();
+
+    test->loadHtml("<input id='editable' type='text' spellcheck='false' pattern='\\d*'>", nullptr);
+    test->waitUntilLoadFinished();
+    test->focusEditableAndWaitUntilInputMethodEnabled();
+    g_assert_cmpuint(test->purpose(), ==, WEBKIT_INPUT_PURPOSE_DIGITS);
+    g_assert_cmpuint(test->hints(), ==, WEBKIT_INPUT_HINT_NONE);
+    test->unfocusEditableAndWaitUntilInputMethodDisabled();
+
+    test->loadHtml("<input id='editable' type='tel' spellcheck='false'>", nullptr);
+    test->waitUntilLoadFinished();
+    test->focusEditableAndWaitUntilInputMethodEnabled();
+    g_assert_cmpuint(test->purpose(), ==, WEBKIT_INPUT_PURPOSE_PHONE);
+    g_assert_cmpuint(test->hints(), ==, WEBKIT_INPUT_HINT_NONE);
+    test->unfocusEditableAndWaitUntilInputMethodDisabled();
+
+    test->loadHtml("<input id='editable' type='url' spellcheck='false'>", nullptr);
+    test->waitUntilLoadFinished();
+    test->focusEditableAndWaitUntilInputMethodEnabled();
+    g_assert_cmpuint(test->purpose(), ==, WEBKIT_INPUT_PURPOSE_URL);
+    g_assert_cmpuint(test->hints(), ==, WEBKIT_INPUT_HINT_NONE);
+    test->unfocusEditableAndWaitUntilInputMethodDisabled();
+
+    test->loadHtml("<input id='editable' type='email' spellcheck='false'>", nullptr);
+    test->waitUntilLoadFinished();
+    test->focusEditableAndWaitUntilInputMethodEnabled();
+    g_assert_cmpuint(test->purpose(), ==, WEBKIT_INPUT_PURPOSE_EMAIL);
+    g_assert_cmpuint(test->hints(), ==, WEBKIT_INPUT_HINT_NONE);
+    test->unfocusEditableAndWaitUntilInputMethodDisabled();
+
+#if 0
+    // FIXME: We should enable input methods in password fields too.
+    test->loadHtml("<input id='editable' type='password'>", nullptr);
+    test->waitUntilLoadFinished();
+    test->focusEditableAndWaitUntilInputMethodEnabled();
+    g_assert_cmpuint(test->purpose(), ==, WEBKIT_INPUT_PURPOSE_PASSWORD);
+    g_assert_cmpuint(test->hints(), ==, WEBKIT_INPUT_HINT_NONE);
+    test->unfocusEditableAndWaitUntilInputMethodDisabled();
+#endif
+
+    test->loadHtml("<div contenteditable id='editable' inputmode='text' spellcheck='false'></div>", nullptr);
+    test->waitUntilLoadFinished();
+    test->focusEditableAndWaitUntilInputMethodEnabled();
+    g_assert_cmpuint(test->purpose(), ==, WEBKIT_INPUT_PURPOSE_FREE_FORM);
+    g_assert_cmpuint(test->hints(), ==, WEBKIT_INPUT_HINT_NONE);
+    test->unfocusEditableAndWaitUntilInputMethodDisabled();
+
+    test->loadHtml("<div contenteditable id='editable' inputmode='decimal' spellcheck='false'></div>", nullptr);
+    test->waitUntilLoadFinished();
+    test->focusEditableAndWaitUntilInputMethodEnabled();
+    g_assert_cmpuint(test->purpose(), ==, WEBKIT_INPUT_PURPOSE_NUMBER);
+    g_assert_cmpuint(test->hints(), ==, WEBKIT_INPUT_HINT_NONE);
+    test->unfocusEditableAndWaitUntilInputMethodDisabled();
+
+    test->loadHtml("<div contenteditable id='editable' inputmode='numeric' spellcheck='false'></div>", nullptr);
+    test->waitUntilLoadFinished();
+    test->focusEditableAndWaitUntilInputMethodEnabled();
+    g_assert_cmpuint(test->purpose(), ==, WEBKIT_INPUT_PURPOSE_DIGITS);
+    g_assert_cmpuint(test->hints(), ==, WEBKIT_INPUT_HINT_NONE);
+    test->unfocusEditableAndWaitUntilInputMethodDisabled();
+
+    test->loadHtml("<div contenteditable id='editable' inputmode='tel' spellcheck='false'></div>", nullptr);
+    test->waitUntilLoadFinished();
+    test->focusEditableAndWaitUntilInputMethodEnabled();
+    g_assert_cmpuint(test->purpose(), ==, WEBKIT_INPUT_PURPOSE_PHONE);
+    g_assert_cmpuint(test->hints(), ==, WEBKIT_INPUT_HINT_NONE);
+    test->unfocusEditableAndWaitUntilInputMethodDisabled();
+
+    test->loadHtml("<div contenteditable id='editable' inputmode='email' spellcheck='false'></div>", nullptr);
+    test->waitUntilLoadFinished();
+    test->focusEditableAndWaitUntilInputMethodEnabled();
+    g_assert_cmpuint(test->purpose(), ==, WEBKIT_INPUT_PURPOSE_EMAIL);
+    g_assert_cmpuint(test->hints(), ==, WEBKIT_INPUT_HINT_NONE);
+    test->unfocusEditableAndWaitUntilInputMethodDisabled();
+
+    test->loadHtml("<div contenteditable id='editable' inputmode='url' spellcheck='false'></div>", nullptr);
+    test->waitUntilLoadFinished();
+    test->focusEditableAndWaitUntilInputMethodEnabled();
+    g_assert_cmpuint(test->purpose(), ==, WEBKIT_INPUT_PURPOSE_URL);
+    g_assert_cmpuint(test->hints(), ==, WEBKIT_INPUT_HINT_NONE);
+    test->unfocusEditableAndWaitUntilInputMethodDisabled();
+
+    test->loadHtml("<div contenteditable id='editable' inputmode='search' spellcheck='false'></div>", nullptr);
+    test->waitUntilLoadFinished();
+    test->focusEditableAndWaitUntilInputMethodEnabled();
+    g_assert_cmpuint(test->purpose(), ==, WEBKIT_INPUT_PURPOSE_FREE_FORM);
+    g_assert_cmpuint(test->hints(), ==, WEBKIT_INPUT_HINT_NONE);
+    test->unfocusEditableAndWaitUntilInputMethodDisabled();
+
+    test->loadHtml("<div contenteditable id='editable' inputmode='none' spellcheck='false'></div>", nullptr);
+    test->waitUntilLoadFinished();
+    test->focusEditableAndWaitUntilInputMethodEnabled();
+    g_assert_cmpuint(test->purpose(), ==, WEBKIT_INPUT_PURPOSE_FREE_FORM);
+    g_assert_cmpuint(test->hints(), ==, WEBKIT_INPUT_HINT_INHIBIT_OSK);
+    test->unfocusEditableAndWaitUntilInputMethodDisabled();
+
+    test->loadHtml("<textarea id='editable'></textarea>", nullptr);
+    test->waitUntilLoadFinished();
+    test->focusEditableAndWaitUntilInputMethodEnabled();
+    g_assert_cmpuint(test->purpose(), ==, WEBKIT_INPUT_PURPOSE_FREE_FORM);
+    g_assert_cmpuint(test->hints(), ==, WEBKIT_INPUT_HINT_SPELLCHECK);
+    test->unfocusEditableAndWaitUntilInputMethodDisabled();
+
+    test->loadHtml("<textarea id='editable' autocapitalize='none'></textarea>", nullptr);
+    test->waitUntilLoadFinished();
+    test->focusEditableAndWaitUntilInputMethodEnabled();
+    g_assert_cmpuint(test->purpose(), ==, WEBKIT_INPUT_PURPOSE_FREE_FORM);
+    g_assert_cmpuint(test->hints(), ==, WEBKIT_INPUT_HINT_SPELLCHECK | WEBKIT_INPUT_HINT_LOWERCASE);
+    test->unfocusEditableAndWaitUntilInputMethodDisabled();
+
+    test->loadHtml("<textarea id='editable' autocapitalize='sentences'></textarea>", nullptr);
+    test->waitUntilLoadFinished();
+    test->focusEditableAndWaitUntilInputMethodEnabled();
+    g_assert_cmpuint(test->purpose(), ==, WEBKIT_INPUT_PURPOSE_FREE_FORM);
+    g_assert_cmpuint(test->hints(), ==, WEBKIT_INPUT_HINT_SPELLCHECK | WEBKIT_INPUT_HINT_UPPERCASE_SENTENCES);
+    test->unfocusEditableAndWaitUntilInputMethodDisabled();
+
+    test->loadHtml("<textarea id='editable' autocapitalize='words'></textarea>", nullptr);
+    test->waitUntilLoadFinished();
+    test->focusEditableAndWaitUntilInputMethodEnabled();
+    g_assert_cmpuint(test->purpose(), ==, WEBKIT_INPUT_PURPOSE_FREE_FORM);
+    g_assert_cmpuint(test->hints(), ==, WEBKIT_INPUT_HINT_SPELLCHECK | WEBKIT_INPUT_HINT_UPPERCASE_WORDS);
+    test->unfocusEditableAndWaitUntilInputMethodDisabled();
+
+    test->loadHtml("<textarea id='editable' autocapitalize='characters'></textarea>", nullptr);
+    test->waitUntilLoadFinished();
+    test->focusEditableAndWaitUntilInputMethodEnabled();
+    g_assert_cmpuint(test->purpose(), ==, WEBKIT_INPUT_PURPOSE_FREE_FORM);
+    g_assert_cmpuint(test->hints(), ==, WEBKIT_INPUT_HINT_SPELLCHECK | WEBKIT_INPUT_HINT_UPPERCASE_CHARS);
+    test->unfocusEditableAndWaitUntilInputMethodDisabled();
+}
+
 void beforeAll()
 {
     InputMethodTest::add("WebKitInputMethodContext", "simple", testWebKitInputMethodContextSimple);
@@ -699,6 +882,7 @@ void beforeAll()
     InputMethodTest::add("WebKitInputMethodContext", "invalid-sequence", testWebKitInputMethodContextInvalidSequence);
     InputMethodTest::add("WebKitInputMethodContext", "cancel-sequence", testWebKitInputMethodContextCancelSequence);
     InputMethodTest::add("WebKitInputMethodContext", "reset", testWebKitInputMethodContextReset);
+    InputMethodTest::add("WebKitInputMethodContext", "content-type", testWebKitInputMethodContextContentType);
 }
 
 void afterAll()