Title: [221092] trunk
Revision
221092
Author
[email protected]
Date
2017-08-23 12:22:28 -0700 (Wed, 23 Aug 2017)

Log Message

Default passive touch event listeners on the root
https://bugs.webkit.org/show_bug.cgi?id=175346
<rdar://problem/33164597>

Reviewed by Sam Weinig.

Source/WebCore:

Make any touchstart or touchmove event listeners passive by default
if they are on the document, window, body or document element targets.
This follows the "intervention" first implemented by Chrome/Blink:

https://github.com/WICG/interventions/issues/35
https://docs.google.com/document/d/1II7oSIpd8pK91V5kEM3tDLKcIj398jOJn8Niqy6_loI/edit
https://github.com/whatwg/dom/issues/365

If the event listener explicitly defines "passive" to false in their
options dictionary, then they'll still get a non-passive listener.

NOTE: Any fallout from this bug should be collected in:
https://bugs.webkit.org/show_bug.cgi?id=175869
Please do not revert this change just because a site is broken. We'll
gather the issues and see if we can evangelise or detect via code.

Tests: fast/events/touch/ios/passive-by-default-on-document-and-window.html
       fast/events/touch/ios/passive-by-default-overridden-on-document-and-window.html

* dom/EventNames.h:
(WebCore::EventNames::isTouchScrollBlockingEventType const): Added this helper
to identify the types of touches we want to check for.
* dom/EventTarget.cpp:
(WebCore::EventTarget::addEventListener): Check for the event being one of the touch-types
that we care about, and the target being one of the Node/Window types we care about. If
so, tell the event listener to be passive.
* dom/EventTarget.h: Use an optional for the passive member.
(WebCore::EventTarget::AddEventListenerOptions::AddEventListenerOptions):
* dom/EventTarget.idl: Change "passive" to not have a default value, so we
can detect if it was explicitly set to false.

LayoutTests:

* fast/events/touch/ios/passive-by-default-on-document-and-window-expected.txt: Added.
* fast/events/touch/ios/passive-by-default-on-document-and-window.html: Added.
* fast/events/touch/ios/passive-by-default-overridden-on-document-and-window-expected.txt: Added.
* fast/events/touch/ios/passive-by-default-overridden-on-document-and-window.html: Added.
* fast/events/touch/ios/tap-with-active-listener-on-window.html: Explicitly set passive to false.
* fast/events/touch/ios/touch-event-regions/document.html: Ditto.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (221091 => 221092)


--- trunk/LayoutTests/ChangeLog	2017-08-23 19:10:00 UTC (rev 221091)
+++ trunk/LayoutTests/ChangeLog	2017-08-23 19:22:28 UTC (rev 221092)
@@ -1,3 +1,18 @@
+2017-08-22  Dean Jackson  <[email protected]>
+
+        Default passive touch event listeners on the root
+        https://bugs.webkit.org/show_bug.cgi?id=175346
+        <rdar://problem/33164597>
+
+        Reviewed by Sam Weinig.
+
+        * fast/events/touch/ios/passive-by-default-on-document-and-window-expected.txt: Added.
+        * fast/events/touch/ios/passive-by-default-on-document-and-window.html: Added.
+        * fast/events/touch/ios/passive-by-default-overridden-on-document-and-window-expected.txt: Added.
+        * fast/events/touch/ios/passive-by-default-overridden-on-document-and-window.html: Added.
+        * fast/events/touch/ios/tap-with-active-listener-on-window.html: Explicitly set passive to false.
+        * fast/events/touch/ios/touch-event-regions/document.html: Ditto.
+
 2017-08-23  Matt Lewis  <[email protected]>
 
         Marked imported/w3c/web-platform-tests/html/webappapis/timers/type-long-settimeout.html as flaky.

Added: trunk/LayoutTests/fast/events/touch/ios/passive-by-default-on-document-and-window-expected.txt (0 => 221092)


