Title: [279310] trunk/Source/WebKit
Revision
279310
Author
[email protected]
Date
2021-06-26 19:06:45 -0700 (Sat, 26 Jun 2021)

Log Message

[iOS] Safari sometimes hangs under sync IPC in `-[WKWebView _setSuppressSoftwareKeyboard:]`
https://bugs.webkit.org/show_bug.cgi?id=227424
rdar://79745385

Reviewed by Tim Horton.

When activating streamlined AutoFill, Safari calls UIKit SPI (`-_setSuppressSoftwareKeyboard:`) on WKWebView to
ensure that the normal software keyboard doesn't briefly appear instead of the AutoFill input view; after
requesting AutoFill credentials, Safari then stops suppressing the software keyboard by setting the SPI property
back to NO. In WebKit, we override `-[WKWebView _setSuppressSoftwareKeyboard:]`, such that WKContentView's
keyboard suppression state follows the web view's state (this is necessary, since WKContentView is the actual
`-firstResponder` when editing focused text inputs). However, when changing software keyboard suppression from
YES to NO, UIKit reloads input views and (in the process) calls into
`-requestAutocorrectionContextWithCompletionHandler:`, which then makes a sync IPC call into the web process.

To avoid this sync IPC call, we refactor the implementation of `-[WKWebView _setSuppressSoftwareKeyboard:]`,
such that we don't immediately attempt to unsuppress the software keyboard by calling into WKContentView.
Instead, we asynchronously request an autocorrection context from the web process, and then call
`-[WKContentView _setSuppressSoftwareKeyboard:NO]` after the autocorrection context request completes (using
the last known autocorrection context data in the UI process rather than making a sync IPC call).

* UIProcess/API/ios/WKWebViewIOS.mm:
(-[WKWebView _setSuppressSoftwareKeyboard:]):

Call into `-updateSoftwareKeyboardSuppressionStateFromWebView` below.

* UIProcess/ios/WKContentViewInteraction.h:
* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView cleanUpInteraction]):

Invoke `-unsuppressSoftwareKeyboardUsingLastAutocorrectionContextIfNeeded` to ensure that we stop software
keyboard suppression if the web process terminates while we're waiting for autocorrection context data to
arrive.

(-[WKContentView requestAutocorrectionContextWithCompletionHandler:]):
(-[WKContentView _handleAutocorrectionContext:]):
(-[WKContentView updateSoftwareKeyboardSuppressionStateFromWebView]):

Add a new helper that keeps WKContentView's software keyboard suppression state in sync with the WKWebView's
software keyboard suppression state. In the case where we're supressing the software keyboard, we can simply
call into `-[WKContentView _setSuppressSoftwareKeyboard:]` right away, since UIKit won't try to request an
autocorrection context.

However, in the case where we're unsuppressing the software keyboard, set a new flag, don't immediately forward
the call to WKContentView. Instead, set the `_unsuppressSoftwareKeyboardAfterNextAutocorrectionContextUpdate`
flag to YES and call into WebPageProxy to request an updated autocorrection context. Upon receiving the response
in `-[WKContentView _handleAutocorrectionContext:]`, we then unset the flag and unsuppress the software keyboard
(crucially, using `_lastAutocorrectionContext` instead of making a synchronous call back to the web content
process).

(-[WKContentView unsuppressSoftwareKeyboardUsingLastAutocorrectionContextIfNeeded]):

Modified Paths

Diff

Modified: trunk/Source/WebKit/ChangeLog (279309 => 279310)


