Title: [237305] trunk
Revision
237305
Author
wenson_hs...@apple.com
Date
2018-10-19 15:00:32 -0700 (Fri, 19 Oct 2018)

Log Message

[iOS] [Datalist] Can't pick datalist suggestions in a stock WKWebView
https://bugs.webkit.org/show_bug.cgi?id=190621
<rdar://problem/45310649>

Reviewed by Tim Horton.

Source/WebKit:

Fixes the bug by refactoring datalist suggestion information on iOS; currently, we override text suggestions on
_WKFormInputSession. This only works for a few internal clients (including Safari) that set a _WKInputDelegate
and also implement either -_webView:willStartInputSession: or -_webView:didStartInputSession:, which is
necessary in order to ensure that WebKit creates and maintains a form input session.

The two pieces of information that datalist code needs to vend to WKContentView are a list of UITextSuggestions
and a custom input view, which are both currently properties of _WKFormInputSession. This patch lifts these out
of the input session and makes them properties of WKContentView, which are used in
WebDataListSuggestionsDropdownIOS.

Test: fast/forms/datalist/datalist-textinput-suggestions-order.html

* UIProcess/ios/WKContentViewInteraction.h:
* UIProcess/ios/WKContentViewInteraction.mm:

Add new properties to WKContentView: an input view for datalist suggestions, and a list of text suggestions.

(-[WKFormInputSession setSuggestions:]):
(-[WKContentView setupInteraction]):
(-[WKContentView cleanupInteraction]):
(-[WKContentView _endEditing]):

Pull out common logic when resigning first responder or tabbing to the next or previous text field into a new
helper. This helper notifies `_inputPeripheral`, `_formInputSession`, and `_dataListTextSuggestionsInputView`
when editing has ended; the input peripheral and suggestions input view use this chance to send the value of the
form control to the web process.

(-[WKContentView resignFirstResponderForWebView]):
(-[WKContentView inputView]):

If a custom input view is not set but we have an input view for a datalist's text suggestions, use the datalist
input view.

(-[WKContentView accessoryTab:]):
(-[WKContentView _stopAssistingNode]):

Clear datalist state on WKContentView.

(-[WKContentView dataListTextSuggestionsInputView]):
(-[WKContentView dataListTextSuggestions]):
(-[WKContentView setDataListTextSuggestionsInputView:]):
(-[WKContentView setDataListTextSuggestions:]):
(-[WKContentView updateTextSuggestionsForInputDelegate]):

Pull out logic for setting suggestions on UIKit's `inputDelegate` (i.e. UIKeyboardImpl). We now first consult
internally-vended text suggestions from _WKFormInputSession; if an internal client has not overridden our text
suggestions, then we simply use suggestions from the current datalist (if present).

* UIProcess/ios/WebDataListSuggestionsDropdownIOS.mm:
(-[WKDataListSuggestionsPicker updateWithInformation:]):
(-[WKDataListSuggestionsPicker showSuggestionsDropdown:activationType:]):
(-[WKDataListSuggestionsPicker invalidate]):
(-[WKDataListSuggestionsPopover updateWithInformation:]):
(-[WKDataListSuggestionsPopover showSuggestionsDropdown:activationType:]):
(-[WKDataListSuggestionsPopover didSelectOptionAtIndex:]):

Change all the places that currently manipulate WKContentView's form input session to directly set text
suggestions and the text suggestion input view on the content view instead.

Tools:

Add a UIScriptController hook to resign first responder on WKWebView. See LayoutTests/ChangeLog for more detail.

* DumpRenderTree/ios/UIScriptControllerIOS.mm:
(WTR::UIScriptController::resignFirstResponder):
* DumpRenderTree/mac/UIScriptControllerMac.mm:
(WTR::UIScriptController::resignFirstResponder):
* TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl:
* TestRunnerShared/UIScriptContext/UIScriptController.cpp:
(WTR::UIScriptController::resignFirstResponder):
* TestRunnerShared/UIScriptContext/UIScriptController.h:
* WebKitTestRunner/UIScriptControllerCocoa.mm:
(WTR::UIScriptController::resignFirstResponder):
* WebKitTestRunner/ios/PlatformWebViewIOS.mm:
(WTR::PlatformWebView::makeWebViewFirstResponder):

Implement this method stub on iOS, to ensure that TestController::resetStateToConsistentValues restores first
responder on the WKWebView when running iOS layout tests.

* WebKitTestRunner/ios/TestControllerIOS.mm:
(WTR::TestController::platformResetStateToConsistentValues):

After resigning first responder to dismiss any on-screen keyboard, ensure that we restore first responder.

LayoutTests:

