Title: [278515] trunk
Revision
278515
Author
[email protected]
Date
2021-06-04 17:57:43 -0700 (Fri, 04 Jun 2021)

Log Message

[iOS] Meaningful click heuristic should account for media state changes
https://bugs.webkit.org/show_bug.cgi?id=226655
rdar://78330664

Reviewed by Tim Horton and Devin Rousso.

Source/WebKit:

Teach the "meaningful click" heuristic about changes to media element state flags. See comments below for more
details.

Test: fast/events/ios/meaningful-click-when-playing-media.html

* WebProcess/WebCoreSupport/WebChromeClient.cpp:
(WebKit::WebChromeClient::isPlayingMediaDidChange):
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::isPlayingMediaDidChange):

Refactor some logic here so that the WebChromeClient calls into WebPage, which then sends an IPC message to the
UI process and additionally calls into a private method for platform-specific logic (see WebPageIOS.mm).

* WebProcess/WebPage/WebPage.h:

Replace `m_didHandleOrPreventMouseDownOrMouseUpEventDuringSyntheticClick` with another flag,
`m_currentSyntheticClickMayNotBeMeaningful`, that is initially set to `true` at the beginning of
`WebPage::completeSyntheticClick`, and consulted after the events have been dispatched to see if anything has
set it to `false` (currently, this includes only playing media state changes and handled click events by the
page). If the flag is set to `false`, we then consider the click to have been "meaningful", with respect to the
`-_webView:didNotHandleTapAsMeaningfulClickAtPoint:` UI delegate method.

(WebKit::WebPage::platformIsPlayingMediaDidChange):
* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::WebPage::completeSyntheticClick):
(WebKit::WebPage::didHandleOrPreventMouseDownOrMouseUpEvent):
(WebKit::WebPage::platformIsPlayingMediaDidChange):

Make these set `m_currentSyntheticClickMayNotBeMeaningful` to `false`.

LayoutTests:

Add a layout test to verify that tapping to play or pause a video triggers "meaningful" synthetic clicks.

* fast/events/ios/meaningful-click-when-playing-media-expected.txt: Added.
* fast/events/ios/meaningful-click-when-playing-media.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (278514 => 278515)


--- trunk/LayoutTests/ChangeLog	2021-06-05 00:24:16 UTC (rev 278514)
+++ trunk/LayoutTests/ChangeLog	2021-06-05 00:57:43 UTC (rev 278515)
@@ -1,3 +1,16 @@
+2021-06-04  Wenson Hsieh  <[email protected]>
+
+        [iOS] Meaningful click heuristic should account for media state changes
+        https://bugs.webkit.org/show_bug.cgi?id=226655
+        rdar://78330664
+
+        Reviewed by Tim Horton and Devin Rousso.
+
+        Add a layout test to verify that tapping to play or pause a video triggers "meaningful" synthetic clicks.
+
+        * fast/events/ios/meaningful-click-when-playing-media-expected.txt: Added.
+        * fast/events/ios/meaningful-click-when-playing-media.html: Added.
+
 2021-06-04  Devin Rousso  <[email protected]>
 
         Web Inspector: Uncaught Exception: undefined is not an object (evaluating 'InspectorBackend.Enum.Page.ResourceType')

Added: trunk/LayoutTests/fast/events/ios/meaningful-click-when-playing-media-expected.txt (0 => 278515)


--- trunk/LayoutTests/fast/events/ios/meaningful-click-when-playing-media-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/events/ios/meaningful-click-when-playing-media-expected.txt	2021-06-05 00:57:43 UTC (rev 278515)
@@ -0,0 +1,12 @@
+This test exercises the 'meaningful click' heuristic when playing or pausing a video, and requires WebKitTestRunner.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS didPlayVideo became true
+PASS didDispatchNonMeaningfulClickCallback is false
+PASS didPauseVideo became true
+PASS didDispatchNonMeaningfulClickCallback is false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/events/ios/meaningful-click-when-playing-media.html (0 => 278515)


