Title: [249368] trunk
Revision
249368
Author
wenson_hs...@apple.com
Date
2019-09-01 13:42:36 -0700 (Sun, 01 Sep 2019)

Log Message

Long presses that interrupt accelerated scrolling dispatch clicks on apps linked against iOS 12 or earlier
https://bugs.webkit.org/show_bug.cgi?id=201346
<rdar://problem/54885784>

Reviewed by Dean Jackson.

Source/WebKit:

For apps that are linked on or after iOS 13, we add a context menu interaction to the content view, which
requires us to disable (or avoid adding) the highlight long press gesture recognizer. However, for apps that are
linked on the iOS 12 SDK or prior, this gesture is still present, and fires when long pressing for (roughly) up
to 0.75 seconds if a tap gesture was not recognized instead. Firing this gesture sends a click event to the
page; this brings back some form of <rdar://problem/53889373>, but only when holding for slightly longer than a
normal tap, and also only in apps linked on iOS 12 or earlier. To fix this, we apply a similar solution as in
r248433 and detect whether a long press gesture interrupted scroll view deceleration in
-gestureRecognizerShouldBegin:. If so, we return NO to avoid clicking. See per-method comments below for more
details.

Testing this bug as-is was tricky, since there's no way in layout tests to simulate being linked on or before a
given SDK version. Luckily, recall that:
1. This bug occurs when the highlight gesture recognizer is enabled and added to the content view.
2. The highlight gesture recognizer only needs to be disabled or removed when context menu interaction is added.
As such, we should be able to restore the highlight gesture recognizer by suppressing the context menu
interaction in an app linked-on-or-after iOS 13, by setting allowsLinkPreview to NO. Unfortunately, this doesn't
quite work, since we currently always avoid adding the highlight gesture recognizer if the app is linked on
iOS 13 or later.

However, this means that the highlight gesture recognizer is absent from the content view in apps linked against
iOS 13 that disable link previews, even though its absence is not required. This means that long pressing a
clickable element in a web view that disables link previews does not show a tap highlight on iOS 13, whereas it
would on iOS 12; this is a regression, albeit a very subtle one. To fix this subtle issue and make it possible
to write a test for this bug, we refactor some logic for creating and configuring the highlight long press
gesture, such that we now unconditionally add the highlight gesture, but only enable it in apps linked on or
after iOS 13 if link previews (i.e. context menu interaction) are not allowed.

Test: fast/scrolling/ios/click-events-after-long-press-during-momentum-scroll-in-overflow.html

* SourcesCocoa.txt:
* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView setAllowsLinkPreview:]):
* UIProcess/ios/WKContentViewInteraction.h:
* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView setupInteraction]):

Refactor our gesture setup logic to always create and add the long press and highlight long press gestures, but
conditionally disable them based on whether or not (1) the context menu is available, and (2) WKWebView's
allowsLinkPreview property.

(-[WKContentView _didChangeLinkPreviewAvailability]):
(-[WKContentView _updateLongPressAndHighlightLongPressGestures]):

Add a new helper to update the enabled state of the long press and highlight long press gestures, by consulting
-_shouldUseContextMenu and -allowsLinkPreview. This is called when setting up the gestures, as well as whenever
-allowsLinkPreview changes.

(-[WKContentView gestureRecognizerShouldBegin:]):

Factor out logic to ascend the view hierarchy in search of a UIScrollView that was interrupted while
decelerating into a local lambda function; use this for both the highlight gesture and the single tap gesture,
to determine whether they should begin.

* UIProcess/ios/WKHighlightLongPressGestureRecognizer.h: Added.
* UIProcess/ios/WKHighlightLongPressGestureRecognizer.mm: Added.

In order to remember the UIScrollView (if any) tracked by the highlight long press gesture, we subclass
_UIWebHighlightLongPressGestureRecognizer. While UILongPressGestureRecognizer does have SPI to ask for a list of
UITouches, by the time the gesture has been recognized and the gesture delegates are invoked, these UITouches
no longer correspond to UIViews. As such, the only time we have access to the list of UITouches with their
UIViews is during the touches* subclass hooks.

(-[WKHighlightLongPressGestureRecognizer reset]):

Clear out the tracked UIScrollView here, when the gesture is reset (i.e. after ending, or being canceled).

(-[WKHighlightLongPressGestureRecognizer touchesBegan:withEvent:]):

Remember the last touched UIScrollView here.

(-[WKHighlightLongPressGestureRecognizer lastTouchedScrollView]):
* WebKit.xcodeproj/project.pbxproj:

Tools:

Add a new test option to allow tests to disable link previews.

* WebKitTestRunner/TestController.cpp:
(WTR::updateTestOptionsFromTestHeader):
* WebKitTestRunner/TestOptions.h:

Drive-by fix: also check enableLazyImageLoading when determining whether two TestOptions are the same.

(WTR::TestOptions::hasSameInitializationOptions const):
* WebKitTestRunner/cocoa/TestControllerCocoa.mm:
(WTR::TestController::platformCreateWebView):

