Title: [255631] branches/safari-610.1.1-branch
Revision
255631
Author
[email protected]
Date
2020-02-03 19:08:39 -0800 (Mon, 03 Feb 2020)

Log Message

Cherry-pick r255385. rdar://problem/58954516

    [iPadOS] Select popovers on amazon.com sometimes dismiss immediately after appearing
    https://bugs.webkit.org/show_bug.cgi?id=206948
    <rdar://problem/58954516>

    Reviewed by Tim Horton.

    Source/WebKit:

    Amazon adds active touchstart event listeners to their select elements, where they call preventDefault() and
    programmatically focus the select element. Doing so prevents clicks from being dispatched by allowing the web
    touch event gesture to recognize instead of the synthetic click gesture, which (inside -_singleTapRecognized:)
    would otherwise dismiss any currently presented popover.

    After making touchstart events dispatch asynchronously, preventing touchstart no longer causes other native
    gestures (such as the synthetic click gesture) to fail in the case where there is a sync touchmove or touchend
    event listener, and the touch gesture has ended before the touchstart handler has finished executing and told
    the UI process whether or not the touch was handled. This is because the touchend or touchmove is dispatched
    synchronously while the touchstart is still being processed; while the web page sees the correct order of
    events, the UI process will end up learning that the synchronous touch was handled before the response to the
    asynchronously dispatched touchstart event has arrived.

    Our current logic in the sync touch event dispatch case then unconditionally ends gesture deferral by calling
    `doneDeferringNativeGestures` with `handled` equal to whether or not the touch event (a "touchend", in this
    case) had been handled. However, in the case where touchstart event is prevented but the touchend event is not,
    this will cause us to prematurely stop deferring gestures even though the page called `preventDefault()` in the
    touchstart event handler, and allow the synthetic click gesture to recognize when it shouldn't.

    To fix this, keep deferring native gestures after handling a sync touch in the case where a touchstart event is
    still being handled; instead, remember whether the touch event was handled using a new member variable
    (`m_handledSynchronousTouchEventWhileDispatchingPreventableTouchStart`), and consult this when the response to
    the touchstart has been received in the UI process to determine whether platform gestures should be allowed to
    recognize. This variable is reset once we're done handling the touchstart.

    Test: fast/events/touch/ios/prevent-default-with-slow-touchstart-handler.html

    * UIProcess/WebPageProxy.cpp:
    (WebKit::WebPageProxy::handlePreventableTouchEvent):
    * UIProcess/WebPageProxy.h:

    LayoutTests:

    Adds a new layout test to verify that preventing default on elements with slow, active touchstart event handlers
    actually prevents click events from being dispatched.

    * fast/events/touch/ios/prevent-default-with-slow-touchstart-handler-expected.txt: Added.
    * fast/events/touch/ios/prevent-default-with-slow-touchstart-handler.html: Added.

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

Modified Paths

Added Paths

Diff

Modified: branches/safari-610.1.1-branch/LayoutTests/ChangeLog (255630 => 255631)


--- branches/safari-610.1.1-branch/LayoutTests/ChangeLog	2020-02-04 03:08:36 UTC (rev 255630)
+++ branches/safari-610.1.1-branch/LayoutTests/ChangeLog	2020-02-04 03:08:39 UTC (rev 255631)
@@ -1,5 +1,73 @@
 2020-02-03  Russell Epstein  <[email protected]>
 
