Title: [213161] trunk
Revision
213161
Author
mra...@apple.com
Date
2017-02-28 11:42:20 -0800 (Tue, 28 Feb 2017)

Log Message

Media: notify clients when autoplayed media ends without being paused
https://bugs.webkit.org/show_bug.cgi?id=168852

Reviewed by Alex Christensen.

Source/WebCore:

Added API tests.

* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::setReadyState):
 Set state accordingly if we autoplayed or if playback was prevented.
(WebCore::HTMLMediaElement::play):
 Update state if playback was prevented.
(WebCore::HTMLMediaElement::playInternal):
 Update state if playback began without user interaction.
(WebCore::HTMLMediaElement::pauseInternal):
 Update state.
(WebCore::HTMLMediaElement::mediaPlayerTimeChanged):
 If playback ends and it began without user interaction, send a DidPlayMediaWithoutInterference event.
(WebCore::HTMLMediaElement::stopWithoutDestroyingMediaPlayer): Ditto.
* html/HTMLMediaElement.h:
* page/AutoplayEvent.h:

Source/WebKit2:

* UIProcess/API/C/WKPageUIClient.h:

Tools:

* TestWebKitAPI/Tests/WebKit2/js-play-with-controls.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/WebsitePolicies.mm:
(TEST): Added.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (213160 => 213161)


--- trunk/Source/WebCore/ChangeLog	2017-02-28 19:37:04 UTC (rev 213160)
+++ trunk/Source/WebCore/ChangeLog	2017-02-28 19:42:20 UTC (rev 213161)
@@ -1,3 +1,27 @@
+2017-02-24  Matt Rajca  <mra...@apple.com>
+
+        Media: notify clients when autoplayed media ends without being paused
+        https://bugs.webkit.org/show_bug.cgi?id=168852
+
+        Reviewed by Alex Christensen.
+
+        Added API tests.
+
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::setReadyState):
+         Set state accordingly if we autoplayed or if playback was prevented.
+        (WebCore::HTMLMediaElement::play):
+         Update state if playback was prevented.
+        (WebCore::HTMLMediaElement::playInternal):
+         Update state if playback began without user interaction.
+        (WebCore::HTMLMediaElement::pauseInternal):
+         Update state.
+        (WebCore::HTMLMediaElement::mediaPlayerTimeChanged):
+         If playback ends and it began without user interaction, send a DidPlayMediaWithoutInterference event.
+        (WebCore::HTMLMediaElement::stopWithoutDestroyingMediaPlayer): Ditto.
+        * html/HTMLMediaElement.h:
+        * page/AutoplayEvent.h:
+
 2017-02-27  Dave Hyatt  <hy...@apple.com>
 
         Update flexbox to Blink's tip of tree

Modified: trunk/Source/WebCore/html/HTMLMediaElement.cpp (213160 => 213161)


