Changeset 204728 in webkit


Ignore:
Timestamp:
Aug 22, 2016, 11:02:03 AM (9 years ago)
Author:
Simon Fraser
Message:

<select> menu on iPad causes shifting of hit-testing areas
https://bugs.webkit.org/show_bug.cgi?id=150079

Reviewed by Tim Horton.

Source/WebKit2:

-isAssistingNode (aka the poorly named isEditable) is input into WebPageProxy::computeCustomFixedPositionRect(),
so when it changes we have to update visible rects. We were doing this on focus, but failing
to do it on blur.

Added the ability to test by:

  1. Making it possible to initiate an animated scroll in the UI process
  2. Adding callbacks for starting and ending interaction with a form control. Sadly

the "ending interaction" for <select> popovers on iPad isn't late enough, since we
have no way currently to know when the dimming view behind the popover animates out,
so for now the test keeps trying to tap a button.

Test: fast/forms/ios/ipad/unfocus-inside-fixed-hittest.html

  • UIProcess/API/Cocoa/WKWebView.mm:

(-[WKWebView _zoomToPoint:atScale:animated:]):
(-[WKWebView _scrollToRect:origin:minimumScrollDistance:]):
(-[WKWebView _scrollByContentOffset:]):
(-[WKWebView _zoomToFocusRect:selectionRect:fontSize:minimumScale:maximumScale:allowScaling:forceScroll:]):
(-[WKWebView didStartFormControlInteraction]):
(-[WKWebView didEndFormControlInteraction]):

  • UIProcess/API/Cocoa/WKWebViewPrivate.h:
  • UIProcess/ios/WKContentView.mm:

(-[WKContentView didUpdateVisibleRect:unobscuredRect:unobscuredRectInScrollViewCoordinates:obscuredInset:scale:minimumScale:inStableState:isChangingObscuredInsetsInteractively:enclosedInScrollableAncestorView:]):

  • UIProcess/ios/WKContentViewInteraction.mm:

(-[WKContentView setIsEditable:]):
(-[WKContentView _startAssistingNode:userIsInteracting:blurPreviousNode:userObject:]):
(-[WKContentView _stopAssistingNode]):

Tools:

-isAssistingNode (aka the poorly named isEditable) is input into WebPageProxy::computeCustomFixedPositionRect(),
so when it changes we have to update visible rects. We were doing this on focus, but failing
to do it on blur.

Added the ability to test by:

  1. Making it possible to initiate an animated scroll in the UI process
  2. Adding callbacks for starting and ending interaction with a form control. Sadly

the "ending interaction" for <select> popovers on iPad isn't late enough, since we
have no way currently to know when the dimming view behind the popover animates out,
so for now the test keeps trying to tap a button.

  • WebKitTestRunner/UIScriptContext/Bindings/UIScriptController.idl:
  • WebKitTestRunner/UIScriptContext/UIScriptContext.h:
  • WebKitTestRunner/UIScriptContext/UIScriptController.cpp:

(WTR::UIScriptController::setDidStartFormControlInteractionCallback):
(WTR::UIScriptController::didStartFormControlInteractionCallback):
(WTR::UIScriptController::setDidEndFormControlInteractionCallback):
(WTR::UIScriptController::didEndFormControlInteractionCallback):
(WTR::UIScriptController::scrollToOffset):
(WTR::UIScriptController::platformSetDidStartFormControlInteractionCallback):
(WTR::UIScriptController::platformSetDidEndFormControlInteractionCallback):

  • WebKitTestRunner/UIScriptContext/UIScriptController.h:
  • WebKitTestRunner/cocoa/TestRunnerWKWebView.h:
  • WebKitTestRunner/cocoa/TestRunnerWKWebView.mm:

(-[TestRunnerWKWebView dealloc]):
(-[TestRunnerWKWebView didStartFormControlInteraction]):
(-[TestRunnerWKWebView didEndFormControlInteraction]):

  • WebKitTestRunner/ios/UIScriptControllerIOS.mm:

