Title: [235201] trunk
Revision
235201
Author
akeer...@apple.com
Date
2018-08-22 14:22:13 -0700 (Wed, 22 Aug 2018)

Log Message

[iOS] Add support for the inputmode attribute
https://bugs.webkit.org/show_bug.cgi?id=183621

Reviewed by Tim Horton.

Source/WebCore:

Added the inputmode attribute to the HTMLInputElement and HTMLTextAreaElement IDL
files. The possible values for the attribute are specified in InputModeNames.

Test: fast/forms/inputmode-attribute.html

* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* html/HTMLAttributeNames.in:
* html/HTMLInputElement.idl:
* html/HTMLTextAreaElement.idl:
* html/HTMLTextFormControlElement.cpp:
(WebCore::HTMLTextFormControlElement::inputMode const):
(WebCore::HTMLTextFormControlElement::setInputMode):
* html/HTMLTextFormControlElement.h:
* html/InputModeNames.cpp: Added.
(WebCore::InputModeNames::text):
(WebCore::InputModeNames::tel):
(WebCore::InputModeNames::url):
(WebCore::InputModeNames::email):
(WebCore::InputModeNames::numeric):
(WebCore::InputModeNames::decimal):
(WebCore::InputModeNames::search):
* html/InputModeNames.h: Added.

Source/WebKit:

The inputmode attribute specifies which input mechanism would be most helpful for
users entering content in textfield inputs and textareas. This patch adds support
for seven values: text, tel, url, email, numeric, decimal and search.

On iOS, we can specify UIKeyboardTypes that best match the supplied inputmode.
- text: UIKeyboardTypeDefault
- tel: UIKeyboardTypePhonePad
- url: UIKeyboardTypeURL
- email: UIKeyboardTypeEmailAddress
- numeric: UIKeyboardTypeNumbersAndPunctuation
- decimal: UIKeyboardTypeDecimalPad
- search: UIKeyboardTypeWebSearch

In the case that the inputmode attribute is not specified, we fall back to using
our existing heuristic to determine what kind of keyboard to show for textfields.

* Shared/AssistedNodeInformation.cpp:
(WebKit::AssistedNodeInformation::encode const):
(WebKit::AssistedNodeInformation::decode):
* Shared/AssistedNodeInformation.h: Added inputMode field.
* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView textInputTraits]):
* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::inputModeForElement):
(WebKit::WebPage::getAssistedNodeInformation):

Tools:

Added an API test to verify that the correct UIKeyboardType is set depending on
the type, inputmode, and pattern specified for an input field.

* TestWebKitAPI/Tests/ios/KeyboardInputTestsIOS.mm:
(TestWebKitAPI::TEST):
* TestWebKitAPI/ios/UIKitSPI.h:

LayoutTests:

Added test to verify behavior when getting and setting the inputmode attribute.

* fast/forms/inputmode-attribute-expected.txt: Added.
* fast/forms/inputmode-attribute.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (235200 => 235201)


--- trunk/LayoutTests/ChangeLog	2018-08-22 21:08:38 UTC (rev 235200)
+++ trunk/LayoutTests/ChangeLog	2018-08-22 21:22:13 UTC (rev 235201)
@@ -1,3 +1,15 @@
+2018-08-22  Aditya Keerthi  <akeer...@apple.com>
+
+        [iOS] Add support for the inputmode attribute
+        https://bugs.webkit.org/show_bug.cgi?id=183621
+
+        Reviewed by Tim Horton.
+
+        Added test to verify behavior when getting and setting the inputmode attribute.
+
+        * fast/forms/inputmode-attribute-expected.txt: Added.
+        * fast/forms/inputmode-attribute.html: Added.
+
 2018-08-22  Per Arne Vollan  <pvol...@apple.com>
 
         [Win] Some video tests under http/tests/security are crashing on EWS.

Added: trunk/LayoutTests/fast/forms/inputmode-attribute-expected.txt (0 => 235201)


