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

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

Issue 1436783002: Oilpan: tidy up AutoplayExperimentHelper. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 1 month 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 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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 "config.h" 5 #include "config.h"
6 #include "core/html/AutoplayExperimentHelper.h" 6 #include "core/html/AutoplayExperimentHelper.h"
7 7
8 #include "core/dom/Document.h" 8 #include "core/dom/Document.h"
9 #include "core/frame/FrameView.h" 9 #include "core/frame/FrameView.h"
10 #include "core/frame/Settings.h" 10 #include "core/frame/Settings.h"
11 #include "core/html/HTMLMediaElement.h" 11 #include "core/html/HTMLMediaElement.h"
12 #include "core/layout/LayoutBox.h" 12 #include "core/layout/LayoutBox.h"
13 #include "core/layout/LayoutObject.h" 13 #include "core/layout/LayoutObject.h"
14 #include "core/layout/LayoutVideo.h" 14 #include "core/layout/LayoutVideo.h"
15 #include "core/layout/LayoutView.h" 15 #include "core/layout/LayoutView.h"
16 #include "core/page/Page.h" 16 #include "core/page/Page.h"
17 #include "platform/Logging.h" 17 #include "platform/Logging.h"
18 #include "platform/UserGestureIndicator.h" 18 #include "platform/UserGestureIndicator.h"
19 #include "platform/geometry/IntRect.h" 19 #include "platform/geometry/IntRect.h"
20 20
21 namespace blink { 21 namespace blink {
22 22
23 using namespace HTMLNames; 23 using namespace HTMLNames;
24 24
25 // Seconds to wait after a video has stopped moving before playing it. 25 // Seconds to wait after a video has stopped moving before playing it.
26 static const double kViewportTimerPollDelay = 0.5; 26 static const double kViewportTimerPollDelay = 0.5;
27 27
28 AutoplayExperimentHelper::AutoplayExperimentHelper(HTMLMediaElement& element) 28 AutoplayExperimentHelper::AutoplayExperimentHelper(HTMLMediaElement& element)
29 : m_element(element) 29 : m_element(&element)
30 , m_mode(Mode::ExperimentOff) 30 , m_mode(Mode::ExperimentOff)
31 , m_playPending(false) 31 , m_playPending(false)
32 , m_registeredWithLayoutObject(false) 32 , m_registeredWithLayoutObject(false)
33 , m_wasInViewport(false) 33 , m_wasInViewport(false)
34 , m_lastLocationUpdateTime(-std::numeric_limits<double>::infinity()) 34 , m_lastLocationUpdateTime(-std::numeric_limits<double>::infinity())
35 , m_viewportTimer(this, &AutoplayExperimentHelper::viewportTimerFired) 35 , m_viewportTimer(this, &AutoplayExperimentHelper::viewportTimerFired)
36 { 36 {
37 if (document().settings()) { 37 if (document().settings()) {
38 m_mode = fromString(document().settings()->autoplayExperimentMode()); 38 m_mode = fromString(document().settings()->autoplayExperimentMode());
39 39
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
78 // do so. Otherwise, install an event listener if we need one. 78 // do so. Otherwise, install an event listener if we need one.
79 if (meetsVisibilityRequirements()) { 79 if (meetsVisibilityRequirements()) {
80 // Override the gesture and play. 80 // Override the gesture and play.
81 prepareToPlay(GesturelessPlaybackStartedByPlayMethodImmediately) ; 81 prepareToPlay(GesturelessPlaybackStartedByPlayMethodImmediately) ;
82 } else { 82 } else {
83 // Wait for viewport visibility. 83 // Wait for viewport visibility.
84 registerForPositionUpdatesIfNeeded(); 84 registerForPositionUpdatesIfNeeded();
85 } 85 }
86 } 86 }
87 87
88 } else if (m_element.isUserGestureRequiredForPlay()) { 88 } else if (element().isUserGestureRequiredForPlay()) {
89 unregisterForPositionUpdatesIfNeeded(); 89 unregisterForPositionUpdatesIfNeeded();
90 } 90 }
91 } 91 }
92 92
93 void AutoplayExperimentHelper::pauseMethodCalled() 93 void AutoplayExperimentHelper::pauseMethodCalled()
94 { 94 {
95 // Don't try to autoplay, if we would have. 95 // Don't try to autoplay, if we would have.
96 m_playPending = false; 96 m_playPending = false;
97 unregisterForPositionUpdatesIfNeeded(); 97 unregisterForPositionUpdatesIfNeeded();
98 } 98 }
(...skipping 15 matching lines...) Expand all
114 114
115 void AutoplayExperimentHelper::registerForPositionUpdatesIfNeeded() 115 void AutoplayExperimentHelper::registerForPositionUpdatesIfNeeded()
116 { 116 {
117 // If we don't require that the player is in the viewport, then we don't 117 // If we don't require that the player is in the viewport, then we don't
118 // need the listener. 118 // need the listener.
119 if (!enabled(IfViewport)) { 119 if (!enabled(IfViewport)) {
120 if (!enabled(IfPageVisible)) 120 if (!enabled(IfPageVisible))
121 return; 121 return;
122 } 122 }
123 123
124 if (LayoutObject* layoutObject = m_element.layoutObject()) { 124 if (LayoutObject* layoutObject = element().layoutObject()) {
125 LayoutMedia* layoutMedia = toLayoutMedia(layoutObject); 125 LayoutMedia* layoutMedia = toLayoutMedia(layoutObject);
126 layoutMedia->setRequestPositionUpdates(true); 126 layoutMedia->setRequestPositionUpdates(true);
127 } 127 }
128 128
129 // Set this unconditionally, in case we have no layout object yet. 129 // Set this unconditionally, in case we have no layout object yet.
130 m_registeredWithLayoutObject = true; 130 m_registeredWithLayoutObject = true;
131 } 131 }
132 132
133 void AutoplayExperimentHelper::unregisterForPositionUpdatesIfNeeded() 133 void AutoplayExperimentHelper::unregisterForPositionUpdatesIfNeeded()
134 { 134 {
135 if (m_registeredWithLayoutObject) { 135 if (m_registeredWithLayoutObject) {
136 if (LayoutObject* obj = m_element.layoutObject()) { 136 if (LayoutObject* obj = element().layoutObject()) {
137 LayoutMedia* layoutMedia = toLayoutMedia(obj); 137 LayoutMedia* layoutMedia = toLayoutMedia(obj);
138 layoutMedia->setRequestPositionUpdates(false); 138 layoutMedia->setRequestPositionUpdates(false);
139 } 139 }
140 } 140 }
141 141
142 // Clear this unconditionally so that we don't re-register if we didn't 142 // Clear this unconditionally so that we don't re-register if we didn't
143 // have a LayoutObject now, but get one later. 143 // have a LayoutObject now, but get one later.
144 m_registeredWithLayoutObject = false; 144 m_registeredWithLayoutObject = false;
145 } 145 }
146 146
147 void AutoplayExperimentHelper::positionChanged(const IntRect& visibleRect) 147 void AutoplayExperimentHelper::positionChanged(const IntRect& visibleRect)
148 { 148 {
149 // Something, maybe position, has changed. If applicable, start a 149 // Something, maybe position, has changed. If applicable, start a
150 // timer to look for the end of a scroll operation. 150 // timer to look for the end of a scroll operation.
151 // Don't do much work here. 151 // Don't do much work here.
152 // Also note that we are called quite often, including when the 152 // Also note that we are called quite often, including when the
153 // page becomes visible. That's why we don't bother to register 153 // page becomes visible. That's why we don't bother to register
154 // for page visibility changes explicitly. 154 // for page visibility changes explicitly.
155 155
156 m_lastVisibleRect = visibleRect; 156 m_lastVisibleRect = visibleRect;
157 157
158 if (!m_element.layoutObject()) 158 if (!element().layoutObject())
159 return; 159 return;
160 160
161 IntRect currentLocation = m_element.layoutObject()->absoluteBoundingBoxRect( ); 161 IntRect currentLocation = element().layoutObject()->absoluteBoundingBoxRect( );
162 bool inViewport = meetsVisibilityRequirements(); 162 bool inViewport = meetsVisibilityRequirements();
163 163
164 if (m_lastLocation != currentLocation) { 164 if (m_lastLocation != currentLocation) {
165 m_lastLocationUpdateTime = monotonicallyIncreasingTime(); 165 m_lastLocationUpdateTime = monotonicallyIncreasingTime();
166 m_lastLocation = currentLocation; 166 m_lastLocation = currentLocation;
167 } 167 }
168 168
169 if (inViewport && !m_wasInViewport) { 169 if (inViewport && !m_wasInViewport) {
170 // Only reset the timer when we transition from not visible to 170 // Only reset the timer when we transition from not visible to
171 // visible, because resetting the timer isn't cheap. 171 // visible, because resetting the timer isn't cheap.
172 m_viewportTimer.startOneShot(kViewportTimerPollDelay, BLINK_FROM_HERE); 172 m_viewportTimer.startOneShot(kViewportTimerPollDelay, BLINK_FROM_HERE);
173 } 173 }
174 m_wasInViewport = inViewport; 174 m_wasInViewport = inViewport;
175 } 175 }
176 176
177 void AutoplayExperimentHelper::updatePositionNotificationRegistration() 177 void AutoplayExperimentHelper::updatePositionNotificationRegistration()
178 { 178 {
179 if (m_registeredWithLayoutObject) { 179 if (m_registeredWithLayoutObject) {
180 LayoutMedia* layoutMedia = toLayoutMedia(m_element.layoutObject()); 180 LayoutMedia* layoutMedia = toLayoutMedia(element().layoutObject());
181 layoutMedia->setRequestPositionUpdates(true); 181 layoutMedia->setRequestPositionUpdates(true);
182 } 182 }
183 } 183 }
184 184
185 void AutoplayExperimentHelper::triggerAutoplayViewportCheckForTesting() 185 void AutoplayExperimentHelper::triggerAutoplayViewportCheckForTesting()
186 { 186 {
187 FrameView* view = document().view(); 187 FrameView* view = document().view();
188 if (view) 188 if (view)
189 positionChanged(view->rootFrameToContents(view->computeVisibleArea())); 189 positionChanged(view->rootFrameToContents(view->computeVisibleArea()));
190 190
(...skipping 17 matching lines...) Expand all
208 } 208 }
209 209
210 // Sufficient time has passed since the last scroll that we'll 210 // Sufficient time has passed since the last scroll that we'll
211 // treat it as the end of scroll. Autoplay if we should. 211 // treat it as the end of scroll. Autoplay if we should.
212 maybeStartPlaying(); 212 maybeStartPlaying();
213 } 213 }
214 214
215 bool AutoplayExperimentHelper::meetsVisibilityRequirements() const 215 bool AutoplayExperimentHelper::meetsVisibilityRequirements() const
216 { 216 {
217 if (enabled(IfPageVisible) 217 if (enabled(IfPageVisible)
218 && m_element.document().pageVisibilityState() != PageVisibilityStateVisi ble) 218 && element().document().pageVisibilityState() != PageVisibilityStateVisi ble)
219 return false; 219 return false;
220 220
221 if (!enabled(IfViewport)) 221 if (!enabled(IfViewport))
222 return true; 222 return true;
223 223
224 if (m_lastVisibleRect.isEmpty()) 224 if (m_lastVisibleRect.isEmpty())
225 return false; 225 return false;
226 226
227 LayoutObject* layoutObject = m_element.layoutObject(); 227 LayoutObject* layoutObject = element().layoutObject();
228 if (!layoutObject) 228 if (!layoutObject)
229 return false; 229 return false;
230 230
231 IntRect currentLocation = layoutObject->absoluteBoundingBoxRect(); 231 IntRect currentLocation = layoutObject->absoluteBoundingBoxRect();
232 232
233 // If element completely fills the screen, then truncate it to exactly 233 // If element completely fills the screen, then truncate it to exactly
234 // match the screen. Any element that is wider just has to cover. 234 // match the screen. Any element that is wider just has to cover.
235 if (currentLocation.x() <= m_lastVisibleRect.x() 235 if (currentLocation.x() <= m_lastVisibleRect.x()
236 && currentLocation.x() + currentLocation.width() >= m_lastVisibleRect.x( ) + m_lastVisibleRect.width()) { 236 && currentLocation.x() + currentLocation.width() >= m_lastVisibleRect.x( ) + m_lastVisibleRect.width()) {
237 currentLocation.setX(m_lastVisibleRect.x()); 237 currentLocation.setX(m_lastVisibleRect.x());
(...skipping 10 matching lines...) Expand all
248 } 248 }
249 249
250 bool AutoplayExperimentHelper::maybeStartPlaying() 250 bool AutoplayExperimentHelper::maybeStartPlaying()
251 { 251 {
252 // See if we're allowed to autoplay now. 252 // See if we're allowed to autoplay now.
253 if (!isEligible() || !meetsVisibilityRequirements()) { 253 if (!isEligible() || !meetsVisibilityRequirements()) {
254 return false; 254 return false;
255 } 255 }
256 256
257 // Start playing! 257 // Start playing!
258 prepareToPlay(m_element.shouldAutoplay() 258 prepareToPlay(element().shouldAutoplay()
259 ? GesturelessPlaybackStartedByAutoplayFlagAfterScroll 259 ? GesturelessPlaybackStartedByAutoplayFlagAfterScroll
260 : GesturelessPlaybackStartedByPlayMethodAfterScroll); 260 : GesturelessPlaybackStartedByPlayMethodAfterScroll);
261 m_element.playInternal(); 261 element().playInternal();
262 262
263 return true; 263 return true;
264 } 264 }
265 265
266 bool AutoplayExperimentHelper::isEligible() const 266 bool AutoplayExperimentHelper::isEligible() const
267 { 267 {
268 if (m_mode == Mode::ExperimentOff) 268 if (m_mode == Mode::ExperimentOff)
269 return false; 269 return false;
270 270
271 // If no user gesture is required, then the experiment doesn't apply. 271 // If no user gesture is required, then the experiment doesn't apply.
272 // This is what prevents us from starting playback more than once. 272 // This is what prevents us from starting playback more than once.
273 // Since this flag is never set to true once it's cleared, it will block 273 // Since this flag is never set to true once it's cleared, it will block
274 // the autoplay experiment forever. 274 // the autoplay experiment forever.
275 if (!m_element.isUserGestureRequiredForPlay()) 275 if (!element().isUserGestureRequiredForPlay())
276 return false; 276 return false;
277 277
278 // Make sure that this is an element of the right type. 278 // Make sure that this is an element of the right type.
279 if (!enabled(ForVideo) 279 if (!enabled(ForVideo) && isHTMLVideoElement(element()))
280 && isHTMLVideoElement(m_element))
281 return false; 280 return false;
282 281
283 if (!enabled(ForAudio) 282 if (!enabled(ForAudio) && isHTMLAudioElement(element()))
284 && isHTMLAudioElement(m_element))
285 return false; 283 return false;
286 284
287 // If nobody has requested playback, either by the autoplay attribute or 285 // If nobody has requested playback, either by the autoplay attribute or
288 // a play() call, then do nothing. 286 // a play() call, then do nothing.
289 287
290 if (!m_playPending && !m_element.shouldAutoplay()) 288 if (!m_playPending && !element().shouldAutoplay())
291 return false; 289 return false;
292 290
293 // Note that the viewport test always returns false on desktop, which is 291 // Note that the viewport test always returns false on desktop, which is
294 // why video-autoplay-experiment.html doesn't check -ifmobile . 292 // why video-autoplay-experiment.html doesn't check -ifmobile .
295 if (enabled(IfMobile) 293 if (enabled(IfMobile)
296 && !document().viewportDescription().isLegacyViewportType()) 294 && !document().viewportDescription().isLegacyViewportType())
297 return false; 295 return false;
298 296
299 // If we require muted media and this is muted, then it is eligible. 297 // If we require muted media and this is muted, then it is eligible.
300 if (enabled(IfMuted)) 298 if (enabled(IfMuted))
301 return m_element.muted(); 299 return element().muted();
302 300
303 // Element is eligible for gesture override, maybe muted. 301 // Element is eligible for gesture override, maybe muted.
304 return true; 302 return true;
305 } 303 }
306 304
307 void AutoplayExperimentHelper::muteIfNeeded() 305 void AutoplayExperimentHelper::muteIfNeeded()
308 { 306 {
309 if (enabled(PlayMuted)) { 307 if (enabled(PlayMuted)) {
310 ASSERT(!isEligible()); 308 ASSERT(!isEligible());
311 // If we are actually changing the muted state, then this will call 309 // If we are actually changing the muted state, then this will call
312 // mutedChanged(). If isEligible(), then mutedChanged() will try 310 // mutedChanged(). If isEligible(), then mutedChanged() will try
313 // to start playback, which we should not do here. 311 // to start playback, which we should not do here.
314 m_element.setMuted(true); 312 element().setMuted(true);
315 } 313 }
316 } 314 }
317 315
318 void AutoplayExperimentHelper::prepareToPlay(AutoplayMetrics metric) 316 void AutoplayExperimentHelper::prepareToPlay(AutoplayMetrics metric)
319 { 317 {
320 m_element.recordAutoplayMetric(metric); 318 element().recordAutoplayMetric(metric);
321 319
322 // This also causes !isEligible, so that we don't allow autoplay more than 320 // This also causes !isEligible, so that we don't allow autoplay more than
323 // once. Be sure to do this before muteIfNeeded(). 321 // once. Be sure to do this before muteIfNeeded().
324 m_element.removeUserGestureRequirement(); 322 element().removeUserGestureRequirement();
325 323
326 unregisterForPositionUpdatesIfNeeded(); 324 unregisterForPositionUpdatesIfNeeded();
327 muteIfNeeded(); 325 muteIfNeeded();
328 326
329 // Record that this autoplayed without a user gesture. This is normally 327 // Record that this autoplayed without a user gesture. This is normally
330 // set when we discover an autoplay attribute, but we include all cases 328 // set when we discover an autoplay attribute, but we include all cases
331 // where playback started without a user gesture, e.g., play(). 329 // where playback started without a user gesture, e.g., play().
332 m_element.setInitialPlayWithoutUserGestures(true); 330 element().setInitialPlayWithoutUserGestures(true);
333 331
334 // Do not actually start playback here. 332 // Do not actually start playback here.
335 } 333 }
336 334
337 Document& AutoplayExperimentHelper::document() const 335 Document& AutoplayExperimentHelper::document() const
338 { 336 {
339 return m_element.document(); 337 return element().document();
338 }
339
340 HTMLMediaElement& AutoplayExperimentHelper::element() const
341 {
342 ASSERT(m_element);
343 return *m_element;
340 } 344 }
341 345
342 AutoplayExperimentHelper::Mode AutoplayExperimentHelper::fromString(const String & mode) 346 AutoplayExperimentHelper::Mode AutoplayExperimentHelper::fromString(const String & mode)
343 { 347 {
344 Mode value = ExperimentOff; 348 Mode value = ExperimentOff;
345 if (mode.contains("-forvideo")) 349 if (mode.contains("-forvideo"))
346 value |= ForVideo; 350 value |= ForVideo;
347 if (mode.contains("-foraudio")) 351 if (mode.contains("-foraudio"))
348 value |= ForAudio; 352 value |= ForAudio;
349 if (mode.contains("-ifpagevisible")) 353 if (mode.contains("-ifpagevisible"))
350 value |= IfPageVisible; 354 value |= IfPageVisible;
351 if (mode.contains("-ifviewport")) 355 if (mode.contains("-ifviewport"))
352 value |= IfViewport; 356 value |= IfViewport;
353 if (mode.contains("-ifmuted")) 357 if (mode.contains("-ifmuted"))
354 value |= IfMuted; 358 value |= IfMuted;
355 if (mode.contains("-ifmobile")) 359 if (mode.contains("-ifmobile"))
356 value |= IfMobile; 360 value |= IfMobile;
357 if (mode.contains("-playmuted")) 361 if (mode.contains("-playmuted"))
358 value |= PlayMuted; 362 value |= PlayMuted;
359 363
360 return value; 364 return value;
361 } 365 }
362 366
363 } 367 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698