From 8ed9cb7dbc8f07abb406569407899514a11c4015 Mon Sep 17 00:00:00 2001 From: alwu Date: Fri, 15 May 2020 01:39:31 +0000 Subject: [PATCH] Bug 1509933 - part1 : add new pref 'media.autoplay.blocking_policy'. r=geckoview-reviewers,snorp,padenot This patch will do : - rename the old pref `media.autoplay.enabled.user-gestures-needed` to the new pref `media.autoplay.blocking_policy` - modify the value of the pref to `int` in order to introduce new policy - implement new policy in `AutoplayPoliocy` The advantage of doing so : - rename the pref to explicitly indicate that it's related the block policy we use - use the transient user gesture activation as a new policy to replace the old one using the user input, which doesn't work on the async handler More details : The old `click-to-play` policy we use is using the user input to determine if the play invocation is called by users or by scripts. But `UserActivation::IsHandlingUserInput()` is buggy which would fail when you call `video.play()` inside an async event handler. So we would like to replace it with the new transient user activation, which would treat the action as an user input if the action is performed within a certain period of time after a user interacts (eg. click) with the page. [1] https://html.spec.whatwg.org/multipage/interaction.html#transient-activation Differential Revision: https://phabricator.services.mozilla.com/D73971 --- browser/app/profile/firefox.js | 2 +- dom/media/AutoplayPolicy.cpp | 32 ++++++++++++++++++++---- mobile/android/app/mobile.js | 2 +- modules/libpref/init/StaticPrefList.yaml | 18 +++++++------ 4 files changed, 40 insertions(+), 14 deletions(-) diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 5c7a8aa592b6..0f03dd565e11 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1481,7 +1481,7 @@ pref("media.gmp-gmpopenh264.visible", true); pref("media.gmp-gmpopenh264.enabled", true); // Switch block autoplay logic to v2, and enable UI. -pref("media.autoplay.enabled.user-gestures-needed", true); +pref("media.autoplay.blocking_policy", 0); // Set Firefox to block autoplay, asking for permission by default. pref("media.autoplay.default", 1); // 0=Allowed, 1=Blocked, 5=All Blocked diff --git a/dom/media/AutoplayPolicy.cpp b/dom/media/AutoplayPolicy.cpp index ce90a8a34354..97d02718ec6a 100644 --- a/dom/media/AutoplayPolicy.cpp +++ b/dom/media/AutoplayPolicy.cpp @@ -33,6 +33,10 @@ mozilla::LazyLogModule gAutoplayPermissionLog("Autoplay"); namespace mozilla { namespace dom { +static const uint32_t sPOLICY_STICKY_ACTIVATION = 0; +static const uint32_t sPOLICY_TRANSIENT_ACTIVATION = 1; +static const uint32_t sPOLICY_USER_INPUT_DEPTH = 2; + static Document* ApproverDocOf(const Document& aDocument) { nsCOMPtr ds = aDocument.GetDocShell(); if (!ds) { @@ -161,15 +165,33 @@ static bool IsAudioContextAllowedToPlay(const AudioContext& aContext) { static bool IsEnableBlockingWebAudioByUserGesturePolicy() { return Preferences::GetBool("media.autoplay.block-webaudio", false) && - StaticPrefs::media_autoplay_enabled_user_gestures_needed(); + StaticPrefs::media_autoplay_blocking_policy() == + sPOLICY_STICKY_ACTIVATION; } static bool IsAllowedToPlayByBlockingModel(const HTMLMediaElement& aElement) { - if (!StaticPrefs::media_autoplay_enabled_user_gestures_needed()) { - // If element is blessed, it would always be allowed to play(). - return aElement.IsBlessed() || UserActivation::IsHandlingUserInput(); + const uint32_t policy = StaticPrefs::media_autoplay_blocking_policy(); + if (policy == sPOLICY_STICKY_ACTIVATION) { + const bool isAllowed = + IsWindowAllowedToPlay(aElement.OwnerDoc()->GetInnerWindow()); + AUTOPLAY_LOG("Use 'sticky-activation', isAllowed=%d", isAllowed); + return isAllowed; } - return IsWindowAllowedToPlay(aElement.OwnerDoc()->GetInnerWindow()); + // If element is blessed, it would always be allowed to play(). + const bool isElementBlessed = aElement.IsBlessed(); + if (policy == sPOLICY_USER_INPUT_DEPTH) { + const bool isUserInput = UserActivation::IsHandlingUserInput(); + AUTOPLAY_LOG("Use 'User-Input-Depth', isBlessed=%d, isUserInput=%d", + isElementBlessed, isUserInput); + return isElementBlessed || isUserInput; + } + const bool hasTransientActivation = + aElement.OwnerDoc()->HasValidTransientUserGestureActivation(); + AUTOPLAY_LOG( + "Use 'transient-activation', isBlessed=%d, " + "hasValidTransientActivation=%d", + isElementBlessed, hasTransientActivation); + return isElementBlessed || hasTransientActivation; } // On GeckoView, we don't store any site's permission in permission manager, we diff --git a/mobile/android/app/mobile.js b/mobile/android/app/mobile.js index b168c2e87ccd..24e006aba3a0 100644 --- a/mobile/android/app/mobile.js +++ b/mobile/android/app/mobile.js @@ -474,7 +474,7 @@ pref("media.video-queue.send-to-compositor-size", 1); pref("media.mediadrm-widevinecdm.visible", true); // Switch block autoplay logic to v2. -pref("media.autoplay.enabled.user-gestures-needed", true); +pref("media.autoplay.blocking_policy", 0); // Set Fennec to block autoplay by default. pref("media.autoplay.default", 1); // 0=Allowed, 1=Blocked diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml index 00c92c698aa2..a397ed0ffca1 100644 --- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -6350,13 +6350,17 @@ #--------------------------------------------------------------------------- -# If "media.autoplay.default" is not ALLOWED, and this pref is true, -# then audible media would only be allowed to autoplay after website has -# been activated by specific user gestures, but non-audible -# media won't be restricted. -- name: media.autoplay.enabled.user-gestures-needed - type: bool - value: false +# This pref defines what the blocking policy would be used in blocking autoplay. +# 0 : use sticky activation (default) +# https://html.spec.whatwg.org/multipage/interaction.html#sticky-activation +# 1 : use transient activation (the transient activation duration can be +# adjusted by the pref `dom.user_activation.transient.timeout`) +# https://html.spec.whatwg.org/multipage/interaction.html#transient-activation +# 2 : user input depth (allow autoplay when the play is trigged by user input +# which is determined by the user input depth) +- name: media.autoplay.blocking_policy + type: uint32_t + value: 0 mirror: always # File-backed MediaCache size.