Refactor an existing layout test to run on both iOS and macOS. On both platforms, it checks that the top
suggestion respects option element order in the document, as well as the current contents of the text field.
On macOS, we use arrow keys and hit return to select a suggestion; on iOS, we tap the suggestions button and
simulate hitting the done button on the input view to dismiss the keyboard.

* fast/forms/datalist/datalist-textinput-suggestions-order-expected.txt:
* fast/forms/datalist/datalist-textinput-suggestions-order.html:
* platform/ios/TestExpectations:

Enable this test on iOS.

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

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (237304 => 237305)


--- trunk/LayoutTests/ChangeLog	2018-10-19 21:37:54 UTC (rev 237304)
+++ trunk/LayoutTests/ChangeLog	2018-10-19 22:00:32 UTC (rev 237305)
@@ -1,3 +1,26 @@
+2018-10-19  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        [iOS] [Datalist] Can't pick datalist suggestions in a stock WKWebView
+        https://bugs.webkit.org/show_bug.cgi?id=190621
+        <rdar://problem/45310649>
+
+        Reviewed by Tim Horton.
+
+        Refactor an existing layout test to run on both iOS and macOS. On both platforms, it checks that the top
+        suggestion respects option element order in the document, as well as the current contents of the text field.
+        On macOS, we use arrow keys and hit return to select a suggestion; on iOS, we tap the suggestions button and
+        simulate hitting the done button on the input view to dismiss the keyboard.
+
+        * fast/forms/datalist/datalist-textinput-suggestions-order-expected.txt:
+        * fast/forms/datalist/datalist-textinput-suggestions-order.html:
+        * platform/ios/TestExpectations:
+
+        Enable this test on iOS.
+
+        * resources/ui-helper.js:
+        (window.UIHelper.resignFirstResponder):
+        (window.UIHelper):
+
 2018-10-19  John Wilander  <wilan...@apple.com>
 
         Only cap lifetime of persistent cookies created client-side through document.cookie when resource load statistics is enabled

Modified: trunk/LayoutTests/fast/forms/datalist/datalist-textinput-suggestions-order-expected.txt (237304 => 237305)


--- trunk/LayoutTests/fast/forms/datalist/datalist-textinput-suggestions-order-expected.txt	2018-10-19 21:37:54 UTC (rev 237304)
+++ trunk/LayoutTests/fast/forms/datalist/datalist-textinput-suggestions-order-expected.txt	2018-10-19 22:00:32 UTC (rev 237305)
@@ -1,11 +1,10 @@
-Test to verify that prefix-matched values are displayed first
 
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+Top suggestion with empty text field: "Orange"
+Top suggestion with "a" in text field: "Apple"
 
-
-PASS input.value is "Orange"
-PASS input.value is "Apple"
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
+This test verifies that datalist suggestions in a text field are ordered in a way that respects the order of option elements in the document, as well as the contents of the text field. To test manually:
+Focus the text field.
+Check that "Orange" is the top suggestion.
+Type "a" and blur the text field.
+Focus the text field again.
+Check that "Apple" is the top suggestion.

Modified: trunk/LayoutTests/fast/forms/datalist/datalist-textinput-suggestions-order.html (237304 => 237305)


--- trunk/LayoutTests/fast/forms/datalist/datalist-textinput-suggestions-order.html	2018-10-19 21:37:54 UTC (rev 237304)
+++ trunk/LayoutTests/fast/forms/datalist/datalist-textinput-suggestions-order.html	2018-10-19 22:00:32 UTC (rev 237305)
@@ -1,8 +1,18 @@
-<!DOCTYPE html>
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true ] -->
 <html>
 <head>
-<script src=""
+<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
 <script src=""
+<style>
+input {
+    width: 300px;
+    height: 50px;
+}
+
+body {
+    margin: 0;
+}
+</style>
 </head>
 <body>
 
@@ -12,27 +22,52 @@
     <option>Pear</option>
     <option>Apple</option>
 </datalist>
+<pre>Top suggestion with empty text field: "<span id="first"></span>"</pre>
+<pre>Top suggestion with "a" in text field: "<span id="second"></span>"</pre>
+<br>
+<div>This test verifies that datalist suggestions in a text field are ordered in a way that respects the order of option
+elements in the document, as well as the contents of the text field. To test manually:</div>
+<ol>
+    <li>Focus the text field.</li>
+    <li>Check that "Orange" is the top suggestion.</li>
+    <li>Type "a" and blur the text field.</li>
+    <li>Focus the text field again.</li>
+    <li>Check that "Apple" is the top suggestion.</li>
+</ol>
 
 <script>
