Bug 1271765 - Part 2: Desktop media control visual refresh. r=jaws draft
authorRay Lin <ralin@mozilla.com>
Wed, 12 Oct 2016 13:31:32 +0800
changeset 440739 6e9d55baed71352d21c73ac00cccd32d140384ea
parent 440738 b931d68b87a693e06310d6ee788afa300c2ccda4
child 440740 c95a694a5c7c938a05966df1e5312265fcec9fe6
push id36312
push userbmo:ralin@mozilla.com
push dateFri, 18 Nov 2016 02:12:31 +0000
reviewersjaws
bugs1271765
milestone53.0a1
Bug 1271765 - Part 2: Desktop media control visual refresh. r=jaws MozReview-Commit-ID: 1GfyGmrhgCs
dom/media/webvtt/vtt.jsm
toolkit/content/widgets/videocontrols.xml
toolkit/locales/en-US/chrome/global/videocontrols.dtd
toolkit/themes/shared/jar.inc.mn
toolkit/themes/shared/media/TopLevelVideoDocument.css
toolkit/themes/shared/media/closeCaptionButton.png
toolkit/themes/shared/media/closeCaptionButton@2x.png
toolkit/themes/shared/media/closedCaptionButton.svg
toolkit/themes/shared/media/error.png
toolkit/themes/shared/media/fullscreenButton.png
toolkit/themes/shared/media/fullscreenButton.svg
toolkit/themes/shared/media/fullscreenButton@2x.png
toolkit/themes/shared/media/muteButton.png
toolkit/themes/shared/media/muteButton.svg
toolkit/themes/shared/media/muteButton@2x.png
toolkit/themes/shared/media/noAudio.png
toolkit/themes/shared/media/noAudio@2x.png
toolkit/themes/shared/media/pauseButton.png
toolkit/themes/shared/media/pauseButton.svg
toolkit/themes/shared/media/pauseButton@2x.png
toolkit/themes/shared/media/playButton.png
toolkit/themes/shared/media/playButton.svg
toolkit/themes/shared/media/playButton@2x.png
toolkit/themes/shared/media/scrubberThumb.png
toolkit/themes/shared/media/scrubberThumb@2x.png
toolkit/themes/shared/media/scrubberThumbWide.png
toolkit/themes/shared/media/scrubberThumbWide@2x.png
toolkit/themes/shared/media/unmuteButton.png
toolkit/themes/shared/media/unmuteButton@2x.png
toolkit/themes/shared/media/videocontrols.css
toolkit/themes/shared/media/volume-empty.png
toolkit/themes/shared/media/volume-empty@2x.png
toolkit/themes/shared/media/volume-full.png
toolkit/themes/shared/media/volume-full@2x.png
--- a/dom/media/webvtt/vtt.jsm
+++ b/dom/media/webvtt/vtt.jsm
@@ -1146,17 +1146,17 @@ this.EXPORTED_SYMBOLS = ["WebVTT"];
       overlay.removeChild(overlay.firstChild);
     }
 
     var controlBar;
     var controlBarShown;
 
     if (controls) {
       controlBar = controls.ownerDocument.getAnonymousElementByAttribute(
-        controls, "class", "controlBar");
+        controls, "anonid", "controlBar");
       controlBarShown = controlBar ? !!controlBar.clientHeight : false;
     }
 
     var paddedOverlay = window.document.createElement("div");
     paddedOverlay.style.position = "absolute";
     paddedOverlay.style.left = "0";
     paddedOverlay.style.right = "0";
     paddedOverlay.style.top = "0";
--- a/toolkit/content/widgets/videocontrols.xml
+++ b/toolkit/content/widgets/videocontrols.xml
@@ -41,16 +41,17 @@
         </getter>
         <setter>
           <![CDATA[
           this.setAttribute("showhours", val);
           // If the duration becomes known while we're still showing the value
           // for time=0, immediately update the value to show or hide the hours.
           // It's less intrusive to do it now than when the user clicks play and
           // is looking right next to the thumb.
+          if (!this.timeLabel) return;
           var displayedTime = this.timeLabel.getAttribute("value");
           if (val && displayedTime == "0:00")
               this.timeLabel.setAttribute("value", "0:00:00");
           else if (!val && displayedTime == "0:00:00")
               this.timeLabel.setAttribute("value", "0:00");
           ]]>
         </setter>
       </property>
