Branch: refs/heads/main Home: https://github.com/WebKit/WebKit Commit: beacee6a1c37d359baa414a90aa73da91247cbd6 https://github.com/WebKit/WebKit/commit/beacee6a1c37d359baa414a90aa73da91247cbd6 Author: Wenson Hsieh <wenson_hs...@apple.com> Date: 2022-12-13 (Tue, 13 Dec 2022)
Changed paths: A LayoutTests/fast/forms/ios/scroll-after-tapping-on-input-with-software-keyboard-expected.txt A LayoutTests/fast/forms/ios/scroll-after-tapping-on-input-with-software-keyboard.html M Source/WebKit/SourcesCocoa.txt A Source/WebKit/UIProcess/ios/RevealFocusedElementDeferrer.h A Source/WebKit/UIProcess/ios/RevealFocusedElementDeferrer.mm M Source/WebKit/UIProcess/ios/WKContentViewInteraction.h M Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm M Source/WebKit/WebKit.xcodeproj/project.pbxproj Log Message: ----------- [iOS] Scrolling after element focus does not avoid input views when OOP keyboard is enabled https://bugs.webkit.org/show_bug.cgi?id=249159 rdar://88057475 Reviewed by Aditya Keerthi. Scrolling to reveal the focused element is currently broken when OOP keyboard is enabled. This is because OOP keyboard causes `UIKeyboardWillShowNotification` to be delivered to the app asynchronously (after communicating with the input UI process), rather than dispatched immediately under the call to `-reloadInputViews`. WebKit currently depends on the latter, since we expect the keyboard's final geometry (after animation) to be set by the time the post-layout editor state arrives in the UI process and we reveal the focused element using `-_zoomToRevealFocusedElement`. However, since this geometry is sent through the "KeyboardWillShow" notification which (normally) arrives after the editor state, we end up proceeding with `-_zoomToRevealFocusedElement` without knowing the final keyboard geometry, so we end up only scrolling to keep the field centered within the web view (ignoring the obscuring bounds of the software keyboard). In some cases (e.g. when focusing an input field in some system views), this can cause focused input fields to be completely obscured by the keyboard. This is somewhat tricky to fix, since it's not guaranteed that the "KeyboardWillShow" notification will always arrive after the editor state or vice versa. To complicate things further, in the Mail compose case (i.e. when the web view's scroller has `-firstResponderKeyboardAvoidanceEnabled` set to `NO`), we'll actually zoom to reveal the focused element only after `UIKeyboardDidShowNotification` instead, since the keyboard geometry isn't available before the animation has finished (see https://commits.webkit.org/246159@main for more context). And of course, this fix also needs to continue working with OOP keyboard disabled, where the "KeyboardWillShow" notification is dispatched before we've even begun waiting for the next editor state. To handle all of the above scenarios, we add a helper class that encapsulates logic for deferring calls to `-_zoomToRevealFocusedElement` after an element is focused. This helper class, `WebKit::RevealFocusedElementDeferrer`, maintains a set of flags that enumerate the three distinct reasons why we could be deferring this call: "waiting for an editor state", "waiting for a `KeyboardWillShow` notification", and "waiting for a `KeyboardDidShow` notification". As `WKContentView` receives keyboard notification from UIKit or receives an editor state update from the web process, it removes the appropriate deferral reasons from this helper object. Finally, when there are no longer any deferral reasons, we call into `-_zoomToRevealFocusedElement` and clear out the helper. Test: fast/forms/ios/scroll-after-tapping-on-input-with-software-keyboard.html * LayoutTests/fast/forms/ios/scroll-after-tapping-on-input-with-software-keyboard-expected.txt: Added. * LayoutTests/fast/forms/ios/scroll-after-tapping-on-input-with-software-keyboard.html: Added. Add a new layout test to exercise this scenario. All existing layout tests are actually insufficient to cover the changes in this fix, since a test needs to: - Show the software keyboard (by default, layout tests run with the hardware keyboard connected). - Check that we scrolled the focused input into (roughly) the center of the visible viewport, not just onto the screen. * Source/WebKit/SourcesCocoa.txt: * Source/WebKit/UIProcess/ios/RevealFocusedElementDeferrer.h: Added. * Source/WebKit/UIProcess/ios/RevealFocusedElementDeferrer.mm: Added. (WebKit::RevealFocusedElementDeferrer::RevealFocusedElementDeferrer): (WebKit::RevealFocusedElementDeferrer::create): (WebKit::RevealFocusedElementDeferrer::fulfill): Add the new helper class. We protect the deferrer here since it expects its client (`WKContentView`) to clear any references to itself when `-_zoomToRevealFocusedElement` is invoked. * Source/WebKit/UIProcess/ios/WKContentViewInteraction.h: * Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm: (-[WKContentView cleanUpInteraction]): (-[WKContentView _keyboardWillShow]): (-[WKContentView _keyboardDidShow]): (-[WKContentView _zoomToRevealFocusedElement]): (-[WKContentView resetShouldZoomToFocusRectAfterShowingKeyboard]): (-[WKContentView _elementDidFocus:userIsInteracting:blurPreviousNode:activityStateChanges:userObject:]): Either call `-_zoomToRevealFocusedElement` immediately, or create a `RevealFocusedElementDeferrer`, passing in deferral reasons as appropriate. See comments above for more details. (-[WKContentView _elementDidBlur]): (-[WKContentView _didUpdateEditorState]): (-[WKContentView _zoomToFocusRectAfterShowingKeyboardIfNeeded]): Deleted. * Source/WebKit/WebKit.xcodeproj/project.pbxproj: Canonical link: https://commits.webkit.org/257785@main _______________________________________________ webkit-changes mailing list webkit-changes@lists.webkit.org https://lists.webkit.org/mailman/listinfo/webkit-changes