Title: [261530] branches/safari-609-branch
Revision
261530
Author
[email protected]
Date
2020-05-11 17:22:29 -0700 (Mon, 11 May 2020)

Log Message

Cherry-pick r260979. rdar://problem/62978869

    REGRESSION: Double tap dispatches one click event on iOS 13.4 when it would dispatch two on iOS 13.3
    https://bugs.webkit.org/show_bug.cgi?id=211179
    <rdar://problem/62594779>

    Reviewed by Tim Horton.

    Source/WebKit:

    https://trac.webkit.org/r253267 introduced deferring gesture recognizers as a way to handle preventable (non-
    passive) touchstart events without blocking the UI process. These deferring gesture recognizers work by having
    other gesture recognizers at or below WKWebView (with few exceptions) require the failure of these deferring
    gestures. These gestures transition to possible state when beginning a touch inside a non-passive touch event
    handling region, and transition to either failed or ended state (depending on whether `preventDefault()` was
    called) after the web content process finished handling the touch event.

    However, this means that the resulting dependency graph now has an edge between each gesture under WKWebView and
    one of the deferring gesture recognizers, due to these new failure requirements. Since gestures that have been
    recognized or have failed don't get reset until all other gestures in the same dependency subgraph have also
    recognized or failed, some gestures (such as the synthetic single tap gesture recognizer in this bug) might not
    be resetting as soon after ending as they did before, since they may be connected to other gesture recognizers
    that are still in possible state by way of the failure requirements added by the new deferring gestures.

    I was already aware of this problem in r253267, and attempted to solve this by bisecting the gesture dependency
    graph into two subgraphs: one containing all the one-finger multi-tap gestures that are reset after a lengthy
    delay, and another containing everything else. To do this, I added two different deferring gesture recognizers:
    one for immediately resettable gestures (meant for gestures in the latter subgraph), and another for gestures
    that are reset after a delay (meant for gestures in the former subgraph).

    Unfortunately, unrelated changes around text interactions in UIKit in iOS 13.4 caused the tap-and-a-half
    gesture for selecting a range of text to now have a delayed reset; this means that gestures in the "immediately
    resettable" gesture subgraph are all forced to wait on the tap-and-a-half text interaction gesture before
    resetting, which causes the bug here, since the synthetic single tap gesture is in this "immediately resettable"
    gesture subgraph.

    To mitigate this, this patch pushes the tap-and-a-half text selection gesture, along with the loupe gesture,
    context menu relationship gesture, and drag lift gestures (i.e. the other gestures that are connected to the
    tap-and-a-half gesture via failure requirements) out of the "immediately resettable" subgraph, and into the
    "delayed" subgraph.

    Test: fast/events/touch/ios/two-click-events-after-double-tap-with-touch-handler.html

    * Platform/spi/ios/UIKitSPI.h:
    * UIProcess/ios/WKContentViewInteraction.mm:
    (-[WKContentView deferringGestureRecognizer:shouldDeferOtherGestureRecognizer:]):

    LayoutTests:

    Add a new layout test to verify that double tapping a button with fast-clicking enabled (i.e. in a device-width
    viewport) fires two click events.

    * fast/events/touch/ios/two-click-events-after-double-tap-with-touch-handler-expected.txt: Added.
    * fast/events/touch/ios/two-click-events-after-double-tap-with-touch-handler.html: Added.

    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@260979 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Modified Paths

Added Paths

Diff

Modified: branches/safari-609-branch/LayoutTests/ChangeLog (261529 => 261530)


--- branches/safari-609-branch/LayoutTests/ChangeLog	2020-05-12 00:22:26 UTC (rev 261529)
+++ branches/safari-609-branch/LayoutTests/ChangeLog	2020-05-12 00:22:29 UTC (rev 261530)
@@ -1,5 +1,78 @@
 2020-05-11  Alan Coon  <[email protected]>
 