--- trunk/LayoutTests/fast/forms/inputmode-attribute-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/forms/inputmode-attribute-expected.txt	2018-08-22 21:22:13 UTC (rev 235201)
@@ -0,0 +1,44 @@
+Test inputmode attribute
+
+
+Missing value default:
+PASS input.inputMode is ""
+PASS input.getAttribute("inputmode") is null
+
+Invalid value default:
+PASS input.inputMode = "foobar"; input.inputMode is ""
+PASS input.getAttribute("inputmode") is "foobar"
+PASS input.setAttribute("inputmode", "baz"); input.inputMode is ""
+
+Valid values:
+PASS input.inputMode = "text"; input.inputMode is "text"
+PASS input.getAttribute("inputmode") is "text"
+PASS input.setAttribute("inputmode", "text"); input.inputMode is "text"
+PASS input.inputMode = "tel"; input.inputMode is "tel"
+PASS input.getAttribute("inputmode") is "tel"
+PASS input.setAttribute("inputmode", "tel"); input.inputMode is "tel"
+PASS input.inputMode = "url"; input.inputMode is "url"
+PASS input.getAttribute("inputmode") is "url"
+PASS input.setAttribute("inputmode", "url"); input.inputMode is "url"
+PASS input.inputMode = "email"; input.inputMode is "email"
+PASS input.getAttribute("inputmode") is "email"
+PASS input.setAttribute("inputmode", "email"); input.inputMode is "email"
+PASS input.inputMode = "numeric"; input.inputMode is "numeric"
+PASS input.getAttribute("inputmode") is "numeric"
+PASS input.setAttribute("inputmode", "numeric"); input.inputMode is "numeric"
+PASS input.inputMode = "decimal"; input.inputMode is "decimal"
+PASS input.getAttribute("inputmode") is "decimal"
+PASS input.setAttribute("inputmode", "decimal"); input.inputMode is "decimal"
+PASS input.inputMode = "search"; input.inputMode is "search"
+PASS input.getAttribute("inputmode") is "search"
+PASS input.setAttribute("inputmode", "search"); input.inputMode is "search"
+
+Valid case-insensitive values:
+PASS input.inputMode = "tExt"; input.inputMode is "text"
+PASS input.getAttribute("inputmode") is "tExt"
+PASS input.setAttribute("inputmode", "tExt"); input.inputMode is "text"
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/forms/inputmode-attribute.html (0 => 235201)


--- trunk/LayoutTests/fast/forms/inputmode-attribute.html	                        (rev 0)
+++ trunk/LayoutTests/fast/forms/inputmode-attribute.html	2018-08-22 21:22:13 UTC (rev 235201)
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src=""
+<p>Test inputmode attribute</p>
+<input id="input">
+<div id=console></div>
+<script>
+debug('Missing value default:');
+shouldBe('input.inputMode', '""');
+shouldBeNull('input.getAttribute("inputmode")');
+
+debug('');
+debug('Invalid value default:');
+shouldBe('input.inputMode = "foobar"; input.inputMode', '""');
+shouldBe('input.getAttribute("inputmode")', '"foobar"');
+shouldBe('input.setAttribute("inputmode", "baz"); input.inputMode', '""');
+
+debug('');
+debug('Valid values:');
+shouldBe('input.inputMode = "text"; input.inputMode', '"text"');
+shouldBe('input.getAttribute("inputmode")', '"text"');
+shouldBe('input.setAttribute("inputmode", "text"); input.inputMode', '"text"');
+shouldBe('input.inputMode = "tel"; input.inputMode', '"tel"');
+shouldBe('input.getAttribute("inputmode")', '"tel"');
+shouldBe('input.setAttribute("inputmode", "tel"); input.inputMode', '"tel"');
+shouldBe('input.inputMode = "url"; input.inputMode', '"url"');
+shouldBe('input.getAttribute("inputmode")', '"url"');
+shouldBe('input.setAttribute("inputmode", "url"); input.inputMode', '"url"');
+shouldBe('input.inputMode = "email"; input.inputMode', '"email"');
+shouldBe('input.getAttribute("inputmode")', '"email"');
+shouldBe('input.setAttribute("inputmode", "email"); input.inputMode', '"email"');
+shouldBe('input.inputMode = "numeric"; input.inputMode', '"numeric"');
+shouldBe('input.getAttribute("inputmode")', '"numeric"');
+shouldBe('input.setAttribute("inputmode", "numeric"); input.inputMode', '"numeric"');
+shouldBe('input.inputMode = "decimal"; input.inputMode', '"decimal"');
+shouldBe('input.getAttribute("inputmode")', '"decimal"');
+shouldBe('input.setAttribute("inputmode", "decimal"); input.inputMode', '"decimal"');
+shouldBe('input.inputMode = "search"; input.inputMode', '"search"');
+shouldBe('input.getAttribute("inputmode")', '"search"');
+shouldBe('input.setAttribute("inputmode", "search"); input.inputMode', '"search"');
+
+debug('');
+debug('Valid case-insensitive values:');
+shouldBe('input.inputMode = "tExt"; input.inputMode', '"text"');
+shouldBe('input.getAttribute("inputmode")', '"tExt"');
+shouldBe('input.setAttribute("inputmode", "tExt"); input.inputMode', '"text"');
+
+debug('');
+</script>
+<script src=""
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (235200 => 235201)