LayoutTests:

Add a couple of new layout tests to verify that using a long press gesture to interrupt momentum scrolling in a
web view that uses API to disable link previews does not result in a click.

* fast/scrolling/ios/click-events-after-long-press-during-momentum-scroll-in-main-frame-expected.txt: Added.
* fast/scrolling/ios/click-events-after-long-press-during-momentum-scroll-in-main-frame.html: Added.
* fast/scrolling/ios/click-events-after-long-press-during-momentum-scroll-in-overflow-expected.txt: Added.
* fast/scrolling/ios/click-events-after-long-press-during-momentum-scroll-in-overflow.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (249367 => 249368)


--- trunk/LayoutTests/ChangeLog	2019-09-01 18:28:35 UTC (rev 249367)
+++ trunk/LayoutTests/ChangeLog	2019-09-01 20:42:36 UTC (rev 249368)
@@ -1,3 +1,19 @@
+2019-09-01  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        Long presses that interrupt accelerated scrolling dispatch clicks on apps linked against iOS 12 or earlier
+        https://bugs.webkit.org/show_bug.cgi?id=201346
+        <rdar://problem/54885784>
+
+        Reviewed by Dean Jackson.
+
+        Add a couple of new layout tests to verify that using a long press gesture to interrupt momentum scrolling in a
+        web view that uses API to disable link previews does not result in a click.
+
+        * fast/scrolling/ios/click-events-after-long-press-during-momentum-scroll-in-main-frame-expected.txt: Added.
+        * fast/scrolling/ios/click-events-after-long-press-during-momentum-scroll-in-main-frame.html: Added.
+        * fast/scrolling/ios/click-events-after-long-press-during-momentum-scroll-in-overflow-expected.txt: Added.
+        * fast/scrolling/ios/click-events-after-long-press-during-momentum-scroll-in-overflow.html: Added.
+
 2019-09-01  Said Abou-Hallawa  <sabouhall...@apple.com>
 
         HTMLImageElement::decode() should return a resolved promise for decoding non bitmap images

Added: trunk/LayoutTests/fast/scrolling/ios/click-events-after-long-press-during-momentum-scroll-in-main-frame-expected.txt (0 => 249368)


--- trunk/LayoutTests/fast/scrolling/ios/click-events-after-long-press-during-momentum-scroll-in-main-frame-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/scrolling/ios/click-events-after-long-press-during-momentum-scroll-in-main-frame-expected.txt	2019-09-01 20:42:36 UTC (rev 249368)
@@ -0,0 +1,10 @@
+Verifies that long pressing the page during momentum scrolling does not dispatch click events to the page. This test requires WebKitTestRunner.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS document.scrollingElement.scrollTop passed 1000
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/scrolling/ios/click-events-after-long-press-during-momentum-scroll-in-main-frame.html (0 => 249368)


--- trunk/LayoutTests/fast/scrolling/ios/click-events-after-long-press-during-momentum-scroll-in-main-frame.html	                        (rev 0)
+++ trunk/LayoutTests/fast/scrolling/ios/click-events-after-long-press-during-momentum-scroll-in-main-frame.html	2019-09-01 20:42:36 UTC (rev 249368)
@@ -0,0 +1,64 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true allowsLinkPreview=false ] -->
+<html>
+<head>
+<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
+<script src=""
+<script src=""
+<script src=""
+<style>
+html, body {
+    width: 100%;
+    margin: 0px;
+    padding: 0px;
+}
+
+#content {
+    width: 100px;
+    height: 5000px;
+    box-sizing: border-box;
+    padding: 20px;
+    background: linear-gradient(to bottom, red 0%, green 50%, blue 100%);
+}
+</style>
+<body _onload_="runTest()">
+<div id="content"></div>
+</body>
+<script>
+jsTestIsAsync = true;
+const minimumExpectedScrollTop = 1000;
+let reachedMinimumScrollPosition = false;
+
+addEventListener("scroll", observeScrollEvent);
+document.body.addEventListener("click", () => testFailed("Observed unexpected click event."), { once: true });
+
+function noteTestProgress() {
+    if (!window.progress)
+        progress = 0;
+    if (++progress == 2)
+        finishJSTest();
+}
+
+async function observeScrollEvent() {
+    if (!window.testRunner || document.scrollingElement.scrollTop < minimumExpectedScrollTop || reachedMinimumScrollPosition)
+        return;
+
+    reachedMinimumScrollPosition = true;
+    testPassed(`document.scrollingElement.scrollTop passed ${minimumExpectedScrollTop}`);
+    removeEventListener("scroll", observeScrollEvent);
+    await longPressAtPoint(160, document.scrollingElement.scrollTop + 350, 1);
+    await UIHelper.waitForDoubleTapDelay();
+    noteTestProgress();
+}
+
+async function runTest()
+{
+    description("Verifies that long pressing the page during momentum scrolling does not dispatch click events to the page. This test requires WebKitTestRunner.");
+
+    if (!window.testRunner)
+        return;
+
+    await UIHelper.dragFromPointToPoint(160, 450, 160, 50, 0.1);
+    noteTestProgress();
+}
+</script>
+</html>