--- trunk/LayoutTests/fast/events/touch/ios/passive-by-default-on-document-and-window-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/events/touch/ios/passive-by-default-on-document-and-window-expected.txt	2017-08-23 19:22:28 UTC (rev 221092)
@@ -0,0 +1,13 @@
+touchstart on body - cancelable: false defaultPrevented: false 
+touchstart on documentElement - cancelable: false defaultPrevented: false 
+touchstart on document - cancelable: false defaultPrevented: false 
+touchstart on window - cancelable: false defaultPrevented: false 
+touchmove on body - cancelable: false defaultPrevented: false 
+touchmove on documentElement - cancelable: false defaultPrevented: false 
+touchmove on document - cancelable: false defaultPrevented: false 
+touchmove on window - cancelable: false defaultPrevented: false 
+touchend on body - cancelable: false defaultPrevented: false 
+touchend on documentElement - cancelable: false defaultPrevented: false 
+touchend on document - cancelable: false defaultPrevented: false 
+touchend on window - cancelable: false defaultPrevented: false 
+Done
Property changes on: trunk/LayoutTests/fast/events/touch/ios/passive-by-default-on-document-and-window-expected.txt
___________________________________________________________________

Added: svn:eol-style

+native \ No newline at end of property

Added: svn:keywords

+Date Revision \ No newline at end of property

Added: svn:mime-type

+text/plain \ No newline at end of property

Added: trunk/LayoutTests/fast/events/touch/ios/passive-by-default-on-document-and-window.html (0 => 221092)


--- trunk/LayoutTests/fast/events/touch/ios/passive-by-default-on-document-and-window.html	                        (rev 0)
+++ trunk/LayoutTests/fast/events/touch/ios/passive-by-default-on-document-and-window.html	2017-08-23 19:22:28 UTC (rev 221092)
@@ -0,0 +1,97 @@
+<script>
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+}
+
+function getUIScript()
+{
+    return `
+    (function() {
+        uiController.dragFromPointToPoint(50, 250, 50, 30, 0.1, function() {
+            uiController.uiScriptComplete("Done");
+        });
+    })();`
+}
+
+function runTest()
+{
+    let output = "";
+    window.addEventListener("touchstart", function(event) {
+        event.preventDefault();
+        output += `touchstart on window - cancelable: ${event.cancelable} defaultPrevented: ${event.defaultPrevented} <br>`;
+    }, false);
+
+    window.addEventListener("touchmove", function(event) {
+        event.preventDefault();
+        output += `touchmove on window - cancelable: ${event.cancelable} defaultPrevented: ${event.defaultPrevented} <br>`;
+    }, false);
+
+    window.addEventListener("touchend", function(event) {
+        event.preventDefault();
+        output += `touchend on window - cancelable: ${event.cancelable} defaultPrevented: ${event.defaultPrevented} <br>`;
+    }, false);
+
+    document.addEventListener("touchstart", function(event) {
+        event.preventDefault();
+        output += `touchstart on document - cancelable: ${event.cancelable} defaultPrevented: ${event.defaultPrevented} <br>`;
+    }, false);
+
+    document.addEventListener("touchmove", function(event) {
+        event.preventDefault();
+        output += `touchmove on document - cancelable: ${event.cancelable} defaultPrevented: ${event.defaultPrevented} <br>`;
+    }, false);
+
+    document.addEventListener("touchend", function(event) {
+        event.preventDefault();
+        output += `touchend on document - cancelable: ${event.cancelable} defaultPrevented: ${event.defaultPrevented} <br>`;
+    }, false);
+
+    document.documentElement.addEventListener("touchstart", function(event) {
+        event.preventDefault();
+        output += `touchstart on documentElement - cancelable: ${event.cancelable} defaultPrevented: ${event.defaultPrevented} <br>`;
+    }, false);
+
+    document.documentElement.addEventListener("touchmove", function(event) {
+        event.preventDefault();
+        output += `touchmove on documentElement - cancelable: ${event.cancelable} defaultPrevented: ${event.defaultPrevented} <br>`;
+    }, false);
+
+    document.documentElement.addEventListener("touchend", function(event) {
+        event.preventDefault();
+        output += `touchend on documentElement - cancelable: ${event.cancelable} defaultPrevented: ${event.defaultPrevented} <br>`;
+    }, false);
+
+    let body = document.querySelector("body");
+
+    body.addEventListener("touchstart", function(event) {
+        event.preventDefault();
+        output += `touchstart on body - cancelable: ${event.cancelable} defaultPrevented: ${event.defaultPrevented} <br>`;
+    }, false);
+
+    body.addEventListener("touchmove", function(event) {
+        event.preventDefault();
+        output += `touchmove on body - cancelable: ${event.cancelable} defaultPrevented: ${event.defaultPrevented} <br>`;
+    }, false);
+
+    body.addEventListener("touchend", function(event) {
+        event.preventDefault();
+        output += `touchend on body - cancelable: ${event.cancelable} defaultPrevented: ${event.defaultPrevented} <br>`;
+    }, false);
+
+    if (testRunner.runUIScript) {
+        testRunner.runUIScript(getUIScript(), function(result) {
+            output += result;
+            document.getElementById("output").innerHTML = output;
+            testRunner.notifyDone();
+        });
+    }
+}
+
+window.addEventListener('load', runTest, false);
+</script>
+<body style="height: 500vh">
+<div id=output>
+This test requires UIScriptController to run.
+</div>
+</body>
Property changes on: trunk/LayoutTests/fast/events/touch/ios/passive-by-default-on-document-and-window.html
___________________________________________________________________