+        Cherry-pick r255385. rdar://problem/58954516
+
+    [iPadOS] Select popovers on amazon.com sometimes dismiss immediately after appearing
+    https://bugs.webkit.org/show_bug.cgi?id=206948
+    <rdar://problem/58954516>
+    
+    Reviewed by Tim Horton.
+    
+    Source/WebKit:
+    
+    Amazon adds active touchstart event listeners to their select elements, where they call preventDefault() and
+    programmatically focus the select element. Doing so prevents clicks from being dispatched by allowing the web
+    touch event gesture to recognize instead of the synthetic click gesture, which (inside -_singleTapRecognized:)
+    would otherwise dismiss any currently presented popover.
+    
+    After making touchstart events dispatch asynchronously, preventing touchstart no longer causes other native
+    gestures (such as the synthetic click gesture) to fail in the case where there is a sync touchmove or touchend
+    event listener, and the touch gesture has ended before the touchstart handler has finished executing and told
+    the UI process whether or not the touch was handled. This is because the touchend or touchmove is dispatched
+    synchronously while the touchstart is still being processed; while the web page sees the correct order of
+    events, the UI process will end up learning that the synchronous touch was handled before the response to the
+    asynchronously dispatched touchstart event has arrived.
+    
+    Our current logic in the sync touch event dispatch case then unconditionally ends gesture deferral by calling
+    `doneDeferringNativeGestures` with `handled` equal to whether or not the touch event (a "touchend", in this
+    case) had been handled. However, in the case where touchstart event is prevented but the touchend event is not,
+    this will cause us to prematurely stop deferring gestures even though the page called `preventDefault()` in the
+    touchstart event handler, and allow the synthetic click gesture to recognize when it shouldn't.
+    
+    To fix this, keep deferring native gestures after handling a sync touch in the case where a touchstart event is
+    still being handled; instead, remember whether the touch event was handled using a new member variable
+    (`m_handledSynchronousTouchEventWhileDispatchingPreventableTouchStart`), and consult this when the response to
+    the touchstart has been received in the UI process to determine whether platform gestures should be allowed to
+    recognize. This variable is reset once we're done handling the touchstart.
+    
+    Test: fast/events/touch/ios/prevent-default-with-slow-touchstart-handler.html
+    
+    * UIProcess/WebPageProxy.cpp:
+    (WebKit::WebPageProxy::handlePreventableTouchEvent):
+    * UIProcess/WebPageProxy.h:
+    
+    LayoutTests:
+    
+    Adds a new layout test to verify that preventing default on elements with slow, active touchstart event handlers
+    actually prevents click events from being dispatched.
+    
+    * fast/events/touch/ios/prevent-default-with-slow-touchstart-handler-expected.txt: Added.
+    * fast/events/touch/ios/prevent-default-with-slow-touchstart-handler.html: Added.
+    
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@255385 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2020-01-29  Wenson Hsieh  <[email protected]>
+
+            [iPadOS] Select popovers on amazon.com sometimes dismiss immediately after appearing
+            https://bugs.webkit.org/show_bug.cgi?id=206948
+            <rdar://problem/58954516>
+
+            Reviewed by Tim Horton.
+
+            Adds a new layout test to verify that preventing default on elements with slow, active touchstart event handlers
+            actually prevents click events from being dispatched.
+
+            * fast/events/touch/ios/prevent-default-with-slow-touchstart-handler-expected.txt: Added.
+            * fast/events/touch/ios/prevent-default-with-slow-touchstart-handler.html: Added.
+
+2020-02-03  Russell Epstein  <[email protected]>
+
         Cherry-pick r255226. rdar://problem/58780584
 
     REGRESSION (r253634): cricbuzz.com media controls vanish depending on page scale

Added: branches/safari-610.1.1-branch/LayoutTests/fast/events/touch/ios/prevent-default-with-slow-touchstart-handler-expected.txt (0 => 255631)


--- branches/safari-610.1.1-branch/LayoutTests/fast/events/touch/ios/prevent-default-with-slow-touchstart-handler-expected.txt	                        (rev 0)
+++ branches/safari-610.1.1-branch/LayoutTests/fast/events/touch/ios/prevent-default-with-slow-touchstart-handler-expected.txt	2020-02-04 03:08:39 UTC (rev 255631)
@@ -0,0 +1,11 @@
+Verifies that calling preventDefault() in touchstart and touchend listeners prevents click events from being dispatched when the web page takes a long time to process the touchstart event. To manually run the test, tap the two boxes and verify that no click events are dispatched.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS handledFirstTouch became true
+PASS handledSecondTouch became true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: branches/safari-610.1.1-branch/LayoutTests/fast/events/touch/ios/prevent-default-with-slow-touchstart-handler.html (0 => 255631)