Added: trunk/LayoutTests/fast/scrolling/ios/click-events-after-long-press-during-momentum-scroll-in-overflow-expected.txt (0 => 249368)


--- trunk/LayoutTests/fast/scrolling/ios/click-events-after-long-press-during-momentum-scroll-in-overflow-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/scrolling/ios/click-events-after-long-press-during-momentum-scroll-in-overflow-expected.txt	2019-09-01 20:42:36 UTC (rev 249368)
@@ -0,0 +1,10 @@
+Verifies that long pressing a subscrollable region during momentum scrolling does not dispatch click events. This test requires WebKitTestRunner.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS scroller.scrollTop passed 500
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/scrolling/ios/click-events-after-long-press-during-momentum-scroll-in-overflow.html (0 => 249368)


--- trunk/LayoutTests/fast/scrolling/ios/click-events-after-long-press-during-momentum-scroll-in-overflow.html	                        (rev 0)
+++ trunk/LayoutTests/fast/scrolling/ios/click-events-after-long-press-during-momentum-scroll-in-overflow.html	2019-09-01 20:42:36 UTC (rev 249368)
@@ -0,0 +1,79 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true internal:AsyncOverflowScrollingEnabled=true allowsLinkPreview=false ] -->
+<html>
+<head>
+<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
+<script src=""
+<script src=""
+<script src=""
+<style>
+html, body {
+    width: 100%;
+    height: 100%;
+    margin: 0px;
+    padding: 0px;
+}
+
+#scroller {
+    width: 100%;
+    height: 75%;
+    overflow: scroll;
+    border: 4px solid black;
+    box-sizing: border-box;
+}
+
+#content {
+    width: 100px;
+    height: 5000px;
+    box-sizing: border-box;
+    padding: 20px;
+    background: linear-gradient(to bottom, red 0%, green 50%, blue 100%);
+}
+</style>
+<body _onload_="runTest()">
+    <div id="scroller">
+        <div id="content"></div>
+    </div>
+    <p id="description"></p>
+    <p id="console"></p>
+</body>
+<script>
+jsTestIsAsync = true;
+
+let reachedMinimumScrollPosition = false;
+const minimumExpectedScrollTop = 500;
+const scroller = document.getElementById("scroller");
+
+scroller.addEventListener("scroll", observeScrollEvent);
+scroller.addEventListener("click", () => testFailed("Observed unexpected click event."), { once: true });
+
+function noteTestProgress() {
+    if (!window.progress)
+        progress = 0;
+    if (++progress == 2)
+        finishJSTest();
+}
+
+async function observeScrollEvent() {
+    if (!window.testRunner || scroller.scrollTop < minimumExpectedScrollTop || reachedMinimumScrollPosition)
+        return;
+
+    reachedMinimumScrollPosition = true;
+    testPassed(`scroller.scrollTop passed ${minimumExpectedScrollTop}`);
+    removeEventListener("scroll", observeScrollEvent);
+    await longPressAtPoint(160, 250, 1);
+    await UIHelper.waitForDoubleTapDelay();
+    noteTestProgress();
+}
+
+async function runTest()
+{
+    description("Verifies that long pressing a subscrollable region during momentum scrolling does not dispatch click events. This test requires WebKitTestRunner.");
+
+    if (!window.testRunner)
+        return;
+
+    await UIHelper.dragFromPointToPoint(160, 250, 160, 50, 0.1);
+    noteTestProgress();
+}
+</script>
+</html>

Modified: trunk/Source/WebKit/ChangeLog (249367 => 249368)