Added: svn:eol-style

+native \ No newline at end of property

Added: svn:keywords

+Date Revision \ No newline at end of property

Added: svn:mime-type

+text/html \ No newline at end of property

Added: trunk/LayoutTests/fast/events/touch/ios/passive-by-default-overridden-on-document-and-window-expected.txt (0 => 221092)


--- trunk/LayoutTests/fast/events/touch/ios/passive-by-default-overridden-on-document-and-window-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/events/touch/ios/passive-by-default-overridden-on-document-and-window-expected.txt	2017-08-23 19:22:28 UTC (rev 221092)
@@ -0,0 +1,13 @@
+touchstart on body - cancelable: true defaultPrevented: true 
+touchstart on documentElement - cancelable: true defaultPrevented: true 
+touchstart on document - cancelable: true defaultPrevented: true 
+touchstart on window - cancelable: true defaultPrevented: true 
+touchmove on body - cancelable: true defaultPrevented: true 
+touchmove on documentElement - cancelable: true defaultPrevented: true 
+touchmove on document - cancelable: true defaultPrevented: true 
+touchmove on window - cancelable: true defaultPrevented: true 
+touchend on body - cancelable: true defaultPrevented: true 
+touchend on documentElement - cancelable: true defaultPrevented: true 
+touchend on document - cancelable: true defaultPrevented: true 
+touchend on window - cancelable: true defaultPrevented: true 
+Done
Property changes on: trunk/LayoutTests/fast/events/touch/ios/passive-by-default-overridden-on-document-and-window-expected.txt
___________________________________________________________________

Added: svn:eol-style

+native \ No newline at end of property

Added: svn:keywords

+Date Revision \ No newline at end of property

Added: svn:mime-type

+text/plain \ No newline at end of property

Added: trunk/LayoutTests/fast/events/touch/ios/passive-by-default-overridden-on-document-and-window.html (0 => 221092)