+if (window.testRunner) {
+    testRunner.waitUntilDone();
+    testRunner.dumpAsText();
+}
 
-description('Test to verify that prefix-matched values are displayed first');
+function focusInputFieldAndChooseFirstSuggestion()
+{
+    return new Promise(async resolve => {
+        await UIHelper.activateAndWaitForInputSessionAt(100, 25);
+        if (UIHelper.isIOS()) {
+            await UIHelper.tapAt(290, 30);
+            await UIHelper.resignFirstResponder();
+            await UIHelper.waitForKeyboardToHide();
+        } else {
+            await UIHelper.typeCharacter("downArrow");
+            await UIHelper.typeCharacter("\r");
+        }
+        resolve();
+    });
+}
 
-var input = document.getElementById("fruit");
+(async () => {
+    await focusInputFieldAndChooseFirstSuggestion();
+    first.textContent = fruit.value;
 
-UIHelper.activateElement(input);
-eventSender.keyDown("downArrow");
-eventSender.keyDown("\r");
-shouldBe('input.value', '"Orange"');
+    fruit.value = "a";
 
-input.value = "a";
+    await focusInputFieldAndChooseFirstSuggestion();
+    second.textContent = fruit.value;
 
-UIHelper.activateElement(input);
-eventSender.keyDown("downArrow");
-eventSender.keyDown("\r");
-shouldBe('input.value', '"Apple"');
-
+    testRunner.notifyDone();
+})();
 </script>
-
-<script src=""
 </body>
 </html>

Modified: trunk/LayoutTests/platform/ios/TestExpectations (237304 => 237305)


--- trunk/LayoutTests/platform/ios/TestExpectations	2018-10-19 21:37:54 UTC (rev 237304)
+++ trunk/LayoutTests/platform/ios/TestExpectations	2018-10-19 22:00:32 UTC (rev 237305)
@@ -3111,7 +3111,6 @@
 # Datalist
 webkit.org/b/186714 fast/forms/datalist/datalist-show-hide.html [ Skip ]
 webkit.org/b/186714 fast/forms/datalist/datalist-textinput-keydown.html [ Skip ]
-webkit.org/b/190621 fast/forms/datalist/datalist-textinput-suggestions-order.html [ Skip ]
 webkit.org/b/190613 fast/forms/datalist/update-range-with-datalist.html [ Skip ]
 
 # We are only accepting GLSL3 for macOS. 

Modified: trunk/LayoutTests/resources/ui-helper.js (237304 => 237305)