(WTR::contentOffsetBoundedInValidRange):
(WTR::UIScriptController::scrollToOffset):
(WTR::UIScriptController::platformSetDidStartFormControlInteractionCallback):
(WTR::UIScriptController::platformSetDidEndFormControlInteractionCallback):

LayoutTests:

This test:

  1. Scrolls in the ui process, so that position:fixed kicks in
  2. Taps on a <select>, which disabled position:fixed behavior
  3. Chooses a <select> option, dismissing the <select>, which restores position:fixed behavior
  4. Tries to tap a button inside position:fixed.
  • fast/forms/ios/ipad/unfocus-inside-fixed-hittest-expected.txt: Added.
  • fast/forms/ios/ipad/unfocus-inside-fixed-hittest.html: Added.
Location:
trunk
Files:
2 added
14 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r204724 r204728  
     12016-08-22  Simon Fraser  <simon.fraser@apple.com>
     2
     3        <select> menu on iPad causes shifting of hit-testing areas
     4        https://bugs.webkit.org/show_bug.cgi?id=150079
     5
     6        Reviewed by Tim Horton.
     7
     8        This test:
     9        1. Scrolls in the ui process, so that position:fixed kicks in
     10        2. Taps on a <select>, which disabled position:fixed behavior
     11        3. Chooses a <select> option, dismissing the <select>, which restores position:fixed behavior
     12        4. Tries to tap a button inside position:fixed.
     13
     14        * fast/forms/ios/ipad/unfocus-inside-fixed-hittest-expected.txt: Added.
     15        * fast/forms/ios/ipad/unfocus-inside-fixed-hittest.html: Added.
     16
    1172016-08-22  Antti Koivisto  <antti@apple.com>
    218
  • trunk/Source/WebKit2/ChangeLog

    r204720 r204728  
     12016-08-22  Simon Fraser  <simon.fraser@apple.com>
     2
     3        <select> menu on iPad causes shifting of hit-testing areas
     4        https://bugs.webkit.org/show_bug.cgi?id=150079
     5
     6        Reviewed by Tim Horton.
     7
     8        -isAssistingNode (aka the poorly named isEditable) is input into WebPageProxy::computeCustomFixedPositionRect(),
     9        so when it changes we have to update visible rects. We were doing this on focus, but failing
     10        to do it on blur.
     11
     12        Added the ability to test by:
     13        1. Making it possible to initiate an animated scroll in the UI process
     14        2. Adding callbacks for starting and ending interaction with a form control. Sadly
     15        the "ending interaction" for <select> popovers on iPad isn't late enough, since we
     16        have no way currently to know when the dimming view behind the popover animates out,
     17        so for now the test keeps trying to tap a button.
     18
     19        Test: fast/forms/ios/ipad/unfocus-inside-fixed-hittest.html
     20
     21        * UIProcess/API/Cocoa/WKWebView.mm:
     22        (-[WKWebView _zoomToPoint:atScale:animated:]):
     23        (-[WKWebView _scrollToRect:origin:minimumScrollDistance:]):
     24        (-[WKWebView _scrollByContentOffset:]):
     25        (-[WKWebView _zoomToFocusRect:selectionRect:fontSize:minimumScale:maximumScale:allowScaling:forceScroll:]):
     26        (-[WKWebView didStartFormControlInteraction]):
     27        (-[WKWebView didEndFormControlInteraction]):
     28        * UIProcess/API/Cocoa/WKWebViewPrivate.h:
     29        * UIProcess/ios/WKContentView.mm:
     30        (-[WKContentView didUpdateVisibleRect:unobscuredRect:unobscuredRectInScrollViewCoordinates:obscuredInset:scale:minimumScale:inStableState:isChangingObscuredInsetsInteractively:enclosedInScrollableAncestorView:]):
     31        * UIProcess/ios/WKContentViewInteraction.mm:
     32        (-[WKContentView setIsEditable:]):
     33        (-[WKContentView _startAssistingNode:userIsInteracting:blurPreviousNode:userObject:]):
     34        (-[WKContentView _stopAssistingNode]):
     35
    1362016-08-22  Daniel Bates  <dabates@apple.com>
    237
  • trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm

    r204525 r204728  
    14341434        _page->willStartUserTriggeredZooming();
    14351435
     1436    LOG_WITH_STREAM(VisibleRects, stream << "_zoomToPoint:" << point << " scale: " << scale << " duration:" << duration);
     1437
    14361438    [_scrollView _zoomToCenter:point scale:scale duration:duration];
    14371439}
     
    15341536    [_contentView willStartZoomOrScroll];
    15351537
     1538    LOG_WITH_STREAM(VisibleRects, stream << "_scrollToRect: scrolling to " << [_scrollView contentOffset] + scrollViewOffsetDelta);
     1539
    15361540    [_scrollView setContentOffset:([_scrollView contentOffset] + scrollViewOffsetDelta) animated:YES];
    15371541    return true;
     
    15501554        return;
    15511555    [_contentView willStartZoomOrScroll];
     1556
     1557    LOG_WITH_STREAM(VisibleRects, stream << "_scrollByContentOffset: scrolling to " << boundedOffset);
     1558
    15521559    [_scrollView setContentOffset:boundedOffset animated:YES];
    15531560}
     
    16741681    if (scale != contentZoomScale(self))
    16751682        _page->willStartUserTriggeredZooming();
     1683
     1684    LOG_WITH_STREAM(VisibleRects, stream << "_zoomToFocusRect: zooming to " << newCenter << " scale:" << scale);
    16761685
    16771686    // The newCenter has been computed in the new scale, but _zoomToCenter expected the center to be in the original scale.
     
    45284537}
    45294538
     4539- (void)didStartFormControlInteraction
     4540{
     4541    // For subclasses to override.
     4542}
     4543
     4544- (void)didEndFormControlInteraction
     4545{
     4546    // For subclasses to override.
     4547}
     4548
    45304549#endif // PLATFORM(IOS)
    45314550
  • trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebViewPrivate.h

    r204525 r204728  
    265265- (void)selectFormAccessoryPickerRow:(int)rowIndex WK_API_AVAILABLE(ios(WK_IOS_TBA));
    266266
     267- (void)didStartFormControlInteraction WK_API_AVAILABLE(ios(WK_IOS_TBA));
     268- (void)didEndFormControlInteraction WK_API_AVAILABLE(ios(WK_IOS_TBA));
     269
    267270#endif
    268271
  • trunk/Source/WebKit2/UIProcess/ios/WKContentView.mm

    r203371 r204728  
    3232#import "AccessibilityIOS.h"
    3333#import "ApplicationStateTracker.h"
     34#import "Logging.h"
    3435#import "PageClientImplIOS.h"
    3536#import "PrintInfo.h"
     
    5960#import <WebCore/PlatformScreen.h>
    6061#import <WebCore/QuartzCoreSPI.h>
     62#import <WebCore/TextStream.h>
    6163#import <wtf/CurrentTime.h>
    6264#import <wtf/RetainPtr.h>
     
    377379
    378380    FloatRect fixedPositionRectForLayout = _page->computeCustomFixedPositionRect(unobscuredRect, zoomScale, WebPageProxy::UnobscuredRectConstraint::ConstrainedToDocumentRect);
     381
     382    LOG_WITH_STREAM(VisibleRects, stream << "didUpdateVisibleRect: visibleRect:" << visibleRect << " unobscuredRect:" << unobscuredRect << " fixedPositionRectForLayout:" << fixedPositionRectForLayout);
    379383
    380384    VisibleContentRectUpdateInfo visibleContentRectUpdateInfo(
  • trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.mm

    r204525 r204728  
    747747{
    748748    return _isEditable;
     749}
     750
     751- (BOOL)setIsEditable:(BOOL)isEditable
     752{
     753    if (isEditable == _isEditable)
     754        return NO;
     755
     756    _isEditable = isEditable;
     757    return YES;
    749758}
    750759
     
    35803589        return;
    35813590
    3582     _isEditable = YES;
     3591    BOOL editableChanged = [self setIsEditable:YES];
    35833592    _assistedNodeInformation = information;
    35843593    _inputPeripheral = nil;
     
    36013610    }
    36023611   
    3603     if (information.insideFixedPosition)
     3612    // The custom fixed position rect behavior is affected by -isAssistingNode, so if that changes we need to recompute rects.
     3613    if (editableChanged)
    36043614        [_webView _updateVisibleContentRects];
    36053615   
     
    36133623        [inputDelegate _webView:_webView didStartInputSession:_formInputSession.get()];
    36143624    }
     3625   
     3626    [_webView didStartFormControlInteraction];
    36153627}
    36163628
     
    36193631    [_formInputSession invalidate];
    36203632    _formInputSession = nil;
    3621     _isEditable = NO;
     3633
     3634    BOOL editableChanged = [self setIsEditable:NO];
     3635
    36223636    _assistedNodeInformation.elementType = InputType::None;
    36233637    _inputPeripheral = nil;
     
    36293643    // The name is misleading, but this actually clears the selection views and removes any selection.
    36303644    [_webSelectionAssistant resignedFirstResponder];
     3645
     3646    // The custom fixed position rect behavior is affected by -isAssistingNode, so if that changes we need to recompute rects.
     3647    if (editableChanged)
     3648        [_webView _updateVisibleContentRects];
     3649
     3650    [_webView didEndFormControlInteraction];
    36313651}
    36323652
  • trunk/Tools/ChangeLog

    r204727 r204728  
     12016-08-22  Simon Fraser  <simon.fraser@apple.com>
     2
     3        <select> menu on iPad causes shifting of hit-testing areas
     4        https://bugs.webkit.org/show_bug.cgi?id=150079
     5
     6        Reviewed by Tim Horton.
     7
     8        -isAssistingNode (aka the poorly named isEditable) is input into WebPageProxy::computeCustomFixedPositionRect(),
     9        so when it changes we have to update visible rects. We were doing this on focus, but failing
     10        to do it on blur.
     11
     12        Added the ability to test by:
     13        1. Making it possible to initiate an animated scroll in the UI process
     14        2. Adding callbacks for starting and ending interaction with a form control. Sadly
     15        the "ending interaction" for <select> popovers on iPad isn't late enough, since we
     16        have no way currently to know when the dimming view behind the popover animates out,
     17        so for now the test keeps trying to tap a button.
     18
     19        * WebKitTestRunner/UIScriptContext/Bindings/UIScriptController.idl:
     20        * WebKitTestRunner/UIScriptContext/UIScriptContext.h:
     21        * WebKitTestRunner/UIScriptContext/UIScriptController.cpp:
     22        (WTR::UIScriptController::setDidStartFormControlInteractionCallback):
     23        (WTR::UIScriptController::didStartFormControlInteractionCallback):
     24        (WTR::UIScriptController::setDidEndFormControlInteractionCallback):
     25        (WTR::UIScriptController::didEndFormControlInteractionCallback):
     26        (WTR::UIScriptController::scrollToOffset):
     27        (WTR::UIScriptController::platformSetDidStartFormControlInteractionCallback):
     28        (WTR::UIScriptController::platformSetDidEndFormControlInteractionCallback):
     29        * WebKitTestRunner/UIScriptContext/UIScriptController.h:
     30        * WebKitTestRunner/cocoa/TestRunnerWKWebView.h:
     31        * WebKitTestRunner/cocoa/TestRunnerWKWebView.mm:
     32        (-[TestRunnerWKWebView dealloc]):
     33        (-[TestRunnerWKWebView didStartFormControlInteraction]):
     34        (-[TestRunnerWKWebView didEndFormControlInteraction]):
     35        * WebKitTestRunner/ios/UIScriptControllerIOS.mm:
     36        (WTR::contentOffsetBoundedInValidRange):
     37        (WTR::UIScriptController::scrollToOffset):
     38        (WTR::UIScriptController::platformSetDidStartFormControlInteractionCallback):
     39        (WTR::UIScriptController::platformSetDidEndFormControlInteractionCallback):
     40
    1412016-08-22  Carlos Alberto Lopez Perez  <clopez@igalia.com>
    242
  • trunk/Tools/WebKitTestRunner/UIScriptContext/Bindings/UIScriptController.idl

    r204525 r204728  
    4646    void dismissFormAccessoryView();
    4747
     48    // Form control handling
     49    attribute object didStartFormControlInteractionCallback;
     50    attribute object didEndFormControlInteractionCallback;
     51
    4852    // <select> picker
    4953    void selectFormAccessoryPickerRow(long rowIndex);
     
    5963    attribute object didEndZoomingCallback;
    6064
     65    void scrollToOffset(long x, long y); // Initiate an animated scroll in the UI process.
    6166    attribute object didEndScrollingCallback;
    6267
  • trunk/Tools/WebKitTestRunner/UIScriptContext/UIScriptContext.h

    r194721 r204728  
    4848    CallbackTypeDidHideKeyboard,
    4949    CallbackTypeDidEndScrolling,
     50    CallbackTypeDidStartFormControlInteraction,
     51    CallbackTypeDidEndFormControlInteraction,
    5052    CallbackTypeNonPersistent = firstNonPersistentCallbackID
    5153} CallbackType;
  • trunk/Tools/WebKitTestRunner/UIScriptContext/UIScriptController.cpp

    r204525 r204728  
    5959#endif
    6060
     61void UIScriptController::setDidStartFormControlInteractionCallback(JSValueRef callback)
     62{
     63    m_context->registerCallback(callback, CallbackTypeDidStartFormControlInteraction);
     64    platformSetDidStartFormControlInteractionCallback();
     65}
     66
     67JSValueRef UIScriptController::didStartFormControlInteractionCallback() const
     68{
     69    return m_context->callbackWithID(CallbackTypeDidStartFormControlInteraction);
     70}
     71
     72void UIScriptController::setDidEndFormControlInteractionCallback(JSValueRef callback)
     73{
     74    m_context->registerCallback(callback, CallbackTypeDidEndFormControlInteraction);
     75    platformSetDidEndFormControlInteractionCallback();
     76}
     77
     78JSValueRef UIScriptController::didEndFormControlInteractionCallback() const
     79{
     80    return m_context->callbackWithID(CallbackTypeDidEndFormControlInteraction);
     81}
     82
    6183void UIScriptController::setWillBeginZoomingCallback(JSValueRef callback)
    6284{
     
    159181}
    160182
     183void UIScriptController::scrollToOffset(long x, long y)
     184{
     185}
     186
    161187void UIScriptController::keyboardAccessoryBarNext()
    162188{
     
    185211{
    186212    return nullptr;
     213}
     214
     215void UIScriptController::platformSetDidStartFormControlInteractionCallback()
     216{
     217}
     218
     219void UIScriptController::platformSetDidEndFormControlInteractionCallback()
     220{
    187221}
    188222
  • trunk/Tools/WebKitTestRunner/UIScriptContext/UIScriptController.h

    r204525 r204728  
    6363    void dismissFormAccessoryView();
    6464    void selectFormAccessoryPickerRow(long);
     65   
     66    void scrollToOffset(long x, long y);
     67
     68    void setDidStartFormControlInteractionCallback(JSValueRef);
     69    JSValueRef didStartFormControlInteractionCallback() const;
     70
     71    void setDidEndFormControlInteractionCallback(JSValueRef);
     72    JSValueRef didEndFormControlInteractionCallback() const;
    6573
    6674    void setWillBeginZoomingCallback(JSValueRef);
     
    8997private:
    9098    UIScriptController(UIScriptContext&);
    91    
     99
     100    void platformSetDidStartFormControlInteractionCallback();
     101    void platformSetDidEndFormControlInteractionCallback();
    92102    void platformSetWillBeginZoomingCallback();
    93103    void platformSetDidEndZoomingCallback();
  • trunk/Tools/WebKitTestRunner/cocoa/TestRunnerWKWebView.h

    r192432 r204728  
    3232#if PLATFORM(IOS)
    3333
     34@property (nonatomic, copy) void (^didStartFormControlInteractionCallback)(void);
     35@property (nonatomic, copy) void (^didEndFormControlInteractionCallback)(void);
    3436@property (nonatomic, copy) void (^willBeginZoomingCallback)(void);
    3537@property (nonatomic, copy) void (^didEndZoomingCallback)(void);
  • trunk/Tools/WebKitTestRunner/cocoa/TestRunnerWKWebView.mm

    r192432 r204728  
    7474    [[NSNotificationCenter defaultCenter] removeObserver:self];
    7575
     76    self.didStartFormControlInteractionCallback = nil;
     77    self.didEndFormControlInteractionCallback = nil;
    7678    self.willBeginZoomingCallback = nil;
    7779    self.didEndZoomingCallback = nil;
     
    8486
    8587    [super dealloc];
     88}
     89
     90- (void)didStartFormControlInteraction
     91{
     92    if (self.didStartFormControlInteractionCallback)
     93        self.didStartFormControlInteractionCallback();
     94}
     95
     96- (void)didEndFormControlInteraction
     97{
     98    if (self.didEndFormControlInteractionCallback)
     99        self.didEndFormControlInteractionCallback();
    86100}
    87101
  • trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm

    r204525 r204728  
    188188}
    189189
     190static CGPoint contentOffsetBoundedInValidRange(UIScrollView *scrollView, CGPoint contentOffset)
     191{
     192    UIEdgeInsets contentInsets = scrollView.contentInset;
     193    CGSize contentSize = scrollView.contentSize;
     194    CGSize scrollViewSize = scrollView.bounds.size;
     195
     196    CGFloat maxHorizontalOffset = contentSize.width + contentInsets.right - scrollViewSize.width;
     197    contentOffset.x = std::min(maxHorizontalOffset, contentOffset.x);
     198    contentOffset.x = std::max(-contentInsets.left, contentOffset.x);
     199
     200    CGFloat maxVerticalOffset = contentSize.height + contentInsets.bottom - scrollViewSize.height;
     201    contentOffset.y = std::min(maxVerticalOffset, contentOffset.y);
     202    contentOffset.y = std::max(-contentInsets.top, contentOffset.y);
     203    return contentOffset;
     204}
     205
     206void UIScriptController::scrollToOffset(long x, long y)
     207{
     208    TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
     209    [webView.scrollView setContentOffset:contentOffsetBoundedInValidRange(webView.scrollView, CGPointMake(x, y)) animated:YES];
     210}
     211
    190212void UIScriptController::keyboardAccessoryBarNext()
    191213{
     
    220242    WKRect wkRect = WKRectMake(contentVisibleRect.origin.x, contentVisibleRect.origin.y, contentVisibleRect.size.width, contentVisibleRect.size.height);
    221243    return m_context->objectFromRect(wkRect);
     244}
     245
     246void UIScriptController::platformSetDidStartFormControlInteractionCallback()
     247{
     248    TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
     249    webView.didStartFormControlInteractionCallback = ^{
     250        if (!m_context)
     251            return;
     252        m_context->fireCallback(CallbackTypeDidStartFormControlInteraction);
     253    };
     254}
     255
     256void UIScriptController::platformSetDidEndFormControlInteractionCallback()
     257{
     258    TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
     259    webView.didEndFormControlInteractionCallback = ^{
     260        if (!m_context)
     261            return;
     262        m_context->fireCallback(CallbackTypeDidEndFormControlInteraction);
     263    };
    222264}
    223265
Note: See TracChangeset for help on using the changeset viewer.