--- trunk/Source/WebKit/ChangeLog	2019-09-01 18:28:35 UTC (rev 249367)
+++ trunk/Source/WebKit/ChangeLog	2019-09-01 20:42:36 UTC (rev 249368)
@@ -1,3 +1,84 @@
+2019-09-01  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        Long presses that interrupt accelerated scrolling dispatch clicks on apps linked against iOS 12 or earlier
+        https://bugs.webkit.org/show_bug.cgi?id=201346
+        <rdar://problem/54885784>
+
+        Reviewed by Dean Jackson.
+
+        For apps that are linked on or after iOS 13, we add a context menu interaction to the content view, which
+        requires us to disable (or avoid adding) the highlight long press gesture recognizer. However, for apps that are
+        linked on the iOS 12 SDK or prior, this gesture is still present, and fires when long pressing for (roughly) up
+        to 0.75 seconds if a tap gesture was not recognized instead. Firing this gesture sends a click event to the
+        page; this brings back some form of <rdar://problem/53889373>, but only when holding for slightly longer than a
+        normal tap, and also only in apps linked on iOS 12 or earlier. To fix this, we apply a similar solution as in
+        r248433 and detect whether a long press gesture interrupted scroll view deceleration in
+        -gestureRecognizerShouldBegin:. If so, we return NO to avoid clicking. See per-method comments below for more
+        details.
+
+        Testing this bug as-is was tricky, since there's no way in layout tests to simulate being linked on or before a
+        given SDK version. Luckily, recall that:
+        1. This bug occurs when the highlight gesture recognizer is enabled and added to the content view.
+        2. The highlight gesture recognizer only needs to be disabled or removed when context menu interaction is added.
+        As such, we should be able to restore the highlight gesture recognizer by suppressing the context menu
+        interaction in an app linked-on-or-after iOS 13, by setting allowsLinkPreview to NO. Unfortunately, this doesn't
+        quite work, since we currently always avoid adding the highlight gesture recognizer if the app is linked on
+        iOS 13 or later.
+
+        However, this means that the highlight gesture recognizer is absent from the content view in apps linked against
+        iOS 13 that disable link previews, even though its absence is not required. This means that long pressing a
+        clickable element in a web view that disables link previews does not show a tap highlight on iOS 13, whereas it
+        would on iOS 12; this is a regression, albeit a very subtle one. To fix this subtle issue and make it possible
+        to write a test for this bug, we refactor some logic for creating and configuring the highlight long press
+        gesture, such that we now unconditionally add the highlight gesture, but only enable it in apps linked on or
+        after iOS 13 if link previews (i.e. context menu interaction) are not allowed.
+
+        Test: fast/scrolling/ios/click-events-after-long-press-during-momentum-scroll-in-overflow.html
+
+        * SourcesCocoa.txt:
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (-[WKWebView setAllowsLinkPreview:]):
+        * UIProcess/ios/WKContentViewInteraction.h:
+        * UIProcess/ios/WKContentViewInteraction.mm:
+        (-[WKContentView setupInteraction]):
+
+        Refactor our gesture setup logic to always create and add the long press and highlight long press gestures, but
+        conditionally disable them based on whether or not (1) the context menu is available, and (2) WKWebView's
+        allowsLinkPreview property.
+
+        (-[WKContentView _didChangeLinkPreviewAvailability]):
+        (-[WKContentView _updateLongPressAndHighlightLongPressGestures]):
+
+        Add a new helper to update the enabled state of the long press and highlight long press gestures, by consulting
+        -_shouldUseContextMenu and -allowsLinkPreview. This is called when setting up the gestures, as well as whenever
+        -allowsLinkPreview changes.
+
+        (-[WKContentView gestureRecognizerShouldBegin:]):
+
+        Factor out logic to ascend the view hierarchy in search of a UIScrollView that was interrupted while
+        decelerating into a local lambda function; use this for both the highlight gesture and the single tap gesture,
+        to determine whether they should begin.
+
+        * UIProcess/ios/WKHighlightLongPressGestureRecognizer.h: Added.
+        * UIProcess/ios/WKHighlightLongPressGestureRecognizer.mm: Added.
+
+        In order to remember the UIScrollView (if any) tracked by the highlight long press gesture, we subclass
+        _UIWebHighlightLongPressGestureRecognizer. While UILongPressGestureRecognizer does have SPI to ask for a list of
+        UITouches, by the time the gesture has been recognized and the gesture delegates are invoked, these UITouches
+        no longer correspond to UIViews. As such, the only time we have access to the list of UITouches with their
+        UIViews is during the touches* subclass hooks.
+
+        (-[WKHighlightLongPressGestureRecognizer reset]):
+
+        Clear out the tracked UIScrollView here, when the gesture is reset (i.e. after ending, or being canceled).
+
+        (-[WKHighlightLongPressGestureRecognizer touchesBegan:withEvent:]):
+
+        Remember the last touched UIScrollView here.
+
+        (-[WKHighlightLongPressGestureRecognizer lastTouchedScrollView]):
+        * WebKit.xcodeproj/project.pbxproj:
+
 2019-08-30  Brent Fulgham  <bfulg...@apple.com>
 
         [WinCairo, FTW] Properly handle device scale factor

Modified: trunk/Source/WebKit/SourcesCocoa.txt (249367 => 249368)


--- trunk/Source/WebKit/SourcesCocoa.txt	2019-09-01 18:28:35 UTC (rev 249367)
+++ trunk/Source/WebKit/SourcesCocoa.txt	2019-09-01 20:42:36 UTC (rev 249368)
@@ -422,6 +422,7 @@
 UIProcess/ios/WKDrawingView.mm
 UIProcess/ios/WKGeolocationProviderIOS.mm
 UIProcess/ios/WKGeolocationProviderIOSObjCSecurityOrigin.mm
+UIProcess/ios/WKHighlightLongPressGestureRecognizer.mm
 UIProcess/ios/WKInspectorNodeSearchGestureRecognizer.mm
 UIProcess/ios/WKKeyboardScrollingAnimator.mm
 UIProcess/ios/WKPasswordView.mm

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm (249367 => 249368)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm	2019-09-01 18:28:35 UTC (rev 249367)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm	2019-09-01 20:42:36 UTC (rev 249368)
@@ -1267,6 +1267,7 @@
         [_contentView _registerPreview];
     else
         [_contentView _unregisterPreview];