--- trunk/Source/WebCore/ChangeLog	2018-08-22 21:08:38 UTC (rev 235200)
+++ trunk/Source/WebCore/ChangeLog	2018-08-22 21:22:13 UTC (rev 235201)
@@ -1,3 +1,34 @@
+2018-08-22  Aditya Keerthi  <akeer...@apple.com>
+
+        [iOS] Add support for the inputmode attribute
+        https://bugs.webkit.org/show_bug.cgi?id=183621
+
+        Reviewed by Tim Horton.
+
+        Added the inputmode attribute to the HTMLInputElement and HTMLTextAreaElement IDL
+        files. The possible values for the attribute are specified in InputModeNames.
+
+        Test: fast/forms/inputmode-attribute.html
+
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * html/HTMLAttributeNames.in:
+        * html/HTMLInputElement.idl:
+        * html/HTMLTextAreaElement.idl:
+        * html/HTMLTextFormControlElement.cpp:
+        (WebCore::HTMLTextFormControlElement::inputMode const):
+        (WebCore::HTMLTextFormControlElement::setInputMode):
+        * html/HTMLTextFormControlElement.h:
+        * html/InputModeNames.cpp: Added.
+        (WebCore::InputModeNames::text):
+        (WebCore::InputModeNames::tel):
+        (WebCore::InputModeNames::url):
+        (WebCore::InputModeNames::email):
+        (WebCore::InputModeNames::numeric):
+        (WebCore::InputModeNames::decimal):
+        (WebCore::InputModeNames::search):
+        * html/InputModeNames.h: Added.
+
 2018-08-22  Eric Carlson  <eric.carl...@apple.com>
 
         Log more often during AirPlay state changes

Modified: trunk/Source/WebCore/Sources.txt (235200 => 235201)


--- trunk/Source/WebCore/Sources.txt	2018-08-22 21:08:38 UTC (rev 235200)
+++ trunk/Source/WebCore/Sources.txt	2018-08-22 21:22:13 UTC (rev 235201)
@@ -1056,6 +1056,7 @@
 html/ImageData.cpp
 html/ImageDocument.cpp
 html/ImageInputType.cpp