+        Cherry-pick r260979. rdar://problem/62978869
+
+    REGRESSION: Double tap dispatches one click event on iOS 13.4 when it would dispatch two on iOS 13.3
+    https://bugs.webkit.org/show_bug.cgi?id=211179
+    <rdar://problem/62594779>
+    
+    Reviewed by Tim Horton.
+    
+    Source/WebKit:
+    
+    https://trac.webkit.org/r253267 introduced deferring gesture recognizers as a way to handle preventable (non-
+    passive) touchstart events without blocking the UI process. These deferring gesture recognizers work by having
+    other gesture recognizers at or below WKWebView (with few exceptions) require the failure of these deferring
+    gestures. These gestures transition to possible state when beginning a touch inside a non-passive touch event
+    handling region, and transition to either failed or ended state (depending on whether `preventDefault()` was
+    called) after the web content process finished handling the touch event.
+    
+    However, this means that the resulting dependency graph now has an edge between each gesture under WKWebView and
+    one of the deferring gesture recognizers, due to these new failure requirements. Since gestures that have been
+    recognized or have failed don't get reset until all other gestures in the same dependency subgraph have also
+    recognized or failed, some gestures (such as the synthetic single tap gesture recognizer in this bug) might not
+    be resetting as soon after ending as they did before, since they may be connected to other gesture recognizers
+    that are still in possible state by way of the failure requirements added by the new deferring gestures.
+    
+    I was already aware of this problem in r253267, and attempted to solve this by bisecting the gesture dependency
+    graph into two subgraphs: one containing all the one-finger multi-tap gestures that are reset after a lengthy
+    delay, and another containing everything else. To do this, I added two different deferring gesture recognizers:
+    one for immediately resettable gestures (meant for gestures in the latter subgraph), and another for gestures
+    that are reset after a delay (meant for gestures in the former subgraph).
+    
+    Unfortunately, unrelated changes around text interactions in UIKit in iOS 13.4 caused the tap-and-a-half
+    gesture for selecting a range of text to now have a delayed reset; this means that gestures in the "immediately
+    resettable" gesture subgraph are all forced to wait on the tap-and-a-half text interaction gesture before
+    resetting, which causes the bug here, since the synthetic single tap gesture is in this "immediately resettable"
+    gesture subgraph.
+    
+    To mitigate this, this patch pushes the tap-and-a-half text selection gesture, along with the loupe gesture,
+    context menu relationship gesture, and drag lift gestures (i.e. the other gestures that are connected to the
+    tap-and-a-half gesture via failure requirements) out of the "immediately resettable" subgraph, and into the
+    "delayed" subgraph.
+    
+    Test: fast/events/touch/ios/two-click-events-after-double-tap-with-touch-handler.html
+    
+    * Platform/spi/ios/UIKitSPI.h:
+    * UIProcess/ios/WKContentViewInteraction.mm:
+    (-[WKContentView deferringGestureRecognizer:shouldDeferOtherGestureRecognizer:]):
+    
+    LayoutTests:
+    
+    Add a new layout test to verify that double tapping a button with fast-clicking enabled (i.e. in a device-width
+    viewport) fires two click events.
+    
+    * fast/events/touch/ios/two-click-events-after-double-tap-with-touch-handler-expected.txt: Added.
+    * fast/events/touch/ios/two-click-events-after-double-tap-with-touch-handler.html: Added.
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@260979 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2020-04-30  Wenson Hsieh  <[email protected]>
+
+            REGRESSION: Double tap dispatches one click event on iOS 13.4 when it would dispatch two on iOS 13.3
+            https://bugs.webkit.org/show_bug.cgi?id=211179
+            <rdar://problem/62594779>
+
+            Reviewed by Tim Horton.
+
+            Add a new layout test to verify that double tapping a button with fast-clicking enabled (i.e. in a device-width
+            viewport) fires two click events.
+
+            * fast/events/touch/ios/two-click-events-after-double-tap-with-touch-handler-expected.txt: Added.
+            * fast/events/touch/ios/two-click-events-after-double-tap-with-touch-handler.html: Added.
+
+2020-05-11  Alan Coon  <[email protected]>
+
         Cherry-pick r259669. rdar://problem/63111225
 
     Preventing touch events should not prevent gestures installed above WKWebView from recognizing

