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

Side by Side Diff: third_party/WebKit/Source/core/html/AutoplayExperimentHelper.cpp

Issue 1949633002: Don't remove the gesture requirement in the autoplay experiment. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: comments. Created 4 years, 7 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
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "core/html/AutoplayExperimentHelper.h" 5 #include "core/html/AutoplayExperimentHelper.h"
6 6
7 #include "core/dom/Document.h" 7 #include "core/dom/Document.h"
8 #include "core/frame/Settings.h" 8 #include "core/frame/Settings.h"
9 #include "core/html/HTMLMediaElement.h" 9 #include "core/html/HTMLMediaElement.h"
10 #include "core/layout/LayoutBox.h" 10 #include "core/layout/LayoutBox.h"
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
64 autoplayMediaEncountered(); 64 autoplayMediaEncountered();
65 65
66 if (isEligible()) { 66 if (isEligible()) {
67 if (meetsVisibilityRequirements()) 67 if (meetsVisibilityRequirements())
68 prepareToAutoplay(GesturelessPlaybackStartedByAutoplayFlagImmediatel y); 68 prepareToAutoplay(GesturelessPlaybackStartedByAutoplayFlagImmediatel y);
69 else 69 else
70 registerForPositionUpdatesIfNeeded(); 70 registerForPositionUpdatesIfNeeded();
71 } 71 }
72 } 72 }
73 73
74 void AutoplayExperimentHelper::playMethodCalled() 74 void AutoplayExperimentHelper::playMethodCalled(bool playing)
75 { 75 {
76 // Set the pending state, even if the play isn't going to be pending. 76 // If a play is already pending, then do nothing. We're already trying
77 // Eligibility can change if, for example, the mute status changes. 77 // to play. Similarly, do nothing if we're already playing.
78 // Having this set is okay. 78 if (m_playPending || playing)
79 m_playPending = true; 79 return;
80 80
81 if (!UserGestureIndicator::utilizeUserGesture()) { 81 if (!UserGestureIndicator::utilizeUserGesture()) {
82 autoplayMediaEncountered(); 82 autoplayMediaEncountered();
83 83
84 if (isEligible()) { 84 // Check for eligibility, but don't worry if playback is currently
85 // Remember that userGestureRequiredForPlay is required for 85 // pending. If we're still not eligible, then this play() will fail.
86 // us to be eligible for the experiment. 86 if (isEligible(IgnorePendingPlayback)) {
87 m_playPending = true;
88
87 // If we are able to override the gesture requirement now, then 89 // If we are able to override the gesture requirement now, then
88 // do so. Otherwise, install an event listener if we need one. 90 // do so. Otherwise, install an event listener if we need one.
91 // We do not actually start playback; play() will do that.
89 if (meetsVisibilityRequirements()) { 92 if (meetsVisibilityRequirements()) {
90 // Override the gesture and assume that play() will succeed. 93 // Override the gesture and assume that play() will succeed.
91 prepareToAutoplay(GesturelessPlaybackStartedByPlayMethodImmediat ely); 94 prepareToAutoplay(GesturelessPlaybackStartedByPlayMethodImmediat ely);
92 } else { 95 } else {
93 // Wait for viewport visibility. 96 // Wait for viewport visibility.
97 // TODO(liberato): if the autoplay is allowed soon enough, then
98 // it should still record *Immediately. Otherwise, we end up
99 // here before the first layout sometimes, when the item is
100 // visible but we just don't know that yet.
94 registerForPositionUpdatesIfNeeded(); 101 registerForPositionUpdatesIfNeeded();
95 } 102 }
96 } 103 }
97 } else if (isUserGestureRequiredForPlay()) { 104 } else if (isLockedPendingUserGesture()) {
98 // If this media tried to autoplay, and we haven't played it yet, then 105 // If this media tried to autoplay, and we haven't played it yet, then
99 // record that the user provided the gesture to start it the first time. 106 // record that the user provided the gesture to start it the first time.
100 if (m_autoplayMediaEncountered && !m_playbackStartedMetricRecorded) 107 if (m_autoplayMediaEncountered && !m_playbackStartedMetricRecorded)
101 recordAutoplayMetric(AutoplayManualStart); 108 recordAutoplayMetric(AutoplayManualStart);
102 // Don't let future gestureless playbacks affect metrics. 109 // Don't let future gestureless playbacks affect metrics.
103 m_autoplayMediaEncountered = true; 110 m_autoplayMediaEncountered = true;
104 m_playbackStartedMetricRecorded = true; 111 m_playbackStartedMetricRecorded = true;
112 m_playPending = false;
105 113
106 unregisterForPositionUpdatesIfNeeded(); 114 unregisterForPositionUpdatesIfNeeded();
107 } 115 }
108 } 116 }
109 117
110 void AutoplayExperimentHelper::pauseMethodCalled() 118 void AutoplayExperimentHelper::pauseMethodCalled()
111 { 119 {
112 // Don't try to autoplay, if we would have. 120 // Don't try to autoplay, if we would have.
113 m_playPending = false; 121 m_playPending = false;
114 unregisterForPositionUpdatesIfNeeded(); 122 unregisterForPositionUpdatesIfNeeded();
115 } 123 }
116 124
117 void AutoplayExperimentHelper::loadMethodCalled() 125 void AutoplayExperimentHelper::loadMethodCalled()
118 { 126 {
119 if (isUserGestureRequiredForPlay() && UserGestureIndicator::utilizeUserGestu re()) { 127 if (isLockedPendingUserGesture() && UserGestureIndicator::utilizeUserGesture ()) {
120 recordAutoplayMetric(AutoplayEnabledThroughLoad); 128 recordAutoplayMetric(AutoplayEnabledThroughLoad);
121 removeUserGestureRequirement(GesturelessPlaybackEnabledByLoad); 129 removeUserGestureRequirement(GesturelessPlaybackEnabledByLoad);
122 } 130 }
123 } 131 }
124 132
125 void AutoplayExperimentHelper::mutedChanged()
126 {
127 // If we are no longer eligible for the autoplay experiment, then also
128 // quit listening for events. If we are eligible, and if we should be
129 // playing, then start playing. In other words, start playing if
130 // we just needed 'mute' to autoplay.
131
132 // Make sure that autoplay was actually deferred. If, for example, the
133 // autoplay attribute is set after the media is ready to play, then it
134 // would normally have no effect. We don't want to start playing.
135 if (!m_autoplayMediaEncountered)
136 return;
137
138 if (!isEligible()) {
139 unregisterForPositionUpdatesIfNeeded();
140 } else {
141 // Try to play. If we can't, then install a listener.
142 if (!maybeStartPlaying())
143 registerForPositionUpdatesIfNeeded();
144 }
145 }
146
147 void AutoplayExperimentHelper::registerForPositionUpdatesIfNeeded() 133 void AutoplayExperimentHelper::registerForPositionUpdatesIfNeeded()
148 { 134 {
149 // If we don't require that the player is in the viewport, then we don't 135 // If we don't require that the player is in the viewport, then we don't
150 // need the listener. 136 // need the listener.
151 if (!requiresViewportVisibility()) { 137 if (!requiresViewportVisibility()) {
152 if (!enabled(IfPageVisible)) 138 if (!enabled(IfPageVisible))
153 return; 139 return;
154 } 140 }
155 141
156 m_client->setRequestPositionUpdates(true); 142 m_client->setRequestPositionUpdates(true);
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
268 currentLocation.setY(m_lastVisibleRect.y()); 254 currentLocation.setY(m_lastVisibleRect.y());
269 currentLocation.setHeight(m_lastVisibleRect.height()); 255 currentLocation.setHeight(m_lastVisibleRect.height());
270 } 256 }
271 257
272 return m_lastVisibleRect.contains(currentLocation); 258 return m_lastVisibleRect.contains(currentLocation);
273 } 259 }
274 260
275 bool AutoplayExperimentHelper::maybeStartPlaying() 261 bool AutoplayExperimentHelper::maybeStartPlaying()
276 { 262 {
277 // See if we're allowed to autoplay now. 263 // See if we're allowed to autoplay now.
278 if (!isEligible() || !meetsVisibilityRequirements()) { 264 if (!isGestureRequirementOverridden())
279 return false; 265 return false;
280 }
281 266
282 // Start playing! 267 // Start playing!
283 prepareToAutoplay(client().shouldAutoplay() 268 prepareToAutoplay(client().shouldAutoplay()
284 ? GesturelessPlaybackStartedByAutoplayFlagAfterScroll 269 ? GesturelessPlaybackStartedByAutoplayFlagAfterScroll
285 : GesturelessPlaybackStartedByPlayMethodAfterScroll); 270 : GesturelessPlaybackStartedByPlayMethodAfterScroll);
286 271
287 // Record that this played without a user gesture. 272 // Record that this played without a user gesture.
288 // This should rarely actually do anything. Usually, playMethodCalled() 273 // This should rarely actually do anything. Usually, playMethodCalled()
289 // and becameReadyToPlay will handle it, but toggling muted state can, 274 // and becameReadyToPlay will handle it, but toggling muted state can,
290 // in some cases, also trigger autoplay if the autoplay attribute is set 275 // in some cases, also trigger autoplay if the autoplay attribute is set
291 // after the media is ready to play. 276 // after the media is ready to play.
292 autoplayMediaEncountered(); 277 autoplayMediaEncountered();
293 278
294 client().playInternal(); 279 client().playInternal();
295 280
296 return true; 281 return true;
297 } 282 }
298 283
299 bool AutoplayExperimentHelper::isEligible() const 284 bool AutoplayExperimentHelper::isGestureRequirementOverridden() const
285 {
286 return isEligible() && meetsVisibilityRequirements();
287 }
288
289 bool AutoplayExperimentHelper::isPlaybackDeferred() const
290 {
291 return m_playPending;
292 }
293
294 bool AutoplayExperimentHelper::isEligible(EligibilityMode mode) const
300 { 295 {
301 if (m_mode == Mode::ExperimentOff) 296 if (m_mode == Mode::ExperimentOff)
302 return false; 297 return false;
303 298
304 // If autoplay is disabled, no one is eligible. 299 // If autoplay is disabled, no one is eligible.
305 if (!client().isAutoplayAllowedPerSettings()) 300 if (!client().isAutoplayAllowedPerSettings())
306 return false; 301 return false;
307 302
308 // If no user gesture is required, then the experiment doesn't apply. 303 // If no user gesture is required, then the experiment doesn't apply.
309 // This is what prevents us from starting playback more than once. 304 // This is what prevents us from starting playback more than once.
310 // Since this flag is never set to true once it's cleared, it will block 305 // Since this flag is never set to true once it's cleared, it will block
311 // the autoplay experiment forever. 306 // the autoplay experiment forever.
312 if (!isUserGestureRequiredForPlay()) 307 if (!isLockedPendingUserGesture())
313 return false; 308 return false;
314 309
315 // Make sure that this is an element of the right type. 310 // Make sure that this is an element of the right type.
316 if (!enabled(ForVideo) && client().isHTMLVideoElement()) 311 if (!enabled(ForVideo) && client().isHTMLVideoElement())
317 return false; 312 return false;
318 313
319 if (!enabled(ForAudio) && client().isHTMLAudioElement()) 314 if (!enabled(ForAudio) && client().isHTMLAudioElement())
320 return false; 315 return false;
321 316
322 // If nobody has requested playback, either by the autoplay attribute or 317 // If nobody has requested playback, either by the autoplay attribute or
323 // a play() call, then do nothing. 318 // a play() call, then do nothing.
324 319
325 if (!m_playPending && !client().shouldAutoplay()) 320 if (mode != IgnorePendingPlayback && !m_playPending && !client().shouldAuto play())
326 return false; 321 return false;
327 322
328 // Note that the viewport test always returns false on desktop, which is 323 // Note that the viewport test always returns false on desktop, which is
329 // why video-autoplay-experiment.html doesn't check -ifmobile . 324 // why video-autoplay-experiment.html doesn't check -ifmobile .
330 if (enabled(IfMobile) 325 if (enabled(IfMobile)
331 && !client().isLegacyViewportType()) 326 && !client().isLegacyViewportType())
332 return false; 327 return false;
333 328
334 // If we require same-origin, then check the origin. 329 // If we require same-origin, then check the origin.
335 if (enabled(IfSameOrigin) && client().isCrossOrigin()) 330 if (enabled(IfSameOrigin) && client().isCrossOrigin())
(...skipping 13 matching lines...) Expand all
349 ASSERT(!isEligible()); 344 ASSERT(!isEligible());
350 // If we are actually changing the muted state, then this will call 345 // If we are actually changing the muted state, then this will call
351 // mutedChanged(). If isEligible(), then mutedChanged() will try 346 // mutedChanged(). If isEligible(), then mutedChanged() will try
352 // to start playback, which we should not do here. 347 // to start playback, which we should not do here.
353 client().setMuted(true); 348 client().setMuted(true);
354 } 349 }
355 } 350 }
356 351
357 void AutoplayExperimentHelper::removeUserGestureRequirement(AutoplayMetrics metr ic) 352 void AutoplayExperimentHelper::removeUserGestureRequirement(AutoplayMetrics metr ic)
358 { 353 {
359 if (client().isUserGestureRequiredForPlay()) { 354 // Note that this could be moved back into HTMLMediaElement fairly easily.
360 m_autoplayDeferredMetric = metric; 355 // It's only here so that we can record the reason, and we can hide the
356 // ordering between unlocking and recording from the element this way.
357 if (client().isLockedPendingUserGesture()) {
358 setDeferredOverrideReason(metric);
361 client().removeUserGestureRequirement(); 359 client().removeUserGestureRequirement();
362 } 360 }
363 } 361 }
364 362
363 void AutoplayExperimentHelper::setDeferredOverrideReason(AutoplayMetrics metric)
364 {
365 // If the player is unlocked, then we don't care about any later reason.
366 if (client().isLockedPendingUserGesture())
367 m_autoplayDeferredMetric = metric;
368 }
369
365 void AutoplayExperimentHelper::prepareToAutoplay(AutoplayMetrics metric) 370 void AutoplayExperimentHelper::prepareToAutoplay(AutoplayMetrics metric)
366 { 371 {
367 // This also causes !isEligible, so that we don't allow autoplay more than 372 // This also causes !isEligible, so that we don't allow autoplay more than
368 // once. Be sure to do this before muteIfNeeded(). 373 // once. Be sure to do this before muteIfNeeded().
369 // Also note that, at this point, we know that we're goint to start 374 // Also note that, at this point, we know that we're goint to start
370 // playback. However, we still don't record the metric here. Instead, 375 // playback. However, we still don't record the metric here. Instead,
371 // we let playbackStarted() do that later. 376 // we let playbackStarted() do that later.
372 removeUserGestureRequirement(metric); 377 setDeferredOverrideReason(metric);
373 378
374 // Don't bother to call autoplayMediaEncountered, since whoever initiates 379 // Don't bother to call autoplayMediaEncountered, since whoever initiates
375 // playback has do it anyway, in case we don't allow autoplay. 380 // playback has do it anyway, in case we don't allow autoplay.
376 381
377 unregisterForPositionUpdatesIfNeeded(); 382 unregisterForPositionUpdatesIfNeeded();
378 muteIfNeeded(); 383 muteIfNeeded();
379 384
380 // Do not actually start playback here. 385 // Do not actually start playback here.
381 } 386 }
382 387
(...skipping 28 matching lines...) Expand all
411 } 416 }
412 417
413 void AutoplayExperimentHelper::autoplayMediaEncountered() 418 void AutoplayExperimentHelper::autoplayMediaEncountered()
414 { 419 {
415 if (!m_autoplayMediaEncountered) { 420 if (!m_autoplayMediaEncountered) {
416 m_autoplayMediaEncountered = true; 421 m_autoplayMediaEncountered = true;
417 recordAutoplayMetric(AutoplayMediaFound); 422 recordAutoplayMetric(AutoplayMediaFound);
418 } 423 }
419 } 424 }
420 425
421 bool AutoplayExperimentHelper::isUserGestureRequiredForPlay() const 426 bool AutoplayExperimentHelper::isLockedPendingUserGesture() const
422 { 427 {
423 return client().isUserGestureRequiredForPlay(); 428 return client().isLockedPendingUserGesture();
424 } 429 }
425 430
426 void AutoplayExperimentHelper::playbackStarted() 431 void AutoplayExperimentHelper::playbackStarted()
427 { 432 {
428 recordAutoplayMetric(AnyPlaybackStarted); 433 recordAutoplayMetric(AnyPlaybackStarted);
429 434
435 // Forget about our most recent visibility check. If another override is
436 // requested, then we'll have to refresh it. That way, we don't need to
437 // keep it up to date in the interim.
438 m_lastVisibleRect = IntRect();
439 m_wasInViewport = false;
440
441 // Any pending play is now playing.
442 m_playPending = false;
443
430 if (m_playbackStartedMetricRecorded) 444 if (m_playbackStartedMetricRecorded)
431 return; 445 return;
432 446
447 // Whether we record anything or not, we only want to record metrics for
448 // the initial playback.
433 m_playbackStartedMetricRecorded = true; 449 m_playbackStartedMetricRecorded = true;
434 450
435 // If this is a gestureless start, record why it was allowed. 451 // If this is a gestureless start, record why it was allowed.
436 if (!UserGestureIndicator::processingUserGesture()) { 452 if (!UserGestureIndicator::processingUserGesture()) {
437 m_waitingForAutoplayPlaybackEnd = true; 453 m_waitingForAutoplayPlaybackEnd = true;
438 recordAutoplayMetric(m_autoplayDeferredMetric); 454 recordAutoplayMetric(m_autoplayDeferredMetric);
439 } 455 }
440 } 456 }
441 457
442 void AutoplayExperimentHelper::playbackStopped() 458 void AutoplayExperimentHelper::playbackStopped()
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
499 { 515 {
500 return enabled(IfViewport) || enabled(IfPartialViewport); 516 return enabled(IfViewport) || enabled(IfPartialViewport);
501 } 517 }
502 518
503 bool AutoplayExperimentHelper::isExperimentEnabled() 519 bool AutoplayExperimentHelper::isExperimentEnabled()
504 { 520 {
505 return m_mode != Mode::ExperimentOff; 521 return m_mode != Mode::ExperimentOff;
506 } 522 }
507 523
508 } // namespace blink 524 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698