Make DidPlayMediaPreventedFromPlaying autoplay event more generic.
https://bugs.webkit.org/show_bug.cgi?id=193128
rdar://34554231
Reviewed by Jer Noble.
Today, the "DidPlayMediaPreventedFromPlaying" autoplay event is only sent for
media prevented from autoplaying. It could be generalized to a "DidPlayMediaWithUserGesture"
event along with a flag that indicates whether or not autoplay was actually prevented.
Source/WebCore:
Moreover, we can include a flag that indicates whether the media element in question
is main content. Clients will then know in more cases when media was played with a user
gesture, whether or not it has audio, as well as its main content status. While the main
content heuristics may not be perfect, they covered the top 20 video-centric websites that
this was tested with and are meant to be used by clients for data evaluation purposes.
As part of this, the PlaybackWithoutUserGesture enum was renamed to AutoplayEventPlaybackState
since it now also applies to cases where there is a user gesture. The
`m_playbackWithoutUserGestureStartedTime` member variable was also removed in favor of
`playbackStartedTime` which also covers all the cases we care about.
Tests: existing API tests were updated to reflect the new names. New API tests
were added for the new case in which the "DidPlayMediaWithUserGesture" event is sent.
* html/HTMLMediaElement.cpp:
(WebCore::convertEnumerationToString): Update to new enum cases.
(WebCore::HTMLMediaElement::setReadyState): Ditto.
(WebCore::HTMLMediaElement::play): Ditto.
(WebCore::HTMLMediaElement::playInternal): Also cover the case where
playback was not prevented but there was a user gesture.
(WebCore::HTMLMediaElement::pauseInternal): Use new name.
(WebCore::HTMLMediaElement::setVolume): Use new name.
(WebCore::HTMLMediaElement::playbackProgressTimerFired): Dispatch the
DidPlayMediaWithUserGesture event when playback was started with a user
gesture as well.
(WebCore::HTMLMediaElement::mediaPlayerDidAddAudioTrack): Use new name.
(WebCore::HTMLMediaElement::mediaPlayerTimeChanged): Ditto.
(WebCore::HTMLMediaElement::mediaPlayerCharacteristicChanged): Ditto.
(WebCore::HTMLMediaElement::stopWithoutDestroyingMediaPlayer): Ditto.
(WebCore::HTMLMediaElement::handleAutoplayEvent): Pass along new media state.
(WebCore::HTMLMediaElement::userDidInterfereWithAutoplay): Use new name.
(WebCore::HTMLMediaElement::setAutoplayEventPlaybackState): Stop setting
m_playbackWithoutUserGestureStartedTime in favor of using playbackStartedTime.
(WebCore::HTMLMediaElement::updateShouldPlay): Use new name.
(WebCore::HTMLMediaElement::setPlaybackWithoutUserGesture): Renamed.
* html/HTMLMediaElement.h:
(WTF::LogArgument<WebCore::HTMLMediaElement::AutoplayEventPlaybackState>::toString): Renamed from...
(WTF::LogArgument<WebCore::HTMLMediaElement::PlaybackWithoutUserGesture>::toString):
* html/MediaElementSession.cpp:
(WebCore::MediaElementSession::isMainContentForPurposesOfAutoplayEvents const): Don't
do the hit testing check for the purposes of autoplay events. It seems to fail on the
basic Vimeo player due to overlapping divs.
(WebCore::isElementMainContentForPurposesOfAutoplay):
(WebCore::MediaElementSession::updateIsMainContent const): Keep the existing behavior
here of hit testing.
(WebCore::isMainContentForPurposesOfAutoplay): Renamed.
* html/MediaElementSession.h:
* page/AutoplayEvent.h:
Source/WebKit:
Tests: existing API tests were updated to reflect the new names. New API tests
were added for the new case in which the "DidPlayMediaWithUserGesture" event is sent.
* Shared/WebCoreArgumentCoders.h: Take into account new flags.
* UIProcess/API/C/WKPage.cpp: Ditto.
(WKPageSetPageUIClient):
* UIProcess/API/C/WKPageUIClient.h: Ditto.
* UIProcess/API/Cocoa/WKUIDelegatePrivate.h: Ditto.
* UIProcess/Cocoa/UIDelegate.mm: Ditto.
(WebKit::toWKAutoplayEventFlags):
(WebKit::toWKAutoplayEvent):
Tools:
Tests: existing API tests were updated to reflect the new names. New API tests
were added for the new case in which the "DidPlayMediaWithUserGesture" event is sent.
* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKit/long-test.mp4: Added.
* TestWebKitAPI/Tests/WebKitCocoa/WebsitePolicies.mm:
(TEST):
* TestWebKitAPI/Tests/WebKitCocoa/audio-with-play-button.html: Added.
* TestWebKitAPI/Tests/WebKitCocoa/video-with-play-button.html: Added.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@239625 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index ebd77ad..74ab373 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,63 @@
+2019-01-03 Matt Rajca <mrajca@apple.com>
+
+ Make DidPlayMediaPreventedFromPlaying autoplay event more generic.
+ https://bugs.webkit.org/show_bug.cgi?id=193128
+ rdar://34554231
+
+ Reviewed by Jer Noble.
+
+ Today, the "DidPlayMediaPreventedFromPlaying" autoplay event is only sent for
+ media prevented from autoplaying. It could be generalized to a "DidPlayMediaWithUserGesture"
+ event along with a flag that indicates whether or not autoplay was actually prevented.
+ Moreover, we can include a flag that indicates whether the media element in question
+ is main content. Clients will then know in more cases when media was played with a user
+ gesture, whether or not it has audio, as well as its main content status. While the main
+ content heuristics may not be perfect, they covered the top 20 video-centric websites that
+ this was tested with and are meant to be used by clients for data evaluation purposes.
+
+ As part of this, the PlaybackWithoutUserGesture enum was renamed to AutoplayEventPlaybackState
+ since it now also applies to cases where there is a user gesture. The
+ `m_playbackWithoutUserGestureStartedTime` member variable was also removed in favor of
+ `playbackStartedTime` which also covers all the cases we care about.
+
+ Tests: existing API tests were updated to reflect the new names. New API tests
+ were added for the new case in which the "DidPlayMediaWithUserGesture" event is sent.
+
+ * html/HTMLMediaElement.cpp:
+ (WebCore::convertEnumerationToString): Update to new enum cases.
+ (WebCore::HTMLMediaElement::setReadyState): Ditto.
+ (WebCore::HTMLMediaElement::play): Ditto.
+ (WebCore::HTMLMediaElement::playInternal): Also cover the case where
+ playback was not prevented but there was a user gesture.
+ (WebCore::HTMLMediaElement::pauseInternal): Use new name.
+ (WebCore::HTMLMediaElement::setVolume): Use new name.
+ (WebCore::HTMLMediaElement::playbackProgressTimerFired): Dispatch the
+ DidPlayMediaWithUserGesture event when playback was started with a user
+ gesture as well.
+ (WebCore::HTMLMediaElement::mediaPlayerDidAddAudioTrack): Use new name.
+ (WebCore::HTMLMediaElement::mediaPlayerTimeChanged): Ditto.
+ (WebCore::HTMLMediaElement::mediaPlayerCharacteristicChanged): Ditto.
+ (WebCore::HTMLMediaElement::stopWithoutDestroyingMediaPlayer): Ditto.
+ (WebCore::HTMLMediaElement::handleAutoplayEvent): Pass along new media state.
+ (WebCore::HTMLMediaElement::userDidInterfereWithAutoplay): Use new name.
+ (WebCore::HTMLMediaElement::setAutoplayEventPlaybackState): Stop setting
+ m_playbackWithoutUserGestureStartedTime in favor of using playbackStartedTime.
+ (WebCore::HTMLMediaElement::updateShouldPlay): Use new name.
+ (WebCore::HTMLMediaElement::setPlaybackWithoutUserGesture): Renamed.
+ * html/HTMLMediaElement.h:
+ (WTF::LogArgument<WebCore::HTMLMediaElement::AutoplayEventPlaybackState>::toString): Renamed from...
+ (WTF::LogArgument<WebCore::HTMLMediaElement::PlaybackWithoutUserGesture>::toString):
+ * html/MediaElementSession.cpp:
+ (WebCore::MediaElementSession::isMainContentForPurposesOfAutoplayEvents const): Don't
+ do the hit testing check for the purposes of autoplay events. It seems to fail on the
+ basic Vimeo player due to overlapping divs.
+ (WebCore::isElementMainContentForPurposesOfAutoplay):
+ (WebCore::MediaElementSession::updateIsMainContent const): Keep the existing behavior
+ here of hit testing.
+ (WebCore::isMainContentForPurposesOfAutoplay): Renamed.
+ * html/MediaElementSession.h:
+ * page/AutoplayEvent.h:
+
2019-01-04 Youenn Fablet <youenn@apple.com>
Crash in WebCore::ServiceWorkerGlobalScope
diff --git a/Source/WebCore/html/HTMLMediaElement.cpp b/Source/WebCore/html/HTMLMediaElement.cpp
index 9fd9d4f..1513e25 100644
--- a/Source/WebCore/html/HTMLMediaElement.cpp
+++ b/Source/WebCore/html/HTMLMediaElement.cpp
@@ -253,17 +253,18 @@
return values[static_cast<size_t>(enumerationValue)];
}
-String convertEnumerationToString(HTMLMediaElement::PlaybackWithoutUserGesture enumerationValue)
+String convertEnumerationToString(HTMLMediaElement::AutoplayEventPlaybackState enumerationValue)
{
static const NeverDestroyed<String> values[] = {
MAKE_STATIC_STRING_IMPL("None"),
- MAKE_STATIC_STRING_IMPL("Started"),
- MAKE_STATIC_STRING_IMPL("Prevented"),
- MAKE_STATIC_STRING_IMPL("NETWORK_NO_SOURCE"),
+ MAKE_STATIC_STRING_IMPL("PreventedAutoplay"),
+ MAKE_STATIC_STRING_IMPL("StartedWithUserGesture"),
+ MAKE_STATIC_STRING_IMPL("StartedWithoutUserGesture"),
};
- static_assert(static_cast<size_t>(HTMLMediaElement::PlaybackWithoutUserGesture::None) == 0, "PlaybackWithoutUserGesture::None is not 0 as expected");
- static_assert(static_cast<size_t>(HTMLMediaElement::PlaybackWithoutUserGesture::Started) == 1, "PlaybackWithoutUserGesture::Started is not 1 as expected");
- static_assert(static_cast<size_t>(HTMLMediaElement::PlaybackWithoutUserGesture::Prevented) == 2, "PlaybackWithoutUserGesture::Prevented is not 2 as expected");
+ static_assert(static_cast<size_t>(HTMLMediaElement::AutoplayEventPlaybackState::None) == 0, "AutoplayEventPlaybackState::None is not 0 as expected");
+ static_assert(static_cast<size_t>(HTMLMediaElement::AutoplayEventPlaybackState::PreventedAutoplay) == 1, "AutoplayEventPlaybackState::PreventedAutoplay is not 1 as expected");
+ static_assert(static_cast<size_t>(HTMLMediaElement::AutoplayEventPlaybackState::StartedWithUserGesture) == 2, "AutoplayEventPlaybackState::StartedWithUserGesture is not 2 as expected");
+ static_assert(static_cast<size_t>(HTMLMediaElement::AutoplayEventPlaybackState::StartedWithoutUserGesture) == 3, "AutoplayEventPlaybackState::StartedWithoutUserGesture is not 3 as expected");
ASSERT(static_cast<size_t>(enumerationValue) < WTF_ARRAY_LENGTH(values));
return values[static_cast<size_t>(enumerationValue)];
}
@@ -2524,12 +2525,12 @@
if (success) {
m_paused = false;
invalidateCachedTime();
- setPlaybackWithoutUserGesture(PlaybackWithoutUserGesture::Started);
+ setAutoplayEventPlaybackState(AutoplayEventPlaybackState::StartedWithoutUserGesture);
m_playbackStartedTime = currentMediaTime().toDouble();
scheduleEvent(eventNames().playEvent);
} else if (success.value() == MediaPlaybackDenialReason::UserGestureRequired) {
ALWAYS_LOG(LOGIDENTIFIER, "Autoplay blocked, user gesture required");
- setPlaybackWithoutUserGesture(PlaybackWithoutUserGesture::Prevented);
+ setAutoplayEventPlaybackState(AutoplayEventPlaybackState::PreventedAutoplay);
}
shouldUpdateDisplayState = true;
@@ -2543,7 +2544,7 @@
ALWAYS_LOG(LOGIDENTIFIER, "Autoplay blocked, user gesture required");
pauseInternal();
- setPlaybackWithoutUserGesture(PlaybackWithoutUserGesture::Prevented);
+ setAutoplayEventPlaybackState(AutoplayEventPlaybackState::PreventedAutoplay);
}
if (shouldUpdateDisplayState) {
@@ -3473,7 +3474,7 @@
auto success = m_mediaSession->playbackPermitted();
if (!success) {
if (success.value() == MediaPlaybackDenialReason::UserGestureRequired)
- setPlaybackWithoutUserGesture(PlaybackWithoutUserGesture::Prevented);
+ setAutoplayEventPlaybackState(AutoplayEventPlaybackState::PreventedAutoplay);
promise.reject(NotAllowedError);
return;
}
@@ -3497,7 +3498,7 @@
auto success = m_mediaSession->playbackPermitted();
if (!success) {
if (success.value() == MediaPlaybackDenialReason::UserGestureRequired)
- setPlaybackWithoutUserGesture(PlaybackWithoutUserGesture::Prevented);
+ setAutoplayEventPlaybackState(AutoplayEventPlaybackState::PreventedAutoplay);
return;
}
if (processingUserGestureForMedia())
@@ -3572,12 +3573,13 @@
scheduleResolvePendingPlayPromises();
if (processingUserGestureForMedia()) {
- if (m_playbackWithoutUserGesture == PlaybackWithoutUserGesture::Prevented) {
- handleAutoplayEvent(AutoplayEvent::DidPlayMediaPreventedFromPlaying);
- setPlaybackWithoutUserGesture(PlaybackWithoutUserGesture::None);
- }
+ if (m_autoplayEventPlaybackState == AutoplayEventPlaybackState::PreventedAutoplay) {
+ handleAutoplayEvent(AutoplayEvent::DidPlayMediaWithUserGesture);
+ setAutoplayEventPlaybackState(AutoplayEventPlaybackState::None);
+ } else
+ setAutoplayEventPlaybackState(AutoplayEventPlaybackState::StartedWithUserGesture);
} else
- setPlaybackWithoutUserGesture(PlaybackWithoutUserGesture::Started);
+ setAutoplayEventPlaybackState(AutoplayEventPlaybackState::StartedWithoutUserGesture);
m_autoplaying = false;
updatePlayState();
@@ -3635,7 +3637,7 @@
if (processingUserGestureForMedia())
userDidInterfereWithAutoplay();
- setPlaybackWithoutUserGesture(PlaybackWithoutUserGesture::None);
+ setAutoplayEventPlaybackState(AutoplayEventPlaybackState::None);
if (!m_paused) {
m_paused = true;
@@ -3716,7 +3718,7 @@
if (isPlaying() && !m_mediaSession->playbackPermitted()) {
pauseInternal();
- setPlaybackWithoutUserGesture(PlaybackWithoutUserGesture::Prevented);
+ setAutoplayEventPlaybackState(AutoplayEventPlaybackState::PreventedAutoplay);
}
#endif
return { };
@@ -3926,9 +3928,10 @@
m_mediaSource->monitorSourceBuffers();
#endif
- if (!seeking() && m_playbackWithoutUserGesture == PlaybackWithoutUserGesture::Started && currentTime() - m_playbackWithoutUserGestureStartedTime->toDouble() > AutoplayInterferenceTimeThreshold) {
- handleAutoplayEvent(AutoplayEvent::DidAutoplayMediaPastThresholdWithoutUserInterference);
- setPlaybackWithoutUserGesture(PlaybackWithoutUserGesture::None);
+ bool playbackStarted = m_autoplayEventPlaybackState == AutoplayEventPlaybackState::StartedWithUserGesture || m_autoplayEventPlaybackState == AutoplayEventPlaybackState::StartedWithoutUserGesture;
+ if (!seeking() && playbackStarted && currentTime() - playbackStartedTime() > AutoplayInterferenceTimeThreshold) {
+ handleAutoplayEvent(m_autoplayEventPlaybackState == AutoplayEventPlaybackState::StartedWithoutUserGesture ? AutoplayEvent::DidAutoplayMediaPastThresholdWithoutUserInterference : AutoplayEvent::DidPlayMediaWithUserGesture);
+ setAutoplayEventPlaybackState(AutoplayEventPlaybackState::None);
}
}
@@ -3982,7 +3985,7 @@
{
if (isPlaying() && !m_mediaSession->playbackPermitted()) {
pauseInternal();
- setPlaybackWithoutUserGesture(PlaybackWithoutUserGesture::Prevented);
+ setAutoplayEventPlaybackState(AutoplayEventPlaybackState::PreventedAutoplay);
}
addAudioTrack(AudioTrack::create(*this, track));
@@ -4825,7 +4828,7 @@
scheduleEvent(eventNames().endedEvent);
if (!wasSeeking)
addBehaviorRestrictionsOnEndIfNecessary();
- setPlaybackWithoutUserGesture(PlaybackWithoutUserGesture::None);
+ setAutoplayEventPlaybackState(AutoplayEventPlaybackState::None);
}
setPlaying(false);
// If the media element has a current media controller, then report the controller state
@@ -5153,7 +5156,7 @@
if (!paused() && !m_mediaSession->playbackPermitted()) {
pauseInternal();
- setPlaybackWithoutUserGesture(PlaybackWithoutUserGesture::Prevented);
+ setAutoplayEventPlaybackState(AutoplayEventPlaybackState::PreventedAutoplay);
}
#if ENABLE(MEDIA_SESSION)
@@ -5655,7 +5658,7 @@
setPausedInternal(true);
m_mediaSession->stopSession();
- setPlaybackWithoutUserGesture(PlaybackWithoutUserGesture::None);
+ setAutoplayEventPlaybackState(AutoplayEventPlaybackState::None);
userCancelledLoad();
@@ -7753,44 +7756,45 @@
{
if (Page* page = document().page()) {
bool hasAudio = this->hasAudio() && !muted() && volume();
- ALWAYS_LOG(LOGIDENTIFIER, "hasAudio = ", hasAudio);
- page->chrome().client().handleAutoplayEvent(event, hasAudio ? AutoplayEventFlags::HasAudio : OptionSet<AutoplayEventFlags>());
+ bool wasPlaybackPrevented = m_autoplayEventPlaybackState == AutoplayEventPlaybackState::PreventedAutoplay;
+ bool hasMainContent = m_mediaSession && m_mediaSession->isMainContentForPurposesOfAutoplayEvents();
+ ALWAYS_LOG(LOGIDENTIFIER, "hasAudio = ", hasAudio, " wasPlaybackPrevented = ", wasPlaybackPrevented, " hasMainContent = ", hasMainContent);
+
+ OptionSet<AutoplayEventFlags> flags;
+ if (hasAudio)
+ flags.add(AutoplayEventFlags::HasAudio);
+ if (wasPlaybackPrevented)
+ flags.add(AutoplayEventFlags::PlaybackWasPrevented);
+ if (hasMainContent)
+ flags.add(AutoplayEventFlags::MediaIsMainContent);
+
+ page->chrome().client().handleAutoplayEvent(event, flags);
}
}
void HTMLMediaElement::userDidInterfereWithAutoplay()
{
- if (m_playbackWithoutUserGesture != PlaybackWithoutUserGesture::Started)
+ if (m_autoplayEventPlaybackState != AutoplayEventPlaybackState::StartedWithoutUserGesture)
return;
// Only consider interference in the first 10 seconds of automatic playback.
- if (currentTime() - m_playbackWithoutUserGestureStartedTime->toDouble() > AutoplayInterferenceTimeThreshold)
+ if (currentTime() - playbackStartedTime() > AutoplayInterferenceTimeThreshold)
return;
ALWAYS_LOG(LOGIDENTIFIER);
handleAutoplayEvent(AutoplayEvent::UserDidInterfereWithPlayback);
- setPlaybackWithoutUserGesture(PlaybackWithoutUserGesture::None);
+ setAutoplayEventPlaybackState(AutoplayEventPlaybackState::None);
}
-void HTMLMediaElement::setPlaybackWithoutUserGesture(PlaybackWithoutUserGesture reason)
+void HTMLMediaElement::setAutoplayEventPlaybackState(AutoplayEventPlaybackState reason)
{
ALWAYS_LOG(LOGIDENTIFIER, reason);
- m_playbackWithoutUserGesture = reason;
+ m_autoplayEventPlaybackState = reason;
- switch (reason) {
- case PlaybackWithoutUserGesture::Started:
- m_playbackWithoutUserGestureStartedTime = currentMediaTime();
- break;
- case PlaybackWithoutUserGesture::None:
- m_playbackWithoutUserGestureStartedTime = WTF::nullopt;
- break;
- case PlaybackWithoutUserGesture::Prevented:
- m_playbackWithoutUserGestureStartedTime = WTF::nullopt;
-
+ if (reason == AutoplayEventPlaybackState::PreventedAutoplay) {
dispatchPlayPauseEventsIfNeedsQuirks();
handleAutoplayEvent(AutoplayEvent::DidPreventMediaFromPlaying);
- break;
}
}
@@ -7975,7 +7979,7 @@
{
if (!paused() && !m_mediaSession->playbackPermitted()) {
pauseInternal();
- setPlaybackWithoutUserGesture(PlaybackWithoutUserGesture::Prevented);
+ setAutoplayEventPlaybackState(AutoplayEventPlaybackState::PreventedAutoplay);
} else if (canTransitionFromAutoplayToPlay())
play();
}
diff --git a/Source/WebCore/html/HTMLMediaElement.h b/Source/WebCore/html/HTMLMediaElement.h
index 118fd4f..6d08748 100644
--- a/Source/WebCore/html/HTMLMediaElement.h
+++ b/Source/WebCore/html/HTMLMediaElement.h
@@ -571,7 +571,7 @@
WEBCORE_EXPORT void didBecomeFullscreenElement() override;
WEBCORE_EXPORT void willExitFullscreen();
- enum class PlaybackWithoutUserGesture { None, Started, Prevented };
+ enum class AutoplayEventPlaybackState { None, PreventedAutoplay, StartedWithUserGesture, StartedWithoutUserGesture };
protected:
HTMLMediaElement(const QualifiedName&, Document&, bool createdByParser);
@@ -822,7 +822,7 @@
void dispatchPlayPauseEventsIfNeedsQuirks();
SuccessOr<MediaPlaybackDenialReason> canTransitionFromAutoplayToPlay() const;
- void setPlaybackWithoutUserGesture(PlaybackWithoutUserGesture);
+ void setAutoplayEventPlaybackState(AutoplayEventPlaybackState);
void userDidInterfereWithAutoplay();
void handleAutoplayEvent(AutoplayEvent);
@@ -1117,8 +1117,7 @@
bool m_haveVisibleTextTrack : 1;
bool m_processingPreferenceChange : 1;
- PlaybackWithoutUserGesture m_playbackWithoutUserGesture { PlaybackWithoutUserGesture::None };
- Optional<MediaTime> m_playbackWithoutUserGestureStartedTime;
+ AutoplayEventPlaybackState m_autoplayEventPlaybackState { AutoplayEventPlaybackState::None };
String m_subtitleTrackLanguage;
MediaTime m_lastTextTrackUpdateTime { -1, 1 };
@@ -1197,15 +1196,15 @@
bool m_playingOnSecondScreen { false };
};
-String convertEnumerationToString(HTMLMediaElement::PlaybackWithoutUserGesture);
+String convertEnumerationToString(HTMLMediaElement::AutoplayEventPlaybackState);
} // namespace WebCore
namespace WTF {
template <>
-struct LogArgument<WebCore::HTMLMediaElement::PlaybackWithoutUserGesture> {
- static String toString(const WebCore::HTMLMediaElement::PlaybackWithoutUserGesture reason)
+struct LogArgument<WebCore::HTMLMediaElement::AutoplayEventPlaybackState> {
+ static String toString(const WebCore::HTMLMediaElement::AutoplayEventPlaybackState reason)
{
return convertEnumerationToString(reason);
}
diff --git a/Source/WebCore/html/MediaElementSession.cpp b/Source/WebCore/html/MediaElementSession.cpp
index 0aba2d2..71b66c0 100644
--- a/Source/WebCore/html/MediaElementSession.cpp
+++ b/Source/WebCore/html/MediaElementSession.cpp
@@ -61,6 +61,7 @@
static bool isElementRectMostlyInMainFrame(const HTMLMediaElement&);
static bool isElementLargeEnoughForMainContent(const HTMLMediaElement&, MediaSessionMainContentPurpose);
+static bool isElementMainContentForPurposesOfAutoplay(const HTMLMediaElement&, bool shouldHitTestMainFrame);
#if !RELEASE_LOG_DISABLED
static String restrictionNames(MediaElementSession::BehaviorRestrictions restriction)
@@ -518,6 +519,11 @@
return isElementLargeEnoughForMainContent(m_element, purpose);
}
+bool MediaElementSession::isMainContentForPurposesOfAutoplayEvents() const
+{
+ return isElementMainContentForPurposesOfAutoplay(m_element, false);
+}
+
MonotonicTime MediaElementSession::mostRecentUserInteractionTime() const
{
return m_mostRecentUserInteractionTime;
@@ -797,7 +803,7 @@
}
#endif
-static bool isMainContentForPurposesOfAutoplay(const HTMLMediaElement& element)
+static bool isElementMainContentForPurposesOfAutoplay(const HTMLMediaElement& element, bool shouldHitTestMainFrame)
{
Document& document = element.document();
if (!document.hasLivingRenderTree() || document.activeDOMObjectsAreStopped() || element.isSuspended() || !element.hasAudio() || !element.hasVideo())
@@ -827,6 +833,9 @@
if (!mainFrame.view() || !mainFrame.view()->renderView())
return false;
+ if (!shouldHitTestMainFrame)
+ return true;
+
RenderView& mainRenderView = *mainFrame.view()->renderView();
// Hit test the area of the main frame where the element appears, to determine if the element is being obscured.
@@ -930,7 +939,7 @@
return false;
bool wasMainContent = m_isMainContent;
- m_isMainContent = isMainContentForPurposesOfAutoplay(m_element);
+ m_isMainContent = isElementMainContentForPurposesOfAutoplay(m_element, true);
if (m_isMainContent != wasMainContent)
m_element.updateShouldPlay();
diff --git a/Source/WebCore/html/MediaElementSession.h b/Source/WebCore/html/MediaElementSession.h
index ba0222b..597ba27 100644
--- a/Source/WebCore/html/MediaElementSession.h
+++ b/Source/WebCore/html/MediaElementSession.h
@@ -141,6 +141,7 @@
enum class PlaybackControlsPurpose { ControlsManager, NowPlaying };
bool canShowControlsManager(PlaybackControlsPurpose) const;
bool isLargeEnoughForMainContent(MediaSessionMainContentPurpose) const;
+ bool isMainContentForPurposesOfAutoplayEvents() const;
MonotonicTime mostRecentUserInteractionTime() const;
bool allowsPlaybackControlsForAutoplayingAudio() const;
diff --git a/Source/WebCore/page/AutoplayEvent.h b/Source/WebCore/page/AutoplayEvent.h
index c44c3e9..1682a74 100644
--- a/Source/WebCore/page/AutoplayEvent.h
+++ b/Source/WebCore/page/AutoplayEvent.h
@@ -29,13 +29,15 @@
enum class AutoplayEvent : uint8_t {
DidPreventMediaFromPlaying,
- DidPlayMediaPreventedFromPlaying,
+ DidPlayMediaWithUserGesture,
DidAutoplayMediaPastThresholdWithoutUserInterference,
UserDidInterfereWithPlayback,
};
enum class AutoplayEventFlags {
HasAudio = 1 << 0,
+ PlaybackWasPrevented = 1 << 1,
+ MediaIsMainContent = 1 << 2,
};
} // namespace WebCore
diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog
index d606105..58e5ba2 100644
--- a/Source/WebKit/ChangeLog
+++ b/Source/WebKit/ChangeLog
@@ -1,3 +1,27 @@
+2019-01-03 Matt Rajca <mrajca@apple.com>
+
+ Make DidPlayMediaPreventedFromPlaying autoplay event more generic.
+ https://bugs.webkit.org/show_bug.cgi?id=193128
+ rdar://34554231
+
+ Reviewed by Jer Noble.
+
+ Today, the "DidPlayMediaPreventedFromPlaying" autoplay event is only sent for
+ media prevented from autoplaying. It could be generalized to a "DidPlayMediaWithUserGesture"
+ event along with a flag that indicates whether or not autoplay was actually prevented.
+
+ Tests: existing API tests were updated to reflect the new names. New API tests
+ were added for the new case in which the "DidPlayMediaWithUserGesture" event is sent.
+
+ * Shared/WebCoreArgumentCoders.h: Take into account new flags.
+ * UIProcess/API/C/WKPage.cpp: Ditto.
+ (WKPageSetPageUIClient):
+ * UIProcess/API/C/WKPageUIClient.h: Ditto.
+ * UIProcess/API/Cocoa/WKUIDelegatePrivate.h: Ditto.
+ * UIProcess/Cocoa/UIDelegate.mm: Ditto.
+ (WebKit::toWKAutoplayEventFlags):
+ (WebKit::toWKAutoplayEvent):
+
2019-01-04 Fujii Hironori <Hironori.Fujii@sony.com>
[curl] Move cookiePersistentStorageFile from NetworkProcessCreationParameters to NetworkSessionCreationParameters
diff --git a/Source/WebKit/Shared/WebCoreArgumentCoders.h b/Source/WebKit/Shared/WebCoreArgumentCoders.h
index 66387a6..573aa75 100644
--- a/Source/WebKit/Shared/WebCoreArgumentCoders.h
+++ b/Source/WebKit/Shared/WebCoreArgumentCoders.h
@@ -760,7 +760,7 @@
using values = EnumValues<
WebCore::AutoplayEvent,
WebCore::AutoplayEvent::DidPreventMediaFromPlaying,
- WebCore::AutoplayEvent::DidPlayMediaPreventedFromPlaying,
+ WebCore::AutoplayEvent::DidPlayMediaWithUserGesture,
WebCore::AutoplayEvent::DidAutoplayMediaPastThresholdWithoutUserInterference,
WebCore::AutoplayEvent::UserDidInterfereWithPlayback
>;
diff --git a/Source/WebKit/UIProcess/API/C/WKPage.cpp b/Source/WebKit/UIProcess/API/C/WKPage.cpp
index ec561dd..63d51b1 100644
--- a/Source/WebKit/UIProcess/API/C/WKPage.cpp
+++ b/Source/WebKit/UIProcess/API/C/WKPage.cpp
@@ -2018,6 +2018,10 @@
WKAutoplayEventFlags wkFlags = kWKAutoplayEventFlagsNone;
if (flags.contains(WebCore::AutoplayEventFlags::HasAudio))
wkFlags |= kWKAutoplayEventFlagsHasAudio;
+ if (flags.contains(WebCore::AutoplayEventFlags::PlaybackWasPrevented))
+ wkFlags |= kWKAutoplayEventFlagsPlaybackWasPrevented;
+ if (flags.contains(WebCore::AutoplayEventFlags::MediaIsMainContent))
+ wkFlags |= kWKAutoplayEventFlagsMediaIsMainContent;
return wkFlags;
}
@@ -2027,8 +2031,8 @@
switch (event) {
case WebCore::AutoplayEvent::DidAutoplayMediaPastThresholdWithoutUserInterference:
return kWKAutoplayEventDidAutoplayMediaPastThresholdWithoutUserInterference;
- case WebCore::AutoplayEvent::DidPlayMediaPreventedFromPlaying:
- return kWKAutoplayEventDidPlayMediaPreventedFromAutoplaying;
+ case WebCore::AutoplayEvent::DidPlayMediaWithUserGesture:
+ return kWKAutoplayEventDidPlayMediaWithUserGesture;
case WebCore::AutoplayEvent::DidPreventMediaFromPlaying:
return kWKAutoplayEventDidPreventFromAutoplaying;
case WebCore::AutoplayEvent::UserDidInterfereWithPlayback:
diff --git a/Source/WebKit/UIProcess/API/C/WKPageUIClient.h b/Source/WebKit/UIProcess/API/C/WKPageUIClient.h
index 4d62bb3..5e5973f 100644
--- a/Source/WebKit/UIProcess/API/C/WKPageUIClient.h
+++ b/Source/WebKit/UIProcess/API/C/WKPageUIClient.h
@@ -49,7 +49,7 @@
enum {
kWKAutoplayEventDidPreventFromAutoplaying,
- kWKAutoplayEventDidPlayMediaPreventedFromAutoplaying,
+ kWKAutoplayEventDidPlayMediaWithUserGesture,
kWKAutoplayEventDidAutoplayMediaPastThresholdWithoutUserInterference,
kWKAutoplayEventUserDidInterfereWithPlayback,
};
@@ -58,6 +58,8 @@
enum {
kWKAutoplayEventFlagsNone = 0,
kWKAutoplayEventFlagsHasAudio = 1 << 0,
+ kWKAutoplayEventFlagsPlaybackWasPrevented = 1 << 1,
+ kWKAutoplayEventFlagsMediaIsMainContent = 1 << 2,
};
typedef uint32_t WKAutoplayEventFlags;
diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegatePrivate.h b/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegatePrivate.h
index 46c9517..cd9a54e 100644
--- a/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegatePrivate.h
+++ b/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegatePrivate.h
@@ -49,7 +49,7 @@
#else
typedef NS_ENUM(NSInteger, _WKAutoplayEvent) {
_WKAutoplayEventDidPreventFromAutoplaying,
- _WKAutoplayEventDidPlayMediaPreventedFromAutoplaying,
+ _WKAutoplayEventDidPlayMediaWithUserGesture,
_WKAutoplayEventDidAutoplayMediaPastThresholdWithoutUserInterference,
_WKAutoplayEventUserDidInterfereWithPlayback,
} WK_API_AVAILABLE(macosx(10.13.4));
@@ -68,6 +68,8 @@
typedef NS_OPTIONS(NSUInteger, _WKAutoplayEventFlags) {
_WKAutoplayEventFlagsNone = 0,
_WKAutoplayEventFlagsHasAudio = 1 << 0,
+ _WKAutoplayEventFlagsPlaybackWasPrevented = 1 << 1,
+ _WKAutoplayEventFlagsMediaIsMainContent = 1 << 2,
} WK_API_AVAILABLE(macosx(10.13.4));
#endif
diff --git a/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm b/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm
index cf138d6..c16853f 100644
--- a/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm
+++ b/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm
@@ -717,6 +717,10 @@
_WKAutoplayEventFlags wkFlags = _WKAutoplayEventFlagsNone;
if (flags.contains(WebCore::AutoplayEventFlags::HasAudio))
wkFlags |= _WKAutoplayEventFlagsHasAudio;
+ if (flags.contains(WebCore::AutoplayEventFlags::PlaybackWasPrevented))
+ wkFlags |= _WKAutoplayEventFlagsPlaybackWasPrevented;
+ if (flags.contains(WebCore::AutoplayEventFlags::MediaIsMainContent))
+ wkFlags |= _WKAutoplayEventFlagsMediaIsMainContent;
return wkFlags;
}
@@ -726,15 +730,15 @@
switch (event) {
case WebCore::AutoplayEvent::DidPreventMediaFromPlaying:
return _WKAutoplayEventDidPreventFromAutoplaying;
- case WebCore::AutoplayEvent::DidPlayMediaPreventedFromPlaying:
- return _WKAutoplayEventDidPlayMediaPreventedFromAutoplaying;
+ case WebCore::AutoplayEvent::DidPlayMediaWithUserGesture:
+ return _WKAutoplayEventDidPlayMediaWithUserGesture;
case WebCore::AutoplayEvent::DidAutoplayMediaPastThresholdWithoutUserInterference:
return _WKAutoplayEventDidAutoplayMediaPastThresholdWithoutUserInterference;
case WebCore::AutoplayEvent::UserDidInterfereWithPlayback:
return _WKAutoplayEventUserDidInterfereWithPlayback;
}
ASSERT_NOT_REACHED();
- return _WKAutoplayEventDidPlayMediaPreventedFromAutoplaying;
+ return _WKAutoplayEventDidPlayMediaWithUserGesture;
}
void UIDelegate::UIClient::toolbarsAreVisible(WebPageProxy&, Function<void(bool)>&& completionHandler)
diff --git a/Tools/ChangeLog b/Tools/ChangeLog
index bfdc5f0..1fe5210 100644
--- a/Tools/ChangeLog
+++ b/Tools/ChangeLog
@@ -1,3 +1,25 @@
+2019-01-03 Matt Rajca <mrajca@apple.com>
+
+ Make DidPlayMediaPreventedFromPlaying autoplay event more generic.
+ https://bugs.webkit.org/show_bug.cgi?id=193128
+ rdar://34554231
+
+ Reviewed by Jer Noble.
+
+ Today, the "DidPlayMediaPreventedFromPlaying" autoplay event is only sent for
+ media prevented from autoplaying. It could be generalized to a "DidPlayMediaWithUserGesture"
+ event along with a flag that indicates whether or not autoplay was actually prevented.
+
+ Tests: existing API tests were updated to reflect the new names. New API tests
+ were added for the new case in which the "DidPlayMediaWithUserGesture" event is sent.
+
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/Tests/WebKit/long-test.mp4: Added.
+ * TestWebKitAPI/Tests/WebKitCocoa/WebsitePolicies.mm:
+ (TEST):
+ * TestWebKitAPI/Tests/WebKitCocoa/audio-with-play-button.html: Added.
+ * TestWebKitAPI/Tests/WebKitCocoa/video-with-play-button.html: Added.
+
2019-01-04 Chris Dumez <cdumez@apple.com>
[PSON] Calling history.back() from inside the load event handler prevents process-swapping
diff --git a/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj b/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
index bcdd2cf..2272d8b 100644
--- a/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
+++ b/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
@@ -734,7 +734,10 @@
C9BF06EF1E9C132500595E3E /* autoplay-muted-with-controls.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = C9BF06EE1E9C130400595E3E /* autoplay-muted-with-controls.html */; };
C9C60E651E53A9DC006DA181 /* autoplay-check-frame.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = C9C60E631E53A9BA006DA181 /* autoplay-check-frame.html */; };
C9C60E661E53A9DC006DA181 /* autoplay-check-in-iframe.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = C9C60E641E53A9BA006DA181 /* autoplay-check-in-iframe.html */; };
+ C9C9A91B21DED28700FDE96E /* audio-with-play-button.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = C9C9A91A21DED24D00FDE96E /* audio-with-play-button.html */; };
+ C9C9A91D21DED7A000FDE96E /* video-with-play-button.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = C9C9A91C21DED79400FDE96E /* video-with-play-button.html */; };
C9E6DD351EA97D0800DD78AA /* FirstResponderSuppression.mm in Sources */ = {isa = PBXBuildFile; fileRef = C9E6DD311EA972D800DD78AA /* FirstResponderSuppression.mm */; };
+ C9E8EE7521DED94300797765 /* long-test.mp4 in Copy Resources */ = {isa = PBXBuildFile; fileRef = C9E8EE7421DED91E00797765 /* long-test.mp4 */; };
CA38459620AE17A900990D3B /* LocalStorageDatabaseTracker.mm in Sources */ = {isa = PBXBuildFile; fileRef = CA38459520AE012E00990D3B /* LocalStorageDatabaseTracker.mm */; };
CA5B94D22190C0F40059FE38 /* IndexedDBTempFileSize-1.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = CA5B94D02190C0E00059FE38 /* IndexedDBTempFileSize-1.html */; };
CA5B94D32190C0F40059FE38 /* IndexedDBTempFileSize-2.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = CA5B94D12190C0E00059FE38 /* IndexedDBTempFileSize-2.html */; };
@@ -975,6 +978,8 @@
dstPath = TestWebKitAPI.resources;
dstSubfolderSpec = 7;
files = (
+ C9C9A91D21DED7A000FDE96E /* video-with-play-button.html in Copy Resources */,
+ C9C9A91B21DED28700FDE96E /* audio-with-play-button.html in Copy Resources */,
55A817FF2181021A0004A39A /* 100x100-red.tga in Copy Resources */,
1A9E52C913E65EF4006917F5 /* 18-characters.html in Copy Resources */,
55A81800218102210004A39A /* 400x400-green.png in Copy Resources */,
@@ -1161,6 +1166,7 @@
46C519E71D3563FD00DAA51A /* LocalStorageNullEntries.localstorage in Copy Resources */,
46C519E81D3563FD00DAA51A /* LocalStorageNullEntries.localstorage-shm in Copy Resources */,
7A6A2C721DCCFB5200C0D085 /* LocalStorageQuirkEnabled.html in Copy Resources */,
+ C9E8EE7521DED94300797765 /* long-test.mp4 in Copy Resources */,
9361002914DC95A70061379D /* lots-of-iframes.html in Copy Resources */,
93AF4ED11506F130007FD57E /* lots-of-images.html in Copy Resources */,
2DD7D3AF178227B30026E1E3 /* lots-of-text-vertical-lr.html in Copy Resources */,
@@ -2012,7 +2018,10 @@
C9BF06EE1E9C130400595E3E /* autoplay-muted-with-controls.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "autoplay-muted-with-controls.html"; sourceTree = "<group>"; };
C9C60E631E53A9BA006DA181 /* autoplay-check-frame.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "autoplay-check-frame.html"; sourceTree = "<group>"; };
C9C60E641E53A9BA006DA181 /* autoplay-check-in-iframe.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "autoplay-check-in-iframe.html"; sourceTree = "<group>"; };
+ C9C9A91A21DED24D00FDE96E /* audio-with-play-button.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = "audio-with-play-button.html"; path = "Tests/WebKitCocoa/audio-with-play-button.html"; sourceTree = SOURCE_ROOT; };
+ C9C9A91C21DED79400FDE96E /* video-with-play-button.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = "video-with-play-button.html"; path = "Tests/WebKitCocoa/video-with-play-button.html"; sourceTree = SOURCE_ROOT; };
C9E6DD311EA972D800DD78AA /* FirstResponderSuppression.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FirstResponderSuppression.mm; sourceTree = "<group>"; };
+ C9E8EE7421DED91E00797765 /* long-test.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = "long-test.mp4"; sourceTree = "<group>"; };
CA38459520AE012E00990D3B /* LocalStorageDatabaseTracker.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = LocalStorageDatabaseTracker.mm; sourceTree = "<group>"; };
CA5B94D02190C0E00059FE38 /* IndexedDBTempFileSize-1.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "IndexedDBTempFileSize-1.html"; sourceTree = "<group>"; };
CA5B94D12190C0E00059FE38 /* IndexedDBTempFileSize-2.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "IndexedDBTempFileSize-2.html"; sourceTree = "<group>"; };
@@ -3230,6 +3239,7 @@
1C2B81851C89252300A5529F /* Ahem.ttf */,
93D3D19B17B1A7B000C7C415 /* all-content-in-one-iframe.html */,
F6B7BE9617469B7E008A3445 /* associate-form-controls.html */,
+ C9C9A91A21DED24D00FDE96E /* audio-with-play-button.html */,
76E182DE15475A8300F1FADD /* auto-submitting-form.html */,
C9C60E631E53A9BA006DA181 /* autoplay-check-frame.html */,
C9C60E641E53A9BA006DA181 /* autoplay-check-in-iframe.html */,
@@ -3266,6 +3276,7 @@
8361F1771E610B2100759B25 /* link-with-download-attribute-with-slashes.html */,
8349D3C31DB9724F004A9F65 /* link-with-download-attribute.html */,
378E647816326FDF00B6C676 /* link-with-title.html */,
+ C9E8EE7421DED91E00797765 /* long-test.mp4 */,
9361002814DC957B0061379D /* lots-of-iframes.html */,
93AF4ECF1506F123007FD57E /* lots-of-images.html */,
2DD7D3AE178227AC0026E1E3 /* lots-of-text-vertical-lr.html */,
@@ -3298,6 +3309,7 @@
524BBCA019E30C63002F1AF1 /* test.mp4 */,
7AE9E5081AE5AE8B00CF874B /* test.pdf */,
07CD32F72065B72A0064A4BE /* video.html */,
+ C9C9A91C21DED79400FDE96E /* video-with-play-button.html */,
1C2B81841C8924A200A5529F /* webfont.html */,
);
name = Resources;
diff --git a/Tools/TestWebKitAPI/Tests/WebKit/long-test.mp4 b/Tools/TestWebKitAPI/Tests/WebKit/long-test.mp4
new file mode 100644
index 0000000..74b3349
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit/long-test.mp4
Binary files differ
diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/WebsitePolicies.mm b/Tools/TestWebKitAPI/Tests/WebKitCocoa/WebsitePolicies.mm
index 708b072..f148b45 100644
--- a/Tools/TestWebKitAPI/Tests/WebKitCocoa/WebsitePolicies.mm
+++ b/Tools/TestWebKitAPI/Tests/WebKitCocoa/WebsitePolicies.mm
@@ -362,8 +362,9 @@
[webView mouseDownAtPoint:playButtonClickPoint simulatePressure:NO];
[webView mouseUpAtPoint:playButtonClickPoint];
- runUntilReceivesAutoplayEvent(kWKAutoplayEventDidPlayMediaPreventedFromAutoplaying);
+ runUntilReceivesAutoplayEvent(kWKAutoplayEventDidPlayMediaWithUserGesture);
ASSERT_TRUE(*receivedAutoplayEventFlags & kWKAutoplayEventFlagsHasAudio);
+ ASSERT_TRUE(*receivedAutoplayEventFlags & kWKAutoplayEventFlagsPlaybackWasPrevented);
receivedAutoplayEvent = WTF::nullopt;
[webView loadHTMLString:@"" baseURL:nil];
@@ -376,8 +377,9 @@
[webView mouseDownAtPoint:playButtonClickPoint simulatePressure:NO];
[webView mouseUpAtPoint:playButtonClickPoint];
- runUntilReceivesAutoplayEvent(kWKAutoplayEventDidPlayMediaPreventedFromAutoplaying);
+ runUntilReceivesAutoplayEvent(kWKAutoplayEventDidPlayMediaWithUserGesture);
ASSERT_TRUE(*receivedAutoplayEventFlags & kWKAutoplayEventFlagsHasAudio);
+ ASSERT_TRUE(*receivedAutoplayEventFlags & kWKAutoplayEventFlagsPlaybackWasPrevented);
receivedAutoplayEvent = WTF::nullopt;
[webView loadHTMLString:@"" baseURL:nil];
@@ -404,8 +406,48 @@
[webView mouseDownAtPoint:playButtonClickPoint simulatePressure:NO];
[webView mouseUpAtPoint:playButtonClickPoint];
- runUntilReceivesAutoplayEvent(kWKAutoplayEventDidPlayMediaPreventedFromAutoplaying);
+ runUntilReceivesAutoplayEvent(kWKAutoplayEventDidPlayMediaWithUserGesture);
ASSERT_TRUE(*receivedAutoplayEventFlags & kWKAutoplayEventFlagsHasAudio);
+ ASSERT_TRUE(*receivedAutoplayEventFlags & kWKAutoplayEventFlagsPlaybackWasPrevented);
+}
+
+TEST(WebKit, WebsitePoliciesPlayingWithUserGesture)
+{
+ auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+ auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+
+ auto delegate = adoptNS([[AutoplayPoliciesDelegate alloc] init]);
+ [delegate setAutoplayPolicyForURL:^(NSURL *) {
+ return _WKWebsiteAutoplayPolicyAllow;
+ }];
+ [webView setNavigationDelegate:delegate.get()];
+ [webView setUIDelegate:delegate.get()];
+
+ receivedAutoplayEvent = WTF::nullopt;
+
+ NSPoint playButtonClickPoint = NSMakePoint(20, 580);
+
+ NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"audio-with-play-button" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
+ [webView loadRequest:request];
+ [webView waitForMessage:@"loaded"];
+ [webView mouseDownAtPoint:playButtonClickPoint simulatePressure:NO];
+ [webView mouseUpAtPoint:playButtonClickPoint];
+
+ runUntilReceivesAutoplayEvent(kWKAutoplayEventDidPlayMediaWithUserGesture);
+ ASSERT_TRUE(*receivedAutoplayEventFlags & kWKAutoplayEventFlagsHasAudio);
+ ASSERT_FALSE(*receivedAutoplayEventFlags & kWKAutoplayEventFlagsMediaIsMainContent);
+
+ receivedAutoplayEvent = WTF::nullopt;
+
+ request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"video-with-play-button" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
+ [webView loadRequest:request];
+ [webView waitForMessage:@"loaded"];
+ [webView mouseDownAtPoint:playButtonClickPoint simulatePressure:NO];
+ [webView mouseUpAtPoint:playButtonClickPoint];
+
+ runUntilReceivesAutoplayEvent(kWKAutoplayEventDidPlayMediaWithUserGesture);
+ ASSERT_TRUE(*receivedAutoplayEventFlags & kWKAutoplayEventFlagsHasAudio);
+ ASSERT_TRUE(*receivedAutoplayEventFlags & kWKAutoplayEventFlagsMediaIsMainContent);
}
TEST(WebKit, WebsitePoliciesPlayingWithoutInterference)
diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/audio-with-play-button.html b/Tools/TestWebKitAPI/Tests/WebKitCocoa/audio-with-play-button.html
new file mode 100644
index 0000000..7f3ede5
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKitCocoa/audio-with-play-button.html
@@ -0,0 +1,28 @@
+<html>
+ <head>
+ <script>
+ function pageLoaded() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("loaded");
+ } catch(e) { }
+ }
+
+ function beganPlaying() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("played");
+ } catch(e) { }
+ }
+
+ function play() {
+ let audio = document.getElementById("audio");
+ audio.playbackRate = 5; // Speeds up the test.
+ audio.play();
+ }
+ </script>
+ </head>
+ <body onload="pageLoaded()">
+ <button onclick="play()">Play</button>
+ <br />
+ <audio controls id="audio" onplaying="beganPlaying()" src="silence-long.m4a" />
+ </body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/video-with-play-button.html b/Tools/TestWebKitAPI/Tests/WebKitCocoa/video-with-play-button.html
new file mode 100644
index 0000000..c0a1ab2
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKitCocoa/video-with-play-button.html
@@ -0,0 +1,28 @@
+<html>
+ <head>
+ <script>
+ function pageLoaded() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("loaded");
+ } catch(e) { }
+ }
+
+ function beganPlaying() {
+ try {
+ window.webkit.messageHandlers.testHandler.postMessage("played");
+ } catch(e) { }
+ }
+
+ function play() {
+ let video = document.getElementById("video");
+ video.playbackRate = 5; // Speeds up the test.
+ video.play();
+ }
+ </script>
+ </head>
+ <body onload="pageLoaded()">
+ <button onclick="play()">Play</button>
+ <br />
+ <video controls id="video" onplaying="beganPlaying()" src="long-test.mp4"></video>
+ </body>
+</html>