Added: branches/safari-609-branch/LayoutTests/fast/events/touch/ios/two-click-events-after-double-tap-with-touch-handler-expected.txt (0 => 261530)


--- branches/safari-609-branch/LayoutTests/fast/events/touch/ios/two-click-events-after-double-tap-with-touch-handler-expected.txt	                        (rev 0)
+++ branches/safari-609-branch/LayoutTests/fast/events/touch/ios/two-click-events-after-double-tap-with-touch-handler-expected.txt	2020-05-12 00:22:29 UTC (rev 261530)
@@ -0,0 +1,13 @@
+This test verifies that double-tapping a button dispatches two click events when fast-clicking is active. To manually run the test, double tap the button; two 'Clicked' messages should appear.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Clicked
+PASS Clicked
+PASS clickCount became 2
+PASS touchStartCount is 2
+PASS successfullyParsed is true
+
+TEST COMPLETE
+Double tap here

Added: branches/safari-609-branch/LayoutTests/fast/events/touch/ios/two-click-events-after-double-tap-with-touch-handler.html (0 => 261530)


--- branches/safari-609-branch/LayoutTests/fast/events/touch/ios/two-click-events-after-double-tap-with-touch-handler.html	                        (rev 0)
+++ branches/safari-609-branch/LayoutTests/fast/events/touch/ios/two-click-events-after-double-tap-with-touch-handler.html	2020-05-12 00:22:29 UTC (rev 261530)
@@ -0,0 +1,43 @@
+<!-- webkit-test-runner [ useFlexibleViewport=true ] -->
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="viewport" content="initial-scale=1, user-scalable=no, width=device-width">
+<html>
+<head>
+    <script src=""
+    <script src=""
+    <style>
+        button {
+            width: 100%;
+            height: 100px;
+            position: absolute;
+            top: 100px;
+            left: 0;
+        }
+    </style>
+</head>
+<body>
+<button>Double tap here</button>
+</body>
+<script>
+jsTestIsAsync = true;
+touchStartCount = 0;
+clickCount = 0;
+
+const button = document.querySelector("button");
+button.addEventListener("touchstart", () => ++touchStartCount);
+button.addEventListener("click", () => {
+    testPassed("Clicked");
+    ++clickCount;
+});
+
+addEventListener("load", async () => {
+    description("This test verifies that double-tapping a button dispatches two click events when fast-clicking is active. To manually run the test, double tap the button; two 'Clicked' messages should appear.");
+
+    await UIHelper.humanSpeedDoubleTapAt(50, 150);
+    await new Promise(resolve => shouldBecomeEqual("clickCount", "2", resolve));
+    shouldBe("touchStartCount", "2");
+    finishJSTest();
+});
+</script>
+</html>

Modified: branches/safari-609-branch/Source/WebKit/ChangeLog (261529 => 261530)


--- branches/safari-609-branch/Source/WebKit/ChangeLog	2020-05-12 00:22:26 UTC (rev 261529)
+++ branches/safari-609-branch/Source/WebKit/ChangeLog	2020-05-12 00:22:29 UTC (rev 261530)
@@ -1,5 +1,109 @@
 2020-05-11  Alan Coon  <[email protected]>
 
