Bug 1543128 - Add a no-controls <video> UAWidget binding to show the Picture-in-Picture toggle. r=jaws
authorMike Conley <mconley@mozilla.com>
Mon, 15 Apr 2019 01:08:52 +0000
changeset 469461 3ac660e7f45c91f5af86614696a1f7acc760049a
parent 469460 15eaea4c4c08bf3bc74f0bf45b97bb1bbf585deb
child 469462 1f09366dd6bd135b45779af7c43a5c5184f747ec
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
bugs1543128
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 1543128 - Add a no-controls <video> UAWidget binding to show the Picture-in-Picture toggle. r=jaws Depends on D26803 Differential Revision: https://phabricator.services.mozilla.com/D26804
toolkit/content/widgets/videocontrols.js
--- a/toolkit/content/widgets/videocontrols.js
+++ b/toolkit/content/widgets/videocontrols.js
@@ -41,22 +41,25 @@ this.VideoControlsWidget = class {
    * - With "controls" set, the VideoControlsImplWidget controls should load.
    * - Without it, on mobile, the NoControlsMobileImplWidget should load, so
    *   the user could see the click-to-play button when the video/audio is blocked.
    * - Without it, on desktop, the NoControlsPictureInPictureImpleWidget should load
    *   if the video is being viewed in Picture-in-Picture.
    */
   switchImpl() {
     let newImpl;
+    let pageURI = this.document.documentURI;
     if (this.element.controls) {
       newImpl = VideoControlsImplWidget;
     } else if (this.isMobile) {
       newImpl = NoControlsMobileImplWidget;
     } else if (VideoControlsWidget.isPictureInPictureVideo(this.element)) {
       newImpl = NoControlsPictureInPictureImplWidget;
+    } else if (pageURI.startsWith("http://") || pageURI.startsWith("https://")) {
+      newImpl = NoControlsDesktopImplWidget;
     }
 
     // Skip if we are asked to load the same implementation, and
     // the underlying element state hasn't changed in ways that we
     // care about. This can happen if the property is set again
     // without a value change.
     if (this.impl &&
         this.impl.constructor == newImpl &&
@@ -2527,8 +2530,76 @@ this.NoControlsPictureInPictureImplWidge
             <span class="statusLabel" id="pictureInPicture">&status.pictureInPicture;</span>
           </div>
           <div class="controlsOverlay stackItem"></div>
         </div>
       </div>`, "application/xml");
     this.shadowRoot.importNodeAndAppendChildAt(this.shadowRoot, parserDoc.documentElement, true);
   }
 };
+
+this.NoControlsDesktopImplWidget = class {
+  constructor(shadowRoot, prefs) {
+    this.shadowRoot = shadowRoot;
+    this.element = shadowRoot.host;
+    this.document = this.element.ownerDocument;
+    this.window = this.document.defaultView;
+    this.prefs = prefs;
+  }
+
+  onsetup() {
+    this.generateContent();
+
+    this.Utils = {
+      init(shadowRoot, prefs) {
+        this.shadowRoot = shadowRoot;
+        this.prefs = prefs;
+        this.video = shadowRoot.host;
+        this.videocontrols = shadowRoot.firstChild;
+        this.document = this.videocontrols.ownerDocument;
+        this.window = this.document.defaultView;
+        this.shadowRoot = shadowRoot;
+
+        this.pictureInPictureToggleButton =
+          this.shadowRoot.getElementById("pictureInPictureToggleButton");
+
+        if (!this.pipToggleEnabled) {
+          this.pictureInPictureToggleButton.setAttribute("hidden", true);
+        }
+      },
+
+      get pipToggleEnabled() {
+        return this.prefs["media.videocontrols.picture-in-picture.video-toggle.enabled"];
+      },
+    };
+    this.Utils.init(this.shadowRoot, this.prefs);
+  }
+
+  elementStateMatches(element) {
+    return true;
+  }
+
+  destructor() {
+  }
+
+  generateContent() {
+    /*
+     * Pass the markup through XML parser purely for the reason of loading the localization DTD.
+     * Remove it when migrate to Fluent.
+     */
+    const parser = new this.window.DOMParser();
+    let parserDoc = parser.parseFromString(`<!DOCTYPE bindings [
+      <!ENTITY % videocontrolsDTD SYSTEM "chrome://global/locale/videocontrols.dtd">
+      %videocontrolsDTD;
+      ]>
+      <div class="videocontrols" xmlns="http://www.w3.org/1999/xhtml" role="none">
+        <link rel="stylesheet" type="text/css" href="chrome://global/skin/media/videocontrols.css" />
+        <div id="controlsContainer" class="controlsContainer" role="none">
+          <div class="controlsOverlay stackItem">
+            <button id="pictureInPictureToggleButton" class="pictureInPictureToggleButton">
+              <div id="pictureInPictureToggleIcon" class="pictureInPictureToggleIcon"></div>
+            </button>
+          </div>
+        </div>
+      </div>`, "application/xml");
+    this.shadowRoot.importNodeAndAppendChildAt(this.shadowRoot, parserDoc.documentElement, true);
+  }
+};