Changeset 278559 in webkit


Ignore:
Timestamp:
Jun 7, 2021, 6:26:39 AM (4 years ago)
Author:
Aditya Keerthi
Message:

[iOS] Unexpected scrolling when switching focus from a text input to a select element
https://bugs.webkit.org/show_bug.cgi?id=226657
<rdar://problem/78290515>

Reviewed by Tim Horton.

Source/WebKit:

When switching focus from a text input to a select element, UIKit makes
deferred calls to -[WKWebView inputView] after the keyboard dismissal.
This method calls -[WKContentView inputViewForWebView], which calls
-[WKContentView _zoomToRevealFocusedElement]. Consequently, these
methods can get invoked while the context menu (dropdown) is displayed
for a focused select element.

In this instance, the call should be idempotent, since the focused element
is fully visible in the viewport. However, since the context menu is visible
and overlaps the element, our logic incorrectly determines that the element
is obscured, leading to unexpected zooming/scrolling. To fix, we need to
correct the logic that determines the visible portion of the view.

Test: fast/forms/ios/form-control-refresh/select/focus-select-after-textfield.html

  • UIProcess/API/ios/WKWebViewIOS.mm:

(-[WKWebView _zoomToFocusRect:selectionRect:fontSize:minimumScale:maximumScale:allowScaling:forceScroll:]):

Always use the window to determine the portion of the webview that is
visible, rather than relying on the root view controller's top-most
full-screen view controller's view.

The old logic worked fine in most cases, since the root view controller
and the top-most full-screen view controller are almost always the same.
Furthermore, the root view controller's view usually takes up the entire
window.

However, when the context menu is on screen, the top-most full-screen
view controller is an internal UIKit view controller
(_UIContextMenuActionsOnlyViewController), and the associated view
is the context menu view. This exposed a flaw in the existing logic, as
visibility detection could be performed by intersecting with an
incorrect view. In general, the top-most full-screen view is not a
reliable way to determine the visible portion of the webview.

LayoutTests:

Add a layout test to exercise the bug.

  • fast/forms/ios/form-control-refresh/select/focus-select-after-textfield-expected.txt: Added.
  • fast/forms/ios/form-control-refresh/select/focus-select-after-textfield.html: Added.
Location:
trunk
Files:
2 added
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r278540 r278559  
     12021-06-07  Aditya Keerthi  <akeerthi@apple.com>
     2
     3        [iOS] Unexpected scrolling when switching focus from a text input to a select element
     4        https://bugs.webkit.org/show_bug.cgi?id=226657
     5        <rdar://problem/78290515>
     6
     7        Reviewed by Tim Horton.
     8
     9        Add a layout test to exercise the bug.
     10
     11        * fast/forms/ios/form-control-refresh/select/focus-select-after-textfield-expected.txt: Added.
     12        * fast/forms/ios/form-control-refresh/select/focus-select-after-textfield.html: Added.
     13
    1142021-06-06  Darin Adler  <darin@apple.com>
    215
  • trunk/Source/WebKit/ChangeLog

    r278548 r278559  
     12021-06-07  Aditya Keerthi  <akeerthi@apple.com>
     2
     3        [iOS] Unexpected scrolling when switching focus from a text input to a select element
     4        https://bugs.webkit.org/show_bug.cgi?id=226657
     5        <rdar://problem/78290515>
     6
     7        Reviewed by Tim Horton.
     8
     9        When switching focus from a text input to a select element, UIKit makes
     10        deferred calls to `-[WKWebView inputView]` after the keyboard dismissal.
     11        This method calls `-[WKContentView inputViewForWebView]`, which calls
     12        `-[WKContentView _zoomToRevealFocusedElement]`. Consequently, these
     13        methods can get invoked while the context menu (dropdown) is displayed
     14        for a focused select element.
     15
     16        In this instance, the call should be idempotent, since the focused element
     17        is fully visible in the viewport. However, since the context menu is visible
     18        and overlaps the element, our logic incorrectly determines that the element
     19        is obscured, leading to unexpected zooming/scrolling. To fix, we need to
     20        correct the logic that determines the visible portion of the view.
     21
     22        Test: fast/forms/ios/form-control-refresh/select/focus-select-after-textfield.html
     23
     24        * UIProcess/API/ios/WKWebViewIOS.mm:
     25        (-[WKWebView _zoomToFocusRect:selectionRect:fontSize:minimumScale:maximumScale:allowScaling:forceScroll:]):
     26
     27        Always use the window to determine the portion of the webview that is
     28        visible, rather than relying on the root view controller's top-most
     29        full-screen view controller's view.
     30
     31        The old logic worked fine in most cases, since the root view controller
     32        and the top-most full-screen view controller are almost always the same.
     33        Furthermore, the root view controller's view usually takes up the entire
     34        window.
     35
     36        However, when the context menu is on screen, the top-most full-screen
     37        view controller is an internal UIKit view controller
     38        (_UIContextMenuActionsOnlyViewController), and the associated view
     39        is the context menu view. This exposed a flaw in the existing logic, as
     40        visibility detection could be performed by intersecting with an
     41        incorrect view. In general, the top-most full-screen view is not a
     42        reliable way to determine the visible portion of the webview.
     43
    1442021-06-07  Carlos Garcia Campos  <cgarcia@igalia.com>
    245
  • trunk/Source/WebKit/UIProcess/API/ios/WKWebViewIOS.mm

    r278315 r278559  
    107107@end
    108108
    109 @interface UIViewController (UIViewControllerInternal)
    110 - (UIViewController *)_rootAncestorViewController;
    111 - (UIViewController *)_viewControllerForSupportedInterfaceOrientations;
    112 @end
    113 
    114109@implementation WKWebView (WKViewInternalIOS)
    115110
     
    12381233    UIWindow *window = [_scrollView window];
    12391234
    1240     // Find the portion of the view that is visible on the screen.
    1241     UIViewController *topViewController = [[[_scrollView _viewControllerForAncestor] _rootAncestorViewController] _viewControllerForSupportedInterfaceOrientations];
    1242     UIView *fullScreenView = topViewController.view;
    1243     if (!fullScreenView)
    1244         fullScreenView = window;
    1245 
    12461235    CGRect unobscuredScrollViewRectInWebViewCoordinates = UIEdgeInsetsInsetRect([self bounds], _obscuredInsets);
    1247     CGRect visibleScrollViewBoundsInWebViewCoordinates = CGRectIntersection(unobscuredScrollViewRectInWebViewCoordinates, [fullScreenView convertRect:[fullScreenView bounds] toView:self]);
     1236    CGRect visibleScrollViewBoundsInWebViewCoordinates = CGRectIntersection(unobscuredScrollViewRectInWebViewCoordinates, [window convertRect:window.bounds toView:self]);
    12481237    CGRect formAssistantFrameInWebViewCoordinates = [window convertRect:_inputViewBoundsInWindow toView:self];
    12491238    CGRect intersectionBetweenScrollViewAndFormAssistant = CGRectIntersection(visibleScrollViewBoundsInWebViewCoordinates, formAssistantFrameInWebViewCoordinates);
Note: See TracChangeset for help on using the changeset viewer.