--- branches/safari-610.1.1-branch/LayoutTests/fast/events/touch/ios/prevent-default-with-slow-touchstart-handler.html	                        (rev 0)
+++ branches/safari-610.1.1-branch/LayoutTests/fast/events/touch/ios/prevent-default-with-slow-touchstart-handler.html	2020-02-04 03:08:39 UTC (rev 255631)
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<script src=""
+<script src=""
+<style>
+.target {
+    width: 150px;
+    height: 150px;
+    margin-bottom: 1em;
+    border: 4px solid black;
+    color: white;
+    font-size: 20px;
+}
+
+#target1 {
+    background-color: rgb(52, 199, 89);
+}
+
+#target2 {
+    background-color: rgb(52, 199, 89);
+}
+</style>
+<script>
+jsTestIsAsync = true;
+handledFirstTouch = false;
+handledSecondTouch = false;
+
+function spinForDuration(duration) {
+    const startTime = Date.now();
+    while (true) {
+        if (Date.now() - startTime > duration)
+            break;
+    }
+}
+
+function handleClick(event) {
+    event.target.style.backgroundColor = "rgb(255, 59, 48)";
+    event.target.textContent = "A click event was dispatched.";
+    testFailed("Should not have handled a click");
+}
+
+addEventListener("load", async () => {
+    const target1 = document.getElementById("target1");
+    target1.addEventListener("touchstart", event => {
+        spinForDuration(100);
+        event.preventDefault();
+    });
+    target1.addEventListener("touchend", event => handledFirstTouch = true);
+    target1.addEventListener("click", handleClick);
+
+    const target2 = document.getElementById("target2");
+    target2.addEventListener("touchstart", () => spinForDuration(100));
+    target2.addEventListener("touchend", event => {
+        event.preventDefault();
+        handledSecondTouch = true;
+    });
+    target2.addEventListener("click", handleClick);
+
+    description("Verifies that calling preventDefault() in touchstart and touchend listeners prevents click events from being dispatched when the web page takes a long time to process the touchstart event. To manually run the test, tap the two boxes and verify that no click events are dispatched.");
+
+    if (!window.testRunner)
+        return;
+
+    await UIHelper.activateElement(target1);
+    await new Promise(resolve => shouldBecomeEqual("handledFirstTouch", "true", resolve));
+
+    await UIHelper.activateElement(target2);
+    await new Promise(resolve => shouldBecomeEqual("handledSecondTouch", "true", resolve));
+
+    finishJSTest();
+});
+</script>
+</head>
+<body>
+    <div class="target" id="target1"></div>
+    <div class="target" id="target2"></div>
+</body>
+</html>
\ No newline at end of file

Modified: branches/safari-610.1.1-branch/Source/WebKit/ChangeLog (255630 => 255631)


--- branches/safari-610.1.1-branch/Source/WebKit/ChangeLog	2020-02-04 03:08:36 UTC (rev 255630)
+++ branches/safari-610.1.1-branch/Source/WebKit/ChangeLog	2020-02-04 03:08:39 UTC (rev 255631)
@@ -1,5 +1,98 @@
 2020-02-03  Russell Epstein  <[email protected]>
 