+html/InputModeNames.cpp
 html/InputType.cpp
 html/InputTypeNames.cpp
 html/LabelableElement.cpp

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (235200 => 235201)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2018-08-22 21:08:38 UTC (rev 235200)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2018-08-22 21:22:13 UTC (rev 235201)
@@ -4790,6 +4790,7 @@
 		E517670320B88C1400D41167 /* DataListSuggestionInformation.h in Headers */ = {isa = PBXBuildFile; fileRef = E517670220B88C1400D41167 /* DataListSuggestionInformation.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E52CF54D20A268AC00DADA27 /* DataListSuggestionsClient.h in Headers */ = {isa = PBXBuildFile; fileRef = E52CF54C20A268AC00DADA27 /* DataListSuggestionsClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E52CF54F20A35A2800DADA27 /* DataListSuggestionPicker.h in Headers */ = {isa = PBXBuildFile; fileRef = E52CF54E20A35A2800DADA27 /* DataListSuggestionPicker.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		E52EFDF42112875A00AD282A /* InputModeNames.h in Headers */ = {isa = PBXBuildFile; fileRef = E52EFDF22112875A00AD282A /* InputModeNames.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E58B45BA20AD07DD00991025 /* DataListButtonElement.h in Headers */ = {isa = PBXBuildFile; fileRef = E58B45B820AD07DD00991025 /* DataListButtonElement.h */; };
 		E58B45BB20AD07DD00991025 /* DataListButtonElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E58B45B920AD07DD00991025 /* DataListButtonElement.cpp */; };
 		E59DD4B821098287003C8B47 /* ListButtonArrow.png in Resources */ = {isa = PBXBuildFile; fileRef = E59DD4B721098285003C8B47 /* ListButtonArrow.png */; };
@@ -14434,6 +14435,8 @@
 		E526AF3E1727F8F200E41781 /* Performance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Performance.cpp; sourceTree = "<group>"; };
 		E52CF54C20A268AC00DADA27 /* DataListSuggestionsClient.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DataListSuggestionsClient.h; sourceTree = "<group>"; };
 		E52CF54E20A35A2800DADA27 /* DataListSuggestionPicker.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DataListSuggestionPicker.h; sourceTree = "<group>"; };
+		E52EFDF22112875A00AD282A /* InputModeNames.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InputModeNames.h; sourceTree = "<group>"; };
+		E52EFDF32112875A00AD282A /* InputModeNames.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = InputModeNames.cpp; sourceTree = "<group>"; };
 		E55F4979151B888000BB67DB /* LengthFunctions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LengthFunctions.cpp; sourceTree = "<group>"; };
 		E58B45B820AD07DD00991025 /* DataListButtonElement.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DataListButtonElement.h; sourceTree = "<group>"; };
 		E58B45B920AD07DD00991025 /* DataListButtonElement.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DataListButtonElement.cpp; sourceTree = "<group>"; };
@@ -20633,6 +20636,8 @@
 				97205AB21239291000B17380 /* ImageDocument.h */,
 				F55B3D8D1251F12D003EF269 /* ImageInputType.cpp */,
 				F55B3D8E1251F12D003EF269 /* ImageInputType.h */,
+				E52EFDF32112875A00AD282A /* InputModeNames.cpp */,
+				E52EFDF22112875A00AD282A /* InputModeNames.h */,
 				37E3524A12450C5200BAF5D9 /* InputType.cpp */,
 				37E3524C12450C6600BAF5D9 /* InputType.h */,
 				C348612115FDE21E007A1CC9 /* InputTypeNames.cpp */,
@@ -28264,6 +28269,7 @@
 				1C010701192594DF008A4201 /* InlineTextBoxStyle.h in Headers */,
 				510A58E51BAA40B100C19282 /* InProcessIDBServer.h in Headers */,
 				2EB767571DA19BDF003E23B5 /* InputEvent.h in Headers */,
+				E52EFDF42112875A00AD282A /* InputModeNames.h in Headers */,
 				37E3524D12450C6600BAF5D9 /* InputType.h in Headers */,
 				C348612415FDE21E007A1CC9 /* InputTypeNames.h in Headers */,
 				93309DEA099E64920056E581 /* InsertIntoTextNodeCommand.h in Headers */,

Modified: trunk/Source/WebCore/html/HTMLAttributeNames.in (235200 => 235201)


--- trunk/Source/WebCore/html/HTMLAttributeNames.in	2018-08-22 21:08:38 UTC (rev 235200)
+++ trunk/Source/WebCore/html/HTMLAttributeNames.in	2018-08-22 21:22:13 UTC (rev 235201)
@@ -144,6 +144,7 @@
 id
 incremental
 indeterminate
+inputmode
 integrity
 is
 ismap

Modified: trunk/Source/WebCore/html/HTMLInputElement.idl (235200 => 235201)


--- trunk/Source/WebCore/html/HTMLInputElement.idl	2018-08-22 21:08:38 UTC (rev 235200)
+++ trunk/Source/WebCore/html/HTMLInputElement.idl	2018-08-22 21:22:13 UTC (rev 235201)
@@ -42,6 +42,7 @@
     [Reflect] attribute DOMString formTarget;
     attribute unsigned long height;
     attribute boolean indeterminate;
+    attribute DOMString inputMode;
     [Conditional=DATALIST_ELEMENT] readonly attribute HTMLElement list;
     [Reflect] attribute DOMString max;
     attribute long minLength;

Modified: trunk/Source/WebCore/html/HTMLTextAreaElement.idl (235200 => 235201)


--- trunk/Source/WebCore/html/HTMLTextAreaElement.idl	2018-08-22 21:08:38 UTC (rev 235200)
+++ trunk/Source/WebCore/html/HTMLTextAreaElement.idl	2018-08-22 21:22:13 UTC (rev 235201)
@@ -59,4 +59,5 @@
     void setSelectionRange(optional long start = 0, optional long end = 0, optional DOMString direction);
 
     attribute DOMString autocomplete;
+    attribute DOMString inputMode;
 };

Modified: trunk/Source/WebCore/html/HTMLTextFormControlElement.cpp (235200 => 235201)


--- trunk/Source/WebCore/html/HTMLTextFormControlElement.cpp	2018-08-22 21:08:38 UTC (rev 235200)
+++ trunk/Source/WebCore/html/HTMLTextFormControlElement.cpp	2018-08-22 21:22:13 UTC (rev 235201)
@@ -39,6 +39,7 @@
 #include "HTMLInputElement.h"
 #include "HTMLNames.h"
 #include "HTMLParserIdioms.h"
+#include "InputModeNames.h"
 #include "LayoutDisallowedScope.h"
 #include "Logging.h"
 #include "NodeTraversal.h"
@@ -674,6 +675,32 @@
 }
 #endif
 
+String HTMLTextFormControlElement::inputMode() const
+{
+    const AtomicString& inputMode = attributeWithoutSynchronization(inputmodeAttr);
+    if (equalIgnoringASCIICase(inputMode, InputModeNames::text()))
+        return InputModeNames::text();
+    if (equalIgnoringASCIICase(inputMode, InputModeNames::tel()))
+        return InputModeNames::tel();
+    if (equalIgnoringASCIICase(inputMode, InputModeNames::url()))
+        return InputModeNames::url();
+    if (equalIgnoringASCIICase(inputMode, InputModeNames::email()))
+        return InputModeNames::email();
+    if (equalIgnoringASCIICase(inputMode, InputModeNames::numeric()))
+        return InputModeNames::numeric();
+    if (equalIgnoringASCIICase(inputMode, InputModeNames::decimal()))
+        return InputModeNames::decimal();
+    if (equalIgnoringASCIICase(inputMode, InputModeNames::search()))
+        return InputModeNames::search();
+
+    return emptyString();
+}
+
+void HTMLTextFormControlElement::setInputMode(const String& value)
+{
+    setAttributeWithoutSynchronization(inputmodeAttr, value);
+}
+
 static void getNextSoftBreak(RootInlineBox*& line, Node*& breakNode, unsigned& breakOffset)
 {
     RootInlineBox* next;

Modified: trunk/Source/WebCore/html/HTMLTextFormControlElement.h (235200 => 235201)


--- trunk/Source/WebCore/html/HTMLTextFormControlElement.h	2018-08-22 21:08:38 UTC (rev 235200)
+++ trunk/Source/WebCore/html/HTMLTextFormControlElement.h	2018-08-22 21:22:13 UTC (rev 235201)
@@ -98,6 +98,9 @@
     WEBCORE_EXPORT void showPlaceholderIfNecessary();
 #endif
 
+    WEBCORE_EXPORT String inputMode() const;
+    void setInputMode(const String&);
+
 protected:
     HTMLTextFormControlElement(const QualifiedName&, Document&, HTMLFormElement*);
     bool isPlaceholderEmpty() const;

Added: trunk/Source/WebCore/html/InputModeNames.cpp (0 => 235201)


--- trunk/Source/WebCore/html/InputModeNames.cpp	                        (rev 0)
+++ trunk/Source/WebCore/html/InputModeNames.cpp	2018-08-22 21:22:13 UTC (rev 235201)
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * 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 "InputModeNames.h"
+
+#include <wtf/NeverDestroyed.h>
+
+namespace WebCore {
+
+namespace InputModeNames {
+
+const AtomicString& text()
+{
+    static NeverDestroyed<AtomicString> mode("text", AtomicString::ConstructFromLiteral);
+    return mode;
+}
+
+const AtomicString& tel()
+{
+    static NeverDestroyed<AtomicString> mode("tel", AtomicString::ConstructFromLiteral);
+    return mode;
+}
+
+const AtomicString& url()
+{
+    static NeverDestroyed<AtomicString> mode("url", AtomicString::ConstructFromLiteral);
+    return mode;
+}
+
+const AtomicString& email()
+{
+    static NeverDestroyed<AtomicString> mode("email", AtomicString::ConstructFromLiteral);
+    return mode;
+}
+
+const AtomicString& numeric()
+{
+    static NeverDestroyed<AtomicString> mode("numeric", AtomicString::ConstructFromLiteral);
+    return mode;
+}
+
+const AtomicString& decimal()
+{
+    static NeverDestroyed<AtomicString> mode("decimal", AtomicString::ConstructFromLiteral);
+    return mode;
+}
+
+const AtomicString& search()
+{
+    static NeverDestroyed<AtomicString> mode("search", AtomicString::ConstructFromLiteral);
+    return mode;
+}
+
+} // namespace InputModeNames
+
+} // namespace WebCore

Added: trunk/Source/WebCore/html/InputModeNames.h (0 => 235201)


--- trunk/Source/WebCore/html/InputModeNames.h	                        (rev 0)
+++ trunk/Source/WebCore/html/InputModeNames.h	2018-08-22 21:22:13 UTC (rev 235201)
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * 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 <wtf/text/AtomicString.h>
+
+namespace WebCore {
+
+namespace InputModeNames {
+
+WEBCORE_EXPORT const AtomicString& text();
+WEBCORE_EXPORT const AtomicString& tel();
+WEBCORE_EXPORT const AtomicString& url();
+WEBCORE_EXPORT const AtomicString& email();
+WEBCORE_EXPORT const AtomicString& numeric();
+WEBCORE_EXPORT const AtomicString& decimal();
+WEBCORE_EXPORT const AtomicString& search();
+
+} // namespace InputModeNames
+
+} // namespace WebCore

Modified: trunk/Source/WebKit/ChangeLog (235200 => 235201)


--- trunk/Source/WebKit/ChangeLog	2018-08-22 21:08:38 UTC (rev 235200)
+++ trunk/Source/WebKit/ChangeLog	2018-08-22 21:22:13 UTC (rev 235201)
@@ -1,3 +1,36 @@
+2018-08-22  Aditya Keerthi  <akeer...@apple.com>
+
+        [iOS] Add support for the inputmode attribute
+        https://bugs.webkit.org/show_bug.cgi?id=183621
+
+        Reviewed by Tim Horton.
+
+        The inputmode attribute specifies which input mechanism would be most helpful for
+        users entering content in textfield inputs and textareas. This patch adds support
+        for seven values: text, tel, url, email, numeric, decimal and search.
+
+        On iOS, we can specify UIKeyboardTypes that best match the supplied inputmode.
+        - text: UIKeyboardTypeDefault
+        - tel: UIKeyboardTypePhonePad
+        - url: UIKeyboardTypeURL
+        - email: UIKeyboardTypeEmailAddress
+        - numeric: UIKeyboardTypeNumbersAndPunctuation
+        - decimal: UIKeyboardTypeDecimalPad
+        - search: UIKeyboardTypeWebSearch
+
+        In the case that the inputmode attribute is not specified, we fall back to using
+        our existing heuristic to determine what kind of keyboard to show for textfields.
+
+        * Shared/AssistedNodeInformation.cpp:
+        (WebKit::AssistedNodeInformation::encode const):
+        (WebKit::AssistedNodeInformation::decode):
+        * Shared/AssistedNodeInformation.h: Added inputMode field.
+        * UIProcess/ios/WKContentViewInteraction.mm:
+        (-[WKContentView textInputTraits]):
+        * WebProcess/WebPage/ios/WebPageIOS.mm:
+        (WebKit::inputModeForElement):
+        (WebKit::WebPage::getAssistedNodeInformation):
+
 2018-08-22  Jeff Miller  <je...@apple.com>
 
         WKNavigationDelegate needs to allow clients to specify a custom blocked plug-in message

Modified: trunk/Source/WebKit/Shared/AssistedNodeInformation.cpp (235200 => 235201)


--- trunk/Source/WebKit/Shared/AssistedNodeInformation.cpp	2018-08-22 21:08:38 UTC (rev 235200)
+++ trunk/Source/WebKit/Shared/AssistedNodeInformation.cpp	2018-08-22 21:22:13 UTC (rev 235201)
@@ -77,6 +77,7 @@
     encoder << isRTL;
     encoder.encodeEnum(autocapitalizeType);
     encoder.encodeEnum(elementType);
+    encoder.encodeEnum(inputMode);
     encoder << formAction;
     encoder << selectOptions;
     encoder << selectedIndex;
@@ -145,6 +146,9 @@
     if (!decoder.decodeEnum(result.elementType))
         return false;
 
+    if (!decoder.decodeEnum(result.inputMode))
+        return false;
+
     if (!decoder.decode(result.formAction))
         return false;
 

Modified: trunk/Source/WebKit/Shared/AssistedNodeInformation.h (235200 => 235201)


--- trunk/Source/WebKit/Shared/AssistedNodeInformation.h	2018-08-22 21:08:38 UTC (rev 235200)
+++ trunk/Source/WebKit/Shared/AssistedNodeInformation.h	2018-08-22 21:22:13 UTC (rev 235201)
@@ -59,6 +59,17 @@
 #endif
 };
 
+enum class InputMode : uint8_t {
+    Auto,
+    Text,
+    Telephone,
+    Url,
+    Email,
+    Numeric,
+    Decimal,
+    Search
+};
+
 #if PLATFORM(IOS)
 struct OptionItem {
     OptionItem() { }
@@ -110,6 +121,7 @@
     bool insideFixedPosition { false };
     AutocapitalizeType autocapitalizeType { AutocapitalizeTypeDefault };
     InputType elementType { InputType::None };
+    InputMode inputMode { InputMode::Auto };
     String formAction;
     Vector<OptionItem> selectOptions;
     int selectedIndex { -1 };

Modified: trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm (235200 => 235201)


--- trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm	2018-08-22 21:08:38 UTC (rev 235200)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm	2018-08-22 21:22:13 UTC (rev 235201)
@@ -3547,24 +3547,64 @@
         [_traits setAutocorrectionType:_assistedNodeInformation.isAutocorrect ? UITextAutocorrectionTypeYes : UITextAutocorrectionTypeNo];
     }
 
-    switch (_assistedNodeInformation.elementType) {
-    case InputType::Phone:
+    switch (_assistedNodeInformation.inputMode) {
+    case InputMode::Auto:
+        switch (_assistedNodeInformation.elementType) {
+        case InputType::Phone:
+            [_traits setKeyboardType:UIKeyboardTypePhonePad];
+            break;
+        case InputType::URL:
+            [_traits setKeyboardType:UIKeyboardTypeURL];
+            break;
+        case InputType::Email:
+            [_traits setKeyboardType:UIKeyboardTypeEmailAddress];
+            break;
+        case InputType::Number:
+            [_traits setKeyboardType:UIKeyboardTypeNumbersAndPunctuation];
+            break;
+        case InputType::NumberPad:
+            [_traits setKeyboardType:UIKeyboardTypeNumberPad];
+            break;
+        case InputType::None:
+        case InputType::ContentEditable:
+        case InputType::Text:
+        case InputType::Password:
+        case InputType::TextArea:
+        case InputType::Search:
+        case InputType::Date:
+        case InputType::DateTime:
+        case InputType::DateTimeLocal:
+        case InputType::Month:
+        case InputType::Week:
+        case InputType::Time:
+        case InputType::Select:
+#if ENABLE(INPUT_TYPE_COLOR)
+        case InputType::Color:
+#endif
+            [_traits setKeyboardType:UIKeyboardTypeDefault];
+        }
+        break;
+    case InputMode::Text:
+        [_traits setKeyboardType:UIKeyboardTypeDefault];
+        break;
+    case InputMode::Telephone:
         [_traits setKeyboardType:UIKeyboardTypePhonePad];
         break;
-    case InputType::URL:
+    case InputMode::Url:
         [_traits setKeyboardType:UIKeyboardTypeURL];
         break;
-    case InputType::Email:
+    case InputMode::Email:
         [_traits setKeyboardType:UIKeyboardTypeEmailAddress];
         break;
-    case InputType::Number:
+    case InputMode::Numeric:
         [_traits setKeyboardType:UIKeyboardTypeNumbersAndPunctuation];
         break;
-    case InputType::NumberPad:
-        [_traits setKeyboardType:UIKeyboardTypeNumberPad];
+    case InputMode::Decimal:
+        [_traits setKeyboardType:UIKeyboardTypeDecimalPad];
         break;
-    default:
-        [_traits setKeyboardType:UIKeyboardTypeDefault];
+    case InputMode::Search:
+        [_traits setKeyboardType:UIKeyboardTypeWebSearch];
+        break;
     }
 
     [_traits setTextContentType:contentTypeFromFieldName(_assistedNodeInformation.autofillFieldName)];

Modified: trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm (235200 => 235201)


--- trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm	2018-08-22 21:08:38 UTC (rev 235200)
+++ trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm	2018-08-22 21:22:13 UTC (rev 235201)
@@ -84,8 +84,10 @@
 #import <WebCore/HTMLParserIdioms.h>
 #import <WebCore/HTMLSelectElement.h>
 #import <WebCore/HTMLTextAreaElement.h>
+#import <WebCore/HTMLTextFormControlElement.h>
 #import <WebCore/HistoryItem.h>
 #import <WebCore/HitTestResult.h>
+#import <WebCore/InputModeNames.h>
 #import <WebCore/KeyboardEvent.h>
 #import <WebCore/LibWebRTCProvider.h>
 #import <WebCore/MediaSessionManagerIOS.h>
@@ -2312,6 +2314,27 @@
     return view->contentsToRootView(renderer->absoluteBoundingBoxRect());
 }
 
+static InputMode inputModeForAssistedNode(const Node& node)
+{
+    const AtomicString& inputMode = downcast<HTMLTextFormControlElement>(node).inputMode();
+    if (inputMode == InputModeNames::text())
+        return InputMode::Text;
+    if (inputMode == InputModeNames::tel())
+        return InputMode::Telephone;
+    if (inputMode == InputModeNames::url())
+        return InputMode::Url;
+    if (inputMode == InputModeNames::email())
+        return InputMode::Email;
+    if (inputMode == InputModeNames::numeric())
+        return InputMode::Numeric;
+    if (inputMode == InputModeNames::decimal())
+        return InputMode::Decimal;
+    if (inputMode == InputModeNames::search())
+        return InputMode::Search;
+
+    return InputMode::Auto;
+}
+
 void WebPage::getAssistedNodeInformation(AssistedNodeInformation& information)
 {
     layoutIfNeeded();
@@ -2417,6 +2440,7 @@
         information.value = element.value();
         information.autofillFieldName = WebCore::toAutofillFieldName(element.autofillData().fieldName);
         information.placeholder = element.attributeWithoutSynchronization(HTMLNames::placeholderAttr);
+        information.inputMode = inputModeForAssistedNode(element);
     } else if (is<HTMLInputElement>(*m_assistedNode)) {
         HTMLInputElement& element = downcast<HTMLInputElement>(*m_assistedNode);
         HTMLFormElement* form = element.form();
@@ -2474,6 +2498,7 @@
         }
 #endif
 
+        information.inputMode = inputModeForAssistedNode(element);
         information.isReadOnly = element.isReadOnly();
         information.value = element.value();
         information.valueAsNumber = element.valueAsNumber();

Modified: trunk/Tools/ChangeLog (235200 => 235201)


--- trunk/Tools/ChangeLog	2018-08-22 21:08:38 UTC (rev 235200)
+++ trunk/Tools/ChangeLog	2018-08-22 21:22:13 UTC (rev 235201)
@@ -1,3 +1,17 @@
+2018-08-22  Aditya Keerthi  <akeer...@apple.com>
+
+        [iOS] Add support for the inputmode attribute
+        https://bugs.webkit.org/show_bug.cgi?id=183621
+
+        Reviewed by Tim Horton.
+
+        Added an API test to verify that the correct UIKeyboardType is set depending on
+        the type, inputmode, and pattern specified for an input field.
+
+        * TestWebKitAPI/Tests/ios/KeyboardInputTestsIOS.mm:
+        (TestWebKitAPI::TEST):
+        * TestWebKitAPI/ios/UIKitSPI.h:
+
 2018-08-22  Alex Christensen  <achristen...@webkit.org>
 
         Fix API test on Sierra after r235139

Modified: trunk/Tools/TestWebKitAPI/Tests/ios/KeyboardInputTestsIOS.mm (235200 => 235201)


--- trunk/Tools/TestWebKitAPI/Tests/ios/KeyboardInputTestsIOS.mm	2018-08-22 21:08:38 UTC (rev 235200)
+++ trunk/Tools/TestWebKitAPI/Tests/ios/KeyboardInputTestsIOS.mm	2018-08-22 21:22:13 UTC (rev 235201)
@@ -163,6 +163,82 @@
     [webView waitForSelectionViewRectsToBecome:expectedSelectionRects];
 }
 
