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

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: docs 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 // Returns whether |document| is whitelisted for autoplay. If true, the user
28 // gesture lock will be initilized as false, indicating that the element is
29 // allowed to autoplay unmuted without user gesture.
30 bool IsDocumentWhitelisted(Document& document) {
31 DCHECK(document.GetSettings());
32
33 const String& whitelist_scope =
34 document.GetSettings()->GetMediaPlaybackGestureWhitelistScope();
35 if (whitelist_scope.IsNull() || whitelist_scope.IsEmpty())
36 return false;
37
38 return document.Url().GetString().StartsWith(whitelist_scope);
39 }
40
41 // Return true if and only if the document settings specifies media playback
42 // requires user gesture.
43 bool ComputeLockedPendingUserGesture(Document& document) {
44 if (!document.GetSettings())
45 return false;
46
47 if (IsDocumentWhitelisted(document)) {
48 return false;
49 }
50
51 if (document.GetSettings()
52 ->GetCrossOriginMediaPlaybackRequiresUserGesture() &&
53 IsDocumentCrossOrigin(document)) {
54 return true;
55 }
56
57 return document.GetSettings()->GetMediaPlaybackRequiresUserGesture();
58 }
59
60 } // anonymous namespace
61
62 AutoplayPolicy::AutoplayPolicy(HTMLMediaElement* element)
63 : locked_pending_user_gesture_(false),
64 locked_pending_user_gesture_if_cross_origin_experiment_enabled_(true),
65 element_(element),
66 autoplay_visibility_observer_(nullptr),
67 autoplay_uma_helper_(AutoplayUmaHelper::Create(element)) {
68 locked_pending_user_gesture_ =
69 ComputeLockedPendingUserGesture(element->GetDocument());
70 locked_pending_user_gesture_if_cross_origin_experiment_enabled_ =
71 IsDocumentCrossOrigin(element->GetDocument());
72 }
73
74 void AutoplayPolicy::VideoWillBeDrawnToCanvas() const {
75 autoplay_uma_helper_->VideoWillBeDrawnToCanvas();
76 }
77
78 void AutoplayPolicy::DidMoveToNewDocument(Document& old_document) {
79 // If any experiment is enabled, then we want to enable a user gesture by
80 // default, otherwise the experiment does nothing.
81 bool old_document_requires_user_gesture =
82 ComputeLockedPendingUserGesture(old_document);
83 bool new_document_requires_user_gesture =
84 ComputeLockedPendingUserGesture(element_->GetDocument());
85 if (new_document_requires_user_gesture && !old_document_requires_user_gesture)
86 locked_pending_user_gesture_ = true;
87
88 if (IsDocumentCrossOrigin(element_->GetDocument()) &&
89 !IsDocumentCrossOrigin(old_document))
90 locked_pending_user_gesture_if_cross_origin_experiment_enabled_ = true;
91
92 autoplay_uma_helper_->DidMoveToNewDocument(old_document);
93 }
94
95 bool AutoplayPolicy::IsEligibleForAutoplayMuted() const {
96 return element_->IsHTMLVideoElement() && element_->muted() &&
97 RuntimeEnabledFeatures::autoplayMutedVideosEnabled();
98 }
99
100 void AutoplayPolicy::StartAutoplayMutedWhenVisible() {
101 // We might end up in a situation where the previous
102 // observer didn't had time to fire yet. We can avoid
103 // creating a new one in this case.
104 if (autoplay_visibility_observer_)
105 return;
106
107 autoplay_visibility_observer_ = new ElementVisibilityObserver(
108 element_, WTF::Bind(&AutoplayPolicy::OnVisibilityChangedForAutoplay,
109 WrapWeakPersistent(this)));
110 autoplay_visibility_observer_->Start();
111 }
112
113 void AutoplayPolicy::StopAutoplayMutedWhenVisible() {
114 if (!autoplay_visibility_observer_)
115 return;
116
117 autoplay_visibility_observer_->Stop();
118 autoplay_visibility_observer_ = nullptr;
119 }
120
121 bool AutoplayPolicy::RequestAutoplayUnmute() {
122 bool was_autoplaying_muted = IsAutoplayingMuted();
Zhiqiang Zhang (Slow) 2017/04/20 15:36:26 I found why the tests are broken... Actually the
123
124 TryUnlockingUserGesture();
125
126 if (was_autoplaying_muted) {
127 if (IsGestureNeededForPlayback()) {
128 autoplay_uma_helper_->RecordAutoplayUnmuteStatus(
129 AutoplayUnmuteActionStatus::kFailure);
130 return false;
131 }
132 autoplay_uma_helper_->RecordAutoplayUnmuteStatus(
133 AutoplayUnmuteActionStatus::kSuccess);
134 }
135 return true;
136 }
137
138 bool AutoplayPolicy::RequestAutoplayByAttribute() {
139 if (!ShouldAutoplay())
140 return false;
141
142 autoplay_uma_helper_->OnAutoplayInitiated(AutoplaySource::kAttribute);
143
144 if (IsGestureNeededForPlayback()) {
145 autoplay_uma_helper_->RecordCrossOriginAutoplayResult(
146 CrossOriginAutoplayResult::kAutoplayBlocked);
147 return false;
148 }
149
150 if (IsGestureNeededForPlaybackIfCrossOriginExperimentEnabled()) {
151 autoplay_uma_helper_->RecordCrossOriginAutoplayResult(
152 CrossOriginAutoplayResult::kAutoplayBlocked);
153 } else {
154 autoplay_uma_helper_->RecordCrossOriginAutoplayResult(
155 CrossOriginAutoplayResult::kAutoplayAllowed);
156 }
157
158 if (!IsEligibleForAutoplayMuted())
mlamouri (slow - plz ping) 2017/04/20 14:37:27 Maybe add a comment reminding the user that this o
Zhiqiang Zhang (Slow) 2017/04/20 15:36:26 Done.
159 return true;
160
161 // Autoplay muted video should be handled by AutoplayPolicy based on the
162 // visibily.
163 StartAutoplayMutedWhenVisible();
164 return false;
165 }
166
167 Nullable<ExceptionCode> AutoplayPolicy::RequestPlay() {
168 if (!UserGestureIndicator::ProcessingUserGesture()) {
169 autoplay_uma_helper_->OnAutoplayInitiated(AutoplaySource::kMethod);
170 if (IsGestureNeededForPlayback()) {
171 autoplay_uma_helper_->RecordCrossOriginAutoplayResult(
172 CrossOriginAutoplayResult::kAutoplayBlocked);
173 return kNotAllowedError;
174 }
175
176 if (IsGestureNeededForPlaybackIfCrossOriginExperimentEnabled()) {
177 autoplay_uma_helper_->RecordCrossOriginAutoplayResult(
178 CrossOriginAutoplayResult::kAutoplayBlocked);
179 } else {
180 autoplay_uma_helper_->RecordCrossOriginAutoplayResult(
181 CrossOriginAutoplayResult::kAutoplayAllowed);
182 }
183 } else {
184 autoplay_uma_helper_->RecordCrossOriginAutoplayResult(
185 CrossOriginAutoplayResult::kPlayedWithGesture);
186 TryUnlockingUserGesture();
187 }
188
189 return nullptr;
190 }
191
192 bool AutoplayPolicy::IsAutoplayingMuted() const {
193 if (!element_->IsHTMLVideoElement() ||
194 !RuntimeEnabledFeatures::autoplayMutedVideosEnabled()) {
195 return false;
196 }
197
198 return !element_->paused() && element_->muted() &&
199 IsLockedPendingUserGesture();
200 }
201
202 bool AutoplayPolicy::IsLockedPendingUserGesture() const {
203 return locked_pending_user_gesture_;
204 }
205
206 void AutoplayPolicy::TryUnlockingUserGesture() {
207 if (IsLockedPendingUserGesture() &&
208 UserGestureIndicator::UtilizeUserGesture()) {
209 UnlockUserGesture();
210 }
211 }
212
213 void AutoplayPolicy::UnlockUserGesture() {
214 locked_pending_user_gesture_ = false;
215 locked_pending_user_gesture_if_cross_origin_experiment_enabled_ = false;
216 }
217
218 bool AutoplayPolicy::IsGestureNeededForPlayback() const {
219 if (!locked_pending_user_gesture_)
220 return false;
221
222 return IsGestureNeededForPlaybackIfPendingUserGestureIsLocked();
223 }
224
225 bool AutoplayPolicy::IsGestureNeededForPlaybackIfPendingUserGestureIsLocked()
226 const {
227 if (element_->GetLoadType() == WebMediaPlayer::kLoadTypeMediaStream)
228 return false;
229
230 // We want to allow muted video to autoplay if:
231 // - the flag is enabled;
232 // - Data Saver is not enabled;
233 // - Preload was not disabled (low end devices);
234 // - Autoplay is enabled in settings;
235 if (element_->IsHTMLVideoElement() && element_->muted() &&
236 RuntimeEnabledFeatures::autoplayMutedVideosEnabled() &&
237 !(element_->GetDocument().GetSettings() &&
238 element_->GetDocument().GetSettings()->GetDataSaverEnabled()) &&
239 !(element_->GetDocument().GetSettings() &&
240 element_->GetDocument()
241 .GetSettings()
242 ->GetForcePreloadNoneForMediaElements()) &&
243 IsAutoplayAllowedPerSettings()) {
244 return false;
245 }
246
247 return true;
248 }
249
250 void AutoplayPolicy::OnVisibilityChangedForAutoplay(bool is_visible) {
251 if (!is_visible) {
252 if (element_->can_autoplay_ && element_->Autoplay()) {
253 element_->PauseInternal();
254 element_->can_autoplay_ = true;
255 }
256 return;
257 }
258
259 if (ShouldAutoplay()) {
260 element_->paused_ = false;
261 element_->ScheduleEvent(EventTypeNames::play);
262 element_->ScheduleNotifyPlaying();
263
264 element_->UpdatePlayState();
265 }
266 }
267
268 bool AutoplayPolicy::IsGestureNeededForPlaybackIfCrossOriginExperimentEnabled()
269 const {
270 if (!locked_pending_user_gesture_if_cross_origin_experiment_enabled_)
271 return false;
272
273 return IsGestureNeededForPlaybackIfPendingUserGestureIsLocked();
274 }
275
276 bool AutoplayPolicy::IsAutoplayAllowedPerSettings() const {
277 LocalFrame* frame = element_->GetDocument().GetFrame();
278 if (!frame)
279 return false;
280 return frame->GetContentSettingsClient()->AllowAutoplay(true);
281 }
282
283 bool AutoplayPolicy::ShouldAutoplay() {
284 if (element_->GetDocument().IsSandboxed(kSandboxAutomaticFeatures))
285 return false;
286 return element_->can_autoplay_ && element_->paused_ && element_->Autoplay();
287 }
288
289 DEFINE_TRACE(AutoplayPolicy) {
290 visitor->Trace(element_);
291 visitor->Trace(autoplay_visibility_observer_);
292 visitor->Trace(autoplay_uma_helper_);
293 }
294
295 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698