+        Cherry-pick r260979. rdar://problem/62978869
+
+    REGRESSION: Double tap dispatches one click event on iOS 13.4 when it would dispatch two on iOS 13.3
+    https://bugs.webkit.org/show_bug.cgi?id=211179
+    <rdar://problem/62594779>
+    
+    Reviewed by Tim Horton.
+    
+    Source/WebKit:
+    
+    https://trac.webkit.org/r253267 introduced deferring gesture recognizers as a way to handle preventable (non-
+    passive) touchstart events without blocking the UI process. These deferring gesture recognizers work by having
+    other gesture recognizers at or below WKWebView (with few exceptions) require the failure of these deferring
+    gestures. These gestures transition to possible state when beginning a touch inside a non-passive touch event
+    handling region, and transition to either failed or ended state (depending on whether `preventDefault()` was
+    called) after the web content process finished handling the touch event.
+    
+    However, this means that the resulting dependency graph now has an edge between each gesture under WKWebView and
+    one of the deferring gesture recognizers, due to these new failure requirements. Since gestures that have been
+    recognized or have failed don't get reset until all other gestures in the same dependency subgraph have also
+    recognized or failed, some gestures (such as the synthetic single tap gesture recognizer in this bug) might not
+    be resetting as soon after ending as they did before, since they may be connected to other gesture recognizers
+    that are still in possible state by way of the failure requirements added by the new deferring gestures.
+    
+    I was already aware of this problem in r253267, and attempted to solve this by bisecting the gesture dependency
+    graph into two subgraphs: one containing all the one-finger multi-tap gestures that are reset after a lengthy
+    delay, and another containing everything else. To do this, I added two different deferring gesture recognizers:
+    one for immediately resettable gestures (meant for gestures in the latter subgraph), and another for gestures
+    that are reset after a delay (meant for gestures in the former subgraph).
+    
+    Unfortunately, unrelated changes around text interactions in UIKit in iOS 13.4 caused the tap-and-a-half
+    gesture for selecting a range of text to now have a delayed reset; this means that gestures in the "immediately
+    resettable" gesture subgraph are all forced to wait on the tap-and-a-half text interaction gesture before
+    resetting, which causes the bug here, since the synthetic single tap gesture is in this "immediately resettable"
+    gesture subgraph.
+    
+    To mitigate this, this patch pushes the tap-and-a-half text selection gesture, along with the loupe gesture,
+    context menu relationship gesture, and drag lift gestures (i.e. the other gestures that are connected to the
+    tap-and-a-half gesture via failure requirements) out of the "immediately resettable" subgraph, and into the
+    "delayed" subgraph.
+    
+    Test: fast/events/touch/ios/two-click-events-after-double-tap-with-touch-handler.html
+    
+    * Platform/spi/ios/UIKitSPI.h:
+    * UIProcess/ios/WKContentViewInteraction.mm:
+    (-[WKContentView deferringGestureRecognizer:shouldDeferOtherGestureRecognizer:]):
+    
+    LayoutTests:
+    
+    Add a new layout test to verify that double tapping a button with fast-clicking enabled (i.e. in a device-width
+    viewport) fires two click events.
+    
+    * fast/events/touch/ios/two-click-events-after-double-tap-with-touch-handler-expected.txt: Added.
+    * fast/events/touch/ios/two-click-events-after-double-tap-with-touch-handler.html: Added.
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@260979 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2020-04-30  Wenson Hsieh  <[email protected]>
+
+            REGRESSION: Double tap dispatches one click event on iOS 13.4 when it would dispatch two on iOS 13.3
+            https://bugs.webkit.org/show_bug.cgi?id=211179
+            <rdar://problem/62594779>
+
+            Reviewed by Tim Horton.
+
+            https://trac.webkit.org/r253267 introduced deferring gesture recognizers as a way to handle preventable (non-
+            passive) touchstart events without blocking the UI process. These deferring gesture recognizers work by having
+            other gesture recognizers at or below WKWebView (with few exceptions) require the failure of these deferring
+            gestures. These gestures transition to possible state when beginning a touch inside a non-passive touch event
+            handling region, and transition to either failed or ended state (depending on whether `preventDefault()` was
+            called) after the web content process finished handling the touch event.
+
+            However, this means that the resulting dependency graph now has an edge between each gesture under WKWebView and
+            one of the deferring gesture recognizers, due to these new failure requirements. Since gestures that have been
+            recognized or have failed don't get reset until all other gestures in the same dependency subgraph have also
+            recognized or failed, some gestures (such as the synthetic single tap gesture recognizer in this bug) might not
+            be resetting as soon after ending as they did before, since they may be connected to other gesture recognizers
+            that are still in possible state by way of the failure requirements added by the new deferring gestures.
+
+            I was already aware of this problem in r253267, and attempted to solve this by bisecting the gesture dependency
+            graph into two subgraphs: one containing all the one-finger multi-tap gestures that are reset after a lengthy
+            delay, and another containing everything else. To do this, I added two different deferring gesture recognizers:
+            one for immediately resettable gestures (meant for gestures in the latter subgraph), and another for gestures
+            that are reset after a delay (meant for gestures in the former subgraph).
+
+            Unfortunately, unrelated changes around text interactions in UIKit in iOS 13.4 caused the tap-and-a-half
+            gesture for selecting a range of text to now have a delayed reset; this means that gestures in the "immediately
+            resettable" gesture subgraph are all forced to wait on the tap-and-a-half text interaction gesture before
+            resetting, which causes the bug here, since the synthetic single tap gesture is in this "immediately resettable"
+            gesture subgraph.
+
+            To mitigate this, this patch pushes the tap-and-a-half text selection gesture, along with the loupe gesture,
+            context menu relationship gesture, and drag lift gestures (i.e. the other gestures that are connected to the
+            tap-and-a-half gesture via failure requirements) out of the "immediately resettable" subgraph, and into the
+            "delayed" subgraph.
+
+            Test: fast/events/touch/ios/two-click-events-after-double-tap-with-touch-handler.html
+
+            * Platform/spi/ios/UIKitSPI.h:
+            * UIProcess/ios/WKContentViewInteraction.mm:
+            (-[WKContentView deferringGestureRecognizer:shouldDeferOtherGestureRecognizer:]):
+
+2020-05-11  Alan Coon  <[email protected]>
+
         Cherry-pick r259669. rdar://problem/63111225
 
     Preventing touch events should not prevent gestures installed above WKWebView from recognizing