+        Cherry-pick r255385. rdar://problem/58954516
+
+    [iPadOS] Select popovers on amazon.com sometimes dismiss immediately after appearing
+    https://bugs.webkit.org/show_bug.cgi?id=206948
+    <rdar://problem/58954516>
+    
+    Reviewed by Tim Horton.
+    
+    Source/WebKit:
+    
+    Amazon adds active touchstart event listeners to their select elements, where they call preventDefault() and
+    programmatically focus the select element. Doing so prevents clicks from being dispatched by allowing the web
+    touch event gesture to recognize instead of the synthetic click gesture, which (inside -_singleTapRecognized:)
+    would otherwise dismiss any currently presented popover.
+    
+    After making touchstart events dispatch asynchronously, preventing touchstart no longer causes other native
+    gestures (such as the synthetic click gesture) to fail in the case where there is a sync touchmove or touchend
+    event listener, and the touch gesture has ended before the touchstart handler has finished executing and told
+    the UI process whether or not the touch was handled. This is because the touchend or touchmove is dispatched
+    synchronously while the touchstart is still being processed; while the web page sees the correct order of
+    events, the UI process will end up learning that the synchronous touch was handled before the response to the
+    asynchronously dispatched touchstart event has arrived.
+    
+    Our current logic in the sync touch event dispatch case then unconditionally ends gesture deferral by calling
+    `doneDeferringNativeGestures` with `handled` equal to whether or not the touch event (a "touchend", in this
+    case) had been handled. However, in the case where touchstart event is prevented but the touchend event is not,
+    this will cause us to prematurely stop deferring gestures even though the page called `preventDefault()` in the
+    touchstart event handler, and allow the synthetic click gesture to recognize when it shouldn't.
+    
+    To fix this, keep deferring native gestures after handling a sync touch in the case where a touchstart event is
+    still being handled; instead, remember whether the touch event was handled using a new member variable
+    (`m_handledSynchronousTouchEventWhileDispatchingPreventableTouchStart`), and consult this when the response to
+    the touchstart has been received in the UI process to determine whether platform gestures should be allowed to
+    recognize. This variable is reset once we're done handling the touchstart.
+    
+    Test: fast/events/touch/ios/prevent-default-with-slow-touchstart-handler.html
+    
+    * UIProcess/WebPageProxy.cpp:
+    (WebKit::WebPageProxy::handlePreventableTouchEvent):
+    * UIProcess/WebPageProxy.h:
+    
+    LayoutTests:
+    
+    Adds a new layout test to verify that preventing default on elements with slow, active touchstart event handlers
+    actually prevents click events from being dispatched.
+    
+    * fast/events/touch/ios/prevent-default-with-slow-touchstart-handler-expected.txt: Added.
+    * fast/events/touch/ios/prevent-default-with-slow-touchstart-handler.html: Added.
+    
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@255385 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2020-01-29  Wenson Hsieh  <[email protected]>
+
+            [iPadOS] Select popovers on amazon.com sometimes dismiss immediately after appearing
+            https://bugs.webkit.org/show_bug.cgi?id=206948
+            <rdar://problem/58954516>
+
+            Reviewed by Tim Horton.
+
+            Amazon adds active touchstart event listeners to their select elements, where they call preventDefault() and
+            programmatically focus the select element. Doing so prevents clicks from being dispatched by allowing the web
+            touch event gesture to recognize instead of the synthetic click gesture, which (inside -_singleTapRecognized:)
+            would otherwise dismiss any currently presented popover.
+
+            After making touchstart events dispatch asynchronously, preventing touchstart no longer causes other native
+            gestures (such as the synthetic click gesture) to fail in the case where there is a sync touchmove or touchend
+            event listener, and the touch gesture has ended before the touchstart handler has finished executing and told
+            the UI process whether or not the touch was handled. This is because the touchend or touchmove is dispatched
+            synchronously while the touchstart is still being processed; while the web page sees the correct order of
+            events, the UI process will end up learning that the synchronous touch was handled before the response to the
+            asynchronously dispatched touchstart event has arrived.
+
+            Our current logic in the sync touch event dispatch case then unconditionally ends gesture deferral by calling
+            `doneDeferringNativeGestures` with `handled` equal to whether or not the touch event (a "touchend", in this
+            case) had been handled. However, in the case where touchstart event is prevented but the touchend event is not,
+            this will cause us to prematurely stop deferring gestures even though the page called `preventDefault()` in the
+            touchstart event handler, and allow the synthetic click gesture to recognize when it shouldn't.
+
+            To fix this, keep deferring native gestures after handling a sync touch in the case where a touchstart event is
+            still being handled; instead, remember whether the touch event was handled using a new member variable
+            (`m_handledSynchronousTouchEventWhileDispatchingPreventableTouchStart`), and consult this when the response to
+            the touchstart has been received in the UI process to determine whether platform gestures should be allowed to
+            recognize. This variable is reset once we're done handling the touchstart.
+
+            Test: fast/events/touch/ios/prevent-default-with-slow-touchstart-handler.html
+
+            * UIProcess/WebPageProxy.cpp:
+            (WebKit::WebPageProxy::handlePreventableTouchEvent):
+            * UIProcess/WebPageProxy.h:
+
+2020-02-03  Russell Epstein  <[email protected]>
+
         Cherry-pick r255376. rdar://problem/58440111
 
     Unreviewed, fix Catalyst build after r255366