--- trunk/Source/WebCore/html/HTMLMediaElement.cpp	2017-02-28 19:37:04 UTC (rev 213160)
+++ trunk/Source/WebCore/html/HTMLMediaElement.cpp	2017-02-28 19:42:20 UTC (rev 213161)
@@ -2416,11 +2416,12 @@
         if (success) {
             m_paused = false;
             invalidateCachedTime();
+            m_playbackWithoutUserGesture = PlaybackWithoutUserGesture::Started;
             m_playbackStartedTime = currentMediaTime().toDouble();
             scheduleEvent(eventNames().playEvent);
             scheduleNotifyAboutPlaying();
         } else if (success.value() == MediaPlaybackDenialReason::UserGestureRequired) {
-            m_preventedFromPlayingWithoutUserGesture = true;
+            m_playbackWithoutUserGesture = PlaybackWithoutUserGesture::Prevented;
 
             if (Page* page = document().page())
                 page->chrome().client().handleAutoplayEvent(AutoplayEvent::DidPreventMediaFromPlaying);
@@ -3104,7 +3105,7 @@
     auto success = m_mediaSession->playbackPermitted(*this);
     if (!success) {
         if (success.value() == MediaPlaybackDenialReason::UserGestureRequired) {
-            m_preventedFromPlayingWithoutUserGesture = true;
+            m_playbackWithoutUserGesture = PlaybackWithoutUserGesture::Prevented;
 
             if (Page* page = document().page())
                 page->chrome().client().handleAutoplayEvent(AutoplayEvent::DidPreventMediaFromPlaying);
@@ -3136,7 +3137,7 @@
     auto success = m_mediaSession->playbackPermitted(*this);
     if (!success) {
         if (success.value() == MediaPlaybackDenialReason::UserGestureRequired) {
-            m_preventedFromPlayingWithoutUserGesture = true;
+            m_playbackWithoutUserGesture = PlaybackWithoutUserGesture::Prevented;
 
             if (Page* page = document().page())
                 page->chrome().client().handleAutoplayEvent(AutoplayEvent::DidPreventMediaFromPlaying);
@@ -3207,11 +3208,14 @@
     } else if (m_readyState >= HAVE_FUTURE_DATA)
         scheduleResolvePendingPlayPromises();
 
-    if (ScriptController::processingUserGestureForMedia() && m_preventedFromPlayingWithoutUserGesture) {
-        if (Page* page = document().page())
-            page->chrome().client().handleAutoplayEvent(AutoplayEvent::DidPlayMediaPreventedFromPlaying);
-        m_preventedFromPlayingWithoutUserGesture = false;
-    }
+    if (ScriptController::processingUserGestureForMedia()) {
+        if (m_playbackWithoutUserGesture == PlaybackWithoutUserGesture::Prevented) {
+            if (Page* page = document().page())
+                page->chrome().client().handleAutoplayEvent(AutoplayEvent::DidPlayMediaPreventedFromPlaying);
+            m_playbackWithoutUserGesture = PlaybackWithoutUserGesture::None;
+        }
+    } else
+        m_playbackWithoutUserGesture = PlaybackWithoutUserGesture::Started;
 
     m_autoplaying = false;
     updatePlayState();
@@ -3252,6 +3256,7 @@
     }
 
     m_autoplaying = false;
+    m_playbackWithoutUserGesture = PlaybackWithoutUserGesture::None;
 
     if (!m_paused) {
         m_paused = true;
@@ -4401,6 +4406,12 @@
                 scheduleEvent(eventNames().endedEvent);
                 if (!wasSeeking)
                     addBehaviorRestrictionsOnEndIfNecessary();
+
+                if (m_playbackWithoutUserGesture == PlaybackWithoutUserGesture::Started) {
+                    if (Page* page = document().page())
+                        page->chrome().client().handleAutoplayEvent(AutoplayEvent::DidEndMediaPlaybackWithoutUserInterference);
+                }
+                m_playbackWithoutUserGesture = PlaybackWithoutUserGesture::None;
             }
             // If the media element has a current media controller, then report the controller state
             // for the media element's current media controller.
@@ -5157,6 +5168,12 @@
     setPausedInternal(true);
     m_mediaSession->clientWillPausePlayback();
 
+    if (m_playbackWithoutUserGesture == PlaybackWithoutUserGesture::Started) {
+        if (Page* page = document().page())
+            page->chrome().client().handleAutoplayEvent(AutoplayEvent::DidEndMediaPlaybackWithoutUserInterference);
+    }
+    m_playbackWithoutUserGesture = PlaybackWithoutUserGesture::None;
+
     userCancelledLoad();
 
     updateRenderer();

Modified: trunk/Source/WebCore/html/HTMLMediaElement.h (213160 => 213161)


--- trunk/Source/WebCore/html/HTMLMediaElement.h	2017-02-28 19:37:04 UTC (rev 213160)
+++ trunk/Source/WebCore/html/HTMLMediaElement.h	2017-02-28 19:42:20 UTC (rev 213161)
@@ -974,7 +974,6 @@
     bool m_creatingControls : 1;
     bool m_receivedLayoutSizeChanged : 1;
     bool m_hasEverNotifiedAboutPlaying : 1;
-    bool m_preventedFromPlayingWithoutUserGesture : 1;
 
     bool m_hasEverHadAudio : 1;
     bool m_hasEverHadVideo : 1;
@@ -991,6 +990,9 @@
     bool m_haveVisibleTextTrack : 1;
     bool m_processingPreferenceChange : 1;
 
+    enum class PlaybackWithoutUserGesture { None, Started, Prevented };
+    PlaybackWithoutUserGesture m_playbackWithoutUserGesture;
+
     String m_subtitleTrackLanguage;
     MediaTime m_lastTextTrackUpdateTime { -1, 1 };
 

Modified: trunk/Source/WebCore/page/AutoplayEvent.h (213160 => 213161)


--- trunk/Source/WebCore/page/AutoplayEvent.h	2017-02-28 19:37:04 UTC (rev 213160)
+++ trunk/Source/WebCore/page/AutoplayEvent.h	2017-02-28 19:42:20 UTC (rev 213161)
@@ -30,6 +30,7 @@
 enum class AutoplayEvent {
     DidPreventMediaFromPlaying,
     DidPlayMediaPreventedFromPlaying,
+    DidEndMediaPlaybackWithoutUserInterference,
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebKit2/ChangeLog (213160 => 213161)


--- trunk/Source/WebKit2/ChangeLog	2017-02-28 19:37:04 UTC (rev 213160)
+++ trunk/Source/WebKit2/ChangeLog	2017-02-28 19:42:20 UTC (rev 213161)
@@ -1,3 +1,12 @@
+2017-02-24  Matt Rajca  <mra...@apple.com>
+
+        Media: notify clients when autoplayed media ends without being paused
+        https://bugs.webkit.org/show_bug.cgi?id=168852
+
+        Reviewed by Alex Christensen.
+
+        * UIProcess/API/C/WKPageUIClient.h:
+
 2017-02-28  Csaba Osztrogonác  <o...@webkit.org>
 
         Remove EFL leftover from WebPageProxy.messages.in

Modified: trunk/Source/WebKit2/UIProcess/API/C/WKPageUIClient.h (213160 => 213161)


--- trunk/Source/WebKit2/UIProcess/API/C/WKPageUIClient.h	2017-02-28 19:37:04 UTC (rev 213160)
+++ trunk/Source/WebKit2/UIProcess/API/C/WKPageUIClient.h	2017-02-28 19:42:20 UTC (rev 213161)
@@ -51,6 +51,7 @@
 enum {
     kWKAutoplayEventDidPreventFromAutoplaying,
     kWKAutoplayEventDidPlayMediaPreventedFromAutoplaying,
+    kWKAutoplayEventDidEndMediaPlaybackWithoutUserInterference,
 };
 typedef uint32_t WKAutoplayEvent;
 

Modified: trunk/Tools/ChangeLog (213160 => 213161)


--- trunk/Tools/ChangeLog	2017-02-28 19:37:04 UTC (rev 213160)
+++ trunk/Tools/ChangeLog	2017-02-28 19:42:20 UTC (rev 213161)
@@ -1,3 +1,14 @@
+2017-02-24  Matt Rajca  <mra...@apple.com>
+
+        Media: notify clients when autoplayed media ends without being paused
+        https://bugs.webkit.org/show_bug.cgi?id=168852
+
+        Reviewed by Alex Christensen.
+
+        * TestWebKitAPI/Tests/WebKit2/js-play-with-controls.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/WebsitePolicies.mm:
+        (TEST): Added.
+
 2017-02-28  Jonathan Bedard  <jbed...@apple.com>
 
         webkitpy: jsc-ews should run when Makefiles and build scripts are changed

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2/js-play-with-controls.html (213160 => 213161)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit2/js-play-with-controls.html	2017-02-28 19:37:04 UTC (rev 213160)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2/js-play-with-controls.html	2017-02-28 19:42:20 UTC (rev 213161)
@@ -11,10 +11,22 @@
             function play() {
                 document.getElementById("video").play();
             }
+
+            function beganPlaying() {
+                try {
+                    window.webkit.messageHandlers.testHandler.postMessage("playing");
+                } catch(e) { }
+            }
+
+            function endedPlaying() {
+                try {
+                    window.webkit.messageHandlers.testHandler.postMessage("ended");
+                } catch(e) { }
+            }
         </script>
     </head>
     <body _onload_="pageLoaded()">
         <button _onclick_="play()">Play</button>
-        <video id="video" src="" />
+        <video id="video" _onplaying_=beganPlaying() _onended_=endedPlaying() src="" />
     </body>
 </html>

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/WebsitePolicies.mm (213160 => 213161)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/WebsitePolicies.mm	2017-02-28 19:37:04 UTC (rev 213160)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/WebsitePolicies.mm	2017-02-28 19:42:20 UTC (rev 213161)
@@ -316,6 +316,41 @@
     [webView waitForMessage:@"played"];
     ASSERT_TRUE(receivedAutoplayEvent == std::nullopt);
 }
+
+TEST(WebKit2, WebsitePoliciesPlayingWithoutInterference)
+{
+    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 336, 276) configuration:configuration.get()]);
+
+    auto delegate = adoptNS([[AutoplayPoliciesDelegate alloc] init]);
+    [delegate setAutoplayPolicyForURL:^(NSURL *) {
+        return _WKWebsiteAutoplayPolicyAllow;
+    }];
+    [webView setNavigationDelegate:delegate.get()];
+
+    WKPageUIClientV9 uiClient;
+    memset(&uiClient, 0, sizeof(uiClient));
+
+    uiClient.base.version = 9;
+    uiClient.handleAutoplayEvent = handleAutoplayEvent;
+
+    WKPageSetPageUIClient([webView _pageForTesting], &uiClient.base);
+
+    receivedAutoplayEvent = std::nullopt;
+    NSURLRequest *jsPlayRequest = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"js-play-with-controls" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
+    [webView loadRequest:jsPlayRequest];
+    [webView waitForMessage:@"playing"];
+
+    ASSERT_TRUE(receivedAutoplayEvent == std::nullopt);
+
+    [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"about:blank"]]];
+    runUntilReceivesAutoplayEvent(kWKAutoplayEventDidEndMediaPlaybackWithoutUserInterference);
+
+    receivedAutoplayEvent = std::nullopt;
+    [webView loadRequest:jsPlayRequest];
+    [webView waitForMessage:@"ended"];
+    runUntilReceivesAutoplayEvent(kWKAutoplayEventDidEndMediaPlaybackWithoutUserInterference);
+}
 #endif
 
 #endif
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to