Bug 649490 - Switch the volume slider on the media controls to be horizontal and always visible. r=Gijs
authorJared Wein <jwein@mozilla.com>
Wed, 27 Nov 2013 10:31:39 -0500
changeset 173683 9915d93be7b6b2527a2c9922fbf7dc8d0b2f8fea
parent 173682 32817c0e869e69d17051a11bd31b263a70f2b0d5
child 173684 012395358640ffd7ba8333697a41281c2883ad64
push id3224
push userlsblakk@mozilla.com
push dateTue, 04 Feb 2014 01:06:49 +0000
treeherdermozilla-beta@60c04d0987f1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersGijs
bugs649490
milestone28.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 649490 - Switch the volume slider on the media controls to be horizontal and always visible. r=Gijs
accessible/tests/mochitest/actions/test_media.html
accessible/tests/mochitest/tree/test_media.html
b2g/chrome/content/touchcontrols.css
browser/metro/theme/touchcontrols.css
toolkit/content/tests/widgets/test_videocontrols.html
toolkit/content/widgets/videocontrols.css
toolkit/content/widgets/videocontrols.xml
toolkit/themes/osx/global/jar.mn
toolkit/themes/osx/global/media/videocontrols.css
toolkit/themes/osx/global/media/volume-empty.png
toolkit/themes/osx/global/media/volume-full.png
toolkit/themes/osx/global/media/volumeThumb.png
toolkit/themes/osx/global/media/volumeThumb@2x.png
toolkit/themes/windows/global/jar.mn
toolkit/themes/windows/global/media/videocontrols.css
toolkit/themes/windows/global/media/volume-empty.png
toolkit/themes/windows/global/media/volume-full.png
toolkit/themes/windows/global/media/volumeThumb.png
--- a/accessible/tests/mochitest/actions/test_media.html
+++ b/accessible/tests/mochitest/actions/test_media.html
@@ -60,17 +60,17 @@ https://bugzilla.mozilla.org/show_bug.cg
       //////////////////////////////////////////////////////////////////////////
       // test actions of audio controls
 
       todo(false, "Focus test are disabled until bug 494175 is fixed.");
 
       var audioElm = getAccessible("audio");
       var playBtn = audioElm.firstChild;
       var scrubber = playBtn.nextSibling.nextSibling.nextSibling;
-      var muteBtn = audioElm.lastChild;
+      var muteBtn = audioElm.lastChild.previousSibling;
 
       var actions = [
         {
           ID: muteBtn,
           actionName: "press",
           events: CLICK_EVENTS,
           eventSeq: [
      //       new focusChecker(muteBtn),
--- a/accessible/tests/mochitest/tree/test_media.html
+++ b/accessible/tests/mochitest/tree/test_media.html
@@ -44,17 +44,21 @@ https://bugzilla.mozilla.org/show_bug.cg
             role: ROLE_SLIDER,
             //name: "0:00 of 0:02 elapsed",
             children: []
           },
           { // mute button
             role: ROLE_PUSHBUTTON,
             name: "Mute",
             children: []
-          }
+          },
+          { // slider of volume bar
+            role: ROLE_SLIDER,
+            children: []
+          },
         ]
       };
       testAccessibleTree("audio", accTree);
 
       todo(false, "Enable name test for slider. Fail on Linux.");
       SimpleTest.finish();
     }
 
--- a/b2g/chrome/content/touchcontrols.css
+++ b/b2g/chrome/content/touchcontrols.css
@@ -49,17 +49,17 @@
 }
 
 /*
  * Normally the button bar has fullscreen spacer play spacer mute, but if
  * this is an audio control rather than a video control, the fullscreen button
  * is hidden by videocontrols.xml, and that alters the position of the
  * play button.  This workaround moves it back to center.
  */
