[webkit-changes] [WebKit/WebKit] beacee: [iOS] Scrolling after element focus does not avoid...

Wenson Hsieh noreply at github.com
Tue Dec 13 06:31:28 PST 2022


  Branch: refs/heads/main
  Home:   https://github.com/WebKit/WebKit
  Commit: beacee6a1c37d359baa414a90aa73da91247cbd6
      https://github.com/WebKit/WebKit/commit/beacee6a1c37d359baa414a90aa73da91247cbd6
  Author: Wenson Hsieh <wenson_hsieh at 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




More information about the webkit-changes mailing list