| 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 445 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 456 this, | 456 this, |
| 457 &HTMLMediaElement::resolveScheduledPlayPromises)), | 457 &HTMLMediaElement::resolveScheduledPlayPromises)), |
| 458 m_playPromiseRejectTask(CancellableTaskFactory::create( | 458 m_playPromiseRejectTask(CancellableTaskFactory::create( |
| 459 this, | 459 this, |
| 460 &HTMLMediaElement::rejectScheduledPlayPromises)), | 460 &HTMLMediaElement::rejectScheduledPlayPromises)), |
| 461 m_audioSourceNode(nullptr), | 461 m_audioSourceNode(nullptr), |
| 462 m_autoplayHelperClient(AutoplayHelperClientImpl::create(this)), | 462 m_autoplayHelperClient(AutoplayHelperClientImpl::create(this)), |
| 463 m_autoplayHelper( | 463 m_autoplayHelper( |
| 464 AutoplayExperimentHelper::create(m_autoplayHelperClient.get())), | 464 AutoplayExperimentHelper::create(m_autoplayHelperClient.get())), |
| 465 m_autoplayUmaHelper(AutoplayUmaHelper::create(this)), | 465 m_autoplayUmaHelper(AutoplayUmaHelper::create(this)), |
| 466 m_remotePlaybackClient(nullptr), | 466 m_remotePlaybackClient(nullptr) { |
| 467 m_autoplayVisibilityObserver(nullptr) { | |
| 468 ThreadState::current()->registerPreFinalizer(this); | 467 ThreadState::current()->registerPreFinalizer(this); |
| 469 | 468 |
| 470 BLINK_MEDIA_LOG << "HTMLMediaElement(" << (void*)this << ")"; | 469 BLINK_MEDIA_LOG << "HTMLMediaElement(" << (void*)this << ")"; |
| 471 | 470 |
| 472 // If any experiment is enabled, then we want to enable a user gesture by | 471 // If any experiment is enabled, then we want to enable a user gesture by |
| 473 // default, otherwise the experiment does nothing. | 472 // default, otherwise the experiment does nothing. |
| 474 if ((document.settings() && | 473 if ((document.settings() && |
| 475 document.settings()->mediaPlaybackRequiresUserGesture()) || | 474 document.settings()->mediaPlaybackRequiresUserGesture()) || |
| 476 m_autoplayHelper->isExperimentEnabled()) { | 475 m_autoplayHelper->isExperimentEnabled()) { |
| 477 m_lockedPendingUserGesture = true; | 476 m_lockedPendingUserGesture = true; |
| 478 } | 477 } |
| 479 | 478 |
| 480 LocalFrame* frame = document.frame(); | 479 LocalFrame* frame = document.frame(); |
| 481 if (frame) { | 480 if (frame) { |
| 482 m_remotePlaybackClient = | 481 m_remotePlaybackClient = |
| 483 frame->loader().client()->createWebRemotePlaybackClient(*this); | 482 frame->loader().client()->createWebRemotePlaybackClient(*this); |
| 484 } | 483 } |
| 485 | 484 |
| 486 setHasCustomStyleCallbacks(); | 485 setHasCustomStyleCallbacks(); |
| 487 addElementToDocumentMap(this, &document); | 486 addElementToDocumentMap(this, &document); |
| 488 | 487 |
| 489 UseCounter::count(document, UseCounter::HTMLMediaElement); | 488 UseCounter::count(document, UseCounter::HTMLMediaElement); |
| 489 |
| 490 m_viewportIntersectionObserver = new ElementViewportIntersectionObserver( |
| 491 this, WTF::bind(&HTMLMediaElement::onVideoViewportIntersectionChanged, |
| 492 wrapWeakPersistent(this))); |
| 493 m_viewportIntersectionObserver->start(); |
| 490 } | 494 } |
| 491 | 495 |
| 492 HTMLMediaElement::~HTMLMediaElement() { | 496 HTMLMediaElement::~HTMLMediaElement() { |
| 493 BLINK_MEDIA_LOG << "~HTMLMediaElement(" << (void*)this << ")"; | 497 BLINK_MEDIA_LOG << "~HTMLMediaElement(" << (void*)this << ")"; |
| 494 | 498 |
| 495 // m_audioSourceNode is explicitly cleared by AudioNode::dispose(). | 499 // m_audioSourceNode is explicitly cleared by AudioNode::dispose(). |
| 496 // Since AudioNode::dispose() is guaranteed to be always called before | 500 // Since AudioNode::dispose() is guaranteed to be always called before |
| 497 // the AudioNode is destructed, m_audioSourceNode is explicitly cleared | 501 // the AudioNode is destructed, m_audioSourceNode is explicitly cleared |
| 498 // even if the AudioNode and the HTMLMediaElement die together. | 502 // even if the AudioNode and the HTMLMediaElement die together. |
| 499 DCHECK(!m_audioSourceNode); | 503 DCHECK(!m_audioSourceNode); |
| 500 } | 504 } |
| 501 | 505 |
| 502 void HTMLMediaElement::dispose() { | 506 void HTMLMediaElement::dispose() { |
| 503 closeMediaSource(); | 507 closeMediaSource(); |
| 504 | 508 |
| 509 m_viewportIntersectionObserver->stop(); |
| 510 |
| 505 // Destroying the player may cause a resource load to be canceled, | 511 // Destroying the player may cause a resource load to be canceled, |
| 506 // which could result in LocalDOMWindow::dispatchWindowLoadEvent() being | 512 // which could result in LocalDOMWindow::dispatchWindowLoadEvent() being |
| 507 // called via ResourceFetch::didLoadResource(), then | 513 // called via ResourceFetch::didLoadResource(), then |
| 508 // FrameLoader::checkCompleted(). But it's guaranteed that the load event | 514 // FrameLoader::checkCompleted(). But it's guaranteed that the load event |
| 509 // doesn't get dispatched during the object destruction. | 515 // doesn't get dispatched during the object destruction. |
| 510 // See Document::isDelayingLoadEvent(). | 516 // See Document::isDelayingLoadEvent(). |
| 511 // Also see http://crbug.com/275223 for more details. | 517 // Also see http://crbug.com/275223 for more details. |
| 512 clearMediaPlayerAndAudioSourceProviderClientWithoutLocking(); | 518 clearMediaPlayerAndAudioSourceProviderClientWithoutLocking(); |
| 513 } | 519 } |
| 514 | 520 |
| (...skipping 1220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1735 if (shouldAutoplay(RecordMetricsBehavior::DoRecord)) { | 1741 if (shouldAutoplay(RecordMetricsBehavior::DoRecord)) { |
| 1736 m_autoplayUmaHelper->onAutoplayInitiated(AutoplaySource::Attribute); | 1742 m_autoplayUmaHelper->onAutoplayInitiated(AutoplaySource::Attribute); |
| 1737 | 1743 |
| 1738 // If the autoplay experiment says that it's okay to play now, | 1744 // If the autoplay experiment says that it's okay to play now, |
| 1739 // then don't require a user gesture. | 1745 // then don't require a user gesture. |
| 1740 m_autoplayHelper->becameReadyToPlay(); | 1746 m_autoplayHelper->becameReadyToPlay(); |
| 1741 | 1747 |
| 1742 if (!isGestureNeededForPlayback()) { | 1748 if (!isGestureNeededForPlayback()) { |
| 1743 if (isHTMLVideoElement() && muted() && | 1749 if (isHTMLVideoElement() && muted() && |
| 1744 RuntimeEnabledFeatures::autoplayMutedVideosEnabled()) { | 1750 RuntimeEnabledFeatures::autoplayMutedVideosEnabled()) { |
| 1745 // We might end up in a situation where the previous | 1751 m_shouldAutoplayWhenVisible = true; |
| 1746 // observer didn't had time to fire yet. We can avoid | |
| 1747 // creating a new one in this case. | |
| 1748 if (!m_autoplayVisibilityObserver) { | |
| 1749 m_autoplayVisibilityObserver = new ElementVisibilityObserver( | |
| 1750 this, | |
| 1751 WTF::bind(&HTMLMediaElement::onVisibilityChangedForAutoplay, | |
| 1752 wrapWeakPersistent(this))); | |
| 1753 m_autoplayVisibilityObserver->start(); | |
| 1754 } | |
| 1755 } else { | 1752 } else { |
| 1756 m_paused = false; | 1753 m_paused = false; |
| 1757 scheduleEvent(EventTypeNames::play); | 1754 scheduleEvent(EventTypeNames::play); |
| 1758 scheduleNotifyPlaying(); | 1755 scheduleNotifyPlaying(); |
| 1759 m_autoplaying = false; | 1756 m_autoplaying = false; |
| 1760 } | 1757 } |
| 1761 } | 1758 } |
| 1762 } | 1759 } |
| 1763 | 1760 |
| 1764 scheduleEvent(EventTypeNames::canplaythrough); | 1761 scheduleEvent(EventTypeNames::canplaythrough); |
| (...skipping 674 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2439 } | 2436 } |
| 2440 | 2437 |
| 2441 void HTMLMediaElement::setMuted(bool muted) { | 2438 void HTMLMediaElement::setMuted(bool muted) { |
| 2442 BLINK_MEDIA_LOG << "setMuted(" << (void*)this << ", " << boolString(muted) | 2439 BLINK_MEDIA_LOG << "setMuted(" << (void*)this << ", " << boolString(muted) |
| 2443 << ")"; | 2440 << ")"; |
| 2444 | 2441 |
| 2445 if (m_muted == muted) | 2442 if (m_muted == muted) |
| 2446 return; | 2443 return; |
| 2447 | 2444 |
| 2448 bool wasAutoplayingMuted = isAutoplayingMuted(); | 2445 bool wasAutoplayingMuted = isAutoplayingMuted(); |
| 2449 bool wasPendingAutoplayMuted = m_autoplayVisibilityObserver && paused() && | 2446 bool wasPendingAutoplayMuted = m_shouldAutoplayWhenVisible && paused() && |
| 2450 m_muted && isLockedPendingUserGesture(); | 2447 m_muted && isLockedPendingUserGesture(); |
| 2451 | 2448 |
| 2452 if (UserGestureIndicator::processingUserGesture()) | 2449 if (UserGestureIndicator::processingUserGesture()) |
| 2453 unlockUserGesture(); | 2450 unlockUserGesture(); |
| 2454 | 2451 |
| 2455 m_muted = muted; | 2452 m_muted = muted; |
| 2456 m_autoplayHelper->mutedChanged(); | 2453 m_autoplayHelper->mutedChanged(); |
| 2457 | 2454 |
| 2458 scheduleEvent(EventTypeNames::volumechange); | 2455 scheduleEvent(EventTypeNames::volumechange); |
| 2459 | 2456 |
| 2460 // If an element autoplayed while muted, it needs to be unlocked to unmute, | 2457 // If an element autoplayed while muted, it needs to be unlocked to unmute, |
| 2461 // otherwise, it will be paused. | 2458 // otherwise, it will be paused. |
| 2462 if (wasAutoplayingMuted) { | 2459 if (wasAutoplayingMuted) { |
| 2463 if (isGestureNeededForPlayback()) { | 2460 if (isGestureNeededForPlayback()) { |
| 2464 pause(); | 2461 pause(); |
| 2465 m_autoplayUmaHelper->recordAutoplayUnmuteStatus( | 2462 m_autoplayUmaHelper->recordAutoplayUnmuteStatus( |
| 2466 AutoplayUnmuteActionStatus::Failure); | 2463 AutoplayUnmuteActionStatus::Failure); |
| 2467 } else { | 2464 } else { |
| 2468 m_autoplayUmaHelper->recordAutoplayUnmuteStatus( | 2465 m_autoplayUmaHelper->recordAutoplayUnmuteStatus( |
| 2469 AutoplayUnmuteActionStatus::Success); | 2466 AutoplayUnmuteActionStatus::Success); |
| 2470 } | 2467 } |
| 2471 } | 2468 } |
| 2472 | 2469 |
| 2473 // This is called after the volumechange event to make sure isAutoplayingMuted | 2470 // This is called after the volumechange event to make sure isAutoplayingMuted |
| 2474 // returns the right value when webMediaPlayer receives the volume update. | 2471 // returns the right value when webMediaPlayer receives the volume update. |
| 2475 if (webMediaPlayer()) | 2472 if (webMediaPlayer()) |
| 2476 webMediaPlayer()->setVolume(effectiveMediaVolume()); | 2473 webMediaPlayer()->setVolume(effectiveMediaVolume()); |
| 2477 | 2474 |
| 2478 // If an element was a candidate for autoplay muted but not visible, it will | 2475 // If an element was a candidate for autoplay muted but not visible, it will |
| 2479 // have a visibility observer ready to start its playback. | 2476 // start its playback once becomes visible. |
| 2480 if (wasPendingAutoplayMuted) { | 2477 if (wasPendingAutoplayMuted) |
| 2481 m_autoplayVisibilityObserver->stop(); | 2478 m_shouldAutoplayWhenVisible = false; |
| 2482 m_autoplayVisibilityObserver = nullptr; | |
| 2483 } | |
| 2484 } | 2479 } |
| 2485 | 2480 |
| 2486 double HTMLMediaElement::effectiveMediaVolume() const { | 2481 double HTMLMediaElement::effectiveMediaVolume() const { |
| 2487 if (m_muted) | 2482 if (m_muted) |
| 2488 return 0; | 2483 return 0; |
| 2489 | 2484 |
| 2490 return m_volume; | 2485 return m_volume; |
| 2491 } | 2486 } |
| 2492 | 2487 |
| 2493 // The spec says to fire periodic timeupdate events (those sent while playing) | 2488 // The spec says to fire periodic timeupdate events (those sent while playing) |
| (...skipping 1339 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3833 visitor->trace(m_textTracks); | 3828 visitor->trace(m_textTracks); |
| 3834 visitor->trace(m_textTracksWhenResourceSelectionBegan); | 3829 visitor->trace(m_textTracksWhenResourceSelectionBegan); |
| 3835 visitor->trace(m_playPromiseResolvers); | 3830 visitor->trace(m_playPromiseResolvers); |
| 3836 visitor->trace(m_playPromiseResolveList); | 3831 visitor->trace(m_playPromiseResolveList); |
| 3837 visitor->trace(m_playPromiseRejectList); | 3832 visitor->trace(m_playPromiseRejectList); |
| 3838 visitor->trace(m_audioSourceProvider); | 3833 visitor->trace(m_audioSourceProvider); |
| 3839 visitor->trace(m_autoplayHelperClient); | 3834 visitor->trace(m_autoplayHelperClient); |
| 3840 visitor->trace(m_autoplayHelper); | 3835 visitor->trace(m_autoplayHelper); |
| 3841 visitor->trace(m_autoplayUmaHelper); | 3836 visitor->trace(m_autoplayUmaHelper); |
| 3842 visitor->trace(m_srcObject); | 3837 visitor->trace(m_srcObject); |
| 3843 visitor->trace(m_autoplayVisibilityObserver); | 3838 visitor->trace(m_viewportIntersectionObserver); |
| 3844 visitor->template registerWeakMembers<HTMLMediaElement, | 3839 visitor->template registerWeakMembers<HTMLMediaElement, |
| 3845 &HTMLMediaElement::clearWeakMembers>( | 3840 &HTMLMediaElement::clearWeakMembers>( |
| 3846 this); | 3841 this); |
| 3847 Supplementable<HTMLMediaElement>::trace(visitor); | 3842 Supplementable<HTMLMediaElement>::trace(visitor); |
| 3848 HTMLElement::trace(visitor); | 3843 HTMLElement::trace(visitor); |
| 3849 ActiveDOMObject::trace(visitor); | 3844 ActiveDOMObject::trace(visitor); |
| 3850 } | 3845 } |
| 3851 | 3846 |
| 3852 DEFINE_TRACE_WRAPPERS(HTMLMediaElement) { | 3847 DEFINE_TRACE_WRAPPERS(HTMLMediaElement) { |
| 3853 visitor->traceWrappers(m_videoTracks); | 3848 visitor->traceWrappers(m_videoTracks); |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4057 DEFINE_STATIC_LOCAL(EnumerationHistogram, histogram, | 4052 DEFINE_STATIC_LOCAL(EnumerationHistogram, histogram, |
| 4058 ("Media.Controls.Show.Video", MediaControlsShowMax)); | 4053 ("Media.Controls.Show.Video", MediaControlsShowMax)); |
| 4059 return histogram; | 4054 return histogram; |
| 4060 } | 4055 } |
| 4061 | 4056 |
| 4062 DEFINE_STATIC_LOCAL(EnumerationHistogram, histogram, | 4057 DEFINE_STATIC_LOCAL(EnumerationHistogram, histogram, |
| 4063 ("Media.Controls.Show.Audio", MediaControlsShowMax)); | 4058 ("Media.Controls.Show.Audio", MediaControlsShowMax)); |
| 4064 return histogram; | 4059 return histogram; |
| 4065 } | 4060 } |
| 4066 | 4061 |
| 4067 void HTMLMediaElement::onVisibilityChangedForAutoplay(bool isVisible) { | 4062 void HTMLMediaElement::onVideoViewportIntersectionChanged( |
| 4068 if (!isVisible) | 4063 const WebRect& rootRect, |
| 4064 const WebRect& intersectRect) { |
| 4065 WebMediaPlayer::ViewportIntersectionInfo info; |
| 4066 info.rootRect = rootRect; |
| 4067 info.intersectRect = intersectRect; |
| 4068 if (m_webMediaPlayer) |
| 4069 m_webMediaPlayer->videoViewportIntersectionChanged(info); |
| 4070 m_currentViewportIntersection = info; |
| 4071 |
| 4072 bool isVisible = !intersectRect.isEmpty(); |
| 4073 m_autoplayUmaHelper->visibilityMaybeChangedforMutedVideo(isVisible); |
| 4074 |
| 4075 if (!isVisible || !m_shouldAutoplayWhenVisible) |
| 4069 return; | 4076 return; |
| 4070 | 4077 |
| 4071 if (shouldAutoplay()) { | 4078 if (shouldAutoplay()) { |
| 4072 m_paused = false; | 4079 m_paused = false; |
| 4073 scheduleEvent(EventTypeNames::play); | 4080 scheduleEvent(EventTypeNames::play); |
| 4074 scheduleNotifyPlaying(); | 4081 scheduleNotifyPlaying(); |
| 4075 m_autoplaying = false; | 4082 m_autoplaying = false; |
| 4076 | 4083 |
| 4077 updatePlayState(); | 4084 updatePlayState(); |
| 4078 } | 4085 } |
| 4079 | 4086 m_shouldAutoplayWhenVisible = false; |
| 4080 // TODO(zqzhang): There's still flaky leak if onVisibilityChangedForAutoplay() | |
| 4081 // is never called. The leak comes from either ElementVisibilityObserver or | |
| 4082 // IntersectionObserver. Should keep an eye on it. See | |
| 4083 // https://crbug.com/627539 | |
| 4084 m_autoplayVisibilityObserver->stop(); | |
| 4085 m_autoplayVisibilityObserver = nullptr; | |
| 4086 } | 4087 } |
| 4087 | 4088 |
| 4088 void HTMLMediaElement::clearWeakMembers(Visitor* visitor) { | 4089 void HTMLMediaElement::clearWeakMembers(Visitor* visitor) { |
| 4089 if (!ThreadHeap::isHeapObjectAlive(m_audioSourceNode)) { | 4090 if (!ThreadHeap::isHeapObjectAlive(m_audioSourceNode)) { |
| 4090 getAudioSourceProvider().setClient(nullptr); | 4091 getAudioSourceProvider().setClient(nullptr); |
| 4091 m_audioSourceNode = nullptr; | 4092 m_audioSourceNode = nullptr; |
| 4092 } | 4093 } |
| 4093 } | 4094 } |
| 4094 | 4095 |
| 4095 void HTMLMediaElement::AudioSourceProviderImpl::wrap( | 4096 void HTMLMediaElement::AudioSourceProviderImpl::wrap( |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4187 | 4188 |
| 4188 IntRect HTMLMediaElement::AutoplayHelperClientImpl::absoluteBoundingBoxRect() | 4189 IntRect HTMLMediaElement::AutoplayHelperClientImpl::absoluteBoundingBoxRect() |
| 4189 const { | 4190 const { |
| 4190 IntRect result; | 4191 IntRect result; |
| 4191 if (LayoutObject* object = m_element->layoutObject()) | 4192 if (LayoutObject* object = m_element->layoutObject()) |
| 4192 result = object->absoluteBoundingBoxRect(); | 4193 result = object->absoluteBoundingBoxRect(); |
| 4193 return result; | 4194 return result; |
| 4194 } | 4195 } |
| 4195 | 4196 |
| 4196 } // namespace blink | 4197 } // namespace blink |
| OLD | NEW |