| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights | 2 * Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights |
| 3 * reserved. | 3 * reserved. |
| 4 * | 4 * |
| 5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
| 6 * modification, are permitted provided that the following conditions | 6 * modification, are permitted provided that the following conditions |
| 7 * are met: | 7 * are met: |
| 8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 58 #include "core/html/track/AudioTrack.h" | 58 #include "core/html/track/AudioTrack.h" |
| 59 #include "core/html/track/AudioTrackList.h" | 59 #include "core/html/track/AudioTrackList.h" |
| 60 #include "core/html/track/AutomaticTrackSelection.h" | 60 #include "core/html/track/AutomaticTrackSelection.h" |
| 61 #include "core/html/track/CueTimeline.h" | 61 #include "core/html/track/CueTimeline.h" |
| 62 #include "core/html/track/InbandTextTrack.h" | 62 #include "core/html/track/InbandTextTrack.h" |
| 63 #include "core/html/track/TextTrackContainer.h" | 63 #include "core/html/track/TextTrackContainer.h" |
| 64 #include "core/html/track/TextTrackList.h" | 64 #include "core/html/track/TextTrackList.h" |
| 65 #include "core/html/track/VideoTrack.h" | 65 #include "core/html/track/VideoTrack.h" |
| 66 #include "core/html/track/VideoTrackList.h" | 66 #include "core/html/track/VideoTrackList.h" |
| 67 #include "core/inspector/ConsoleMessage.h" | 67 #include "core/inspector/ConsoleMessage.h" |
| 68 #include "core/layout/api/LayoutMediaItem.h" | 68 #include "core/layout/LayoutMedia.h" |
| 69 #include "core/layout/api/LayoutViewItem.h" | 69 #include "core/layout/api/LayoutViewItem.h" |
| 70 #include "core/layout/compositing/PaintLayerCompositor.h" | 70 #include "core/layout/compositing/PaintLayerCompositor.h" |
| 71 #include "core/loader/FrameLoader.h" | 71 #include "core/loader/FrameLoader.h" |
| 72 #include "core/loader/FrameLoaderClient.h" | 72 #include "core/loader/FrameLoaderClient.h" |
| 73 #include "core/page/ChromeClient.h" | 73 #include "core/page/ChromeClient.h" |
| 74 #include "core/page/NetworkStateNotifier.h" | 74 #include "core/page/NetworkStateNotifier.h" |
| 75 #include "platform/ContentType.h" | 75 #include "platform/ContentType.h" |
| 76 #include "platform/Histogram.h" | 76 #include "platform/Histogram.h" |
| 77 #include "platform/LayoutTestSupport.h" | 77 #include "platform/LayoutTestSupport.h" |
| 78 #include "platform/MIMETypeFromURL.h" | 78 #include "platform/MIMETypeFromURL.h" |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 279 case WebMediaPlayer::PreloadAuto: | 279 case WebMediaPlayer::PreloadAuto: |
| 280 return "auto"; | 280 return "auto"; |
| 281 } | 281 } |
| 282 | 282 |
| 283 NOTREACHED(); | 283 NOTREACHED(); |
| 284 return String(); | 284 return String(); |
| 285 } | 285 } |
| 286 | 286 |
| 287 } // anonymous namespace | 287 } // anonymous namespace |
| 288 | 288 |
| 289 class HTMLMediaElement::AutoplayHelperClientImpl | |
| 290 : public AutoplayExperimentHelper::Client { | |
| 291 public: | |
| 292 static AutoplayHelperClientImpl* create(HTMLMediaElement* element) { | |
| 293 return new AutoplayHelperClientImpl(element); | |
| 294 } | |
| 295 | |
| 296 virtual ~AutoplayHelperClientImpl(); | |
| 297 | |
| 298 using RecordMetricsBehavior = HTMLMediaElement::RecordMetricsBehavior; | |
| 299 | |
| 300 double currentTime() const override { return m_element->currentTime(); } | |
| 301 double duration() const override { return m_element->duration(); } | |
| 302 bool paused() const override { return m_element->paused(); } | |
| 303 bool ended() const override { return m_element->ended(); } | |
| 304 bool muted() const override { return m_element->muted(); } | |
| 305 void setMuted(bool muted) override { m_element->setMuted(muted); } | |
| 306 void playInternal() override { m_element->playInternal(); } | |
| 307 void pauseInternal() override { m_element->pauseInternal(); } | |
| 308 bool isLockedPendingUserGesture() const override { | |
| 309 return m_element->isLockedPendingUserGesture(); | |
| 310 } | |
| 311 void unlockUserGesture() override { m_element->unlockUserGesture(); } | |
| 312 void recordAutoplayMetric(AutoplayMetrics metric) override { | |
| 313 m_element->recordAutoplayMetric(metric); | |
| 314 } | |
| 315 bool shouldAutoplay() override { | |
| 316 return m_element->shouldAutoplay(RecordMetricsBehavior::DoNotRecord); | |
| 317 } | |
| 318 bool isHTMLVideoElement() const override { | |
| 319 return m_element->isHTMLVideoElement(); | |
| 320 } | |
| 321 bool isHTMLAudioElement() const override { | |
| 322 return m_element->isHTMLAudioElement(); | |
| 323 } | |
| 324 | |
| 325 // Document | |
| 326 bool isLegacyViewportType() override; | |
| 327 PageVisibilityState pageVisibilityState() const override; | |
| 328 String autoplayExperimentMode() const override; | |
| 329 | |
| 330 // Frame | |
| 331 bool isCrossOrigin() const override { | |
| 332 const LocalFrame* frame = m_element->document().frame(); | |
| 333 return frame && frame->isCrossOriginSubframe(); | |
| 334 } | |
| 335 | |
| 336 bool isAutoplayAllowedPerSettings() const override; | |
| 337 | |
| 338 // LayoutObject | |
| 339 void setRequestPositionUpdates(bool) override; | |
| 340 IntRect absoluteBoundingBoxRect() const override; | |
| 341 | |
| 342 DEFINE_INLINE_VIRTUAL_TRACE() { | |
| 343 visitor->trace(m_element); | |
| 344 Client::trace(visitor); | |
| 345 } | |
| 346 | |
| 347 private: | |
| 348 AutoplayHelperClientImpl(HTMLMediaElement* element) : m_element(element) {} | |
| 349 | |
| 350 Member<HTMLMediaElement> m_element; | |
| 351 }; | |
| 352 | |
| 353 void HTMLMediaElement::recordAutoplayMetric(AutoplayMetrics metric) { | |
| 354 DEFINE_STATIC_LOCAL(EnumerationHistogram, autoplayHistogram, | |
| 355 ("Blink.MediaElement.Autoplay", NumberOfAutoplayMetrics)); | |
| 356 autoplayHistogram.count(metric); | |
| 357 } | |
| 358 | |
| 359 MIMETypeRegistry::SupportsType HTMLMediaElement::supportsType( | 289 MIMETypeRegistry::SupportsType HTMLMediaElement::supportsType( |
| 360 const ContentType& contentType) { | 290 const ContentType& contentType) { |
| 361 DEFINE_STATIC_LOCAL(const String, codecs, ("codecs")); | 291 DEFINE_STATIC_LOCAL(const String, codecs, ("codecs")); |
| 362 | 292 |
| 363 String type = contentType.type().lower(); | 293 String type = contentType.type().lower(); |
| 364 // The codecs string is not lower-cased because MP4 values are case sensitive | 294 // The codecs string is not lower-cased because MP4 values are case sensitive |
| 365 // per http://tools.ietf.org/html/rfc4281#page-7. | 295 // per http://tools.ietf.org/html/rfc4281#page-7. |
| 366 String typeCodecs = contentType.parameter(codecs); | 296 String typeCodecs = contentType.parameter(codecs); |
| 367 | 297 |
| 368 if (type.isEmpty()) | 298 if (type.isEmpty()) |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 445 m_textTracksVisible(false), | 375 m_textTracksVisible(false), |
| 446 m_shouldPerformAutomaticTrackSelection(true), | 376 m_shouldPerformAutomaticTrackSelection(true), |
| 447 m_tracksAreReady(true), | 377 m_tracksAreReady(true), |
| 448 m_processingPreferenceChange(false), | 378 m_processingPreferenceChange(false), |
| 449 m_playingRemotely(false), | 379 m_playingRemotely(false), |
| 450 m_inOverlayFullscreenVideo(false), | 380 m_inOverlayFullscreenVideo(false), |
| 451 m_audioTracks(this, AudioTrackList::create(*this)), | 381 m_audioTracks(this, AudioTrackList::create(*this)), |
| 452 m_videoTracks(this, VideoTrackList::create(*this)), | 382 m_videoTracks(this, VideoTrackList::create(*this)), |
| 453 m_textTracks(this, nullptr), | 383 m_textTracks(this, nullptr), |
| 454 m_audioSourceNode(nullptr), | 384 m_audioSourceNode(nullptr), |
| 455 m_autoplayHelperClient(AutoplayHelperClientImpl::create(this)), | |
| 456 m_autoplayHelper( | |
| 457 AutoplayExperimentHelper::create(m_autoplayHelperClient.get())), | |
| 458 m_autoplayUmaHelper(AutoplayUmaHelper::create(this)), | 385 m_autoplayUmaHelper(AutoplayUmaHelper::create(this)), |
| 459 m_remotePlaybackClient(nullptr), | 386 m_remotePlaybackClient(nullptr), |
| 460 m_autoplayVisibilityObserver(nullptr) { | 387 m_autoplayVisibilityObserver(nullptr) { |
| 461 ThreadState::current()->registerPreFinalizer(this); | 388 ThreadState::current()->registerPreFinalizer(this); |
| 462 | 389 |
| 463 BLINK_MEDIA_LOG << "HTMLMediaElement(" << (void*)this << ")"; | 390 BLINK_MEDIA_LOG << "HTMLMediaElement(" << (void*)this << ")"; |
| 464 | 391 |
| 465 // If any experiment is enabled, then we want to enable a user gesture by | 392 // If any experiment is enabled, then we want to enable a user gesture by |
| 466 // default, otherwise the experiment does nothing. | 393 // default, otherwise the experiment does nothing. |
| 467 if ((document.settings() && | 394 if ((document.settings() && |
| 468 document.settings()->mediaPlaybackRequiresUserGesture()) || | 395 document.settings()->mediaPlaybackRequiresUserGesture())) { |
| 469 m_autoplayHelper->isExperimentEnabled()) { | |
| 470 m_lockedPendingUserGesture = true; | 396 m_lockedPendingUserGesture = true; |
| 471 } | 397 } |
| 472 | 398 |
| 473 LocalFrame* frame = document.frame(); | 399 LocalFrame* frame = document.frame(); |
| 474 if (frame) { | 400 if (frame) { |
| 475 m_remotePlaybackClient = | 401 m_remotePlaybackClient = |
| 476 frame->loader().client()->createWebRemotePlaybackClient(*this); | 402 frame->loader().client()->createWebRemotePlaybackClient(*this); |
| 477 } | 403 } |
| 478 | 404 |
| 479 setHasCustomStyleCallbacks(); | 405 setHasCustomStyleCallbacks(); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 506 } | 432 } |
| 507 | 433 |
| 508 void HTMLMediaElement::didMoveToNewDocument(Document& oldDocument) { | 434 void HTMLMediaElement::didMoveToNewDocument(Document& oldDocument) { |
| 509 BLINK_MEDIA_LOG << "didMoveToNewDocument(" << (void*)this << ")"; | 435 BLINK_MEDIA_LOG << "didMoveToNewDocument(" << (void*)this << ")"; |
| 510 | 436 |
| 511 m_autoplayUmaHelper->didMoveToNewDocument(oldDocument); | 437 m_autoplayUmaHelper->didMoveToNewDocument(oldDocument); |
| 512 // If any experiment is enabled, then we want to enable a user gesture by | 438 // If any experiment is enabled, then we want to enable a user gesture by |
| 513 // default, otherwise the experiment does nothing. | 439 // default, otherwise the experiment does nothing. |
| 514 bool oldDocumentRequiresUserGesture = | 440 bool oldDocumentRequiresUserGesture = |
| 515 (oldDocument.settings() && | 441 (oldDocument.settings() && |
| 516 oldDocument.settings()->mediaPlaybackRequiresUserGesture()) || | 442 oldDocument.settings()->mediaPlaybackRequiresUserGesture()); |
| 517 m_autoplayHelper->isExperimentEnabled(); | |
| 518 bool newDocumentRequiresUserGesture = | 443 bool newDocumentRequiresUserGesture = |
| 519 (document().settings() && | 444 (document().settings() && |
| 520 document().settings()->mediaPlaybackRequiresUserGesture()) || | 445 document().settings()->mediaPlaybackRequiresUserGesture()); |
| 521 m_autoplayHelper->isExperimentEnabled(); | |
| 522 if (newDocumentRequiresUserGesture && !oldDocumentRequiresUserGesture) { | 446 if (newDocumentRequiresUserGesture && !oldDocumentRequiresUserGesture) { |
| 523 m_lockedPendingUserGesture = true; | 447 m_lockedPendingUserGesture = true; |
| 524 } | 448 } |
| 525 | 449 |
| 526 if (m_shouldDelayLoadEvent) { | 450 if (m_shouldDelayLoadEvent) { |
| 527 document().incrementLoadEventDelayCount(); | 451 document().incrementLoadEventDelayCount(); |
| 528 // Note: Keeping the load event delay count increment on oldDocument that | 452 // Note: Keeping the load event delay count increment on oldDocument that |
| 529 // was added when m_shouldDelayLoadEvent was set so that destruction of | 453 // was added when m_shouldDelayLoadEvent was set so that destruction of |
| 530 // m_webMediaPlayer can not cause load event dispatching in oldDocument. | 454 // m_webMediaPlayer can not cause load event dispatching in oldDocument. |
| 531 } else { | 455 } else { |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 741 | 665 |
| 742 BLINK_MEDIA_LOG << "canPlayType(" << (void*)this << ", " << mimeType | 666 BLINK_MEDIA_LOG << "canPlayType(" << (void*)this << ", " << mimeType |
| 743 << ") -> " << canPlay; | 667 << ") -> " << canPlay; |
| 744 | 668 |
| 745 return canPlay; | 669 return canPlay; |
| 746 } | 670 } |
| 747 | 671 |
| 748 void HTMLMediaElement::load() { | 672 void HTMLMediaElement::load() { |
| 749 BLINK_MEDIA_LOG << "load(" << (void*)this << ")"; | 673 BLINK_MEDIA_LOG << "load(" << (void*)this << ")"; |
| 750 | 674 |
| 751 m_autoplayHelper->loadMethodCalled(); | 675 if (isLockedPendingUserGesture() && |
| 676 UserGestureIndicator::utilizeUserGesture()) { |
| 677 unlockUserGesture(); |
| 678 } |
| 752 | 679 |
| 753 m_ignorePreloadNone = true; | 680 m_ignorePreloadNone = true; |
| 754 invokeLoadAlgorithm(); | 681 invokeLoadAlgorithm(); |
| 755 } | 682 } |
| 756 | 683 |
| 757 // TODO(srirama.m): Currently m_ignorePreloadNone is reset before calling | 684 // TODO(srirama.m): Currently m_ignorePreloadNone is reset before calling |
| 758 // invokeLoadAlgorithm() in all places except load(). Move it inside here | 685 // invokeLoadAlgorithm() in all places except load(). Move it inside here |
| 759 // once microtask is implemented for "Await a stable state" step | 686 // once microtask is implemented for "Await a stable state" step |
| 760 // in resource selection algorithm. | 687 // in resource selection algorithm. |
| 761 void HTMLMediaElement::invokeLoadAlgorithm() { | 688 void HTMLMediaElement::invokeLoadAlgorithm() { |
| (...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1062 | 989 |
| 1063 LocalFrame* frame = document().frame(); | 990 LocalFrame* frame = document().frame(); |
| 1064 if (!frame) { | 991 if (!frame) { |
| 1065 mediaLoadingFailed(WebMediaPlayer::NetworkStateFormatError); | 992 mediaLoadingFailed(WebMediaPlayer::NetworkStateFormatError); |
| 1066 return; | 993 return; |
| 1067 } | 994 } |
| 1068 | 995 |
| 1069 // The resource fetch algorithm | 996 // The resource fetch algorithm |
| 1070 setNetworkState(kNetworkLoading); | 997 setNetworkState(kNetworkLoading); |
| 1071 | 998 |
| 1072 m_autoplayHelper->loadingStarted(); | |
| 1073 | |
| 1074 // Set m_currentSrc *before* changing to the cache url, the fact that we are | 999 // Set m_currentSrc *before* changing to the cache url, the fact that we are |
| 1075 // loading from the app cache is an internal detail not exposed through the | 1000 // loading from the app cache is an internal detail not exposed through the |
| 1076 // media element API. | 1001 // media element API. |
| 1077 m_currentSrc = url; | 1002 m_currentSrc = url; |
| 1078 | 1003 |
| 1079 if (m_audioSourceNode) | 1004 if (m_audioSourceNode) |
| 1080 m_audioSourceNode->onCurrentSrcChanged(m_currentSrc); | 1005 m_audioSourceNode->onCurrentSrcChanged(m_currentSrc); |
| 1081 | 1006 |
| 1082 BLINK_MEDIA_LOG << "loadResource(" << (void*)this << ") - m_currentSrc -> " | 1007 BLINK_MEDIA_LOG << "loadResource(" << (void*)this << ") - m_currentSrc -> " |
| 1083 << urlForLoggingMedia(m_currentSrc); | 1008 << urlForLoggingMedia(m_currentSrc); |
| (...skipping 641 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1725 | 1650 |
| 1726 if (m_readyState == kHaveEnoughData && oldState < kHaveEnoughData && | 1651 if (m_readyState == kHaveEnoughData && oldState < kHaveEnoughData && |
| 1727 tracksAreReady) { | 1652 tracksAreReady) { |
| 1728 if (oldState <= kHaveCurrentData) { | 1653 if (oldState <= kHaveCurrentData) { |
| 1729 scheduleEvent(EventTypeNames::canplay); | 1654 scheduleEvent(EventTypeNames::canplay); |
| 1730 if (isPotentiallyPlaying) | 1655 if (isPotentiallyPlaying) |
| 1731 scheduleNotifyPlaying(); | 1656 scheduleNotifyPlaying(); |
| 1732 } | 1657 } |
| 1733 | 1658 |
| 1734 // Check for autoplay, and record metrics about it if needed. | 1659 // Check for autoplay, and record metrics about it if needed. |
| 1735 if (shouldAutoplay(RecordMetricsBehavior::DoRecord)) { | 1660 if (shouldAutoplay()) { |
| 1736 m_autoplayUmaHelper->onAutoplayInitiated(AutoplaySource::Attribute); | 1661 m_autoplayUmaHelper->onAutoplayInitiated(AutoplaySource::Attribute); |
| 1737 | 1662 |
| 1738 // If the autoplay experiment says that it's okay to play now, | |
| 1739 // then don't require a user gesture. | |
| 1740 m_autoplayHelper->becameReadyToPlay(); | |
| 1741 | |
| 1742 if (!isGestureNeededForPlayback()) { | 1663 if (!isGestureNeededForPlayback()) { |
| 1743 if (isHTMLVideoElement() && muted() && | 1664 if (isHTMLVideoElement() && muted() && |
| 1744 RuntimeEnabledFeatures::autoplayMutedVideosEnabled()) { | 1665 RuntimeEnabledFeatures::autoplayMutedVideosEnabled()) { |
| 1745 // We might end up in a situation where the previous | 1666 // We might end up in a situation where the previous |
| 1746 // observer didn't had time to fire yet. We can avoid | 1667 // observer didn't had time to fire yet. We can avoid |
| 1747 // creating a new one in this case. | 1668 // creating a new one in this case. |
| 1748 if (!m_autoplayVisibilityObserver) { | 1669 if (!m_autoplayVisibilityObserver) { |
| 1749 m_autoplayVisibilityObserver = new ElementVisibilityObserver( | 1670 m_autoplayVisibilityObserver = new ElementVisibilityObserver( |
| 1750 this, | 1671 this, |
| 1751 WTF::bind(&HTMLMediaElement::onVisibilityChangedForAutoplay, | 1672 WTF::bind(&HTMLMediaElement::onVisibilityChangedForAutoplay, |
| (...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2105 // 4.8.10.8 Playing the media resource | 2026 // 4.8.10.8 Playing the media resource |
| 2106 // The ended attribute must return true if the media element has ended | 2027 // The ended attribute must return true if the media element has ended |
| 2107 // playback and the direction of playback is forwards, and false otherwise. | 2028 // playback and the direction of playback is forwards, and false otherwise. |
| 2108 return endedPlayback() && getDirectionOfPlayback() == Forward; | 2029 return endedPlayback() && getDirectionOfPlayback() == Forward; |
| 2109 } | 2030 } |
| 2110 | 2031 |
| 2111 bool HTMLMediaElement::autoplay() const { | 2032 bool HTMLMediaElement::autoplay() const { |
| 2112 return fastHasAttribute(autoplayAttr); | 2033 return fastHasAttribute(autoplayAttr); |
| 2113 } | 2034 } |
| 2114 | 2035 |
| 2115 bool HTMLMediaElement::shouldAutoplay( | 2036 bool HTMLMediaElement::shouldAutoplay() { |
| 2116 const RecordMetricsBehavior recordMetrics) { | 2037 if (document().isSandboxed(SandboxAutomaticFeatures)) |
| 2117 if (m_autoplaying && m_paused && autoplay()) { | 2038 return false; |
| 2118 if (document().isSandboxed(SandboxAutomaticFeatures)) { | 2039 return m_autoplaying && m_paused && autoplay(); |
| 2119 if (recordMetrics == RecordMetricsBehavior::DoRecord) | |
| 2120 m_autoplayHelper->recordSandboxFailure(); | |
| 2121 return false; | |
| 2122 } | |
| 2123 | |
| 2124 return true; | |
| 2125 } | |
| 2126 | |
| 2127 return false; | |
| 2128 } | 2040 } |
| 2129 | 2041 |
| 2130 String HTMLMediaElement::preload() const { | 2042 String HTMLMediaElement::preload() const { |
| 2131 return preloadTypeToString(preloadType()); | 2043 return preloadTypeToString(preloadType()); |
| 2132 } | 2044 } |
| 2133 | 2045 |
| 2134 void HTMLMediaElement::setPreload(const AtomicString& preload) { | 2046 void HTMLMediaElement::setPreload(const AtomicString& preload) { |
| 2135 BLINK_MEDIA_LOG << "setPreload(" << (void*)this << ", " << preload << ")"; | 2047 BLINK_MEDIA_LOG << "setPreload(" << (void*)this << ", " << preload << ")"; |
| 2136 setAttribute(preloadAttr, preload); | 2048 setAttribute(preloadAttr, preload); |
| 2137 } | 2049 } |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2226 resolver->reject(DOMException::create(code.get(), message)); | 2138 resolver->reject(DOMException::create(code.get(), message)); |
| 2227 return promise; | 2139 return promise; |
| 2228 } | 2140 } |
| 2229 | 2141 |
| 2230 return promise; | 2142 return promise; |
| 2231 } | 2143 } |
| 2232 | 2144 |
| 2233 Nullable<ExceptionCode> HTMLMediaElement::play() { | 2145 Nullable<ExceptionCode> HTMLMediaElement::play() { |
| 2234 BLINK_MEDIA_LOG << "play(" << (void*)this << ")"; | 2146 BLINK_MEDIA_LOG << "play(" << (void*)this << ")"; |
| 2235 | 2147 |
| 2236 m_autoplayHelper->playMethodCalled(); | |
| 2237 | |
| 2238 if (!UserGestureIndicator::processingUserGesture()) { | 2148 if (!UserGestureIndicator::processingUserGesture()) { |
| 2239 m_autoplayUmaHelper->onAutoplayInitiated(AutoplaySource::Method); | 2149 m_autoplayUmaHelper->onAutoplayInitiated(AutoplaySource::Method); |
| 2240 if (isGestureNeededForPlayback()) { | 2150 if (isGestureNeededForPlayback()) { |
| 2241 // If playback is deferred, then don't start playback but don't | |
| 2242 // fail yet either. | |
| 2243 if (m_autoplayHelper->isPlaybackDeferred()) | |
| 2244 return nullptr; | |
| 2245 | |
| 2246 // If we're already playing, then this play would do nothing anyway. | 2151 // If we're already playing, then this play would do nothing anyway. |
| 2247 // Call playInternal to handle scheduling the promise resolution. | 2152 // Call playInternal to handle scheduling the promise resolution. |
| 2248 if (!m_paused) { | 2153 if (!m_paused) { |
| 2249 playInternal(); | 2154 playInternal(); |
| 2250 return nullptr; | 2155 return nullptr; |
| 2251 } | 2156 } |
| 2252 | 2157 |
| 2253 recordAutoplayMetric(PlayMethodFailed); | |
| 2254 String message = ExceptionMessages::failedToExecute( | 2158 String message = ExceptionMessages::failedToExecute( |
| 2255 "play", "HTMLMediaElement", | 2159 "play", "HTMLMediaElement", |
| 2256 "API can only be initiated by a user gesture."); | 2160 "API can only be initiated by a user gesture."); |
| 2257 document().addConsoleMessage(ConsoleMessage::create( | 2161 document().addConsoleMessage(ConsoleMessage::create( |
| 2258 JSMessageSource, WarningMessageLevel, message)); | 2162 JSMessageSource, WarningMessageLevel, message)); |
| 2259 return NotAllowedError; | 2163 return NotAllowedError; |
| 2260 } | 2164 } |
| 2261 } else { | 2165 } else { |
| 2262 UserGestureIndicator::utilizeUserGesture(); | 2166 UserGestureIndicator::utilizeUserGesture(); |
| 2263 // We ask the helper to remove the gesture requirement for us, so that | 2167 unlockUserGesture(); |
| 2264 // it can record the reason. | |
| 2265 m_autoplayHelper->unlockUserGesture(GesturelessPlaybackEnabledByPlayMethod); | |
| 2266 } | 2168 } |
| 2267 | 2169 |
| 2268 if (m_error && m_error->code() == MediaError::kMediaErrSrcNotSupported) | 2170 if (m_error && m_error->code() == MediaError::kMediaErrSrcNotSupported) |
| 2269 return NotSupportedError; | 2171 return NotSupportedError; |
| 2270 | 2172 |
| 2271 playInternal(); | 2173 playInternal(); |
| 2272 | 2174 |
| 2273 return nullptr; | 2175 return nullptr; |
| 2274 } | 2176 } |
| 2275 | 2177 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2322 | 2224 |
| 2323 pauseInternal(); | 2225 pauseInternal(); |
| 2324 } | 2226 } |
| 2325 | 2227 |
| 2326 void HTMLMediaElement::pauseInternal() { | 2228 void HTMLMediaElement::pauseInternal() { |
| 2327 BLINK_MEDIA_LOG << "pauseInternal(" << (void*)this << ")"; | 2229 BLINK_MEDIA_LOG << "pauseInternal(" << (void*)this << ")"; |
| 2328 | 2230 |
| 2329 if (m_networkState == kNetworkEmpty) | 2231 if (m_networkState == kNetworkEmpty) |
| 2330 invokeResourceSelectionAlgorithm(); | 2232 invokeResourceSelectionAlgorithm(); |
| 2331 | 2233 |
| 2332 m_autoplayHelper->pauseMethodCalled(); | |
| 2333 | |
| 2334 m_autoplaying = false; | 2234 m_autoplaying = false; |
| 2335 | 2235 |
| 2336 if (!m_paused) { | 2236 if (!m_paused) { |
| 2337 m_paused = true; | 2237 m_paused = true; |
| 2338 scheduleTimeupdateEvent(false); | 2238 scheduleTimeupdateEvent(false); |
| 2339 scheduleEvent(EventTypeNames::pause); | 2239 scheduleEvent(EventTypeNames::pause); |
| 2340 | 2240 |
| 2341 // Force an update to official playback position. Automatic updates from | 2241 // Force an update to official playback position. Automatic updates from |
| 2342 // currentPlaybackPosition() will be blocked while m_paused = true. This | 2242 // currentPlaybackPosition() will be blocked while m_paused = true. This |
| 2343 // blocking is desired while paused, but its good to update it one final | 2243 // blocking is desired while paused, but its good to update it one final |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2446 return; | 2346 return; |
| 2447 | 2347 |
| 2448 bool wasAutoplayingMuted = isAutoplayingMuted(); | 2348 bool wasAutoplayingMuted = isAutoplayingMuted(); |
| 2449 bool wasPendingAutoplayMuted = m_autoplayVisibilityObserver && paused() && | 2349 bool wasPendingAutoplayMuted = m_autoplayVisibilityObserver && paused() && |
| 2450 m_muted && isLockedPendingUserGesture(); | 2350 m_muted && isLockedPendingUserGesture(); |
| 2451 | 2351 |
| 2452 if (UserGestureIndicator::processingUserGesture()) | 2352 if (UserGestureIndicator::processingUserGesture()) |
| 2453 unlockUserGesture(); | 2353 unlockUserGesture(); |
| 2454 | 2354 |
| 2455 m_muted = muted; | 2355 m_muted = muted; |
| 2456 m_autoplayHelper->mutedChanged(); | |
| 2457 | 2356 |
| 2458 scheduleEvent(EventTypeNames::volumechange); | 2357 scheduleEvent(EventTypeNames::volumechange); |
| 2459 | 2358 |
| 2460 // If an element autoplayed while muted, it needs to be unlocked to unmute, | 2359 // If an element autoplayed while muted, it needs to be unlocked to unmute, |
| 2461 // otherwise, it will be paused. | 2360 // otherwise, it will be paused. |
| 2462 if (wasAutoplayingMuted) { | 2361 if (wasAutoplayingMuted) { |
| 2463 if (isGestureNeededForPlayback()) { | 2362 if (isGestureNeededForPlayback()) { |
| 2464 pause(); | 2363 pause(); |
| 2465 m_autoplayUmaHelper->recordAutoplayUnmuteStatus( | 2364 m_autoplayUmaHelper->recordAutoplayUnmuteStatus( |
| 2466 AutoplayUnmuteActionStatus::Failure); | 2365 AutoplayUnmuteActionStatus::Failure); |
| (...skipping 867 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3334 if (shouldBePlaying) { | 3233 if (shouldBePlaying) { |
| 3335 setDisplayMode(Video); | 3234 setDisplayMode(Video); |
| 3336 | 3235 |
| 3337 if (!isPlaying) { | 3236 if (!isPlaying) { |
| 3338 // Set rate, muted before calling play in case they were set before the | 3237 // Set rate, muted before calling play in case they were set before the |
| 3339 // media engine was setup. The media engine should just stash the rate | 3238 // media engine was setup. The media engine should just stash the rate |
| 3340 // and muted values since it isn't already playing. | 3239 // and muted values since it isn't already playing. |
| 3341 webMediaPlayer()->setRate(playbackRate()); | 3240 webMediaPlayer()->setRate(playbackRate()); |
| 3342 webMediaPlayer()->setVolume(effectiveMediaVolume()); | 3241 webMediaPlayer()->setVolume(effectiveMediaVolume()); |
| 3343 webMediaPlayer()->play(); | 3242 webMediaPlayer()->play(); |
| 3344 m_autoplayHelper->playbackStarted(); | |
| 3345 } | 3243 } |
| 3346 | 3244 |
| 3347 startPlaybackProgressTimer(); | 3245 startPlaybackProgressTimer(); |
| 3348 m_playing = true; | 3246 m_playing = true; |
| 3349 } else { // Should not be playing right now | 3247 } else { // Should not be playing right now |
| 3350 if (isPlaying) { | 3248 if (isPlaying) { |
| 3351 webMediaPlayer()->pause(); | 3249 webMediaPlayer()->pause(); |
| 3352 m_autoplayHelper->playbackStopped(); | |
| 3353 } | 3250 } |
| 3354 | 3251 |
| 3355 m_playbackProgressTimer.stop(); | 3252 m_playbackProgressTimer.stop(); |
| 3356 m_playing = false; | 3253 m_playing = false; |
| 3357 double time = currentTime(); | 3254 double time = currentTime(); |
| 3358 if (time > m_lastSeekTime) | 3255 if (time > m_lastSeekTime) |
| 3359 addPlayedRange(m_lastSeekTime, time); | 3256 addPlayedRange(m_lastSeekTime, time); |
| 3360 } | 3257 } |
| 3361 | 3258 |
| 3362 if (layoutObject()) | 3259 if (layoutObject()) |
| (...skipping 458 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3821 visitor->trace(m_mediaSource); | 3718 visitor->trace(m_mediaSource); |
| 3822 visitor->trace(m_audioTracks); | 3719 visitor->trace(m_audioTracks); |
| 3823 visitor->trace(m_videoTracks); | 3720 visitor->trace(m_videoTracks); |
| 3824 visitor->trace(m_cueTimeline); | 3721 visitor->trace(m_cueTimeline); |
| 3825 visitor->trace(m_textTracks); | 3722 visitor->trace(m_textTracks); |
| 3826 visitor->trace(m_textTracksWhenResourceSelectionBegan); | 3723 visitor->trace(m_textTracksWhenResourceSelectionBegan); |
| 3827 visitor->trace(m_playPromiseResolvers); | 3724 visitor->trace(m_playPromiseResolvers); |
| 3828 visitor->trace(m_playPromiseResolveList); | 3725 visitor->trace(m_playPromiseResolveList); |
| 3829 visitor->trace(m_playPromiseRejectList); | 3726 visitor->trace(m_playPromiseRejectList); |
| 3830 visitor->trace(m_audioSourceProvider); | 3727 visitor->trace(m_audioSourceProvider); |
| 3831 visitor->trace(m_autoplayHelperClient); | |
| 3832 visitor->trace(m_autoplayHelper); | |
| 3833 visitor->trace(m_autoplayUmaHelper); | 3728 visitor->trace(m_autoplayUmaHelper); |
| 3834 visitor->trace(m_srcObject); | 3729 visitor->trace(m_srcObject); |
| 3835 visitor->trace(m_autoplayVisibilityObserver); | 3730 visitor->trace(m_autoplayVisibilityObserver); |
| 3836 visitor->template registerWeakMembers<HTMLMediaElement, | 3731 visitor->template registerWeakMembers<HTMLMediaElement, |
| 3837 &HTMLMediaElement::clearWeakMembers>( | 3732 &HTMLMediaElement::clearWeakMembers>( |
| 3838 this); | 3733 this); |
| 3839 Supplementable<HTMLMediaElement>::trace(visitor); | 3734 Supplementable<HTMLMediaElement>::trace(visitor); |
| 3840 HTMLElement::trace(visitor); | 3735 HTMLElement::trace(visitor); |
| 3841 ActiveDOMObject::trace(visitor); | 3736 ActiveDOMObject::trace(visitor); |
| 3842 } | 3737 } |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3904 // - Autoplay is enabled in settings; | 3799 // - Autoplay is enabled in settings; |
| 3905 if (isHTMLVideoElement() && muted() && | 3800 if (isHTMLVideoElement() && muted() && |
| 3906 RuntimeEnabledFeatures::autoplayMutedVideosEnabled() && | 3801 RuntimeEnabledFeatures::autoplayMutedVideosEnabled() && |
| 3907 !(document().settings() && document().settings()->dataSaverEnabled()) && | 3802 !(document().settings() && document().settings()->dataSaverEnabled()) && |
| 3908 !(document().settings() && | 3803 !(document().settings() && |
| 3909 document().settings()->forcePreloadNoneForMediaElements()) && | 3804 document().settings()->forcePreloadNoneForMediaElements()) && |
| 3910 isAutoplayAllowedPerSettings()) { | 3805 isAutoplayAllowedPerSettings()) { |
| 3911 return false; | 3806 return false; |
| 3912 } | 3807 } |
| 3913 | 3808 |
| 3914 if (m_autoplayHelper->isGestureRequirementOverridden()) | |
| 3915 return false; | |
| 3916 | |
| 3917 return true; | 3809 return true; |
| 3918 } | 3810 } |
| 3919 | 3811 |
| 3920 bool HTMLMediaElement::isAutoplayAllowedPerSettings() const { | 3812 bool HTMLMediaElement::isAutoplayAllowedPerSettings() const { |
| 3921 LocalFrame* frame = document().frame(); | 3813 LocalFrame* frame = document().frame(); |
| 3922 if (!frame) | 3814 if (!frame) |
| 3923 return false; | 3815 return false; |
| 3924 FrameLoaderClient* frameLoaderClient = frame->loader().client(); | 3816 FrameLoaderClient* frameLoaderClient = frame->loader().client(); |
| 3925 return frameLoaderClient && frameLoaderClient->allowAutoplay(false); | 3817 return frameLoaderClient && frameLoaderClient->allowAutoplay(false); |
| 3926 } | 3818 } |
| 3927 | 3819 |
| 3928 void HTMLMediaElement::setNetworkState(NetworkState state) { | 3820 void HTMLMediaElement::setNetworkState(NetworkState state) { |
| 3929 if (m_networkState != state) { | 3821 if (m_networkState != state) { |
| 3930 m_networkState = state; | 3822 m_networkState = state; |
| 3931 if (MediaControls* controls = mediaControls()) | 3823 if (MediaControls* controls = mediaControls()) |
| 3932 controls->networkStateChanged(); | 3824 controls->networkStateChanged(); |
| 3933 } | 3825 } |
| 3934 } | 3826 } |
| 3935 | 3827 |
| 3936 void HTMLMediaElement::videoWillBeDrawnToCanvas() const { | 3828 void HTMLMediaElement::videoWillBeDrawnToCanvas() const { |
| 3937 DCHECK(isHTMLVideoElement()); | 3829 DCHECK(isHTMLVideoElement()); |
| 3938 UseCounter::count(document(), UseCounter::VideoInCanvas); | 3830 UseCounter::count(document(), UseCounter::VideoInCanvas); |
| 3939 if (m_autoplayUmaHelper->hasSource() && !m_autoplayUmaHelper->isVisible()) | 3831 if (m_autoplayUmaHelper->hasSource() && !m_autoplayUmaHelper->isVisible()) |
| 3940 UseCounter::count(document(), UseCounter::HiddenAutoplayedVideoInCanvas); | 3832 UseCounter::count(document(), UseCounter::HiddenAutoplayedVideoInCanvas); |
| 3941 } | 3833 } |
| 3942 | 3834 |
| 3943 void HTMLMediaElement::notifyPositionMayHaveChanged( | |
| 3944 const IntRect& visibleRect) { | |
| 3945 m_autoplayHelper->positionChanged(visibleRect); | |
| 3946 } | |
| 3947 | |
| 3948 void HTMLMediaElement::updatePositionNotificationRegistration() { | |
| 3949 m_autoplayHelper->updatePositionNotificationRegistration(); | |
| 3950 } | |
| 3951 | |
| 3952 // TODO(liberato): remove once autoplay gesture override experiment concludes. | |
| 3953 void HTMLMediaElement::triggerAutoplayViewportCheckForTesting() { | |
| 3954 if (FrameView* view = document().view()) | |
| 3955 m_autoplayHelper->positionChanged( | |
| 3956 view->rootFrameToContents(view->computeVisibleArea())); | |
| 3957 m_autoplayHelper->triggerAutoplayViewportCheckForTesting(); | |
| 3958 } | |
| 3959 | |
| 3960 void HTMLMediaElement::scheduleResolvePlayPromises() { | 3835 void HTMLMediaElement::scheduleResolvePlayPromises() { |
| 3961 // TODO(mlamouri): per spec, we should create a new task but we can't create | 3836 // TODO(mlamouri): per spec, we should create a new task but we can't create |
| 3962 // a new cancellable task without cancelling the previous one. There are two | 3837 // a new cancellable task without cancelling the previous one. There are two |
| 3963 // approaches then: cancel the previous task and create a new one with the | 3838 // approaches then: cancel the previous task and create a new one with the |
| 3964 // appended promise list or append the new promise to the current list. The | 3839 // appended promise list or append the new promise to the current list. The |
| 3965 // latter approach is preferred because it might be the less observable | 3840 // latter approach is preferred because it might be the less observable |
| 3966 // change. | 3841 // change. |
| 3967 DCHECK(m_playPromiseResolveList.isEmpty() || | 3842 DCHECK(m_playPromiseResolveList.isEmpty() || |
| 3968 m_playPromiseResolveTaskHandle.isActive()); | 3843 m_playPromiseResolveTaskHandle.isActive()); |
| 3969 if (m_playPromiseResolvers.isEmpty()) | 3844 if (m_playPromiseResolvers.isEmpty()) |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4148 } | 4023 } |
| 4149 | 4024 |
| 4150 DEFINE_TRACE(HTMLMediaElement::AudioClientImpl) { | 4025 DEFINE_TRACE(HTMLMediaElement::AudioClientImpl) { |
| 4151 visitor->trace(m_client); | 4026 visitor->trace(m_client); |
| 4152 } | 4027 } |
| 4153 | 4028 |
| 4154 DEFINE_TRACE(HTMLMediaElement::AudioSourceProviderImpl) { | 4029 DEFINE_TRACE(HTMLMediaElement::AudioSourceProviderImpl) { |
| 4155 visitor->trace(m_client); | 4030 visitor->trace(m_client); |
| 4156 } | 4031 } |
| 4157 | 4032 |
| 4158 HTMLMediaElement::AutoplayHelperClientImpl::~AutoplayHelperClientImpl() {} | |
| 4159 | |
| 4160 bool HTMLMediaElement::AutoplayHelperClientImpl::isLegacyViewportType() { | |
| 4161 return m_element->document().viewportDescription().isLegacyViewportType(); | |
| 4162 } | |
| 4163 | |
| 4164 PageVisibilityState | |
| 4165 HTMLMediaElement::AutoplayHelperClientImpl::pageVisibilityState() const { | |
| 4166 return m_element->document().pageVisibilityState(); | |
| 4167 } | |
| 4168 | |
| 4169 String HTMLMediaElement::AutoplayHelperClientImpl::autoplayExperimentMode() | |
| 4170 const { | |
| 4171 String mode; | |
| 4172 if (m_element->document().settings()) | |
| 4173 mode = m_element->document().settings()->autoplayExperimentMode(); | |
| 4174 | |
| 4175 return mode; | |
| 4176 } | |
| 4177 | |
| 4178 bool HTMLMediaElement::AutoplayHelperClientImpl::isAutoplayAllowedPerSettings() | |
| 4179 const { | |
| 4180 return m_element->isAutoplayAllowedPerSettings(); | |
| 4181 } | |
| 4182 | |
| 4183 void HTMLMediaElement::AutoplayHelperClientImpl::setRequestPositionUpdates( | |
| 4184 bool request) { | |
| 4185 if (LayoutObject* layoutObject = m_element->layoutObject()) { | |
| 4186 LayoutMediaItem layoutMediaItem = | |
| 4187 LayoutMediaItem(toLayoutMedia(layoutObject)); | |
| 4188 layoutMediaItem.setRequestPositionUpdates(request); | |
| 4189 } | |
| 4190 } | |
| 4191 | |
| 4192 IntRect HTMLMediaElement::AutoplayHelperClientImpl::absoluteBoundingBoxRect() | |
| 4193 const { | |
| 4194 IntRect result; | |
| 4195 if (LayoutObject* object = m_element->layoutObject()) | |
| 4196 result = object->absoluteBoundingBoxRect(); | |
| 4197 return result; | |
| 4198 } | |
| 4199 | |
| 4200 } // namespace blink | 4033 } // namespace blink |
| OLD | NEW |