Diff
Modified: trunk/Source/WebCore/ChangeLog (205411 => 205412)
--- trunk/Source/WebCore/ChangeLog 2016-09-03 23:34:00 UTC (rev 205411)
+++ trunk/Source/WebCore/ChangeLog 2016-09-04 00:24:14 UTC (rev 205412)
@@ -1,3 +1,67 @@
+2016-09-03 Wenson Hsieh <[email protected]>
+
+ Refactor the heuristic for showing media controls to take all media sessions into account
+ https://bugs.webkit.org/show_bug.cgi?id=161503
+ <rdar://problem/28033783>
+
+ Reviewed by Darin Adler.
+
+ Currently, when selecting a media session to show playback controls for, we grab the first media session that
+ passes our heuristic. Using this method, we are unable to take additional factors into account, such as whether
+ another media session's element is scrolled in view, or if another media session has been interacted with more
+ recently. To address this, we make the following changes:
+
+ 1. Consider the list of all MediaElementSessions.
+
+ 2. Select only the MediaElementSessions capable of showing media controls and sort the list by a special
+ heuristic that takes visibility and time of last user interaction into account. The first element on
+ this list is the strongest candidate for main content.
+
+ 3. If this strongest candidate is visible in the viewport, or it is playing with audio, we return this
+ as the chosen candidate. Otherwise, we return this session only if no other non-candidate video could be
+ confused as the main content (i.e. the non-candidate video is not only visible in the viewport, but also
+ large enough to be considered main content).
+
+ Using this new method of determining the video to show controls for, we retain previous behavior for pages with
+ a single video. On pages with multiple videos, the above logic ensures that if the current controlled video is
+ paused, scrolled out of view, and then a new video is scrolled into view, we will either hide media controls to
+ avoid confusion if that video could be confused for main content (using the mechanism in step 3), or we
+ hook up the media controls to the new video if it satisfies main content (using the mechanism in step 2).
+
+ This patch also adds 6 new TestWebKitAPI unit tests.
+
+ * html/HTMLMediaElement.cpp:
+ (WebCore::mediaElementSessionInfoForSession):
+ (WebCore::preferMediaControlsForCandidateSessionOverOtherCandidateSession):
+ (WebCore::mediaSessionMayBeConfusedWithMainContent):
+ (WebCore::bestMediaSessionForShowingPlaybackControlsManager):
+ (WebCore::HTMLMediaElement::didAttachRenderers):
+ (WebCore::HTMLMediaElement::layoutSizeChanged):
+ (WebCore::HTMLMediaElement::isVisibleInViewportChanged):
+ (WebCore::HTMLMediaElement::resetPlaybackSessionState):
+ (WebCore::HTMLMediaElement::isVisibleInViewport):
+ (WebCore::HTMLMediaElement::updatePlaybackControlsManager):
+ * html/HTMLMediaElement.h:
+ * html/MediaElementSession.cpp:
+ (WebCore::MediaElementSession::removeBehaviorRestriction):
+ (WebCore::MediaElementSession::canShowControlsManager):
+ (WebCore::MediaElementSession::isLargeEnoughForMainContent):
+ (WebCore::MediaElementSession::mostRecentUserInteractionTime):
+ (WebCore::MediaElementSession::wantsToObserveViewportVisibilityForMediaControls):
+ (WebCore::MediaElementSession::wantsToObserveViewportVisibilityForAutoplay):
+ (WebCore::MediaElementSession::resetPlaybackSessionState):
+ (WebCore::MediaElementSession::canControlControlsManager): Deleted.
+ * html/MediaElementSession.h:
+ * platform/audio/PlatformMediaSession.h:
+ (WebCore::PlatformMediaSession::resetPlaybackSessionState):
+ (WebCore::PlatformMediaSession::canControlControlsManager): Deleted.
+ * platform/audio/PlatformMediaSessionManager.cpp:
+ (WebCore::PlatformMediaSessionManager::currentSessionsMatching):
+ (WebCore::PlatformMediaSessionManager::currentSessionMatching): Deleted.
+ * platform/audio/PlatformMediaSessionManager.h:
+ * platform/cocoa/WebPlaybackSessionModelMediaElement.mm:
+ (WebPlaybackSessionModelMediaElement::setMediaElement):
+
2016-09-03 Darin Adler <[email protected]>
Streamline DOMImplementation, and move it to our new DOM exception system
Modified: trunk/Source/WebCore/html/HTMLMediaElement.cpp (205411 => 205412)
--- trunk/Source/WebCore/html/HTMLMediaElement.cpp 2016-09-03 23:34:00 UTC (rev 205411)
+++ trunk/Source/WebCore/html/HTMLMediaElement.cpp 2016-09-04 00:24:14 UTC (rev 205412)
@@ -346,6 +346,79 @@
}
#endif
+struct MediaElementSessionInfo {
+ const MediaElementSession* session;
+
+ double timeOfLastUserInteraction;
+ bool canShowControlsManager : 1;
+ bool isVisibleInViewportOrFullscreen : 1;
+ bool isLargeEnoughForMainContent : 1;
+ bool isPlayingAudio : 1;
+};
+
+static MediaElementSessionInfo mediaElementSessionInfoForSession(const MediaElementSession& session)
+{
+ const HTMLMediaElement& element = session.element();
+ return {
+ &session,
+ session.mostRecentUserInteractionTime(),
+ session.canShowControlsManager(),
+ element.isFullscreen() || element.isVisibleInViewport(),
+ session.isLargeEnoughForMainContent(),
+ element.isPlaying() && element.hasAudio() && !element.muted()
+ };
+}
+
+static bool preferMediaControlsForCandidateSessionOverOtherCandidateSession(const MediaElementSessionInfo& session, const MediaElementSessionInfo& otherSession)
+{
+ // Prioritize visible media over offscreen media.
+ if (session.isVisibleInViewportOrFullscreen != otherSession.isVisibleInViewportOrFullscreen)
+ return session.isVisibleInViewportOrFullscreen;
+
+ // As a tiebreaker, prioritize elements that the user recently interacted with.
+ return session.timeOfLastUserInteraction > otherSession.timeOfLastUserInteraction;
+}
+
+static bool mediaSessionMayBeConfusedWithMainContent(const MediaElementSessionInfo& session)
+{
+ if (!session.isVisibleInViewportOrFullscreen)
+ return false;
+
+ if (!session.isLargeEnoughForMainContent)
+ return false;
+
+ // Even if this video is not a candidate, if it is visible to the user and large enough
+ // to be main content, it poses a risk for being confused with main content.
+ return true;
+}
+
+static const MediaElementSession* bestMediaSessionForShowingPlaybackControlsManager()
+{
+ auto allSessions = PlatformMediaSessionManager::sharedManager().currentSessionsMatching([] (const PlatformMediaSession& session) {
+ return is<MediaElementSession>(session);
+ });
+
+ Vector<MediaElementSessionInfo> candidateSessions;
+ bool atLeastOneNonCandidateMayBeConfusedForMainContent = false;
+ for (auto& session : allSessions) {
+ auto mediaElementSessionInfo = mediaElementSessionInfoForSession(downcast<MediaElementSession>(*session));
+ if (mediaElementSessionInfo.canShowControlsManager)
+ candidateSessions.append(mediaElementSessionInfo);
+ else if (mediaSessionMayBeConfusedWithMainContent(mediaElementSessionInfo))
+ atLeastOneNonCandidateMayBeConfusedForMainContent = true;
+ }
+
+ if (!candidateSessions.size())
+ return nullptr;
+
+ std::sort(candidateSessions.begin(), candidateSessions.end(), preferMediaControlsForCandidateSessionOverOtherCandidateSession);
+ auto strongestSessionCandidate = candidateSessions.first();
+ if (!strongestSessionCandidate.isVisibleInViewportOrFullscreen && !strongestSessionCandidate.isPlayingAudio && atLeastOneNonCandidateMayBeConfusedForMainContent)
+ return nullptr;
+
+ return strongestSessionCandidate.session;
+}
+
HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document& document, bool createdByParser)
: HTMLElement(tagName, document)
, ActiveDOMObject(&document)
@@ -837,8 +910,7 @@
{
if (auto* renderer = this->renderer()) {
renderer->updateFromElement();
- if (m_mediaSession->hasBehaviorRestriction(MediaElementSession::InvisibleAutoplayNotPermitted)
- || m_mediaSession->hasBehaviorRestriction(MediaElementSession::OverrideUserGestureRequirementForMainContent))
+ if (m_mediaSession && m_mediaSession->wantsToObserveViewportVisibilityForAutoplay())
renderer->registerForVisibleInViewportCallback();
}
updateShouldAutoplay();
@@ -4022,6 +4094,11 @@
m_receivedLayoutSizeChanged = true;
scheduleUpdatePlaybackControlsManager();
}
+
+ // If the video is a candidate for main content, we should register it for viewport visibility callbacks
+ // if it hasn't already been registered.
+ if (renderer() && m_mediaSession && !m_mediaSession->wantsToObserveViewportVisibilityForAutoplay() && m_mediaSession->wantsToObserveViewportVisibilityForMediaControls())
+ renderer()->registerForVisibleInViewportCallback();
}
void HTMLMediaElement::visibilityDidChange()
@@ -7141,6 +7218,7 @@
void HTMLMediaElement::isVisibleInViewportChanged()
{
updateShouldAutoplay();
+ scheduleUpdatePlaybackControlsManager();
}
void HTMLMediaElement::updateShouldAutoplay()
@@ -7169,6 +7247,18 @@
play();
}
+void HTMLMediaElement::resetPlaybackSessionState()
+{
+ if (m_mediaSession)
+ m_mediaSession->resetPlaybackSessionState();
+}
+
+bool HTMLMediaElement::isVisibleInViewport() const
+{
+ auto renderer = this->renderer();
+ return renderer && renderer->visibleInViewportState() == RenderElement::VisibleInViewport;
+}
+
void HTMLMediaElement::updatePlaybackControlsManager()
{
Page* page = document().page();
@@ -7175,14 +7265,11 @@
if (!page)
return;
- PlatformMediaSession* session = PlatformMediaSessionManager::sharedManager().currentSessionMatching([] (const PlatformMediaSession& session) {
- return session.canControlControlsManager();
- });
-
- if (!is<MediaElementSession>(session))
+ // FIXME: Ensure that the renderer here should be up to date.
+ if (auto bestMediaSession = bestMediaSessionForShowingPlaybackControlsManager())
+ page->chrome().client().setUpPlaybackControlsManager(bestMediaSession->element());
+ else
page->chrome().client().clearPlaybackControlsManager();
- else
- page->chrome().client().setUpPlaybackControlsManager(downcast<MediaElementSession>(session)->element());
}
void HTMLMediaElement::scheduleUpdatePlaybackControlsManager()
Modified: trunk/Source/WebCore/html/HTMLMediaElement.h (205411 => 205412)
--- trunk/Source/WebCore/html/HTMLMediaElement.h 2016-09-03 23:34:00 UTC (rev 205411)
+++ trunk/Source/WebCore/html/HTMLMediaElement.h 2016-09-04 00:24:14 UTC (rev 205412)
@@ -468,6 +468,9 @@
RenderMedia* renderer() const;
+ void resetPlaybackSessionState();
+ bool isVisibleInViewport() const;
+
protected:
HTMLMediaElement(const QualifiedName&, Document&, bool createdByParser);
virtual ~HTMLMediaElement();
Modified: trunk/Source/WebCore/html/MediaElementSession.cpp (205411 => 205412)
--- trunk/Source/WebCore/html/MediaElementSession.cpp 2016-09-03 23:34:00 UTC (rev 205411)
+++ trunk/Source/WebCore/html/MediaElementSession.cpp 2016-09-04 00:24:14 UTC (rev 205412)
@@ -47,6 +47,7 @@
#include "RenderView.h"
#include "ScriptController.h"
#include "SourceBuffer.h"
+#include <wtf/CurrentTime.h>
#if PLATFORM(IOS)
#include "AudioSession.h"
@@ -137,6 +138,9 @@
void MediaElementSession::removeBehaviorRestriction(BehaviorRestrictions restriction)
{
+ if (restriction & RequireUserGestureToControlControlsManager)
+ m_mostRecentUserInteractionTime = monotonicallyIncreasingTime();
+
LOG(Media, "MediaElementSession::removeBehaviorRestriction - removing %s", restrictionName(restriction).utf8().data());
m_restrictions &= ~restriction;
}
@@ -212,69 +216,89 @@
return true;
}
-bool MediaElementSession::canControlControlsManager() const
+bool MediaElementSession::canShowControlsManager() const
{
if (m_element.isFullscreen()) {
- LOG(Media, "MediaElementSession::canControlControlsManager - returning TRUE: Is fullscreen");
+ LOG(Media, "MediaElementSession::canShowControlsManager - returning TRUE: Is fullscreen");
return true;
}
if (!m_element.hasAudio()) {
- LOG(Media, "MediaElementSession::canControlControlsManager - returning FALSE: No audio");
+ LOG(Media, "MediaElementSession::canShowControlsManager - returning FALSE: No audio");
return false;
}
if (m_element.document().activeDOMObjectsAreSuspended()) {
- LOG(Media, "MediaElementSession::canControlControlsManager - returning FALSE: activeDOMObjectsAreSuspended()");
+ LOG(Media, "MediaElementSession::canShowControlsManager - returning FALSE: activeDOMObjectsAreSuspended()");
return false;
}
if (!playbackPermitted(m_element)) {
- LOG(Media, "MediaElementSession::canControlControlsManager - returning FALSE: Playback not permitted");
+ LOG(Media, "MediaElementSession::canShowControlsManager - returning FALSE: Playback not permitted");
return false;
}
if (!hasBehaviorRestriction(RequireUserGestureToControlControlsManager) || ScriptController::processingUserGestureForMedia()) {
- LOG(Media, "MediaElementSession::canControlControlsManager - returning TRUE: No user gesture required");
+ LOG(Media, "MediaElementSession::canShowControlsManager - returning TRUE: No user gesture required");
return true;
}
if (hasBehaviorRestriction(RequirePlaybackToControlControlsManager) && !m_element.isPlaying()) {
- LOG(Media, "MediaElementSession::canControlControlsManager - returning FALSE: Needs to be playing");
+ LOG(Media, "MediaElementSession::canShowControlsManager - returning FALSE: Needs to be playing");
return false;
}
if (m_element.muted()) {
- LOG(Media, "MediaElementSession::canControlControlsManager - returning FALSE: Muted");
+ LOG(Media, "MediaElementSession::canShowControlsManager - returning FALSE: Muted");
return false;
}
if (m_element.isVideo()) {
if (!m_element.renderer()) {
- LOG(Media, "MediaElementSession::canControlControlsManager - returning FALSE: No renderer");
+ LOG(Media, "MediaElementSession::canShowControlsManager - returning FALSE: No renderer");
return false;
}
if (m_element.document().isMediaDocument()) {
- LOG(Media, "MediaElementSession::canControlControlsManager - returning TRUE: Is media document");
+ LOG(Media, "MediaElementSession::canShowControlsManager - returning TRUE: Is media document");
return true;
}
if (!m_element.hasVideo()) {
- LOG(Media, "MediaElementSession::canControlControlsManager - returning FALSE: No video");
+ LOG(Media, "MediaElementSession::canShowControlsManager - returning FALSE: No video");
return false;
}
- if (isElementLargeEnoughForMainContent(m_element)) {
- LOG(Media, "MediaElementSession::canControlControlsManager - returning TRUE: Is main content");
+ if (isLargeEnoughForMainContent()) {
+ LOG(Media, "MediaElementSession::canShowControlsManager - returning TRUE: Is main content");
return true;
}
}
- LOG(Media, "MediaElementSession::canControlControlsManager - returning FALSE: No user gesture");
+ LOG(Media, "MediaElementSession::canShowControlsManager - returning FALSE: No user gesture");
return false;
}
+bool MediaElementSession::isLargeEnoughForMainContent() const
+{
+ return isElementLargeEnoughForMainContent(m_element);
+}
+
+double MediaElementSession::mostRecentUserInteractionTime() const
+{
+ return m_mostRecentUserInteractionTime;
+}
+
+bool MediaElementSession::wantsToObserveViewportVisibilityForMediaControls() const
+{
+ return isLargeEnoughForMainContent();
+}
+
+bool MediaElementSession::wantsToObserveViewportVisibilityForAutoplay() const
+{
+ return hasBehaviorRestriction(InvisibleAutoplayNotPermitted) || hasBehaviorRestriction(OverrideUserGestureRequirementForMainContent);
+}
+
#if ENABLE(WIRELESS_PLAYBACK_TARGET)
void MediaElementSession::showPlaybackTargetPicker(const HTMLMediaElement& element)
{
@@ -502,6 +526,12 @@
}
+void MediaElementSession::resetPlaybackSessionState()
+{
+ m_mostRecentUserInteractionTime = 0;
+ addBehaviorRestriction(RequireUserGestureToControlControlsManager | RequirePlaybackToControlControlsManager);
+}
+
bool MediaElementSession::allowsPictureInPicture(const HTMLMediaElement& element) const
{
Settings* settings = element.document().settings();
Modified: trunk/Source/WebCore/html/MediaElementSession.h (205411 => 205412)
--- trunk/Source/WebCore/html/MediaElementSession.h 2016-09-03 23:34:00 UTC (rev 205411)
+++ trunk/Source/WebCore/html/MediaElementSession.h 2016-09-04 00:24:14 UTC (rev 205412)
@@ -54,8 +54,6 @@
bool pageAllowsDataLoading(const HTMLMediaElement&) const;
bool pageAllowsPlaybackAfterResuming(const HTMLMediaElement&) const;
- bool canControlControlsManager() const override;
-
#if ENABLE(WIRELESS_PLAYBACK_TARGET)
void showPlaybackTargetPicker(const HTMLMediaElement&);
bool hasWirelessPlaybackTargets(const HTMLMediaElement&) const;
@@ -78,6 +76,8 @@
void mediaEngineUpdated(const HTMLMediaElement&);
+ void resetPlaybackSessionState() override;
+
// Restrictions to modify default behaviors.
enum BehaviorRestrictionFlags : unsigned {
NoRestrictions = 0,
@@ -111,6 +111,12 @@
HTMLMediaElement& element() const { return m_element; }
+ bool wantsToObserveViewportVisibilityForMediaControls() const;
+ bool wantsToObserveViewportVisibilityForAutoplay() const;
+ bool canShowControlsManager() const;
+ bool isLargeEnoughForMainContent() const;
+ double mostRecentUserInteractionTime() const;
+
private:
#if ENABLE(WIRELESS_PLAYBACK_TARGET)
@@ -140,6 +146,8 @@
bool m_hasPlaybackTargetAvailabilityListeners { false };
#endif
+ double m_mostRecentUserInteractionTime { 0 };
+
mutable bool m_isMainContent { false };
Timer m_mainContentCheckTimer;
};
Modified: trunk/Source/WebCore/platform/audio/PlatformMediaSession.h (205411 => 205412)
--- trunk/Source/WebCore/platform/audio/PlatformMediaSession.h 2016-09-03 23:34:00 UTC (rev 205411)
+++ trunk/Source/WebCore/platform/audio/PlatformMediaSession.h 2016-09-04 00:24:14 UTC (rev 205412)
@@ -145,7 +145,6 @@
bool shouldOverrideBackgroundLoadingRestriction() const;
- virtual bool canControlControlsManager() const { return false; }
virtual bool canPlayToWirelessPlaybackTarget() const { return false; }
virtual bool isPlayingToWirelessPlaybackTarget() const { return m_isPlayingToWirelessPlaybackTarget; }
void isPlayingToWirelessPlaybackTargetChanged(bool);
@@ -166,6 +165,7 @@
void setCanProduceAudio(bool);
void scheduleClientDataBufferingCheck();
+ virtual void resetPlaybackSessionState() { }
protected:
PlatformMediaSessionClient& client() const { return m_client; }
Modified: trunk/Source/WebCore/platform/audio/PlatformMediaSessionManager.cpp (205411 => 205412)
--- trunk/Source/WebCore/platform/audio/PlatformMediaSessionManager.cpp 2016-09-03 23:34:00 UTC (rev 205411)
+++ trunk/Source/WebCore/platform/audio/PlatformMediaSessionManager.cpp 2016-09-04 00:24:14 UTC (rev 205412)
@@ -280,13 +280,14 @@
return m_sessions[0];
}
-PlatformMediaSession* PlatformMediaSessionManager::currentSessionMatching(std::function<bool(const PlatformMediaSession &)> filter)
+Vector<PlatformMediaSession*> PlatformMediaSessionManager::currentSessionsMatching(std::function<bool(const PlatformMediaSession &)> filter)
{
+ Vector<PlatformMediaSession*> matchingSessions;
for (auto& session : m_sessions) {
if (filter(*session))
- return session;
+ matchingSessions.append(session);
}
- return nullptr;
+ return matchingSessions;
}
bool PlatformMediaSessionManager::sessionCanLoadMedia(const PlatformMediaSession& session) const
Modified: trunk/Source/WebCore/platform/audio/PlatformMediaSessionManager.h (205411 => 205412)
--- trunk/Source/WebCore/platform/audio/PlatformMediaSessionManager.h 2016-09-03 23:34:00 UTC (rev 205411)
+++ trunk/Source/WebCore/platform/audio/PlatformMediaSessionManager.h 2016-09-04 00:24:14 UTC (rev 205412)
@@ -92,7 +92,7 @@
void setCurrentSession(PlatformMediaSession&);
PlatformMediaSession* currentSession() const;
- PlatformMediaSession* currentSessionMatching(std::function<bool(const PlatformMediaSession&)>);
+ Vector<PlatformMediaSession*> currentSessionsMatching(std::function<bool(const PlatformMediaSession&)>);
void sessionIsPlayingToWirelessPlaybackTargetChanged(PlatformMediaSession&);
void sessionCanProduceAudioChanged(PlatformMediaSession&);
Modified: trunk/Source/WebCore/platform/cocoa/WebPlaybackSessionModelMediaElement.mm (205411 => 205412)
--- trunk/Source/WebCore/platform/cocoa/WebPlaybackSessionModelMediaElement.mm 2016-09-03 23:34:00 UTC (rev 205411)
+++ trunk/Source/WebCore/platform/cocoa/WebPlaybackSessionModelMediaElement.mm 2016-09-04 00:24:14 UTC (rev 205412)
@@ -67,6 +67,9 @@
}
m_isListening = false;
+ if (m_mediaElement)
+ m_mediaElement->resetPlaybackSessionState();
+
m_mediaElement = mediaElement;
if (m_mediaElement) {
Modified: trunk/Source/WebKit2/ChangeLog (205411 => 205412)
--- trunk/Source/WebKit2/ChangeLog 2016-09-03 23:34:00 UTC (rev 205411)
+++ trunk/Source/WebKit2/ChangeLog 2016-09-04 00:24:14 UTC (rev 205412)
@@ -1,3 +1,37 @@
+2016-09-03 Wenson Hsieh <[email protected]>
+
+ Refactor the heuristic for showing media controls to take all media sessions into account
+ https://bugs.webkit.org/show_bug.cgi?id=161503
+ <rdar://problem/28033783>
+
+ Reviewed by Darin Adler.
+
+ Adds an SPI testing hook for sending the element ID of the currently controlled video element from the web
+ process to the UI process. See VideoControlsManager.mm in Tools/TestWebKitAPI/ for usage.
+
+ * UIProcess/API/Cocoa/WKWebView.mm:
+ (-[WKWebView _requestControlledElementID]):
+ (-[WKWebView _handleControlledElementIDResponse:]):
+ (-[WKWebView _hasActiveVideoForControlsManager]): Deleted.
+ * UIProcess/API/Cocoa/WKWebViewPrivate.h:
+ * UIProcess/Cocoa/WebPlaybackSessionManagerProxy.h:
+ * UIProcess/Cocoa/WebPlaybackSessionManagerProxy.messages.in:
+ * UIProcess/Cocoa/WebPlaybackSessionManagerProxy.mm:
+ (WebKit::WebPlaybackSessionManagerProxy::handleControlledElementIDResponse):
+ (WebKit::WebPlaybackSessionManagerProxy::requestControlledElementID):
+ * UIProcess/PageClient.h:
+ * UIProcess/WebPageProxy.cpp:
+ (WebKit::WebPageProxy::requestControlledElementID):
+ (WebKit::WebPageProxy::handleControlledElementIDResponse):
+ * UIProcess/WebPageProxy.h:
+ * UIProcess/mac/PageClientImpl.h:
+ * UIProcess/mac/PageClientImpl.mm:
+ (WebKit::PageClientImpl::handleControlledElementIDResponse):
+ * WebProcess/cocoa/WebPlaybackSessionManager.h:
+ * WebProcess/cocoa/WebPlaybackSessionManager.messages.in:
+ * WebProcess/cocoa/WebPlaybackSessionManager.mm:
+ (WebKit::WebPlaybackSessionManager::handleControlledElementIDRequest):
+
2016-09-03 Darin Adler <[email protected]>
Streamline DOMImplementation, and move it to our new DOM exception system
Modified: trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm (205411 => 205412)
--- trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm 2016-09-03 23:34:00 UTC (rev 205411)
+++ trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm 2016-09-04 00:24:14 UTC (rev 205412)
@@ -4553,6 +4553,17 @@
{
return _page && _page->hasActiveVideoForControlsManager();
}
+
+- (void)_requestControlledElementID
+{
+ if (_page)
+ _page->requestControlledElementID();
+}
+
+- (void)_handleControlledElementIDResponse:(NSString *)identifier
+{
+ // Overridden by subclasses.
+}
#endif // PLATFORM(MAC)
// Execute the supplied block after the next transaction from the WebProcess.
Modified: trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebViewPrivate.h (205411 => 205412)
--- trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebViewPrivate.h 2016-09-03 23:34:00 UTC (rev 205411)
+++ trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebViewPrivate.h 2016-09-04 00:24:14 UTC (rev 205412)
@@ -271,6 +271,8 @@
#if !TARGET_OS_IPHONE
@property (nonatomic, readonly) BOOL _hasActiveVideoForControlsManager WK_API_AVAILABLE(macosx(WK_MAC_TBA));
+- (void)_requestControlledElementID WK_API_AVAILABLE(macosx(WK_MAC_TBA));
+- (void)_handleControlledElementIDResponse:(NSString *)identifier WK_API_AVAILABLE(macosx(WK_MAC_TBA));
#endif
- (void)_doAfterNextPresentationUpdate:(void (^)(void))updateBlock WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
Modified: trunk/Source/WebKit2/UIProcess/Cocoa/WebPlaybackSessionManagerProxy.h (205411 => 205412)
--- trunk/Source/WebKit2/UIProcess/Cocoa/WebPlaybackSessionManagerProxy.h 2016-09-03 23:34:00 UTC (rev 205411)
+++ trunk/Source/WebKit2/UIProcess/Cocoa/WebPlaybackSessionManagerProxy.h 2016-09-04 00:24:14 UTC (rev 205412)
@@ -146,6 +146,7 @@
void invalidate();
PlatformWebPlaybackSessionInterface* controlsManagerInterface();
+ void requestControlledElementID();
private:
friend class WebPlaybackSessionModelContext;
@@ -176,6 +177,7 @@
void setWirelessVideoPlaybackDisabled(uint64_t contextId, bool);
void setDuration(uint64_t contextId, double duration);
void setRate(uint64_t contextId, bool isPlaying, double rate);
+ void handleControlledElementIDResponse(uint64_t, String) const;
// Messages to WebPlaybackSessionManager
void play(uint64_t contextId);
Modified: trunk/Source/WebKit2/UIProcess/Cocoa/WebPlaybackSessionManagerProxy.messages.in (205411 => 205412)
--- trunk/Source/WebKit2/UIProcess/Cocoa/WebPlaybackSessionManagerProxy.messages.in 2016-09-03 23:34:00 UTC (rev 205411)
+++ trunk/Source/WebKit2/UIProcess/Cocoa/WebPlaybackSessionManagerProxy.messages.in 2016-09-04 00:24:14 UTC (rev 205412)
@@ -35,5 +35,7 @@
SetRate(uint64_t contextId, bool isPlaying, double rate)
SetUpPlaybackControlsManagerWithID(uint64_t contextId)
ClearPlaybackControlsManager()
+
+ HandleControlledElementIDResponse(uint64_t contextId, String id)
}
#endif
Modified: trunk/Source/WebKit2/UIProcess/Cocoa/WebPlaybackSessionManagerProxy.mm (205411 => 205412)
--- trunk/Source/WebKit2/UIProcess/Cocoa/WebPlaybackSessionManagerProxy.mm 2016-09-03 23:34:00 UTC (rev 205411)
+++ trunk/Source/WebKit2/UIProcess/Cocoa/WebPlaybackSessionManagerProxy.mm 2016-09-04 00:24:14 UTC (rev 205412)
@@ -394,6 +394,19 @@
ensureModel(contextId).setRate(isPlaying, rate);
}
+
+void WebPlaybackSessionManagerProxy::handleControlledElementIDResponse(uint64_t contextId, String identifier) const
+{
+#if PLATFORM(MAC)
+ if (contextId == m_controlsManagerContextId)
+ m_page->handleControlledElementIDResponse(identifier);
+#else
+ UNUSED_PARAM(contextId);
+ UNUSED_PARAM(identifier);
+#endif
+}
+
+
#pragma mark Messages to WebPlaybackSessionManager
void WebPlaybackSessionManagerProxy::play(uint64_t contextId)
@@ -456,6 +469,12 @@
m_page->send(Messages::WebPlaybackSessionManager::SelectLegibleMediaOption(contextId, index), m_page->pageID());
}
+void WebPlaybackSessionManagerProxy::requestControlledElementID()
+{
+ if (m_controlsManagerContextId)
+ m_page->send(Messages::WebPlaybackSessionManager::HandleControlledElementIDRequest(m_controlsManagerContextId), m_page->pageID());
+}
+
PlatformWebPlaybackSessionInterface* WebPlaybackSessionManagerProxy::controlsManagerInterface()
{
if (!m_controlsManagerContextId)
Modified: trunk/Source/WebKit2/UIProcess/PageClient.h (205411 => 205412)
--- trunk/Source/WebKit2/UIProcess/PageClient.h 2016-09-03 23:34:00 UTC (rev 205411)
+++ trunk/Source/WebKit2/UIProcess/PageClient.h 2016-09-04 00:24:14 UTC (rev 205412)
@@ -247,6 +247,7 @@
virtual void recordAutocorrectionResponse(WebCore::AutocorrectionResponseType, const String& replacedString, const String& replacementString) = 0;
virtual void recommendedScrollbarStyleDidChange(WebCore::ScrollbarStyle) = 0;
virtual void removeNavigationGestureSnapshot() = 0;
+ virtual void handleControlledElementIDResponse(const String&) = 0;
virtual CGRect boundsOfLayerInLayerBackedWindowCoordinates(CALayer *) const = 0;
Modified: trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp (205411 => 205412)
--- trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp 2016-09-03 23:34:00 UTC (rev 205411)
+++ trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp 2016-09-04 00:24:14 UTC (rev 205412)
@@ -6298,6 +6298,19 @@
#endif
}
+void WebPageProxy::requestControlledElementID() const
+{
+#if ENABLE(VIDEO_PRESENTATION_MODE)
+ if (m_playbackSessionManager)
+ m_playbackSessionManager->requestControlledElementID();
+#endif
+}
+
+void WebPageProxy::handleControlledElementIDResponse(const String& identifier) const
+{
+ m_pageClient.handleControlledElementIDResponse(identifier);
+}
+
bool WebPageProxy::isPlayingVideoInEnhancedFullscreen() const
{
#if ENABLE(VIDEO_PRESENTATION_MODE)
Modified: trunk/Source/WebKit2/UIProcess/WebPageProxy.h (205411 => 205412)
--- trunk/Source/WebKit2/UIProcess/WebPageProxy.h 2016-09-03 23:34:00 UTC (rev 205411)
+++ trunk/Source/WebKit2/UIProcess/WebPageProxy.h 2016-09-04 00:24:14 UTC (rev 205412)
@@ -1031,6 +1031,8 @@
#if PLATFORM(MAC)
void videoControlsManagerDidChange();
bool hasActiveVideoForControlsManager() const;
+ void requestControlledElementID() const;
+ void handleControlledElementIDResponse(const String&) const;
bool isPlayingVideoInEnhancedFullscreen() const;
#endif
Modified: trunk/Source/WebKit2/UIProcess/mac/PageClientImpl.h (205411 => 205412)
--- trunk/Source/WebKit2/UIProcess/mac/PageClientImpl.h 2016-09-03 23:34:00 UTC (rev 205411)
+++ trunk/Source/WebKit2/UIProcess/mac/PageClientImpl.h 2016-09-04 00:24:14 UTC (rev 205412)
@@ -206,6 +206,7 @@
void didFailLoadForMainFrame() override;
void didSameDocumentNavigationForMainFrame(SameDocumentNavigationType) override;
void removeNavigationGestureSnapshot() override;
+ void handleControlledElementIDResponse(const String&) override;
void didPerformImmediateActionHitTest(const WebHitTestResultData&, bool contentPreventsDefault, API::Object*) override;
void* immediateActionAnimationControllerForHitTestResult(RefPtr<API::HitTestResult>, uint64_t, RefPtr<API::Object>) override;
Modified: trunk/Source/WebKit2/UIProcess/mac/PageClientImpl.mm (205411 => 205412)
--- trunk/Source/WebKit2/UIProcess/mac/PageClientImpl.mm 2016-09-03 23:34:00 UTC (rev 205411)
+++ trunk/Source/WebKit2/UIProcess/mac/PageClientImpl.mm 2016-09-04 00:24:14 UTC (rev 205412)
@@ -752,6 +752,13 @@
gestureController->removeSwipeSnapshot();
}
+void PageClientImpl::handleControlledElementIDResponse(const String& identifier)
+{
+#if WK_API_ENABLED
+ [m_webView _handleControlledElementIDResponse:nsStringFromWebCoreString(identifier)];
+#endif
+}
+
void PageClientImpl::didChangeBackgroundColor()
{
notImplemented();
Modified: trunk/Source/WebKit2/WebProcess/cocoa/WebPlaybackSessionManager.h (205411 => 205412)
--- trunk/Source/WebKit2/WebProcess/cocoa/WebPlaybackSessionManager.h 2016-09-03 23:34:00 UTC (rev 205411)
+++ trunk/Source/WebKit2/WebProcess/cocoa/WebPlaybackSessionManager.h 2016-09-04 00:24:14 UTC (rev 205412)
@@ -143,6 +143,7 @@
void endScanning(uint64_t contextId);
void selectAudioMediaOption(uint64_t contextId, uint64_t index);
void selectLegibleMediaOption(uint64_t contextId, uint64_t index);
+ void handleControlledElementIDRequest(uint64_t contextId);
WebPage* m_page;
HashMap<WebCore::HTMLMediaElement*, uint64_t> m_mediaElements;
Modified: trunk/Source/WebKit2/WebProcess/cocoa/WebPlaybackSessionManager.messages.in (205411 => 205412)
--- trunk/Source/WebKit2/WebProcess/cocoa/WebPlaybackSessionManager.messages.in 2016-09-03 23:34:00 UTC (rev 205411)
+++ trunk/Source/WebKit2/WebProcess/cocoa/WebPlaybackSessionManager.messages.in 2016-09-04 00:24:14 UTC (rev 205412)
@@ -35,5 +35,6 @@
EndScanning(uint64_t contextId)
SelectAudioMediaOption(uint64_t contextId, uint64_t index)
SelectLegibleMediaOption(uint64_t contextId, uint64_t index)
+ HandleControlledElementIDRequest(uint64_t contextId)
}
#endif
Modified: trunk/Source/WebKit2/WebProcess/cocoa/WebPlaybackSessionManager.mm (205411 => 205412)
--- trunk/Source/WebKit2/WebProcess/cocoa/WebPlaybackSessionManager.mm 2016-09-03 23:34:00 UTC (rev 205411)
+++ trunk/Source/WebKit2/WebProcess/cocoa/WebPlaybackSessionManager.mm 2016-09-04 00:24:14 UTC (rev 205412)
@@ -415,6 +415,13 @@
ensureModel(contextId).selectLegibleMediaOption(index);
}
+void WebPlaybackSessionManager::handleControlledElementIDRequest(uint64_t contextId)
+{
+ auto element = ensureModel(contextId).mediaElement();
+ if (element)
+ m_page->send(Messages::WebPlaybackSessionManagerProxy::HandleControlledElementIDResponse(contextId, element->getIdAttribute()));
+}
+
} // namespace WebKit
#endif // PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
Modified: trunk/Tools/ChangeLog (205411 => 205412)
--- trunk/Tools/ChangeLog 2016-09-03 23:34:00 UTC (rev 205411)
+++ trunk/Tools/ChangeLog 2016-09-04 00:24:14 UTC (rev 205412)
@@ -1,3 +1,40 @@
+2016-09-03 Wenson Hsieh <[email protected]>
+
+ Refactor the heuristic for showing media controls to take all media sessions into account
+ https://bugs.webkit.org/show_bug.cgi?id=161503
+ <rdar://problem/28033783>
+
+ Reviewed by Darin Adler.
+
+ Adds new unit tests verifying the behavior of media playback controls when scrolling another video into view.
+ Please see the WebCore ChangeLog for more details about this change. Also refactors existing
+ VideoControlsManager tests by folding duplicated setup and testing logic into helper methods to make the unit
+ tests more readable.
+
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/Tests/WebKit2Cocoa/VideoControlsManager.mm:
+ (-[MessageHandler initWithMessage:handler:]):
+ (-[MessageHandler userContentController:didReceiveScriptMessage:]):
+ (-[VideoControlsManagerTestWebView performAfterLoading:]):
+ (-[VideoControlsManagerTestWebView loadTestPageNamed:]):
+ (-[VideoControlsManagerTestWebView loadTestPageNamed:andExpectControlsManager:afterReceivingMessage:]):
+ (-[VideoControlsManagerTestWebView performAfterReceivingMessage:action:]):
+ (-[VideoControlsManagerTestWebView controlledElementID]):
+ (-[VideoControlsManagerTestWebView _handleControlledElementIDResponse:]):
+ (TestWebKitAPI::setUpWebViewForTestingVideoControlsManager):
+ (TestWebKitAPI::TEST):
+ (-[MediaPlaybackMessageHandler initWithWKWebView:finalMessageString:]): Deleted.
+ (-[MediaPlaybackMessageHandler userContentController:didReceiveScriptMessage:]): Deleted.
+ (-[OnLoadMessageHandler initWithWKWebView:handler:]): Deleted.
+ (-[OnLoadMessageHandler userContentController:didReceiveScriptMessage:]): Deleted.
+ (-[WKWebView performAfterLoading:]): Deleted.
+ * TestWebKitAPI/Tests/WebKit2Cocoa/large-video-playing-scroll-away.html: Added.
+ * TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-click-to-pause.html: Added.
+ * TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-scroll-to-video.html: Added.
+ * TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-paused-video-hides-controls.html: Added.
+ * TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-muted-video-hides-controls.html: Added.
+ * TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-video-keeps-controls.html: Added.
+
2016-09-03 Youenn Fablet <[email protected]>
run-webkit-tests should detect w3c test resource files
Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (205411 => 205412)
--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2016-09-03 23:34:00 UTC (rev 205411)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2016-09-04 00:24:14 UTC (rev 205412)
@@ -64,6 +64,12 @@
2E1DFDED1D42A51100714A00 /* large-videos-with-audio.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 2E1DFDEC1D42A41C00714A00 /* large-videos-with-audio.html */; };
2E1DFDEF1D42A6F200714A00 /* large-videos-with-audio-autoplay.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 2E1DFDEE1D42A6EB00714A00 /* large-videos-with-audio-autoplay.html */; };
2E1DFDF11D42E1E400714A00 /* large-video-seek-to-beginning-and-play-after-ending.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 2E1DFDF01D42E14400714A00 /* large-video-seek-to-beginning-and-play-after-ending.html */; };
+ 2E691AEA1D78B53600129407 /* large-videos-paused-video-hides-controls.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 2E691AE81D78B52B00129407 /* large-videos-paused-video-hides-controls.html */; };
+ 2E691AEB1D78B53600129407 /* large-videos-playing-video-keeps-controls.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 2E691AE91D78B52B00129407 /* large-videos-playing-video-keeps-controls.html */; };
+ 2E691AED1D78B91000129407 /* large-videos-playing-muted-video-hides-controls.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 2E691AEC1D78B90200129407 /* large-videos-playing-muted-video-hides-controls.html */; };
+ 2E691AEF1D79DE8400129407 /* large-videos-autoplaying-click-to-pause.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 2E691AEE1D79DE6F00129407 /* large-videos-autoplaying-click-to-pause.html */; };
+ 2E691AF11D79E51A00129407 /* large-videos-autoplaying-scroll-to-video.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 2E691AF01D79E51400129407 /* large-videos-autoplaying-scroll-to-video.html */; };
+ 2E691AF31D79E75E00129407 /* large-video-playing-scroll-away.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 2E691AF21D79E75400129407 /* large-video-playing-scroll-away.html */; };
2E7765CD16C4D80A00BA2BB1 /* mainIOS.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2E7765CC16C4D80A00BA2BB1 /* mainIOS.mm */; };
2E7765CF16C4D81100BA2BB1 /* mainMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2E7765CE16C4D81100BA2BB1 /* mainMac.mm */; };
33BE5AF9137B5AAE00705813 /* MouseMoveAfterCrash_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 33BE5AF8137B5AAE00705813 /* MouseMoveAfterCrash_Bundle.cpp */; };
@@ -520,6 +526,12 @@
dstPath = TestWebKitAPI.resources;
dstSubfolderSpec = 7;
files = (
+ 2E691AF31D79E75E00129407 /* large-video-playing-scroll-away.html in Copy Resources */,
+ 2E691AF11D79E51A00129407 /* large-videos-autoplaying-scroll-to-video.html in Copy Resources */,
+ 2E691AEF1D79DE8400129407 /* large-videos-autoplaying-click-to-pause.html in Copy Resources */,
+ 2E691AED1D78B91000129407 /* large-videos-playing-muted-video-hides-controls.html in Copy Resources */,
+ 2E691AEA1D78B53600129407 /* large-videos-paused-video-hides-controls.html in Copy Resources */,
+ 2E691AEB1D78B53600129407 /* large-videos-playing-video-keeps-controls.html in Copy Resources */,
1A9E52C913E65EF4006917F5 /* 18-characters.html in Copy Resources */,
379028B914FAC24C007E6B43 /* acceptsFirstMouse.html in Copy Resources */,
1C2B81871C8925A000A5529F /* Ahem.ttf in Copy Resources */,
@@ -743,6 +755,12 @@
2E1DFDEC1D42A41C00714A00 /* large-videos-with-audio.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "large-videos-with-audio.html"; sourceTree = "<group>"; };
2E1DFDEE1D42A6EB00714A00 /* large-videos-with-audio-autoplay.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "large-videos-with-audio-autoplay.html"; sourceTree = "<group>"; };
2E1DFDF01D42E14400714A00 /* large-video-seek-to-beginning-and-play-after-ending.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "large-video-seek-to-beginning-and-play-after-ending.html"; sourceTree = "<group>"; };
+ 2E691AE81D78B52B00129407 /* large-videos-paused-video-hides-controls.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "large-videos-paused-video-hides-controls.html"; sourceTree = "<group>"; };
+ 2E691AE91D78B52B00129407 /* large-videos-playing-video-keeps-controls.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "large-videos-playing-video-keeps-controls.html"; sourceTree = "<group>"; };
+ 2E691AEC1D78B90200129407 /* large-videos-playing-muted-video-hides-controls.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "large-videos-playing-muted-video-hides-controls.html"; sourceTree = "<group>"; };
+ 2E691AEE1D79DE6F00129407 /* large-videos-autoplaying-click-to-pause.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "large-videos-autoplaying-click-to-pause.html"; sourceTree = "<group>"; };
+ 2E691AF01D79E51400129407 /* large-videos-autoplaying-scroll-to-video.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "large-videos-autoplaying-scroll-to-video.html"; sourceTree = "<group>"; };
+ 2E691AF21D79E75400129407 /* large-video-playing-scroll-away.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "large-video-playing-scroll-away.html"; sourceTree = "<group>"; };
2E7765CC16C4D80A00BA2BB1 /* mainIOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = mainIOS.mm; sourceTree = "<group>"; };
2E7765CE16C4D81100BA2BB1 /* mainMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = mainMac.mm; sourceTree = "<group>"; };
333B9CE11277F23100FEFCE3 /* PreventEmptyUserAgent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PreventEmptyUserAgent.cpp; sourceTree = "<group>"; };
@@ -1400,6 +1418,12 @@
A16F66B81C40E9E100BD4D24 /* Resources */ = {
isa = PBXGroup;
children = (
+ 2E691AF21D79E75400129407 /* large-video-playing-scroll-away.html */,
+ 2E691AF01D79E51400129407 /* large-videos-autoplaying-scroll-to-video.html */,
+ 2E691AEE1D79DE6F00129407 /* large-videos-autoplaying-click-to-pause.html */,
+ 2E691AEC1D78B90200129407 /* large-videos-playing-muted-video-hides-controls.html */,
+ 2E691AE81D78B52B00129407 /* large-videos-paused-video-hides-controls.html */,
+ 2E691AE91D78B52B00129407 /* large-videos-playing-video-keeps-controls.html */,
5C9E593E1D3EB1DE00E3C62E /* ApplicationCache.db */,
5C9E593F1D3EB1DE00E3C62E /* ApplicationCache.db-shm */,
5C9E59401D3EB1DE00E3C62E /* ApplicationCache.db-wal */,
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/VideoControlsManager.mm (205411 => 205412)
--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/VideoControlsManager.mm 2016-09-03 23:34:00 UTC (rev 205411)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/VideoControlsManager.mm 2016-09-04 00:24:14 UTC (rev 205412)
@@ -37,66 +37,30 @@
#if WK_API_ENABLED && PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200
-static bool testedControlsManagerAfterPlaying;
-static bool receivedScriptMessage;
+@interface WKWebView (WKWebViewAdditions)
-@interface MediaPlaybackMessageHandler : NSObject <WKScriptMessageHandler> {
- RetainPtr<WKWebView> _webView;
-}
+- (void)_interactWithMediaControlsForTesting;
-@property (nonatomic) BOOL expectedToHaveControlsManager;
-@property (nonatomic, retain) NSString *finalMessageString;
-
-- (instancetype)initWithWKWebView:(WKWebView*)webView finalMessageString:(NSString *)finalMessageString;
@end
-@implementation MediaPlaybackMessageHandler
-
-- (instancetype)initWithWKWebView:(WKWebView*)webView finalMessageString:(NSString *)finalMessageString
-{
- if (!(self = [super init]))
- return nil;
-
- _webView = webView;
- _finalMessageString = finalMessageString;
-
- return self;
+@interface MessageHandler : NSObject <WKScriptMessageHandler> {
+ dispatch_block_t _handler;
+ NSString *_message;
}
-- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
-{
- receivedScriptMessage = true;
+- (instancetype)initWithMessage:(NSString *)message handler:(dispatch_block_t)handler;
- NSString *bodyString = (NSString *)[message body];
- if ([bodyString isEqualToString:self.finalMessageString]) {
- BOOL hasControlsManager = [_webView _hasActiveVideoForControlsManager];
- if (self.expectedToHaveControlsManager)
- EXPECT_TRUE(hasControlsManager);
- else
- EXPECT_FALSE(hasControlsManager);
- testedControlsManagerAfterPlaying = true;
- }
-}
@end
-@interface OnLoadMessageHandler : NSObject <WKScriptMessageHandler> {
- RetainPtr<WKWebView> _webView;
-}
+@implementation MessageHandler
-@property (nonatomic, strong) dispatch_block_t onloadHandler;
-
-- (instancetype)initWithWKWebView:(WKWebView*)webView handler:(dispatch_block_t)handler;
-@end
-
-@implementation OnLoadMessageHandler
-
-- (instancetype)initWithWKWebView:(WKWebView*)webView handler:(dispatch_block_t)handler
+- (instancetype)initWithMessage:(NSString *)message handler:(dispatch_block_t)handler
{
if (!(self = [super init]))
return nil;
- _webView = webView;
- _onloadHandler = handler;
+ _handler = [handler copy];
+ _message = message;
return self;
}
@@ -103,30 +67,28 @@
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
- if (![(NSString *)[message body] isEqualToString:@"loaded"])
- return;
-
- if (_onloadHandler)
- _onloadHandler();
-
- _onloadHandler = nil;
+ if ([(NSString *)[message body] isEqualToString:_message] && _handler)
+ _handler();
}
-@end
-@interface WKWebView (WKWebViewAdditions)
-
-- (void)_interactWithMediaControlsForTesting;
-
@end
-@interface WKWebView (TestingAdditions)
+@interface VideoControlsManagerTestWebView : WKWebView
- (void)mouseDownAtPoint:(NSPoint)point;
- (void)performAfterLoading:(dispatch_block_t)actions;
+- (void)loadTestPageNamed:(NSString *)pageName;
+- (void)loadTestPageNamed:(NSString *)pageName andExpectControlsManager:(BOOL)expectControlsManager afterReceivingMessage:(NSString *)message;
+- (void)performAfterReceivingMessage:(NSString *)message action:(dispatch_block_t)action;
+@property (nonatomic, readonly) NSString *controlledElementID;
+
@end
-@implementation WKWebView (TestingAdditions)
+@implementation VideoControlsManagerTestWebView {
+ bool _isDoneQueryingControlledElementID;
+ NSString *_controlledElementID;
+}
- (void)mouseDownAtPoint:(NSPoint)point {
[self mouseDown:[NSEvent mouseEventWithType:NSEventTypeLeftMouseDown location:NSMakePoint(point.x, point.y) modifierFlags:0 timestamp:GetCurrentEventTime() windowNumber:0 context:[NSGraphicsContext currentContext] eventNumber:0 clickCount:0 pressure:0]];
@@ -133,78 +95,103 @@
}
- (void)performAfterLoading:(dispatch_block_t)actions {
- OnLoadMessageHandler *handler = [[OnLoadMessageHandler alloc] initWithWKWebView:self handler:actions];
+ MessageHandler *handler = [[MessageHandler alloc] initWithMessage:@"loaded" handler:actions];
NSString *_onloadScript_ = @"window._onload_ = function() { window.webkit.messageHandlers.onloadHandler.postMessage('loaded'); }";
WKUserScript *script = [[WKUserScript alloc] initWithSource:onloadScript injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
- [[[self configuration] userContentController] addUserScript:script];
- [[[self configuration] userContentController] addScriptMessageHandler:handler name:@"onloadHandler"];
+
+ WKUserContentController* contentController = [[self configuration] userContentController];
+ [contentController addUserScript:script];
+ [contentController addScriptMessageHandler:handler name:@"onloadHandler"];
}
+- (void)loadTestPageNamed:(NSString *)pageName
+{
+ NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:pageName withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
+ [self loadRequest:request];
+}
+
+- (void)loadTestPageNamed:(NSString *)pageName andExpectControlsManager:(BOOL)expectControlsManager afterReceivingMessage:(NSString *)message
+{
+ __block bool doneWaiting = false;
+ [self performAfterReceivingMessage:message action:^ {
+ BOOL hasVideoForControlsManager = [self _hasActiveVideoForControlsManager];
+ if (expectControlsManager)
+ EXPECT_TRUE(hasVideoForControlsManager);
+ else
+ EXPECT_FALSE(hasVideoForControlsManager);
+ doneWaiting = true;
+ }];
+
+ [self loadTestPageNamed:pageName];
+ TestWebKitAPI::Util::run(&doneWaiting);
+}
+
+- (void)performAfterReceivingMessage:(NSString *)message action:(dispatch_block_t)action
+{
+ RetainPtr<MessageHandler> handler = adoptNS([[MessageHandler alloc] initWithMessage:message handler:action]);
+ [[[self configuration] userContentController] addScriptMessageHandler:handler.get() name:@"playingHandler"];
+}
+
+- (NSString *)controlledElementID
+{
+ _isDoneQueryingControlledElementID = false;
+ [self _requestControlledElementID];
+ TestWebKitAPI::Util::run(&_isDoneQueryingControlledElementID);
+ return _controlledElementID;
+}
+
+- (void)_handleControlledElementIDResponse:(NSString *)identifier
+{
+ _controlledElementID = [identifier copy];
+ _isDoneQueryingControlledElementID = true;
+}
+
@end
namespace TestWebKitAPI {
-TEST(VideoControlsManager, VideoControlsManagerSingleLargeVideo)
+RetainPtr<VideoControlsManagerTestWebView*> setUpWebViewForTestingVideoControlsManager(NSRect frame)
{
RetainPtr<WKWebViewConfiguration> configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
configuration.get().mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeNone;
- RetainPtr<WKWebView> webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) configuration:configuration.get()]);
- RetainPtr<MediaPlaybackMessageHandler> handler = adoptNS([[MediaPlaybackMessageHandler alloc] initWithWKWebView:webView.get() finalMessageString:@"playing"]);
- [[configuration userContentController] addScriptMessageHandler:handler.get() name:@"playingHandler"];
-
+ RetainPtr<VideoControlsManagerTestWebView> webView = adoptNS([[VideoControlsManagerTestWebView alloc] initWithFrame:frame configuration:configuration.get()]);
RetainPtr<NSWindow> window = adoptNS([[NSWindow alloc] initWithContentRect:[webView frame] styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]);
[[window contentView] addSubview:webView.get()];
+ return webView;
+}
+
+TEST(VideoControlsManager, VideoControlsManagerSingleLargeVideo)
+{
+ RetainPtr<VideoControlsManagerTestWebView*> webView = setUpWebViewForTestingVideoControlsManager(NSMakeRect(0, 0, 100, 100));
+
// A large video with audio should have a controls manager even if it is played via script like this video.
// So the expectation is YES.
- [handler setExpectedToHaveControlsManager:YES];
- NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"large-video-with-audio" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
- [webView loadRequest:request];
-
- TestWebKitAPI::Util::run(&testedControlsManagerAfterPlaying);
- TestWebKitAPI::Util::run(&receivedScriptMessage);
+ [webView loadTestPageNamed:@"large-video-with-audio" andExpectControlsManager:YES afterReceivingMessage:@"playing"];
}
TEST(VideoControlsManager, VideoControlsManagerSingleSmallVideo)
{
- RetainPtr<WKWebViewConfiguration> configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
- configuration.get().mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeNone;
- RetainPtr<WKWebView> webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) configuration:configuration.get()]);
- RetainPtr<MediaPlaybackMessageHandler> handler = adoptNS([[MediaPlaybackMessageHandler alloc] initWithWKWebView:webView.get() finalMessageString:@"playing"]);
- [[configuration userContentController] addScriptMessageHandler:handler.get() name:@"playingHandler"];
+ RetainPtr<VideoControlsManagerTestWebView*> webView = setUpWebViewForTestingVideoControlsManager(NSMakeRect(0, 0, 100, 100));
- RetainPtr<NSWindow> window = adoptNS([[NSWindow alloc] initWithContentRect:[webView frame] styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]);
- [[window contentView] addSubview:webView.get()];
-
// A small video will not have a controls manager unless it started playing because of a user gesture. Since this
// video is started with a script, the expectation is NO.
- [handler setExpectedToHaveControlsManager:NO];
- NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"video-with-audio" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
- [webView loadRequest:request];
-
- TestWebKitAPI::Util::run(&testedControlsManagerAfterPlaying);
- TestWebKitAPI::Util::run(&receivedScriptMessage);
+ [webView loadTestPageNamed:@"video-with-audio" andExpectControlsManager:NO afterReceivingMessage:@"playing"];
}
TEST(VideoControlsManager, VideoControlsManagerMultipleVideosWithAudio)
{
- RetainPtr<WKWebViewConfiguration> configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
- configuration.get().mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeNone;
- RetainPtr<WKWebView> webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) configuration:configuration.get()]);
+ RetainPtr<VideoControlsManagerTestWebView*> webView = setUpWebViewForTestingVideoControlsManager(NSMakeRect(0, 0, 100, 100));
__block BOOL didShowMediaControls;
__block bool isDoneLoading = false;
- RetainPtr<NSWindow> window = adoptNS([[NSWindow alloc] initWithContentRect:[webView frame] styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]);
- [[window contentView] addSubview:webView.get()];
- RetainPtr<OnLoadMessageHandler> _onloadHandler_ = adoptNS([[OnLoadMessageHandler alloc] initWithWKWebView:webView.get() handler:^() {
+ [webView performAfterLoading:^ {
didShowMediaControls = [webView _hasActiveVideoForControlsManager];
isDoneLoading = true;
- }]);
- [[configuration userContentController] addScriptMessageHandler:onloadHandler.get() name:@"onloadHandler"];
+ }];
- NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"large-videos-with-audio" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
- [webView loadRequest:request];
+ [webView loadTestPageNamed:@"large-videos-with-audio"];
TestWebKitAPI::Util::run(&isDoneLoading);
EXPECT_FALSE(didShowMediaControls);
@@ -212,175 +199,157 @@
TEST(VideoControlsManager, VideoControlsManagerMultipleVideosWithAudioAndAutoplay)
{
- RetainPtr<WKWebViewConfiguration> configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
- configuration.get().mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeNone;
- RetainPtr<WKWebView> webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) configuration:configuration.get()]);
+ RetainPtr<VideoControlsManagerTestWebView*> webView = setUpWebViewForTestingVideoControlsManager(NSMakeRect(0, 0, 100, 100));
__block BOOL didShowMediaControls;
__block bool isDoneLoading = false;
- RetainPtr<NSWindow> window = adoptNS([[NSWindow alloc] initWithContentRect:[webView frame] styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]);
- [[window contentView] addSubview:webView.get()];
- RetainPtr<OnLoadMessageHandler> _onloadHandler_ = adoptNS([[OnLoadMessageHandler alloc] initWithWKWebView:webView.get() handler:^() {
+ [webView performAfterLoading:^ {
didShowMediaControls = [webView _hasActiveVideoForControlsManager];
isDoneLoading = true;
- }]);
- [[configuration userContentController] addScriptMessageHandler:onloadHandler.get() name:@"onloadHandler"];
+ }];
- NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"large-videos-with-audio-autoplay" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
- [webView loadRequest:request];
+ [webView loadTestPageNamed:@"large-videos-with-audio-autoplay"];
TestWebKitAPI::Util::run(&isDoneLoading);
EXPECT_TRUE(didShowMediaControls);
}
-TEST(VideoControlsManager, VideoControlsManagerSingleSmallAutoplayingVideo)
+TEST(VideoControlsManager, VideoControlsManagerMultipleVideosScrollPausedVideoOutOfView)
{
- RetainPtr<WKWebViewConfiguration> configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
- configuration.get().mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeNone;
- RetainPtr<WKWebView> webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) configuration:configuration.get()]);
- RetainPtr<MediaPlaybackMessageHandler> playbackHandler = adoptNS([[MediaPlaybackMessageHandler alloc] initWithWKWebView:webView.get() finalMessageString:@"paused"]);
- [[configuration userContentController] addScriptMessageHandler:playbackHandler.get() name:@"playingHandler"];
+ RetainPtr<VideoControlsManagerTestWebView*> webView = setUpWebViewForTestingVideoControlsManager(NSMakeRect(0, 0, 500, 500));
- RetainPtr<NSWindow> window = adoptNS([[NSWindow alloc] initWithContentRect:[webView frame] styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]);
- [[window contentView] addSubview:webView.get()];
+ [webView loadTestPageNamed:@"large-videos-paused-video-hides-controls" andExpectControlsManager:NO afterReceivingMessage:@"paused"];
+}
- RetainPtr<OnLoadMessageHandler> _onloadHandler_ = adoptNS([[OnLoadMessageHandler alloc] initWithWKWebView:webView.get() handler:^() {
- [webView mouseDownAtPoint:NSMakePoint(50, 50)];
- }]);
- [[configuration userContentController] addScriptMessageHandler:onloadHandler.get() name:@"onloadHandler"];
+TEST(VideoControlsManager, VideoControlsManagerMultipleVideosScrollPlayingVideoWithSoundOutOfView)
+{
+ RetainPtr<VideoControlsManagerTestWebView*> webView = setUpWebViewForTestingVideoControlsManager(NSMakeRect(0, 0, 500, 500));
- // A small video should have a controls manager after the first user gesture, which includes pausing the video. The expectation is YES.
- [playbackHandler setExpectedToHaveControlsManager:YES];
- NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"autoplaying-video-with-audio" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
- [webView loadRequest:request];
+ [webView loadTestPageNamed:@"large-videos-playing-video-keeps-controls" andExpectControlsManager:YES afterReceivingMessage:@"playing"];
+}
- TestWebKitAPI::Util::run(&testedControlsManagerAfterPlaying);
- TestWebKitAPI::Util::run(&receivedScriptMessage);
+TEST(VideoControlsManager, VideoControlsManagerMultipleVideosScrollPlayingMutedVideoOutOfView)
+{
+ RetainPtr<VideoControlsManagerTestWebView*> webView = setUpWebViewForTestingVideoControlsManager(NSMakeRect(0, 0, 500, 500));
+
+ [webView loadTestPageNamed:@"large-videos-playing-muted-video-hides-controls" andExpectControlsManager:NO afterReceivingMessage:@"playing"];
}
-TEST(VideoControlsManager, VideoControlsManagerLargeAutoplayingVideoSeeksAfterEnding)
+TEST(VideoControlsManager, VideoControlsManagerMultipleVideosShowControlsForLastInteractedVideo)
{
- RetainPtr<WKWebViewConfiguration> configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
- configuration.get().mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeNone;
- RetainPtr<WKWebView> webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) configuration:configuration.get()]);
- RetainPtr<MediaPlaybackMessageHandler> handler = adoptNS([[MediaPlaybackMessageHandler alloc] initWithWKWebView:webView.get() finalMessageString:@"ended"]);
- [[configuration userContentController] addScriptMessageHandler:handler.get() name:@"playingHandler"];
+ RetainPtr<VideoControlsManagerTestWebView*> webView = setUpWebViewForTestingVideoControlsManager(NSMakeRect(0, 0, 800, 600));
+ NSPoint clickPoint = NSMakePoint(400, 300);
- RetainPtr<NSWindow> window = adoptNS([[NSWindow alloc] initWithContentRect:[webView frame] styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]);
- [[window contentView] addSubview:webView.get()];
+ [webView performAfterLoading:^ {
+ [webView mouseDownAtPoint:clickPoint];
+ }];
- // Since the video has ended, the expectation is NO even if the page programmatically seeks to the beginning.
- [handler setExpectedToHaveControlsManager:NO];
- NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"large-video-seek-after-ending" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
- [webView loadRequest:request];
+ __block bool firstVideoPaused = false;
+ __block bool secondVideoPaused = false;
+ [webView performAfterReceivingMessage:@"paused" action:^ {
+ NSString *controlledElementID = [webView controlledElementID];
+ if (firstVideoPaused) {
+ secondVideoPaused = true;
+ EXPECT_TRUE([controlledElementID isEqualToString:@"second"]);
+ } else {
+ [webView mouseDownAtPoint:clickPoint];
+ EXPECT_TRUE([controlledElementID isEqualToString:@"first"]);
+ }
+ firstVideoPaused = true;
+ }];
- TestWebKitAPI::Util::run(&testedControlsManagerAfterPlaying);
- TestWebKitAPI::Util::run(&receivedScriptMessage);
+ [webView loadTestPageNamed:@"large-videos-autoplaying-click-to-pause"];
+ TestWebKitAPI::Util::run(&secondVideoPaused);
}
-TEST(VideoControlsManager, VideoControlsManagerLargeAutoplayingVideoSeeksAndPlaysAfterEnding)
+TEST(VideoControlsManager, VideoControlsManagerMultipleVideosSwitchControlledVideoWhenScrolling)
{
- RetainPtr<WKWebViewConfiguration> configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
- configuration.get().mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeNone;
- RetainPtr<WKWebView> webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) configuration:configuration.get()]);
- RetainPtr<MediaPlaybackMessageHandler> handler = adoptNS([[MediaPlaybackMessageHandler alloc] initWithWKWebView:webView.get() finalMessageString:@"replaying"]);
- [[configuration userContentController] addScriptMessageHandler:handler.get() name:@"playingHandler"];
+ RetainPtr<VideoControlsManagerTestWebView*> webView = setUpWebViewForTestingVideoControlsManager(NSMakeRect(0, 0, 800, 600));
- RetainPtr<NSWindow> window = adoptNS([[NSWindow alloc] initWithContentRect:[webView frame] styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]);
- [[window contentView] addSubview:webView.get()];
+ __block bool scrolledSecondVideoIntoView = false;
+ [webView loadTestPageNamed:@"large-videos-autoplaying-scroll-to-video"];
+ [webView performAfterReceivingMessage:@"scrolled" action:^ {
+ scrolledSecondVideoIntoView = true;
+ }];
- // Since the video is still playing, the expectation is YES even if the video has ended once.
- [handler setExpectedToHaveControlsManager:YES];
- NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"large-video-seek-to-beginning-and-play-after-ending" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
- [webView loadRequest:request];
+ TestWebKitAPI::Util::run(&scrolledSecondVideoIntoView);
+ EXPECT_TRUE([[webView controlledElementID] isEqualToString:@"second"]);
+}
- TestWebKitAPI::Util::run(&testedControlsManagerAfterPlaying);
- TestWebKitAPI::Util::run(&receivedScriptMessage);
+TEST(VideoControlsManager, VideoControlsManagerMultipleVideosScrollOnlyLargeVideoOutOfView)
+{
+ RetainPtr<VideoControlsManagerTestWebView*> webView = setUpWebViewForTestingVideoControlsManager(NSMakeRect(0, 0, 500, 500));
+
+ [webView loadTestPageNamed:@"large-video-playing-scroll-away" andExpectControlsManager:YES afterReceivingMessage:@"scrolled"];
}
+TEST(VideoControlsManager, VideoControlsManagerSingleSmallAutoplayingVideo)
+{
+ RetainPtr<VideoControlsManagerTestWebView*> webView = setUpWebViewForTestingVideoControlsManager(NSMakeRect(0, 0, 100, 100));
+
+ [webView performAfterLoading:^ {
+ [webView mouseDownAtPoint:NSMakePoint(50, 50)];
+ }];
+
+ [webView loadTestPageNamed:@"autoplaying-video-with-audio" andExpectControlsManager:YES afterReceivingMessage:@"paused"];
+}
+
+TEST(VideoControlsManager, VideoControlsManagerLargeAutoplayingVideoSeeksAfterEnding)
+{
+ RetainPtr<VideoControlsManagerTestWebView*> webView = setUpWebViewForTestingVideoControlsManager(NSMakeRect(0, 0, 100, 100));
+
+ // Since the video has ended, the expectation is NO even if the page programmatically seeks to the beginning.
+ [webView loadTestPageNamed:@"large-video-seek-after-ending" andExpectControlsManager:NO afterReceivingMessage:@"ended"];
+}
+
+TEST(VideoControlsManager, VideoControlsManagerLargeAutoplayingVideoSeeksAndPlaysAfterEnding)
+{
+ RetainPtr<VideoControlsManagerTestWebView*> webView = setUpWebViewForTestingVideoControlsManager(NSMakeRect(0, 0, 100, 100));
+
+ // Since the video is still playing, the expectation is YES even if the video has ended once.
+ [webView loadTestPageNamed:@"large-video-seek-to-beginning-and-play-after-ending" andExpectControlsManager:YES afterReceivingMessage:@"replaying"];
+}
+
TEST(VideoControlsManager, VideoControlsManagerLargeAutoplayingVideoAfterSeekingToEnd)
{
- RetainPtr<WKWebViewConfiguration> configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
- configuration.get().mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeNone;
- RetainPtr<WKWebView> webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) configuration:configuration.get()]);
- RetainPtr<MediaPlaybackMessageHandler> handler = adoptNS([[MediaPlaybackMessageHandler alloc] initWithWKWebView:webView.get() finalMessageString:@"ended"]);
- [[configuration userContentController] addScriptMessageHandler:handler.get() name:@"playingHandler"];
+ RetainPtr<VideoControlsManagerTestWebView*> webView = setUpWebViewForTestingVideoControlsManager(NSMakeRect(0, 0, 100, 100));
- RetainPtr<NSWindow> window = adoptNS([[NSWindow alloc] initWithContentRect:[webView frame] styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]);
- [[window contentView] addSubview:webView.get()];
-
- RetainPtr<OnLoadMessageHandler> _onloadHandler_ = adoptNS([[OnLoadMessageHandler alloc] initWithWKWebView:webView.get() handler:^() {
+ [webView performAfterLoading:^ {
[webView mouseDownAtPoint:NSMakePoint(50, 50)];
- }]);
- [[configuration userContentController] addScriptMessageHandler:onloadHandler.get() name:@"onloadHandler"];
+ }];
// We expect there to be media controls, since this is a user gestured seek to the end.
// This is akin to seeking to the end by scrubbing in the controls.
- [handler setExpectedToHaveControlsManager:YES];
- NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"large-video-hides-controls-after-seek-to-end" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
- [webView loadRequest:request];
-
- TestWebKitAPI::Util::run(&testedControlsManagerAfterPlaying);
- TestWebKitAPI::Util::run(&receivedScriptMessage);
+ [webView loadTestPageNamed:@"large-video-hides-controls-after-seek-to-end" andExpectControlsManager:YES afterReceivingMessage:@"ended"];
}
TEST(VideoControlsManager, VideoControlsManagerSingleLargeVideoWithoutAudio)
{
- RetainPtr<WKWebViewConfiguration> configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
- configuration.get().mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeNone;
- RetainPtr<WKWebView> webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) configuration:configuration.get()]);
- RetainPtr<MediaPlaybackMessageHandler> handler = adoptNS([[MediaPlaybackMessageHandler alloc] initWithWKWebView:webView.get() finalMessageString:@"playing"]);
- [[configuration userContentController] addScriptMessageHandler:handler.get() name:@"playingHandler"];
+ RetainPtr<VideoControlsManagerTestWebView*> webView = setUpWebViewForTestingVideoControlsManager(NSMakeRect(0, 0, 100, 100));
- RetainPtr<NSWindow> window = adoptNS([[NSWindow alloc] initWithContentRect:[webView frame] styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]);
- [[window contentView] addSubview:webView.get()];
-
// A large video with no audio will not have a controls manager unless it started playing because of a user gesture. Since this
// video is started with a script, the expectation is NO.
- [handler setExpectedToHaveControlsManager:NO];
- NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"large-video-without-audio" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
- [webView loadRequest:request];
-
- TestWebKitAPI::Util::run(&testedControlsManagerAfterPlaying);
- TestWebKitAPI::Util::run(&receivedScriptMessage);
+ [webView loadTestPageNamed:@"large-video-without-audio" andExpectControlsManager:NO afterReceivingMessage:@"playing"];
}
TEST(VideoControlsManager, VideoControlsManagerAudioElementStartedWithScript)
{
- RetainPtr<WKWebViewConfiguration> configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
- configuration.get().mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeNone;
- RetainPtr<WKWebView> webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) configuration:configuration.get()]);
- RetainPtr<MediaPlaybackMessageHandler> handler = adoptNS([[MediaPlaybackMessageHandler alloc] initWithWKWebView:webView.get() finalMessageString:@"playing"]);
- [[configuration userContentController] addScriptMessageHandler:handler.get() name:@"playingHandler"];
+ RetainPtr<VideoControlsManagerTestWebView*> webView = setUpWebViewForTestingVideoControlsManager(NSMakeRect(0, 0, 100, 100));
- RetainPtr<NSWindow> window = adoptNS([[NSWindow alloc] initWithContentRect:[webView frame] styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]);
- [[window contentView] addSubview:webView.get()];
-
// An audio element MUST be started with a user gesture in order to have a controls manager, so the expectation is NO.
- [handler setExpectedToHaveControlsManager:NO];
- NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"audio-only" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
- [webView loadRequest:request];
-
- TestWebKitAPI::Util::run(&testedControlsManagerAfterPlaying);
- TestWebKitAPI::Util::run(&receivedScriptMessage);
+ [webView loadTestPageNamed:@"audio-only" andExpectControlsManager:NO afterReceivingMessage:@"playing"];
}
TEST(VideoControlsManager, VideoControlsManagerTearsDownMediaControlsOnDealloc)
{
- RetainPtr<WKWebViewConfiguration> configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
- configuration.get().mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeNone;
- RetainPtr<WKWebView> webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) configuration:configuration.get()]);
+ RetainPtr<VideoControlsManagerTestWebView*> webView = setUpWebViewForTestingVideoControlsManager(NSMakeRect(0, 0, 100, 100));
- RetainPtr<NSWindow> window = adoptNS([[NSWindow alloc] initWithContentRect:[webView frame] styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]);
- [[window contentView] addSubview:webView.get()];
-
NSURL *urlOfVideo = [[NSBundle mainBundle] URLForResource:@"video-with-audio" withExtension:@"mp4" subdirectory:@"TestWebKitAPI.resources"];
[webView loadFileURL:urlOfVideo allowingReadAccessToURL:[urlOfVideo URLByDeletingLastPathComponent]];
__block bool finishedTest = false;
- [webView performAfterLoading:^()
- {
+ [webView performAfterLoading:^ {
// Verify that we tear down the media controls properly, such that we don't crash when the web view is released.
if ([webView respondsToSelector:@selector(_interactWithMediaControlsForTesting)])
[webView _interactWithMediaControlsForTesting];
@@ -394,16 +363,10 @@
TEST(VideoControlsManager, VideoControlsManagerSmallVideoInMediaDocument)
{
- RetainPtr<WKWebViewConfiguration> configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
- configuration.get().mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeNone;
- RetainPtr<WKWebView> webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) configuration:configuration.get()]);
-
- RetainPtr<NSWindow> window = adoptNS([[NSWindow alloc] initWithContentRect:[webView frame] styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]);
- [[window contentView] addSubview:webView.get()];
-
+ RetainPtr<VideoControlsManagerTestWebView*> webView = setUpWebViewForTestingVideoControlsManager(NSMakeRect(0, 0, 100, 100));
+
__block bool finishedLoad = false;
- [webView performAfterLoading:^()
- {
+ [webView performAfterLoading:^ {
finishedLoad = true;
}];
@@ -418,40 +381,16 @@
TEST(VideoControlsManager, VideoControlsManagerLongSkinnyVideoInWideMainFrame)
{
- RetainPtr<WKWebViewConfiguration> configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
- configuration.get().mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeNone;
- RetainPtr<WKWebView> webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 1600, 800) configuration:configuration.get()]);
- RetainPtr<NSWindow> window = adoptNS([[NSWindow alloc] initWithContentRect:[webView frame] styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]);
- [[window contentView] addSubview:webView.get()];
+ RetainPtr<VideoControlsManagerTestWebView*> webView = setUpWebViewForTestingVideoControlsManager(NSMakeRect(0, 0, 1600, 800));
- RetainPtr<MediaPlaybackMessageHandler> handler = adoptNS([[MediaPlaybackMessageHandler alloc] initWithWKWebView:webView.get() finalMessageString:@"playing"]);
- [[configuration userContentController] addScriptMessageHandler:handler.get() name:@"playingHandler"];
- [handler setExpectedToHaveControlsManager:NO];
-
- NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"skinny-autoplaying-video-with-audio" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
- [webView loadRequest:request];
-
- TestWebKitAPI::Util::run(&testedControlsManagerAfterPlaying);
- TestWebKitAPI::Util::run(&receivedScriptMessage);
+ [webView loadTestPageNamed:@"skinny-autoplaying-video-with-audio" andExpectControlsManager:NO afterReceivingMessage:@"playing"];
}
TEST(VideoControlsManager, VideoControlsManagerFullSizeVideoInWideMainFrame)
{
- RetainPtr<WKWebViewConfiguration> configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
- configuration.get().mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeNone;
- RetainPtr<WKWebView> webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 1600, 800) configuration:configuration.get()]);
- RetainPtr<NSWindow> window = adoptNS([[NSWindow alloc] initWithContentRect:[webView frame] styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]);
- [[window contentView] addSubview:webView.get()];
+ RetainPtr<VideoControlsManagerTestWebView*> webView = setUpWebViewForTestingVideoControlsManager(NSMakeRect(0, 0, 1600, 800));
- RetainPtr<MediaPlaybackMessageHandler> handler = adoptNS([[MediaPlaybackMessageHandler alloc] initWithWKWebView:webView.get() finalMessageString:@"playing"]);
- [[configuration userContentController] addScriptMessageHandler:handler.get() name:@"playingHandler"];
- [handler setExpectedToHaveControlsManager:YES];
-
- NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"full-size-autoplaying-video-with-audio" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
- [webView loadRequest:request];
-
- TestWebKitAPI::Util::run(&testedControlsManagerAfterPlaying);
- TestWebKitAPI::Util::run(&receivedScriptMessage);
+ [webView loadTestPageNamed:@"full-size-autoplaying-video-with-audio" andExpectControlsManager:YES afterReceivingMessage:@"playing"];
}
} // namespace TestWebKitAPI
Added: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-playing-scroll-away.html (0 => 205412)
--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-playing-scroll-away.html (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-playing-scroll-away.html 2016-09-04 00:24:14 UTC (rev 205412)
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <style>
+ video {
+ width: 480px;
+ height: 320px;
+ }
+ div {
+ margin-top: 5000px;
+ }
+ </style>
+ <script>
+ function handleLoaded() {
+ document.querySelector("div").scrollIntoView();
+ setTimeout(function() {
+ window.webkit.messageHandlers.playingHandler.postMessage("scrolled");
+ }, 0);
+ }
+ </script>
+ </head>
+ <body _onload_=handleLoaded()>
+ <video autoplay loop id="first" src=""
+ <br>
+ <div>hello world!</div>
+ </body>
+<html>
Added: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-click-to-pause.html (0 => 205412)
--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-click-to-pause.html (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-click-to-pause.html 2016-09-04 00:24:14 UTC (rev 205412)
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <style>
+ video {
+ width: 480px;
+ height: 320px;
+ }
+ </style>
+ <script>
+ var isFirstClick = true;
+ function handleMouseDown() {
+ document.querySelector(isFirstClick ? "#first" : "#second").pause();
+ isFirstClick = false;
+ }
+
+ function handleFirstPause() {
+ setTimeout(function() {
+ try {
+ window.webkit.messageHandlers.playingHandler.postMessage("paused");
+ } catch(e) { }
+ }, 0);
+ }
+
+ function handleSecondPause() {
+ setTimeout(function() {
+ try {
+ window.webkit.messageHandlers.playingHandler.postMessage("paused");
+ } catch(e) { }
+ }, 0);
+ }
+ </script>
+ </head>
+ <body _onmousedown_=handleMouseDown()>
+ <video autoplay loop id="first" src="" _onpause_=handleFirstPause()></video>
+ <video autoplay loop id="second" src="" _onpause_=handleSecondPause()></video>
+ </body>
+<html>
Added: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-scroll-to-video.html (0 => 205412)
--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-scroll-to-video.html (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-scroll-to-video.html 2016-09-04 00:24:14 UTC (rev 205412)
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <style>
+ video {
+ width: 480px;
+ height: 320px;
+ }
+ #second {
+ margin-top: 5000px;
+ }
+ </style>
+ <script>
+ function handleLoaded() {
+ document.querySelector("#second").scrollIntoView();
+ setTimeout(function() {
+ window.webkit.messageHandlers.playingHandler.postMessage("scrolled");
+ }, 0);
+ }
+ </script>
+ </head>
+ <body _onload_=handleLoaded()>
+ <video autoplay loop id="first" src=""
+ <br>
+ <video autoplay loop id="second" src=""
+ </body>
+<html>
Added: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-paused-video-hides-controls.html (0 => 205412)
--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-paused-video-hides-controls.html (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-paused-video-hides-controls.html 2016-09-04 00:24:14 UTC (rev 205412)
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<style>
+ video {
+ width: 480px;
+ height: 320px;
+ }
+ #bar {
+ margin-top: 5000px;
+ }
+</style>
+<script>
+ function handleLoaded() {
+ document.querySelector("#bar").scrollIntoView();
+ document.querySelector("#foo").pause();
+ }
+ function handlePaused() {
+ setTimeout(function() {
+ try {
+ window.webkit.messageHandlers.playingHandler.postMessage("paused");
+ } catch(e) { }
+ }, 0);
+ }
+</script>
+<body _onload_=handleLoaded()>
+ <video autoplay loop id="foo" _onpause_=handlePaused()><source src=""
+ <br>
+ <video id="bar"><source src=""
+</body>
+<html>
\ No newline at end of file
Added: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-muted-video-hides-controls.html (0 => 205412)
--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-muted-video-hides-controls.html (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-muted-video-hides-controls.html 2016-09-04 00:24:14 UTC (rev 205412)
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<style>
+ video {
+ width: 480px;
+ height: 320px;
+ }
+ #bar {
+ margin-top: 5000px;
+ }
+</style>
+<script>
+ function handleLoaded() {
+ document.querySelector("#foo").muted = true;
+ document.querySelector("#bar").scrollIntoView();
+ setTimeout(function() {
+ try {
+ window.webkit.messageHandlers.playingHandler.postMessage("playing");
+ } catch(e) { }
+ }, 0);
+ }
+</script>
+<body _onload_=handleLoaded()>
+ <video autoplay loop id="foo"><source src=""
+ <br>
+ <video id="bar"><source src=""
+</body>
+<html>
\ No newline at end of file
Added: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-video-keeps-controls.html (0 => 205412)
--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-video-keeps-controls.html (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-video-keeps-controls.html 2016-09-04 00:24:14 UTC (rev 205412)
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<style>
+ video {
+ width: 480px;
+ height: 320px;
+ }
+ #bar {
+ margin-top: 5000px;
+ }
+</style>
+<script>
+ function handleLoaded() {
+ document.querySelector("#bar").scrollIntoView();
+ setTimeout(function() {
+ try {
+ window.webkit.messageHandlers.playingHandler.postMessage("playing");
+ } catch(e) { }
+ }, 0);
+ }
+</script>
+<body _onload_=handleLoaded()>
+ <video autoplay loop id="foo"><source src=""
+ <br>
+ <video id="bar"><source src=""
+</body>
+<html>
\ No newline at end of file