-.controlBar.audio .playButton {
+.controlBar.audio-only .playButton {
   transform: translateX(28px);
 }
 
 .playButton[paused="true"] {
   background: url("chrome://browser/content/images/play-hdpi.png") no-repeat center;
 }
 
 .muteButton {
--- a/browser/metro/theme/touchcontrols.css
+++ b/browser/metro/theme/touchcontrols.css
@@ -49,17 +49,17 @@
 }
 
 /*
  * Normally the button bar has fullscreen spacer play spacer mute, but if
  * this is an audio control rather than a video control, the fullscreen button
  * is hidden by videocontrols.xml, and that alters the position of the
  * play button.  This workaround moves it back to center.
  */
-.controlBar.audio .playButton {
+.controlBar.audio-only .playButton {
   transform: translateX(28px);
 }
 
 .playButton[paused="true"] {
   background: url("chrome://browser/skin/images/play-hdpi.png") no-repeat center;
 }
 
 .muteButton {
--- a/toolkit/content/tests/widgets/test_videocontrols.html
+++ b/toolkit/content/tests/widgets/test_videocontrols.html
@@ -25,24 +25,25 @@ const videoHeight = 240;
 const videoDuration = 3.8329999446868896;
 
 const playButtonWidth = 28;
 const playButtonHeight = 28;
 const muteButtonWidth = 33;
 const muteButtonHeight = 28;
 const durationWidth = 34;
 const fullscreenButtonWidth = document.mozFullScreenEnabled ? 28 : 0;
-const scrubberWidth = videoWidth - playButtonWidth - muteButtonWidth - durationWidth - fullscreenButtonWidth;
+const volumeSliderWidth = 32;
+const scrubberWidth = videoWidth - playButtonWidth - durationWidth - muteButtonWidth - volumeSliderWidth - fullscreenButtonWidth;
 const scrubberHeight = 28;
 
 // Play button is on the bottom-left
 const playButtonCenterX = 0 + Math.round(playButtonWidth / 2);
 const playButtonCenterY = videoHeight - Math.round(playButtonHeight / 2);
-// Mute button is on the bottom-right before the full screen button
-const muteButtonCenterX = videoWidth - Math.round(muteButtonWidth / 2) - fullscreenButtonWidth;
+// Mute button is on the bottom-right before the full screen button and volume slider
+const muteButtonCenterX = videoWidth - Math.round(muteButtonWidth / 2) - volumeSliderWidth - fullscreenButtonWidth;
 const muteButtonCenterY = videoHeight - Math.round(muteButtonHeight / 2);
 // Scrubber bar is between the play and mute buttons. We don't need it's
 // X center, just the offset of its box.
 const scrubberOffsetX = 0 + playButtonWidth;
 const scrubberCenterY = videoHeight - Math.round(scrubberHeight / 2);
 
 function runTest(event) {
   ok(true, "----- test #" + testnum + " -----");
--- a/toolkit/content/widgets/videocontrols.css
+++ b/toolkit/content/widgets/videocontrols.css
@@ -87,17 +87,18 @@ html|span.statActivity[activity="playing
 html|span.statActivity[activity="ended"] > html|span.statActivityEnded,
 html|span.statActivity[seeking] > html|span.statActivitySeeking {
   display: inline;
 }
 
 .controlBar[size="hidden"],
 .controlBar[size="small"] .durationBox,
 .controlBar[size="small"] .durationLabel,
-.controlBar[size="small"] .positionLabel {
+.controlBar[size="small"] .positionLabel,
+.controlBar[size="small"] .volumeStack {
   visibility: collapse;
 }
 
 .controlBar[size="small"] .scrubberStack,
 .controlBar[size="small"] .backgroundBar,
 .controlBar[size="small"] .bufferBar,
 .controlBar[size="small"] .progressBar,
 .controlBar[size="small"] .scrubber {
--- a/toolkit/content/widgets/videocontrols.xml
+++ b/toolkit/content/widgets/videocontrols.xml
@@ -282,19 +282,20 @@
                     </stack>
                     <vbox class="durationBox">
                         <label class="positionLabel" role="presentation"/>
                         <label class="durationLabel" role="presentation"/>
                     </vbox>
                     <button class="muteButton"
                             mutelabel="&muteButton.muteLabel;"
                             unmutelabel="&muteButton.unmuteLabel;"/>
-                    <stack class="volumeStack" hidden="true" fadeout="true">
-                        <box class="volumeBackgroundBar"/>
-                        <scale class="volumeControl" orient="vertical" dir="reverse" movetoclick="true"/>
+                    <stack class="volumeStack">
+                      <box class="volumeBackground"/>
+                      <box class="volumeForeground" anonid="volumeForeground"/>
+                      <scale class="volumeControl" movetoclick="true"/>
                     </stack>
                     <button class="fullscreenButton"
                             enterfullscreenlabel="&fullscreenButton.enterfullscreenlabel;"
                             exitfullscreenlabel="&fullscreenButton.exitfullscreenlabel;"/>
                 </hbox>
             </vbox>
         </stack>
     </xbl:content>
@@ -308,17 +309,16 @@
 
             this.Utils = {
                 debug : false,
                 video : null,
                 videocontrols : null,
                 controlBar : null,
                 playButton : null,
                 muteButton : null,
-                volumeStack    : null,
                 volumeControl  : null,
                 durationLabel  : null,
                 positionLabel  : null,
                 scrubberThumb  : null,
                 scrubber       : null,
                 progressBar    : null,
                 bufferBar      : null,
                 statusOverlay  : null,
@@ -337,16 +337,23 @@
 
                 firstFrameShown : false,
                 timeUpdateCount : 0,
                 maxCurrentTimeSeen : 0,
                 _isAudioOnly : false,
                 get isAudioOnly() { return this._isAudioOnly; },
                 set isAudioOnly(val) {
                     this._isAudioOnly = val;
+                    if (this._isAudioOnly) {
+                        this.controlBar.setAttribute("audio-only", true);
+                    } else {
+                        this.controlBar.removeAttribute("audio-only");
+                    }
+                    this.adjustControlSize();
+
                     if (!this.isTopLevelSyntheticDocument)
                         return;
                     if (this._isAudioOnly) {
                         this.video.style.height = this._controlBarHeight + "px";
                         this.video.style.width = "66%";
                     } else {
                         this.video.style.removeProperty("height");
                         this.video.style.removeProperty("width");
@@ -457,16 +464,17 @@
                         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._fullscreenButtonWidth = this.fullscreenButton.clientWidth;
                     this._controlBarHeight = this.controlBar.clientHeight;
                     this.controlBar.hidden = true;
                     this.adjustControlSize();
 
                     // Preserve Statistics when toggling fullscreen mode due to bug 714071.
                     if (XPCNativeWrapper.unwrap(this.video).mozMediaStatisticsShowing)
                         this.showStatistics(true);
@@ -549,19 +557,21 @@
                             // We throttle timechange events, so the thumb might not be
                             // exactly at the end when the video finishes.
                             this.showPosition(Math.round(this.video.currentTime * 1000),
                                               Math.round(this.video.duration * 1000));
                             this.startFadeIn(this.controlBar);
                             this.setupStatusFader();
                             break;
                         case "volumechange":
-                            var volume = this.video.muted ? 0 : Math.round(this.video.volume * 100);
+                            var volume = this.video.muted ? 0 : this.video.volume;
+                            var volumePercentage = Math.round(volume * 100);
                             this.setMuteButtonState(this.video.muted);
-                            this.volumeControl.value = volume;
+                            this.volumeControl.value = volumePercentage;
+                            this.volumeForeground.style.paddingRight = (1 - volume) * this._volumeControlWidth + "px";
                             break;
                         case "loadedmetadata":
                             this.adjustControlSize();
                             // If a <video> doesn't have any video data, treat it as <audio>
                             // and show the controls (they won't fade back out)
                             if (this.video instanceof HTMLVideoElement &&
                                 (this.video.videoWidth == 0 || this.video.videoHeight == 0)) {
                                 this.isAudioOnly = true;
@@ -849,31 +859,16 @@
                     var endTime = 0;
                     if (index >= 0) {
                         endTime = Math.round(buffered.end(index) * 1000);
                     }
                     this.bufferBar.max = duration;
                     this.bufferBar.value = endTime;
                 },
 
-                onVolumeMouseInOut : function (event) {
-                    let doc = this.video.ownerDocument;
-                    let win = doc.defaultView;
-                    if (this.isVideoWithoutAudioTrack() ||
-                        (this.isAudioOnly && this.isTopLevelSyntheticDocument)) {
-                        return;
-                    }
-                    // Ignore events caused by transitions between mute button and volumeStack,
-                    // or between nodes inside these two elements.
-                    if (this.isEventWithin(event, this.muteButton, this.volumeStack))
-                        return;
-                    var isMouseOver = (event.type == "mouseover");
-                    this.startFade(this.volumeStack, isMouseOver);
-                },
-
                 _controlsHiddenByTimeout : false,
                 _showControlsTimeout : 0,
                 SHOW_CONTROLS_TIMEOUT_MS: 500,
                 _showControlsFn : function () {
                     if (Utils.video.mozMatchesSelector("video:hover")) {
                         Utils.startFadeIn(Utils.controlBar, false);
                         Utils._showControlsTimeout = 0;
                         Utils._controlsHiddenByTimeout = false;
@@ -1355,34 +1350,41 @@
                   let doc = this.video.ownerDocument;
                   let win = doc.defaultView;
                   return doc.mozSyntheticDocument && win === win.top;
                 },
 
                 _playButtonWidth : 0,
                 _durationLabelWidth : 0,
                 _muteButtonWidth : 0,
+                _volumeControlWidth : 0,
                 _fullscreenButtonWidth : 0,
                 _controlBarHeight : 0,
                 _overlayPlayButtonHeight : 64,
                 _overlayPlayButtonWidth : 64,
+                _volumeStackMarginEnd : 8,
                 adjustControlSize : function adjustControlSize() {
                     let doc = this.video.ownerDocument;
-                    let isAudioOnly = this.isAudioOnly;
-                    if (isAudioOnly && !this.isTopLevelSyntheticDocument)
-                        return;
 
                     // 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._fullscreenButtonWidth;
+
+                    let isAudioOnly = this.isAudioOnly;
+                    if (isAudioOnly) {
+                        // When the fullscreen button is hidden we add margin-end to the volume stack.
+                        minWidthAllControls -= this._fullscreenButtonWidth - this._volumeStackMarginEnd;
+                    }
+
                     let minHeightForControlBar = this._controlBarHeight;
                     let minWidthOnlyPlayPause = this._playButtonWidth + this._muteButtonWidth;
 
                     let videoHeight = isAudioOnly ? minHeightForControlBar : this.video.clientHeight;
                     let videoWidth = isAudioOnly ? minWidthAllControls : this.video.clientWidth;
 
                     if (this._overlayPlayButtonHeight > videoHeight || this._overlayPlayButtonWidth > videoWidth)
                         this.clickToPlay.hidden = true;
@@ -1395,48 +1397,48 @@
                     else if (videoWidth < minWidthAllControls)
                         size = "small";
                     this.controlBar.setAttribute("size", size);
                 },
 
                 init : function (binding) {
                     this.video = binding.parentNode;
                     this.videocontrols = binding;
-                    this.isAudioOnly = (this.video instanceof HTMLAudioElement);
 
                     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.volumeStack   = document.getAnonymousElementByAttribute(binding, "class", "volumeStack");
                     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.statsOverlay  = document.getAnonymousElementByAttribute(binding, "class", "statsOverlay");
                     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.statsTable       = document.getAnonymousElementByAttribute(binding, "class", "statsTable");
                     this.stats.filename   = document.getAnonymousElementByAttribute(binding, "class", "statFilename");
                     this.stats.size       = document.getAnonymousElementByAttribute(binding, "class", "statSize");
                     this.stats.activity   = document.getAnonymousElementByAttribute(binding, "class", "statActivity");
                     this.stats.volume     = document.getAnonymousElementByAttribute(binding, "class", "statVolume");
                     this.stats.readyState = document.getAnonymousElementByAttribute(binding, "class", "statReadyState");
                     this.stats.netState   = document.getAnonymousElementByAttribute(binding, "class", "statNetState");
                     this.stats.framesParsed    = document.getAnonymousElementByAttribute(binding, "class", "statFramesParsed");
                     this.stats.framesDecoded   = document.getAnonymousElementByAttribute(binding, "class", "statFramesDecoded");
                     this.stats.framesPresented = document.getAnonymousElementByAttribute(binding, "class", "statFramesPresented");
                     this.stats.framesPainted   = document.getAnonymousElementByAttribute(binding, "class", "statFramesPainted");
 
+                    this.isAudioOnly = (this.video instanceof HTMLAudioElement);
                     this.setupInitialState();
                     this.setupNewLoadState();
 
                     // Use the handleEvent() callback for all media events.
                     // The "error" event listener must capture, so that it can trap error events
                     // from the <source> children, which don't bubble.
                     for each (let event in this.videoEvents)
                         this.video.addEventListener(event, this, (event == "error") ? true : false);
@@ -1454,25 +1456,16 @@
 
                     addListener(this.muteButton, "command", this.toggleMute);
                     addListener(this.playButton, "command", this.togglePause);
                     addListener(this.fullscreenButton, "command", this.toggleFullscreen);
                     addListener(this.clickToPlay, "click", this.clickToPlayClickHandler);
                     addListener(this.controlsSpacer, "click", this.clickToPlayClickHandler);
                     addListener(this.controlsSpacer, "dblclick", this.toggleFullscreen);
 
-                    if (this.isAudioOnly) {
-                      this.controlBar.classList.add("audio");
-                    } else {
-                      addListener(this.muteButton, "mouseover", this.onVolumeMouseInOut);
-                      addListener(this.muteButton, "mouseout", this.onVolumeMouseInOut);
-                      addListener(this.volumeStack, "mouseover", this.onVolumeMouseInOut);
-                      addListener(this.volumeStack, "mouseout", this.onVolumeMouseInOut);
-                    }
-
                     addListener(this.videocontrols, "resizevideocontrols", this.adjustControlSize);
                     addListener(this.videocontrols, "transitionend", this.onTransitionEnd);
                     addListener(this.video.ownerDocument, "mozfullscreenchange", this.onFullscreenChange);
                     addListener(this.video, "keypress", this.keyHandler);
 
                     this.log("--- videocontrols initialized ---");
                 }
             };
@@ -1534,21 +1527,22 @@
                         <spacer flex="1"/>
                         <button class="playButton"
                                 playlabel="&playButton.playLabel;"
                                 pauselabel="&playButton.pauseLabel;"/>
                         <spacer flex="1"/>
                         <button class="muteButton"
                                 mutelabel="&muteButton.muteLabel;"
                                 unmutelabel="&muteButton.unmuteLabel;"/>
-                        <stack class="volumeStack" hidden="true" fadeout="true">
-                            <box class="volumeBackgroundBar"/>
-                            <scale class="volumeControl" orient="vertical" dir="reverse" movetoclick="true"/>
+                        <stack class="volumeStack">
+                          <box class="volumeBackground"/>
+                          <box class="volumeForeground" anonid="volumeForeground"/>
+                          <scale class="volumeControl" movetoclick="true"/>
                         </stack>
-                    </hbox>
+                      </hbox>
                     <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"/>
--- a/toolkit/themes/osx/global/jar.mn
+++ b/toolkit/themes/osx/global/jar.mn
@@ -169,18 +169,18 @@ toolkit.jar:
   skin/classic/global/media/fullscreenButton@2x.png                  (media/fullscreenButton@2x.png)
   skin/classic/global/media/scrubberThumb.png                        (media/scrubberThumb.png)
   skin/classic/global/media/scrubberThumb@2x.png                     (media/scrubberThumb@2x.png)
   skin/classic/global/media/scrubberThumbWide.png                    (media/scrubberThumbWide.png)
   skin/classic/global/media/scrubberThumbWide@2x.png                 (media/scrubberThumbWide@2x.png)
   skin/classic/global/media/error.png                                (media/error.png)
   skin/classic/global/media/throbber.png                             (media/throbber.png)
   skin/classic/global/media/stalled.png                              (media/stalled.png)
-  skin/classic/global/media/volumeThumb.png                          (media/volumeThumb.png)
-  skin/classic/global/media/volumeThumb@2x.png                       (media/volumeThumb@2x.png)
+  skin/classic/global/media/volume-empty.png                         (media/volume-empty.png)
+  skin/classic/global/media/volume-full.png                          (media/volume-full.png)
   skin/classic/global/media/clicktoplay-bgtexture.png                (media/clicktoplay-bgtexture.png)
   skin/classic/global/media/videoClickToPlayButton.svg               (media/videoClickToPlayButton.svg)
   skin/classic/global/menu/menu-arrow.png                            (menu/menu-arrow.png)
   skin/classic/global/menu/menu-arrow@2x.png                         (menu/menu-arrow@2x.png)
   skin/classic/global/menu/menu-check.png                            (menu/menu-check.png)
   skin/classic/global/menu/menu-check@2x.png                         (menu/menu-check@2x.png)
   skin/classic/global/scale/scale-tray-horiz.gif                     (scale/scale-tray-horiz.gif)
   skin/classic/global/scale/scale-tray-vert.gif                      (scale/scale-tray-vert.gif)
--- a/toolkit/themes/osx/global/media/videocontrols.css
+++ b/toolkit/themes/osx/global/media/videocontrols.css
@@ -54,54 +54,57 @@
 .muteButton[muted] {
   background-image: url(chrome://global/skin/media/unmuteButton.png);
 }
 
 .muteButton[noAudio] {
   background-image: url(chrome://global/skin/media/noAudio.png);
 }
 
+.muteButton[noAudio] + .volumeStack {
+  display: none;
+}
+
 .fullscreenButton {
   background-image: -moz-image-rect(url("chrome://global/skin/media/fullscreenButton.png"), 0, 16, 16, 0);
 }
 
 .fullscreenButton[fullscreened] {
   background-image: -moz-image-rect(url("chrome://global/skin/media/fullscreenButton.png"), 0, 32, 16, 16);
 }
 
-.volumeStack {
-  width: 28px;
-  height: 70px;
-  background-color: rgba(35,31,32,.74);
-  /* use negative margin to place stack over the mute button to its left. */
-  margin: -70px 3px 28px -31px;
-  overflow: hidden; /* crop it when sliding down, don't grow the control bar */
-  position: relative; /* Trick to work around negative margin interfering with dragging the thumb. */
-  padding-top: 6px;
+.volumeControl {
+  width: 32px;
+  opacity: 0;
 }
 
-.volumeControl {
-  min-height: 64px;
+.volumeBackground,
+.volumeForeground {
+  background-repeat: no-repeat;
+  background-position: center;
+  width: 32px;
 }
 
-/* .scale-thumb is an element inside the <scale> implementation. */
-.volumeControl .scale-thumb {
-  /* Override the default thumb appearance with a custom image. */
-  -moz-appearance: none;
-  background: url(chrome://global/skin/media/volumeThumb.png) no-repeat center;
-  border: none;
-  min-width: 20px;
-  min-height: 10px;
+.volumeBackground {
+  background-image: url(chrome://global/skin/media/volume-empty.png);
+}
+
+.volumeForeground {
+  background-image: url(chrome://global/skin/media/volume-full.png);
+  background-clip: content-box;
 }
 
-.volumeBackgroundBar {
-  /* margin left/right: make bar 8px wide (control width = 28, minus 2 * 10 margin) */
-  margin: 0 10px;
-  background-color: rgba(255,255,255,.75);
-  border-radius: 2.5px;
+.controlBar[audio-only] > .volumeStack {
+  /* This value is duplicated in the videocontrols.xml adjustControlSize function. */
+  -moz-margin-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. */
@@ -332,20 +335,16 @@ html|table {
   .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;
   }
-  .volumeControl .scale-thumb {
-    background-image: url(chrome://global/skin/media/volumeThumb@2x.png);
-    background-size: 20px 10px;
-  }
   .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;
   }
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..589abfbd5816bb3ec179a3fdf6530106356dba8e
GIT binary patch
literal 295
zc%17D@N?(olHy`uVBq!ia0vp^3P3Et!3HGD8EPYelw^r(L`iUdT1k0gQ7VIDN`6wR
zf@f}GdTLN=VoGJ<$y6JlqLZF3jv*DdlK%YvZ-3Z<Y1*-4ZdJD>`Hrv!tU2xE+<j((
z4pXA`iXU841Qtw6UFRX@>U`8sNR(BCZJ~Ndj`*Y+6VFVBb_;2N|4o~gKje1uViXqW
zc4`)2TgUX#U!_h>Ao`MyIKxM6joE@;*%yty4Geh<7%UxxGz}XM`0f&Oarnd3QLfOL
z$zZ51R4-;Cc<Bt|jRWN>WmdCdOoGgo%w+!1m>ST-V{@`pWUJR9*^G-P7<A2fI4pan
ql^!hANIM|h%GSdiE6dCx!SL>yqE+B(ySG43F?hQAxvX<aXaWGv&|&KU
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..4398a569b8c76d0b42fd2900abfcdec1747a0483
GIT binary patch
literal 297
zc$@(#0oMMBP)<h;3K|Lk000e1NJLTq001BW000mO1^@s6cL04^0000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUy%Sl8*RCwBA{Qv(y!$1O-&!0cj+s<$x
zHh^MX#!sI<(aIt-B#S`U3M!5g<SbOO%oWL^XsFmpVl<Ky0?0w=3HA~YFfua2&BW$Y
zT;jMKzy`#>pzLWt^9_I&U<*P<BE|4JKoshm-B7WsK&*vD10yXQ07?U|&=hFVGfOZr
z3@`vWKoXXipx`Dw9e^tlasu&pD0?O}jhNFa4PXP`k=W^Ia?wcHkY*u3D)2yZR0K83
v0crqCw4&IY-VVS8qL3ZNIMCHGK!5=N%h^ktibA+A00000NkvXXu0mjf898vG
deleted file mode 100644
index 5ac7cdd84dd9c65ce0ceb532f7b98d2cfd7bdb40..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 31d8073c33173f154b65f039b817b2b12c625e07..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/toolkit/themes/windows/global/jar.mn
+++ b/toolkit/themes/windows/global/jar.mn
@@ -158,17 +158,18 @@ toolkit.jar:
         skin/classic/global/media/muteButton.png                 (media/muteButton.png)
         skin/classic/global/media/unmuteButton.png               (media/unmuteButton.png)
         skin/classic/global/media/noAudio.png                    (media/noAudio.png)
         skin/classic/global/media/fullscreenButton.png           (media/fullscreenButton.png)
         skin/classic/global/media/scrubberThumb.png              (media/scrubberThumb.png)
         skin/classic/global/media/scrubberThumbWide.png          (media/scrubberThumbWide.png)
         skin/classic/global/media/throbber.png                   (media/throbber.png)
         skin/classic/global/media/stalled.png                    (media/stalled.png)
-        skin/classic/global/media/volumeThumb.png                (media/volumeThumb.png)
+        skin/classic/global/media/volume-empty.png               (media/volume-empty.png)
+        skin/classic/global/media/volume-full.png                (media/volume-full.png)
         skin/classic/global/media/error.png                      (media/error.png)
         skin/classic/global/media/clicktoplay-bgtexture.png      (media/clicktoplay-bgtexture.png)
         skin/classic/global/media/videoClickToPlayButton.svg     (media/videoClickToPlayButton.svg)
         skin/classic/global/printpreview/arrow-left.png          (printpreview/arrow-left.png)
         skin/classic/global/printpreview/arrow-left-end.png      (printpreview/arrow-left-end.png)
         skin/classic/global/printpreview/arrow-right.png         (printpreview/arrow-right.png)
         skin/classic/global/printpreview/arrow-right-end.png     (printpreview/arrow-right-end.png)
         skin/classic/global/radio/radio-check.gif                (radio/radio-check.gif)
@@ -339,17 +340,18 @@ toolkit.jar:
         skin/classic/aero/global/media/muteButton.png                    (media/muteButton.png)
         skin/classic/aero/global/media/unmuteButton.png                  (media/unmuteButton.png)
         skin/classic/aero/global/media/noAudio.png                       (media/noAudio.png)
         skin/classic/aero/global/media/fullscreenButton.png              (media/fullscreenButton.png)
         skin/classic/aero/global/media/scrubberThumb.png                 (media/scrubberThumb.png)
         skin/classic/aero/global/media/scrubberThumbWide.png             (media/scrubberThumbWide.png)
         skin/classic/aero/global/media/throbber.png                      (media/throbber.png)
         skin/classic/aero/global/media/stalled.png                       (media/stalled.png)
-        skin/classic/aero/global/media/volumeThumb.png                   (media/volumeThumb.png)
+        skin/classic/aero/global/media/volume-empty.png                  (media/volume-empty.png)
+        skin/classic/aero/global/media/volume-full.png                   (media/volume-full.png)
         skin/classic/aero/global/media/error.png                         (media/error.png)
         skin/classic/aero/global/media/clicktoplay-bgtexture.png         (media/clicktoplay-bgtexture.png)
         skin/classic/aero/global/media/videoClickToPlayButton.svg        (media/videoClickToPlayButton.svg)
         skin/classic/aero/global/printpreview/arrow-left.png             (printpreview/arrow-left-aero.png)
         skin/classic/aero/global/printpreview/arrow-left-end.png         (printpreview/arrow-left-end-aero.png)
         skin/classic/aero/global/printpreview/arrow-right.png            (printpreview/arrow-right-aero.png)
         skin/classic/aero/global/printpreview/arrow-right-end.png        (printpreview/arrow-right-end-aero.png)
         skin/classic/aero/global/radio/radio-check.gif                   (radio/radio-check.gif)
--- a/toolkit/themes/windows/global/media/videocontrols.css
+++ b/toolkit/themes/windows/global/media/videocontrols.css
@@ -54,54 +54,57 @@
 .muteButton[muted] {
   background-image: url(chrome://global/skin/media/unmuteButton.png);
 }
 
 .muteButton[noAudio] {
   background-image: url(chrome://global/skin/media/noAudio.png);
 }
 
+.muteButton[noAudio] + .volumeStack {
+  display: none;
+}
+
 .fullscreenButton {
   background-image: -moz-image-rect(url("chrome://global/skin/media/fullscreenButton.png"), 0, 16, 16, 0);
 }
 
 .fullscreenButton[fullscreened] {
   background-image: -moz-image-rect(url("chrome://global/skin/media/fullscreenButton.png"), 0, 32, 16, 16);
 }
 
-.volumeStack {
-  width: 28px;
-  height: 70px;
-  background-color: rgba(35,31,32,.74);
-  /* use negative margin to place stack over the mute button to its left. */
-  margin: -70px 3px 28px -31px;
-  overflow: hidden; /* crop it when sliding down, don't grow the control bar */
-  position: relative; /* Trick to work around negative margin interfering with dragging the thumb. */
-  padding-top: 6px;
+.volumeControl {
+  width: 32px;
+  opacity: 0;
 }
 
-.volumeControl {
-  min-height: 64px;
+.volumeBackground,
+.volumeForeground {
+  background-repeat: no-repeat;
+  background-position: center;
+  width: 32px;
 }
 
-/* .scale-thumb is an element inside the <scale> implementation. */
-.volumeControl .scale-thumb {
-  /* Override the default thumb appearance with a custom image. */
-  -moz-appearance: none;
-  background: url(chrome://global/skin/media/volumeThumb.png) no-repeat center;
-  border: none;
-  min-width: 20px;
-  min-height: 10px;
+.volumeBackground {
+  background-image: url(chrome://global/skin/media/volume-empty.png);
+}
+
+.volumeForeground {
+  background-image: url(chrome://global/skin/media/volume-full.png);
+  background-clip: content-box;
 }
 
-.volumeBackgroundBar {
-  /* margin left/right: make bar 8px wide (control width = 28, minus 2 * 10 margin) */
-  margin: 0 10px;
-  background-color: rgba(255,255,255,.75);
-  border-radius: 2.5px;
+.controlBar[audio-only] > .volumeStack {
+  /* This value is duplicated in the videocontrols.xml adjustControlSize function. */
+  -moz-margin-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. */
@@ -165,17 +168,18 @@
 
 .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 {
+.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;
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..589abfbd5816bb3ec179a3fdf6530106356dba8e
GIT binary patch
literal 295
zc%17D@N?(olHy`uVBq!ia0vp^3P3Et!3HGD8EPYelw^r(L`iUdT1k0gQ7VIDN`6wR
zf@f}GdTLN=VoGJ<$y6JlqLZF3jv*DdlK%YvZ-3Z<Y1*-4ZdJD>`Hrv!tU2xE+<j((
z4pXA`iXU841Qtw6UFRX@>U`8sNR(BCZJ~Ndj`*Y+6VFVBb_;2N|4o~gKje1uViXqW
zc4`)2TgUX#U!_h>Ao`MyIKxM6joE@;*%yty4Geh<7%UxxGz}XM`0f&Oarnd3QLfOL
z$zZ51R4-;Cc<Bt|jRWN>WmdCdOoGgo%w+!1m>ST-V{@`pWUJR9*^G-P7<A2fI4pan
ql^!hANIM|h%GSdiE6dCx!SL>yqE+B(ySG43F?hQAxvX<aXaWGv&|&KU
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..4398a569b8c76d0b42fd2900abfcdec1747a0483
GIT binary patch
literal 297
zc$@(#0oMMBP)<h;3K|Lk000e1NJLTq001BW000mO1^@s6cL04^0000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUy%Sl8*RCwBA{Qv(y!$1O-&!0cj+s<$x
zHh^MX#!sI<(aIt-B#S`U3M!5g<SbOO%oWL^XsFmpVl<Ky0?0w=3HA~YFfua2&BW$Y
zT;jMKzy`#>pzLWt^9_I&U<*P<BE|4JKoshm-B7WsK&*vD10yXQ07?U|&=hFVGfOZr
z3@`vWKoXXipx`Dw9e^tlasu&pD0?O}jhNFa4PXP`k=W^Ia?wcHkY*u3D)2yZR0K83
v0crqCw4&IY-VVS8qL3ZNIMCHGK!5=N%h^ktibA+A00000NkvXXu0mjf898vG
deleted file mode 100644
index 5ac7cdd84dd9c65ce0ceb532f7b98d2cfd7bdb40..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001