| Index: third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
|
| diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
|
| index 7a3c5bb811ac9c53744959f8ea10062c0685cee2..f089f48e84b876dadf4c3854088fb35fcc7851a4 100644
|
| --- a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
|
| +++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
|
| @@ -37,6 +37,7 @@
|
| #include "core/dom/Fullscreen.h"
|
| #include "core/dom/shadow/ShadowRoot.h"
|
| #include "core/events/Event.h"
|
| +#include "core/frame/FrameView.h"
|
| #include "core/frame/LocalFrame.h"
|
| #include "core/frame/Settings.h"
|
| #include "core/frame/UseCounter.h"
|
| @@ -329,14 +330,13 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document& docum
|
| , m_remoteRoutesAvailable(false)
|
| , m_playingRemotely(false)
|
| , m_isFinalizing(false)
|
| - , m_initialPlayWithoutUserGesture(false)
|
| - , m_autoplayMediaCounted(false)
|
| , m_inOverlayFullscreenVideo(false)
|
| , m_audioTracks(AudioTrackList::create(*this))
|
| , m_videoTracks(VideoTrackList::create(*this))
|
| , m_textTracks(nullptr)
|
| , m_audioSourceNode(nullptr)
|
| - , m_autoplayHelper(*this)
|
| + , m_autoplayHelperClient(adoptPtr(new AutoplayHelperClientImpl(this)))
|
| + , m_autoplayHelper(adoptPtr(new AutoplayExperimentHelper(*m_autoplayHelperClient)))
|
| {
|
| #if ENABLE(OILPAN)
|
| ThreadState::current()->registerPreFinalizer(this);
|
| @@ -356,6 +356,12 @@ HTMLMediaElement::~HTMLMediaElement()
|
| {
|
| WTF_LOG(Media, "HTMLMediaElement::~HTMLMediaElement(%p)", this);
|
|
|
| + if (m_autoplayHelper)
|
| + m_autoplayHelper.clear();
|
| +
|
| + if (m_autoplayHelperClient)
|
| + m_autoplayHelperClient.clear();
|
| +
|
| #if !ENABLE(OILPAN)
|
| // HTMLMediaElement and m_asyncEventQueue always become unreachable
|
| // together. So HTMLMediaElement and m_asyncEventQueue are destructed in
|
| @@ -654,47 +660,11 @@ String HTMLMediaElement::canPlayType(const String& mimeType, const String& keySy
|
| return canPlay;
|
| }
|
|
|
| -void HTMLMediaElement::recordMetricsIfPausing()
|
| -{
|
| - // If not playing, then nothing to record.
|
| - // TODO(liberato): test metrics. this was m_paused.
|
| - if (m_paused)
|
| - return;
|
| -
|
| - const bool bailout = isBailout();
|
| -
|
| - // Record that play was paused. We don't care if it was autoplay,
|
| - // play(), or the user manually started it.
|
| - recordAutoplayMetric(AnyPlaybackPaused);
|
| - if (bailout)
|
| - recordAutoplayMetric(AnyPlaybackBailout);
|
| -
|
| - // If this was a gestureless play, then record that separately.
|
| - // These cover attr and play() gestureless starts.
|
| - if (m_initialPlayWithoutUserGesture) {
|
| - m_initialPlayWithoutUserGesture = false;
|
| -
|
| - recordAutoplayMetric(AutoplayPaused);
|
| -
|
| - if (bailout)
|
| - recordAutoplayMetric(AutoplayBailout);
|
| - }
|
| -}
|
| -
|
| void HTMLMediaElement::load()
|
| {
|
| WTF_LOG(Media, "HTMLMediaElement::load(%p)", this);
|
|
|
| - recordMetricsIfPausing();
|
| -
|
| - if (UserGestureIndicator::processingUserGesture() && m_userGestureRequiredForPlay) {
|
| - recordAutoplayMetric(AutoplayEnabledThroughLoad);
|
| - m_userGestureRequiredForPlay = false;
|
| - // While usergesture-initiated load()s technically count as autoplayed,
|
| - // they don't feel like such to the users and hence we don't want to
|
| - // count them for the purposes of metrics.
|
| - m_autoplayMediaCounted = true;
|
| - }
|
| + m_autoplayHelper->loadMethodCalled();
|
|
|
| prepareForLoad();
|
| loadInternal();
|
| @@ -918,6 +888,8 @@ void HTMLMediaElement::loadResource(const KURL& url, ContentType& contentType, c
|
| // The resource fetch algorithm
|
| setNetworkState(NETWORK_LOADING);
|
|
|
| + m_autoplayHelper->loadingStarted();
|
| +
|
| // Set m_currentSrc *before* changing to the cache url, the fact that we are loading from the app
|
| // cache is an internal detail not exposed through the media element API.
|
| m_currentSrc = url;
|
| @@ -944,7 +916,7 @@ void HTMLMediaElement::loadResource(const KURL& url, ContentType& contentType, c
|
|
|
| if (url.protocolIs(mediaSourceBlobProtocol)) {
|
| if (isMediaStreamURL(url.string())) {
|
| - m_userGestureRequiredForPlay = false;
|
| + m_autoplayHelper->removeUserGestureRequirement(GesturelessPlaybackEnabledByStream);
|
| } else {
|
| m_mediaSource = HTMLMediaSource::lookup(url.string());
|
|
|
| @@ -1529,10 +1501,10 @@ void HTMLMediaElement::setReadyState(ReadyState state)
|
| }
|
|
|
| // Check for autoplay, and record metrics about it if needed.
|
| - if (shouldAutoplay(RecordMetricsBehavior::DoRecord)) {
|
| + if (shouldAutoplay(RecordMetricsBehavior::RecordOnSandboxFailure)) {
|
| // If the autoplay experiment says that it's okay to play now,
|
| // then don't require a user gesture.
|
| - m_autoplayHelper.becameReadyToPlay();
|
| + m_autoplayHelper->becameReadyToPlay();
|
|
|
| if (!m_userGestureRequiredForPlay) {
|
| m_paused = false;
|
| @@ -1671,8 +1643,6 @@ void HTMLMediaElement::seek(double time)
|
| // 11 - Set the current playback position to the given new playback position.
|
| webMediaPlayer()->seek(time);
|
|
|
| - m_initialPlayWithoutUserGesture = false;
|
| -
|
| // 14-17 are handled, if necessary, when the engine signals a readystate change or otherwise
|
| // satisfies seek completion and signals a time change.
|
| }
|
| @@ -1854,12 +1824,9 @@ bool HTMLMediaElement::autoplay() const
|
| bool HTMLMediaElement::shouldAutoplay(const RecordMetricsBehavior recordMetrics)
|
| {
|
| if (m_autoplaying && m_paused && autoplay()) {
|
| - if (recordMetrics == RecordMetricsBehavior::DoRecord)
|
| - autoplayMediaEncountered();
|
| -
|
| if (document().isSandboxed(SandboxAutomaticFeatures)) {
|
| - if (recordMetrics == RecordMetricsBehavior::DoRecord)
|
| - recordAutoplayMetric(AutoplayDisabledBySandbox);
|
| + if (recordMetrics == RecordMetricsBehavior::RecordOnSandboxFailure)
|
| + m_autoplayHelper->recordSandboxFailure();
|
| return false;
|
| }
|
|
|
| @@ -1934,21 +1901,19 @@ void HTMLMediaElement::play()
|
| {
|
| WTF_LOG(Media, "HTMLMediaElement::play(%p)", this);
|
|
|
| - m_autoplayHelper.playMethodCalled();
|
| + m_autoplayHelper->playMethodCalled();
|
|
|
| if (!UserGestureIndicator::processingUserGesture()) {
|
| - autoplayMediaEncountered();
|
| -
|
| if (m_userGestureRequiredForPlay) {
|
| recordAutoplayMetric(PlayMethodFailed);
|
| String message = ExceptionMessages::failedToExecute("play", "HTMLMediaElement", "API can only be initiated by a user gesture.");
|
| document().addConsoleMessage(ConsoleMessage::create(JSMessageSource, WarningMessageLevel, message));
|
| return;
|
| }
|
| - } else if (m_userGestureRequiredForPlay) {
|
| - if (m_autoplayMediaCounted)
|
| - recordAutoplayMetric(AutoplayManualStart);
|
| - m_userGestureRequiredForPlay = false;
|
| + } else {
|
| + // We ask the helper to remove the gesture requirement for us, so that
|
| + // it can record the reason.
|
| + m_autoplayHelper->removeUserGestureRequirement(GesturelessPlaybackEnabledByPlayMethod);
|
| }
|
|
|
| playInternal();
|
| @@ -1989,26 +1954,6 @@ void HTMLMediaElement::playInternal()
|
| updatePlayState();
|
| }
|
|
|
| -void HTMLMediaElement::autoplayMediaEncountered()
|
| -{
|
| - if (!m_autoplayMediaCounted) {
|
| - m_autoplayMediaCounted = true;
|
| - recordAutoplayMetric(AutoplayMediaFound);
|
| -
|
| - if (!m_userGestureRequiredForPlay)
|
| - m_initialPlayWithoutUserGesture = true;
|
| - }
|
| -}
|
| -
|
| -bool HTMLMediaElement::isBailout() const
|
| -{
|
| - // We count the user as having bailed-out on the video if they watched
|
| - // less than one minute and less than 50% of it.
|
| - const double playedTime = currentTime();
|
| - const double progress = playedTime / duration();
|
| - return (playedTime < 60) && (progress < 0.5);
|
| -}
|
| -
|
| void HTMLMediaElement::pause()
|
| {
|
| WTF_LOG(Media, "HTMLMediaElement::pause(%p)", this);
|
| @@ -2028,13 +1973,11 @@ void HTMLMediaElement::pauseInternal()
|
| if (m_networkState == NETWORK_EMPTY)
|
| scheduleDelayedAction(LoadMediaResource);
|
|
|
| - m_autoplayHelper.pauseMethodCalled();
|
| + m_autoplayHelper->pauseMethodCalled();
|
|
|
| m_autoplaying = false;
|
|
|
| if (!m_paused) {
|
| - recordMetricsIfPausing();
|
| -
|
| m_paused = true;
|
| scheduleTimeupdateEvent(false);
|
| scheduleEvent(EventTypeNames::pause);
|
| @@ -2126,7 +2069,7 @@ void HTMLMediaElement::setMuted(bool muted)
|
|
|
| m_muted = muted;
|
|
|
| - m_autoplayHelper.mutedChanged();
|
| + m_autoplayHelper->mutedChanged();
|
|
|
| updateVolume();
|
|
|
| @@ -2726,6 +2669,7 @@ void HTMLMediaElement::timeChanged()
|
| // forwards, and paused is false,
|
| if (!m_paused) {
|
| // changes paused to true and fires a simple event named pause at the media element.
|
| + m_autoplayHelper->playbackEnded();
|
| m_paused = true;
|
| scheduleEvent(EventTypeNames::pause);
|
| }
|
| @@ -2734,7 +2678,6 @@ void HTMLMediaElement::timeChanged()
|
| m_sentEndEvent = true;
|
| scheduleEvent(EventTypeNames::ended);
|
| }
|
| - recordMetricsIfPausing();
|
| }
|
| } else {
|
| m_sentEndEvent = false;
|
| @@ -2941,17 +2884,18 @@ void HTMLMediaElement::updatePlayState()
|
| webMediaPlayer()->setRate(playbackRate());
|
| updateVolume();
|
| webMediaPlayer()->play();
|
| + m_autoplayHelper->playbackStarted();
|
| }
|
|
|
| if (mediaControls())
|
| mediaControls()->playbackStarted();
|
| startPlaybackProgressTimer();
|
| m_playing = true;
|
| - recordAutoplayMetric(AnyPlaybackStarted);
|
|
|
| } else { // Should not be playing right now
|
| if (isPlaying)
|
| webMediaPlayer()->pause();
|
| +
|
| refreshCachedTime();
|
|
|
| m_playbackProgressTimer.stop();
|
| @@ -3019,8 +2963,6 @@ void HTMLMediaElement::stop()
|
| {
|
| WTF_LOG(Media, "HTMLMediaElement::stop(%p)", this);
|
|
|
| - recordMetricsIfPausing();
|
| -
|
| // Close the async event queue so that no events are enqueued.
|
| cancelPendingEventsAndCallbacks();
|
| m_asyncEventQueue->close();
|
| @@ -3489,7 +3431,6 @@ DEFINE_TRACE(HTMLMediaElement)
|
| visitor->trace(m_textTracksWhenResourceSelectionBegan);
|
| visitor->trace(m_audioSourceProvider);
|
| visitor->template registerWeakMembers<HTMLMediaElement, &HTMLMediaElement::clearWeakMembers>(this);
|
| - visitor->trace(m_autoplayHelper);
|
| HeapSupplementable<HTMLMediaElement>::trace(visitor);
|
| #endif
|
| HTMLElement::trace(visitor);
|
| @@ -3534,11 +3475,6 @@ void HTMLMediaElement::removeUserGestureRequirement()
|
| m_userGestureRequiredForPlay = false;
|
| }
|
|
|
| -void HTMLMediaElement::setInitialPlayWithoutUserGestures(bool value)
|
| -{
|
| - m_initialPlayWithoutUserGesture = value;
|
| -}
|
| -
|
| void HTMLMediaElement::setNetworkState(NetworkState state)
|
| {
|
| if (m_networkState != state) {
|
| @@ -3550,18 +3486,20 @@ void HTMLMediaElement::setNetworkState(NetworkState state)
|
|
|
| void HTMLMediaElement::notifyPositionMayHaveChanged(const IntRect& visibleRect)
|
| {
|
| - m_autoplayHelper.positionChanged(visibleRect);
|
| + m_autoplayHelper->positionChanged(visibleRect);
|
| }
|
|
|
| void HTMLMediaElement::updatePositionNotificationRegistration()
|
| {
|
| - m_autoplayHelper.updatePositionNotificationRegistration();
|
| + m_autoplayHelper->updatePositionNotificationRegistration();
|
| }
|
|
|
| // TODO(liberato): remove once autoplay gesture override experiment concludes.
|
| void HTMLMediaElement::triggerAutoplayViewportCheckForTesting()
|
| {
|
| - m_autoplayHelper.triggerAutoplayViewportCheckForTesting();
|
| + if (FrameView* view = document().view())
|
| + m_autoplayHelper->positionChanged(view->rootFrameToContents(view->computeVisibleArea()));
|
| + m_autoplayHelper->triggerAutoplayViewportCheckForTesting();
|
| }
|
|
|
| void HTMLMediaElement::clearWeakMembers(Visitor* visitor)
|
| @@ -3630,4 +3568,43 @@ DEFINE_TRACE(HTMLMediaElement::AudioSourceProviderImpl)
|
| visitor->trace(m_client);
|
| }
|
|
|
| +HTMLMediaElement::AutoplayHelperClientImpl::~AutoplayHelperClientImpl()
|
| +{
|
| +}
|
| +
|
| +bool HTMLMediaElement::AutoplayHelperClientImpl::isLegacyViewportType()
|
| +{
|
| + return m_element->document().viewportDescription().isLegacyViewportType();
|
| +}
|
| +
|
| +PageVisibilityState HTMLMediaElement::AutoplayHelperClientImpl::pageVisibilityState() const
|
| +{
|
| + return m_element->document().pageVisibilityState();
|
| +}
|
| +
|
| +String HTMLMediaElement::AutoplayHelperClientImpl::autoplayExperimentMode() const
|
| +{
|
| + String mode;
|
| + if (m_element->document().settings())
|
| + mode = m_element->document().settings()->autoplayExperimentMode();
|
| +
|
| + return mode;
|
| +}
|
| +
|
| +void HTMLMediaElement::AutoplayHelperClientImpl::setRequestPositionUpdates(bool request)
|
| +{
|
| + if (LayoutObject* layoutObject = m_element->layoutObject()) {
|
| + LayoutMedia* layoutMedia = toLayoutMedia(layoutObject);
|
| + layoutMedia->setRequestPositionUpdates(request);
|
| + }
|
| +}
|
| +
|
| +IntRect HTMLMediaElement::AutoplayHelperClientImpl::absoluteBoundingBoxRect() const
|
| +{
|
| + IntRect result;
|
| + if (LayoutObject* object = m_element->layoutObject())
|
| + result = object->absoluteBoundingBoxRect();
|
| + return result;
|
| +}
|
| +
|
| } // namespace blink
|
|
|