--- trunk/LayoutTests/fast/events/ios/meaningful-click-when-playing-media.html	                        (rev 0)
+++ trunk/LayoutTests/fast/events/ios/meaningful-click-when-playing-media.html	2021-06-05 00:57:43 UTC (rev 278515)
@@ -0,0 +1,61 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true ] -->
+<html>
+<head>
+<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
+<style>
+body, html {
+    font-size: 18px;
+    font-family: system-ui;
+    width: 100%;
+    height: 100%;
+    margin: 0;
+}
+</style>
+<script src=""
+<script src=""
+<script>
+jsTestIsAsync = true;
+didPauseVideo = false;
+didPlayVideo = false;
+
+addEventListener("load", async () => {
+    description("This test exercises the 'meaningful click' heuristic when playing or pausing a video, and requires WebKitTestRunner.");
+    document.body.addEventListener("click", async () => {
+        const video = document.querySelector("video");
+        if (video.paused) {
+            await video.play();
+            didPlayVideo = true;
+        } else {
+            await video.pause();
+            didPauseVideo = true;
+        }
+    });
+
+    if (!window.testRunner)
+        return;
+
+    async function checkForNonMeaningfulClick(shouldPlay) {
+        didDispatchNonMeaningfulClickCallback = false;
+        testRunner.installDidNotHandleTapAsMeaningfulClickCallback(() => {
+            didDispatchNonMeaningfulClickCallback = true;
+        });
+
+        await UIHelper.activateElement(document.body);
+        await UIHelper.waitForDoubleTapDelay();
+        await new Promise(resolve => shouldBecomeEqual(shouldPlay ? "didPlayVideo" : "didPauseVideo", "true", resolve));
+        shouldBeFalse("didDispatchNonMeaningfulClickCallback");
+        testRunner.clearTestRunnerCallbacks();
+    }
+
+    await checkForNonMeaningfulClick(true);
+    await checkForNonMeaningfulClick(false);
+    finishJSTest();
+});
+</script>
+</head>
+<body>
+    <div id="description"></div>
+    <div id="console"></div>
+    <video loop src=""
+</body>
+</html>
\ No newline at end of file

Modified: trunk/Source/WebKit/ChangeLog (278514 => 278515)


--- trunk/Source/WebKit/ChangeLog	2021-06-05 00:24:16 UTC (rev 278514)
+++ trunk/Source/WebKit/ChangeLog	2021-06-05 00:57:43 UTC (rev 278515)
@@ -1,3 +1,41 @@
+2021-06-04  Wenson Hsieh  <[email protected]>
+
+        [iOS] Meaningful click heuristic should account for media state changes
+        https://bugs.webkit.org/show_bug.cgi?id=226655
+        rdar://78330664
+
+        Reviewed by Tim Horton and Devin Rousso.
+
+        Teach the "meaningful click" heuristic about changes to media element state flags. See comments below for more
+        details.
+
+        Test: fast/events/ios/meaningful-click-when-playing-media.html
+
+        * WebProcess/WebCoreSupport/WebChromeClient.cpp:
+        (WebKit::WebChromeClient::isPlayingMediaDidChange):
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::isPlayingMediaDidChange):
+
+        Refactor some logic here so that the WebChromeClient calls into WebPage, which then sends an IPC message to the
+        UI process and additionally calls into a private method for platform-specific logic (see WebPageIOS.mm).
+
+        * WebProcess/WebPage/WebPage.h:
+
+        Replace `m_didHandleOrPreventMouseDownOrMouseUpEventDuringSyntheticClick` with another flag,
+        `m_currentSyntheticClickMayNotBeMeaningful`, that is initially set to `true` at the beginning of
+        `WebPage::completeSyntheticClick`, and consulted after the events have been dispatched to see if anything has
+        set it to `false` (currently, this includes only playing media state changes and handled click events by the
+        page). If the flag is set to `false`, we then consider the click to have been "meaningful", with respect to the
+        `-_webView:didNotHandleTapAsMeaningfulClickAtPoint:` UI delegate method.
+
+        (WebKit::WebPage::platformIsPlayingMediaDidChange):
+        * WebProcess/WebPage/ios/WebPageIOS.mm:
+        (WebKit::WebPage::completeSyntheticClick):
+        (WebKit::WebPage::didHandleOrPreventMouseDownOrMouseUpEvent):
+        (WebKit::WebPage::platformIsPlayingMediaDidChange):
+
+        Make these set `m_currentSyntheticClickMayNotBeMeaningful` to `false`.
+
 2021-06-04  Ryosuke Niwa  <[email protected]>
 
         Store MediaPlayer using WeakPtr in MediaPlayerPrivateRemote

Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp (278514 => 278515)


--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp	2021-06-05 00:24:16 UTC (rev 278514)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp	2021-06-05 00:57:43 UTC (rev 278515)
@@ -1235,7 +1235,7 @@
 
 void WebChromeClient::isPlayingMediaDidChange(MediaProducer::MediaStateFlags state)
 {
-    m_page.send(Messages::WebPageProxy::IsPlayingMediaDidChange(state));
+    m_page.isPlayingMediaDidChange(state);
 }
 
 void WebChromeClient::handleAutoplayEvent(AutoplayEvent event, OptionSet<AutoplayEventFlags> flags)

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp (278514 => 278515)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2021-06-05 00:24:16 UTC (rev 278514)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2021-06-05 00:57:43 UTC (rev 278515)
@@ -7360,6 +7360,11 @@
     WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::SetCORSDisablingPatterns(m_identifier, m_corsDisablingPatterns), 0);
 }
 
+void WebPage::isPlayingMediaDidChange(WebCore::MediaProducer::MediaStateFlags state)
+{
+    platformIsPlayingMediaDidChange();
+    send(Messages::WebPageProxy::IsPlayingMediaDidChange(state));
+}
 
 #if ENABLE(MEDIA_USAGE)
 void WebPage::addMediaUsageManagerSession(MediaSessionIdentifier identifier, const String& bundleIdentifier, const URL& pageURL)

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.h (278514 => 278515)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.h	2021-06-05 00:24:16 UTC (rev 278514)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.h	2021-06-05 00:57:43 UTC (rev 278515)
@@ -1401,6 +1401,8 @@
     void removeMediaUsageManagerSession(WebCore::MediaSessionIdentifier);
 #endif
 
