Title: [247158] trunk
Revision
247158
Author
wenson_hs...@apple.com
Date
2019-07-05 09:22:42 -0700 (Fri, 05 Jul 2019)

Log Message

Touching media controls sometimes shows software keyboard
https://bugs.webkit.org/show_bug.cgi?id=199490
<rdar://problem/52076270>

Reviewed by Eric Carlson.

Source/WebKit:

In r243044, we added a compatibility hack for Google Slides (and other G-suite properties) to allow the on-
screen keyboard to show up after a prevented touch event in the case where an element was already focused, even
if the touch event handler doesn't explicitly refocus the element. However, this means that if a regular text
field (or other form control) has been programmatically focused, then interacting with any other element that
prevents default on touchstart will cause us to show the keyboard for that focused element.

To mitigate this, only fall down this refocusing codepath in the case where the focused element is a hidden
editable element (in the style of many Google productivity web apps). For non-hidden editable elements that are
already focused, this refocusing logic is not necessary, since the user should be able to interact with the
control to show the keyboard anyways; for hidden editable areas, this compatibility hack is actually needed,
since there is typically no other way for a user to focus these elements and show an on-screen keyboard.

Tests:  fast/events/touch/ios/show-keyboard-after-preventing-touchstart.html
        fast/events/touch/ios/do-not-show-keyboard-after-preventing-touchstart.html

* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::dispatchTouchEvent):
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::WebPage::isTransparentOrFullyClipped const):

Renamed from enclosingLayerIsTransparentOrFullyClipped, and pulled out into a private helper method.

(WebKit::WebPage::platformEditorState const):
(WebKit::WebPage::requestEvasionRectsAboveSelection):
(WebKit::WebPage::getFocusedElementInformation):
(WebKit::enclosingLayerIsTransparentOrFullyClipped): Deleted.

Tools:

Adds plumbing for a new testing hook to check whether or not there is an active input session. See other
ChangeLog entries for more detail.

* DumpRenderTree/ios/UIScriptControllerIOS.mm:
(WTR::UIScriptController::hasInputSession const):
* TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl:
* TestRunnerShared/UIScriptContext/UIScriptController.cpp:
(WTR::UIScriptController::hasInputSession const):
* TestRunnerShared/UIScriptContext/UIScriptController.h:
* WebKitTestRunner/ios/UIScriptControllerIOS.mm:
(WTR::UIScriptController::hasInputSession const):

LayoutTests:

Adds a new layout test to verify that the keyboard only appears after a handled touch event if the focused
element is inside a hidden editable area; otherwise, the keyboard should not be present.

* fast/events/touch/ios/do-not-show-keyboard-after-preventing-touchstart-expected.txt: Added.
* fast/events/touch/ios/do-not-show-keyboard-after-preventing-touchstart.html: Added.

This test passes as long as we didn't begin showing the keyboard after tapping.

* fast/events/touch/ios/show-keyboard-after-preventing-touchstart-expected.txt:
* fast/events/touch/ios/show-keyboard-after-preventing-touchstart.html:

Adjust this existing test to make the focused textarea hidden.

* resources/ui-helper.js:
(window.UIHelper.hasInputSession):

Add a new testing hook to check whether there is an active input session.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (247157 => 247158)


--- trunk/LayoutTests/ChangeLog	2019-07-05 15:29:11 UTC (rev 247157)
+++ trunk/LayoutTests/ChangeLog	2019-07-05 16:22:42 UTC (rev 247158)
@@ -1,3 +1,29 @@
+2019-07-05  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        Touching media controls sometimes shows software keyboard
+        https://bugs.webkit.org/show_bug.cgi?id=199490
+        <rdar://problem/52076270>
+
+        Reviewed by Eric Carlson.
+
+        Adds a new layout test to verify that the keyboard only appears after a handled touch event if the focused
+        element is inside a hidden editable area; otherwise, the keyboard should not be present.
+
+        * fast/events/touch/ios/do-not-show-keyboard-after-preventing-touchstart-expected.txt: Added.
+        * fast/events/touch/ios/do-not-show-keyboard-after-preventing-touchstart.html: Added.
+
+        This test passes as long as we didn't begin showing the keyboard after tapping.
+
+        * fast/events/touch/ios/show-keyboard-after-preventing-touchstart-expected.txt:
+        * fast/events/touch/ios/show-keyboard-after-preventing-touchstart.html:
+
+        Adjust this existing test to make the focused textarea hidden.
+
+        * resources/ui-helper.js:
+        (window.UIHelper.hasInputSession):
+
+        Add a new testing hook to check whether there is an active input session.
+
 2019-07-05  Antoine Quint  <grao...@apple.com>
 
         [Pointer Events] Respect pointer capture when dispatching mouse boundary events and updating :hover

