⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 259669 in webkit


Ignore:
Timestamp:
Apr 7, 2020, 2:00:49 PM (6 years ago)
Author:
Wenson Hsieh
Message:

Preventing touch events should not prevent gestures installed above WKWebView from recognizing
https://bugs.webkit.org/show_bug.cgi?id=210080
<rdar://problem/61365814>

Reviewed by Tim Horton.

Source/WebKit:

Makes a small adjustment to native gesture deferral logic, so that gestures installed above WKWebView (in the
view hierarchy) are not prevented from recognizing by WKDeferringGestureRecognizer. This makes it possible for
WebKit clients to install custom gestures outside of WKWebView that cannot be prevented by web content, without
having to create a separate window and pass touches through to the WKWebView.

Test: fast/events/touch/ios/prevent-default-with-window-tap-gesture.html

  • UIProcess/ios/WKContentViewInteraction.mm:

(-[WKContentView deferringGestureRecognizer:shouldDeferOtherGestureRecognizer:]):

Tools:

Add a UIScriptController helper method that allows a test to install a tap gesture recognizer on the UIWindow
containing the web view. This method additionally takes a JavaScript callback, which is invoked when the tap
gesture is recognized.

  • TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl:
  • TestRunnerShared/UIScriptContext/UIScriptContext.h:
  • TestRunnerShared/UIScriptContext/UIScriptController.h:

(WTR::UIScriptController::installTapGestureOnWindow):

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

(-[TestRunnerWKWebView resetInteractionCallbacks]):
(-[TestRunnerWKWebView didRecognizeTapOnWindow]):
(-[TestRunnerWKWebView windowTapRecognizedCallback]):
(-[TestRunnerWKWebView setWindowTapRecognizedCallback:]):
(-[TestRunnerWKWebView willMoveToWindow:]):
(-[TestRunnerWKWebView didMoveToWindow]):
(-[TestRunnerWKWebView gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:]):

  • WebKitTestRunner/ios/UIScriptControllerIOS.h:
  • WebKitTestRunner/ios/UIScriptControllerIOS.mm:

(WTR::UIScriptControllerIOS::installTapGestureOnWindow):

LayoutTests:

Add a new layout test to verify that calling preventDefault() on touchstart doesn't prevent gesture recognizers
installed above the WKWebView from recognizing. To do this, we use the new UIScriptController method to add a
gesture recognizer to the window containing the web view, and then simulate a tap over an element that prevents
the touchstart event.

  • fast/events/touch/ios/prevent-default-with-window-tap-gesture-expected.txt: Added.
  • fast/events/touch/ios/prevent-default-with-window-tap-gesture.html: Added.
  • resources/ui-helper.js:

(window.UIHelper.async activateElementAfterInstallingTapGestureOnWindow.return.new.Promise.):
(window.UIHelper.async activateElementAfterInstallingTapGestureOnWindow.return.new.Promise):
(window.UIHelper.async activateElementAfterInstallingTapGestureOnWindow):
(window.UIHelper):

