Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(498)

Unified Diff: third_party/WebKit/Source/core/html/media/AutoplayPolicy.cpp

Issue 2813303005: [Blink>Media] Moving autoplay logic to AutoplayPolicy (Closed)
Patch Set: fixed event order for setMuted and added comments Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/core/html/media/AutoplayPolicy.cpp
diff --git a/third_party/WebKit/Source/core/html/media/AutoplayPolicy.cpp b/third_party/WebKit/Source/core/html/media/AutoplayPolicy.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..286a173c391736ff1c6362ae83054978ed8ad93c
--- /dev/null
+++ b/third_party/WebKit/Source/core/html/media/AutoplayPolicy.cpp
@@ -0,0 +1,254 @@
+// Copyright 2017 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 "core/html/media/AutoplayPolicy.h"
+
+#include "core/dom/Document.h"
+#include "core/dom/ElementVisibilityObserver.h"
+#include "core/frame/ContentSettingsClient.h"
+#include "core/frame/LocalFrame.h"
+#include "core/frame/Settings.h"
+#include "core/html/HTMLMediaElement.h"
+#include "core/html/media/AutoplayUmaHelper.h"
+#include "platform/RuntimeEnabledFeatures.h"
+#include "platform/UserGestureIndicator.h"
+#include "public/platform/WebMediaPlayer.h"
+
+namespace blink {
+
+namespace {
+
+bool IsDocumentCrossOrigin(Document& document) {
+ const LocalFrame* frame = document.GetFrame();
+ return frame && frame->IsCrossOriginSubframe();
+}
+
+bool IsDocumentWhitelisted(Document& document) {
+ DCHECK(document.GetSettings());
+
+ const String& whitelist_scope =
+ document.GetSettings()->GetMediaPlaybackGestureWhitelistScope();
+ if (whitelist_scope.IsNull() || whitelist_scope.IsEmpty())
+ return false;
+
+ return document.Url().GetString().StartsWith(whitelist_scope);
+}
+
+// Return true if and only if the document settings specifies media playback
+// requires user gesture.
+bool ComputeLockedPendingUserGesture(Document& document) {
+ if (!document.GetSettings())
+ return false;
+
+ if (IsDocumentWhitelisted(document)) {
+ return false;
+ }
+
+ if (document.GetSettings()
+ ->GetCrossOriginMediaPlaybackRequiresUserGesture() &&
+ IsDocumentCrossOrigin(document)) {
+ return true;
+ }
+
+ return document.GetSettings()->GetMediaPlaybackRequiresUserGesture();
+}
+
+} // anonymous namespace
+
+AutoplayPolicy::AutoplayPolicy(HTMLMediaElement* element)
+ : locked_pending_user_gesture_(false),
+ locked_pending_user_gesture_if_cross_origin_experiment_enabled_(true),
+ element_(element),
+ autoplay_visibility_observer_(nullptr) {
+ locked_pending_user_gesture_ =
+ ComputeLockedPendingUserGesture(element->GetDocument());
+ locked_pending_user_gesture_if_cross_origin_experiment_enabled_ =
+ IsDocumentCrossOrigin(element->GetDocument());
+}
+
+AutoplayPolicy::~AutoplayPolicy() = default;
+
+void AutoplayPolicy::DidMoveToNewDocument(Document& old_document) {
+ // If any experiment is enabled, then we want to enable a user gesture by
+ // default, otherwise the experiment does nothing.
+ bool old_document_requires_user_gesture =
+ ComputeLockedPendingUserGesture(old_document);
+ bool new_document_requires_user_gesture =
+ ComputeLockedPendingUserGesture(element_->GetDocument());
+ if (new_document_requires_user_gesture && !old_document_requires_user_gesture)
+ locked_pending_user_gesture_ = true;
+
+ if (IsDocumentCrossOrigin(element_->GetDocument()) &&
+ !IsDocumentCrossOrigin(old_document))
+ locked_pending_user_gesture_if_cross_origin_experiment_enabled_ = true;
+}
+
+bool AutoplayPolicy::IsEligibleForAutoplayMuted() const {
+ return element_->IsHTMLVideoElement() && element_->muted() &&
+ RuntimeEnabledFeatures::autoplayMutedVideosEnabled();
+}
+
+void AutoplayPolicy::StartAutoplayMutedWhenVisible() {
+ // We might end up in a situation where the previous
+ // observer didn't had time to fire yet. We can avoid
+ // creating a new one in this case.
+ if (!autoplay_visibility_observer_) {
mlamouri (slow - plz ping) 2017/04/18 13:28:28 Early return?
Zhiqiang Zhang (Slow) 2017/04/18 16:56:44 Done.
+ autoplay_visibility_observer_ = new ElementVisibilityObserver(
+ element_, WTF::Bind(&AutoplayPolicy::OnVisibilityChangedForAutoplay,
+ WrapWeakPersistent(this)));
+ autoplay_visibility_observer_->Start();
+ }
+}
+
+void AutoplayPolicy::StopAutoplayMutedWhenVisible() {
+ if (autoplay_visibility_observer_) {
mlamouri (slow - plz ping) 2017/04/18 13:28:28 ditto
Zhiqiang Zhang (Slow) 2017/04/18 16:56:44 Done.
+ autoplay_visibility_observer_->Stop();
+ autoplay_visibility_observer_ = nullptr;
+ }
+}
+
+bool AutoplayPolicy::CheckUnmuteShouldPauseAutoplay() {
+ if (!element_->IsHTMLVideoElement() ||
+ !RuntimeEnabledFeatures::autoplayMutedVideosEnabled()) {
+ return false;
+ }
+ bool result =
+ !element_->paused() && element_->muted() && IsLockedPendingUserGesture();
+ if (result) {
+ element_->autoplay_uma_helper().RecordAutoplayUnmuteStatus(
+ AutoplayUnmuteActionStatus::kFailure);
+ } else {
+ element_->autoplay_uma_helper().RecordAutoplayUnmuteStatus(
+ AutoplayUnmuteActionStatus::kSuccess);
+ }
+ return result;
+}
+
+Nullable<ExceptionCode> AutoplayPolicy::CheckPlayMethodAllowed() {
+ if (!UserGestureIndicator::ProcessingUserGesture()) {
+ element_->autoplay_uma_helper().OnAutoplayInitiated(
+ AutoplaySource::kMethod);
+ if (IsGestureNeededForPlayback()) {
+ element_->autoplay_uma_helper().RecordCrossOriginAutoplayResult(
+ CrossOriginAutoplayResult::kAutoplayBlocked);
+ return kNotAllowedError;
+ }
+
+ if (IsGestureNeededForPlaybackIfCrossOriginExperimentEnabled()) {
+ element_->autoplay_uma_helper().RecordCrossOriginAutoplayResult(
+ CrossOriginAutoplayResult::kAutoplayBlocked);
+ } else {
+ element_->autoplay_uma_helper().RecordCrossOriginAutoplayResult(
+ CrossOriginAutoplayResult::kAutoplayAllowed);
+ }
+ } else {
+ element_->autoplay_uma_helper().RecordCrossOriginAutoplayResult(
+ CrossOriginAutoplayResult::kPlayedWithGesture);
+ UserGestureIndicator::UtilizeUserGesture();
+ UnlockUserGesture();
+ }
+ return nullptr;
+}
+
+bool AutoplayPolicy::IsAutoplayingMuted() {
+ if (!element_->IsHTMLVideoElement() ||
+ !RuntimeEnabledFeatures::autoplayMutedVideosEnabled()) {
+ return false;
+ }
+
+ return !element_->paused() && element_->muted() &&
+ IsLockedPendingUserGesture();
+}
+
+bool AutoplayPolicy::IsLockedPendingUserGesture() const {
+ return locked_pending_user_gesture_;
+}
+
+void AutoplayPolicy::TryUnlockingUserGesture() {
+ if (IsLockedPendingUserGesture() &&
+ UserGestureIndicator::UtilizeUserGesture()) {
+ UnlockUserGesture();
+ }
+}
+
+void AutoplayPolicy::UnlockUserGesture() {
+ locked_pending_user_gesture_ = false;
+ locked_pending_user_gesture_if_cross_origin_experiment_enabled_ = false;
+}
+
+bool AutoplayPolicy::IsGestureNeededForPlayback() const {
+ if (!locked_pending_user_gesture_)
+ return false;
+
+ return IsGestureNeededForPlaybackIfPendingUserGestureIsLocked();
+}
+
+bool AutoplayPolicy::IsGestureNeededForPlaybackIfPendingUserGestureIsLocked()
+ const {
+ if (element_->GetLoadType() == WebMediaPlayer::kLoadTypeMediaStream)
+ return false;
+
+ // We want to allow muted video to autoplay if:
+ // - the flag is enabled;
+ // - Data Saver is not enabled;
+ // - Preload was not disabled (low end devices);
+ // - Autoplay is enabled in settings;
+ if (element_->IsHTMLVideoElement() && element_->muted() &&
+ RuntimeEnabledFeatures::autoplayMutedVideosEnabled() &&
+ !(element_->GetDocument().GetSettings() &&
+ element_->GetDocument().GetSettings()->GetDataSaverEnabled()) &&
+ !(element_->GetDocument().GetSettings() &&
+ element_->GetDocument()
+ .GetSettings()
+ ->GetForcePreloadNoneForMediaElements()) &&
+ IsAutoplayAllowedPerSettings()) {
+ return false;
+ }
+
+ return true;
+}
+
+void AutoplayPolicy::OnVisibilityChangedForAutoplay(bool is_visible) {
+ if (!is_visible) {
+ if (element_->can_autoplay_ && element_->Autoplay()) {
+ element_->PauseInternal();
+ element_->can_autoplay_ = true;
+ }
+ return;
+ }
+
+ if (element_->ShouldAutoplay()) {
+ element_->paused_ = false;
+ element_->ScheduleEvent(EventTypeNames::play);
+ element_->ScheduleNotifyPlaying();
+
+ element_->UpdatePlayState();
+ }
+}
+
+bool AutoplayPolicy::IsGestureNeededForPlaybackIfCrossOriginExperimentEnabled()
+ const {
+ if (!locked_pending_user_gesture_if_cross_origin_experiment_enabled_)
+ return false;
+
+ return IsGestureNeededForPlaybackIfPendingUserGestureIsLocked();
+}
+
+bool AutoplayPolicy::IsAutoplayAllowedPerSettings() const {
+ LocalFrame* frame = element_->GetDocument().GetFrame();
+ if (!frame)
+ return false;
+ return frame->GetContentSettingsClient()->AllowAutoplay(true);
+}
+
+bool HTMLMediaElement::IsInCrossOriginFrame() const {
+ return IsDocumentCrossOrigin(GetDocument());
+}
+
+DEFINE_TRACE(AutoplayPolicy) {
+ visitor->Trace(element_);
+ visitor->Trace(autoplay_visibility_observer_);
+}
+
+} // namespace blink

Powered by Google App Engine
This is Rietveld 408576698