| Index: Source/core/html/AutoplayExperimentHelper.cpp
|
| diff --git a/Source/core/html/AutoplayExperimentHelper.cpp b/Source/core/html/AutoplayExperimentHelper.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..3aa5811dc2c6c232404f8dea9fbf040b989ce8f1
|
| --- /dev/null
|
| +++ b/Source/core/html/AutoplayExperimentHelper.cpp
|
| @@ -0,0 +1,180 @@
|
| +// Copyright 2015 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "config.h"
|
| +#include "core/html/AutoplayExperimentHelper.h"
|
| +
|
| +#include "core/dom/Document.h"
|
| +#include "core/frame/Settings.h"
|
| +#include "core/html/HTMLMediaElement.h"
|
| +#include "core/layout/LayoutBox.h"
|
| +#include "core/layout/LayoutObject.h"
|
| +#include "core/layout/LayoutVideo.h"
|
| +#include "core/layout/LayoutView.h"
|
| +#include "core/page/Page.h"
|
| +#include "platform/Logging.h"
|
| +#include "platform/UserGestureIndicator.h"
|
| +#include "platform/geometry/IntRect.h"
|
| +
|
| +namespace blink {
|
| +
|
| +using namespace HTMLNames;
|
| +
|
| +AutoplayExperimentHelper::AutoplayExperimentHelper(HTMLMediaElement& element)
|
| + : m_element(element)
|
| + , m_mode(AutoplayExperimentConfig::Mode::Off)
|
| + , m_playPending(false)
|
| +{
|
| + if (document().settings()) {
|
| + m_mode = AutoplayExperimentConfig::fromString(document().settings()->autoplayExperimentMode());
|
| +
|
| + if (m_mode != AutoplayExperimentConfig::Mode::Off) {
|
| + WTF_LOG(Media, "HTMLMediaElement: autoplay experiment set to %d",
|
| + m_mode);
|
| + }
|
| + }
|
| +}
|
| +
|
| +AutoplayExperimentHelper::~AutoplayExperimentHelper()
|
| +{
|
| +}
|
| +
|
| +void AutoplayExperimentHelper::becameReadyToPlay()
|
| +{
|
| + // Assuming that we're eligible to override the user gesture requirement,
|
| + // then play.
|
| + if (isEligible()) {
|
| + prepareToPlay(GesturelessPlaybackStartedByAutoplayFlagImmediately);
|
| + }
|
| +}
|
| +
|
| +void AutoplayExperimentHelper::playMethodCalled()
|
| +{
|
| + // Set the pending state, even if the play isn't going to be pending.
|
| + // Eligibility can change if, for example, the mute status changes.
|
| + // Having this set is okay.
|
| + m_playPending = true;
|
| +
|
| + if (!UserGestureIndicator::processingUserGesture()) {
|
| +
|
| + if (isEligible()) {
|
| + // Remember that userGestureRequiredForPlay is required for
|
| + // us to be eligible for the experiment.
|
| + // We are able to override the gesture requirement now, so
|
| + // do so.
|
| + prepareToPlay(GesturelessPlaybackStartedByPlayMethodImmediately);
|
| + }
|
| +
|
| + }
|
| +}
|
| +
|
| +void AutoplayExperimentHelper::pauseMethodCalled()
|
| +{
|
| + // Don't try to autoplay, if we would have.
|
| + m_playPending = false;
|
| +}
|
| +
|
| +void AutoplayExperimentHelper::mutedChanged()
|
| +{
|
| + // In other words, start playing if we just needed 'mute' to autoplay.
|
| + maybeStartPlaying();
|
| +}
|
| +
|
| +bool AutoplayExperimentHelper::maybeStartPlaying()
|
| +{
|
| + // See if we're allowed to autoplay now.
|
| + if (!isEligible()) {
|
| + return false;
|
| + }
|
| +
|
| + // Start playing!
|
| + prepareToPlay(m_element.shouldAutoplay()
|
| + ? GesturelessPlaybackStartedByAutoplayFlagAfterScroll
|
| + : GesturelessPlaybackStartedByPlayMethodAfterScroll);
|
| + m_element.playInternal();
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool AutoplayExperimentHelper::isEligible() const
|
| +{
|
| + // If no user gesture is required, then the experiment doesn't apply.
|
| + // This is what prevents us from starting playback more than once.
|
| + // Since this flag is never set to true once it's cleared, it will block
|
| + // the autoplay experiment forever.
|
| + if (!m_element.isUserGestureRequiredForPlay())
|
| + return false;
|
| +
|
| + if (m_mode == AutoplayExperimentConfig::Mode::Off)
|
| + return false;
|
| +
|
| + // Make sure that this is an element of the right type.
|
| + if (!enabled(AutoplayExperimentConfig::Mode::ForVideo)
|
| + && isHTMLVideoElement(m_element))
|
| + return false;
|
| +
|
| + if (!enabled(AutoplayExperimentConfig::Mode::ForAudio)
|
| + && isHTMLAudioElement(m_element))
|
| + return false;
|
| +
|
| + // If nobody has requested playback, either by the autoplay attribute or
|
| + // a play() call, then do nothing.
|
| + if (!m_playPending && !m_element.shouldAutoplay())
|
| + return false;
|
| +
|
| + // If the video is already playing, then do nothing. Note that there
|
| + // is not a path where a user gesture is required but the video is
|
| + // playing. However, we check for completeness.
|
| + if (!m_element.paused())
|
| + return false;
|
| +
|
| + // Note that the viewport test always returns false on desktop, which is
|
| + // why video-autoplay-experiment.html doesn't check -ifmobile .
|
| + if (enabled(AutoplayExperimentConfig::Mode::IfMobile)
|
| + && !document().viewportDescription().isLegacyViewportType())
|
| + return false;
|
| +
|
| + // If media is muted, then autoplay when it comes into view.
|
| + if (enabled(AutoplayExperimentConfig::Mode::IfMuted))
|
| + return m_element.muted();
|
| +
|
| + // Autoplay when it comes into view (if needed), maybe muted.
|
| + return true;
|
| +}
|
| +
|
| +void AutoplayExperimentHelper::muteIfNeeded()
|
| +{
|
| + if (enabled(AutoplayExperimentConfig::Mode::PlayMuted)) {
|
| + ASSERT(!isEligible());
|
| + // If we are actually changing the muted state, then this will call
|
| + // mutedChanged(). If isEligible(), then mutedChanged() will try
|
| + // to start playback, which we should not do here.
|
| + m_element.setMuted(true);
|
| + }
|
| +}
|
| +
|
| +void AutoplayExperimentHelper::prepareToPlay(AutoplayMetrics metric)
|
| +{
|
| + m_element.recordAutoplayMetric(metric);
|
| +
|
| + // This also causes !isEligible, so that we don't allow autoplay more than
|
| + // once. Be sure to do this before muteIfNeeded().
|
| + m_element.removeUserGestureRequirement();
|
| +
|
| + muteIfNeeded();
|
| +
|
| + // Record that this autoplayed without a user gesture. This is normally
|
| + // set when we discover an autoplay attribute, but we include all cases
|
| + // where playback started without a user gesture, e.g., play().
|
| + m_element.setInitialPlayWithoutUserGestures(true);
|
| +
|
| + // Do not actually start playback here.
|
| +}
|
| +
|
| +Document& AutoplayExperimentHelper::document() const
|
| +{
|
| + return m_element.document();
|
| +}
|
| +
|
| +}
|
|
|