Added: trunk/LayoutTests/fast/events/touch/ios/do-not-show-keyboard-after-preventing-touchstart-expected.txt (0 => 247158)


--- trunk/LayoutTests/fast/events/touch/ios/do-not-show-keyboard-after-preventing-touchstart-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/events/touch/ios/do-not-show-keyboard-after-preventing-touchstart-expected.txt	2019-07-05 16:22:42 UTC (rev 247158)
@@ -0,0 +1,11 @@
+
+Verifies that the keyboard does not show up even after preventing default on touchstart when a regular input field is focused. To manually test, tap the red box; the keyboard should not appear.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS hasInputSession is false
+PASS document.activeElement is textarea
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/events/touch/ios/do-not-show-keyboard-after-preventing-touchstart.html (0 => 247158)


--- trunk/LayoutTests/fast/events/touch/ios/do-not-show-keyboard-after-preventing-touchstart.html	                        (rev 0)
+++ trunk/LayoutTests/fast/events/touch/ios/do-not-show-keyboard-after-preventing-touchstart.html	2019-07-05 16:22:42 UTC (rev 247158)
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script src=""
+<style>
+html, body {
+    width: 100%;
+    height: 100%;
+    margin: 0;
+}
+
+textarea, #target {
+    width: 100%;
+    height: 100px;
+}
+
+#target {
+    background-color: tomato;
+    opacity: 0.25;
+}
+</style>
+</head>
+<body>
+    <textarea></textarea>
+    <div id="target"></div>
+    <pre id="description"></pre>
+    <pre id="console"></pre>
+</body>
+<script>
+    jsTestIsAsync = true;
+    textarea = document.querySelector("textarea");
+    target = document.getElementById("target");
+    target.addEventListener("touchstart", event => event.preventDefault());
+
+    description("Verifies that the keyboard does not show up even after preventing default on touchstart when a regular input field is focused. To manually test, tap the red box; the keyboard should not appear.");
+
+    addEventListener("load", async () => {
+        textarea.focus();
+        await UIHelper.activateElement(target);
+        await UIHelper.ensurePresentationUpdate();
+        hasInputSession = await UIHelper.hasInputSession();
+        shouldBe("hasInputSession", "false");
+        shouldBe("document.activeElement", "textarea");
+        finishJSTest();
+    });
+</script>
+</html>

Modified: trunk/LayoutTests/fast/events/touch/ios/show-keyboard-after-preventing-touchstart-expected.txt (247157 => 247158)


--- trunk/LayoutTests/fast/events/touch/ios/show-keyboard-after-preventing-touchstart-expected.txt	2019-07-05 15:29:11 UTC (rev 247157)
+++ trunk/LayoutTests/fast/events/touch/ios/show-keyboard-after-preventing-touchstart-expected.txt	2019-07-05 16:22:42 UTC (rev 247158)
@@ -1,5 +1,5 @@
 
-Verifies that the keyboard shows up even after preventing default on touchstart. To manually test, tap the textarea; the textarea should remain focused, and the keyboard should appear.
+Verifies that the keyboard shows up even after preventing default on touchstart when focusing a hidden editable area. To manually test, tap the red box; the textarea should remain focused, and the keyboard should appear.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 

Modified: trunk/LayoutTests/fast/events/touch/ios/show-keyboard-after-preventing-touchstart.html (247157 => 247158)


--- trunk/LayoutTests/fast/events/touch/ios/show-keyboard-after-preventing-touchstart.html	2019-07-05 15:29:11 UTC (rev 247157)
+++ trunk/LayoutTests/fast/events/touch/ios/show-keyboard-after-preventing-touchstart.html	2019-07-05 16:22:42 UTC (rev 247158)
@@ -10,16 +10,31 @@
     margin: 0;
 }
 
