Backed out 5 changesets (bug 1513681) for browser_autoplay_blocked.js failures CLOSED TREE
authorBogdan Tara <btara@mozilla.com>
Sat, 29 Dec 2018 04:00:53 +0200
changeset 452110 0c02d1f0db78ff9e5b2be24f8f40bb6383c17f4e
parent 452109 05288089adb4b9be69bc58680730fe96b0278047
child 452111 2b4dd78913757e27c9175105197ac45844b41b90
push id75323
push userbtara@mozilla.com
push dateSat, 29 Dec 2018 02:01:18 +0000
treeherderautoland@0c02d1f0db78 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1513681
milestone66.0a1
backs outd24ddb803761f36c05030455c1144bcce9f2a5b2
6f52b229d9537e4ecd5eba6a8f93dff55c0e0852
79a78732c3ac2b91eee4378ba630da3090cccd2e
d0a9422928aec6530c4def97000ef14cbdc5ca91
23b5a58e3bcce5a76f36f8f681b69d88d859a559
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
Backed out 5 changesets (bug 1513681) for browser_autoplay_blocked.js failures CLOSED TREE Backed out changeset d24ddb803761 (bug 1513681) Backed out changeset 6f52b229d953 (bug 1513681) Backed out changeset 79a78732c3ac (bug 1513681) Backed out changeset d0a9422928ae (bug 1513681) Backed out changeset 23b5a58e3bcc (bug 1513681)
browser/base/content/tabbrowser.js
browser/modules/PermissionUI.jsm
browser/modules/SitePermissions.jsm
dom/base/nsDocument.cpp
dom/base/nsIDocument.h
dom/html/HTMLMediaElement.cpp
toolkit/actors/AudibleAutoplayChild.jsm
toolkit/actors/AutoplayChild.jsm
toolkit/actors/moz.build
toolkit/content/tests/browser/browser.ini
toolkit/content/tests/browser/browser_autoplay_audibleMediaOccurred.js
toolkit/content/widgets/browser.xml
toolkit/modules/ActorManagerParent.jsm
--- a/browser/base/content/tabbrowser.js
+++ b/browser/base/content/tabbrowser.js
@@ -4758,27 +4758,24 @@ window._gBrowser = {
         tab.removeAttribute("activemedia-blocked");
         this._tabAttrModified(tab, ["activemedia-blocked"]);
         let hist = Services.telemetry.getHistogramById("TAB_AUDIO_INDICATOR_USED");
         hist.add(2 /* unblockByVisitingTab */ );
         tab.finishMediaBlockTimer();
       }
     });
 
