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

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: addressed nits 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) {
mlamouri (slow - plz ping) 2017/04/19 14:09:55 nit: add comment explaining what this is doing?
Zhiqiang Zhang (Slow) 2017/04/20 10:30:45 Done.
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 autoplay_uma_helper_(AutoplayUmaHelper::Create(element)) {
65 locked_pending_user_gesture_ =
66 ComputeLockedPendingUserGesture(element->GetDocument());
67 locked_pending_user_gesture_if_cross_origin_experiment_enabled_ =
68 IsDocumentCrossOrigin(element->GetDocument());
69 }
70
71 void AutoplayPolicy::VideoWillBeDrawnToCanvas() const {
72 autoplay_uma_helper_->VideoWillBeDrawnToCanvas();
73 }
74
75 void AutoplayPolicy::DidMoveToNewDocument(Document& old_document) {
76 // If any experiment is enabled, then we want to enable a user gesture by
77 // default, otherwise the experiment does nothing.
78 bool old_document_requires_user_gesture =
79 ComputeLockedPendingUserGesture(old_document);
80 bool new_document_requires_user_gesture =
81 ComputeLockedPendingUserGesture(element_->GetDocument());
82 if (new_document_requires_user_gesture && !old_document_requires_user_gesture)
83 locked_pending_user_gesture_ = true;
84
85 if (IsDocumentCrossOrigin(element_->GetDocument()) &&
86 !IsDocumentCrossOrigin(old_document))
87 locked_pending_user_gesture_if_cross_origin_experiment_enabled_ = true;
88
89 autoplay_uma_helper_->DidMoveToNewDocument(old_document);
90 }
91
92 bool AutoplayPolicy::IsEligibleForAutoplayMuted() const {
93 return element_->IsHTMLVideoElement() && element_->muted() &&
94 RuntimeEnabledFeatures::autoplayMutedVideosEnabled();
95 }
96
97 void AutoplayPolicy::StartAutoplayMutedWhenVisible() {
98 // We might end up in a situation where the previous
99 // observer didn't had time to fire yet. We can avoid
100 // creating a new one in this case.
101 if (autoplay_visibility_observer_)
102 return;
103
104 autoplay_visibility_observer_ = new ElementVisibilityObserver(
105 element_, WTF::Bind(&AutoplayPolicy::OnVisibilityChangedForAutoplay,
106 WrapWeakPersistent(this)));
107 autoplay_visibility_observer_->Start();
108 }
109
110 void AutoplayPolicy::StopAutoplayMutedWhenVisible() {
111 if (!autoplay_visibility_observer_)
112 return;
113
114 autoplay_visibility_observer_->Stop();
115 autoplay_visibility_observer_ = nullptr;
116 }
117
118 bool AutoplayPolicy::RequestAutoplayUnmute() {
119 if (!element_->IsHTMLVideoElement() ||
120 !RuntimeEnabledFeatures::autoplayMutedVideosEnabled()) {
121 return false;
122 }
123 bool result =
124 !element_->paused() && element_->muted() && IsLockedPendingUserGesture();
125 if (result) {
126 autoplay_uma_helper_->RecordAutoplayUnmuteStatus(
127 AutoplayUnmuteActionStatus::kFailure);
128 } else {
129 autoplay_uma_helper_->RecordAutoplayUnmuteStatus(
130 AutoplayUnmuteActionStatus::kSuccess);
131 }
132 return result;
133 }
134
135 bool AutoplayPolicy::RequestAutoplayByAttribute() {
136 if (ShouldAutoplay()) {
mlamouri (slow - plz ping) 2017/04/19 14:09:55 maybe an early return would be better? :)
Zhiqiang Zhang (Slow) 2017/04/20 10:30:45 Done. Also moved the code a bit to make the logic
137 autoplay_uma_helper_->OnAutoplayInitiated(AutoplaySource::kAttribute);
138
139 if (!IsGestureNeededForPlayback()) {
140 if (IsGestureNeededForPlaybackIfCrossOriginExperimentEnabled()) {
141 autoplay_uma_helper_->RecordCrossOriginAutoplayResult(
142 CrossOriginAutoplayResult::kAutoplayBlocked);
143 } else {
144 autoplay_uma_helper_->RecordCrossOriginAutoplayResult(
145 CrossOriginAutoplayResult::kAutoplayAllowed);
146 }
147 if (IsEligibleForAutoplayMuted())
148 StartAutoplayMutedWhenVisible();
149 else
150 return true;
151 } else {
152 autoplay_uma_helper_->RecordCrossOriginAutoplayResult(
153 CrossOriginAutoplayResult::kAutoplayBlocked);
154 }
155 }
156 return false;
157 }
158
159 Nullable<ExceptionCode> AutoplayPolicy::RequestPlay() {
160 if (!UserGestureIndicator::ProcessingUserGesture()) {
161 autoplay_uma_helper_->OnAutoplayInitiated(AutoplaySource::kMethod);
162 if (IsGestureNeededForPlayback()) {
163 autoplay_uma_helper_->RecordCrossOriginAutoplayResult(
164 CrossOriginAutoplayResult::kAutoplayBlocked);
165 return kNotAllowedError;
166 }
167
168 if (IsGestureNeededForPlaybackIfCrossOriginExperimentEnabled()) {
169 autoplay_uma_helper_->RecordCrossOriginAutoplayResult(
170 CrossOriginAutoplayResult::kAutoplayBlocked);
171 } else {
172 autoplay_uma_helper_->RecordCrossOriginAutoplayResult(
173 CrossOriginAutoplayResult::kAutoplayAllowed);
174 }
175 } else {
176 autoplay_uma_helper_->RecordCrossOriginAutoplayResult(
177 CrossOriginAutoplayResult::kPlayedWithGesture);
178 UserGestureIndicator::UtilizeUserGesture();
179 UnlockUserGesture();
180 }
181 return nullptr;
mlamouri (slow - plz ping) 2017/04/19 14:09:55 empty line above?
Zhiqiang Zhang (Slow) 2017/04/20 10:30:45 Done.
182 }
183
184 bool AutoplayPolicy::IsAutoplayingMuted() {
185 if (!element_->IsHTMLVideoElement() ||
186 !RuntimeEnabledFeatures::autoplayMutedVideosEnabled()) {
187 return false;
188 }
189
190 return !element_->paused() && element_->muted() &&
191 IsLockedPendingUserGesture();
192 }
193
194 bool AutoplayPolicy::IsLockedPendingUserGesture() const {
195 return locked_pending_user_gesture_;
mlamouri (slow - plz ping) 2017/04/19 14:09:55 stupid question: I know it's a copy-paste from the
Zhiqiang Zhang (Slow) 2017/04/20 10:30:45 We shouldn't consider locked_pending_user_gesture_
196 }
197
198 void AutoplayPolicy::TryUnlockingUserGesture() {
199 if (IsLockedPendingUserGesture() &&
200 UserGestureIndicator::UtilizeUserGesture()) {
201 UnlockUserGesture();
202 }
203 }
204
205 void AutoplayPolicy::UnlockUserGesture() {
206 locked_pending_user_gesture_ = false;
207 locked_pending_user_gesture_if_cross_origin_experiment_enabled_ = false;
208 }
209
210 bool AutoplayPolicy::IsGestureNeededForPlayback() const {
211 if (!locked_pending_user_gesture_)
212 return false;
213
214 return IsGestureNeededForPlaybackIfPendingUserGestureIsLocked();
215 }
216
217 bool AutoplayPolicy::IsGestureNeededForPlaybackIfPendingUserGestureIsLocked()
218 const {
219 if (element_->GetLoadType() == WebMediaPlayer::kLoadTypeMediaStream)
220 return false;
221
222 // We want to allow muted video to autoplay if:
223 // - the flag is enabled;
224 // - Data Saver is not enabled;
225 // - Preload was not disabled (low end devices);
226 // - Autoplay is enabled in settings;
227 if (element_->IsHTMLVideoElement() && element_->muted() &&
228 RuntimeEnabledFeatures::autoplayMutedVideosEnabled() &&
229 !(element_->GetDocument().GetSettings() &&
230 element_->GetDocument().GetSettings()->GetDataSaverEnabled()) &&
231 !(element_->GetDocument().GetSettings() &&
232 element_->GetDocument()
233 .GetSettings()
234 ->GetForcePreloadNoneForMediaElements()) &&
235 IsAutoplayAllowedPerSettings()) {
236 return false;
237 }
238
239 return true;
240 }
241
242 void AutoplayPolicy::OnVisibilityChangedForAutoplay(bool is_visible) {
243 if (!is_visible) {
244 if (element_->can_autoplay_ && element_->Autoplay()) {
245 element_->PauseInternal();
246 element_->can_autoplay_ = true;
247 }
248 return;
249 }
250
251 if (ShouldAutoplay()) {
252 element_->paused_ = false;
253 element_->ScheduleEvent(EventTypeNames::play);
254 element_->ScheduleNotifyPlaying();
255
256 element_->UpdatePlayState();
257 }
258 }
259
260 bool AutoplayPolicy::IsGestureNeededForPlaybackIfCrossOriginExperimentEnabled()
261 const {
262 if (!locked_pending_user_gesture_if_cross_origin_experiment_enabled_)
263 return false;
264
265 return IsGestureNeededForPlaybackIfPendingUserGestureIsLocked();
266 }
267
268 bool AutoplayPolicy::IsAutoplayAllowedPerSettings() const {
269 LocalFrame* frame = element_->GetDocument().GetFrame();
270 if (!frame)
271 return false;
272 return frame->GetContentSettingsClient()->AllowAutoplay(true);
273 }
274
275 bool AutoplayPolicy::ShouldAutoplay() {
276 if (element_->GetDocument().IsSandboxed(kSandboxAutomaticFeatures))
277 return false;
278 return element_->can_autoplay_ && element_->paused_ && element_->Autoplay();
279 }
280
281 DEFINE_TRACE(AutoplayPolicy) {
282 visitor->Trace(element_);
283 visitor->Trace(autoplay_visibility_observer_);
284 visitor->Trace(autoplay_uma_helper_);
285 }
286
287 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698