- Revision
- 277265
- Author
- [email protected]
- Date
- 2021-05-10 09:26:17 -0700 (Mon, 10 May 2021)
Log Message
[iPadOS] Do not present custom input peripherals when switching back to a tab with a focused element
https://bugs.webkit.org/show_bug.cgi?id=225541
<rdar://problem/77537795>
Reviewed by Wenson Hsieh.
Source/WebKit:
With the introduction of desktop-class browing on iPad, form control
elements began to retain focus even after their input peripheral
(popover, menu, etc.) was dismissed. This behavior matches macOS - when
a <select> element is clicked, a menu is presented, and when a option
is selected, the menu is dismissed but the element retains focus.
Consequently, when a <select> menu is dismissed by choosing an option on
an iPad with a hardware keyboard, the element retains focus. Now, when
switching tabs and coming back to the tab with the focused <select>, an
activity state update is triggered. Upon recognizing that there is a
focused element, an ElementDidFocus message is sent to the UIProcess.
In [WKContentView _elementDidFocus:userIsInteracting:blurPreviousNode:activityStateChanges:userObject:],
the focus is given permission to present the input peripheral (menu)
when the hardware keyboard is attached. This is necessary when necessary
when focusing a text input, because the UCB needs to be displayed and
text selection needs to be set up. However, the behavior is undesirable
for elements that present a popover or a menu (select, color inputs, and
date inputs), since the user is unexpectedly shown an input peripheral.
Even worse, the user's scroll position will be changed to ensure the
focused element is visible.
To fix the undesirable behavior, and get closer to the macOS behavior,
custom input peripherals should not be displayed when switching back
to a tab with a focused element.
Test: fast/forms/ios/focus-select-and-switch-tabs.html
* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView _elementDidFocus:userIsInteracting:blurPreviousNode:activityStateChanges:userObject:]):
Only show the input peripheral if it is not a keyboard view.
Tools:
Updated a UIScriptController hook that simulates attaching a hardware
keyboard to also swizzle [UIKeyboard isInHardwareKeyboardMode].
* WebKitTestRunner/ios/TestControllerIOS.mm:
(WTR::TestController::platformInitialize):
(WTR::TestController::platformResetStateToConsistentValues):
Moved the default swizzling behavior into this method so that it remains
consistent across tests.
Unfortunately, the default swizzling behavior contrasts with the default
value of GSEventSetHardwareKeyboardAttached. However, this is an existing
inconsistency, and should be looked at more carefully in a separate
investigation.
* WebKitTestRunner/ios/UIScriptControllerIOS.mm:
(WTR::returnYes):
(WTR::returnNo):
(WTR::UIScriptControllerIOS::setHardwareKeyboardAttached):
LayoutTests:
Added a test which simulates a tab switch by removing and re-adding the
webview to the window.
* fast/forms/ios/focus-select-and-switch-tabs-expected.txt: Added.
* fast/forms/ios/focus-select-and-switch-tabs.html: Added.
* resources/ui-helper.js:
(window.UIHelper.becomeFirstResponder):
(window.UIHelper.removeViewFromWindow):
(window.UIHelper.addViewToWindow):
Modified Paths
Added Paths
Diff
Modified: trunk/LayoutTests/ChangeLog (277264 => 277265)
--- trunk/LayoutTests/ChangeLog 2021-05-10 16:08:29 UTC (rev 277264)
+++ trunk/LayoutTests/ChangeLog 2021-05-10 16:26:17 UTC (rev 277265)
@@ -1,3 +1,21 @@
+2021-05-10 Aditya Keerthi <[email protected]>
+
+ [iPadOS] Do not present custom input peripherals when switching back to a tab with a focused element
+ https://bugs.webkit.org/show_bug.cgi?id=225541
+ <rdar://problem/77537795>
+
+ Reviewed by Wenson Hsieh.
+
+ Added a test which simulates a tab switch by removing and re-adding the
+ webview to the window.
+
+ * fast/forms/ios/focus-select-and-switch-tabs-expected.txt: Added.
+ * fast/forms/ios/focus-select-and-switch-tabs.html: Added.
+ * resources/ui-helper.js:
+ (window.UIHelper.becomeFirstResponder):
+ (window.UIHelper.removeViewFromWindow):
+ (window.UIHelper.addViewToWindow):
+
2021-05-10 Philippe Normand <[email protected]>
[GStreamer] fast/mediastream/MediaStream-video-element-video-tracks-disabled.html fails
Added: trunk/LayoutTests/fast/forms/ios/focus-select-and-switch-tabs-expected.txt (0 => 277265)
--- trunk/LayoutTests/fast/forms/ios/focus-select-and-switch-tabs-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/forms/ios/focus-select-and-switch-tabs-expected.txt 2021-05-10 16:26:17 UTC (rev 277265)
@@ -0,0 +1,10 @@
+This test verifies that focusing a select element, choosing an option, and then switching tabs, does not re-open a menu.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS didShowContextMenu is false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/fast/forms/ios/focus-select-and-switch-tabs.html (0 => 277265)
--- trunk/LayoutTests/fast/forms/ios/focus-select-and-switch-tabs.html (rev 0)
+++ trunk/LayoutTests/fast/forms/ios/focus-select-and-switch-tabs.html 2021-05-10 16:26:17 UTC (rev 277265)
@@ -0,0 +1,44 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true ] -->
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
+ <script src=""
+ <script src=""
+ </head>
+<body>
+<select id="select">
+ <option>A</option>
+ <option>B</option>
+ <option>C</option>
+</select>
+</body>
+<script>
+jsTestIsAsync = true;
+
+addEventListener("load", async () => {
+ description("This test verifies that focusing a select element, choosing an option, and then switching tabs, does not re-open a menu.");
+
+ await UIHelper.setHardwareKeyboardAttached(true);
+
+ // Open and close the <select> menu.
+ await UIHelper.activateElement(select);
+ await UIHelper.waitForContextMenuToShow();
+ await UIHelper.selectFormAccessoryPickerRow(1);
+ await UIHelper.waitForContextMenuToHide();
+
+ // Simulate a tab switch, returning to the current tab.
+ await UIHelper.removeViewFromWindow();
+ await UIHelper.addViewToWindow();
+ await UIHelper.becomeFirstResponder();
+
+ // Check if the menu was presented after returning to the tab.
+ await UIHelper.ensurePresentationUpdate();
+ await UIHelper.selectFormAccessoryPickerRow(0);
+ await UIHelper.ensurePresentationUpdate();
+ didShowContextMenu = select.value === "A";
+ shouldBeFalse("didShowContextMenu");
+
+ finishJSTest();
+});
+</script>
+</html>
Modified: trunk/LayoutTests/resources/ui-helper.js (277264 => 277265)
--- trunk/LayoutTests/resources/ui-helper.js 2021-05-10 16:08:29 UTC (rev 277264)
+++ trunk/LayoutTests/resources/ui-helper.js 2021-05-10 16:26:17 UTC (rev 277265)
@@ -1096,6 +1096,30 @@
return new Promise(resolve => testRunner.runUIScript(`uiController.resignFirstResponder()`, resolve));
}
+ static becomeFirstResponder()
+ {
+ if (!this.isWebKit2())
+ return Promise.resolve();
+
+ return new Promise(resolve => testRunner.runUIScript(`uiController.becomeFirstResponder()`, resolve));
+ }
+
+ static removeViewFromWindow()
+ {
+ if (!this.isWebKit2())
+ return Promise.resolve();
+
+ return new Promise(resolve => testRunner.runUIScript(`uiController.removeViewFromWindow()`, resolve));
+ }
+
+ static addViewToWindow()
+ {
+ if (!this.isWebKit2())
+ return Promise.resolve();
+
+ return new Promise(resolve => testRunner.runUIScript(`uiController.addViewToWindow()`, resolve));
+ }
+
static minimumZoomScale()
{
if (!this.isWebKit2())
Modified: trunk/Source/WebKit/ChangeLog (277264 => 277265)
--- trunk/Source/WebKit/ChangeLog 2021-05-10 16:08:29 UTC (rev 277264)
+++ trunk/Source/WebKit/ChangeLog 2021-05-10 16:26:17 UTC (rev 277265)
@@ -1,3 +1,44 @@
+2021-05-10 Aditya Keerthi <[email protected]>
+
+ [iPadOS] Do not present custom input peripherals when switching back to a tab with a focused element
+ https://bugs.webkit.org/show_bug.cgi?id=225541
+ <rdar://problem/77537795>
+
+ Reviewed by Wenson Hsieh.
+
+ With the introduction of desktop-class browing on iPad, form control
+ elements began to retain focus even after their input peripheral
+ (popover, menu, etc.) was dismissed. This behavior matches macOS - when
+ a <select> element is clicked, a menu is presented, and when a option
+ is selected, the menu is dismissed but the element retains focus.
+
+ Consequently, when a <select> menu is dismissed by choosing an option on
+ an iPad with a hardware keyboard, the element retains focus. Now, when
+ switching tabs and coming back to the tab with the focused <select>, an
+ activity state update is triggered. Upon recognizing that there is a
+ focused element, an ElementDidFocus message is sent to the UIProcess.
+
+ In [WKContentView _elementDidFocus:userIsInteracting:blurPreviousNode:activityStateChanges:userObject:],
+ the focus is given permission to present the input peripheral (menu)
+ when the hardware keyboard is attached. This is necessary when necessary
+ when focusing a text input, because the UCB needs to be displayed and
+ text selection needs to be set up. However, the behavior is undesirable
+ for elements that present a popover or a menu (select, color inputs, and
+ date inputs), since the user is unexpectedly shown an input peripheral.
+ Even worse, the user's scroll position will be changed to ensure the
+ focused element is visible.
+
+ To fix the undesirable behavior, and get closer to the macOS behavior,
+ custom input peripherals should not be displayed when switching back
+ to a tab with a focused element.
+
+ Test: fast/forms/ios/focus-select-and-switch-tabs.html
+
+ * UIProcess/ios/WKContentViewInteraction.mm:
+ (-[WKContentView _elementDidFocus:userIsInteracting:blurPreviousNode:activityStateChanges:userObject:]):
+
+ Only show the input peripheral if it is not a keyboard view.
+
2021-05-10 Alex Christensen <[email protected]>
Remove WKBundlePageGroupRef
Modified: trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm (277264 => 277265)
--- trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm 2021-05-10 16:08:29 UTC (rev 277264)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm 2021-05-10 16:26:17 UTC (rev 277265)
@@ -6216,7 +6216,7 @@
if (_isChangingFocus)
return YES;
- if ([UIKeyboard isInHardwareKeyboardMode])
+ if (_isFocusingElementWithKeyboard && [UIKeyboard isInHardwareKeyboardMode])
return YES;
#endif
}
Modified: trunk/Tools/ChangeLog (277264 => 277265)
--- trunk/Tools/ChangeLog 2021-05-10 16:08:29 UTC (rev 277264)
+++ trunk/Tools/ChangeLog 2021-05-10 16:26:17 UTC (rev 277265)
@@ -1,3 +1,31 @@
+2021-05-10 Aditya Keerthi <[email protected]>
+
+ [iPadOS] Do not present custom input peripherals when switching back to a tab with a focused element
+ https://bugs.webkit.org/show_bug.cgi?id=225541
+ <rdar://problem/77537795>
+
+ Reviewed by Wenson Hsieh.
+
+ Updated a UIScriptController hook that simulates attaching a hardware
+ keyboard to also swizzle [UIKeyboard isInHardwareKeyboardMode].
+
+ * WebKitTestRunner/ios/TestControllerIOS.mm:
+ (WTR::TestController::platformInitialize):
+ (WTR::TestController::platformResetStateToConsistentValues):
+
+ Moved the default swizzling behavior into this method so that it remains
+ consistent across tests.
+
+ Unfortunately, the default swizzling behavior contrasts with the default
+ value of GSEventSetHardwareKeyboardAttached. However, this is an existing
+ inconsistency, and should be looked at more carefully in a separate
+ investigation.
+
+ * WebKitTestRunner/ios/UIScriptControllerIOS.mm:
+ (WTR::returnYes):
+ (WTR::returnNo):
+ (WTR::UIScriptControllerIOS::setHardwareKeyboardAttached):
+
2021-05-10 Alex Christensen <[email protected]>
Remove WKBundlePageGroupRef
Modified: trunk/Tools/WebKitTestRunner/ios/TestControllerIOS.mm (277264 => 277265)
--- trunk/Tools/WebKitTestRunner/ios/TestControllerIOS.mm 2021-05-10 16:08:29 UTC (rev 277264)
+++ trunk/Tools/WebKitTestRunner/ios/TestControllerIOS.mm 2021-05-10 16:26:17 UTC (rev 277265)
@@ -110,10 +110,6 @@
CFNotificationCenterAddObserver(center, this, handleKeyboardDidHideNotification, (CFStringRef)UIKeyboardDidHideNotification, nullptr, CFNotificationSuspensionBehaviorDeliverImmediately);
CFNotificationCenterAddObserver(center, this, handleMenuWillHideNotification, (CFStringRef)UIMenuControllerWillHideMenuNotification, nullptr, CFNotificationSuspensionBehaviorDeliverImmediately);
CFNotificationCenterAddObserver(center, this, handleMenuDidHideNotification, (CFStringRef)UIMenuControllerDidHideMenuNotification, nullptr, CFNotificationSuspensionBehaviorDeliverImmediately);
-
- // Override the implementation of +[UIKeyboard isInHardwareKeyboardMode] to ensure that test runs are deterministic
- // regardless of whether a hardware keyboard is attached. We intentionally never restore the original implementation.
- method_setImplementation(class_getClassMethod([UIKeyboard class], @selector(isInHardwareKeyboardMode)), reinterpret_cast<IMP>(overrideIsInHardwareKeyboardMode));
}
void TestController::platformDestroy()
@@ -178,6 +174,12 @@
GSEventSetHardwareKeyboardAttached(true, 0);
+ // Override the implementation of +[UIKeyboard isInHardwareKeyboardMode] to ensure that test runs are deterministic
+ // regardless of whether a hardware keyboard is attached. We intentionally never restore the original implementation.
+ //
+ // FIXME: Investigate whether this can be removed. The swizzled return value is inconsistent with GSEventSetHardwareKeyboardAttached.
+ method_setImplementation(class_getClassMethod([UIKeyboard class], @selector(isInHardwareKeyboardMode)), reinterpret_cast<IMP>(overrideIsInHardwareKeyboardMode));
+
#if !HAVE(NONDESTRUCTIVE_IMAGE_PASTE_SUPPORT_QUERY)
// FIXME: Remove this workaround once -[UIKeyboardImpl delegateSupportsImagePaste] no longer increments the general pasteboard's changeCount.
if (!m_keyboardDelegateSupportsImagePasteSwizzler)
Modified: trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm (277264 => 277265)
--- trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm 2021-05-10 16:08:29 UTC (rev 277264)
+++ trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm 2021-05-10 16:26:17 UTC (rev 277265)
@@ -58,6 +58,16 @@
namespace WTR {
+static BOOL returnYes()
+{
+ return YES;
+}
+
+static BOOL returnNo()
+{
+ return NO;
+}
+
static NSDictionary *toNSDictionary(CGRect rect)
{
return @{
@@ -1210,6 +1220,7 @@
void UIScriptControllerIOS::setHardwareKeyboardAttached(bool attached)
{
GSEventSetHardwareKeyboardAttached(attached, 0);
+ method_setImplementation(class_getClassMethod([UIKeyboard class], @selector(isInHardwareKeyboardMode)), reinterpret_cast<IMP>(attached ? returnYes : returnNo));
}
void UIScriptControllerIOS::setAllowsViewportShrinkToFit(bool allows)