--- trunk/LayoutTests/fast/events/touch/ios/passive-by-default-overridden-on-document-and-window.html	                        (rev 0)
+++ trunk/LayoutTests/fast/events/touch/ios/passive-by-default-overridden-on-document-and-window.html	2017-08-23 19:22:28 UTC (rev 221092)
@@ -0,0 +1,97 @@
+<script>
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+}
+
+function getUIScript()
+{
+    return `
+    (function() {
+        uiController.dragFromPointToPoint(50, 250, 50, 30, 0.1, function() {
+            uiController.uiScriptComplete("Done");
+        });
+    })();`
+}
+
+function runTest()
+{
+    let output = "";
+    window.addEventListener("touchstart", function(event) {
+        event.preventDefault();
+        output += `touchstart on window - cancelable: ${event.cancelable} defaultPrevented: ${event.defaultPrevented} <br>`;
+    }, { "passive": false });
+
+    window.addEventListener("touchmove", function(event) {
+        event.preventDefault();
+        output += `touchmove on window - cancelable: ${event.cancelable} defaultPrevented: ${event.defaultPrevented} <br>`;
+    }, { "passive": false });
+
+    window.addEventListener("touchend", function(event) {
+        event.preventDefault();
+        output += `touchend on window - cancelable: ${event.cancelable} defaultPrevented: ${event.defaultPrevented} <br>`;
+    }, { "passive": false });
+
+    document.addEventListener("touchstart", function(event) {
+        event.preventDefault();
+        output += `touchstart on document - cancelable: ${event.cancelable} defaultPrevented: ${event.defaultPrevented} <br>`;
+    }, { "passive": false });
+
+    document.addEventListener("touchmove", function(event) {
+        event.preventDefault();
+        output += `touchmove on document - cancelable: ${event.cancelable} defaultPrevented: ${event.defaultPrevented} <br>`;
+    }, { "passive": false });
+
+    document.addEventListener("touchend", function(event) {
+        event.preventDefault();
+        output += `touchend on document - cancelable: ${event.cancelable} defaultPrevented: ${event.defaultPrevented} <br>`;
+    }, { "passive": false });
+
+    document.documentElement.addEventListener("touchstart", function(event) {
+        event.preventDefault();
+        output += `touchstart on documentElement - cancelable: ${event.cancelable} defaultPrevented: ${event.defaultPrevented} <br>`;
+    }, { "passive": false });
+
+    document.documentElement.addEventListener("touchmove", function(event) {
+        event.preventDefault();
+        output += `touchmove on documentElement - cancelable: ${event.cancelable} defaultPrevented: ${event.defaultPrevented} <br>`;
+    }, { "passive": false });
+
+    document.documentElement.addEventListener("touchend", function(event) {
+        event.preventDefault();
+        output += `touchend on documentElement - cancelable: ${event.cancelable} defaultPrevented: ${event.defaultPrevented} <br>`;
+    }, { "passive": false });
+
+    let body = document.querySelector("body");
+
+    body.addEventListener("touchstart", function(event) {
+        event.preventDefault();
+        output += `touchstart on body - cancelable: ${event.cancelable} defaultPrevented: ${event.defaultPrevented} <br>`;
+    }, { "passive": false });
+
+    body.addEventListener("touchmove", function(event) {
+        event.preventDefault();
+        output += `touchmove on body - cancelable: ${event.cancelable} defaultPrevented: ${event.defaultPrevented} <br>`;
+    }, { "passive": false });
+
+    body.addEventListener("touchend", function(event) {
+        event.preventDefault();
+        output += `touchend on body - cancelable: ${event.cancelable} defaultPrevented: ${event.defaultPrevented} <br>`;
+    }, { "passive": false });
+
+    if (testRunner.runUIScript) {
+        testRunner.runUIScript(getUIScript(), function(result) {
+            output += result;
+            document.getElementById("output").innerHTML = output;
+            testRunner.notifyDone();
+        });
+    }
+}
+
+window.addEventListener('load', runTest, false);
+</script>
+<body style="height: 500vh">
+<div id=output>
+This test requires UIScriptController to run.
+</div>
+</body>
Property changes on: trunk/LayoutTests/fast/events/touch/ios/passive-by-default-overridden-on-document-and-window.html
___________________________________________________________________

Added: svn:eol-style

+native \ No newline at end of property

Added: svn:keywords

+Date Revision \ No newline at end of property

Added: svn:mime-type

+text/html \ No newline at end of property

Modified: trunk/LayoutTests/fast/events/touch/ios/tap-with-active-listener-on-window.html (221091 => 221092)