+TEST(KeyboardInputTests, KeyboardTypeForInput)
+{
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+    auto inputDelegate = adoptNS([[TestInputDelegate alloc] init]);
+
+    [inputDelegate setFocusStartsInputSessionPolicyHandler:[&] (WKWebView *, id <_WKFocusedElementInfo>) -> _WKFocusStartsInputSessionPolicy {
+        return _WKFocusStartsInputSessionPolicyAllow;
+    }];
+    [webView _setInputDelegate:inputDelegate.get()];
+    [webView synchronouslyLoadHTMLString:@"<input id='input'>"];
+
+    auto runTest = ^(NSString *inputType, NSString *inputMode, NSString *pattern, UIKeyboardType expectedKeyboardType) {
+        [webView stringByEvaluatingJavaScript:@"input.blur()"];
+        [webView stringByEvaluatingJavaScript:[NSString stringWithFormat:@"input.type = '%@'; input.inputMode = '%@'; input.pattern = '%@'", inputType, inputMode, pattern]];
+        [webView stringByEvaluatingJavaScript:@"input.focus()"];
+
+        UIView<UITextInputPrivate> *textInput = (UIView<UITextInputPrivate> *)[webView textInputContentView];
+        UIKeyboardType keyboardType = [textInput textInputTraits].keyboardType;
+
+        bool success = keyboardType == expectedKeyboardType;
+        if (!success)
+            NSLog(@"Displayed %li for <input type='%@' inputmode='%@' pattern='%@'>. Expected %li.", (long)keyboardType, inputType, inputMode, pattern, (long)expectedKeyboardType);
+
+        return success;
+    };
+
+    NSDictionary *expectedKeyboardTypeForInputType = @{
+        @"text": @(UIKeyboardTypeDefault),
+        @"password": @(UIKeyboardTypeDefault),
+        @"search": @(UIKeyboardTypeDefault),
+        @"email": @(UIKeyboardTypeEmailAddress),
+        @"tel": @(UIKeyboardTypePhonePad),
+        @"number": @(UIKeyboardTypeNumbersAndPunctuation),
+        @"url": @(UIKeyboardTypeURL)
+    };
+
+    NSDictionary *expectedKeyboardTypeForInputMode = @{
+        @"": @(-1),
+        @"text": @(UIKeyboardTypeDefault),
+        @"tel": @(UIKeyboardTypePhonePad),
+        @"url": @(UIKeyboardTypeURL),
+        @"email": @(UIKeyboardTypeEmailAddress),
+        @"numeric": @(UIKeyboardTypeNumbersAndPunctuation),
+        @"decimal": @(UIKeyboardTypeDecimalPad),
+        @"search": @(UIKeyboardTypeWebSearch)
+    };
+
+    NSDictionary *expectedKeyboardTypeForPattern = @{
+        @"": @(-1),
+        @"\\\\d*": @(UIKeyboardTypeNumberPad),
+        @"[0-9]*": @(UIKeyboardTypeNumberPad)
+    };
+
+    for (NSString *inputType in [expectedKeyboardTypeForInputType allKeys]) {
+        for (NSString *inputMode in [expectedKeyboardTypeForInputMode allKeys]) {
+            for (NSString *pattern in [expectedKeyboardTypeForPattern allKeys]) {
+                NSNumber *keyboardType;
+                if (inputMode.length) {
+                    // inputmode has the highest priority.
+                    keyboardType = expectedKeyboardTypeForInputMode[inputMode];
+                } else {
+                    if (pattern.length && ([inputType isEqual: @"text"] || [inputType isEqual: @"number"])) {
+                        // Special case for text and number inputs that have a numeric pattern.
+                        keyboardType = expectedKeyboardTypeForPattern[pattern];
+                    } else {
+                        // Otherwise, the input type determines the keyboard type.
+                        keyboardType = expectedKeyboardTypeForInputType[inputType];
+                    }
+                }
+
+                EXPECT_TRUE(runTest(inputType, inputMode, pattern, (UIKeyboardType)keyboardType.intValue));
+            }
+        }
+    }
+}
+
 } // namespace TestWebKitAPI
 
 #endif // WK_API_ENABLED && PLATFORM(IOS)

Modified: trunk/Tools/TestWebKitAPI/ios/UIKitSPI.h (235200 => 235201)


--- trunk/Tools/TestWebKitAPI/ios/UIKitSPI.h	2018-08-22 21:08:38 UTC (rev 235200)
+++ trunk/Tools/TestWebKitAPI/ios/UIKitSPI.h	2018-08-22 21:22:13 UTC (rev 235201)
@@ -59,6 +59,9 @@
 
 @end
 
+@interface UITextInputTraits : NSObject <UITextInputTraits>
+@end
+
 @protocol UIDragInteractionDelegate_ForWebKitOnly <UIDragInteractionDelegate>
 @optional
 - (void)_dragInteraction:(UIDragInteraction *)interaction prepareForSession:(id<UIDragSession>)session completion:(void(^)(void))completion;
@@ -71,6 +74,7 @@
 @class WebEvent;
 
 @protocol UITextInputPrivate <UITextInput, UITextInputTraits_Private>
+- (UITextInputTraits *)textInputTraits;
 - (void)insertTextSuggestion:(UITextSuggestion *)textSuggestion;
 - (void)handleKeyWebEvent:(WebEvent *)theEvent withCompletionHandler:(void (^)(WebEvent *, BOOL))completionHandler;
 @end
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to