+    [_contentView _didChangeLinkPreviewAvailability];
 #endif // HAVE(LINK_PREVIEW)
 #endif // PLATFORM(IOS_FAMILY)
 }

Modified: trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h (249367 => 249368)


--- trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h	2019-09-01 18:28:35 UTC (rev 249367)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h	2019-09-01 20:42:36 UTC (rev 249368)
@@ -99,7 +99,6 @@
 
 @class _UILookupGestureRecognizer;
 @class _UIHighlightView;
-@class _UIWebHighlightLongPressGestureRecognizer;
 @class UIHoverGestureRecognizer;
 @class UITargetedPreview;
 @class WebEvent;
@@ -109,6 +108,7 @@
 @class WKFocusedFormControlView;
 @class WKFormInputControl;
 @class WKFormInputSession;
+@class WKHighlightLongPressGestureRecognizer;
 @class WKInspectorNodeSearchGestureRecognizer;
 
 typedef void (^UIWKAutocorrectionCompletionHandler)(UIWKAutocorrectionRects *rectsForInput);
@@ -213,7 +213,7 @@
 #endif
 
     RetainPtr<WKSyntheticTapGestureRecognizer> _singleTapGestureRecognizer;
-    RetainPtr<_UIWebHighlightLongPressGestureRecognizer> _highlightLongPressGestureRecognizer;
+    RetainPtr<WKHighlightLongPressGestureRecognizer> _highlightLongPressGestureRecognizer;
     RetainPtr<UILongPressGestureRecognizer> _longPressGestureRecognizer;
     RetainPtr<WKSyntheticTapGestureRecognizer> _doubleTapGestureRecognizer;
     RetainPtr<UITapGestureRecognizer> _nonBlockingDoubleTapGestureRecognizer;
@@ -548,6 +548,8 @@
 @property (nonatomic, readonly) BOOL _shouldAvoidResizingWhenInputViewBoundsChange;
 @property (nonatomic, readonly) BOOL _shouldAvoidScrollingWhenFocusedContentIsVisible;
 
+- (void)_didChangeLinkPreviewAvailability;
+
 @end
 
 @interface WKContentView (WKTesting)

Modified: trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm (249367 => 249368)


--- trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm	2019-09-01 18:28:35 UTC (rev 249367)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm	2019-09-01 20:42:36 UTC (rev 249368)
@@ -52,6 +52,7 @@
 #import "WKFocusedFormControlView.h"
 #import "WKFormInputControl.h"
 #import "WKFormSelectControl.h"
+#import "WKHighlightLongPressGestureRecognizer.h"
 #import "WKImagePreviewViewController.h"
 #import "WKInspectorNodeSearchGestureRecognizer.h"
 #import "WKNSURLExtras.h"
@@ -755,15 +756,15 @@
     [_twoFingerDoubleTapGestureRecognizer setDelegate:self];
     [self addGestureRecognizer:_twoFingerDoubleTapGestureRecognizer.get()];
 
-    _highlightLongPressGestureRecognizer = adoptNS([[_UIWebHighlightLongPressGestureRecognizer alloc] initWithTarget:self action:@selector(_highlightLongPressRecognized:)]);
+    _highlightLongPressGestureRecognizer = adoptNS([[WKHighlightLongPressGestureRecognizer alloc] initWithTarget:self action:@selector(_highlightLongPressRecognized:)]);
     [_highlightLongPressGestureRecognizer setDelay:highlightDelay];
     [_highlightLongPressGestureRecognizer setDelegate:self];
+    [self addGestureRecognizer:_highlightLongPressGestureRecognizer.get()];
 
+    [self _createAndConfigureLongPressGestureRecognizer];
+
 #if HAVE(LINK_PREVIEW)
-    if (!self._shouldUseContextMenus) {
-        [self addGestureRecognizer:_highlightLongPressGestureRecognizer.get()];
-        [self _createAndConfigureLongPressGestureRecognizer];
-    }
+    [self _updateLongPressAndHighlightLongPressGestures];
 #endif
 
 #if ENABLE(DATA_INTERACTION)
@@ -1006,6 +1007,23 @@
 #endif
 }
 