-textarea {
+textarea, #target {
     width: 100%;
     height: 100px;
-    font-size: 50px;
-    text-align: center;
+    position: absolute;
+    top: 0;
 }
+
+#target {
+    background-color: tomato;
+    z-index: 1;
+    opacity: 0.25;
+}
+
+textarea {
+    opacity: 0;
+}
+
+#description {
+    margin-top: 100px;
+}
 </style>
 </head>
 <body>
     <textarea></textarea>
+    <div id="target"></div>
     <pre id="description"></pre>
     <pre id="console"></pre>
 </body>
@@ -26,13 +41,14 @@
 <script>
     jsTestIsAsync = true;
     textarea = document.querySelector("textarea");
+    target = document.getElementById("target");
+    target.addEventListener("touchstart", event => event.preventDefault());
 
-    description("Verifies that the keyboard shows up even after preventing default on touchstart. To manually test, tap the textarea; the textarea should remain focused, and the keyboard should appear.");
+    description("Verifies that the keyboard shows up even after preventing default on touchstart when focusing a hidden editable area. To manually test, tap the red box; the textarea should remain focused, and the keyboard should appear.");
 
-    textarea.addEventListener("touchstart", event => event.preventDefault());
     addEventListener("load", async () => {
         textarea.focus();
-        await UIHelper.activateElementAndWaitForInputSession(textarea);
+        await UIHelper.activateElementAndWaitForInputSession(target);
         testPassed("keyboard was shown.");
         shouldBe("document.activeElement", "textarea");
         textarea.blur();

Modified: trunk/LayoutTests/resources/ui-helper.js (247157 => 247158)


--- trunk/LayoutTests/resources/ui-helper.js	2019-07-05 15:29:11 UTC (rev 247157)
+++ trunk/LayoutTests/resources/ui-helper.js	2019-07-05 16:22:42 UTC (rev 247158)
@@ -372,6 +372,13 @@
         });
     }
 
+    static hasInputSession()
+    {
+        return new Promise(resolve => {
+            testRunner.runUIScript("uiController.hasInputSession", result => resolve(result === "true"));
+        });
+    }
+
     static isPresentingModally()
     {
         return new Promise(resolve => {

Modified: trunk/Source/WebKit/ChangeLog (247157 => 247158)


--- trunk/Source/WebKit/ChangeLog	2019-07-05 15:29:11 UTC (rev 247157)
+++ trunk/Source/WebKit/ChangeLog	2019-07-05 16:22:42 UTC (rev 247158)
@@ -1,3 +1,39 @@
+2019-07-05  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        Touching media controls sometimes shows software keyboard
+        https://bugs.webkit.org/show_bug.cgi?id=199490
+        <rdar://problem/52076270>
+
+        Reviewed by Eric Carlson.
+
+        In r243044, we added a compatibility hack for Google Slides (and other G-suite properties) to allow the on-
+        screen keyboard to show up after a prevented touch event in the case where an element was already focused, even
+        if the touch event handler doesn't explicitly refocus the element. However, this means that if a regular text
+        field (or other form control) has been programmatically focused, then interacting with any other element that
+        prevents default on touchstart will cause us to show the keyboard for that focused element.
+
+        To mitigate this, only fall down this refocusing codepath in the case where the focused element is a hidden
+        editable element (in the style of many Google productivity web apps). For non-hidden editable elements that are
+        already focused, this refocusing logic is not necessary, since the user should be able to interact with the
+        control to show the keyboard anyways; for hidden editable areas, this compatibility hack is actually needed,
+        since there is typically no other way for a user to focus these elements and show an on-screen keyboard.
+
+        Tests:  fast/events/touch/ios/show-keyboard-after-preventing-touchstart.html
+                fast/events/touch/ios/do-not-show-keyboard-after-preventing-touchstart.html
+
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::dispatchTouchEvent):
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/ios/WebPageIOS.mm:
+        (WebKit::WebPage::isTransparentOrFullyClipped const):
+
+        Renamed from enclosingLayerIsTransparentOrFullyClipped, and pulled out into a private helper method.
+
+        (WebKit::WebPage::platformEditorState const):
+        (WebKit::WebPage::requestEvasionRectsAboveSelection):
+        (WebKit::WebPage::getFocusedElementInformation):
+        (WebKit::enclosingLayerIsTransparentOrFullyClipped): Deleted.
+
 2019-07-04  Chris Dumez  <cdu...@apple.com>
 
         Simplify logic that handles registering WebProcessProxy objects with their WebsiteDataStore

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp (247157 => 247158)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2019-07-05 15:29:11 UTC (rev 247157)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2019-07-05 16:22:42 UTC (rev 247158)
@@ -2896,7 +2896,7 @@
     if (handled && oldFocusedElement) {
         auto newFocusedFrame = makeRefPtr(m_page->focusController().focusedFrame());
         auto newFocusedElement = makeRefPtr(newFocusedFrame ? newFocusedFrame->document()->focusedElement() : nullptr);
-        if (oldFocusedElement == newFocusedElement)
+        if (oldFocusedElement == newFocusedElement && isTransparentOrFullyClipped(*newFocusedElement))
             elementDidRefocus(*newFocusedElement);
     }
 }

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.h (247157 => 247158)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.h	2019-07-05 15:29:11 UTC (rev 247157)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.h	2019-07-05 16:22:42 UTC (rev 247158)
@@ -1448,6 +1448,7 @@
 
 #if PLATFORM(IOS_FAMILY)
     void didChooseFilesForOpenPanelWithDisplayStringAndIcon(const Vector<String>&, const String& displayString, const IPC::DataReference& iconData);
+    bool isTransparentOrFullyClipped(const WebCore::Element&) const;
 #endif
 
 #if ENABLE(SANDBOX_EXTENSIONS)

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


--- trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm	2019-07-05 15:29:11 UTC (rev 247157)
+++ trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm	2019-07-05 16:22:42 UTC (rev 247158)
@@ -185,9 +185,13 @@
     data.hasPlainText = data.hasContent && hasAnyPlainText(Range::create(root->document(), VisiblePosition { startInEditableRoot }, VisiblePosition { lastPositionInNode(root) }));
 }
 