@@ -126,17 +127,21 @@
             switch (which) {
               case "curpos":
                 if (this.type == "scrubber") {
                     // Update the time shown in the thumb.
                     this.thumb.setTime(newValue);
                     this.Utils.positionLabel.setAttribute("value", this.thumb.timeLabel.value);
                     // Update the value bar to match the thumb position.
                     let percent = newValue / this.max;
-                    this.valueBar.value = Math.round(percent * 10000); // has max=10000
+                    if (!isNaN(percent) && percent != Infinity) {
+                      this.valueBar.value = Math.round(percent * 10000); // has max=10000
+                    } else {
+                      this.valueBar.removeAttribute("value");
+                    }
                 }
 
                 // The value of userChanged is true when changing the position with the mouse,
                 // but not when pressing an arrow key. However, the base binding sets
                 // ._userChanged in its keypress handlers, so we just need to check both.
                 if (!userChanged && !this._userChanged)
                   return;
                 this.setAttribute("value", newValue);
@@ -198,84 +203,89 @@
 
   <binding id="videoControls">
 
     <resources>
         <stylesheet src="chrome://global/content/bindings/videocontrols.css"/>
         <stylesheet src="chrome://global/skin/media/videocontrols.css"/>
     </resources>
 
-    <xbl:content xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-                 class="mediaControlsFrame">
-        <stack flex="1">
-            <vbox flex="1" class="statusOverlay" hidden="true">
-                <box class="statusIcon"/>
-                <label class="errorLabel" anonid="errorAborted">&error.aborted;</label>
-                <label class="errorLabel" anonid="errorNetwork">&error.network;</label>
-                <label class="errorLabel" anonid="errorDecode">&error.decode;</label>
-                <label class="errorLabel" anonid="errorSrcNotSupported">&error.srcNotSupported;</label>
-                <label class="errorLabel" anonid="errorNoSource">&error.noSource2;</label>
-                <label class="errorLabel" anonid="errorGeneric">&error.generic;</label>
-            </vbox>
+    <xbl:content xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    xmlns="http://www.w3.org/1999/xhtml" class="mediaControlsFrame">
+        <div anonid="controlsContainer" class="controlsContainer" role="none">
+            <div anonid="statusOverlay" class="statusOverlay stackItem" hidden="true">
+                <div anonid="statusIcon" class="statusIcon"></div>
+                <span class="errorLabel" anonid="errorAborted">&error.aborted;</span>
+                <span class="errorLabel" anonid="errorNetwork">&error.network;</span>
+                <span class="errorLabel" anonid="errorDecode">&error.decode;</span>
+                <span class="errorLabel" anonid="errorSrcNotSupported">&error.srcNotSupported;</span>
+                <span class="errorLabel" anonid="errorNoSource">&error.noSource2;</span>
+                <span class="errorLabel" anonid="errorGeneric">&error.generic;</span>
+            </div>
 
-            <vbox class="controlsOverlay">
-                <stack flex="1">
-                    <spacer class="controlsSpacer" flex="1"/>
-                    <box class="clickToPlay" hidden="true" flex="1"/>
-                    <vbox class="textTrackList" hidden="true" offlabel="&closedCaption.off;"></vbox>
-                </stack>
-                <hbox class="controlBar" hidden="true">
-                    <button class="playButton"
+            <div anonid="controlsOverlay" class="controlsOverlay stackItem">
+                <div class="controlsSpacerStack" aria-hideen="true">
+                  <div anonid="controlsSpacer" class="controlsSpacer stackItem" role="none"></div>
+                  <div anonid="clickToPlay" class="clickToPlay" hidden="true"></div>
+                </div>
+                <div anonid="controlBar" class="controlBar" hidden="true">
+                    <button anonid="playButton"
+                            class="playButton"
                             playlabel="&playButton.playLabel;"
                             pauselabel="&playButton.pauseLabel;"/>
-                    <stack class="scrubberStack" flex="1">
-                        <box class="backgroundBar"/>
-                        <progressmeter class="bufferBar"/>
-                        <progressmeter class="progressBar" max="10000"/>
-                        <scale class="scrubber" movetoclick="true"/>
-                    </stack>
-                    <vbox class="durationBox">
-                        <label class="positionLabel" role="presentation"/>
-                        <label class="durationLabel" role="presentation"/>
-                    </vbox>
-                    <button class="muteButton"
+                    <div anonid="scrubberStack" class="scrubberStack progressContainer" role="none">
+                      <div class="progressBackgroundBar stackItem" role="none">
+                        <div class="progressStack" role="none">
+                          <progress anonid="bufferBar" class="bufferBar" value="0" max="100"></progress>
+                          <progress anonid="progressBar" class="progressBar" value="0" max="100"></progress>
+                        </div>
+                      </div>
+                      <input type="range" anonid="scrubber" class="scrubber"/>
+                    </div>
+                    <span anonid="positionLabel" class="positionLabel" role="presentation"></span>
+                    <span anonid="durationLabel" class="durationLabel" role="presentation"></span>
+                    <div anonid="positionDurationBox" class="positionDurationBox" role="none">
+                      &positionAndDuration.nameFormat;
+                    </div>
+                    <div anonid="controlBarSpacer" class="controlBarSpacer" hidden="true" role="none"></div>
+                    <button anonid="muteButton"
+                            class="muteButton"
                             mutelabel="&muteButton.muteLabel;"
                             unmutelabel="&muteButton.unmuteLabel;"/>
-                    <stack class="volumeStack">
-                      <box class="volumeBackground"/>
-                      <box class="volumeForeground" anonid="volumeForeground"/>
-                      <scale class="volumeControl" movetoclick="true"/>
-                    </stack>
-                    <button class="closedCaptionButton"/>
-                    <button class="fullscreenButton"
+                    <div anonid="volumeStack" class="volumeStack progressContainer" role="none">
+                      <input type="range" anonid="volumeControl" class="volumeControl" min="0" max="100" step="1"/>
+                    </div>
+                    <button anonid="closedCaptionButton" class="closedCaptionButton"/>
+                    <button anonid="fullscreenButton"
+                            class="fullscreenButton"
                             enterfullscreenlabel="&fullscreenButton.enterfullscreenlabel;"
                             exitfullscreenlabel="&fullscreenButton.exitfullscreenlabel;"/>
-                </hbox>
-            </vbox>
-        </stack>
+                </div>
+                <div anonid="textTrackList" class="textTrackList" hidden="true" offlabel="&closedCaption.off;"></div>
+            </div>
+        </div>
     </xbl:content>
 
     <implementation>
 
         <constructor>
             <![CDATA[
-            this.isTouchControl = false;
+            this.isTouchControls = false;
             this.randomID = 0;
 
             this.Utils = {
                 debug : false,
                 video : null,
                 videocontrols : null,
                 controlBar : null,
                 playButton : null,
                 muteButton : null,
                 volumeControl  : null,
                 durationLabel  : null,
                 positionLabel  : null,
-                scrubberThumb  : null,
                 scrubber       : null,
                 progressBar    : null,
                 bufferBar      : null,
                 statusOverlay  : null,
                 controlsSpacer : null,
                 clickToPlay    : null,
                 controlsOverlay : null,
                 fullscreenButton : null,
@@ -288,26 +298,27 @@
                                "playing", "waiting", "canplay", "canplaythrough",
                                "seeking", "seeked", "emptied", "loadedmetadata",
                                "error", "suspend", "stalled",
                                "mozinterruptbegin", "mozinterruptend" ],
 
                 firstFrameShown : false,
                 timeUpdateCount : 0,
                 maxCurrentTimeSeen : 0,
+                isPausedByDragging: false,
                 _isAudioOnly : false,
                 get isAudioOnly() { return this._isAudioOnly; },
                 set isAudioOnly(val) {
                     this._isAudioOnly = val;
                     this.setFullscreenButtonState();
 
                     if (!this.isTopLevelSyntheticDocument)
                         return;
                     if (this._isAudioOnly) {
-                        this.video.style.height = this._controlBarHeight + "px";
+                        this.video.style.height = this.controlBar.minHeight + "px";
                         this.video.style.width = "66%";
                     } else {
                         this.video.style.removeProperty("height");
                         this.video.style.removeProperty("width");
                     }
                 },
                 suppressError : false,
 
@@ -361,16 +372,17 @@
 
                     this.setFullscreenButtonState();
 
                     var duration = Math.round(this.video.duration * 1000); // in ms
                     var currentTime = Math.round(this.video.currentTime * 1000); // in ms
                     this.log("Initial playback position is at " + currentTime + " of " + duration);
                     // It would be nice to retain maxCurrentTimeSeen, but it would be difficult
                     // to determine if the media source changed while we were detached.
+                    this.initPositionDurationBox();
                     this.maxCurrentTimeSeen = currentTime;
                     this.showPosition(currentTime, duration);
 
                     // If we have metadata, check if this is a <video> without
                     // video data, or a video with no audio track.
                     if (this.video.readyState >= this.video.HAVE_METADATA) {
                         if (this.video instanceof HTMLVideoElement &&
                             (this.video.videoWidth == 0 || this.video.videoHeight == 0))
@@ -391,41 +403,92 @@
 
                     // If the first frame hasn't loaded, kick off a throbber fade-in.
                     if (this.video.readyState >= this.video.HAVE_CURRENT_DATA)
                         this.firstFrameShown = true;
 
                     // We can't determine the exact buffering status, but do know if it's
                     // fully loaded. (If it's still loading, it will fire a progress event
                     // and we'll figure out the exact state then.)
-                    this.bufferBar.setAttribute("max", 100);
+                    this.bufferBar.max = 100;
                     if (this.video.readyState >= this.video.HAVE_METADATA)
                         this.showBuffered();
                     else
-                        this.bufferBar.setAttribute("value", 0);
+                        this.bufferBar.value = 0;
 
                     // Set the current status icon.
                     if (this.hasError()) {
                         this.clickToPlay.hidden = true;
                         this.statusIcon.setAttribute("type", "error");
                         this.updateErrorText();
                         this.setupStatusFader(true);
                     }
 
                     // An event handler for |onresize| should be added when bug 227495 is fixed.
                     this.controlBar.hidden = false;
-                    this._playButtonWidth = this.playButton.clientWidth;
-                    this._durationLabelWidth = this.durationLabel.clientWidth;
-                    this._muteButtonWidth = this.muteButton.clientWidth;
-                    this._volumeControlWidth = this.volumeControl.clientWidth;
-                    this._closedCaptionButtonWidth = this.closedCaptionButton.clientWidth;
-                    this._fullscreenButtonWidth = this.fullscreenButton.clientWidth;
-                    this._controlBarHeight = this.controlBar.clientHeight;
+
+                    let layoutControls = [
+                      ...this.controlBar.children,
+                      this.durationSpan,
+                      this.controlBar,
+                      this.clickToPlay
+                    ];
+
+                    for (let control of layoutControls) {
+                      if (!control) {
+                        break;
+                      }
+
+                      Object.defineProperties(control, {
+                        minWidth: {
+                          value: control.clientWidth,
+                          writable: true
+                        },
+                        minHeight: {
+                          value: control.clientHeight,
+                          writable: true
+                        },
+                        isAdjustableControl: {
+                          value: true
+                        },
+                        isWanted: {
+                          value: true,
+                          writable: true
+                        },
+                        hideByAdjustment: {
+                          set: (v) => {
+                            if (v) {
+                              control.setAttribute("hidden", "true");
+                            } else {
+                              control.removeAttribute("hidden");
+                            }
+
+                            control._isHiddenByAdjustment = v;
+                          },
+                          get: () => control._isHiddenByAdjustment
+                        },
+                        _isHiddenByAdjustment: {
+                          value: false,
+                          writable: true
+                        }
+                      });
+                    }
+                    // Cannot get minimal width of flexible scrubber and clickToPlay.
+                    // Rewrite to empirical value for now.
+                    this.controlBar.minHeight = 40;
+                    this.scrubberStack.minWidth = 64;
+                    this.volumeControl.minWidth = 48;
+                    this.clickToPlay.minWidth = 48;
+
+                    if (this.positionDurationBox) {
+                      this.positionDurationBox.minWidth -= this.durationSpan.minWidth;
+                    }
+
+                    this.adjustControlSize();
                     this.controlBar.hidden = true;
-                    this.adjustControlSize();
 
                     // Can only update the volume controls once we've computed
                     // _volumeControlWidth, since the volume slider implementation
                     // depends on it.
                     this.updateVolumeControls();
                 },
 
                 setupNewLoadState : function() {
@@ -438,18 +501,20 @@
                     // so that they don't get in the way of the playing video. Otherwise we'll
                     // go ahead and reveal the controls now, so they're an obvious user cue.
                     //
                     // (Note: the |controls| attribute is already handled via layout/style/html.css)
                     var shouldShow = !this.dynamicControls ||
                       (this.video.paused &&
                        !(this.video.autoplay && this.video.mozAutoplayEnabled));
                     // Hide the overlay if the video time is non-zero or if an error occurred to workaround bug 718107.
-                    this.startFade(this.clickToPlay, shouldShow && !this.isAudioOnly &&
-                                   this.video.currentTime == 0 && !this.hasError(), true);
+                    let shouldClickToPlayShow = shouldShow && !this.isAudioOnly &&
+                                                this.video.currentTime == 0 && !this.hasError();
+                    this.startFade(this.clickToPlay, shouldClickToPlayShow, true);
+                    this.startFade(this.controlsSpacer, shouldClickToPlayShow, true);
                     this.startFade(this.controlBar, shouldShow, true);
                 },
 
                 get dynamicControls() {
                     // Don't fade controls for <audio> elements.
                     var enabled = !this.isAudioOnly;
 
                     // Allow tests to explicitly suppress the fading of controls.
@@ -459,39 +524,43 @@
                     // If the video hits an error, suppress controls if it
                     // hasn't managed to do anything else yet.
                     if (!this.firstFrameShown && this.hasError())
                         enabled = false;
 
                     return enabled;
                 },
 
+                updateVolume() {
+                  const volume = this.volumeControl.value;
+                  this.setVolume(volume / 100);
+                },
+
                 updateVolumeControls() {
                     var volume = this.video.muted ? 0 : this.video.volume;
                     var volumePercentage = Math.round(volume * 100);
                     this.updateMuteButtonState();
                     this.volumeControl.value = volumePercentage;
-                    this.volumeForeground.style.paddingRight = (1 - volume) * this._volumeControlWidth + "px";
                 },
 
                 handleEvent : function(aEvent) {
                     this.log("Got media event ----> " + aEvent.type);
 
                     // If the binding is detached (or has been replaced by a
                     // newer instance of the binding), nuke our event-listeners.
                     if (this.videocontrols.randomID != this.randomID) {
                         this.terminateEventListeners();
                         return;
                     }
 
                     switch (aEvent.type) {
                         case "play":
                             this.setPlayButtonState(false);
                             this.setupStatusFader();
-                            if (!this._triggeredByControls && this.dynamicControls && this.videocontrols.isTouchControl)
+                            if (!this._triggeredByControls && this.dynamicControls && this.videocontrols.isTouchControls)
                                 this.startFadeOut(this.controlBar);
                             if (!this._triggeredByControls)
                                 this.clickToPlay.hidden = true;
                             this._triggeredByControls = false;
                             break;
                         case "pause":
                             // Little white lie: if we've internally paused the video
                             // while dragging the scrubber, don't change the button state.
@@ -580,20 +649,21 @@
                             // statusOverlay while we wait for HAVE_ENOUGH_DATA).
                             // If we've seen more than 2 timeupdate events,
                             // the count is no longer relevant to setupStatusFader.
                             if (this.timeUpdateCount <= 2)
                                 this.setupStatusFader();
 
                             // If the user is dragging the scrubber ignore the delayed seek
                             // responses (don't yank the thumb away from the user)
-                            if (this.scrubber.isDragging)
+                            if (this.scrubber.isDragging || this.scrubber.startToDrag)
                                 return;
 
                             this.showPosition(currentTime, duration);
+                            this.showBuffered();
                             break;
                         case "emptied":
                             this.bufferBar.value = 0;
                             this.showPosition(0, 0);
                             break;
                         case "seeking":
                             this.showBuffered();
                             this.statusIcon.setAttribute("type", "throbber");
@@ -739,41 +809,120 @@
                             mins = "0" + mins;
                         timeString = hours + ":" + mins + ":" + secs;
                     } else {
                         timeString = mins + ":" + secs;
                     }
                     return timeString;
                 },
 
+                initPositionDurationBox : function() {
+                  if (this.videocontrols.isTouchControls) {
+                    return;
+                  }
+
+                  const positionTextNode = Array.prototype.find.call(
+                    this.positionDurationBox.childNodes, (n) => !!~n.textContent.search("#1"));
+                  const durationSpan = this.durationSpan;
+                  const durationFormat = durationSpan.textContent;
+                  const positionFormat = positionTextNode.textContent;
+
+                  durationSpan.classList.add("duration");
+                  durationSpan.setAttribute("role", "none");
+
+                  Object.defineProperties(this.positionDurationBox, {
+                    durationSpan: {
+                      value: durationSpan
+                    },
+                    position: {
+                      set: (v) => {
+                        positionTextNode.textContent = positionFormat.replace("#1", v);
+                      }
+                    },
+                    duration: {
+                      set: (v) => {
+                        durationSpan.textContent = v ? durationFormat.replace("#2", v) : "";
+                      }
+                    }
+                  });
+                },
+
                 showDuration : function(duration) {
                     let isInfinite = (duration == Infinity);
                     this.log("Duration is " + duration + "ms.\n");
 
                     if (isNaN(duration) || isInfinite)
                         duration = this.maxCurrentTimeSeen;
 
                     // Format the duration as "h:mm:ss" or "m:ss"
                     let timeString = isInfinite ? "" : this.formatTime(duration);
-                    this.durationLabel.setAttribute("value", timeString);
+                    if (this.videocontrols.isTouchControls) {
+                      this.durationLabel.setAttribute("value", timeString);
+                    } else {
+                      this.positionDurationBox.duration = timeString;
+                    }
 
                     // "durationValue" property is used by scale binding to
                     // generate accessible name.
                     this.scrubber.durationValue = timeString;
 
                     // If the duration is over an hour, thumb should show h:mm:ss instead of mm:ss
-                    this.scrubberThumb.showHours = (duration >= 3600000);
 
                     this.scrubber.max = duration;
                     // XXX Can't set increment here, due to bug 473103. Also, doing so causes
                     // snapping when dragging with the mouse, so we can't just set a value for
                     // the arrow-keys.
                     this.scrubber.pageIncrement = Math.round(duration / 10);
                 },
 
+                pauseVideoDuringDragging: function() {
+                  if (!this.video.paused &&
+                      !this.isPausedByDragging &&
+                      this.scrubber.isDragging) {
+                    this.isPausedByDragging = true;
+                    this.video.pause();
+                  }
+                },
+
+                onScrubberInput: function(e) {
+                  const duration = Math.round(this.video.duration * 1000); // in ms
+                  let time = this.scrubber.value;
+
+                  if (!this.scrubber.startToDrag || this.scrubber.isDragging) {
+                    this.seekToPosition(time);
+                    this.showPosition(time, duration);
+                  }
+
+                  this.scrubber.startToDrag = true;
+                },
+
+                onScrubberChange: function(e) {
+                  this.scrubber.startToDrag = false;
+                  this.scrubber.isDragging = false;
+
+                  if (this.isPausedByDragging) {
+                    this.video.play();
+                    this.isPausedByDragging = false;
+                  }
+                },
+
+                updateScrubberProgress() {
+                  if (this.videocontrols.isTouchControls) {
+                    return;
+                  }
+
+                  const positionPercent = this.scrubber.value / this.scrubber.max * 100;
+
+                  if (!isNaN(positionPercent) && positionPercent != Infinity) {
+                    this.progressBar.value = positionPercent;
+                  } else {
+                    this.progressBar.value = 0;
+                  }
+                },
+
                 seekToPosition : function(newPosition) {
                     newPosition /= 1000; // convert from ms
                     this.log("+++ seeking to " + newPosition);
                     if (this.videocontrols.isGonk) {
                         // We use fastSeek() on B2G, and an accurate (but slower)
                         // seek on other platforms (that are likely to be higher
                         // perf).
                         this.video.fastSeek(newPosition);
@@ -793,18 +942,25 @@
                     // it, or the video is a stream), then we want to fudge the duration
                     // by using the maximum playback position that's been seen.
                     if (currentTime > this.maxCurrentTimeSeen)
                         this.maxCurrentTimeSeen = currentTime;
                     this.showDuration(duration);
 
                     this.log("time update @ " + currentTime + "ms of " + duration + "ms");
 
-                    this.positionLabel.setAttribute("value", this.formatTime(currentTime));
+                    let positionTime = this.formatTime(currentTime);
+
                     this.scrubber.value = currentTime;
+                    if (this.videocontrols.isTouchControls) {
+                      this.positionLabel.setAttribute("value", positionTime);
+                    } else {
+                      this.positionDurationBox.position = positionTime;
+                      this.updateScrubberProgress();
+                    }
                 },
 
                 showBuffered : function() {
                     function bsearch(haystack, needle, cmp) {
                         var length = haystack.length;
                         var low = 0;
                         var high = length;
                         while (low < high) {
@@ -826,18 +982,19 @@
                             return 1;
                         } else if (time >= buffered.start(i)) {
                             return 0;
                         }
                         return -1;
                     }
 
                     var duration = Math.round(this.video.duration * 1000);
-                    if (isNaN(duration))
+                    if (isNaN(duration) || duration == Infinity) {
                         duration = this.maxCurrentTimeSeen;
+                    }
 
                     // Find the range that the current play position is in and use that
                     // range for bufferBar.  At some point we may support multiple ranges
                     // displayed in the bar.
                     var currentTime = this.video.currentTime;
                     var buffered = this.video.buffered;
                     var index = bsearch(buffered, currentTime, bufferedCompare);
                     var endTime = 0;
@@ -865,18 +1022,19 @@
                         Utils.startFade(Utils.controlBar, false);
                         Utils._hideControlsTimeout = 0;
                         Utils._controlsHiddenByTimeout = true;
                     }
                 },
                 HIDE_CONTROLS_TIMEOUT_MS : 2000,
                 onMouseMove : function(event) {
                     // Pause playing video when the mouse is dragging over the control bar.
-                    if (this.scrubber.isDragging) {
-                      this.scrubber.pauseVideoDuringDragging();
+                    if (this.scrubber.startToDrag) {
+                      this.scrubber.isDragging = true;
+                      this.pauseVideoDuringDragging();
                     }
 
                     // If the controls are static, don't change anything.
                     if (!this.dynamicControls)
                         return;
 
                     clearTimeout(this._hideControlsTimeout);
 
@@ -954,25 +1112,29 @@
                 },
 
                 startFade : function(element, fadeIn, immediate) {
                     if (element.classList.contains("controlBar") && fadeIn) {
                         // Bug 493523, the scrubber doesn't call valueChanged while hidden,
                         // so our dependent state (eg, timestamp in the thumb) will be stale.
                         // As a workaround, update it manually when it first becomes unhidden.
                         if (element.hidden)
+                          if (this.videocontrols.isTouchControls) {
                             this.scrubber.valueChanged("curpos", this.video.currentTime * 1000, false);
+                          } else {
+                            this.scrubber.value = this.video.currentTime * 1000;
+                          }
                     }
 
                     if (immediate)
                         element.setAttribute("immediate", true);
                     else
                         element.removeAttribute("immediate");
 
-                    if (fadeIn) {
+                    if (fadeIn && !(element.isAdjustableControl && element.hideByAdjustment)) {
                         element.hidden = false;
                         // force style resolution, so that transition begins
                         // when we remove the attribute.
                         element.clientTop;
                         element.removeAttribute("fadeout");
                         if (element.classList.contains("controlBar"))
                             this.controlsSpacer.removeAttribute("hideCursor");
                     } else {
@@ -990,17 +1152,19 @@
                         return;
 
                     var element = event.originalTarget;
 
                     // Nothing to do when a fade *in* finishes.
                     if (!element.hasAttribute("fadeout"))
                         return;
 
-                    this.scrubber.dragStateChanged(false);
+                    if (this.videocontrols.isTouchControls) {
+                      this.scrubber.dragStateChanged(false);
+                    }
                     element.hidden = true;
                 },
 
                 _triggeredByControls: false,
 
                 startPlay : function() {
                     this._triggeredByControls = true;
                     this.hideClickToPlay();
@@ -1097,24 +1261,27 @@
                 hideClickToPlay : function() {
                     let videoHeight = this.video.clientHeight;
                     let videoWidth = this.video.clientWidth;
 
                     // The play button will animate to 3x its size. This
                     // shows the animation unless the video is too small
                     // to show 2/3 of the animation.
                     let animationScale = 2;
-                    if (this._overlayPlayButtonHeight * animationScale > (videoHeight - this._controlBarHeight) ||
-                        this._overlayPlayButtonWidth * animationScale > videoWidth) {
-                        this.clickToPlay.setAttribute("immediate", "true");
-                        this.clickToPlay.hidden = true;
+                    let animationMinSize = this.clickToPlay.minWidth * animationScale;
+
+                    if (animationMinSize > videoWidth ||
+                        animationMinSize > (videoHeight - this.controlBar.minHeight)) {
+                      this.clickToPlay.setAttribute("immediate", "true");
+                      this.clickToPlay.hidden = true;
                     } else {
                         this.clickToPlay.removeAttribute("immediate");
                     }
                     this.clickToPlay.setAttribute("fadeout", "true");
+                    this.controlsSpacer.setAttribute("fadeout", "true");
                 },
 
                 setPlayButtonState : function(aPaused) {
                   if (aPaused)
                       this.playButton.setAttribute("paused", "true");
                   else
                       this.playButton.removeAttribute("paused");
 
@@ -1248,43 +1415,48 @@
                     event.preventDefault(); // Prevent page scrolling
                 },
 
                 isSupportedTextTrack : function(textTrack) {
                   return textTrack.kind == "subtitles" ||
                          textTrack.kind == "captions";
                 },
 
+                get isClosedCaptionAvailable() {
+                  return this.overlayableTextTracks.length && !this.videocontrols.isTouchControls;
+                },
+
                 get overlayableTextTracks() {
                   return Array.prototype.filter.call(this.video.textTracks, this.isSupportedTextTrack);
                 },
 
                 isClosedCaptionOn : function() {
                   for (let tt of this.overlayableTextTracks) {
                     if (tt.mode === "showing") {
                       return true;
                     }
                   }
 
                   return false;
                 },
 
                 setClosedCaptionButtonState : function() {
-                  if (!this.overlayableTextTracks.length || this.videocontrols.isTouchControl) {
+                  if (!this.isClosedCaptionAvailable) {
                     this.closedCaptionButton.setAttribute("hidden", "true");
                     return;
                   }
 
                   this.closedCaptionButton.removeAttribute("hidden");
 
                   if (this.isClosedCaptionOn()) {
                     this.closedCaptionButton.setAttribute("enabled", "true");
                   } else {
                     this.closedCaptionButton.removeAttribute("enabled");
                   }
+                  this.adjustControlSize();
 
                   let ttItems = this.textTrackList.childNodes;
 
                   for (let tti of ttItems) {
                     const idx = +tti.getAttribute("index");
 
                     if (idx == this.currentTextTrackIndex) {
                       tti.setAttribute("on", "true");
@@ -1348,43 +1520,21 @@
                 },
 
                 onControlBarTransitioned : function() {
                   this.textTrackList.setAttribute("hidden", "true");
                   this.video.dispatchEvent(new CustomEvent("controlbarchange"));
                 },
 
                 toggleClosedCaption : function() {
-                  if (this.overlayableTextTracks.length === 1) {
-                    const lastTTIdx = this.overlayableTextTracks[0].index;
-                    this.changeTextTrack(this.isClosedCaptionOn() ? 0 : lastTTIdx);
-                    return;
-                  }
-
                   if (this.textTrackList.hasAttribute("hidden")) {
                     this.textTrackList.removeAttribute("hidden");
                   } else {
                     this.textTrackList.setAttribute("hidden", "true");
                   }
-
-                  let maxButtonWidth = 0;
-
-                  for (let tti of this.textTrackList.childNodes) {
-                    if (tti.clientWidth > maxButtonWidth) {
-                      maxButtonWidth = tti.clientWidth;
-                    }
-                  }
-
-                  if (maxButtonWidth > this.video.clientWidth) {
-                    maxButtonWidth = this.video.clientWidth;
-                  }
-
-                  for (let tti of this.textTrackList.childNodes) {
-                    tti.style.width = maxButtonWidth + "px";
-                  }
                 },
 
                 onTextTrackAdd : function(trackEvent) {
                   this.addNewTextTrack(trackEvent.track);
                   this.setClosedCaptionButtonState();
                 },
 
                 onTextTrackRemove : function(trackEvent) {
@@ -1409,16 +1559,21 @@
                       this.video.dispatchEvent(new CustomEvent("texttrackchange"));
                     }
                   }
 
                   this.setClosedCaptionButtonState();
                 },
 
                 initTextTracks : function() {
+                  if (!this.isClosedCaptionAvailable) {
+                    this.closedCaptionButton.setAttribute("hidden", "true");
+                    return;
+                  }
+
                   const offLabel = this.textTrackList.getAttribute("offlabel");
 
                   this.addNewTextTrack({
                     label: offLabel,
                     kind: "subtitles"
                   });
 
                   for (let tt of this.overlayableTextTracks) {
@@ -1446,118 +1601,156 @@
                 },
 
                 get isTopLevelSyntheticDocument() {
                   let doc = this.video.ownerDocument;
                   let win = doc.defaultView;
                   return doc.mozSyntheticDocument && win === win.top;
                 },
 
-                _playButtonWidth : 0,
-                _durationLabelWidth : 0,
-                _muteButtonWidth : 0,
-                _volumeControlWidth : 0,
-                _closedCaptionButtonWidth : 0,
-                _fullscreenButtonWidth : 0,
-                _controlBarHeight : 0,
-                _overlayPlayButtonHeight : 64,
-                _overlayPlayButtonWidth : 64,
-                _controlBarPaddingEnd: 8,
                 adjustControlSize : function adjustControlSize() {
-                    let doc = this.video.ownerDocument;
+                  if (!this.controlBar.minWidth || this.videocontrols.isTouchControls) {
+                    return;
+                  }
+
+                  let videoWidth = this.video.clientWidth;
+                  let videoHeight = this.video.clientHeight;
+                  const minControlBarPaddingWidth = 18;
+
+                  if (this.video.readyState >= this.video.HAVE_METADATA) {
+                    if (!this.isAudioOnly && this.video.videoWidth && this.video.videoHeight) {
+                      let rect = this.video.getBoundingClientRect();
+                      let widthRatio = rect.width / this.video.videoWidth;
+                      let heightRatio = rect.height / this.video.videoHeight;
+                      let resizedWidth = this.video.videoWidth * Math.min(widthRatio, heightRatio);
+
+                      this.controlsContainer.style.width = `${resizedWidth}px`;
+                      this.controlsContainer.style.left = `${(videoWidth - resizedWidth) / 2}px`;
 
-                    // The scrubber has |flex=1|, therefore |minScrubberWidth|
-                    // was generated by empirical testing.
-                    let minScrubberWidth = 25;
-                    let minWidthAllControls = this._playButtonWidth +
-                                              minScrubberWidth +
-                                              this._durationLabelWidth +
-                                              this._muteButtonWidth +
-                                              this._volumeControlWidth +
-                                              this._closedCaptionButtonWidth +
-                                              this._fullscreenButtonWidth;
+                      videoWidth = resizedWidth;
+                    } else {
+                      this.controlsContainer.style.width = "";
+                      this.controlsContainer.style.left = "";
+                    }
+                  }
+                  // Hide and show control in order.
+                  const prioritizedControls = [
+                    this.playButton,
+                    this.muteButton,
+                    this.fullscreenButton,
+                    this.closedCaptionButton,
+                    this.positionDurationBox,
+                    this.scrubberStack,
+                    this.durationSpan,
+                    this.volumeStack
+                  ];
 
-                    let isFullscreenUnavailable = this.controlBar.hasAttribute("fullscreen-unavailable");
-                    if (isFullscreenUnavailable) {
-                        // When the fullscreen button is hidden we add margin-end to the volume stack.
-                        minWidthAllControls -= this._fullscreenButtonWidth - this._controlBarPaddingEnd;
+                  if (this.controlBar.hasAttribute("fullscreen-unavailable")) {
+                    this.fullscreenButton.isWanted = false;
+                  }
+                  if (!this.isClosedCaptionAvailable) {
+                    this.closedCaptionButton.isWanted = false;
+                  }
+                  if (this.muteButton.hasAttribute("noAudio")) {
+                    this.volumeStack.isWanted = false;
+                  }
+
+                  let widthUsed = minControlBarPaddingWidth;
+                  let preventAppendControl = false;
+
+                  for (let control of prioritizedControls) {
+                    if (!control.isWanted) {
+                      control.hideByAdjustment = true;
+                      continue;
                     }
 
-                    let minHeightForControlBar = this._controlBarHeight;
-                    let minWidthOnlyPlayPause = this._playButtonWidth + this._muteButtonWidth;
-
-                    let isAudioOnly = this.isAudioOnly;
-                    let videoHeight = isAudioOnly ? minHeightForControlBar : this.video.clientHeight;
-                    let videoWidth = isAudioOnly ? minWidthAllControls : this.video.clientWidth;
+                    control.hideByAdjustment = preventAppendControl ||
+                                               widthUsed + control.minWidth > videoWidth;
 
-                    // Adapt the size of the controls to the size of the video
-                    if (this.video.readyState >= this.video.HAVE_METADATA) {
-                      if (!this.isAudioOnly && this.video.videoWidth && this.video.videoHeight) {
-                        var rect = this.video.getBoundingClientRect();
-                        var widthRatio = rect.width / this.video.videoWidth;
-                        var heightRatio = rect.height / this.video.videoHeight;
-                        var width = this.video.videoWidth * Math.min(widthRatio, heightRatio);
+                    if (control.hideByAdjustment) {
+                      preventAppendControl = true;
+                    } else {
+                      widthUsed += control.minWidth;
+                    }
+                  }
+
+                  if (this.durationSpan.hideByAdjustment) {
+                    this.positionDurationBox.setAttribute("positionOnly", "true");
+                  } else {
+                    this.positionDurationBox.removeAttribute("positionOnly");
+                  }
 
-                        this.controlsOverlay.setAttribute("scaled", true);
-                        this.controlsOverlay.style.width = width + "px";
-                        this.controlsSpacer.style.width = width + "px";
-                        this.controlBar.style.width = width + "px";
-                      } else {
-                        this.controlsOverlay.removeAttribute("scaled");
-                        this.controlsOverlay.style.width = "";
-                        this.controlsSpacer.style.width = "";
-                        this.controlBar.style.width = "";
-                      }
-                    }
+                  if (videoHeight < this.controlBar.minHeight ||
+                      widthUsed === minControlBarPaddingWidth) {
+                    this.controlBar.setAttribute("size", "hidden");
+                    this.controlBar.hideByAdjustment = true;
+                  } else {
+                    this.controlBar.removeAttribute("size");
+                    this.controlBar.hideByAdjustment = false;
+                  }
+
+                  // Use flexible spacer to separate controls when scrubber is hidden.
+                  // As long as muteButton hidden, which means only play button presents,
+                  // hide spacer and make playButton centered.
+                  this.controlBarSpacer.hidden = !this.scrubberStack.hidden || this.muteButton.hidden;
 
-                    if ((this._overlayPlayButtonHeight + this._controlBarHeight) > videoHeight ||
-                        this._overlayPlayButtonWidth > videoWidth) {
-                        this.clickToPlay.hidden = true;
-                    } else if (this.clickToPlay.hidden &&
-                               !this.video.played.length &&
-                               this.video.paused) {
-                        // Check this.video.paused to handle when a video is
-                        // playing but hasn't processed any frames yet
-                        this.clickToPlay.hidden = false;
+                  // Adjust clickToPlayButton size.
+                  const minVideoSideLength = Math.min(videoWidth, videoHeight);
+                  const clickToPlayViewRatio = 0.15;
+                  const clickToPlayScaledSize = Math.max(
+                    this.clickToPlay.minWidth, minVideoSideLength * clickToPlayViewRatio);
+
+                  if (clickToPlayScaledSize >= videoWidth ||
+                    (clickToPlayScaledSize + this.controlBar.minHeight / 2 >= videoHeight / 2 )) {
+
+                    this.clickToPlay.hideByAdjustment = true;
+                  } else {
+                    if (this.clickToPlay.hidden && !this.video.played.length && this.video.paused) {
+                      this.clickToPlay.hideByAdjustment = false;
                     }
-
-                    let size = "normal";
-                    if (videoHeight < minHeightForControlBar)
-                        size = "hidden";
-                    else if (videoWidth < minWidthOnlyPlayPause)
-                        size = "hidden";
-                    else if (videoWidth < minWidthAllControls)
-                        size = "small";
-                    this.controlBar.setAttribute("size", size);
+                    this.clickToPlay.style.width = `${clickToPlayScaledSize}px`;
+                    this.clickToPlay.style.height = `${clickToPlayScaledSize}px`;
+                  }
                 },
 
                 init : function(binding) {
                     this.video = binding.parentNode;
                     this.videocontrols = binding;
 
-                    this.statusIcon    = document.getAnonymousElementByAttribute(binding, "class", "statusIcon");
-                    this.controlBar    = document.getAnonymousElementByAttribute(binding, "class", "controlBar");
-                    this.playButton    = document.getAnonymousElementByAttribute(binding, "class", "playButton");
-                    this.muteButton    = document.getAnonymousElementByAttribute(binding, "class", "muteButton");
-                    this.volumeControl = document.getAnonymousElementByAttribute(binding, "class", "volumeControl");
-                    this.progressBar   = document.getAnonymousElementByAttribute(binding, "class", "progressBar");
-                    this.bufferBar     = document.getAnonymousElementByAttribute(binding, "class", "bufferBar");
-                    this.scrubber      = document.getAnonymousElementByAttribute(binding, "class", "scrubber");
-                    this.scrubberThumb = document.getAnonymousElementByAttribute(this.scrubber, "class", "scale-thumb");
-                    this.durationLabel = document.getAnonymousElementByAttribute(binding, "class", "durationLabel");
-                    this.positionLabel = document.getAnonymousElementByAttribute(binding, "class", "positionLabel");
-                    this.statusOverlay = document.getAnonymousElementByAttribute(binding, "class", "statusOverlay");
-                    this.controlsOverlay = document.getAnonymousElementByAttribute(binding, "class", "controlsOverlay");
-                    this.controlsSpacer     = document.getAnonymousElementByAttribute(binding, "class", "controlsSpacer");
-                    this.clickToPlay        = document.getAnonymousElementByAttribute(binding, "class", "clickToPlay");
-                    this.fullscreenButton   = document.getAnonymousElementByAttribute(binding, "class", "fullscreenButton");
-                    this.volumeForeground   = document.getAnonymousElementByAttribute(binding, "anonid", "volumeForeground");
-                    this.closedCaptionButton = document.getAnonymousElementByAttribute(binding, "class", "closedCaptionButton");
-                    this.textTrackList = document.getAnonymousElementByAttribute(binding, "class", "textTrackList");
+                    this.controlsContainer    = document.getAnonymousElementByAttribute(binding, "anonid", "controlsContainer");
+                    this.statusIcon    = document.getAnonymousElementByAttribute(binding, "anonid", "statusIcon");
+                    this.controlBar    = document.getAnonymousElementByAttribute(binding, "anonid", "controlBar");
+                    this.playButton    = document.getAnonymousElementByAttribute(binding, "anonid", "playButton");
+                    this.controlBarSpacer    = document.getAnonymousElementByAttribute(binding, "anonid", "controlBarSpacer");
+                    this.muteButton    = document.getAnonymousElementByAttribute(binding, "anonid", "muteButton");
+                    this.volumeStack   = document.getAnonymousElementByAttribute(binding, "anonid", "volumeStack");
+                    this.volumeControl = document.getAnonymousElementByAttribute(binding, "anonid", "volumeControl");
+                    this.progressBar   = document.getAnonymousElementByAttribute(binding, "anonid", "progressBar");
+                    this.bufferBar     = document.getAnonymousElementByAttribute(binding, "anonid", "bufferBar");
+                    this.scrubberStack = document.getAnonymousElementByAttribute(binding, "anonid", "scrubberStack");
+                    this.scrubber      = document.getAnonymousElementByAttribute(binding, "anonid", "scrubber");
+                    this.durationLabel = document.getAnonymousElementByAttribute(binding, "anonid", "durationLabel");
+                    this.positionLabel = document.getAnonymousElementByAttribute(binding, "anonid", "positionLabel");
+                    this.positionDurationBox   = document.getAnonymousElementByAttribute(binding, "anonid", "positionDurationBox");
+                    this.statusOverlay = document.getAnonymousElementByAttribute(binding, "anonid", "statusOverlay");
+                    this.controlsOverlay = document.getAnonymousElementByAttribute(binding, "anonid", "controlsOverlay");
+                    this.controlsSpacer     = document.getAnonymousElementByAttribute(binding, "anonid", "controlsSpacer");
+                    this.clickToPlay        = document.getAnonymousElementByAttribute(binding, "anonid", "clickToPlay");
+                    this.fullscreenButton   = document.getAnonymousElementByAttribute(binding, "anonid", "fullscreenButton");
+                    this.closedCaptionButton = document.getAnonymousElementByAttribute(binding, "anonid", "closedCaptionButton");
+                    this.textTrackList = document.getAnonymousElementByAttribute(binding, "anonid", "textTrackList");
 
+                    if (this.positionDurationBox) {
+                      this.durationSpan = this.positionDurationBox.getElementsByTagName("span")[0];
+                    }
+
+                    // XXX controlsContainer is a desktop only element. To determine whether
+                    // isTouchControls or not during the whole initialization process, get
+                    // this state overridden here.
+                    this.videocontrols.isTouchControls = !this.controlsContainer;
                     this.isAudioOnly = (this.video instanceof HTMLAudioElement);
                     this.setupInitialState();
                     this.setupNewLoadState();
                     this.initTextTracks();
 
                     // Use the handleEvent() callback for all media events.
                     // Only the "error" event listener must capture, so that it can trap error
                     // events from <source> children, which don't bubble. But we use capture
@@ -1574,40 +1767,47 @@
 
                     // Helper function to add an event listener to the given element
                     function addListener(elem, eventName, func) {
                       let boundFunc = func.bind(self);
                       self.controlListeners.push({ item: elem, event: eventName, func: boundFunc });
                       elem.addEventListener(eventName, boundFunc, { mozSystemGroup: true });
                     }
 
-                    addListener(this.muteButton, "command", this.toggleMute);
-                    addListener(this.closedCaptionButton, "command", this.toggleClosedCaption);
+                    addListener(this.muteButton, "click", this.toggleMute);
+                    addListener(this.closedCaptionButton, "click", this.toggleClosedCaption);
+                    addListener(this.fullscreenButton, "click", this.toggleFullscreen);
                     addListener(this.playButton, "click", this.clickToPlayClickHandler);
-                    addListener(this.fullscreenButton, "command", this.toggleFullscreen);
                     addListener(this.clickToPlay, "click", this.clickToPlayClickHandler);
                     addListener(this.controlsSpacer, "click", this.clickToPlayClickHandler);
                     addListener(this.controlsSpacer, "dblclick", this.toggleFullscreen);
 
                     addListener(this.videocontrols, "resizevideocontrols", this.adjustControlSize);
                     addListener(this.videocontrols, "transitionend", this.onTransitionEnd);
                     addListener(this.video.ownerDocument, "mozfullscreenchange", this.onFullscreenChange);
-                    addListener(this.videocontrols, "transitionend", this.onControlBarTransitioned);
+                    addListener(this.controlBar, "transitionend", this.onControlBarTransitioned);
                     addListener(this.video.ownerDocument, "fullscreenchange", this.onFullscreenChange);
                     addListener(this.video, "keypress", this.keyHandler);
-                    addListener(this.video.textTracks, "addtrack", this.onTextTrackAdd);
-                    addListener(this.video.textTracks, "removetrack", this.onTextTrackRemove);
 
                     addListener(this.videocontrols, "dragstart", function(event) {
                         event.preventDefault(); // prevent dragging of controls image (bug 517114)
                     });
 
+                    if (!this.videocontrols.isTouchControls) {
+                      addListener(this.scrubber, "input", this.onScrubberInput);
+                      addListener(this.scrubber, "change", this.onScrubberChange);
+                      addListener(this.volumeControl, "input", this.updateVolume);
+                      addListener(this.video.textTracks, "addtrack", this.onTextTrackAdd);
+                      addListener(this.video.textTracks, "removetrack", this.onTextTrackRemove);
+                    }
+
                     this.log("--- videocontrols initialized ---");
                 }
             };
+
             this.Utils.init(this);
             ]]>
         </constructor>
         <destructor>
             <![CDATA[
             this.Utils.terminateEventListeners();
             // randomID used to be a <field>, which meant that the XBL machinery
             // undefined the property when the element was unbound. The code in
@@ -1616,89 +1816,91 @@
             delete this.randomID;
             ]]>
         </destructor>
 
     </implementation>
 
     <handlers>
         <handler event="mouseover">
-            if (!this.isTouchControl)
+            if (!this.isTouchControls)
                 this.Utils.onMouseInOut(event);
         </handler>
         <handler event="mouseout">
-            if (!this.isTouchControl)
+            if (!this.isTouchControls)
                 this.Utils.onMouseInOut(event);
         </handler>
         <handler event="mousemove">
-            if (!this.isTouchControl)
+            if (!this.isTouchControls)
                 this.Utils.onMouseMove(event);
         </handler>
     </handlers>
   </binding>
 
   <binding id="touchControls" extends="chrome://global/content/bindings/videocontrols.xml#videoControls">
 
     <xbl:content xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" class="mediaControlsFrame">
         <stack flex="1">
-            <vbox flex="1" class="statusOverlay" hidden="true">
-                <box class="statusIcon"/>
+            <vbox anonid="statusOverlay" flex="1" class="statusOverlay" hidden="true">
+                <box anonid="statusIcon" class="statusIcon"/>
                 <label class="errorLabel" anonid="errorAborted">&error.aborted;</label>
                 <label class="errorLabel" anonid="errorNetwork">&error.network;</label>
                 <label class="errorLabel" anonid="errorDecode">&error.decode;</label>
                 <label class="errorLabel" anonid="errorSrcNotSupported">&error.srcNotSupported;</label>
                 <label class="errorLabel" anonid="errorNoSource">&error.noSource2;</label>
                 <label class="errorLabel" anonid="errorGeneric">&error.generic;</label>
             </vbox>
 
-            <vbox class="controlsOverlay">
-                <spacer class="controlsSpacer" flex="1"/>
+            <vbox anonid="controlsOverlay" class="controlsOverlay">
+                <spacer anonid="controlsSpacer" class="controlsSpacer" flex="1"/>
                 <box flex="1" hidden="true">
-                    <box class="clickToPlay" hidden="true" flex="1"/>
-                    <vbox class="textTrackList" hidden="true" offlabel="&closedCaption.off;"></vbox>
+                    <box anonid="clickToPlay" class="clickToPlay" hidden="true" flex="1"/>
+                    <vbox anonid="textTrackList" class="textTrackList" hidden="true" offlabel="&closedCaption.off;"></vbox>
                 </box>
-                <vbox class="controlBar" hidden="true">
+                <vbox anonid="controlBar" class="controlBar" hidden="true">
                     <hbox class="buttonsBar">
-                        <button class="playButton"
+                        <button anonid="playButton"
+                                class="playButton"
                                 playlabel="&playButton.playLabel;"
                                 pauselabel="&playButton.pauseLabel;"/>
-                        <label class="positionLabel" role="presentation"/>
-                        <stack class="scrubberStack">
+                        <label anonid="positionLabel" class="positionLabel" role="presentation"/>
+                        <stack anonid="scrubberStack" class="scrubberStack">
                             <box class="backgroundBar"/>
                             <progressmeter class="flexibleBar" value="100"/>
-                            <progressmeter class="bufferBar"/>
-                            <progressmeter class="progressBar" max="10000"/>
-                            <scale class="scrubber" movetoclick="true"/>
+                            <progressmeter anonid="bufferBar" class="bufferBar"/>
+                            <progressmeter anonid="progressBar" class="progressBar" max="10000"/>
+                            <scale anonid="scrubber" class="scrubber" movetoclick="true"/>
                         </stack>
-                        <label class="durationLabel" role="presentation"/>
-                        <button class="muteButton"
+                        <label anonid="durationLabel" class="durationLabel" role="presentation"/>
+                        <button anonid="muteButton"
+                                class="muteButton"
                                 mutelabel="&muteButton.muteLabel;"
                                 unmutelabel="&muteButton.unmuteLabel;"/>
-                        <stack class="volumeStack">
-                          <box class="volumeBackground"/>
-                          <box class="volumeForeground" anonid="volumeForeground"/>
-                          <scale class="volumeControl" movetoclick="true"/>
+                        <stack anonid="volumeStack" class="volumeStack">
+                          <box anonid="volumeBackground" class="volumeBackground"/>
+                          <box anonid="volumeForeground" class="volumeForeground"/>
+                          <scale anonid="volumeControl" class="volumeControl" movetoclick="true"/>
                         </stack>
-                        <button class="castingButton" hidden="true"
+                        <button anonid="castingButton" class="castingButton" hidden="true"
                                 aria-label="&castingButton.castingLabel;"/>
-                        <button class="closedCaptionButton" hidden="true"/>
-                        <button class="fullscreenButton"
+                        <button anonid="closedCaptionButton" class="closedCaptionButton" hidden="true"/>
+                        <button anonid="fullscreenButton"
+                            class="fullscreenButton"
                             enterfullscreenlabel="&fullscreenButton.enterfullscreenlabel;"
                             exitfullscreenlabel="&fullscreenButton.exitfullscreenlabel;"/>
                     </hbox>
                 </vbox>
             </vbox>
         </stack>
     </xbl:content>
 
     <implementation>
-
         <constructor>
           <![CDATA[
-          this.isTouchControl = true;
+          this.isTouchControls = true;
           this.TouchUtils = {
             videocontrols: null,
             video: null,
             controlsTimer: null,
             controlsTimeout: 5000,
             positionLabel: null,
             castingButton: null,
 
@@ -1823,17 +2025,17 @@
               this.Utils.scrubber.addEventListener("touchstart", function() {
                 self.clearTimer();
               }, false);
               this.Utils.scrubber.addEventListener("touchend", function() {
                 self.delayHideControls(self.controlsTimeout);
               }, false);
               this.Utils.muteButton.addEventListener("click", function() { self.delayHideControls(self.controlsTimeout); }, false);
 
-              this.castingButton = document.getAnonymousElementByAttribute(binding, "class", "castingButton");
+              this.castingButton = document.getAnonymousElementByAttribute(binding, "anonid", "castingButton");
               this.castingButton.addEventListener("command", function() {
                 self.startCasting();
               }, false);
 
               this.video.addEventListener("media-videoCasting", function(e) {
                 if (!e.isTrusted)
                   return;
                 self.updateCasting(e.detail);
@@ -1853,17 +2055,18 @@
               // transitioned into or out of fullscreen mode, and we don't want
               // 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.TouchUtils.init(this);
+
+          this.TouchUtils.init(this)
           this.dispatchEvent(new CustomEvent("VideoBindingAttached"));
       ]]>
       </constructor>
       <destructor>
           <![CDATA[
           // XBL destructors don't appear to be inherited properly, so we need
           // to do this here in addition to the videoControls destructor. :-(
           delete this.randomID;
--- a/toolkit/locales/en-US/chrome/global/videocontrols.dtd
+++ b/toolkit/locales/en-US/chrome/global/videocontrols.dtd
@@ -32,8 +32,18 @@
 <!ENTITY error.generic "Video playback aborted due to an unknown error.">
 
 <!-- LOCALIZATION NOTE (scrubberScale.nameFormat): the #1 string is the current
 media position, and the #2 string is the total duration. For example, when at
 the 5 minute mark in a 6 hour long video, #1 would be "5:00" and #2 would be
 "6:00:00", result string would be "5:00 of 6:00:00 elapsed".
 -->
 <!ENTITY scrubberScale.nameFormat "#1 of #2 elapsed">
+
+<!-- LOCALIZATION NOTE (positionAndDuration.nameFormat): the #1 string is the current
+media position, and the #2 string is the total duration. For example, when at
+the 5 minute mark in a 6 hour long video, #1 would be "5:00" and #2 would be
+"6:00:00", result string would be "5:00 / 6:00:00".
+Note that #2 is not always avaiable. For example, when at the 5 minute mark in an
+unknown duration video, #1 would be "5:00" and string which is surrounded by <span>
+would be deleted, result string would be "5:00".
+-->
+<!ENTITY positionAndDuration.nameFormat "#1<span> / #2</span>">
--- a/toolkit/themes/shared/jar.inc.mn
+++ b/toolkit/themes/shared/jar.inc.mn
@@ -59,41 +59,24 @@ toolkit.jar:
   skin/classic/global/reader/RM-Content-Width-Plus-44x16.svg             (../../shared/reader/RM-Content-Width-Plus-44x16.svg)
   skin/classic/global/reader/RM-Line-Height-Minus-38x14.svg            (../../shared/reader/RM-Line-Height-Minus-38x14.svg)
   skin/classic/global/reader/RM-Line-Height-Plus-38x24.svg             (../../shared/reader/RM-Line-Height-Plus-38x24.svg)
   skin/classic/global/media/TopLevelImageDocument.css      (../../shared/media/TopLevelImageDocument.css)
   skin/classic/global/media/TopLevelVideoDocument.css      (../../shared/media/TopLevelVideoDocument.css)
   skin/classic/global/media/imagedoc-lightnoise.png        (../../shared/media/imagedoc-lightnoise.png)
   skin/classic/global/media/imagedoc-darknoise.png         (../../shared/media/imagedoc-darknoise.png)
 * skin/classic/global/media/videocontrols.css              (../../shared/media/videocontrols.css)
-  skin/classic/global/media/pauseButton.png                (../../shared/media/pauseButton.png)
-  skin/classic/global/media/pauseButton@2x.png             (../../shared/media/pauseButton@2x.png)
-  skin/classic/global/media/playButton.png                 (../../shared/media/playButton.png)
-  skin/classic/global/media/playButton@2x.png              (../../shared/media/playButton@2x.png)
-  skin/classic/global/media/muteButton.png                 (../../shared/media/muteButton.png)
-  skin/classic/global/media/muteButton@2x.png              (../../shared/media/muteButton@2x.png)
-  skin/classic/global/media/unmuteButton.png               (../../shared/media/unmuteButton.png)
-  skin/classic/global/media/unmuteButton@2x.png            (../../shared/media/unmuteButton@2x.png)
-  skin/classic/global/media/noAudio.png                    (../../shared/media/noAudio.png)
-  skin/classic/global/media/noAudio@2x.png                 (../../shared/media/noAudio@2x.png)
-  skin/classic/global/media/closeCaptionButton.png         (../../shared/media/closeCaptionButton.png)
-  skin/classic/global/media/closeCaptionButton@2x.png      (../../shared/media/closeCaptionButton@2x.png)
-  skin/classic/global/media/fullscreenButton.png           (../../shared/media/fullscreenButton.png)
-  skin/classic/global/media/fullscreenButton@2x.png        (../../shared/media/fullscreenButton@2x.png)
-  skin/classic/global/media/scrubberThumb.png              (../../shared/media/scrubberThumb.png)
-  skin/classic/global/media/scrubberThumb@2x.png           (../../shared/media/scrubberThumb@2x.png)
-  skin/classic/global/media/scrubberThumbWide.png          (../../shared/media/scrubberThumbWide.png)
-  skin/classic/global/media/scrubberThumbWide@2x.png       (../../shared/media/scrubberThumbWide@2x.png)
+  skin/classic/global/media/pauseButton.svg                (../../shared/media/pauseButton.svg)
+  skin/classic/global/media/playButton.svg                 (../../shared/media/playButton.svg)
+  skin/classic/global/media/muteButton.svg                 (../../shared/media/muteButton.svg)
+  skin/classic/global/media/closedCaptionButton.svg        (../../shared/media/closedCaptionButton.svg)
+  skin/classic/global/media/fullscreenButton.svg           (../../shared/media/fullscreenButton.svg)
   skin/classic/global/media/error.png                      (../../shared/media/error.png)
   skin/classic/global/media/throbber.png                   (../../shared/media/throbber.png)
   skin/classic/global/media/stalled.png                    (../../shared/media/stalled.png)
-  skin/classic/global/media/volume-empty.png               (../../shared/media/volume-empty.png)
-  skin/classic/global/media/volume-empty@2x.png            (../../shared/media/volume-empty@2x.png)
-  skin/classic/global/media/volume-full.png                (../../shared/media/volume-full.png)
-  skin/classic/global/media/volume-full@2x.png             (../../shared/media/volume-full@2x.png)
   skin/classic/global/media/clicktoplay-bgtexture.png      (../../shared/media/clicktoplay-bgtexture.png)
   skin/classic/global/media/videoClickToPlayButton.svg     (../../shared/media/videoClickToPlayButton.svg)
 #ifdef MOZ_PLACES
   skin/classic/mozapps/places/defaultFavicon.png           (../../shared/places/defaultFavicon.png)
   skin/classic/mozapps/places/defaultFavicon@2x.png        (../../shared/places/defaultFavicon@2x.png)
   skin/classic/mozapps/places/defaultFavicon-inverted.png  (../../shared/places/defaultFavicon-inverted.png)
   skin/classic/mozapps/places/defaultFavicon-inverted@2x.png (../../shared/places/defaultFavicon-inverted@2x.png)
 #endif
--- a/toolkit/themes/shared/media/TopLevelVideoDocument.css
+++ b/toolkit/themes/shared/media/TopLevelVideoDocument.css
@@ -3,10 +3,11 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 body {
   background-image: url("chrome://global/skin/media/imagedoc-darknoise.png");
   background-color: rgb(33,33,33); /* Average color of that ^ image. */
 }
 
 video {
-  box-shadow: 0 0 15px #000;
+  border: 1px #000000 solid;
+  box-shadow: 0 0 5px rgba(0,0,0,0.6);
 }
deleted file mode 100644
index 469310fb1b21ed705925decd18710dd0df37d915..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 03350789221b94d830ebc4dafb1b6e4447f79f71..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
--- /dev/null
+++ b/toolkit/themes/shared/media/closedCaptionButton.svg
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="18px" height="18px" viewBox="0 0 18 18">
+  <style>
+    use:not(:target) {
+      display: none;
+    }
+    use {
+      fill: #ffffff;
+    }
+    use[id$="-hover"] {
+      fill: #48a0f7;
+    }
+    use[id$="-active"] {
+      fill: #2d89e6;
+    }
+    use[id$="-focus"] {
+      fill: #48a0f7;
+    }
+    use[id$="-disabled"] {
+      fill: #ffffff;
+    }
+  </style>
+  <symbol id="cc-off-shape">
+    <path fill-rule="evenodd" clip-rule="evenodd" d="M16.531,16.107H5.267l1.982-2H15c0.6,0,1-0.4,1-1V5.274
+      l1.946-1.964C17.963,3.399,18,3.483,18,3.576v11.031C18,15.407,17.331,16.107,16.531,16.107z M14.016,8.506h-1.218l1.005-1.014
+      C13.913,7.789,13.984,8.128,14.016,8.506z M11.786,12.361c-0.828,0-1.476-0.326-1.913-0.902l1.09-1.101
+      c0.136,0.323,0.374,0.541,0.796,0.541c0.514,0,0.695-0.44,0.756-1.014h1.535C13.908,11.43,13.071,12.361,11.786,12.361z
+       M1.496,16.106C0.697,16.104,0,15.406,0,14.607V3.576c0-0.8,0.7-1.5,1.5-1.5h12.846L16.299,0l1.316,1.283L2.615,17.13L1.496,16.106
+      z M3,4.107c-0.6,0-1,0.4-1,1v8c0,0.6,0.4,1,1,1h0.029l2.031-2.16c-0.757-0.503-1.191-1.457-1.191-2.744
+      c0-1.936,1.069-3.14,2.428-3.14c1.357,0,2.136,0.76,2.361,2.059l3.777-4.016H3z M8.298,8.506H7.355
+      c-0.047-0.623-0.49-1.23-0.99-1.23c-0.561,0-1.337,0.84-1.337,1.995c0,0.674,0.381,1.427,0.95,1.702L8.298,8.506z"/>
+  </symbol>
+
+  <symbol id="cc-shape">
+    <path d="M16.531,1.984H1.5c-0.8,0-1.5,0.7-1.5,1.5v11.031c0,0.8,0.7,1.5,1.5,1.5h15.031
+      c0.8,0,1.469-0.7,1.469-1.5V3.484C18,2.684,17.331,1.984,16.531,1.984z M16,13.016c0,0.6-0.4,1-1,1H3c-0.6,0-1-0.4-1-1v-8
+      c0-0.6,0.4-1,1-1h12c0.6,0,1,0.4,1,1V13.016z M6.426,10.807c-0.811,0-0.96-0.789-0.96-1.628c0-1.155,0.338-1.745,0.899-1.745
+      c0.5,0,0.818,0.357,0.866,0.98h1.484C8.585,6.877,7.785,5.972,6.297,5.972c-1.359,0-2.428,1.205-2.428,3.14
+      c0,1.944,0.974,3.157,2.583,3.157c1.285,0,2.153-0.93,2.295-2.476H7.244C7.183,10.367,6.94,10.807,6.426,10.807z M11.759,10.807
+      c-0.811,0-0.96-0.789-0.96-1.628c0-1.155,0.338-1.745,0.899-1.745c0.5,0,0.756,0.357,0.803,0.98h1.515
+      c-0.129-1.537-0.898-2.443-2.385-2.443c-1.359,0-2.396,1.205-2.396,3.14c0,1.944,0.943,3.157,2.552,3.157
+      c1.285,0,2.122-0.93,2.264-2.476h-1.535C12.454,10.367,12.273,10.807,11.759,10.807z"/>
+  </symbol>
+  <use id="cc" xlink:href="#cc-shape"/>
+  <use id="cc-hover" xlink:href="#cc-shape"/>
+  <use id="cc-active" xlink:href="#cc-shape"/>
+  <use id="cc-focus" xlink:href="#cc-shape"/>
+  <use id="cc-disabled" xlink:href="#cc-shape"/>
+
+  <use id="cc-off" xlink:href="#cc-off-shape"/>
+  <use id="cc-off-hover" xlink:href="#cc-off-shape"/>
+  <use id="cc-off-active" xlink:href="#cc-off-shape"/>
+  <use id="cc-off-focus" xlink:href="#cc-off-shape"/>
+  <use id="cc-off-disabled" xlink:href="#cc-off-shape"/>
+</svg>
index 58e37283a73eff086420d0969544fa8bc5dd7924..362a293f223fe1c29751b711de8c48de950ebd49
GIT binary patch
literal 20345
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
D)qq~X
deleted file mode 100644
index ffbc3d5ae4627d9beb7c4e8c6ef80542e7e1414c..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
--- /dev/null
+++ b/toolkit/themes/shared/media/fullscreenButton.svg
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="18px" height="18px" viewBox="0 0 18 18">
+  <style>
+    use:not(:target) {
+      display: none;
+    }
+    use {
+      fill: #ffffff;
+    }
+    use[id$="-hover"] {
+      fill: #48a0f7;
+    }
+    use[id$="-active"] {
+      fill: #2d89e6;
+    }
+    use[id$="-focus"] {
+      fill: #48a0f7;
+    }
+    use[id$="-disabled"] {
+      fill: #ffffff;
+    }
+  </style>
+  <symbol id="fullscreen-shape">
+    <path d="M6.728,10.188l-3.235,3.094l0.017-2.267l-1.513-0.016l0,5l4.987-0.008l0.011-1.537l-2.281-0.022
+  l3.097-3.158L6.728,10.188z M14.453,11.004l-0.022,2.281l-3.158-3.097l-1.086,1.083l3.094,3.235l-2.267-0.017l-0.016,1.514l5,0
+  l-0.008-4.988L14.453,11.004z M11.015,2.01l-0.011,1.537l2.281,0.022l-3.097,3.158l1.083,1.086l3.235-3.094L14.49,6.986
+  l1.513,0.016v-5L11.015,2.01z M6.986,3.511l0.016-1.514l-5,0L2.01,6.985l1.537,0.011l0.022-2.281l3.158,3.097l1.086-1.083
+  L4.718,3.494L6.986,3.511z"/>
+  </symbol>
+  <symbol id="unfullscreen-shape">
+    <path d="M2.047,11.135l-0.011,1.537l2.281,0.022L1.22,15.851l1.083,1.086l3.235-3.094l-0.017,2.268l1.513,0.016
+  l0-5L2.047,11.135z M13.781,12.587l2.267,0.017l0.016-1.514l-5,0l0.008,4.988l1.537,0.011l0.022-2.281l3.158,3.097l1.086-1.083
+  L13.781,12.587z M16.058,5.578l-2.281-0.021l3.097-3.158l-1.083-1.086l-3.235,3.094l0.017-2.267L11.06,2.123v5l4.988-0.008
+  L16.058,5.578z M5.516,2.098L5.494,4.379L2.336,1.283L1.25,2.365L4.344,5.6L2.077,5.583L2.06,7.097l5,0L7.053,2.109L5.516,2.098z"/>
+  </symbol>
+  <use id="fullscreen" xlink:href="#fullscreen-shape"/>
+  <use id="fullscreen-hover" xlink:href="#fullscreen-shape"/>
+  <use id="fullscreen-active" xlink:href="#fullscreen-shape"/>
+  <use id="fullscreen-focus" xlink:href="#fullscreen-shape"/>
+  <use id="fullscreen-disabled" xlink:href="#fullscreen-shape"/>
+
+  <use id="unfullscreen" xlink:href="#unfullscreen-shape"/>
+  <use id="unfullscreen-hover" xlink:href="#unfullscreen-shape"/>
+  <use id="unfullscreen-active" xlink:href="#unfullscreen-shape"/>
+  <use id="unfullscreen-focus" xlink:href="#unfullscreen-shape"/>
+  <use id="unfullscreen-disabled" xlink:href="#unfullscreen-shape"/>
+</svg>
deleted file mode 100644
index b09ebbd43ce8dd62741992a0d00df1018897d164..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 894480761d0742015ffcfcc2d28bc10e88cbe4a9..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
--- /dev/null
+++ b/toolkit/themes/shared/media/muteButton.svg
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="18px" height="18px" viewBox="0 0 18 18">
+  <style>
+    use:not(:target) {
+      display: none;
+    }
+    use {
+      fill: #ffffff;
+    }
+    use[id$="-hover"] {
+      fill: #48a0f7;
+    }
+    use[id$="-active"] {
+      fill: #2d89e6;
+    }
+    use[id$="-focus"] {
+      fill: #48a0f7;
+    }
+    use[id$="-disabled"] {
+      fill: #ffffff;
+    }
+  </style>
+  <symbol id="unmute-shape">
+    <path d="M3.52,5.367c-1.332,0-2.422,1.09-2.422,2.422v2.422c0,1.332,1.09,2.422,2.422,2.422h1.516l4.102,3.633
+    V1.735L5.035,5.367H3.52z M12.059,9c0-0.727-0.484-1.211-1.211-1.211v2.422C11.574,10.211,12.059,9.727,12.059,9z M14.48,9
+    c0-1.695-1.211-3.148-2.785-3.512l-0.363,1.09C12.422,6.82,13.27,7.789,13.27,9c0,1.211-0.848,2.18-1.938,2.422l0.484,1.09
+    C13.27,12.148,14.48,10.695,14.48,9z M12.543,3.188l-0.484,1.09C14.238,4.883,15.691,6.82,15.691,9c0,2.18-1.453,4.117-3.512,4.601
+    l0.484,1.09c2.422-0.605,4.238-2.906,4.238-5.691C16.902,6.215,15.086,3.914,12.543,3.188z"/>
+  </symbol>
+  <symbol id="mute-shape">
+    <path d="M3.52,5.367c-1.332,0-2.422,1.09-2.422,2.422v2.422c0,1.332,1.09,2.422,2.422,2.422h1.516l4.102,3.633
+      V1.735L5.035,5.367H3.52z"/>
+    <path fill-rule="evenodd" clip-rule="evenodd" d="M12.155,12.066l-1.138-1.138l4.872-4.872l1.138,1.138
+      L12.155,12.066z"/>
+    <path fill-rule="evenodd" clip-rule="evenodd" d="M10.998,7.204l1.138-1.138l4.872,4.872l-1.138,1.138L10.998,7.204
+		z"/>
+  </symbol>
+  <symbol id="noaudio-shape">
+	  <path d="M14.901,3.571l-4.412,3.422V1.919L6.286,5.46H4.869c-1.298,0-2.36,1.062-2.36,2.36v2.36
+		c0,1.062,0.708,1.888,1.652,2.242l-2.242,1.77l1.18,1.416L16.081,4.987L14.901,3.571z M10.489,16.081V11.36l-2.669,2.36
+		L10.489,16.081z"/>
+  </symbol>
+  <use id="unmute" xlink:href="#unmute-shape"/>
+  <use id="unmute-hover" xlink:href="#unmute-shape"/>
+  <use id="unmute-active" xlink:href="#unmute-shape"/>
+  <use id="unmute-focus" xlink:href="#unmute-shape"/>
+  <use id="unmute-disabled" xlink:href="#unmute-shape"/>
+
+  <use id="mute" xlink:href="#mute-shape"/>
+  <use id="mute-hover" xlink:href="#mute-shape"/>
+  <use id="mute-active" xlink:href="#mute-shape"/>
+  <use id="mute-focus" xlink:href="#mute-shape"/>
+  <use id="mute-disabled" xlink:href="#mute-shape"/>
+
+  <use id="noaudio" xlink:href="#noaudio-shape"/>
+</svg>
deleted file mode 100644
index b2cd21c5ebc271dbe97d72207827cb48e0b0fa05..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 3db8c973b6594cb8820661564eb8dacb673c09b9..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 7de728b2d7a17a75cc0e5b44da308e7a9e8db013..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 944098ca19a4f63331ae852606c3907285e7e203..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
--- /dev/null
+++ b/toolkit/themes/shared/media/pauseButton.svg
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="18px" height="18px" viewBox="0 0 18 18">
+  <style>
+    use:not(:target) {
+      display: none;
+    }
+    use {
+      fill: #ffffff;
+    }
+    use[id$="-hover"] {
+      fill: #48a0f7;
+    }
+    use[id$="-active"] {
+      fill: #2d89e6;
+    }
+    use[id$="-focus"] {
+      fill: #48a0f7;
+    }
+    use[id$="-disabled"] {
+      fill: #ffffff;
+    }
+  </style>
+
+
+  <symbol id="pause-shape">
+    <path fill-rule="evenodd" clip-rule="evenodd" d="M6.002,1.953C5.172,1.953,4.5,2.626,4.5,3.455v11.08
+        c0,0.83,0.672,1.502,1.502,1.502c0.829,0,1.502-0.672,1.502-1.502V3.455C7.504,2.626,6.831,1.953,6.002,1.953z M12,1.953
+        c-0.828,0-1.5,0.672-1.5,1.5v11.094c0,0.828,0.672,1.5,1.5,1.5s1.5-0.672,1.5-1.5V3.453C13.5,2.625,12.828,1.953,12,1.953z"/>
+  </symbol>
+
+  <use id="pause" xlink:href="#pause-shape"/>
+  <use id="pause-hover" xlink:href="#pause-shape"/>
+  <use id="pause-active" xlink:href="#pause-shape"/>
+  <use id="pause-focus" xlink:href="#pause-shape"/>
+  <use id="pause-disalbed" xlink:href="#pause-shape"/>
+</svg>
deleted file mode 100644
index df22919419082d251064811ac730eea234008ad6..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 11e2731df64f9dd00623f263150d8a651ee1b1bc..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
--- /dev/null
+++ b/toolkit/themes/shared/media/playButton.svg
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="18px" height="18px" viewBox="0 0 18 18">
+  <style>
+    use:not(:target) {
+      display: none;
+    }
+    use {
+      fill: #ffffff;
+    }
+    use[id$="-hover"] {
+      fill: #48a0f7;
+    }
+    use[id$="-active"] {
+      fill: #2d89e6;
+    }
+    use[id$="-focus"] {
+      fill: #48a0f7;
+    }
+    use[id$="-disabled"] {
+      fill: #ffffff;
+    }
+    use[id$="-clicktoplay"] {
+      fill: #000000;
+    }
+  </style>
+
+  <symbol id="play-shape">
+    <path d="M3.243,15.155c0,0.845,0.593,1.157,1.317,0.707l9.659-6.041c0.727-0.453,0.722-1.193,0-1.645L4.556,2.137
+    C3.827,1.682,3.237,2.014,3.237,2.844v12.312H3.243z"/>
+  </symbol>
+
+  <use id="play" xlink:href="#play-shape"/>
+  <use id="play-hover" xlink:href="#play-shape"/>
+  <use id="play-active" xlink:href="#play-shape"/>
+  <use id="play-focus" xlink:href="#play-shape"/>
+  <use id="play-clicktoplay" xlink:href="#play-shape"/>
+</svg>
deleted file mode 100644
index fb20075b24af20c17d2ab0f301e04b74c0fbdb50..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index f159627631c536f0def829f45f3715f198db1a5e..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index f8790f46724c449f053f490ff840f279da03964b..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 96d2ed75140584a92940e65b4f5d1f7a60a133c3..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 52c9d72727e8d6c263c288454003b06cb2e819b9..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 5b76e2fa45d8481ca0a81e524c4a20508adfc284..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 86f21859eee91db51bab2e89ce0b05f2378f2dd3..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
--- a/toolkit/themes/shared/media/videocontrols.css
+++ b/toolkit/themes/shared/media/videocontrols.css
@@ -1,440 +1,478 @@
 /* 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/. */
 
-@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
-@namespace html url("http://www.w3.org/1999/xhtml");
+@namespace xul url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
+@namespace url("http://www.w3.org/1999/xhtml");
+
+video > xul|videocontrols,
+audio > xul|videocontrols {
+  writing-mode: horizontal-tb;
+  width: 100%;
+  height: 100%;
+  display: inline-block;
+}
+
+.controlsContainer [hidden="true"],
+.controlBar[hidden] {
+  display: none;
+}
+
+.controlBar[size="hidden"] {
+  display: none;
+}
+
+.controlsContainer,
+.progressContainer {
+  position: relative;
+  height: 100%;
+}
+
+.stackItem {
+  position: absolute;
+  left: 0;
+  bottom: 0;
+  width: 100%;
+  height: 100%;
+}
+
+.statusOverlay {
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+  background-color: rgb(80,80,80);
+}
+
+.controlsOverlay {
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  position: relative;
+}
+
+.controlsSpacerStack {
+  display: flex;
+  flex-direction: column;
+  flex-grow: 1;
+  justify-content: center;
+  align-items: center;
+}
+
+.controlsSpacer {
+  background-color: rgba(255,255,255,.4);
+}
 
 .controlBar {
-  height: 28px;
-  background-color: rgba(35,31,32,.74);
+  position: relative;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  overflow: hidden;
+  height: 40px;
+  padding: 0 9px;
+  background-color: rgba(26,26,26,.8);
 }
 
 .playButton,
 .muteButton,
 .closedCaptionButton,
 .fullscreenButton {
+  height: 100%;
+  min-height: 30px;
+  min-width: 30px;
+  padding: 6px;
+  border: 0;
+  margin: 0;
   background-color: transparent;
   background-repeat: no-repeat;
   background-position: center;
-  -moz-appearance: none;   /* Remove the native button appearance and styling */
-  margin: 0;
-  padding: 0;
-  min-height: 28px;
-  min-width: 28px;
-  border: none;
-  opacity: 0.7;
-}
-
-.playButton:hover,
-.muteButton:hover,
-.closedCaptionButton:hover,
-.fullscreenButton:hover {
-  opacity: 1;
-}
-
-.playButton:hover:active,
-.muteButton:hover:active,
-.closedCaptionButton:hover:active,
-.fullscreenButton:hover:active {
-  opacity: 0.4;
+  background-origin: content-box;
+  background-clip: content-box;
 }
 
 .playButton {
-  background-image: url(chrome://global/skin/media/pauseButton.png);
-  margin-right: -22px; /* 1/2 of scrubber thumb width, for overhang. */
-  position: relative; /* Trick to work around negative margin interfering with clicking on the button. */
+  background-image: url(chrome://global/skin/media/pauseButton.svg#pause);
+}
+.playButton:hover {
+  background-image: url(chrome://global/skin/media/pauseButton.svg#pause-hover);
+}
+.playButton:hover:active {
+  background-image: url(chrome://global/skin/media/pauseButton.svg#pause-active);
 }
-
 .playButton[paused] {
-  background-image: url(chrome://global/skin/media/playButton.png);
+  background-image: url(chrome://global/skin/media/playButton.svg#play);
+}
+.playButton[paused]:hover {
+  background-image: url(chrome://global/skin/media/playButton.svg#play-hover);
+}
+.playButton[paused]:hover:active {
+  background-image: url(chrome://global/skin/media/playButton.svg#play-active);
 }
 
 .muteButton {
-  background-image: url(chrome://global/skin/media/muteButton.png);
-  min-width: 33px;
+  background-image: url(chrome://global/skin/media/muteButton.svg#unmute);
+}
+.muteButton:hover {
+  background-image: url(chrome://global/skin/media/muteButton.svg#unmute-hover);
+}
+.muteButton:hover:active {
+  background-image: url(chrome://global/skin/media/muteButton.svg#unmute-active);
 }
 .muteButton[muted] {
-  background-image: url(chrome://global/skin/media/unmuteButton.png);
+  background-image: url(chrome://global/skin/media/muteButton.svg#mute);
+}
+.muteButton[muted]:hover {
+  background-image: url(chrome://global/skin/media/muteButton.svg#mute-hover);
 }
-
-.muteButton[noAudio] {
-  background-image: url(chrome://global/skin/media/noAudio.png);
+.muteButton[muted]:hover:active {
+  background-image: url(chrome://global/skin/media/muteButton.svg#mute-active);
 }
-
+.muteButton[noAudio],
+.muteButton[noAudio]:hover,
+.muteButton[noAudio]:hover:active {
+  background-image: url(chrome://global/skin/media/muteButton.svg#noaudio);
+}
 .muteButton[noAudio] + .volumeStack {
   display: none;
 }
 
 .closedCaptionButton {
-  background-image: url(chrome://global/skin/media/closeCaptionButton.png);
-  background-position: 4px;
+  background-image: url(chrome://global/skin/media/closedCaptionButton.svg#cc-off);
 }
-
+.closedCaptionButton:hover {
+  background-image: url(chrome://global/skin/media/closedCaptionButton.svg#cc-off-hover);
+}
+.closedCaptionButton:hover:active {
+  background-image: url(chrome://global/skin/media/closedCaptionButton.svg#cc-off-active);
+}
 .closedCaptionButton[enabled] {
-  opacity: 1;
+  background-image: url(chrome://global/skin/media/closedCaptionButton.svg#cc);
 }
-
-.closedCaptionButton[hidden] {
-  display: none;
+.closedCaptionButton[enabled]:hover {
+  background-image: url(chrome://global/skin/media/closedCaptionButton.svg#cc-hover);
+}
+.closedCaptionButton[enabled]:hover:active {
+  background-image: url(chrome://global/skin/media/closedCaptionButton.svg#cc-active);
 }
 
 .fullscreenButton {
-  background-image: -moz-image-rect(url("chrome://global/skin/media/fullscreenButton.png"), 0, 16, 16, 0);
+  background-image: url(chrome://global/skin/media/fullscreenButton.svg#fullscreen);
+}
+.fullscreenButton:hover {
+  background-image: url(chrome://global/skin/media/fullscreenButton.svg#fullscreen-hover);
+}
+.fullscreenButton:hover:active {
+  background-image: url(chrome://global/skin/media/fullscreenButton.svg#fullscreen-active);
+}
+.fullscreenButton[fullscreened] {
+  background-image: url(chrome://global/skin/media/fullscreenButton.svg#unfullscreen);
+}
+.fullscreenButton[fullscreened]:hover {
+  background-image: url(chrome://global/skin/media/fullscreenButton.svg#unfullscreen-hover);
+}
+.fullscreenButton[fullscreened]:hover:active {
+  background-image: url(chrome://global/skin/media/fullscreenButton.svg#unfullscreen-active);
+}
+
+.controlBarSpacer {
+  flex-grow: 1;
+}
+
+.volumeControl::-moz-range-thumb,
+.scrubber::-moz-range-thumb {
+  height: 13px;
+  width: 13px;
+  border: none;
+  border-radius: 50%;
+  background-color: #ffffff;
+  filter: drop-shadow(0px 0px 5px rgba(0,0,0,0.65));
 }
 
-.fullscreenButton[fullscreened] {
-  background-image: -moz-image-rect(url("chrome://global/skin/media/fullscreenButton.png"), 0, 32, 16, 16);
+.volumeControl::-moz-focus-outer,
+.scrubber::-moz-focus-outer {
+  border: 0;
+}
+
+.progressBackgroundBar {
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
 }
 
-.volumeControl {
-  width: 32px;
-  opacity: 0;
+.progressStack {
+  position: relative;
+  width: 100%;
+  height: 5px;
+}
+
+.scrubberStack {
+  min-width: 48px;
+  flex-basis: 48px;
+  flex-grow: 2;
+  flex-shrink: 0;
+  margin: 0 9px;
+}
+
+.volumeStack {
+  max-width: 60px;
+  min-width: 48px;
+  flex-grow: 1;
+  flex-shrink: 0;
+  margin-right: 6px;
+  margin-left: 4px;
 }
 
+.bufferBar,
+.progressBar,
+.scrubber,
 .volumeBackground,
-.volumeForeground {
-  background-repeat: no-repeat;
-  background-position: center;
-  width: 32px;
+.volumeControl {
+  bottom: 0;
+  left: 0;
+  position: absolute;
+  width: 100%;
+  height: 100%;
+  padding: 0;
+  border: 0;
+  border-radius: 2.5px;
+  margin: 0;
+  background: none;
+  background-color: transparent;
+}
+
+.bufferBar,
+.volumeBackground {
+  background-color: rgba(0,0,0,0.7);
+}
+
+.bufferBar::-moz-progress-bar,
+.progressBar::-moz-progress-bar,
+.volumeBackground::-moz-meter-bar {
+  height: 100%;
+  padding: 0;
+  margin: 0;
+  border: 0;
+  border-radius: 2.5px;
+  background: none;
 }
 
-.volumeBackground {
-  background-image: url(chrome://global/skin/media/volume-empty.png);
+.scrubber:hover::-moz-range-thumb,
+.volumeControl:hover::-moz-range-thumb {
+  background-color: #48a0f7;
+}
+
+.scrubber:active::-moz-range-thumb,
+.volumeControl:active::-moz-range-thumb {
+  background-color: #2d89e6;
+}
+
+.scrubber::-moz-range-track,
+.scrubber::-moz-range-progress {
+  background-color: transparent;
 }
 
-.volumeForeground {
-  background-image: url(chrome://global/skin/media/volume-full.png);
-  background-clip: content-box;
+.volumeControl::-moz-range-progress,
+.volumeControl::-moz-range-track {
+  height: 5px;
+  border-radius: 2.5px;
+}
+
+.volumeControl::-moz-range-progress {
+  background-color: #ffffff;
+}
+
+.volumeControl::-moz-range-track {
+  background-color: rgba(0,0,0,0.7);
+}
+
+
+.bufferBar::-moz-progress-bar {
+  background-color: rgba(255,255,255,0.3);
+  border-radius: 2.5px;
+}
+
+.progressBar::-moz-progress-bar {
+  background-color: #00b6f0;
 }
 
 .textTrackList {
-  display: -moz-box;
-  -moz-appearance: none;
-  -moz-box-pack: end;
-  -moz-box-align: end;
-  padding: 0;
+  position: absolute;
+  right: 5px;
+  bottom: 45px;
+  max-width: 80%;
+  border: 1px solid #000000;
+  border-radius: 2.5px;
+  padding: 5px 0;
+  vertical-align: middle;
+  font-size: 12px;
+  background-color: #000000;
+  opacity: 0.7;
 }
 
-.textTrackList[hidden] {
+.textTrackList > .textTrackItem {
+  display: block;
+  width: 100%;
+  height: 30px;
+  padding: 2px 10px;
+  border: none;
+  margin: 0;
+  white-space: nowrap;
+  overflow: hidden;
+  text-align: left;
+  text-overflow: ellipsis;
+  color: #ffffff;
+  background-color: transparent;
+}
+
+.textTrackList > .textTrackItem:hover {
+  background-color: #444444;
+}
+
+.textTrackList > .textTrackItem[on] {
+  color: #00b6f0;
+}
+
+.positionLabel,
+.durationLabel {
   display: none;
 }
 
-.textTrackList > html|*.textTrackItem {
-  -moz-appearance: none;
-  -moz-box-align: start;
-  text-align: start;
-  overflow: hidden;
-  margin: 0;
-  padding: 2px 10px;
-  -moz-margin-end: 10px;
-  border: none;
-  color: rgba(255,255,255,.5);
-  background-color: rgba(35,31,32,.74);
+.positionDurationBox {
+  min-width: 9ch;
+  text-align: center;
+  padding-inline-start: 1px;
+  padding-inline-end: 9px;
   white-space: nowrap;
-}
-
-.textTrackList > html|*.textTrackItem[on] {
-  color: white;
-  background-color: black;
+  font: message-box;
+  font-size: 13px;
+  font-size-adjust: 0.6;
+  color: #ffffff;
 }
 
-.textTrackList > html|*.textTrackItem:hover {
-  background-color: rgba(0,0,0,.55);
-}
-
-.controlBar[fullscreen-unavailable] {
-  /* This value is duplicated in the videocontrols.xml adjustControlSize function. */
-  padding-inline-end: 8px;
-}
-
-.volumeControl .scale-thumb {
-  min-width: 0;
-  opacity: 0;
-}
-
-.durationBox {
-  -moz-box-pack: center;
-}
-
-.durationLabel {
-  margin-left: -22px; /* 1/2 of scrubber thumb width, for overhang. */
-  padding-left: 8px; /* don't bump into the scrubber bar */
-  color: rgba(255,255,255,.75);
-  font: message-box;
-  font-size: 11px;
+.positionDurationBox[positionOnly] {
+  min-width: 4ch;
 }
 
 %ifdef XP_MACOSX
-.durationLabel {
-  padding-top: 2px; /* center vertically with scrubber bar */
-}
-%else
-.durationLabel {
-  padding-top: 0; /* center vertically with scrubber bar */
+.positionDurationBox {
+  font-size-adjust: unset;
 }
 %endif
 
-.positionLabel {
-  display: none;
-}
-
-.backgroundBar {
-  /* margin top/bottom: make bar 8px tall (control height = 28, minus 2 * 10 margin) */
-  /* margin left/right: 1/2 of scrubber thumb width, for overhang. */
-  margin: 10px 22px;
-  background-color: rgba(255,255,255,.5);
-  border-radius: 2.5px;
-}
-
-.bufferBar,
-.progressBar {
-  /* margin top/bottom: make bar 8px tall (control height = 28, minus 2 * 10 margin) */
-  /* margin left/right: 1/2 of scrubber thumb width, for overhang. */
-  margin: 10px 22px;
-  -moz-appearance: none;
-  border: none;
-  background-color: transparent;
-  min-width: 0;
-  min-height: 0;
-}
-
-/* .progress-bar is an element inside the <progressmeter> implementation. */
-.bufferBar .progress-bar {
-  /*
-   * Note that this is drawn on top of the .backgroundBar. So although this
-   * has the same background-color specified, the semitransparent
-   * compositing gives it a different visual appearance.
-   */
-  background-color: rgba(255,255,255,.5);
-  border-radius: 2.5px;
-  -moz-appearance: none;
-}
-
-.progressBar .progress-bar {
-  background-color: white;
-  border-radius: 2.5px;
-  -moz-appearance: none;
-}
-
-/* .scale-slider is an element inside the <scale> implementation. */
-.scrubber .scale-slider,
-.volumeControl .scale-slider {
-  /* Hide the default horizontal bar. */
-  -moz-appearance: none;
-  background: none;
-  margin: 0;
-}
-
-.scrubber .scale-slider {
-  /* abs(margin-top) + margin-bottom + bar height == timeThumb height */
-  margin-top: -10px;
-  margin-bottom: 10px;
-}
-/* .scale-thumb is an element inside the <scale> implementation. */
-.scrubber .scale-thumb,
-.volumeControl .scale-thumb {
-  /* Override the default thumb appearance with a custom image. */
-  -moz-appearance: none;
-  background: transparent;
-  border: none;
-}
-
-.timeThumb {
-  background: url(chrome://global/skin/media/scrubberThumb.png) no-repeat center;
-  min-width: 45px;
-  min-height: 28px;
-  -moz-box-pack: center;
-}
-
-.timeThumb[showhours="true"] {
-  background-image: url(chrome://global/skin/media/scrubberThumbWide.png);
-}
-
-.timeLabel {
-  color: rgba(255,255,255,.75);
-  font: message-box;
-  font-size: 10px;
-  text-shadow: rgba(0,0,0,.3) 0 1px;
-  padding-top: 7px;
-}
-
-%ifdef XP_MACOSX
-.timeLabel {
-  padding-top: 7px; /* center vertically with scrubber bar */
-}
-%else
-.timeLabel {
-  padding-top: 5px; /* center vertically with scrubber bar */
-}
-%endif
-
-.statusOverlay {
-  -moz-box-align: center;
-  -moz-box-pack: center;
-  background-color: rgba(0,0,0,.55);
+.duration {
+  display: inline-block;
+  white-space: pre;
+  color: #929292;
 }
 
 .statusIcon {
-  margin-bottom: 28px; /* same height as .controlBar, to keep icon centered above it */
   width: 36px;
   height: 36px;
+  margin-bottom: 20px;
 }
 
 .statusIcon[type="throbber"] {
   background: url(chrome://global/skin/media/throbber.png) no-repeat center;
 }
 
 .statusIcon[type="throbber"][stalled] {
   background: url(chrome://global/skin/media/stalled.png) no-repeat center;
 }
 
 .statusIcon[type="error"] {
+  min-width: 70px;
+  min-height: 60px;
   background: url(chrome://global/skin/media/error.png) no-repeat center;
+  background-size: contain;
 }
 
 /* Overlay Play button */
 .clickToPlay {
-  width: 64px;
-  height: 64px;
-  -moz-box-pack: center;
-  -moz-box-align: center;
-  opacity: 0.7;
-  background-image: url(chrome://global/skin/media/clicktoplay-bgtexture.png),
-                    url(chrome://global/skin/media/videoClickToPlayButton.svg);
-  background-repeat: repeat, no-repeat;
-  background-position: center, center;
-  background-size: auto, 64px 64px;
-  background-color: hsla(0,0%,10%,.5);
-}
-.clickToPlay:hover {
-  opacity: 1;
+  min-width: 48px;
+  min-height: 48px;
+  border-radius: 50%;
+  background-image: url(chrome://global/skin/media/playButton.svg#play);
+  background-repeat: no-repeat;
+  background-position: 54% 50%;
+  background-size: 40% 40%;
+  background-color: #1a1a1a;
+  opacity: 0.8;
+  position: relative;
+  top: 20px;
 }
 
-/* Statistics formatting */
-html|*.statsDiv {
-  position: relative;
-}
-html|td {
-  height: 1em;
-  max-height: 1em;
-  padding: 0 2px;
+.controlsSpacerStack:hover > .clickToPlay,
+.clickToPlay:hover {
+  opacity: 0.55;
 }
-html|table {
-  font-family: Helvetica, Arial, sans-serif;
-  font-size: 11px;
-  color: white;
-  text-shadow:
-    -1px -1px 0 #000,
-    1px -1px 0 #000,
-    -1px 1px 0 #000,
-    1px 1px 0 #000;
-  min-width: 100%;
-  background: rgba(68,68,68,.7);
-  table-layout: fixed;
-  border-collapse: collapse;
-  position: absolute;
+
+.controlsSpacerStack:hover > .clickToPlay[fadeout] {
+  opacity: 0;
+}
+
+.controlBar[fullscreen-unavailable] .fullscreenButton {
+  display: none;
 }
 
 /* CSS Transitions */
 .clickToPlay {
-  transition-property: opacity, background-size;
+  transition-property: transform, opacity;
   transition-duration: 400ms, 400ms;
 }
-.clickToPlay[fadeout] {
-  background-size: auto, 192px 192px;
+
+.controlsSpacer[fadeout] {
   opacity: 0;
 }
+
+.clickToPlay[fadeout] {
+  transform: scale(3);
+  opacity: 0;
+}
+
 .clickToPlay[fadeout][immediate] {
   transition-property: opacity, background-size;
   transition-duration: 0s, 0s;
 }
 .controlBar:not([immediate]) {
   transition-property: opacity;
   transition-duration: 200ms;
 }
 .controlBar[fadeout] {
   opacity: 0;
 }
 .volumeStack:not([immediate]) {
   transition-property: opacity, margin-top;
   transition-duration: 200ms, 200ms;
 }
-.volumeStack[fadeout] {
-  opacity: 0;
-  margin-top: 0;
-}
 .statusOverlay:not([immediate]) {
   transition-property: opacity;
   transition-duration: 300ms;
   transition-delay: 750ms;
 }
 .statusOverlay[fadeout] {
   opacity: 0;
 }
 
 /* Error description formatting */
 .errorLabel {
-  font-family: Helvetica, Arial, sans-serif;
-  font-size: 11px;
-  color: #bbb;
-  text-shadow:
-    -1px -1px 0 #000,
-    1px -1px 0 #000,
-    -1px 1px 0 #000,
-    1px 1px 0 #000;
   padding: 0 10px;
   text-align: center;
+  font: message-box;
+  font-size: 14px;
+  color: #ffffff;
 }
 
-@media (min-resolution: 2dppx) {
-  .playButton {
-    background-image: url(chrome://global/skin/media/pauseButton@2x.png);
-    background-size: 28px 28px;
-  }
-  .playButton[paused] {
-    background-image: url(chrome://global/skin/media/playButton@2x.png);
-    background-size: 28px 28px;
-  }
-  .volumeBackground {
-    background-image: url(chrome://global/skin/media/volume-empty@2x.png);
-    background-size: 32px 16px;
-  }
-  .volumeForeground {
-    background-image: url(chrome://global/skin/media/volume-full@2x.png);
-    background-size: 32px 16px;
-  }
-  .muteButton {
-    background-image: url(chrome://global/skin/media/muteButton@2x.png);
-    background-size: 33px 28px;
-  }
-  .muteButton[muted] {
-    background-image: url(chrome://global/skin/media/unmuteButton@2x.png);
-    background-size: 33px 28px;
-  }
-  .muteButton[noAudio] {
-    background-image: url(chrome://global/skin/media/noAudio@2x.png);
-    background-size: 33px 28px;
-  }
-  .closedCaptionButton {
-    background-image: url(chrome://global/skin/media/closeCaptionButton@2x.png);
-    background-position: 4px;
-    background-size: 28px 28px;
-  }
-  .fullscreenButton {
-    background-image: -moz-image-rect(url("chrome://global/skin/media/fullscreenButton@2x.png"), 0, 32, 32, 0);
-    background-size: 16px 16px;
-  }
-  .fullscreenButton[fullscreened] {
-    background-image: -moz-image-rect(url("chrome://global/skin/media/fullscreenButton@2x.png"), 0, 64, 32, 32);
-    background-size: 16px 16px;
-  }
-  .timeThumb {
-    background-image: url(chrome://global/skin/media/scrubberThumb@2x.png);
-    background-size: 33px 28px;
-  }
-  .timeThumb[showhours="true"] {
-    background-image: url(chrome://global/skin/media/scrubberThumbWide@2x.png);
-    background-size: 45px 28px;
-  }
+.errorLabel {
+  display: none;
 }
+
+[error="errorAborted"]         > [anonid="errorAborted"],
+[error="errorNetwork"]         > [anonid="errorNetwork"],
+[error="errorDecode"]          > [anonid="errorDecode"],
+[error="errorSrcNotSupported"] > [anonid="errorSrcNotSupported"],
+[error="errorNoSource"]        > [anonid="errorNoSource"],
+[error="errorGeneric"]         > [anonid="errorGeneric"] {
+  display: inline;
+}
deleted file mode 100644
index 589abfbd5816bb3ec179a3fdf6530106356dba8e..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index ca494e89366563cbb509761eb1f8f3bcae60e2cd..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 4398a569b8c76d0b42fd2900abfcdec1747a0483..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 5bf63c7ee25a0a7c2fbfee5db50b95b20093b1e8..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001