+- (void)_didChangeLinkPreviewAvailability
+{
+    [self _updateLongPressAndHighlightLongPressGestures];
+}
+
+- (void)_updateLongPressAndHighlightLongPressGestures
+{
+    // We only disable the highlight long press gesture in the case where UIContextMenu is available and we
+    // also allow link previews, since the context menu interaction's gestures need to take precedence over
+    // highlight long press gestures.
+    [_highlightLongPressGestureRecognizer setEnabled:!self._shouldUseContextMenus || !_webView.allowsLinkPreview];
+
+    // We only enable the long press gesture in the case where the app is linked on iOS 12 or earlier (and
+    // therefore prefers the legacy action sheet over context menus), and link previews are also enabled.
+    [_longPressGestureRecognizer setEnabled:!self._shouldUseContextMenus && _webView.allowsLinkPreview];
+}
+
 - (UIView *)unscaledView
 {
     return _interactionViewsContainerView.get();
@@ -2091,12 +2109,12 @@
     if (gestureRecognizer == _stylusSingleTapGestureRecognizer)
         return _webView._stylusTapGestureShouldCreateEditableImage;
 
-    if (gestureRecognizer == _singleTapGestureRecognizer) {
+    auto isInterruptingDecelerationForScrollViewOrAncestor = [&] (UIScrollView *scrollView) {
         UIScrollView *mainScroller = _webView.scrollView;
-        UIView *view = [_singleTapGestureRecognizer lastTouchedScrollView] ?: mainScroller;
+        UIView *view = scrollView ?: mainScroller;
         while (view) {
             if ([view isKindOfClass:UIScrollView.class] && [(UIScrollView *)view _isInterruptingDeceleration])
-                return NO;
+                return YES;
 
             if (mainScroller == view)
                 break;
@@ -2103,9 +2121,12 @@
 
             view = view.superview;
         }
-        return YES;
-    }
+        return NO;
+    };
 
+    if (gestureRecognizer == _singleTapGestureRecognizer)
+        return !isInterruptingDecelerationForScrollViewOrAncestor([_singleTapGestureRecognizer lastTouchedScrollView]);
+
     if (gestureRecognizer == _highlightLongPressGestureRecognizer
         || gestureRecognizer == _doubleTapGestureRecognizer
         || gestureRecognizer == _nonBlockingDoubleTapGestureRecognizer
@@ -2123,6 +2144,9 @@
     }
 
     if (gestureRecognizer == _highlightLongPressGestureRecognizer) {
+        if (isInterruptingDecelerationForScrollViewOrAncestor([_highlightLongPressGestureRecognizer lastTouchedScrollView]))
+            return NO;
+
         if (hasFocusedElement(_focusedElementInformation)) {
             // This is a different element than the focused one.
             // Prevent the gesture if there is no node.

Added: trunk/Source/WebKit/UIProcess/ios/WKHighlightLongPressGestureRecognizer.h (0 => 249368)


--- trunk/Source/WebKit/UIProcess/ios/WKHighlightLongPressGestureRecognizer.h	                        (rev 0)
+++ trunk/Source/WebKit/UIProcess/ios/WKHighlightLongPressGestureRecognizer.h	2019-09-01 20:42:36 UTC (rev 249368)
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if PLATFORM(IOS_FAMILY)
+
+#import "UIKitSPI.h"
+
+@interface WKHighlightLongPressGestureRecognizer : _UIWebHighlightLongPressGestureRecognizer
+
+@property (nonatomic, readonly, weak) UIScrollView *lastTouchedScrollView;
+
+@end
+
+#endif

Added: trunk/Source/WebKit/UIProcess/ios/WKHighlightLongPressGestureRecognizer.mm (0 => 249368)


--- trunk/Source/WebKit/UIProcess/ios/WKHighlightLongPressGestureRecognizer.mm	                        (rev 0)
+++ trunk/Source/WebKit/UIProcess/ios/WKHighlightLongPressGestureRecognizer.mm	2019-09-01 20:42:36 UTC (rev 249368)
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "WKHighlightLongPressGestureRecognizer.h"
+
+#if PLATFORM(IOS_FAMILY)
+
+#import <wtf/WeakObjCPtr.h>
+
+@implementation WKHighlightLongPressGestureRecognizer {
+    WeakObjCPtr<UIScrollView> _lastTouchedScrollView;
+}
+
+- (void)reset
+{
+    [super reset];
+
+    _lastTouchedScrollView = nil;
+}
+
+- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
+{
+    [super touchesBegan:touches withEvent:event];
+
+    for (UITouch *touch in touches) {
+        if ([touch.view isKindOfClass:UIScrollView.class]) {
+            _lastTouchedScrollView = (UIScrollView *)touch.view;
+            break;
+        }
+    }
+}
+
+- (UIScrollView *)lastTouchedScrollView
+{
+    return _lastTouchedScrollView.get().get();
+}
+
+@end
+
+#endif // PLATFORM(IOS_FAMILY)

Modified: trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj (249367 => 249368)


--- trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj	2019-09-01 18:28:35 UTC (rev 249367)
+++ trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj	2019-09-01 20:42:36 UTC (rev 249368)
@@ -1707,6 +1707,7 @@
 		F4CB09E5225D5A0900891487 /* WebsiteMediaSourcePolicy.h in Headers */ = {isa = PBXBuildFile; fileRef = F4CB09E4225D5A0300891487 /* WebsiteMediaSourcePolicy.h */; };
 		F4D5F51D206087A10038BBA8 /* WKTextInputListViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = F4D5F519206087A00038BBA8 /* WKTextInputListViewController.h */; };
 		F4D5F51F206087A10038BBA8 /* WKQuickboardListViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = F4D5F51B206087A10038BBA8 /* WKQuickboardListViewController.h */; };
+		F4DB54E62319E733009E3155 /* WKHighlightLongPressGestureRecognizer.h in Headers */ = {isa = PBXBuildFile; fileRef = F4DB54E42319E733009E3155 /* WKHighlightLongPressGestureRecognizer.h */; };
 		F6113E25126CE1820057D0A7 /* APIUserContentURLPattern.h in Headers */ = {isa = PBXBuildFile; fileRef = F6113E24126CE1820057D0A7 /* APIUserContentURLPattern.h */; };
 		F6113E29126CE19B0057D0A7 /* WKUserContentURLPattern.h in Headers */ = {isa = PBXBuildFile; fileRef = F6113E27126CE19B0057D0A7 /* WKUserContentURLPattern.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		F634445612A885C8000612D8 /* APISecurityOrigin.h in Headers */ = {isa = PBXBuildFile; fileRef = F634445512A885C8000612D8 /* APISecurityOrigin.h */; };
@@ -4764,6 +4765,8 @@
 		F4D5F51A206087A10038BBA8 /* WKTextInputListViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = WKTextInputListViewController.mm; path = ios/forms/WKTextInputListViewController.mm; sourceTree = "<group>"; };
 		F4D5F51B206087A10038BBA8 /* WKQuickboardListViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WKQuickboardListViewController.h; path = ios/forms/WKQuickboardListViewController.h; sourceTree = "<group>"; };
 		F4D5F51C206087A10038BBA8 /* WKQuickboardListViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = WKQuickboardListViewController.mm; path = ios/forms/WKQuickboardListViewController.mm; sourceTree = "<group>"; };
+		F4DB54E42319E733009E3155 /* WKHighlightLongPressGestureRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WKHighlightLongPressGestureRecognizer.h; path = ios/WKHighlightLongPressGestureRecognizer.h; sourceTree = "<group>"; };
+		F4DB54E52319E733009E3155 /* WKHighlightLongPressGestureRecognizer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = WKHighlightLongPressGestureRecognizer.mm; path = ios/WKHighlightLongPressGestureRecognizer.mm; sourceTree = "<group>"; };
 		F4F59AD32065A5C9006CAA46 /* WKSelectMenuListViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = WKSelectMenuListViewController.mm; path = ios/forms/WKSelectMenuListViewController.mm; sourceTree = "<group>"; };
 		F4F59AD42065A5CA006CAA46 /* WKSelectMenuListViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WKSelectMenuListViewController.h; path = ios/forms/WKSelectMenuListViewController.h; sourceTree = "<group>"; };
 		F6113E24126CE1820057D0A7 /* APIUserContentURLPattern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APIUserContentURLPattern.h; sourceTree = "<group>"; };
@@ -6101,6 +6104,8 @@
 				0FCB4E3F18BBE044000FCFC9 /* WKGeolocationProviderIOS.h */,
 				0FCB4E4018BBE044000FCFC9 /* WKGeolocationProviderIOS.mm */,
 				0FCB4E4118BBE044000FCFC9 /* WKGeolocationProviderIOSObjCSecurityOrigin.mm */,
+				F4DB54E42319E733009E3155 /* WKHighlightLongPressGestureRecognizer.h */,
+				F4DB54E52319E733009E3155 /* WKHighlightLongPressGestureRecognizer.mm */,
 				933DF82D1B3BC09000AEA9E3 /* WKImagePreviewViewController.h */,
 				933DF82F1B3BC0B400AEA9E3 /* WKImagePreviewViewController.mm */,
 				0F3C7259196F5F6800AEDD0C /* WKInspectorHighlightView.h */,
@@ -9938,6 +9943,7 @@
 				A543E307215AD13700279CD9 /* WebPageInspectorTargetFrontendChannel.h in Headers */,
 				C0CE72A11247E71D00BC0EC4 /* WebPageMessages.h in Headers */,
 				2D5C9D0619C81D8F00B3C5C1 /* WebPageOverlay.h in Headers */,
+				46C392292316EC4D008EED9B /* WebPageProxyIdentifier.h in Headers */,
 				BCBD3915125BB1A800D2C29F /* WebPageProxyMessages.h in Headers */,
 				512127C41908239A00DAF35C /* WebPasteboardOverrides.h in Headers */,
 				7C4694D11A51E36800AD5845 /* WebPasteboardProxy.h in Headers */,
@@ -10028,7 +10034,6 @@
 				C5FA1ED318E1062200B3F402 /* WKAirPlayRoutePicker.h in Headers */,
 				2D12DAB520662C73006F00FB /* WKAnimationDelegate.h in Headers */,
 				BCDDB32D124EC2E10048D13C /* WKAPICast.h in Headers */,
-				46C392292316EC4D008EED9B /* WebPageProxyIdentifier.h in Headers */,
 				512E34E5130B4D0500ABD19A /* WKApplicationCacheManager.h in Headers */,
 				A13DC682207AA6B20066EF72 /* WKApplicationStateTrackingView.h in Headers */,
 				BC4075F4124FF0270068F20A /* WKArray.h in Headers */,
@@ -10178,6 +10183,7 @@
 				BC0E619812D6CD120012A72A /* WKGeolocationPosition.h in Headers */,
 				0FCB4E4F18BBE044000FCFC9 /* WKGeolocationProviderIOS.h in Headers */,
 				BCC8B374125FB69000DE46A4 /* WKGeometry.h in Headers */,
+				F4DB54E62319E733009E3155 /* WKHighlightLongPressGestureRecognizer.h in Headers */,
 				1A422F8B18B29B5400D8CD96 /* WKHistoryDelegatePrivate.h in Headers */,
 				B62E7312143047B00069EC35 /* WKHitTestResult.h in Headers */,
 				51D124991E763C01002B2820 /* WKHTTPCookieStore.h in Headers */,

Modified: trunk/Tools/ChangeLog (249367 => 249368)


--- trunk/Tools/ChangeLog	2019-09-01 18:28:35 UTC (rev 249367)
+++ trunk/Tools/ChangeLog	2019-09-01 20:42:36 UTC (rev 249368)
@@ -1,3 +1,23 @@
+2019-09-01  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        Long presses that interrupt accelerated scrolling dispatch clicks on apps linked against iOS 12 or earlier
+        https://bugs.webkit.org/show_bug.cgi?id=201346
+        <rdar://problem/54885784>
+
+        Reviewed by Dean Jackson.
+
+        Add a new test option to allow tests to disable link previews.
+
+        * WebKitTestRunner/TestController.cpp:
+        (WTR::updateTestOptionsFromTestHeader):
+        * WebKitTestRunner/TestOptions.h:
+
+        Drive-by fix: also check enableLazyImageLoading when determining whether two TestOptions are the same.
+
+        (WTR::TestOptions::hasSameInitializationOptions const):
+        * WebKitTestRunner/cocoa/TestControllerCocoa.mm:
+        (WTR::TestController::platformCreateWebView):
+
 2019-08-30  Brent Fulgham  <bfulg...@apple.com>
 
         [WinCairo, FTW] Properly handle device scale factor

Modified: trunk/Tools/WebKitTestRunner/TestController.cpp (249367 => 249368)


--- trunk/Tools/WebKitTestRunner/TestController.cpp	2019-09-01 18:28:35 UTC (rev 249367)
+++ trunk/Tools/WebKitTestRunner/TestController.cpp	2019-09-01 20:42:36 UTC (rev 249368)
@@ -1402,6 +1402,8 @@
             testOptions.enablePageCache = parseBooleanTestHeaderValue(value);
         else if (key == "enableLazyImageLoading")
             testOptions.enableLazyImageLoading = parseBooleanTestHeaderValue(value);
+        else if (key == "allowsLinkPreview")
+            testOptions.allowsLinkPreview = parseBooleanTestHeaderValue(value);
         pairStart = pairEnd + 1;
     }
 }