--- trunk/Source/WebKit/ChangeLog	2021-06-27 01:07:51 UTC (rev 279309)
+++ trunk/Source/WebKit/ChangeLog	2021-06-27 02:06:45 UTC (rev 279310)
@@ -1,3 +1,57 @@
+2021-06-26  Wenson Hsieh  <[email protected]>
+
+        [iOS] Safari sometimes hangs under sync IPC in `-[WKWebView _setSuppressSoftwareKeyboard:]`
+        https://bugs.webkit.org/show_bug.cgi?id=227424
+        rdar://79745385
+
+        Reviewed by Tim Horton.
+
+        When activating streamlined AutoFill, Safari calls UIKit SPI (`-_setSuppressSoftwareKeyboard:`) on WKWebView to
+        ensure that the normal software keyboard doesn't briefly appear instead of the AutoFill input view; after
+        requesting AutoFill credentials, Safari then stops suppressing the software keyboard by setting the SPI property
+        back to NO. In WebKit, we override `-[WKWebView _setSuppressSoftwareKeyboard:]`, such that WKContentView's
+        keyboard suppression state follows the web view's state (this is necessary, since WKContentView is the actual
+        `-firstResponder` when editing focused text inputs). However, when changing software keyboard suppression from
+        YES to NO, UIKit reloads input views and (in the process) calls into
+        `-requestAutocorrectionContextWithCompletionHandler:`, which then makes a sync IPC call into the web process.
+
+        To avoid this sync IPC call, we refactor the implementation of `-[WKWebView _setSuppressSoftwareKeyboard:]`,
+        such that we don't immediately attempt to unsuppress the software keyboard by calling into WKContentView.
+        Instead, we asynchronously request an autocorrection context from the web process, and then call
+        `-[WKContentView _setSuppressSoftwareKeyboard:NO]` after the autocorrection context request completes (using
+        the last known autocorrection context data in the UI process rather than making a sync IPC call).
+
+        * UIProcess/API/ios/WKWebViewIOS.mm:
+        (-[WKWebView _setSuppressSoftwareKeyboard:]):
+
+        Call into `-updateSoftwareKeyboardSuppressionStateFromWebView` below.
+
+        * UIProcess/ios/WKContentViewInteraction.h:
+        * UIProcess/ios/WKContentViewInteraction.mm:
+        (-[WKContentView cleanUpInteraction]):
+
+        Invoke `-unsuppressSoftwareKeyboardUsingLastAutocorrectionContextIfNeeded` to ensure that we stop software
+        keyboard suppression if the web process terminates while we're waiting for autocorrection context data to
+        arrive.
+
+        (-[WKContentView requestAutocorrectionContextWithCompletionHandler:]):
+        (-[WKContentView _handleAutocorrectionContext:]):
+        (-[WKContentView updateSoftwareKeyboardSuppressionStateFromWebView]):
+
+        Add a new helper that keeps WKContentView's software keyboard suppression state in sync with the WKWebView's
+        software keyboard suppression state. In the case where we're supressing the software keyboard, we can simply
+        call into `-[WKContentView _setSuppressSoftwareKeyboard:]` right away, since UIKit won't try to request an
+        autocorrection context.
+
+        However, in the case where we're unsuppressing the software keyboard, set a new flag, don't immediately forward
+        the call to WKContentView. Instead, set the `_unsuppressSoftwareKeyboardAfterNextAutocorrectionContextUpdate`
+        flag to YES and call into WebPageProxy to request an updated autocorrection context. Upon receiving the response
+        in `-[WKContentView _handleAutocorrectionContext:]`, we then unset the flag and unsuppress the software keyboard
+        (crucially, using `_lastAutocorrectionContext` instead of making a synchronous call back to the web content
+        process).
+
+        (-[WKContentView unsuppressSoftwareKeyboardUsingLastAutocorrectionContextIfNeeded]):
+
 2021-06-25  Brent Fulgham  <[email protected]>
 
         [macOS] Add logging and clean up AppSSO flows 

Modified: trunk/Source/WebKit/UIProcess/API/ios/WKWebViewIOS.mm (279309 => 279310)


--- trunk/Source/WebKit/UIProcess/API/ios/WKWebViewIOS.mm	2021-06-27 01:07:51 UTC (rev 279309)
+++ trunk/Source/WebKit/UIProcess/API/ios/WKWebViewIOS.mm	2021-06-27 02:06:45 UTC (rev 279310)
@@ -3083,8 +3083,8 @@
 
 - (void)_setSuppressSoftwareKeyboard:(BOOL)suppressSoftwareKeyboard
 {
-    [super _setSuppressSoftwareKeyboard:suppressSoftwareKeyboard];
-    [_contentView _setSuppressSoftwareKeyboard:suppressSoftwareKeyboard];
+    super._suppressSoftwareKeyboard = suppressSoftwareKeyboard;
+    [_contentView updateSoftwareKeyboardSuppressionStateFromWebView];
 }
 
 - (void)_snapshotRect:(CGRect)rectInViewCoordinates intoImageOfWidth:(CGFloat)imageWidth completionHandler:(void(^)(CGImageRef))completionHandler