-    this.addEventListener("GloballyAutoplayBlocked", (event) => {
+    this.addEventListener("AudibleAutoplayMediaOccurred", (event) => {
       let browser = event.originalTarget;
       let tab = this.getTabForBrowser(browser);
       if (!tab) {
         return;
       }
 
-      SitePermissions.set(event.detail.url, "autoplay-media",
-                          SitePermissions.BLOCK,
-                          SitePermissions.SCOPE_GLOBAL,
-                          browser);
+      Services.obs.notifyObservers(tab, "AudibleAutoplayMediaOccurred");
     });
   },
 
   setSuccessor(aTab, successorTab) {
     if (aTab.ownerGlobal != window) {
       throw new Error("Cannot set the successor of another window's tab");
     }
     if (successorTab == aTab) {
--- a/browser/modules/PermissionUI.jsm
+++ b/browser/modules/PermissionUI.jsm
@@ -301,16 +301,29 @@ var PermissionPromptPrototype = {
       // If we're reading and setting permissions, then we need
       // to check to see if we already have a permission setting
       // for this particular principal.
       let {state} = SitePermissions.get(requestingURI,
                                         this.permissionKey,
                                         this.browser);
 
       if (state == SitePermissions.BLOCK) {
+        // If the request is blocked by a global setting then we record
+        // a flag that lasts for the duration of the current page load
+        // to notify the user that the permission has been blocked.
+        // Currently only applies to autoplay-media
+        if (state == SitePermissions.getDefault(this.permissionKey) &&
+            SitePermissions.showGloballyBlocked(this.permissionKey)) {
+          SitePermissions.set(this.principal.URI,
+                              this.permissionKey,
+                              state,
+                              SitePermissions.SCOPE_GLOBAL,
+                              this.browser);
+        }
+
         this.cancel();
         return;
       }
 
       if (state == SitePermissions.ALLOW) {
         this.allow();
         return;
       }
@@ -322,16 +335,18 @@ var PermissionPromptPrototype = {
     } else if (this.permissionKey) {
       // If we're reading a permission which already has a temporary value,
       // see if we can use the temporary value.
       let {state} = SitePermissions.get(null,
                                         this.permissionKey,
                                         this.browser);
 
       if (state == SitePermissions.BLOCK) {
+        // TODO: Add support for showGloballyBlocked
+
         this.cancel();
         return;
       }
     }
 
     let chromeWin = this.browser.ownerGlobal;
     if (!chromeWin.PopupNotifications) {
       this.cancel();
--- a/browser/modules/SitePermissions.jsm
+++ b/browser/modules/SitePermissions.jsm
@@ -429,16 +429,33 @@ var SitePermissions = {
     if (permissionID in gPermissionObject &&
         gPermissionObject[permissionID].getDefault)
       return gPermissionObject[permissionID].getDefault();
 
     // Otherwise try to get the default preference for that permission.
     return this._defaultPrefBranch.getIntPref(permissionID, this.UNKNOWN);
   },
 
+  /**
+   * Return whether the browser should notify the user if a permission was
+   * globally blocked due to a preference.
+   *
+   * @param {string} permissionID
+   *        The ID to get the state for.
+   *
+   * @return boolean Whether to show notification for globally blocked permissions.
+   */
+  showGloballyBlocked(permissionID) {
+    if (permissionID in gPermissionObject &&
+        gPermissionObject[permissionID].showGloballyBlocked)
+      return gPermissionObject[permissionID].showGloballyBlocked;
+
+    return false;
+  },
+
   /*
    * Return whether SitePermissions is permitted to store a TEMPORARY ALLOW
    * state for a particular permission.
    *
    * @param {string} permissionID
    *        The ID to get the state for.
    *
    * @return boolean Whether storing TEMPORARY ALLOW is permitted.
@@ -741,16 +758,17 @@ var gPermissionObject = {
    *    Array of permission states to be exposed to the user.
    *    Defaults to ALLOW, BLOCK and the default state (see getDefault).
    *    The PROMPT_HIDE state is deliberately excluded from "plugin:flash" since we
    *    don't want to expose a "Hide Prompt" button to the user through pageinfo.
    */
 
   "autoplay-media": {
     exactHostMatch: true,
+    showGloballyBlocked: true,
     permitTemporaryAllow: true,
     notifyWhenTemporaryPermissionChanged: true,
     getDefault() {
       let state = Services.prefs.getIntPref("media.autoplay.default",
                                             Ci.nsIAutoplay.PROMPT);
       if (state == Ci.nsIAutoplay.ALLOWED) {
         return SitePermissions.ALLOW;
       } if (state == Ci.nsIAutoplay.BLOCKED) {
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -11745,38 +11745,28 @@ void nsIDocument::NotifyUserGestureActiv
   while (doc && !doc->mUserGestureActivated) {
     MOZ_LOG(gUserInteractionPRLog, LogLevel::Debug,
             ("Document %p has been activated by user.", this));
     doc->mUserGestureActivated = true;
     doc = doc->GetSameTypeParentDocument();
   }
 }
 
-void nsIDocument::MaybeNotifyAutoplayBlocked() {
-  nsIDocument* topLevelDoc = GetTopLevelContentDocument();
-  if (!topLevelDoc ||
-      !nsContentUtils::IsExactSitePermDeny(topLevelDoc->NodePrincipal(),
-          "autoplay-media")) {
-    return;
-  }
-
-  // This event is used to notify front-end side that we've blocked autoplay
-  // permanantly, so front-end side should show blocking icon as well.
-  RefPtr<AsyncEventDispatcher> asyncDispatcher = new AsyncEventDispatcher(
-      topLevelDoc, NS_LITERAL_STRING("GloballyAutoplayBlocked"),
-      CanBubble::eYes, ChromeOnlyDispatch::eYes);
-  asyncDispatcher->PostDOMEvent();
-}
-
 void nsIDocument::SetDocTreeHadAudibleMedia() {
   nsIDocument* topLevelDoc = GetTopLevelContentDocument();
   if (!topLevelDoc) {
     return;
   }
 
+  if (!topLevelDoc->mDocTreeHadAudibleMedia) {
+    RefPtr<AsyncEventDispatcher> asyncDispatcher = new AsyncEventDispatcher(
+        topLevelDoc, NS_LITERAL_STRING("AudibleAutoplayMediaOccurred"),
+        CanBubble::eYes, ChromeOnlyDispatch::eYes);
+    asyncDispatcher->PostDOMEvent();
+  }
   topLevelDoc->mDocTreeHadAudibleMedia = true;
 }
 
 void nsIDocument::SetDocTreeHadPlayRevoked() {
   nsIDocument* topLevelDoc = GetTopLevelContentDocument();
   if (topLevelDoc) {
     topLevelDoc->mDocTreeHadPlayRevoked = true;
   }
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -3385,20 +3385,16 @@ class nsIDocument : public nsINode,
    * element containing the subdocument containing aFrame, and/or find the
    * nearest non-anonymous ancestor in this document.
    * Returns null if there is no such element.
    */
   nsIContent* GetContentInThisDocument(nsIFrame* aFrame) const;
 
   void ReportShadowDOMUsage();
 
-  // When the doc is blocked permanantly, we would dispatch event to notify
-  // front-end side to show blocking icon.
-  void MaybeNotifyAutoplayBlocked();
-
   // Sets flags for media autoplay telemetry.
   void SetDocTreeHadAudibleMedia();
   void SetDocTreeHadPlayRevoked();
 
  protected:
   void DoUpdateSVGUseElementShadowTrees();
 
   already_AddRefed<nsIPrincipal> MaybeDowngradePrincipal(
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -3692,17 +3692,16 @@ void HTMLMediaElement::DispatchEventsWhe
     DispatchAsyncEvent(NS_LITERAL_STRING("blocked"));
   }
 #if defined(MOZ_WIDGET_ANDROID)
   RefPtr<AsyncEventDispatcher> asyncDispatcher = new AsyncEventDispatcher(
       this, NS_LITERAL_STRING("MozAutoplayMediaBlocked"), CanBubble::eYes,
       ChromeOnlyDispatch::eYes);
   asyncDispatcher->PostDOMEvent();
 #endif
-  OwnerDoc()->MaybeNotifyAutoplayBlocked();
 }
 
 void HTMLMediaElement::PlayInternal(bool aHandlingUserInput) {
   if (mPreloadAction == HTMLMediaElement::PRELOAD_NONE) {
     // The media load algorithm will be initiated by a user interaction.
     // We want to boost the channel priority for better responsiveness.
     // Note this must be done before UpdatePreloadAction() which will
     // update |mPreloadAction|.
rename from toolkit/actors/AutoplayChild.jsm
rename to toolkit/actors/AudibleAutoplayChild.jsm
--- a/toolkit/actors/AutoplayChild.jsm
+++ b/toolkit/actors/AudibleAutoplayChild.jsm
@@ -1,15 +1,15 @@
 /* vim: set ts=2 sw=2 sts=2 et tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
-var EXPORTED_SYMBOLS = ["AutoplayChild"];
+var EXPORTED_SYMBOLS = ["AudibleAutoplayChild"];
 
 ChromeUtils.import("resource://gre/modules/ActorChild.jsm");
 
-class AutoplayChild extends ActorChild {
+class AudibleAutoplayChild extends ActorChild {
   handleEvent(event) {
-    this.mm.sendAsyncMessage("GloballyAutoplayBlocked");
+    this.mm.sendAsyncMessage("AudibleAutoplayMediaOccurred");
   }
 }
--- a/toolkit/actors/moz.build
+++ b/toolkit/actors/moz.build
@@ -6,18 +6,18 @@
 
 with Files('**'):
     BUG_COMPONENT = ('Toolkit', 'General')
 
 with Files('Finder*.jsm'):
     BUG_COMPONENT = ('Toolkit', 'Find Toolbar')
 
 FINAL_TARGET_FILES.actors += [
+    'AudibleAutoplayChild.jsm',
     'AudioPlaybackChild.jsm',
-    'AutoplayChild.jsm',
     'BrowserChild.jsm',
     'ControllersChild.jsm',
     'DateTimePickerChild.jsm',
     'ExtFindChild.jsm',
     'FindBarChild.jsm',
     'FinderChild.jsm',
     'PopupBlockingChild.jsm',
     'PrintingChild.jsm',
--- a/toolkit/content/tests/browser/browser.ini
+++ b/toolkit/content/tests/browser/browser.ini
@@ -25,16 +25,17 @@ support-files =
   silentAudioTrack.webm
   doggy.png
   firebird.png
 
 [browser_audioCompeting.js]
 tags = audiochannel
 [browser_audioCompeting_onlyForActiveAgent.js]
 tags = audiochannel
+[browser_autoplay_audibleMediaOccurred.js]
 [browser_autoplay_policy_iframe_hierarchy.js]
 support-files =
   file_autoplay_three_layers_frame1.html
   file_autoplay_three_layers_frame2.html
   file_autoplay_two_layers_frame1.html
   file_autoplay_two_layers_frame2.html
   file_video.html
   gizmo.mp4
new file mode 100644
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_autoplay_audibleMediaOccurred.js
@@ -0,0 +1,27 @@
+/**
+ * This test is used to test whether the topic 'AudibleAutoplayMediaOccurred'
+ * is sent correctly when the autoplay audible media tries to start.
+ */
+"use strict";
+
+const PAGE = "https://example.com/browser/toolkit/content/tests/browser/file_mediaPlayback.html";
+
+add_task(async function testAudibleAutoplayMedia() {
+  info("- open new tab  -");
+  let tab = await BrowserTestUtils.openNewForegroundTab(window.gBrowser,
+                                                        "about:blank");
+  let browser = tab.linkedBrowser;
+
+  // start observing the topic before loading the page to ensure we can get it.
+  let audibleAutoplayOccurred = TestUtils.topicObserved("AudibleAutoplayMediaOccurred");
+  browser.loadURI(PAGE, {
+    triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
+  });
+
+  await BrowserTestUtils.browserLoaded(browser);
+  await audibleAutoplayOccurred;
+  ok(true, "Got the topic 'AudibleAutoplayMediaOccurred'.");
+
+  info("- remove tab -");
+  BrowserTestUtils.removeTab(tab);
+});
--- a/toolkit/content/widgets/browser.xml
+++ b/toolkit/content/widgets/browser.xml
@@ -757,24 +757,21 @@
           <![CDATA[
             let event = document.createEvent("Events");
             event.initEvent("DOMAudioPlaybackStopped", true, false);
             this.dispatchEvent(event);
           ]]>
         </body>
       </method>
 
-      <method name="notifyGloballyAutoplayBlocked">
+      <method name="notifyAudibleAutoplayMediaOccurred">
         <body>
           <![CDATA[
-            let event = document.createEvent("CustomEvent");
-            event.initCustomEvent("GloballyAutoplayBlocked", true, false,
-              {
-                url: this.documentURI,
-              });
+            let event = document.createEvent("Events");
+            event.initEvent("AudibleAutoplayMediaOccurred", true, false);
             this.dispatchEvent(event);
           ]]>
         </body>
       </method>
 
       <!--
         When the pref "media.block-autoplay-until-in-foreground" is on,
         Gecko delays starting playback of media resources in tabs until the
@@ -1106,17 +1103,17 @@
             this.messageManager.addMessageListener("PopupBlocking:UpdateBlockedPopups", this);
             this.messageManager.addMessageListener("Autoscroll:Start", this);
             this.messageManager.addMessageListener("Autoscroll:Cancel", this);
             this.messageManager.addMessageListener("AudioPlayback:Start", this);
             this.messageManager.addMessageListener("AudioPlayback:Stop", this);
             this.messageManager.addMessageListener("AudioPlayback:ActiveMediaBlockStart", this);
             this.messageManager.addMessageListener("AudioPlayback:ActiveMediaBlockStop", this);
             this.messageManager.addMessageListener("UnselectedTabHover:Toggle", this);
-            this.messageManager.addMessageListener("GloballyAutoplayBlocked", this);
+            this.messageManager.addMessageListener("AudibleAutoplayMediaOccurred", this);
 
             if (this.hasAttribute("selectmenulist")) {
               this.messageManager.addMessageListener("Forms:ShowDropDown", this);
               this.messageManager.addMessageListener("Forms:HideDropDown", this);
             }
 
           }
         ]]></body>
@@ -1248,18 +1245,18 @@
             case "AudioPlayback:ActiveMediaBlockStop":
               this.activeMediaBlockStopped();
               break;
             case "UnselectedTabHover:Toggle":
               this._shouldSendUnselectedTabHover = data.enable ?
                 ++this._unselectedTabHoverMessageListenerCount > 0 :
                 --this._unselectedTabHoverMessageListenerCount == 0;
               break;
-            case "GloballyAutoplayBlocked":
-              this.notifyGloballyAutoplayBlocked();
+            case "AudibleAutoplayMediaOccurred":
+              this.notifyAudibleAutoplayMediaOccurred();
               break;
             case "Forms:ShowDropDown": {
               if (!this._selectParentHelper) {
                 this._selectParentHelper =
                   ChromeUtils.import("resource://gre/modules/SelectParentHelper.jsm", {}).SelectParentHelper;
               }
 
               let menulist = document.getElementById(this.getAttribute("selectmenulist"));
--- a/toolkit/modules/ActorManagerParent.jsm
+++ b/toolkit/modules/ActorManagerParent.jsm
@@ -96,38 +96,38 @@
 var EXPORTED_SYMBOLS = ["ActorManagerParent"];
 
 ChromeUtils.import("resource://gre/modules/ExtensionUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 const {DefaultMap} = ExtensionUtils;
 
 let ACTORS = {
+  AudibleAutoplay: {
+    child: {
+      module: "resource://gre/actors/AudibleAutoplayChild.jsm",
+      events: {
+        "AudibleAutoplayMediaOccurred": {},
+      },
+    },
+  },
+
   AudioPlayback: {
     child: {
       module: "resource://gre/actors/AudioPlaybackChild.jsm",
       messages: [
         "AudioPlayback",
         "TemporaryPermissionChanged",
       ],
       observers: [
         "audio-playback",
       ],
     },
   },
 
-  Autoplay: {
-    child: {
-      module: "resource://gre/actors/AutoplayChild.jsm",
-      events: {
-        "GloballyAutoplayBlocked": {},
-      },
-    },
-  },
-
   Browser: {
     child: {
       module: "resource://gre/actors/BrowserChild.jsm",
       events: {
         "DOMWindowClose": {},
       },
 
       messages: [