--- trunk/LayoutTests/resources/ui-helper.js	2018-10-19 21:37:54 UTC (rev 237304)
+++ trunk/LayoutTests/resources/ui-helper.js	2018-10-19 22:00:32 UTC (rev 237305)
@@ -132,6 +132,9 @@
 
     static waitForKeyboardToHide()
     {
+        if (!this.isWebKit2() || !this.isIOS())
+            return Promise.resolve();
+
         return new Promise(resolve => {
             testRunner.runUIScript(`
                 (function() {
@@ -350,4 +353,12 @@
 
         return new Promise(resolve => testRunner.runUIScript(`uiController.setViewScale(${scale})`, resolve));
     }
+
+    static resignFirstResponder()
+    {
+        if (!this.isWebKit2())
+            return Promise.resolve();
+
+        return new Promise(resolve => testRunner.runUIScript(`uiController.resignFirstResponder()`, resolve));
+    }
 }

Modified: trunk/Source/WebKit/ChangeLog (237304 => 237305)


--- trunk/Source/WebKit/ChangeLog	2018-10-19 21:37:54 UTC (rev 237304)
+++ trunk/Source/WebKit/ChangeLog	2018-10-19 22:00:32 UTC (rev 237305)
@@ -1,3 +1,70 @@
+2018-10-19  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        [iOS] [Datalist] Can't pick datalist suggestions in a stock WKWebView
+        https://bugs.webkit.org/show_bug.cgi?id=190621
+        <rdar://problem/45310649>
+
+        Reviewed by Tim Horton.
+
+        Fixes the bug by refactoring datalist suggestion information on iOS; currently, we override text suggestions on
+        _WKFormInputSession. This only works for a few internal clients (including Safari) that set a _WKInputDelegate
+        and also implement either -_webView:willStartInputSession: or -_webView:didStartInputSession:, which is
+        necessary in order to ensure that WebKit creates and maintains a form input session.
+
+        The two pieces of information that datalist code needs to vend to WKContentView are a list of UITextSuggestions
+        and a custom input view, which are both currently properties of _WKFormInputSession. This patch lifts these out
+        of the input session and makes them properties of WKContentView, which are used in
+        WebDataListSuggestionsDropdownIOS.
+
+        Test: fast/forms/datalist/datalist-textinput-suggestions-order.html
+
+        * UIProcess/ios/WKContentViewInteraction.h:
+        * UIProcess/ios/WKContentViewInteraction.mm:
+
+        Add new properties to WKContentView: an input view for datalist suggestions, and a list of text suggestions.
+
+        (-[WKFormInputSession setSuggestions:]):
+        (-[WKContentView setupInteraction]):
+        (-[WKContentView cleanupInteraction]):
+        (-[WKContentView _endEditing]):
+
+        Pull out common logic when resigning first responder or tabbing to the next or previous text field into a new
+        helper. This helper notifies `_inputPeripheral`, `_formInputSession`, and `_dataListTextSuggestionsInputView`
+        when editing has ended; the input peripheral and suggestions input view use this chance to send the value of the
+        form control to the web process.
+
+        (-[WKContentView resignFirstResponderForWebView]):
+        (-[WKContentView inputView]):
+
+        If a custom input view is not set but we have an input view for a datalist's text suggestions, use the datalist
+        input view.
+
+        (-[WKContentView accessoryTab:]):
+        (-[WKContentView _stopAssistingNode]):
+
+        Clear datalist state on WKContentView.
+
+        (-[WKContentView dataListTextSuggestionsInputView]):
+        (-[WKContentView dataListTextSuggestions]):
+        (-[WKContentView setDataListTextSuggestionsInputView:]):
+        (-[WKContentView setDataListTextSuggestions:]):
+        (-[WKContentView updateTextSuggestionsForInputDelegate]):
+
+        Pull out logic for setting suggestions on UIKit's `inputDelegate` (i.e. UIKeyboardImpl). We now first consult
+        internally-vended text suggestions from _WKFormInputSession; if an internal client has not overridden our text
+        suggestions, then we simply use suggestions from the current datalist (if present).
+
+        * UIProcess/ios/WebDataListSuggestionsDropdownIOS.mm:
+        (-[WKDataListSuggestionsPicker updateWithInformation:]):
+        (-[WKDataListSuggestionsPicker showSuggestionsDropdown:activationType:]):
+        (-[WKDataListSuggestionsPicker invalidate]):
+        (-[WKDataListSuggestionsPopover updateWithInformation:]):
+        (-[WKDataListSuggestionsPopover showSuggestionsDropdown:activationType:]):
+        (-[WKDataListSuggestionsPopover didSelectOptionAtIndex:]):
+
+        Change all the places that currently manipulate WKContentView's form input session to directly set text
+        suggestions and the text suggestion input view on the content view instead.
+
 2018-10-19  John Wilander  <wilan...@apple.com>
 
         Only cap lifetime of persistent cookies created client-side through document.cookie when resource load statistics is enabled

Modified: trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h (237304 => 237305)


--- trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h	2018-10-19 21:37:54 UTC (rev 237304)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h	2018-10-19 22:00:32 UTC (rev 237305)
@@ -159,6 +159,7 @@
 }
 
 @class WKFocusedElementInfo;
+@protocol WKFormControl;
 
 @interface WKFormInputSession : NSObject <_WKFormInputSession>
 
@@ -247,6 +248,11 @@
 
     RetainPtr<WKKeyboardScrollViewAnimator> _keyboardScrollingAnimator;
 
+#if ENABLE(DATALIST_ELEMENT)
+    RetainPtr<UIView <WKFormControl>> _dataListTextSuggestionsInputView;
+    RetainPtr<NSArray<UITextSuggestion *>> _dataListTextSuggestions;
+#endif
+
     BOOL _isEditable;
     BOOL _showingTextStyleOptions;
     BOOL _hasValidPositionInformation;
@@ -311,6 +317,11 @@
 @property (nonatomic, readonly) UIWebFormAccessory *formAccessoryView;
 @property (nonatomic) BOOL suppressAssistantSelectionView;
 
+#if ENABLE(DATALIST_ELEMENT)
+@property (nonatomic, strong) UIView <WKFormControl> *dataListTextSuggestionsInputView;
+@property (nonatomic, strong) NSArray<UITextSuggestion *> *dataListTextSuggestions;
+#endif
+
 - (void)setupInteraction;
 - (void)cleanupInteraction;
 
@@ -392,6 +403,10 @@
 
 - (void)reloadContextViewForPresentedListViewController;
 
+#if ENABLE(DATALIST_ELEMENT)
+- (void)updateTextSuggestionsForInputDelegate;
+#endif
+
 @end
 
 @interface WKContentView (WKTesting)

Modified: trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm (237304 => 237305)


--- trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm	2018-10-19 21:37:54 UTC (rev 237304)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm	2018-10-19 22:00:32 UTC (rev 237305)
@@ -395,15 +395,11 @@
 
 - (void)setSuggestions:(NSArray<UITextSuggestion *> *)suggestions
 {
-    // Suggestions that come from a <datalist> should not be overwritten by other clients.
-#if ENABLE(DATALIST_ELEMENT)
-    if ([_contentView assistedNodeInformation].hasSuggestions && ![suggestions.firstObject isKindOfClass:[WKDataListTextSuggestion class]])
+    if (suggestions == _suggestions || [suggestions isEqualToArray:_suggestions.get()])
         return;
-#endif
 
-    id <UITextInputSuggestionDelegate> suggestionDelegate = (id <UITextInputSuggestionDelegate>)[_contentView inputDelegate];
     _suggestions = adoptNS([suggestions copy]);
-    [suggestionDelegate setSuggestions:suggestions];
+    [_contentView updateTextSuggestionsForInputDelegate];
 }
 
 - (BOOL)requiresStrongPasswordAssistance
@@ -712,6 +708,11 @@
     _needsDeferredEndScrollingSelectionUpdate = NO;
     _isChangingFocus = NO;
     _isBlurringFocusedNode = NO;
+
+#if ENABLE(DATALIST_ELEMENT)
+    _dataListTextSuggestionsInputView = nil;
+    _dataListTextSuggestions = nil;
+#endif
 }
 
 - (void)cleanupInteraction
@@ -807,6 +808,11 @@
     
     [_keyboardScrollingAnimator invalidate];
     _keyboardScrollingAnimator = nil;
+
+#if ENABLE(DATALIST_ELEMENT)
+    _dataListTextSuggestionsInputView = nil;
+    _dataListTextSuggestions = nil;
+#endif
 }
 
 - (void)_removeDefaultGestureRecognizers
@@ -968,6 +974,15 @@
     return YES;
 }
 
+- (void)_endEditing
+{
+    [_inputPeripheral endEditing];
+    [_formInputSession endEditing];
+#if ENABLE(DATALIST_ELEMENT)
+    [_dataListTextSuggestionsInputView controlEndEditing];
+#endif
+}
+
 - (BOOL)canBecomeFirstResponder
 {
     return _becomingFirstResponder;
@@ -1017,9 +1032,7 @@
     _resigningFirstResponder = YES;
     if (!_webView._retainingActiveFocusedState) {
         // We need to complete the editing operation before we blur the element.
-        [_inputPeripheral endEditing];
-        [_formInputSession endEditing];
-
+        [self _endEditing];
         _page->blurAssistedNode();
     }
 
@@ -1362,7 +1375,15 @@
     } else
         [self _displayFormNodeInputView];
 
-    return [_formInputSession customInputView] ?: [_inputPeripheral assistantView];
+    if (UIView *customInputView = [_formInputSession customInputView])
+        return customInputView;
+
+#if ENABLE(DATALIST_ELEMENT)
+    if (_dataListTextSuggestionsInputView)
+        return _dataListTextSuggestionsInputView.get();
+#endif
+
+    return [_inputPeripheral assistantView];
 }
 
 - (CGRect)_selectionClipRect
@@ -3170,9 +3191,7 @@
 
 - (void)accessoryTab:(BOOL)isNext
 {
-    [_formInputSession endEditing];
-
-    [_inputPeripheral endEditing];
+    [self _endEditing];
     _inputPeripheral = nil;
 
     _didAccessoryTabInitiateFocus = YES; // Will be cleared in either -_displayFormNodeInputView or -cleanupInteraction.
@@ -4322,6 +4341,11 @@
     [_formInputSession invalidate];
     _formInputSession = nil;
 
+#if ENABLE(DATALIST_ELEMENT)
+    _dataListTextSuggestionsInputView = nil;
+    _dataListTextSuggestions = nil;
+#endif
+
     BOOL editableChanged = [self setIsEditable:NO];
 
     _assistedNodeInformation.elementType = InputType::None;
@@ -4740,6 +4764,62 @@
         [_textSelectionAssistant activateSelection];
 }
 
+#if ENABLE(DATALIST_ELEMENT)
+
+- (UIView <WKFormControl> *)dataListTextSuggestionsInputView
+{
+    return _dataListTextSuggestionsInputView.get();
+}
+
+- (NSArray<UITextSuggestion *> *)dataListTextSuggestions
+{
+    return _dataListTextSuggestions.get();
+}
+
+- (void)setDataListTextSuggestionsInputView:(UIView <WKFormControl> *)suggestionsInputView
+{
+    if (_dataListTextSuggestionsInputView == suggestionsInputView)
+        return;
+
+    _dataListTextSuggestionsInputView = suggestionsInputView;
+
+    if (![_formInputSession customInputView])
+        [self reloadInputViews];
+}
+
+- (void)setDataListTextSuggestions:(NSArray<UITextSuggestion *> *)textSuggestions
+{
+    if (textSuggestions == _dataListTextSuggestions || [textSuggestions isEqualToArray:_dataListTextSuggestions.get()])
+        return;
+
+    _dataListTextSuggestions = textSuggestions;
+
+    if (![_formInputSession suggestions].count)
+        [self updateTextSuggestionsForInputDelegate];
+}
+
+#endif
+
+- (void)updateTextSuggestionsForInputDelegate
+{
+    // Text suggestions vended from clients take precedence over text suggestions from a focused form control with a datalist.
+    id <UITextInputSuggestionDelegate> inputDelegate = (id <UITextInputSuggestionDelegate>)self.inputDelegate;
+    NSArray<UITextSuggestion *> *formInputSessionSuggestions = [_formInputSession suggestions];
+    if (formInputSessionSuggestions.count) {
+        [inputDelegate setSuggestions:formInputSessionSuggestions];
+        return;
+    }
+
+#if ENABLE(DATALIST_ELEMENT)
+    if ([_dataListTextSuggestions count]) {
+        [inputDelegate setSuggestions:_dataListTextSuggestions.get()];
+        return;
+    }
+#endif
+
+    [inputDelegate setSuggestions:nil];
+}
+
 - (void)_showPlaybackTargetPicker:(BOOL)hasVideo fromRect:(const IntRect&)elementRect routeSharingPolicy:(WebCore::RouteSharingPolicy)routeSharingPolicy routingContextUID:(NSString *)routingContextUID
 {
 #if ENABLE(AIRPLAY_PICKER)

Modified: trunk/Source/WebKit/UIProcess/ios/WebDataListSuggestionsDropdownIOS.mm (237304 => 237305)


--- trunk/Source/WebKit/UIProcess/ios/WebDataListSuggestionsDropdownIOS.mm	2018-10-19 21:37:54 UTC (rev 237304)
+++ trunk/Source/WebKit/UIProcess/ios/WebDataListSuggestionsDropdownIOS.mm	2018-10-19 22:00:32 UTC (rev 237305)
@@ -32,7 +32,6 @@
 #import "WKContentViewInteraction.h"
 #import "WKFormPeripheral.h"
 #import "WKFormPopover.h"
-#import "_WKFormInputSession.h"
 
 static const CGFloat maxVisibleSuggestions = 5;
 static const CGFloat suggestionsPopoverCellHeight = 44;
@@ -220,12 +219,12 @@
 {
     [super updateWithInformation:WTFMove(information)];
     if (information.activationType != WebCore::DataListSuggestionActivationType::IndicatorClicked) {
-        [[self.view _formInputSession] setCustomInputView:nil];
-        [[self.view _formInputSession] setSuggestions:[self textSuggestions]];
+        self.view.dataListTextSuggestionsInputView = nil;
+        self.view.dataListTextSuggestions = self.textSuggestions;
         return;
     }
 
-    [[self.view _formInputSession] setCustomInputView:_pickerView.get()];
+    self.view.dataListTextSuggestionsInputView = _pickerView.get();
 
     [_pickerView reloadAllComponents];
     [_pickerView selectRow:0 inComponent:0 animated:NO];
@@ -235,10 +234,10 @@
 {
     [super showSuggestionsDropdown:dropdown activationType:activationType];
     if (activationType == WebCore::DataListSuggestionActivationType::IndicatorClicked) {
-        [[self.view _formInputSession] setCustomInputView:_pickerView.get()];
+        self.view.dataListTextSuggestionsInputView = _pickerView.get();
         [_pickerView selectRow:0 inComponent:0 animated:NO];
     } else
-        [[self.view _formInputSession] setSuggestions:[self textSuggestions]];
+        self.view.dataListTextSuggestions = self.textSuggestions;
 }
 
 - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
@@ -258,8 +257,8 @@
 
 - (void)invalidate
 {
-    if ([[self.view _formInputSession] customInputView] == _pickerView.get())
-        [[self.view _formInputSession] setCustomInputView:nil];
+    if (self.view.dataListTextSuggestionsInputView == _pickerView.get())
+        self.view.dataListTextSuggestionsInputView = nil;
 
     [_pickerView setDelegate:nil];
     [_pickerView setDataSource:nil];
@@ -307,7 +306,7 @@
 {
     [super updateWithInformation:WTFMove(information)];
     [_suggestionsViewController reloadData];
-    [[self.view _formInputSession] setSuggestions:[self textSuggestions]];
+    self.view.dataListTextSuggestions = self.textSuggestions;
 }
 
 - (void)showSuggestionsDropdown:(WebKit::WebDataListSuggestionsDropdownIOS *)dropdown activationType:(WebCore::DataListSuggestionActivationType)activationType
@@ -317,7 +316,7 @@
     _suggestionsViewController = adoptNS([[WKDataListSuggestionsViewController alloc] initWithStyle:UITableViewStylePlain]);
     [_suggestionsViewController setControl:self];
     [_suggestionsViewController reloadData];
-    [[self.view _formInputSession] setSuggestions:[self textSuggestions]];
+    self.view.dataListTextSuggestions = self.textSuggestions;
 
 ALLOW_DEPRECATED_DECLARATIONS_BEGIN
     [_popover setPopoverController:[[[UIPopoverController alloc] initWithContentViewController:_suggestionsViewController.get()] autorelease]];
@@ -335,7 +334,7 @@
 {
     [super didSelectOptionAtIndex:index];
     [[_popover popoverController] dismissPopoverAnimated:YES];
-    [[self.view _formInputSession] setSuggestions:@[ [WKDataListTextSuggestion textSuggestionWithInputText:[self suggestionAtIndex:index]] ]];
+    self.view.dataListTextSuggestions = @[ [WKDataListTextSuggestion textSuggestionWithInputText:[self suggestionAtIndex:index]] ];
 }
 
 @end

Modified: trunk/Tools/ChangeLog (237304 => 237305)


--- trunk/Tools/ChangeLog	2018-10-19 21:37:54 UTC (rev 237304)
+++ trunk/Tools/ChangeLog	2018-10-19 22:00:32 UTC (rev 237305)
@@ -1,3 +1,34 @@
+2018-10-19  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        [iOS] [Datalist] Can't pick datalist suggestions in a stock WKWebView
+        https://bugs.webkit.org/show_bug.cgi?id=190621
+        <rdar://problem/45310649>
+
+        Reviewed by Tim Horton.
+
+        Add a UIScriptController hook to resign first responder on WKWebView. See LayoutTests/ChangeLog for more detail.
+
+        * DumpRenderTree/ios/UIScriptControllerIOS.mm:
+        (WTR::UIScriptController::resignFirstResponder):
+        * DumpRenderTree/mac/UIScriptControllerMac.mm:
+        (WTR::UIScriptController::resignFirstResponder):
+        * TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl:
+        * TestRunnerShared/UIScriptContext/UIScriptController.cpp:
+        (WTR::UIScriptController::resignFirstResponder):
+        * TestRunnerShared/UIScriptContext/UIScriptController.h:
+        * WebKitTestRunner/UIScriptControllerCocoa.mm:
+        (WTR::UIScriptController::resignFirstResponder):
+        * WebKitTestRunner/ios/PlatformWebViewIOS.mm:
+        (WTR::PlatformWebView::makeWebViewFirstResponder):
+
+        Implement this method stub on iOS, to ensure that TestController::resetStateToConsistentValues restores first
+        responder on the WKWebView when running iOS layout tests.
+
+        * WebKitTestRunner/ios/TestControllerIOS.mm:
+        (WTR::TestController::platformResetStateToConsistentValues):
+
+        After resigning first responder to dismiss any on-screen keyboard, ensure that we restore first responder.
+
 2018-10-19  Dean Jackson  <d...@apple.com>
 
         ASSERTION FAILED: !frame().animation().hasAnimations() in WebCore::FrameView::didDestroyRenderTree()

Modified: trunk/Tools/DumpRenderTree/ios/UIScriptControllerIOS.mm (237304 => 237305)


--- trunk/Tools/DumpRenderTree/ios/UIScriptControllerIOS.mm	2018-10-19 21:37:54 UTC (rev 237304)
+++ trunk/Tools/DumpRenderTree/ios/UIScriptControllerIOS.mm	2018-10-19 22:00:32 UTC (rev 237305)
@@ -82,6 +82,10 @@
     });
 }
 
+void UIScriptController::resignFirstResponder()
+{
+}
+
 void UIScriptController::setViewScale(double)
 {
 }

Modified: trunk/Tools/DumpRenderTree/mac/UIScriptControllerMac.mm (237304 => 237305)


--- trunk/Tools/DumpRenderTree/mac/UIScriptControllerMac.mm	2018-10-19 21:37:54 UTC (rev 237304)
+++ trunk/Tools/DumpRenderTree/mac/UIScriptControllerMac.mm	2018-10-19 22:00:32 UTC (rev 237305)
@@ -89,6 +89,10 @@
     });
 }
 
+void UIScriptController::resignFirstResponder()
+{
+}
+
 void UIScriptController::setViewScale(double)
 {
 }

Modified: trunk/Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl (237304 => 237305)


--- trunk/Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl	2018-10-19 21:37:54 UTC (rev 237304)
+++ trunk/Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl	2018-10-19 22:00:32 UTC (rev 237305)
@@ -219,6 +219,8 @@
 
     void setViewScale(double scale);
 
+    void resignFirstResponder();
+
     void scrollToOffset(long x, long y); // Initiate an animated scroll in the UI process.
     attribute object didEndScrollingCallback;
 

Modified: trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.cpp (237304 => 237305)


--- trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.cpp	2018-10-19 21:37:54 UTC (rev 237304)
+++ trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.cpp	2018-10-19 22:00:32 UTC (rev 237305)
@@ -214,6 +214,10 @@
 {
 }
 
+void UIScriptController::resignFirstResponder()
+{
+}
+
 void UIScriptController::simulateAccessibilitySettingsChangeNotification(JSValueRef)
 {
 }

Modified: trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.h (237304 => 237305)


--- trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.h	2018-10-19 21:37:54 UTC (rev 237304)
+++ trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.h	2018-10-19 22:00:32 UTC (rev 237305)
@@ -68,6 +68,8 @@
     void zoomToScale(double scale, JSValueRef callback);
     void setViewScale(double);
 
+    void resignFirstResponder();
+
     void simulateAccessibilitySettingsChangeNotification(JSValueRef callback);
 
     void touchDownAtPoint(long x, long y, long touchCount, JSValueRef callback);

Modified: trunk/Tools/WebKitTestRunner/UIScriptControllerCocoa.mm (237304 => 237305)


--- trunk/Tools/WebKitTestRunner/UIScriptControllerCocoa.mm	2018-10-19 21:37:54 UTC (rev 237304)
+++ trunk/Tools/WebKitTestRunner/UIScriptControllerCocoa.mm	2018-10-19 22:00:32 UTC (rev 237305)
@@ -42,4 +42,11 @@
 #endif
 }
 
+void UIScriptController::resignFirstResponder()
+{
+#if WK_API_ENABLED
+    [TestController::singleton().mainWebView()->platformView() resignFirstResponder];
+#endif
+}
+
 } // namespace WTR

Modified: trunk/Tools/WebKitTestRunner/ios/PlatformWebViewIOS.mm (237304 => 237305)


--- trunk/Tools/WebKitTestRunner/ios/PlatformWebViewIOS.mm	2018-10-19 21:37:54 UTC (rev 237304)
+++ trunk/Tools/WebKitTestRunner/ios/PlatformWebViewIOS.mm	2018-10-19 22:00:32 UTC (rev 237305)
@@ -286,8 +286,7 @@
 
 void PlatformWebView::makeWebViewFirstResponder()
 {
-    // FIXME: iOS equivalent?
-    // [m_window makeFirstResponder:m_view];
+    [m_view becomeFirstResponder];
 }
 
 void PlatformWebView::changeWindowScaleIfNeeded(float)

Modified: trunk/Tools/WebKitTestRunner/ios/TestControllerIOS.mm (237304 => 237305)


--- trunk/Tools/WebKitTestRunner/ios/TestControllerIOS.mm	2018-10-19 21:37:54 UTC (rev 237304)
+++ trunk/Tools/WebKitTestRunner/ios/TestControllerIOS.mm	2018-10-19 22:00:32 UTC (rev 237305)
@@ -107,6 +107,7 @@
 
     [[UIDevice currentDevice] setOrientation:UIDeviceOrientationPortrait animated:NO];
     
+    BOOL shouldRestoreFirstResponder = NO;
     if (PlatformWebView* platformWebView = mainWebView()) {
         TestRunnerWKWebView *webView = platformWebView->platformView();
         webView._stableStateOverride = nil;
@@ -121,10 +122,13 @@
         [scrollView setContentOffset:CGPointZero];
 
         if (webView.interactingWithFormControl)
-            [webView resignFirstResponder];
+            shouldRestoreFirstResponder = [webView resignFirstResponder];
     }
 
     runUntil(isDoneWaitingForKeyboardToDismiss, m_currentInvocation->shortTimeout());
+
+    if (shouldRestoreFirstResponder)
+        [mainWebView()->platformView() becomeFirstResponder];
 }
 
 void TestController::platformConfigureViewForTest(const TestInvocation& test)
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to