Bug 1543122 - Add a preference for controlling whether or not we display a toggle for Picture-in-Picture on <video> elements. r=jaws
authorMike Conley <mconley@mozilla.com>
Mon, 15 Apr 2019 01:07:13 +0000
changeset 469456 22f9a15468c4017eeae659c4f00eea7053a490f7
parent 469455 3619626a7662df350d6136343ad86c3799e3ab0d
child 469457 fbb2191cafbe3fc90a78e197a7d98af62bc95ac8
push id112792
push userncsoregi@mozilla.com
push dateMon, 15 Apr 2019 09:49:11 +0000
treeherdermozilla-inbound@a57f27d3ccd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjaws
bugs1543122
milestone68.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 1543122 - Add a preference for controlling whether or not we display a toggle for Picture-in-Picture on <video> elements. r=jaws Depends on D26775 Differential Revision: https://phabricator.services.mozilla.com/D26776
toolkit/actors/UAWidgetsChild.jsm
toolkit/content/widgets/videocontrols.js
--- a/toolkit/actors/UAWidgetsChild.jsm
+++ b/toolkit/actors/UAWidgetsChild.jsm
@@ -51,16 +51,19 @@ class UAWidgetsChild extends ActorChild 
     let uri;
     let widgetName;
     let prefKeys = [];
     switch (aElement.localName) {
       case "video":
       case "audio":
         uri = "chrome://global/content/elements/videocontrols.js";
         widgetName = "VideoControlsWidget";
+        prefKeys = [
+          "media.videocontrols.picture-in-picture.video-toggle.enabled",
+        ];
         break;
       case "input":
         uri = "chrome://global/content/elements/datetimebox.js";
         widgetName = "DateTimeBoxWidget";
         break;
       case "embed":
       case "object":
         uri = "chrome://global/content/elements/pluginProblem.js";
--- a/toolkit/content/widgets/videocontrols.js
+++ b/toolkit/content/widgets/videocontrols.js
@@ -7,18 +7,19 @@
 // This is a UA widget. It runs in per-origin UA widget scope,
 // to be loaded by UAWidgetsChild.jsm.
 
 /*
  * This is the class of entry. It will construct the actual implementation
  * according to the value of the "controls" property.
  */
 this.VideoControlsWidget = class {
-  constructor(shadowRoot) {
+  constructor(shadowRoot, prefs) {
     this.shadowRoot = shadowRoot;
+    this.prefs = prefs;
     this.element = shadowRoot.host;
     this.document = this.element.ownerDocument;
     this.window = this.document.defaultView;
 
     this.isMobile = this.window.navigator.appVersion.includes("Android");
   }
 
   /*
@@ -62,17 +63,17 @@ this.VideoControlsWidget = class {
         this.impl.elementStateMatches(this.element)) {
       return;
     }
     if (this.impl) {
       this.impl.destructor();
       this.shadowRoot.firstChild.remove();
     }
     if (newImpl) {
-      this.impl = new newImpl(this.shadowRoot);
+      this.impl = new newImpl(this.shadowRoot, this.prefs);
       this.impl.onsetup();
     } else {
       this.impl = undefined;
     }
   }
 
   destructor() {
     if (!this.impl) {
@@ -84,18 +85,19 @@ this.VideoControlsWidget = class {
   }
 
   static isPictureInPictureVideo(someVideo) {
     return someVideo.isCloningElementVisually;
   }
 };
 
 this.VideoControlsImplWidget = class {
-  constructor(shadowRoot) {
+  constructor(shadowRoot, prefs) {
     this.shadowRoot = shadowRoot;
+    this.prefs = prefs;
     this.element = shadowRoot.host;
     this.document = this.element.ownerDocument;
     this.window = this.document.defaultView;
   }
 
   onsetup() {
     this.generateContent();
 
@@ -1938,23 +1940,28 @@ this.VideoControlsImplWidget = class {
           if (this.clickToPlay.hidden && !this.video.played.length && this.video.paused) {
             this.clickToPlay.hiddenByAdjustment = false;
           }
           this.clickToPlay.style.width = `${clickToPlayScaledSize}px`;
           this.clickToPlay.style.height = `${clickToPlayScaledSize}px`;
         }
       },
 
-      init(shadowRoot) {
+      get pipToggleEnabled() {
+        return this.prefs["media.videocontrols.picture-in-picture.video-toggle.enabled"];
+      },
+
+      init(shadowRoot, prefs) {
         this.shadowRoot = shadowRoot;
         this.video = this.installReflowCallValidator(shadowRoot.host);
         this.videocontrols = this.installReflowCallValidator(shadowRoot.firstChild);
         this.document = this.videocontrols.ownerDocument;
         this.window = this.document.defaultView;
         this.shadowRoot = shadowRoot;
+        this.prefs = prefs;
 
         this.controlsContainer = this.shadowRoot.getElementById("controlsContainer");
         this.statusIcon = this.shadowRoot.getElementById("statusIcon");
         this.controlBar = this.shadowRoot.getElementById("controlBar");
         this.playButton = this.shadowRoot.getElementById("playButton");
         this.controlBarSpacer = this.shadowRoot.getElementById("controlBarSpacer");
         this.muteButton = this.shadowRoot.getElementById("muteButton");
         this.volumeStack = this.shadowRoot.getElementById("volumeStack");
@@ -2205,17 +2212,17 @@ this.VideoControlsImplWidget = class {
         // the controls to remain visible. this.controlsTimeout is a full
         // 5s, which feels too long after the transition.
         if (this.video.currentTime !== 0) {
           this.delayHideControls(this.Utils.HIDE_CONTROLS_TIMEOUT_MS);
         }
       },
     };
 
-    this.Utils.init(this.shadowRoot);
+    this.Utils.init(this.shadowRoot, this.prefs);
     if (this.Utils.isTouchControls) {
       this.TouchUtils.init(this.shadowRoot, this.Utils);
     }
     this.shadowRoot.firstChild.dispatchEvent(new this.window.CustomEvent("VideoBindingAttached"));
 
     this._setupEventListeners();
   }
 
@@ -2463,18 +2470,19 @@ this.NoControlsMobileImplWidget = class 
           </div>
         </div>
       </div>`, "application/xml");
     this.shadowRoot.importNodeAndAppendChildAt(this.shadowRoot, parserDoc.documentElement, true);
   }
 };
 
 this.NoControlsPictureInPictureImplWidget = class {
-  constructor(shadowRoot) {
+  constructor(shadowRoot, prefs) {
     this.shadowRoot = shadowRoot;
+    this.prefs = prefs;
     this.element = shadowRoot.host;
     this.document = this.element.ownerDocument;
     this.window = this.document.defaultView;
   }
 
   onsetup() {
     this.generateContent();
   }