Modified: branches/safari-609-branch/Source/WebKit/Platform/spi/ios/UIKitSPI.h (261529 => 261530)


--- branches/safari-609-branch/Source/WebKit/Platform/spi/ios/UIKitSPI.h	2020-05-12 00:22:26 UTC (rev 261529)
+++ branches/safari-609-branch/Source/WebKit/Platform/spi/ios/UIKitSPI.h	2020-05-12 00:22:29 UTC (rev 261530)
@@ -1097,6 +1097,12 @@
 @interface UITargetedPreview ()
 @property (nonatomic, strong, setter=_setOverridePositionTrackingView:) UIView *overridePositionTrackingView;
 @end
+
+@interface UIContextMenuInteraction ()
+@property (nonatomic, readonly) UIGestureRecognizer *gestureRecognizerForFailureRelationships;
+- (void)_presentMenuAtLocation:(CGPoint)location;
+@end
+
 #endif // USE(UICONTEXTMENU)
 
 #if HAVE(LINK_PREVIEW) && USE(UICONTEXTMENU)
@@ -1121,6 +1127,12 @@
 @property (nonatomic, readonly) BOOL inGesture;
 @end
 
+#if ENABLE(DRAG_SUPPORT)
+@interface UIDragInteraction (IPI)
+@property (nonatomic, readonly, getter=_initiationDriver) id initiationDriver;
+@end
+#endif // ENABLE(DRAG_SUPPORT)
+
 #if HAVE(LINK_PREVIEW) && USE(UICONTEXTMENU)
 @interface UIContextMenuConfiguration (IPI)
 @property (nonatomic, copy) UIContextMenuContentPreviewProvider previewProvider;

