Bug 1520088 - part3 : implement different phases autoplay checking. r=cpearce
authorAlastor Wu <alwu@mozilla.com>
Wed, 16 Jan 2019 18:21:39 +0000
changeset 511251 2ce9b482cda2d1ca16f063754be1bd43515de585
parent 511250 1d2fcf021b32addc028800b6f0b315c7c4779b3d
child 511252 5e0eb1c0074453818e7135ad87a97e4f3b1e674b
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce
bugs1520088
milestone66.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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
dom/media/AutoplayPolicy.cpp
--- a/dom/media/AutoplayPolicy.cpp
+++ b/dom/media/AutoplayPolicy.cpp
@@ -55,16 +55,28 @@ static bool IsActivelyCapturingOrHasAPer
   }
 
   auto principal = nsGlobalWindowInner::Cast(aWindow)->GetPrincipal();
   return (nsContentUtils::IsExactSitePermAllow(principal, "camera") ||
           nsContentUtils::IsExactSitePermAllow(principal, "microphone") ||
           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;
   }
 
   if (IsActivelyCapturingOrHasAPermission(aWindow)) {
     AUTOPLAY_LOG(
         "Allow autoplay as document has camera or microphone or screen"
@@ -86,23 +98,16 @@ static bool IsWindowAllowedToPlay(nsPIDO
     return false;
   }
 
   Document* approver = ApproverDocOf(*aWindow->GetExtantDoc());
   if (!approver) {
     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;
   }
 
   if (approver->IsExtensionPage()) {
     AUTOPLAY_LOG("Allow autoplay as in extension document.");
     return true;
@@ -164,55 +169,96 @@ static bool IsEnableBlockingWebAudioByUs
 }
 
 /* static */ bool AutoplayPolicy::WouldBeAllowedToPlayIfAutoplayDisabled(
     const AudioContext& aContext) {
   return IsAudioContextAllowedToPlay(aContext);
 }
 
 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(
     const HTMLMediaElement& aElement) {
   const bool result = IsAllowedToPlayInternal(aElement);
   AUTOPLAY_LOG("IsAllowedToPlay, mediaElement=%p, isAllowToPlay=%s", &aElement,
                result ? "allowed" : "blocked");
   return result;
 }
 
 /* static */ bool AutoplayPolicy::IsAllowedToPlay(
     const AudioContext& aContext) {
+  /**
+   * 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;
+  }
+
+  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 IsAudioContextAllowedToPlay(aContext);
+  return IsWindowAllowedToPlay(window);
 }
 
 /* static */ DocumentAutoplayPolicy AutoplayPolicy::IsAllowedToPlay(
     const Document& aDocument) {
   if (DefaultAutoplayBehaviour() == nsIAutoplay::ALLOWED ||
       IsWindowAllowedToPlay(aDocument.GetInnerWindow())) {
     return DocumentAutoplayPolicy::Allowed;
   }