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

Side by Side 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "core/html/media/AutoplayPolicy.h"
6
7 #include "core/dom/Document.h"
8 #include "core/dom/ElementVisibilityObserver.h"
9 #include "core/frame/ContentSettingsClient.h"
10 #include "core/frame/LocalFrame.h"
11 #include "core/frame/Settings.h"
12 #include "core/html/HTMLMediaElement.h"
13 #include "core/html/media/AutoplayUmaHelper.h"
14 #include "platform/RuntimeEnabledFeatures.h"
15 #include "platform/UserGestureIndicator.h"
16 #include "public/platform/WebMediaPlayer.h"
17
18 namespace blink {
19
20 namespace {
21
22 bool IsDocumentCrossOrigin(Document& document) {
23 const LocalFrame* frame = document.GetFrame();
24 return frame && frame->IsCrossOriginSubframe();
25 }
26
27 bool IsDocumentWhitelisted(Document& document) {
28 DCHECK(document.GetSettings());
29
30 const String& whitelist_scope =
31 document.GetSettings()->GetMediaPlaybackGestureWhitelistScope();
32 if (whitelist_scope.IsNull() || whitelist_scope.IsEmpty())
33 return false;
34
35 return document.Url().GetString().StartsWith(whitelist_scope);
36 }
37
38 // Return true if and only if the document settings specifies media playback
39 // requires user gesture.
40 bool ComputeLockedPendingUserGesture(Document& document) {
41 if (!document.GetSettings())
42 return false;
43
44 if (IsDocumentWhitelisted(document)) {
45 return false;
46 }
47
48 if (document.GetSettings()
49 ->GetCrossOriginMediaPlaybackRequiresUserGesture() &&
50 IsDocumentCrossOrigin(document)) {
51 return true;
52 }
53
54 return document.GetSettings()->GetMediaPlaybackRequiresUserGesture();
55 }
56
57 } // anonymous namespace
58
59 AutoplayPolicy::AutoplayPolicy(HTMLMediaElement* element)
60 : locked_pending_user_gesture_(false),
61 locked_pending_user_gesture_if_cross_origin_experiment_enabled_(true),
62 element_(element),
63 autoplay_visibility_observer_(nullptr) {
64 locked_pending_user_gesture_ =
65 ComputeLockedPendingUserGesture(element->GetDocument());
66 locked_pending_user_gesture_if_cross_origin_experiment_enabled_ =
67 IsDocumentCrossOrigin(element->GetDocument());
68 }
69
70 AutoplayPolicy::~AutoplayPolicy() = default;
71
72 void AutoplayPolicy::DidMoveToNewDocument(Document& old_document) {
73 // If any experiment is enabled, then we want to enable a user gesture by
74 // default, otherwise the experiment does nothing.
75 bool old_document_requires_user_gesture =
76 ComputeLockedPendingUserGesture(old_document);
77 bool new_document_requires_user_gesture =
78 ComputeLockedPendingUserGesture(element_->GetDocument());
79 if (new_document_requires_user_gesture && !old_document_requires_user_gesture)
80 locked_pending_user_gesture_ = true;
81
82 if (IsDocumentCrossOrigin(element_->GetDocument()) &&
83 !IsDocumentCrossOrigin(old_document))
84 locked_pending_user_gesture_if_cross_origin_experiment_enabled_ = true;
85 }
86
87 bool AutoplayPolicy::IsEligibleForAutoplayMuted() const {
88 return element_->IsHTMLVideoElement() && element_->muted() &&
89 RuntimeEnabledFeatures::autoplayMutedVideosEnabled();
90 }
91
92 void AutoplayPolicy::StartAutoplayMutedWhenVisible() {
93 // We might end up in a situation where the previous
94 // observer didn't had time to fire yet. We can avoid
95 // creating a new one in this case.
96 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.
97 autoplay_visibility_observer_ = new ElementVisibilityObserver(
98 element_, WTF::Bind(&AutoplayPolicy::OnVisibilityChangedForAutoplay,
99 WrapWeakPersistent(this)));
100 autoplay_visibility_observer_->Start();
101 }
102 }
103
104 void AutoplayPolicy::StopAutoplayMutedWhenVisible() {
105 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.
106 autoplay_visibility_observer_->Stop();
107 autoplay_visibility_observer_ = nullptr;
108 }
109 }
110
111 bool AutoplayPolicy::CheckUnmuteShouldPauseAutoplay() {
112 if (!element_->IsHTMLVideoElement() ||
113 !RuntimeEnabledFeatures::autoplayMutedVideosEnabled()) {
114 return false;
115 }
116 bool result =
117 !element_->paused() && element_->muted() && IsLockedPendingUserGesture();
118 if (result) {
119 element_->autoplay_uma_helper().RecordAutoplayUnmuteStatus(
120 AutoplayUnmuteActionStatus::kFailure);
121 } else {
122 element_->autoplay_uma_helper().RecordAutoplayUnmuteStatus(
123 AutoplayUnmuteActionStatus::kSuccess);
124 }
125 return result;
126 }
127
128 Nullable<ExceptionCode> AutoplayPolicy::CheckPlayMethodAllowed() {
129 if (!UserGestureIndicator::ProcessingUserGesture()) {
130 element_->autoplay_uma_helper().OnAutoplayInitiated(
131 AutoplaySource::kMethod);
132 if (IsGestureNeededForPlayback()) {
133 element_->autoplay_uma_helper().RecordCrossOriginAutoplayResult(
134 CrossOriginAutoplayResult::kAutoplayBlocked);
135 return kNotAllowedError;
136 }
137
138 if (IsGestureNeededForPlaybackIfCrossOriginExperimentEnabled()) {
139 element_->autoplay_uma_helper().RecordCrossOriginAutoplayResult(
140 CrossOriginAutoplayResult::kAutoplayBlocked);
141 } else {
142 element_->autoplay_uma_helper().RecordCrossOriginAutoplayResult(
143 CrossOriginAutoplayResult::kAutoplayAllowed);
144 }
145 } else {
146 element_->autoplay_uma_helper().RecordCrossOriginAutoplayResult(
147 CrossOriginAutoplayResult::kPlayedWithGesture);
148 UserGestureIndicator::UtilizeUserGesture();
149 UnlockUserGesture();
150 }
151 return nullptr;
152 }
153
154 bool AutoplayPolicy::IsAutoplayingMuted() {
155 if (!element_->IsHTMLVideoElement() ||
156 !RuntimeEnabledFeatures::autoplayMutedVideosEnabled()) {
157 return false;
158 }
159
160 return !element_->paused() && element_->muted() &&
161 IsLockedPendingUserGesture();
162 }
163
164 bool AutoplayPolicy::IsLockedPendingUserGesture() const {
165 return locked_pending_user_gesture_;
166 }
167
168 void AutoplayPolicy::TryUnlockingUserGesture() {
169 if (IsLockedPendingUserGesture() &&
170 UserGestureIndicator::UtilizeUserGesture()) {
171 UnlockUserGesture();
172 }
173 }
174
175 void AutoplayPolicy::UnlockUserGesture() {
176 locked_pending_user_gesture_ = false;
177 locked_pending_user_gesture_if_cross_origin_experiment_enabled_ = false;
178 }
179
180 bool AutoplayPolicy::IsGestureNeededForPlayback() const {
181 if (!locked_pending_user_gesture_)
182 return false;
183
184 return IsGestureNeededForPlaybackIfPendingUserGestureIsLocked();
185 }
186
187 bool AutoplayPolicy::IsGestureNeededForPlaybackIfPendingUserGestureIsLocked()
188 const {
189 if (element_->GetLoadType() == WebMediaPlayer::kLoadTypeMediaStream)
190 return false;
191
192 // We want to allow muted video to autoplay if:
193 // - the flag is enabled;
194 // - Data Saver is not enabled;
195 // - Preload was not disabled (low end devices);
196 // - Autoplay is enabled in settings;
197 if (element_->IsHTMLVideoElement() && element_->muted() &&
198 RuntimeEnabledFeatures::autoplayMutedVideosEnabled() &&
199 !(element_->GetDocument().GetSettings() &&
200 element_->GetDocument().GetSettings()->GetDataSaverEnabled()) &&
201 !(element_->GetDocument().GetSettings() &&
202 element_->GetDocument()
203 .GetSettings()
204 ->GetForcePreloadNoneForMediaElements()) &&
205 IsAutoplayAllowedPerSettings()) {
206 return false;
207 }
208
209 return true;
210 }
211
212 void AutoplayPolicy::OnVisibilityChangedForAutoplay(bool is_visible) {
213 if (!is_visible) {
214 if (element_->can_autoplay_ && element_->Autoplay()) {
215 element_->PauseInternal();
216 element_->can_autoplay_ = true;
217 }
218 return;
219 }
220
221 if (element_->ShouldAutoplay()) {
222 element_->paused_ = false;
223 element_->ScheduleEvent(EventTypeNames::play);
224 element_->ScheduleNotifyPlaying();
225
226 element_->UpdatePlayState();
227 }
228 }
229
230 bool AutoplayPolicy::IsGestureNeededForPlaybackIfCrossOriginExperimentEnabled()
231 const {
232 if (!locked_pending_user_gesture_if_cross_origin_experiment_enabled_)
233 return false;
234
235 return IsGestureNeededForPlaybackIfPendingUserGestureIsLocked();
236 }
237
238 bool AutoplayPolicy::IsAutoplayAllowedPerSettings() const {
239 LocalFrame* frame = element_->GetDocument().GetFrame();
240 if (!frame)
241 return false;
242 return frame->GetContentSettingsClient()->AllowAutoplay(true);
243 }
244
245 bool HTMLMediaElement::IsInCrossOriginFrame() const {
246 return IsDocumentCrossOrigin(GetDocument());
247 }
248
249 DEFINE_TRACE(AutoplayPolicy) {
250 visitor->Trace(element_);
251 visitor->Trace(autoplay_visibility_observer_);
252 }
253
254 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698