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

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

Issue 2475643004: Monitor the intersection of video and viewport. (Closed)
Patch Set: Addressed miu's comments from PS#5. Created 4 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 /* 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 18 matching lines...) Expand all
29 #include "bindings/core/v8/ExceptionState.h" 29 #include "bindings/core/v8/ExceptionState.h"
30 #include "bindings/core/v8/ExceptionStatePlaceholder.h" 30 #include "bindings/core/v8/ExceptionStatePlaceholder.h"
31 #include "bindings/core/v8/ScriptController.h" 31 #include "bindings/core/v8/ScriptController.h"
32 #include "bindings/core/v8/ScriptEventListener.h" 32 #include "bindings/core/v8/ScriptEventListener.h"
33 #include "bindings/core/v8/ScriptPromiseResolver.h" 33 #include "bindings/core/v8/ScriptPromiseResolver.h"
34 #include "core/HTMLNames.h" 34 #include "core/HTMLNames.h"
35 #include "core/css/MediaList.h" 35 #include "core/css/MediaList.h"
36 #include "core/dom/Attribute.h" 36 #include "core/dom/Attribute.h"
37 #include "core/dom/DOMException.h" 37 #include "core/dom/DOMException.h"
38 #include "core/dom/ElementTraversal.h" 38 #include "core/dom/ElementTraversal.h"
39 #include "core/dom/ElementVisibilityObserver.h" 39 #include "core/dom/ElementVisibilityObserver.h"
Zhiqiang Zhang (Slow) 2016/11/15 11:29:27 nit: remove this unused include
xjz 2016/11/15 23:03:39 This header file is needed.
40 #include "core/dom/Fullscreen.h" 40 #include "core/dom/Fullscreen.h"
41 #include "core/dom/TaskRunnerHelper.h" 41 #include "core/dom/TaskRunnerHelper.h"
42 #include "core/dom/shadow/ShadowRoot.h" 42 #include "core/dom/shadow/ShadowRoot.h"
43 #include "core/events/Event.h" 43 #include "core/events/Event.h"
44 #include "core/frame/FrameView.h" 44 #include "core/frame/FrameView.h"
45 #include "core/frame/LocalFrame.h" 45 #include "core/frame/LocalFrame.h"
46 #include "core/frame/Settings.h" 46 #include "core/frame/Settings.h"
47 #include "core/frame/UseCounter.h" 47 #include "core/frame/UseCounter.h"
48 #include "core/frame/csp/ContentSecurityPolicy.h" 48 #include "core/frame/csp/ContentSecurityPolicy.h"
49 #include "core/html/AutoplayUmaHelper.h" 49 #include "core/html/AutoplayUmaHelper.h"
(...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after
457 this, 457 this,
458 &HTMLMediaElement::resolveScheduledPlayPromises)), 458 &HTMLMediaElement::resolveScheduledPlayPromises)),
459 m_playPromiseRejectTask(CancellableTaskFactory::create( 459 m_playPromiseRejectTask(CancellableTaskFactory::create(
460 this, 460 this,
461 &HTMLMediaElement::rejectScheduledPlayPromises)), 461 &HTMLMediaElement::rejectScheduledPlayPromises)),
462 m_audioSourceNode(nullptr), 462 m_audioSourceNode(nullptr),
463 m_autoplayHelperClient(AutoplayHelperClientImpl::create(this)), 463 m_autoplayHelperClient(AutoplayHelperClientImpl::create(this)),
464 m_autoplayHelper( 464 m_autoplayHelper(
465 AutoplayExperimentHelper::create(m_autoplayHelperClient.get())), 465 AutoplayExperimentHelper::create(m_autoplayHelperClient.get())),
466 m_autoplayUmaHelper(AutoplayUmaHelper::create(this)), 466 m_autoplayUmaHelper(AutoplayUmaHelper::create(this)),
467 m_remotePlaybackClient(nullptr), 467 m_remotePlaybackClient(nullptr) {
468 m_autoplayVisibilityObserver(nullptr) {
469 ThreadState::current()->registerPreFinalizer(this); 468 ThreadState::current()->registerPreFinalizer(this);
470 469
471 BLINK_MEDIA_LOG << "HTMLMediaElement(" << (void*)this << ")"; 470 BLINK_MEDIA_LOG << "HTMLMediaElement(" << (void*)this << ")";
472 471
473 // If any experiment is enabled, then we want to enable a user gesture by 472 // If any experiment is enabled, then we want to enable a user gesture by
474 // default, otherwise the experiment does nothing. 473 // default, otherwise the experiment does nothing.
475 if ((document.settings() && 474 if ((document.settings() &&
476 document.settings()->mediaPlaybackRequiresUserGesture()) || 475 document.settings()->mediaPlaybackRequiresUserGesture()) ||
477 m_autoplayHelper->isExperimentEnabled()) { 476 m_autoplayHelper->isExperimentEnabled()) {
478 m_lockedPendingUserGesture = true; 477 m_lockedPendingUserGesture = true;
479 } 478 }
480 479
481 setHasCustomStyleCallbacks(); 480 setHasCustomStyleCallbacks();
482 addElementToDocumentMap(this, &document); 481 addElementToDocumentMap(this, &document);
483 482
484 UseCounter::count(document, UseCounter::HTMLMediaElement); 483 UseCounter::count(document, UseCounter::HTMLMediaElement);
484
485 m_videoViewportRatioObserver = new ElementViewportRatioObserver(
486 this, WTF::bind(&HTMLMediaElement::onVideoViewportRatioChanged,
487 wrapWeakPersistent(this)));
488 m_videoViewportRatioObserver->start();
485 } 489 }
486 490
487 HTMLMediaElement::~HTMLMediaElement() { 491 HTMLMediaElement::~HTMLMediaElement() {
488 BLINK_MEDIA_LOG << "~HTMLMediaElement(" << (void*)this << ")"; 492 BLINK_MEDIA_LOG << "~HTMLMediaElement(" << (void*)this << ")";
489 493
490 // m_audioSourceNode is explicitly cleared by AudioNode::dispose(). 494 // m_audioSourceNode is explicitly cleared by AudioNode::dispose().
491 // Since AudioNode::dispose() is guaranteed to be always called before 495 // Since AudioNode::dispose() is guaranteed to be always called before
492 // the AudioNode is destructed, m_audioSourceNode is explicitly cleared 496 // the AudioNode is destructed, m_audioSourceNode is explicitly cleared
493 // even if the AudioNode and the HTMLMediaElement die together. 497 // even if the AudioNode and the HTMLMediaElement die together.
494 DCHECK(!m_audioSourceNode); 498 DCHECK(!m_audioSourceNode);
495 } 499 }
496 500
497 void HTMLMediaElement::dispose() { 501 void HTMLMediaElement::dispose() {
498 closeMediaSource(); 502 closeMediaSource();
499 503
504 m_videoViewportRatioObserver->stop();
505
500 // Destroying the player may cause a resource load to be canceled, 506 // Destroying the player may cause a resource load to be canceled,
501 // which could result in LocalDOMWindow::dispatchWindowLoadEvent() being 507 // which could result in LocalDOMWindow::dispatchWindowLoadEvent() being
502 // called via ResourceFetch::didLoadResource(), then 508 // called via ResourceFetch::didLoadResource(), then
503 // FrameLoader::checkCompleted(). But it's guaranteed that the load event 509 // FrameLoader::checkCompleted(). But it's guaranteed that the load event
504 // doesn't get dispatched during the object destruction. 510 // doesn't get dispatched during the object destruction.
505 // See Document::isDelayingLoadEvent(). 511 // See Document::isDelayingLoadEvent().
506 // Also see http://crbug.com/275223 for more details. 512 // Also see http://crbug.com/275223 for more details.
507 clearMediaPlayerAndAudioSourceProviderClientWithoutLocking(); 513 clearMediaPlayerAndAudioSourceProviderClientWithoutLocking();
508 } 514 }
509 515
(...skipping 1206 matching lines...) Expand 10 before | Expand all | Expand 10 after
1716 if (shouldAutoplay(RecordMetricsBehavior::DoRecord)) { 1722 if (shouldAutoplay(RecordMetricsBehavior::DoRecord)) {
1717 m_autoplayUmaHelper->onAutoplayInitiated(AutoplaySource::Attribute); 1723 m_autoplayUmaHelper->onAutoplayInitiated(AutoplaySource::Attribute);
1718 1724
1719 // If the autoplay experiment says that it's okay to play now, 1725 // If the autoplay experiment says that it's okay to play now,
1720 // then don't require a user gesture. 1726 // then don't require a user gesture.
1721 m_autoplayHelper->becameReadyToPlay(); 1727 m_autoplayHelper->becameReadyToPlay();
1722 1728
1723 if (!isGestureNeededForPlayback()) { 1729 if (!isGestureNeededForPlayback()) {
1724 if (isHTMLVideoElement() && muted() && 1730 if (isHTMLVideoElement() && muted() &&
1725 RuntimeEnabledFeatures::autoplayMutedVideosEnabled()) { 1731 RuntimeEnabledFeatures::autoplayMutedVideosEnabled()) {
1726 // We might end up in a situation where the previous 1732 m_shouldAutoplayWhenVisible = true;
1727 // observer didn't had time to fire yet. We can avoid
1728 // creating a new one in this case.
1729 if (!m_autoplayVisibilityObserver) {
1730 m_autoplayVisibilityObserver = new ElementVisibilityObserver(
1731 this,
1732 WTF::bind(&HTMLMediaElement::onVisibilityChangedForAutoplay,
1733 wrapWeakPersistent(this)));
1734 m_autoplayVisibilityObserver->start();
1735 }
1736 } else { 1733 } else {
1737 m_paused = false; 1734 m_paused = false;
1738 invalidateCachedTime(); 1735 invalidateCachedTime();
1739 scheduleEvent(EventTypeNames::play); 1736 scheduleEvent(EventTypeNames::play);
1740 scheduleNotifyPlaying(); 1737 scheduleNotifyPlaying();
1741 m_autoplaying = false; 1738 m_autoplaying = false;
1742 } 1739 }
1743 } 1740 }
1744 } 1741 }
1745 1742
(...skipping 602 matching lines...) Expand 10 before | Expand all | Expand 10 after
2348 2345
2349 void HTMLMediaElement::setMuted(bool muted) { 2346 void HTMLMediaElement::setMuted(bool muted) {
2350 BLINK_MEDIA_LOG << "setMuted(" << (void*)this << ", " << boolString(muted) 2347 BLINK_MEDIA_LOG << "setMuted(" << (void*)this << ", " << boolString(muted)
2351 << ")"; 2348 << ")";
2352 2349
2353 if (m_muted == muted) 2350 if (m_muted == muted)
2354 return; 2351 return;
2355 2352
2356 bool wasAutoplayingMuted = 2353 bool wasAutoplayingMuted =
2357 !paused() && m_muted && isLockedPendingUserGesture(); 2354 !paused() && m_muted && isLockedPendingUserGesture();
2358 bool wasPendingAutoplayMuted = m_autoplayVisibilityObserver && paused() && 2355 bool wasPendingAutoplayMuted = m_shouldAutoplayWhenVisible && paused() &&
2359 m_muted && isLockedPendingUserGesture(); 2356 m_muted && isLockedPendingUserGesture();
2360 2357
2361 if (UserGestureIndicator::processingUserGesture()) 2358 if (UserGestureIndicator::processingUserGesture())
2362 unlockUserGesture(); 2359 unlockUserGesture();
2363 2360
2364 m_muted = muted; 2361 m_muted = muted;
2365 m_autoplayHelper->mutedChanged(); 2362 m_autoplayHelper->mutedChanged();
2366 2363
2367 updateVolume(); 2364 updateVolume();
2368 2365
2369 scheduleEvent(EventTypeNames::volumechange); 2366 scheduleEvent(EventTypeNames::volumechange);
2370 2367
2371 // If an element autoplayed while muted, it needs to be unlocked to unmute, 2368 // If an element autoplayed while muted, it needs to be unlocked to unmute,
2372 // otherwise, it will be paused. 2369 // otherwise, it will be paused.
2373 if (wasAutoplayingMuted) { 2370 if (wasAutoplayingMuted) {
2374 if (isGestureNeededForPlayback()) { 2371 if (isGestureNeededForPlayback()) {
2375 pause(); 2372 pause();
2376 m_autoplayUmaHelper->recordAutoplayUnmuteStatus( 2373 m_autoplayUmaHelper->recordAutoplayUnmuteStatus(
2377 AutoplayUnmuteActionStatus::Failure); 2374 AutoplayUnmuteActionStatus::Failure);
2378 } else { 2375 } else {
2379 m_autoplayUmaHelper->recordAutoplayUnmuteStatus( 2376 m_autoplayUmaHelper->recordAutoplayUnmuteStatus(
2380 AutoplayUnmuteActionStatus::Success); 2377 AutoplayUnmuteActionStatus::Success);
2381 } 2378 }
2382 } 2379 }
2383 2380
2384 // If an element was a candidate for autoplay muted but not visible, it will 2381 // If an element was a candidate for autoplay muted but not visible, it will
2385 // have a visibility observer ready to start its playback. 2382 // start its playback once becomes visible.
2386 if (wasPendingAutoplayMuted) { 2383 if (wasPendingAutoplayMuted)
2387 m_autoplayVisibilityObserver->stop(); 2384 m_shouldAutoplayWhenVisible = false;
2388 m_autoplayVisibilityObserver = nullptr;
2389 }
2390 } 2385 }
2391 2386
2392 void HTMLMediaElement::updateVolume() { 2387 void HTMLMediaElement::updateVolume() {
2393 if (webMediaPlayer()) 2388 if (webMediaPlayer())
2394 webMediaPlayer()->setVolume(effectiveMediaVolume()); 2389 webMediaPlayer()->setVolume(effectiveMediaVolume());
2395 2390
2396 if (mediaControls()) 2391 if (mediaControls())
2397 mediaControls()->updateVolume(); 2392 mediaControls()->updateVolume();
2398 } 2393 }
2399 2394
(...skipping 1335 matching lines...) Expand 10 before | Expand all | Expand 10 after
3735 visitor->trace(m_textTracks); 3730 visitor->trace(m_textTracks);
3736 visitor->trace(m_textTracksWhenResourceSelectionBegan); 3731 visitor->trace(m_textTracksWhenResourceSelectionBegan);
3737 visitor->trace(m_playPromiseResolvers); 3732 visitor->trace(m_playPromiseResolvers);
3738 visitor->trace(m_playPromiseResolveList); 3733 visitor->trace(m_playPromiseResolveList);
3739 visitor->trace(m_playPromiseRejectList); 3734 visitor->trace(m_playPromiseRejectList);
3740 visitor->trace(m_audioSourceProvider); 3735 visitor->trace(m_audioSourceProvider);
3741 visitor->trace(m_autoplayHelperClient); 3736 visitor->trace(m_autoplayHelperClient);
3742 visitor->trace(m_autoplayHelper); 3737 visitor->trace(m_autoplayHelper);
3743 visitor->trace(m_autoplayUmaHelper); 3738 visitor->trace(m_autoplayUmaHelper);
3744 visitor->trace(m_srcObject); 3739 visitor->trace(m_srcObject);
3745 visitor->trace(m_autoplayVisibilityObserver); 3740 visitor->trace(m_videoViewportRatioObserver);
3746 visitor->template registerWeakMembers<HTMLMediaElement, 3741 visitor->template registerWeakMembers<HTMLMediaElement,
3747 &HTMLMediaElement::clearWeakMembers>( 3742 &HTMLMediaElement::clearWeakMembers>(
3748 this); 3743 this);
3749 Supplementable<HTMLMediaElement>::trace(visitor); 3744 Supplementable<HTMLMediaElement>::trace(visitor);
3750 HTMLElement::trace(visitor); 3745 HTMLElement::trace(visitor);
3751 ActiveDOMObject::trace(visitor); 3746 ActiveDOMObject::trace(visitor);
3752 } 3747 }
3753 3748
3754 DEFINE_TRACE_WRAPPERS(HTMLMediaElement) { 3749 DEFINE_TRACE_WRAPPERS(HTMLMediaElement) {
3755 visitor->traceWrappers(m_videoTracks); 3750 visitor->traceWrappers(m_videoTracks);
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
3961 DEFINE_STATIC_LOCAL(EnumerationHistogram, histogram, 3956 DEFINE_STATIC_LOCAL(EnumerationHistogram, histogram,
3962 ("Media.Controls.Show.Video", MediaControlsShowMax)); 3957 ("Media.Controls.Show.Video", MediaControlsShowMax));
3963 return histogram; 3958 return histogram;
3964 } 3959 }
3965 3960
3966 DEFINE_STATIC_LOCAL(EnumerationHistogram, histogram, 3961 DEFINE_STATIC_LOCAL(EnumerationHistogram, histogram,
3967 ("Media.Controls.Show.Audio", MediaControlsShowMax)); 3962 ("Media.Controls.Show.Audio", MediaControlsShowMax));
3968 return histogram; 3963 return histogram;
3969 } 3964 }
3970 3965
3971 void HTMLMediaElement::onVisibilityChangedForAutoplay(bool isVisible) { 3966 void HTMLMediaElement::onVideoViewportRatioChanged(float ratio) {
3972 if (!isVisible) 3967 if (m_webMediaPlayer) {
3968 m_webMediaPlayer->videoViewportRatioChanged(ratio);
3969 }
3970 m_viewportRatio = ratio;
3971 bool isVisible = ratio > 0.f;
3972 m_autoplayUmaHelper->visibilityMaybeChangedforMutedVideo(isVisible);
3973
3974 if (!isVisible || !m_shouldAutoplayWhenVisible)
3973 return; 3975 return;
3974 3976
3975 if (shouldAutoplay()) { 3977 if (shouldAutoplay()) {
3976 m_paused = false; 3978 m_paused = false;
3977 invalidateCachedTime(); 3979 invalidateCachedTime();
3978 scheduleEvent(EventTypeNames::play); 3980 scheduleEvent(EventTypeNames::play);
3979 scheduleNotifyPlaying(); 3981 scheduleNotifyPlaying();
3980 m_autoplaying = false; 3982 m_autoplaying = false;
3981 3983
3982 updatePlayState(); 3984 updatePlayState();
3983 } 3985 }
3984 3986 m_shouldAutoplayWhenVisible = false;
3985 // TODO(zqzhang): There's still flaky leak if onVisibilityChangedForAutoplay()
3986 // is never called. The leak comes from either ElementVisibilityObserver or
3987 // IntersectionObserver. Should keep an eye on it. See
3988 // https://crbug.com/627539
3989 m_autoplayVisibilityObserver->stop();
3990 m_autoplayVisibilityObserver = nullptr;
3991 } 3987 }
3992 3988
3993 void HTMLMediaElement::clearWeakMembers(Visitor* visitor) { 3989 void HTMLMediaElement::clearWeakMembers(Visitor* visitor) {
3994 if (!ThreadHeap::isHeapObjectAlive(m_audioSourceNode)) { 3990 if (!ThreadHeap::isHeapObjectAlive(m_audioSourceNode)) {
3995 getAudioSourceProvider().setClient(nullptr); 3991 getAudioSourceProvider().setClient(nullptr);
3996 m_audioSourceNode = nullptr; 3992 m_audioSourceNode = nullptr;
3997 } 3993 }
3998 } 3994 }
3999 3995
4000 void HTMLMediaElement::AudioSourceProviderImpl::wrap( 3996 void HTMLMediaElement::AudioSourceProviderImpl::wrap(
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
4092 4088
4093 IntRect HTMLMediaElement::AutoplayHelperClientImpl::absoluteBoundingBoxRect() 4089 IntRect HTMLMediaElement::AutoplayHelperClientImpl::absoluteBoundingBoxRect()
4094 const { 4090 const {
4095 IntRect result; 4091 IntRect result;
4096 if (LayoutObject* object = m_element->layoutObject()) 4092 if (LayoutObject* object = m_element->layoutObject())
4097 result = object->absoluteBoundingBoxRect(); 4093 result = object->absoluteBoundingBoxRect();
4098 return result; 4094 return result;
4099 } 4095 }
4100 4096
4101 } // namespace blink 4097 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698