OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved. | 2 * Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
242 // when used with parameters, e.g. "application/octet-stream;codecs=theora", is a type that the user agent knows | 242 // when used with parameters, e.g. "application/octet-stream;codecs=theora", is a type that the user agent knows |
243 // it cannot render. | 243 // it cannot render. |
244 if (contentMIMEType != "application/octet-stream" || contentTypeCodecs.isEmp ty()) { | 244 if (contentMIMEType != "application/octet-stream" || contentTypeCodecs.isEmp ty()) { |
245 WebMimeRegistry::SupportsType supported = Platform::current()->mimeRegis try()->supportsMediaMIMEType(contentMIMEType, contentTypeCodecs, keySystem.lower ()); | 245 WebMimeRegistry::SupportsType supported = Platform::current()->mimeRegis try()->supportsMediaMIMEType(contentMIMEType, contentTypeCodecs, keySystem.lower ()); |
246 return supported > WebMimeRegistry::IsNotSupported; | 246 return supported > WebMimeRegistry::IsNotSupported; |
247 } | 247 } |
248 | 248 |
249 return false; | 249 return false; |
250 } | 250 } |
251 | 251 |
252 // These values are used for a histogram. Do not reorder. | 252 void HTMLMediaElement::recordAutoplayMetric(AutoplayMetrics metric) |
253 enum AutoplayMetrics { | |
254 // Media element with autoplay seen. | |
255 AutoplayMediaFound = 0, | |
256 // Autoplay enabled and user stopped media play at any point. | |
257 AutoplayStopped = 1, | |
258 // Autoplay enabled but user bailed out on media play early. | |
259 AutoplayBailout = 2, | |
260 // Autoplay disabled but user manually started media. | |
261 AutoplayManualStart = 3, | |
262 // Autoplay was (re)enabled through a user-gesture triggered load() | |
263 AutoplayEnabledThroughLoad = 4, | |
264 // Autoplay disabled by sandbox flags. | |
265 AutoplayDisabledBySandbox = 5, | |
266 // This enum value must be last. | |
267 NumberOfAutoplayMetrics, | |
268 }; | |
269 | |
270 static void recordAutoplayMetric(AutoplayMetrics metric) | |
271 { | 253 { |
272 Platform::current()->histogramEnumeration("Blink.MediaElement.Autoplay", met ric, NumberOfAutoplayMetrics); | 254 Platform::current()->histogramEnumeration("Blink.MediaElement.Autoplay", met ric, NumberOfAutoplayMetrics); |
273 } | 255 } |
274 | 256 |
275 WebMimeRegistry::SupportsType HTMLMediaElement::supportsType(const ContentType& contentType, const String& keySystem) | 257 WebMimeRegistry::SupportsType HTMLMediaElement::supportsType(const ContentType& contentType, const String& keySystem) |
276 { | 258 { |
277 DEFINE_STATIC_LOCAL(const String, codecs, ("codecs")); | 259 DEFINE_STATIC_LOCAL(const String, codecs, ("codecs")); |
278 | 260 |
279 if (!RuntimeEnabledFeatures::mediaEnabled()) | 261 if (!RuntimeEnabledFeatures::mediaEnabled()) |
280 return WebMimeRegistry::IsNotSupported; | 262 return WebMimeRegistry::IsNotSupported; |
(...skipping 10 matching lines...) Expand all Loading... | |
291 // 4.8.10.3 MIME types - The canPlayType(type) method must return the empty string if type is a type that the | 273 // 4.8.10.3 MIME types - The canPlayType(type) method must return the empty string if type is a type that the |
292 // user agent knows it cannot render or is the type "application/octet-strea m" | 274 // user agent knows it cannot render or is the type "application/octet-strea m" |
293 if (type == "application/octet-stream") | 275 if (type == "application/octet-stream") |
294 return WebMimeRegistry::IsNotSupported; | 276 return WebMimeRegistry::IsNotSupported; |
295 | 277 |
296 return Platform::current()->mimeRegistry()->supportsMediaMIMEType(type, type Codecs, system); | 278 return Platform::current()->mimeRegistry()->supportsMediaMIMEType(type, type Codecs, system); |
297 } | 279 } |
298 | 280 |
299 URLRegistry* HTMLMediaElement::s_mediaStreamRegistry = 0; | 281 URLRegistry* HTMLMediaElement::s_mediaStreamRegistry = 0; |
300 | 282 |
283 class HTMLMediaElement::AutoplayExperimentScrollListener : public EventListener { | |
284 public: | |
285 AutoplayExperimentScrollListener(HTMLMediaElement* element) : EventListe ner(CPPEventListenerType), m_element(element) { } | |
286 virtual bool operator==(const EventListener& them) | |
287 { | |
288 return &them == this; | |
289 } | |
290 | |
291 void handleEvent(ExecutionContext*, Event*) override | |
292 { | |
293 if (m_element) | |
294 m_element->autoplayExperimentMaybeStartPlaying(); | |
295 } | |
296 | |
297 private: | |
298 HTMLMediaElement* m_element; | |
299 }; | |
300 | |
301 void HTMLMediaElement::setMediaStreamRegistry(URLRegistry* registry) | 301 void HTMLMediaElement::setMediaStreamRegistry(URLRegistry* registry) |
302 { | 302 { |
303 ASSERT(!s_mediaStreamRegistry); | 303 ASSERT(!s_mediaStreamRegistry); |
304 s_mediaStreamRegistry = registry; | 304 s_mediaStreamRegistry = registry; |
305 } | 305 } |
306 | 306 |
307 bool HTMLMediaElement::isMediaStreamURL(const String& url) | 307 bool HTMLMediaElement::isMediaStreamURL(const String& url) |
308 { | 308 { |
309 return s_mediaStreamRegistry ? s_mediaStreamRegistry->contains(url) : false; | 309 return s_mediaStreamRegistry ? s_mediaStreamRegistry->contains(url) : false; |
310 } | 310 } |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
352 , m_completelyLoaded(false) | 352 , m_completelyLoaded(false) |
353 , m_havePreparedToPlay(false) | 353 , m_havePreparedToPlay(false) |
354 , m_tracksAreReady(true) | 354 , m_tracksAreReady(true) |
355 , m_haveVisibleTextTrack(false) | 355 , m_haveVisibleTextTrack(false) |
356 , m_processingPreferenceChange(false) | 356 , m_processingPreferenceChange(false) |
357 , m_remoteRoutesAvailable(false) | 357 , m_remoteRoutesAvailable(false) |
358 , m_playingRemotely(false) | 358 , m_playingRemotely(false) |
359 , m_isFinalizing(false) | 359 , m_isFinalizing(false) |
360 , m_initialPlayWithoutUserGestures(false) | 360 , m_initialPlayWithoutUserGestures(false) |
361 , m_autoplayMediaCounted(false) | 361 , m_autoplayMediaCounted(false) |
362 , m_autoplayExperimentPlayPending(false) | |
363 , m_autoplayExperimentStartedByExperiment(false) | |
364 , m_autoplayExperimentMode(ExperimentOff) | |
362 , m_audioTracks(AudioTrackList::create(*this)) | 365 , m_audioTracks(AudioTrackList::create(*this)) |
363 , m_videoTracks(VideoTrackList::create(*this)) | 366 , m_videoTracks(VideoTrackList::create(*this)) |
364 , m_textTracks(nullptr) | 367 , m_textTracks(nullptr) |
365 #if ENABLE(WEB_AUDIO) | 368 #if ENABLE(WEB_AUDIO) |
366 , m_audioSourceNode(nullptr) | 369 , m_audioSourceNode(nullptr) |
367 #endif | 370 #endif |
368 { | 371 { |
369 #if ENABLE(OILPAN) | 372 #if ENABLE(OILPAN) |
370 ThreadState::current()->registerPreFinalizer(this); | 373 ThreadState::current()->registerPreFinalizer(this); |
371 #endif | 374 #endif |
372 ASSERT(RuntimeEnabledFeatures::mediaEnabled()); | 375 ASSERT(RuntimeEnabledFeatures::mediaEnabled()); |
373 | 376 |
374 WTF_LOG(Media, "HTMLMediaElement::HTMLMediaElement(%p)", this); | 377 WTF_LOG(Media, "HTMLMediaElement::HTMLMediaElement(%p)", this); |
375 | 378 |
376 if (document.settings() && document.settings()->mediaPlaybackRequiresUserGes ture()) | 379 if (document.settings() && document.settings()->mediaPlaybackRequiresUserGes ture()) |
377 m_userGestureRequiredForPlay = true; | 380 m_userGestureRequiredForPlay = true; |
378 | 381 |
382 if (document.settings()) { | |
383 const String& autoplayMode = document.settings()->autoplayExperimentMode (); | |
384 if (autoplayMode == "always") { | |
385 m_autoplayExperimentMode = ExperimentAlways; | |
386 } else if (autoplayMode == "if-muted") { | |
387 m_autoplayExperimentMode = ExperimentIfMuted; | |
388 } else if (autoplayMode == "play-muted") { | |
389 m_autoplayExperimentMode = ExperimentPlayMuted; | |
390 } | |
391 | |
392 if (m_autoplayExperimentMode != ExperimentOff) { | |
393 WTF_LOG(Media, "HTMLMediaElement: autoplay experiment set to '%s'", | |
394 autoplayMode.ascii().data()); | |
395 } | |
396 } | |
397 | |
379 setHasCustomStyleCallbacks(); | 398 setHasCustomStyleCallbacks(); |
380 addElementToDocumentMap(this, &document); | 399 addElementToDocumentMap(this, &document); |
381 } | 400 } |
382 | 401 |
383 HTMLMediaElement::~HTMLMediaElement() | 402 HTMLMediaElement::~HTMLMediaElement() |
384 { | 403 { |
385 WTF_LOG(Media, "HTMLMediaElement::~HTMLMediaElement(%p)", this); | 404 WTF_LOG(Media, "HTMLMediaElement::~HTMLMediaElement(%p)", this); |
405 | |
406 autoplayExperimentClearScrollListenerIfNeeded(); | |
407 | |
386 #if !ENABLE(OILPAN) | 408 #if !ENABLE(OILPAN) |
387 // HTMLMediaElement and m_asyncEventQueue always become unreachable | 409 // HTMLMediaElement and m_asyncEventQueue always become unreachable |
388 // together. So HTMLMediaElement and m_asyncEventQueue are destructed in | 410 // together. So HTMLMediaElement and m_asyncEventQueue are destructed in |
389 // the same GC. We don't need to close it explicitly in Oilpan. | 411 // the same GC. We don't need to close it explicitly in Oilpan. |
390 m_asyncEventQueue->close(); | 412 m_asyncEventQueue->close(); |
391 | 413 |
392 setShouldDelayLoadEvent(false); | 414 setShouldDelayLoadEvent(false); |
393 | 415 |
394 if (m_textTracks) | 416 if (m_textTracks) |
395 m_textTracks->clearOwner(); | 417 m_textTracks->clearOwner(); |
(...skipping 1120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1516 scheduleEvent(EventTypeNames::canplay); | 1538 scheduleEvent(EventTypeNames::canplay); |
1517 if (isPotentiallyPlaying) | 1539 if (isPotentiallyPlaying) |
1518 scheduleEvent(EventTypeNames::playing); | 1540 scheduleEvent(EventTypeNames::playing); |
1519 } | 1541 } |
1520 | 1542 |
1521 if (m_autoplaying && m_paused && autoplay()) { | 1543 if (m_autoplaying && m_paused && autoplay()) { |
1522 autoplayMediaEncountered(); | 1544 autoplayMediaEncountered(); |
1523 | 1545 |
1524 if (document().isSandboxed(SandboxAutomaticFeatures)) { | 1546 if (document().isSandboxed(SandboxAutomaticFeatures)) { |
1525 recordAutoplayMetric(AutoplayDisabledBySandbox); | 1547 recordAutoplayMetric(AutoplayDisabledBySandbox); |
1526 } else if (!m_userGestureRequiredForPlay) { | 1548 } else { |
1527 m_paused = false; | 1549 // If the autoplay experiment says that it's okay to play now, |
1528 invalidateCachedTime(); | 1550 // then don't require a user gesture. |
1529 scheduleEvent(EventTypeNames::play); | 1551 if (autoplayExperimentIsEligible()) { |
1530 scheduleEvent(EventTypeNames::playing); | 1552 if (autoplayExperimentIsVisible()) { |
1553 autoplayExperimentPrepareToPlay(AutoplayExperimentStarte dByLoad); | |
1554 // Will play below. | |
1555 } else { | |
1556 // Wait for visibility checks to pass. | |
1557 autoplayExperimentInstallScrollListenerIfNeeded(); | |
1558 } | |
1559 } | |
1560 | |
1561 if (!m_userGestureRequiredForPlay) { | |
1562 m_paused = false; | |
1563 invalidateCachedTime(); | |
1564 scheduleEvent(EventTypeNames::play); | |
1565 scheduleEvent(EventTypeNames::playing); | |
1566 } | |
1531 } | 1567 } |
1532 } | 1568 } |
1533 | 1569 |
1534 scheduleEvent(EventTypeNames::canplaythrough); | 1570 scheduleEvent(EventTypeNames::canplaythrough); |
1535 | 1571 |
1536 shouldUpdateDisplayState = true; | 1572 shouldUpdateDisplayState = true; |
1537 } | 1573 } |
1538 | 1574 |
1539 if (shouldUpdateDisplayState) { | 1575 if (shouldUpdateDisplayState) { |
1540 updateDisplayState(); | 1576 updateDisplayState(); |
(...skipping 378 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1919 | 1955 |
1920 MediaPlayer::Preload HTMLMediaElement::effectivePreloadType() const | 1956 MediaPlayer::Preload HTMLMediaElement::effectivePreloadType() const |
1921 { | 1957 { |
1922 return autoplay() ? MediaPlayer::Auto : preloadType(); | 1958 return autoplay() ? MediaPlayer::Auto : preloadType(); |
1923 } | 1959 } |
1924 | 1960 |
1925 void HTMLMediaElement::play() | 1961 void HTMLMediaElement::play() |
1926 { | 1962 { |
1927 WTF_LOG(Media, "HTMLMediaElement::play(%p)", this); | 1963 WTF_LOG(Media, "HTMLMediaElement::play(%p)", this); |
1928 | 1964 |
1965 // Set the pending state, even if the play isn't going to be pending. | |
1966 // Eligibility can change if, for example, the mute status changes. | |
1967 // Having this set is okay. | |
1968 m_autoplayExperimentPlayPending = true; | |
1969 | |
1929 if (!UserGestureIndicator::processingUserGesture()) { | 1970 if (!UserGestureIndicator::processingUserGesture()) { |
1930 autoplayMediaEncountered(); | 1971 autoplayMediaEncountered(); |
1972 | |
1973 if (autoplayExperimentIsEligible()) { | |
1974 // Remember that m_userGestureRequiredForPlay is required for | |
1975 // us to be eligible for the experiment. | |
1976 // If we are able to override the gesture requirement now, then | |
1977 // do so. Otherwise, install a scroll listener if we need one. | |
1978 if (autoplayExperimentIsVisible()) { | |
1979 // Override the gesture and play. | |
1980 autoplayExperimentPrepareToPlay(AutoplayExperimentStartedByPlay) ; | |
1981 } else { | |
1982 // Wait for visibility. | |
1983 autoplayExperimentInstallScrollListenerIfNeeded(); | |
1984 } | |
1985 } | |
1986 | |
1931 if (m_userGestureRequiredForPlay) { | 1987 if (m_userGestureRequiredForPlay) { |
1932 String message = ExceptionMessages::failedToExecute("play", "HTMLMed iaElement", "API can only be initiated by a user gesture."); | 1988 String message = ExceptionMessages::failedToExecute("play", "HTMLMed iaElement", "API can only be initiated by a user gesture."); |
1933 document().executionContext()->addConsoleMessage(ConsoleMessage::cre ate(JSMessageSource, WarningMessageLevel, message)); | 1989 document().executionContext()->addConsoleMessage(ConsoleMessage::cre ate(JSMessageSource, WarningMessageLevel, message)); |
1934 return; | 1990 return; |
1935 } | 1991 } |
1936 } else if (m_userGestureRequiredForPlay) { | 1992 } else if (m_userGestureRequiredForPlay) { |
1937 if (m_autoplayMediaCounted) | 1993 if (m_autoplayMediaCounted) |
1938 recordAutoplayMetric(AutoplayManualStart); | 1994 recordAutoplayMetric(AutoplayManualStart); |
1939 m_userGestureRequiredForPlay = false; | 1995 m_userGestureRequiredForPlay = false; |
1996 autoplayExperimentClearScrollListenerIfNeeded(); | |
1940 } | 1997 } |
1941 | 1998 |
1942 playInternal(); | 1999 playInternal(); |
1943 } | 2000 } |
1944 | 2001 |
1945 void HTMLMediaElement::playInternal() | 2002 void HTMLMediaElement::playInternal() |
1946 { | 2003 { |
1947 WTF_LOG(Media, "HTMLMediaElement::playInternal(%p)", this); | 2004 WTF_LOG(Media, "HTMLMediaElement::playInternal(%p)", this); |
1948 | 2005 |
1949 // 4.8.10.9. Playing the media resource | 2006 // 4.8.10.9. Playing the media resource |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1986 } | 2043 } |
1987 } | 2044 } |
1988 | 2045 |
1989 void HTMLMediaElement::gesturelessInitialPlayHalted() | 2046 void HTMLMediaElement::gesturelessInitialPlayHalted() |
1990 { | 2047 { |
1991 ASSERT(m_initialPlayWithoutUserGestures); | 2048 ASSERT(m_initialPlayWithoutUserGestures); |
1992 m_initialPlayWithoutUserGestures = false; | 2049 m_initialPlayWithoutUserGestures = false; |
1993 | 2050 |
1994 recordAutoplayMetric(AutoplayStopped); | 2051 recordAutoplayMetric(AutoplayStopped); |
1995 | 2052 |
2053 if (m_autoplayExperimentStartedByExperiment) | |
2054 recordAutoplayMetric(AutoplayExperimentStopped); | |
2055 | |
1996 // We count the user as having bailed-out on the video if they watched | 2056 // We count the user as having bailed-out on the video if they watched |
1997 // less than one minute and less than 50% of it. | 2057 // less than one minute and less than 50% of it. |
1998 double playedTime = currentTime(); | 2058 double playedTime = currentTime(); |
1999 if (playedTime < 60) { | 2059 if (playedTime < 60) { |
2000 double progress = playedTime / duration(); | 2060 double progress = playedTime / duration(); |
2001 if (progress < 0.5) | 2061 if (progress < 0.5) { |
2002 recordAutoplayMetric(AutoplayBailout); | 2062 recordAutoplayMetric(AutoplayBailout); |
2063 // If this autoplay was started by the experiment, then record | |
2064 // that separately. | |
2065 if (m_autoplayExperimentStartedByExperiment) | |
2066 recordAutoplayMetric(AutoplayExperimentBailout); | |
2067 } | |
2003 } | 2068 } |
2004 } | 2069 } |
2005 | 2070 |
2006 void HTMLMediaElement::pause() | 2071 void HTMLMediaElement::pause() |
2007 { | 2072 { |
2008 WTF_LOG(Media, "HTMLMediaElement::pause(%p)", this); | 2073 WTF_LOG(Media, "HTMLMediaElement::pause(%p)", this); |
2009 | 2074 |
2010 if (!m_player || m_networkState == NETWORK_EMPTY) | 2075 if (!m_player || m_networkState == NETWORK_EMPTY) |
2011 scheduleDelayedAction(LoadMediaResource); | 2076 scheduleDelayedAction(LoadMediaResource); |
2012 | 2077 |
2078 // Don't try to autoplay, if we would have. | |
2079 m_autoplayExperimentPlayPending = false; | |
2080 autoplayExperimentClearScrollListenerIfNeeded(); | |
2081 | |
2013 m_autoplaying = false; | 2082 m_autoplaying = false; |
2014 | 2083 |
2015 if (!m_paused) { | 2084 if (!m_paused) { |
2016 if (m_initialPlayWithoutUserGestures) | 2085 if (m_initialPlayWithoutUserGestures) |
2017 gesturelessInitialPlayHalted(); | 2086 gesturelessInitialPlayHalted(); |
2018 | 2087 |
2019 m_paused = true; | 2088 m_paused = true; |
2020 scheduleTimeupdateEvent(false); | 2089 scheduleTimeupdateEvent(false); |
2021 scheduleEvent(EventTypeNames::pause); | 2090 scheduleEvent(EventTypeNames::pause); |
2022 } | 2091 } |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2100 | 2169 |
2101 void HTMLMediaElement::setMuted(bool muted) | 2170 void HTMLMediaElement::setMuted(bool muted) |
2102 { | 2171 { |
2103 WTF_LOG(Media, "HTMLMediaElement::setMuted(%p, %s)", this, boolString(muted) ); | 2172 WTF_LOG(Media, "HTMLMediaElement::setMuted(%p, %s)", this, boolString(muted) ); |
2104 | 2173 |
2105 if (m_muted == muted) | 2174 if (m_muted == muted) |
2106 return; | 2175 return; |
2107 | 2176 |
2108 m_muted = muted; | 2177 m_muted = muted; |
2109 | 2178 |
2179 // If we are no longer eligible for the autoplay experiment, then also | |
2180 // quit listening to scroll events. If we are eligible, and if we should | |
2181 // be playing, then start playing. In other words, start playing if | |
2182 // we just needed 'mute' to autoplay. | |
2183 if (!autoplayExperimentIsEligible()) { | |
2184 autoplayExperimentClearScrollListenerIfNeeded(); | |
2185 } else { | |
2186 // Try to play. If we can't, then install a visibility listener. | |
2187 if (!autoplayExperimentMaybeStartPlaying()) | |
2188 autoplayExperimentInstallScrollListenerIfNeeded(); | |
2189 } | |
2190 | |
2110 updateVolume(); | 2191 updateVolume(); |
2111 | 2192 |
2112 scheduleEvent(EventTypeNames::volumechange); | 2193 scheduleEvent(EventTypeNames::volumechange); |
2113 } | 2194 } |
2114 | 2195 |
2115 void HTMLMediaElement::updateVolume() | 2196 void HTMLMediaElement::updateVolume() |
2116 { | 2197 { |
2117 if (webMediaPlayer()) | 2198 if (webMediaPlayer()) |
2118 webMediaPlayer()->setVolume(effectiveMediaVolume()); | 2199 webMediaPlayer()->setVolume(effectiveMediaVolume()); |
2119 | 2200 |
(...skipping 1584 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3704 } | 3785 } |
3705 | 3786 |
3706 #if ENABLE(WEB_AUDIO) | 3787 #if ENABLE(WEB_AUDIO) |
3707 void HTMLMediaElement::clearWeakMembers(Visitor* visitor) | 3788 void HTMLMediaElement::clearWeakMembers(Visitor* visitor) |
3708 { | 3789 { |
3709 if (!Heap::isHeapObjectAlive(m_audioSourceNode) && audioSourceProvider()) | 3790 if (!Heap::isHeapObjectAlive(m_audioSourceNode) && audioSourceProvider()) |
3710 audioSourceProvider()->setClient(nullptr); | 3791 audioSourceProvider()->setClient(nullptr); |
3711 } | 3792 } |
3712 #endif | 3793 #endif |
3713 | 3794 |
3795 void HTMLMediaElement::autoplayExperimentInstallScrollListenerIfNeeded() | |
3796 { | |
3797 if (document().domWindow() && !m_autoplayExperimentScrollListener) { | |
3798 m_autoplayExperimentScrollListener = adoptRef(new AutoplayExperimentScro llListener(this)); | |
3799 document().domWindow()->addEventListener("scroll", m_autoplayExperimentS crollListener, false); | |
philipj_slow
2015/07/21 12:51:29
I take it this will prevent smooth scrolling while
liberato (no reviews please)
2015/07/27 06:03:09
good point. we really only care if it ends up in
Rick Byers
2015/08/05 14:27:59
Listening to scroll events doesn't "prevent smooth
philipj_slow
2015/08/05 14:40:12
Oh... http://rbyers.github.io/EventListenerOptions
| |
3800 } | |
3714 } | 3801 } |
3802 | |
3803 void HTMLMediaElement::autoplayExperimentClearScrollListenerIfNeeded() | |
3804 { | |
3805 if (m_autoplayExperimentScrollListener) { | |
3806 LocalDOMWindow* domWindow = document().domWindow(); | |
3807 if (domWindow) { | |
3808 domWindow->removeEventListener("scroll", m_autoplayExperimentScrollL istener, false); | |
3809 } | |
3810 // Either way, clear our ref. | |
3811 m_autoplayExperimentScrollListener.clear(); | |
3812 } | |
3813 } | |
3814 | |
3815 bool HTMLMediaElement::autoplayExperimentIsVisible() | |
3816 { | |
3817 // We could check for eligibility here, but we skip it. Some of our | |
3818 // callers need to do it separately, and we don't want to check more | |
3819 // than we need to. | |
3820 | |
3821 // Autoplay is requested, and we're willing to override if the visibility | |
3822 // requirements are met. | |
3823 | |
3824 // Check visibility. | |
3825 const LocalDOMWindow* domWindow = document().domWindow(); | |
3826 if (!domWindow) | |
3827 return false; | |
3828 | |
3829 FloatRect us(offsetLeft(), offsetTop(), clientWidth(), clientHeight()); | |
3830 FloatRect screen(domWindow->scrollX(), domWindow->scrollY(), domWindow->inne rWidth(), domWindow->innerHeight()); | |
3831 | |
3832 return screen.contains(us); | |
3833 } | |
3834 | |
3835 bool HTMLMediaElement::autoplayExperimentMaybeStartPlaying() | |
3836 { | |
3837 // Make sure that we're eligible and visible. | |
3838 if (!autoplayExperimentIsEligible() || !autoplayExperimentIsVisible()) { | |
3839 return false; | |
3840 } | |
3841 | |
3842 // Start playing! | |
3843 autoplayExperimentPrepareToPlay(AutoplayExperimentStartedByScroll); | |
3844 // Why are we always preparing? Just go! | |
3845 playInternal(); | |
3846 | |
3847 return true; | |
3848 } | |
3849 | |
3850 bool HTMLMediaElement::autoplayExperimentIsEligible() const | |
3851 { | |
3852 // If no user gesture is required, then the experiment doesn't apply. | |
3853 // This is what prevents us from starting playback more than once. | |
3854 // Since this flag is never set to true once it's cleared, it will block | |
3855 // the autoplay experiment forever. | |
3856 if (!m_userGestureRequiredForPlay) | |
3857 return false; | |
3858 | |
3859 if (m_autoplayExperimentMode == ExperimentOff) | |
3860 return false; | |
3861 | |
3862 // If nobody has requested playback, either by the autoplay attribute or | |
3863 // a play() call, then do nothing. | |
3864 if (!m_autoplayExperimentPlayPending && !autoplay()) | |
3865 return false; | |
3866 | |
3867 // If the video is already playing, then do nothing. Note that there | |
3868 // is not a path where a user gesture is required but the video is | |
3869 // playing. However, we check for completeness. | |
3870 if (!m_paused) | |
3871 return false; | |
3872 | |
3873 // Note that the viewport test always returns false on desktop. For | |
3874 // tests, we allow an override. | |
3875 const bool optimizedForMobile = document().viewportDescription().isLegacyVie wportType() | |
3876 || (document().settings() && document().settings()->overrideOptimizedFor MobileCheck()); | |
3877 | |
3878 if (!optimizedForMobile) | |
3879 return false; | |
3880 | |
3881 if (m_autoplayExperimentMode == ExperimentIfMuted) { | |
3882 // If media is muted, then autoplay when it comes into view. | |
3883 return fastHasAttribute(mutedAttr) || m_muted; | |
3884 } | |
3885 | |
3886 // Autoplay when it comes into view, maybe muted. | |
3887 return true; | |
3888 } | |
3889 | |
3890 void HTMLMediaElement::autoplayExperimentMuteIfNeeded() | |
3891 { | |
3892 if (m_autoplayExperimentMode == ExperimentPlayMuted) { | |
3893 m_muted = true; | |
3894 updateVolume(); | |
3895 } | |
3896 } | |
3897 | |
3898 void HTMLMediaElement::autoplayExperimentPrepareToPlay(AutoplayMetrics metric) | |
3899 { | |
3900 recordAutoplayMetric(metric); | |
3901 | |
3902 // This also causes !autoplayExperimentIsEligible, so that we don't | |
3903 // allow autoplay more than once. | |
3904 m_userGestureRequiredForPlay = false; | |
3905 | |
3906 m_autoplayExperimentStartedByExperiment = true; | |
3907 autoplayExperimentClearScrollListenerIfNeeded(); | |
3908 autoplayExperimentMuteIfNeeded(); | |
3909 | |
3910 // Record that this autoplayed without a user gesture. This is normally | |
3911 // set when we discover an autoplay attribute, but we include all cases | |
3912 // where playback started without a user gesture, e.g., play(). | |
3913 m_initialPlayWithoutUserGestures = true; | |
3914 } | |
3915 | |
3916 } | |
OLD | NEW |