Modified: trunk/Tools/WebKitTestRunner/TestOptions.h (249367 => 249368)


--- trunk/Tools/WebKitTestRunner/TestOptions.h	2019-09-01 18:28:35 UTC (rev 249367)
+++ trunk/Tools/WebKitTestRunner/TestOptions.h	2019-09-01 20:42:36 UTC (rev 249368)
@@ -95,6 +95,7 @@
     bool enableAppNap { false };
     bool enablePageCache { false };
     bool enableLazyImageLoading { false };
+    bool allowsLinkPreview { true };
 
     double contentInsetTop { 0 };
 
@@ -151,7 +152,9 @@
             || contentInsetTop != options.contentInsetTop
             || contentMode != options.contentMode
             || enableAppNap != options.enableAppNap
-            || enablePageCache != options.enablePageCache)
+            || enablePageCache != options.enablePageCache
+            || enableLazyImageLoading != options.enableLazyImageLoading
+            || allowsLinkPreview != options.allowsLinkPreview)
             return false;
 
         if (!contextOptions.hasSameInitializationOptions(options.contextOptions))

Modified: trunk/Tools/WebKitTestRunner/cocoa/TestControllerCocoa.mm (249367 => 249368)


--- trunk/Tools/WebKitTestRunner/cocoa/TestControllerCocoa.mm	2019-09-01 18:28:35 UTC (rev 249367)
+++ trunk/Tools/WebKitTestRunner/cocoa/TestControllerCocoa.mm	2019-09-01 20:42:36 UTC (rev 249368)
@@ -177,6 +177,8 @@
 
     if (options.editable)
         m_mainWebView->setEditable(true);
+
+    m_mainWebView->platformView().allowsLinkPreview = options.allowsLinkPreview;
 }
 
 PlatformWebView* TestController::platformCreateOtherPage(PlatformWebView* parentView, WKPageConfigurationRef, const TestOptions& options)
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to