Modified: branches/safari-610.1.1-branch/Source/WebKit/UIProcess/WebPageProxy.cpp (255630 => 255631)


--- branches/safari-610.1.1-branch/Source/WebKit/UIProcess/WebPageProxy.cpp	2020-02-04 03:08:36 UTC (rev 255630)
+++ branches/safari-610.1.1-branch/Source/WebKit/UIProcess/WebPageProxy.cpp	2020-02-04 03:08:39 UTC (rev 255631)
@@ -2868,10 +2868,13 @@
             if (m_handlingPreventableTouchStartCount)
                 --m_handlingPreventableTouchStartCount;
 
+            bool handledOrFailedWithError = handled || error != CallbackBase::Error::None || m_handledSynchronousTouchEventWhileDispatchingPreventableTouchStart;
+            if (!isHandlingPreventableTouchStart())
+                m_handledSynchronousTouchEventWhileDispatchingPreventableTouchStart = false;
+
             if (error == CallbackBase::Error::ProcessExited)
                 return;
 
-            bool handledOrFailedWithError = handled || error != CallbackBase::Error::None;
             didReceiveEvent(event.type(), handledOrFailedWithError);
             pageClient().doneWithTouchEvent(event, handledOrFailedWithError);
             if (!isHandlingPreventableTouchStart())
@@ -2891,7 +2894,10 @@
         handled = true;
     didReceiveEvent(event.type(), handled);
     pageClient().doneWithTouchEvent(event, handled);
-    pageClient().doneDeferringNativeGestures(handled);
+    if (!isHandlingPreventableTouchStart())
+        pageClient().doneDeferringNativeGestures(handled);
+    else if (handled)
+        m_handledSynchronousTouchEventWhileDispatchingPreventableTouchStart = true;
     m_process->responsivenessTimer().stop();
 }
 

Modified: branches/safari-610.1.1-branch/Source/WebKit/UIProcess/WebPageProxy.h (255630 => 255631)


--- branches/safari-610.1.1-branch/Source/WebKit/UIProcess/WebPageProxy.h	2020-02-04 03:08:36 UTC (rev 255630)
+++ branches/safari-610.1.1-branch/Source/WebKit/UIProcess/WebPageProxy.h	2020-02-04 03:08:39 UTC (rev 255631)
@@ -2456,6 +2456,7 @@
     Deque<QueuedTouchEvents> m_touchEventQueue;
 #endif
 
+    bool m_handledSynchronousTouchEventWhileDispatchingPreventableTouchStart { false };
     uint64_t m_handlingPreventableTouchStartCount { 0 };
 
 #if ENABLE(INPUT_TYPE_COLOR)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to