Modified: trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h (279309 => 279310)


--- trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h	2021-06-27 01:07:51 UTC (rev 279309)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h	2021-06-27 02:06:45 UTC (rev 279310)
@@ -441,6 +441,8 @@
     BOOL _isFocusingElementWithKeyboard;
     BOOL _isBlurringFocusedElement;
     BOOL _isRelinquishingFirstResponderToFocusedElement;
+    BOOL _unsuppressSoftwareKeyboardAfterNextAutocorrectionContextUpdate;
+    BOOL _isUnsuppressingSoftwareKeyboardUsingLastAutocorrectionContext;
 
     BOOL _focusRequiresStrongPasswordAssistance;
     BOOL _waitingForEditDragSnapshot;
@@ -709,6 +711,8 @@
 - (void)_didChangeLinkPreviewAvailability;
 - (void)setContinuousSpellCheckingEnabled:(BOOL)enabled;
 
+- (void)updateSoftwareKeyboardSuppressionStateFromWebView;
+
 #if USE(UICONTEXTMENU)
 - (UIView *)textEffectsWindow;
 

Modified: trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm (279309 => 279310)


--- trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm	2021-06-27 01:07:51 UTC (rev 279309)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm	2021-06-27 02:06:45 UTC (rev 279310)
@@ -1180,6 +1180,7 @@
     [self _removeContainerForContextMenuHintPreviews];
     [self _removeContainerForDragPreviews];
     [self _removeContainerForDropPreviews];
+    [self unsuppressSoftwareKeyboardUsingLastAutocorrectionContextIfNeeded];
 
     _hasSetUpInteractions = NO;
     _suppressSelectionAssistantReasons = { };
@@ -4623,7 +4624,20 @@
         return;
     }
 
-    if (_page->isRunningModalJavaScriptDialog() || _domPasteRequestHandler) {
+    bool respondWithLastKnownAutocorrectionContext = ([&] {
+        if (_page->isRunningModalJavaScriptDialog())
+            return true;
+
+        if (_domPasteRequestHandler)
+            return true;
+
+        if (_isUnsuppressingSoftwareKeyboardUsingLastAutocorrectionContext)
+            return true;
+
+        return false;
+    })();
+
+    if (respondWithLastKnownAutocorrectionContext) {
         completionHandler([WKAutocorrectionContext autocorrectionContextWithWebContext:_lastAutocorrectionContext]);
         return;
     }
@@ -4649,8 +4663,34 @@
 {
     _lastAutocorrectionContext = context;
     [self _invokePendingAutocorrectionContextHandler:[WKAutocorrectionContext autocorrectionContextWithWebContext:context]];
+    [self unsuppressSoftwareKeyboardUsingLastAutocorrectionContextIfNeeded];
 }
 
+- (void)updateSoftwareKeyboardSuppressionStateFromWebView
+{
+    BOOL webViewIsSuppressingSoftwareKeyboard = [_webView _suppressSoftwareKeyboard];
+    if (webViewIsSuppressingSoftwareKeyboard) {
+        _unsuppressSoftwareKeyboardAfterNextAutocorrectionContextUpdate = NO;
+        self._suppressSoftwareKeyboard = webViewIsSuppressingSoftwareKeyboard;
+        return;
+    }
+
+    if (self._suppressSoftwareKeyboard == webViewIsSuppressingSoftwareKeyboard)
+        return;
+
+    if (!std::exchange(_unsuppressSoftwareKeyboardAfterNextAutocorrectionContextUpdate, YES))
+        _page->requestAutocorrectionContext();
+}
+
+- (void)unsuppressSoftwareKeyboardUsingLastAutocorrectionContextIfNeeded
+{
+    if (!std::exchange(_unsuppressSoftwareKeyboardAfterNextAutocorrectionContextUpdate, NO))
+        return;
+
+    SetForScope<BOOL> unsuppressSoftwareKeyboardScope { _isUnsuppressingSoftwareKeyboardUsingLastAutocorrectionContext, YES };
+    self._suppressSoftwareKeyboard = NO;
+}
+
 - (void)runModalJavaScriptDialog:(CompletionHandler<void()>&&)callback
 {
     if (_isFocusingElementWithKeyboard)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to