-static bool enclosingLayerIsTransparentOrFullyClipped(const RenderObject& renderer)
+bool WebPage::isTransparentOrFullyClipped(const Element& element) const
 {
-    auto* enclosingLayer = renderer.enclosingLayer();
+    auto* renderer = element.renderer();
+    if (!renderer)
+        return false;
+
+    auto* enclosingLayer = renderer->enclosingLayer();
     return enclosingLayer && enclosingLayer->isTransparentOrFullyClippedRespectingParentFrames();
 }
 
@@ -264,9 +268,8 @@
             postLayoutData.caretColor = renderer.style().caretColor();
         }
         if (result.isContentEditable) {
-            auto container = makeRefPtr(selection.rootEditableElement());
-            if (container && container->renderer())
-                postLayoutData.editableRootIsTransparentOrFullyClipped = enclosingLayerIsTransparentOrFullyClipped(*container->renderer());
+            if (auto container = makeRefPtr(selection.rootEditableElement()))
+                postLayoutData.editableRootIsTransparentOrFullyClipped = isTransparentOrFullyClipped(*container);
         }
         computeEditableRootHasContentAndPlainText(selection, postLayoutData);
     }
@@ -1801,7 +1804,7 @@
         return;
     }
 
-    if (!m_focusedElement || !m_focusedElement->renderer() || enclosingLayerIsTransparentOrFullyClipped(*m_focusedElement->renderer())) {
+    if (!m_focusedElement || !m_focusedElement->renderer() || isTransparentOrFullyClipped(*m_focusedElement)) {
         reply({ });
         return;
     }
@@ -2991,7 +2994,7 @@
         information.isReadOnly = false;
     }
 