Modified: branches/safari-609-branch/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm (261529 => 261530)


--- branches/safari-609-branch/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm	2020-05-12 00:22:26 UTC (rev 261529)
+++ branches/safari-609-branch/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm	2020-05-12 00:22:29 UTC (rev 261530)
@@ -6832,6 +6832,7 @@
 
 - (BOOL)deferringGestureRecognizer:(WKDeferringGestureRecognizer *)deferringGestureRecognizer shouldDeferOtherGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
 {
+#if ENABLE(IOS_TOUCH_EVENTS)
     if ([_webView _isNavigationSwipeGestureRecognizer:gestureRecognizer])
         return NO;
 
@@ -6849,39 +6850,46 @@
     if (!gestureIsInstalledOnOrUnderWebView)
         return NO;
 
-#if ENABLE(IOS_TOUCH_EVENTS)
-    auto isOneFingerMultipleTapGesture = [](UIGestureRecognizer *gesture) -> BOOL {
-        if (![gesture isKindOfClass:UITapGestureRecognizer.class])
-            return NO;
+    if ([gestureRecognizer isKindOfClass:WKDeferringGestureRecognizer.class])
+        return NO;
 
-        UITapGestureRecognizer *tapGesture = (UITapGestureRecognizer *)gesture;
-        return tapGesture.numberOfTapsRequired > 1 && tapGesture.numberOfTouchesRequired < 2;
-    };
+    if (gestureRecognizer == _touchEventGestureRecognizer)
+        return NO;
 
-    if (deferringGestureRecognizer == _deferringGestureRecognizerForDelayedResettableGestures) {
-        if ([gestureRecognizer isKindOfClass:WKDeferringGestureRecognizer.class])
-            return NO;
+    auto mayDelayResetOfContainingSubgraph = [&](UIGestureRecognizer *gesture) -> BOOL {
+#if USE(UICONTEXTMENU)
+        if (gesture == [_contextMenuInteraction gestureRecognizerForFailureRelationships])
+            return YES;
+#endif
 
-        if (gestureRecognizer == _touchEventGestureRecognizer)
-            return NO;
+#if ENABLE(DRAG_SUPPORT)
+        if (gesture.delegate == [_dragInteraction _initiationDriver])
+            return YES;
+#endif
 
-        return isOneFingerMultipleTapGesture(gestureRecognizer);
-    }
+        if ([gesture isKindOfClass:tapAndAHalfRecognizerClass()])
+            return YES;
 
-    if (deferringGestureRecognizer == _deferringGestureRecognizerForImmediatelyResettableGestures) {
-        if ([gestureRecognizer isKindOfClass:WKDeferringGestureRecognizer.class])
-            return NO;
+        if (gesture == [_textInteractionAssistant loupeGesture])
+            return YES;
 
-        if (gestureRecognizer == _touchEventGestureRecognizer)
-            return NO;
+        if ([gesture isKindOfClass:UITapGestureRecognizer.class]) {
+            UITapGestureRecognizer *tapGesture = (UITapGestureRecognizer *)gesture;
+            return tapGesture.numberOfTapsRequired > 1 && tapGesture.numberOfTouchesRequired < 2;
+        }
 
-        return !isOneFingerMultipleTapGesture(gestureRecognizer);
-    }
+        return NO;
+    };
 
-    ASSERT_NOT_REACHED();
-#endif
+    if (mayDelayResetOfContainingSubgraph(gestureRecognizer))
+        return deferringGestureRecognizer == _deferringGestureRecognizerForDelayedResettableGestures;
 
+    return deferringGestureRecognizer == _deferringGestureRecognizerForImmediatelyResettableGestures;
+#else
+    UNUSED_PARAM(deferringGestureRecognizer);
+    UNUSED_PARAM(gestureRecognizer);
     return NO;
+#endif
 }
 
 #if ENABLE(DRAG_SUPPORT)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to