--- trunk/LayoutTests/fast/events/touch/ios/tap-with-active-listener-on-window.html	2017-08-23 19:10:00 UTC (rev 221091)
+++ trunk/LayoutTests/fast/events/touch/ios/tap-with-active-listener-on-window.html	2017-08-23 19:22:28 UTC (rev 221092)
@@ -24,7 +24,7 @@
             window.addEventListener('touchstart', function(event) {
                 output += 'Received' + (event.cancelable ? ' cancelable' : '') + ' event ' + event.type + ' at ' + event.touches[0].clientX + ', ' + event.touches[0].clientY + '<br>';
                 event.preventDefault();
-            });
+            }, { passive: false });
 
             window.addEventListener('touchend', function(event) {
                 output += 'Received' + (event.cancelable ? ' cancelable' : '') + ' event ' + event.type + '<br>';

Modified: trunk/LayoutTests/fast/events/touch/ios/touch-event-regions/document.html (221091 => 221092)


--- trunk/LayoutTests/fast/events/touch/ios/touch-event-regions/document.html	2017-08-23 19:10:00 UTC (rev 221091)
+++ trunk/LayoutTests/fast/events/touch/ios/touch-event-regions/document.html	2017-08-23 19:22:28 UTC (rev 221092)
@@ -13,7 +13,7 @@
 </head>
 <body>
     <script>
-        document.addEventListener('touchstart', function() { });
+        document.addEventListener('touchstart', function() { }, { passive: false });
     </script>
 </body>
 </html>

Modified: trunk/Source/WebCore/ChangeLog (221091 => 221092)


--- trunk/Source/WebCore/ChangeLog	2017-08-23 19:10:00 UTC (rev 221091)
+++ trunk/Source/WebCore/ChangeLog	2017-08-23 19:22:28 UTC (rev 221092)
@@ -1,3 +1,42 @@
+2017-08-22  Dean Jackson  <[email protected]>
+
+        Default passive touch event listeners on the root
+        https://bugs.webkit.org/show_bug.cgi?id=175346
+        <rdar://problem/33164597>
+
+        Reviewed by Sam Weinig.
+
+        Make any touchstart or touchmove event listeners passive by default
+        if they are on the document, window, body or document element targets.
+        This follows the "intervention" first implemented by Chrome/Blink:
+
+        https://github.com/WICG/interventions/issues/35
+        https://docs.google.com/document/d/1II7oSIpd8pK91V5kEM3tDLKcIj398jOJn8Niqy6_loI/edit
+        https://github.com/whatwg/dom/issues/365
+
+        If the event listener explicitly defines "passive" to false in their
+        options dictionary, then they'll still get a non-passive listener.
+
+        NOTE: Any fallout from this bug should be collected in:
+        https://bugs.webkit.org/show_bug.cgi?id=175869
+        Please do not revert this change just because a site is broken. We'll
+        gather the issues and see if we can evangelise or detect via code.
+
+        Tests: fast/events/touch/ios/passive-by-default-on-document-and-window.html
+               fast/events/touch/ios/passive-by-default-overridden-on-document-and-window.html
+
+        * dom/EventNames.h:
+        (WebCore::EventNames::isTouchScrollBlockingEventType const): Added this helper
+        to identify the types of touches we want to check for.
+        * dom/EventTarget.cpp:
+        (WebCore::EventTarget::addEventListener): Check for the event being one of the touch-types
+        that we care about, and the target being one of the Node/Window types we care about. If
+        so, tell the event listener to be passive.
+        * dom/EventTarget.h: Use an optional for the passive member.
+        (WebCore::EventTarget::AddEventListenerOptions::AddEventListenerOptions):
+        * dom/EventTarget.idl: Change "passive" to not have a default value, so we
+        can detect if it was explicitly set to false.
+
 2017-08-23  Tim Horton  <[email protected]>
 
         Try to fix the WinCairo build after r221068

Modified: trunk/Source/WebCore/dom/EventNames.h (221091 => 221092)


--- trunk/Source/WebCore/dom/EventNames.h	2017-08-23 19:10:00 UTC (rev 221091)
+++ trunk/Source/WebCore/dom/EventNames.h	2017-08-23 19:22:28 UTC (rev 221092)
@@ -324,6 +324,7 @@
     bool isWheelEventType(const AtomicString& eventType) const;
     bool isGestureEventType(const AtomicString& eventType) const;
     bool isTouchEventType(const AtomicString& eventType) const;
+    bool isTouchScrollBlockingEventType(const AtomicString& eventType) const;
 #if ENABLE(GAMEPAD)
     bool isGamepadEventType(const AtomicString& eventType) const;
 #endif
@@ -350,6 +351,12 @@
     return eventType == gesturestartEvent || eventType == gesturechangeEvent || eventType == gestureendEvent;
 }
 
+inline bool EventNames::isTouchScrollBlockingEventType(const AtomicString& eventType) const
+{
+    return eventType == touchstartEvent
+        || eventType == touchmoveEvent;
+}
+
 inline bool EventNames::isTouchEventType(const AtomicString& eventType) const
 {
     return eventType == touchstartEvent

Modified: trunk/Source/WebCore/dom/EventTarget.cpp (221091 => 221092)


--- trunk/Source/WebCore/dom/EventTarget.cpp	2017-08-23 19:10:00 UTC (rev 221091)
+++ trunk/Source/WebCore/dom/EventTarget.cpp	2017-08-23 19:22:28 UTC (rev 221092)
@@ -34,6 +34,7 @@
 
 #include "DOMWrapperWorld.h"
 #include "EventNames.h"
+#include "HTMLBodyElement.h"
 #include "InspectorInstrumentation.h"
 #include "JSEventListener.h"
 #include "NoEventDispatchAssertion.h"
@@ -68,9 +69,20 @@
 
 bool EventTarget::addEventListener(const AtomicString& eventType, Ref<EventListener>&& listener, const AddEventListenerOptions& options)
 {
+    auto passive = options.passive;
+
+    if (!passive.has_value() && eventNames().isTouchScrollBlockingEventType(eventType)) {
+        if (toDOMWindow())
+            passive = true;
+        else if (auto* node = toNode()) {
+            if (node->isDocumentNode() || node->document().documentElement() == node || node->document().body() == node)
+                passive = true;
+        }
+    }
+
     bool listenerCreatedFromScript = listener->type() == EventListener::JSEventListenerType && !listener->wasCreatedFromMarkup();
 
-    if (!ensureEventTargetData().eventListenerMap.add(eventType, WTFMove(listener), { options.capture, options.passive, options.once }))
+    if (!ensureEventTargetData().eventListenerMap.add(eventType, WTFMove(listener), { options.capture, passive.value_or(false), options.once }))
         return false;
 
     if (listenerCreatedFromScript)

Modified: trunk/Source/WebCore/dom/EventTarget.h (221091 => 221092)


--- trunk/Source/WebCore/dom/EventTarget.h	2017-08-23 19:10:00 UTC (rev 221091)
+++ trunk/Source/WebCore/dom/EventTarget.h	2017-08-23 19:22:28 UTC (rev 221092)
@@ -81,13 +81,13 @@
     };
 
     struct AddEventListenerOptions : ListenerOptions {
-        AddEventListenerOptions(bool capture = false, bool passive = false, bool _once_ = false)
+        AddEventListenerOptions(bool capture = false, std::optional<bool> passive = std::nullopt, bool _once_ = false)
             : ListenerOptions(capture)
             , passive(passive)
             , once(once)
         { }
 
-        bool passive;
+        std::optional<bool> passive;
         bool once;
     };
 

Modified: trunk/Source/WebCore/dom/EventTarget.idl (221091 => 221092)


--- trunk/Source/WebCore/dom/EventTarget.idl	2017-08-23 19:10:00 UTC (rev 221091)
+++ trunk/Source/WebCore/dom/EventTarget.idl	2017-08-23 19:22:28 UTC (rev 221092)
@@ -36,6 +36,6 @@
 };
 
 dictionary AddEventListenerOptions : EventListenerOptions {
-    boolean passive = false;
+    boolean passive;
     boolean _once_ = false;
 };
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to