+    void isPlayingMediaDidChange(WebCore::MediaProducer::MediaStateFlags);
+
 #if ENABLE(IMAGE_EXTRACTION)
     void requestImageExtraction(WebCore::Element&, CompletionHandler<void(RefPtr<WebCore::Element>&&)>&&);
     void updateWithImageExtractionResult(WebCore::ImageExtractionResult&&, const WebCore::ElementContext&, const WebCore::FloatPoint& location, CompletionHandler<void(ImageExtractionUpdateResult)>&&);
@@ -1897,6 +1899,8 @@
     
     void consumeNetworkExtensionSandboxExtensions(const SandboxExtension::HandleArray&);
 
+    void platformIsPlayingMediaDidChange();
+
     WebCore::PageIdentifier m_identifier;
 
     std::unique_ptr<WebCore::Page> m_page;
@@ -2185,8 +2189,8 @@
     RefPtr<WebCore::Node> m_potentialTapNode;
     WebCore::FloatPoint m_potentialTapLocation;
     RefPtr<WebCore::SecurityOrigin> m_potentialTapSecurityOrigin;
-    bool m_didHandleOrPreventMouseDownOrMouseUpEventDuringSyntheticClick { false };
 
+    bool m_currentSyntheticClickMayNotBeMeaningful { true };
     bool m_hasReceivedVisibleContentRectsAfterDidCommitLoad { false };
     bool m_hasRestoredExposedContentRectAfterDidCommitLoad { false };
     bool m_scaleWasSetByUIProcess { false };
@@ -2358,6 +2362,7 @@
 inline bool WebPage::platformNeedsLayoutForEditorState(const WebCore::Frame&) const { return false; }
 inline void WebPage::didHandleOrPreventMouseDownOrMouseUpEvent() { }
 inline void WebPage::prepareToRunModalJavaScriptDialog() { }
+inline void WebPage::platformIsPlayingMediaDidChange() { }
 #endif
 
 } // namespace WebKit

Modified: trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm (278514 => 278515)


--- trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm	2021-06-05 00:24:16 UTC (rev 278514)
+++ trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm	2021-06-05 00:57:43 UTC (rev 278515)
@@ -874,7 +874,7 @@
     bool altKey = modifiers.contains(WebEvent::Modifier::AltKey);
     bool metaKey = modifiers.contains(WebEvent::Modifier::MetaKey);
 
-    m_didHandleOrPreventMouseDownOrMouseUpEventDuringSyntheticClick = false;
+    m_currentSyntheticClickMayNotBeMeaningful = true;
 
     tapWasHandled |= mainframe.eventHandler().handleMousePressEvent(PlatformMouseEvent(roundedAdjustedPoint, roundedAdjustedPoint, LeftButton, PlatformEvent::MousePressed, 1, shiftKey, ctrlKey, altKey, metaKey, WallTime::now(), WebCore::ForceAtClick, syntheticClickType, pointerId));
     if (m_isClosed)
@@ -903,7 +903,7 @@
         return;
 
     bool shouldDispatchDidNotHandleTapAsMeaningfulClickAtPoint = ([&] {
-        if (m_didHandleOrPreventMouseDownOrMouseUpEventDuringSyntheticClick)
+        if (!m_currentSyntheticClickMayNotBeMeaningful)
             return false;
 
         if (oldFocusedElement != newFocusedElement)
@@ -924,8 +924,6 @@
     if (!tapWasHandled || !nodeRespondingToClick.isElementNode())
         send(Messages::WebPageProxy::DidNotHandleTapAsClick(roundedIntPoint(location)));
 
-    m_didHandleOrPreventMouseDownOrMouseUpEventDuringSyntheticClick = false;
-    
     send(Messages::WebPageProxy::DidCompleteSyntheticClick());
 }
 
@@ -947,7 +945,7 @@
 
 void WebPage::didHandleOrPreventMouseDownOrMouseUpEvent()
 {
-    m_didHandleOrPreventMouseDownOrMouseUpEventDuringSyntheticClick = true;
+    m_currentSyntheticClickMayNotBeMeaningful = false;
 }
 
 void WebPage::handleDoubleTapForDoubleClickAtPoint(const IntPoint& point, OptionSet<WebEvent::Modifier> modifiers, TransactionID lastLayerTreeTransactionId)
@@ -4694,6 +4692,11 @@
         scheduleEditorStateUpdateForStartOrEndContainerNodeIfNeeded(endContainer.get());
 }
 
+void WebPage::platformIsPlayingMediaDidChange()
+{
+    m_currentSyntheticClickMayNotBeMeaningful = false;
+}
+
 } // namespace WebKit
 
 #undef RELEASE_LOG_IF_ALLOWED
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to