Location:
trunk
Files:
2 added
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r259657 r259669  
     12020-04-07  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        Preventing touch events should not prevent gestures installed above WKWebView from recognizing
     4        https://bugs.webkit.org/show_bug.cgi?id=210080
     5        <rdar://problem/61365814>
     6
     7        Reviewed by Tim Horton.
     8
     9        Add a new layout test to verify that calling preventDefault() on touchstart doesn't prevent gesture recognizers
     10        installed above the WKWebView from recognizing. To do this, we use the new UIScriptController method to add a
     11        gesture recognizer to the window containing the web view, and then simulate a tap over an element that prevents
     12        the touchstart event.
     13
     14        * fast/events/touch/ios/prevent-default-with-window-tap-gesture-expected.txt: Added.
     15        * fast/events/touch/ios/prevent-default-with-window-tap-gesture.html: Added.
     16        * resources/ui-helper.js:
     17        (window.UIHelper.async activateElementAfterInstallingTapGestureOnWindow.return.new.Promise.):
     18        (window.UIHelper.async activateElementAfterInstallingTapGestureOnWindow.return.new.Promise):
     19        (window.UIHelper.async activateElementAfterInstallingTapGestureOnWindow):
     20        (window.UIHelper):
     21
    1222020-04-07  Truitt Savell  <tsavell@apple.com>
    223
  • trunk/LayoutTests/resources/ui-helper.js

    r259417 r259669  
    11461146                        uiController.uiScriptComplete();
    11471147                    });
     1148                })();`, resolve);
     1149        });
     1150    }
     1151
     1152    static async activateElementAfterInstallingTapGestureOnWindow(element)
     1153    {
     1154        if (!this.isWebKit2() || !this.isIOSFamily())
     1155            return activateElement(element);
     1156
     1157        const x = element.offsetLeft + element.offsetWidth / 2;
     1158        const y = element.offsetTop + element.offsetHeight / 2;
     1159        return new Promise(resolve => {
     1160            testRunner.runUIScript(`
     1161                (function() {
     1162                    let progress = 0;
     1163                    function incrementProgress() {
     1164                        if (++progress == 2)
     1165                            uiController.uiScriptComplete();
     1166                    }
     1167                    uiController.installTapGestureOnWindow(incrementProgress);
     1168                    uiController.singleTapAtPoint(${x}, ${y}, incrementProgress);
    11481169                })();`, resolve);
    11491170        });
  • trunk/Source/WebKit/ChangeLog

    r259665 r259669  
     12020-04-07  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        Preventing touch events should not prevent gestures installed above WKWebView from recognizing
     4        https://bugs.webkit.org/show_bug.cgi?id=210080
     5        <rdar://problem/61365814>
     6
     7        Reviewed by Tim Horton.
     8
     9        Makes a small adjustment to native gesture deferral logic, so that gestures installed above WKWebView (in the
     10        view hierarchy) are not prevented from recognizing by WKDeferringGestureRecognizer. This makes it possible for
     11        WebKit clients to install custom gestures outside of WKWebView that cannot be prevented by web content, without
     12        having to create a separate window and pass touches through to the WKWebView.
     13
     14        Test: fast/events/touch/ios/prevent-default-with-window-tap-gesture.html
     15
     16        * UIProcess/ios/WKContentViewInteraction.mm:
     17        (-[WKContentView deferringGestureRecognizer:shouldDeferOtherGestureRecognizer:]):
     18
    1192020-04-07  Brian Burg  <bburg@apple.com>
    220
  • trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm

    r259541 r259669  
    69406940        return NO;
    69416941
     6942    auto webView = _webView.getAutoreleased();
     6943    auto view = gestureRecognizer.view;
     6944    BOOL gestureIsInstalledOnOrUnderWebView = NO;
     6945    while (view) {
     6946        if (view == webView) {
     6947            gestureIsInstalledOnOrUnderWebView = YES;
     6948            break;
     6949        }
     6950        view = view.superview;
     6951    }
     6952
     6953    if (!gestureIsInstalledOnOrUnderWebView)
     6954        return NO;
     6955
    69426956#if ENABLE(IOS_TOUCH_EVENTS)
    69436957    auto isOneFingerMultipleTapGesture = [](UIGestureRecognizer *gesture) -> BOOL {
  • trunk/Tools/ChangeLog

    r259668 r259669  
     12020-04-07  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        Preventing touch events should not prevent gestures installed above WKWebView from recognizing
     4        https://bugs.webkit.org/show_bug.cgi?id=210080
     5        <rdar://problem/61365814>
     6
     7        Reviewed by Tim Horton.
     8
     9        Add a UIScriptController helper method that allows a test to install a tap gesture recognizer on the UIWindow
     10        containing the web view. This method additionally takes a JavaScript callback, which is invoked when the tap
     11        gesture is recognized.
     12
     13        * TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl:
     14        * TestRunnerShared/UIScriptContext/UIScriptContext.h:
     15        * TestRunnerShared/UIScriptContext/UIScriptController.h:
     16        (WTR::UIScriptController::installTapGestureOnWindow):
     17        * WebKitTestRunner/cocoa/TestRunnerWKWebView.h:
     18        * WebKitTestRunner/cocoa/TestRunnerWKWebView.mm:
     19        (-[TestRunnerWKWebView resetInteractionCallbacks]):
     20        (-[TestRunnerWKWebView didRecognizeTapOnWindow]):
     21        (-[TestRunnerWKWebView windowTapRecognizedCallback]):
     22        (-[TestRunnerWKWebView setWindowTapRecognizedCallback:]):
     23        (-[TestRunnerWKWebView willMoveToWindow:]):
     24        (-[TestRunnerWKWebView didMoveToWindow]):
     25        (-[TestRunnerWKWebView gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:]):
     26        * WebKitTestRunner/ios/UIScriptControllerIOS.h:
     27        * WebKitTestRunner/ios/UIScriptControllerIOS.mm:
     28        (WTR::UIScriptControllerIOS::installTapGestureOnWindow):
     29
    1302020-04-07  Alexey Shvayka  <shvaikalesh@gmail.com>
    231
  • trunk/Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl

    r257187 r259669  
    323323    void addViewToWindow(object callback);
    324324
     325    void installTapGestureOnWindow(object callback);
     326
    325327    void overridePreference(DOMString preference, DOMString value);
    326328
  • trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptContext.h

    r251522 r259669  
    6565    CallbackTypeDidDismissContextMenu,
    6666    CallbackTypeWillCreateNewPage,
     67    CallbackTypeWindowTapRecognized,
    6768    CallbackTypeNonPersistent = firstNonPersistentCallbackID
    6869} CallbackType;
  • trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.h

    r257187 r259669  
    118118    virtual void addViewToWindow(JSValueRef) { notImplemented(); }
    119119
     120    virtual void installTapGestureOnWindow(JSValueRef) { notImplemented(); }
     121
    120122    // Compositing
    121123
  • trunk/Tools/WebKitTestRunner/cocoa/TestRunnerWKWebView.h

    r251522 r259669  
    4646@property (nonatomic, copy) void (^didEndScrollingCallback)(void);
    4747@property (nonatomic, copy) void (^rotationDidEndCallback)(void);
     48@property (nonatomic, copy) void (^windowTapRecognizedCallback)(void);
    4849@property (nonatomic, copy) NSString *accessibilitySpeakSelectionContent;
    4950
  • trunk/Tools/WebKitTestRunner/cocoa/TestRunnerWKWebView.mm

    r253465 r259669  
    5656};
    5757
    58 @interface TestRunnerWKWebView () <WKUIDelegatePrivate> {
     58@interface TestRunnerWKWebView () <WKUIDelegatePrivate
     59#if PLATFORM(IOS_FAMILY)
     60    , UIGestureRecognizerDelegate
     61#endif
     62> {
    5963    RetainPtr<NSNumber> m_stableStateOverride;
    6064    BOOL _isInteractingWithFormControl;
     
    6266    Optional<CustomMenuActionInfo> _customMenuActionInfo;
    6367    RetainPtr<NSArray<NSString *>> _allowedMenuActions;
     68#if PLATFORM(IOS_FAMILY)
     69    RetainPtr<UITapGestureRecognizer> _windowTapGestureRecognizer;
     70    BlockPtr<void()> _windowTapRecognizedCallback;
     71#endif
    6472}
    6573
     
    173181    self.didEndScrollingCallback = nil;
    174182    self.rotationDidEndCallback = nil;
     183    self.windowTapRecognizedCallback = nil;
    175184#endif // PLATFORM(IOS_FAMILY)
    176185}
     
    410419}
    411420
     421- (void)didRecognizeTapOnWindow
     422{
     423    ASSERT(self.windowTapRecognizedCallback);
     424    if (self.windowTapRecognizedCallback)
     425        self.windowTapRecognizedCallback();
     426}
     427
     428- (void(^)())windowTapRecognizedCallback
     429{
     430    return _windowTapRecognizedCallback.get();
     431}
     432
     433- (void)setWindowTapRecognizedCallback:(void(^)())windowTapRecognizedCallback
     434{
     435    _windowTapRecognizedCallback = windowTapRecognizedCallback;
     436
     437    if (windowTapRecognizedCallback && !_windowTapGestureRecognizer) {
     438        ASSERT(self.window);
     439        _windowTapGestureRecognizer = adoptNS([[UITapGestureRecognizer alloc] init]);
     440        [_windowTapGestureRecognizer setDelegate:self];
     441        [_windowTapGestureRecognizer addTarget:self action:@selector(didRecognizeTapOnWindow)];
     442        [self.window addGestureRecognizer:_windowTapGestureRecognizer.get()];
     443    } else if (!windowTapRecognizedCallback && _windowTapGestureRecognizer) {
     444        [self.window removeGestureRecognizer:_windowTapGestureRecognizer.get()];
     445        _windowTapGestureRecognizer = nil;
     446    }
     447}
     448
     449- (void)willMoveToWindow:(UIWindow *)window
     450{
     451    [super willMoveToWindow:window];
     452
     453    if (_windowTapGestureRecognizer)
     454        [self.window removeGestureRecognizer:_windowTapGestureRecognizer.get()];
     455}
     456
     457- (void)didMoveToWindow
     458{
     459    [super didMoveToWindow];
     460
     461    if (_windowTapGestureRecognizer)
     462        [self.window addGestureRecognizer:_windowTapGestureRecognizer.get()];
     463}
     464
    412465- (void)_accessibilityDidGetSpeakSelectionContent:(NSString *)content
    413466{
     
    450503}
    451504
     505#pragma mark - UIGestureRecognizerDelegate
     506
     507- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
     508{
     509    return gestureRecognizer == _windowTapGestureRecognizer;
     510}
     511
    452512#endif // PLATFORM(IOS_FAMILY)
    453513
  • trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.h

    r255507 r259669  
    141141    void setAllowsViewportShrinkToFit(bool) override;
    142142    void copyText(JSStringRef) override;
     143    void installTapGestureOnWindow(JSValueRef) override;
    143144
    144145    void setDidStartFormControlInteractionCallback(JSValueRef) override;
  • trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm

    r255507 r259669  
    12641264}
    12651265
     1266void UIScriptControllerIOS::installTapGestureOnWindow(JSValueRef callback)
     1267{
     1268    m_context->registerCallback(callback, CallbackTypeWindowTapRecognized);
     1269    webView().windowTapRecognizedCallback = makeBlockPtr([this, strongThis = makeRef(*this)] {
     1270        if (!m_context)
     1271            return;
     1272        m_context->fireCallback(CallbackTypeWindowTapRecognized);
     1273    }).get();
     1274}
     1275
    12661276}
    12671277
Note: See TracChangeset for help on using the changeset viewer.