From 0d5851b149496386c6a23f8570527ee18270c06d Mon Sep 17 00:00:00 2001 From: Alastor Wu Date: Wed, 16 Jan 2019 18:21:39 +0000 Subject: [PATCH] Bug 1520088 - part3 : implement different phases autoplay checking. r=cpearce The autoplay checking for media element has 4 different phases, 1. check whether media element itself meets the autoplay condition 2. check whethr the site is in the autoplay whitelist 3. check global autoplay setting and check wether the site is in the autoplay blacklist. 4. check whether media is allowed under current blocking model (click-to-play or user-gesture-activation) Differential Revision: https://phabricator.services.mozilla.com/D16525 --HG-- extra : moz-landing-system : lando --- dom/media/AutoplayPolicy.cpp | 94 +++++++++++++++++++++++++++--------- 1 file changed, 70 insertions(+), 24 deletions(-) diff --git a/dom/media/AutoplayPolicy.cpp b/dom/media/AutoplayPolicy.cpp index 6fded2b31af3..fbcf31572896 100644 --- a/dom/media/AutoplayPolicy.cpp +++ b/dom/media/AutoplayPolicy.cpp @@ -60,6 +60,18 @@ static bool IsActivelyCapturingOrHasAPermission(nsPIDOMWindowInner* aWindow) { nsContentUtils::IsExactSitePermAllow(principal, "screen")); } +static bool IsSiteInAutoplayWhiteList(const Document* aDocument) { + return aDocument ? nsContentUtils::IsExactSitePermAllow( + aDocument->NodePrincipal(), "autoplay-media") + : false; +} + +static bool IsSiteInAutoplayBlackList(const Document* aDocument) { + return aDocument ? nsContentUtils::IsExactSitePermDeny( + aDocument->NodePrincipal(), "autoplay-media") + : false; +} + static bool IsWindowAllowedToPlay(nsPIDOMWindowInner* aWindow) { if (!aWindow) { return false; @@ -91,13 +103,6 @@ static bool IsWindowAllowedToPlay(nsPIDOMWindowInner* aWindow) { return false; } - if (nsContentUtils::IsExactSitePermAllow(approver->NodePrincipal(), - "autoplay-media")) { - AUTOPLAY_LOG( - "Allow autoplay as document has permanent autoplay permission."); - return true; - } - if (approver->HasBeenUserGestureActivated()) { AUTOPLAY_LOG("Allow autoplay as document activated by user gesture."); return true; @@ -169,28 +174,40 @@ static bool IsEnableBlockingWebAudioByUserGesturePolicy() { } static bool IsAllowedToPlayInternal(const HTMLMediaElement& aElement) { - const uint32_t autoplayDefault = DefaultAutoplayBehaviour(); - // TODO : this old way would be removed when user-gestures-needed becomes - // as a default option to block autoplay. - if (!Preferences::GetBool("media.autoplay.enabled.user-gestures-needed", - false)) { - // If element is blessed, it would always be allowed to play(). - return (autoplayDefault == nsIAutoplay::ALLOWED || aElement.IsBlessed() || - EventStateManager::IsHandlingUserInput()); - } - + /** + * The autoplay checking has 4 different phases, + * 1. check whether media element itself meets the autoplay condition + * 2. check whethr the site is in the autoplay whitelist + * 3. check global autoplay setting and check wether the site is in the + * autoplay blacklist. + * 4. check whether media is allowed under current blocking model + * (click-to-play or user-gesture-activation) + */ if (IsMediaElementAllowedToPlay(aElement)) { return true; } - if (IsWindowAllowedToPlay(aElement.OwnerDoc()->GetInnerWindow())) { - AUTOPLAY_LOG("Autoplay allowed as window is allowed to play, media %p.", - &aElement); + Document* approver = ApproverDocOf(*aElement.OwnerDoc()); + if (IsSiteInAutoplayWhiteList(approver)) { + AUTOPLAY_LOG( + "Allow autoplay as document has permanent autoplay permission."); return true; } - return IsMediaElementAllowedToPlay(aElement) || - autoplayDefault == nsIAutoplay::ALLOWED; + if (DefaultAutoplayBehaviour() == nsIAutoplay::ALLOWED && + !IsSiteInAutoplayBlackList(approver)) { + AUTOPLAY_LOG( + "Allow autoplay as global autoplay setting is allowing autoplay by " + "default."); + return true; + } + + if (!Preferences::GetBool("media.autoplay.enabled.user-gestures-needed", + false)) { + // If element is blessed, it would always be allowed to play(). + return aElement.IsBlessed() || EventStateManager::IsHandlingUserInput(); + } + return IsWindowAllowedToPlay(aElement.OwnerDoc()->GetInnerWindow()); } /* static */ bool AutoplayPolicy::IsAllowedToPlay( @@ -203,11 +220,40 @@ static bool IsAllowedToPlayInternal(const HTMLMediaElement& aElement) { /* static */ bool AutoplayPolicy::IsAllowedToPlay( const AudioContext& aContext) { - if (!IsEnableBlockingWebAudioByUserGesturePolicy()) { + /** + * The autoplay checking has 4 different phases, + * 1. check whether audio context itself meets the autoplay condition + * 2. check whethr the site is in the autoplay whitelist + * 3. check global autoplay setting and check wether the site is in the + * autoplay blacklist. + * 4. check whether media is allowed under current blocking model + * (only support user-gesture-activation) + */ + if (aContext.IsOffline()) { return true; } - return IsAudioContextAllowedToPlay(aContext); + nsPIDOMWindowInner* window = aContext.GetParentObject(); + Document* approver = aContext.GetParentObject() ? + ApproverDocOf(*(window->GetExtantDoc())) : nullptr; + if (IsSiteInAutoplayWhiteList(approver)) { + AUTOPLAY_LOG( + "Allow autoplay as document has permanent autoplay permission."); + return true; + } + + if (DefaultAutoplayBehaviour() == nsIAutoplay::ALLOWED && + !IsSiteInAutoplayBlackList(approver)) { + AUTOPLAY_LOG( + "Allow autoplay as global autoplay setting is allowing autoplay by " + "default."); + return true; + } + + if (!IsEnableBlockingWebAudioByUserGesturePolicy()) { + return true; + } + return IsWindowAllowedToPlay(window); } /* static */ DocumentAutoplayPolicy AutoplayPolicy::IsAllowedToPlay(