-    if (m_focusedElement->document().quirks().shouldSuppressAutocorrectionAndAutocaptializationInHiddenEditableAreas() && m_focusedElement->renderer() && enclosingLayerIsTransparentOrFullyClipped(*m_focusedElement->renderer())) {
+    if (m_focusedElement->document().quirks().shouldSuppressAutocorrectionAndAutocaptializationInHiddenEditableAreas() && isTransparentOrFullyClipped(*m_focusedElement)) {
         information.autocapitalizeType = AutocapitalizeTypeNone;
         information.isAutocorrect = false;
     }

Modified: trunk/Tools/ChangeLog (247157 => 247158)


--- trunk/Tools/ChangeLog	2019-07-05 15:29:11 UTC (rev 247157)
+++ trunk/Tools/ChangeLog	2019-07-05 16:22:42 UTC (rev 247158)
@@ -1,3 +1,23 @@
+2019-07-05  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        Touching media controls sometimes shows software keyboard
+        https://bugs.webkit.org/show_bug.cgi?id=199490
+        <rdar://problem/52076270>
+
+        Reviewed by Eric Carlson.
+
+        Adds plumbing for a new testing hook to check whether or not there is an active input session. See other
+        ChangeLog entries for more detail.
+
+        * DumpRenderTree/ios/UIScriptControllerIOS.mm:
+        (WTR::UIScriptController::hasInputSession const):
+        * TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl:
+        * TestRunnerShared/UIScriptContext/UIScriptController.cpp:
+        (WTR::UIScriptController::hasInputSession const):
+        * TestRunnerShared/UIScriptContext/UIScriptController.h:
+        * WebKitTestRunner/ios/UIScriptControllerIOS.mm:
+        (WTR::UIScriptController::hasInputSession const):
+
 2019-07-04  Aakash Jain  <aakash_j...@apple.com>
 
         [ews-build] Remove GTK and WPE queue from old EWS and dashboard

Modified: trunk/Tools/DumpRenderTree/ios/UIScriptControllerIOS.mm (247157 => 247158)


--- trunk/Tools/DumpRenderTree/ios/UIScriptControllerIOS.mm	2019-07-05 15:29:11 UTC (rev 247157)
+++ trunk/Tools/DumpRenderTree/ios/UIScriptControllerIOS.mm	2019-07-05 16:22:42 UTC (rev 247158)
@@ -287,6 +287,11 @@
     return false;
 }
 
+bool UIScriptController::hasInputSession() const
+{
+    return false;
+}
+
 double UIScriptController::minimumZoomScale() const
 {
     return gWebScrollView.minimumZoomScale;

Modified: trunk/Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl (247157 => 247158)


--- trunk/Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl	2019-07-05 15:29:11 UTC (rev 247157)
+++ trunk/Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl	2019-07-05 16:22:42 UTC (rev 247158)
@@ -224,6 +224,7 @@
     attribute object didShowKeyboardCallback;
     attribute object didHideKeyboardCallback;
     readonly attribute boolean isShowingKeyboard;
+    readonly attribute boolean hasInputSession;
 
     attribute object didShowMenuCallback;
     attribute object didHideMenuCallback;

Modified: trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.cpp (247157 => 247158)


--- trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.cpp	2019-07-05 15:29:11 UTC (rev 247157)
+++ trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.cpp	2019-07-05 16:22:42 UTC (rev 247158)
@@ -453,6 +453,11 @@
     return false;
 }
 
+bool UIScriptController::hasInputSession() const
+{
+    return false;
+}
+
 double UIScriptController::zoomScale() const
 {
     return 1;

Modified: trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.h (247157 => 247158)


--- trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.h	2019-07-05 15:29:11 UTC (rev 247157)
+++ trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.h	2019-07-05 16:22:42 UTC (rev 247158)
@@ -163,6 +163,7 @@
     JSValueRef didHideKeyboardCallback() const;
 
     bool isShowingKeyboard() const;
+    bool hasInputSession() const;
 
     void setDidHideMenuCallback(JSValueRef);
     JSValueRef didHideMenuCallback() const;

Modified: trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm (247157 => 247158)


--- trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm	2019-07-05 15:29:11 UTC (rev 247157)
+++ trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm	2019-07-05 16:22:42 UTC (rev 247158)
@@ -625,6 +625,11 @@
     return TestController::singleton().mainWebView()->platformView().showingKeyboard;
 }
 
+bool UIScriptController::hasInputSession() const
+{
+    return TestController::singleton().mainWebView()->platformView().isInteractingWithFormControl;
+}
+
 void UIScriptController::applyAutocorrection(JSStringRef newString, JSStringRef oldString, JSValueRef callback)
 {
     unsigned callbackID = m_context->prepareForAsyncTask(callback, CallbackTypeNonPersistent);
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to