Bug 1328060 - re-adjust controls when get metadata of video duration. r=jaws
☠☠ backed out by e2486eb5bb76 ☠ ☠
authorRay Lin <ralin@mozilla.com>
Mon, 23 Jan 2017 00:35:08 +0800
changeset 332354 6661e2f65c07db3f4ecd3741ca7723e9e20c8bd2
parent 332353 492847b731713ad596d2759e5a0b8725bc5da207
child 332355 c08cb388baee030a47ac0852dba459602bbce761
push id36864
push usercbook@mozilla.com
push dateFri, 03 Feb 2017 10:12:15 +0000
treeherderautoland@6661e2f65c07 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjaws
bugs1328060
milestone54.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 1328060 - re-adjust controls when get metadata of video duration. r=jaws MozReview-Commit-ID: AKY5Umg08P6
toolkit/content/tests/widgets/test_videocontrols.html
toolkit/content/widgets/videocontrols.xml
toolkit/themes/shared/media/videocontrols.css
--- a/toolkit/content/tests/widgets/test_videocontrols.html
+++ b/toolkit/content/tests/widgets/test_videocontrols.html
@@ -25,17 +25,17 @@ const videoHeight = 240;
 const videoDuration = 3.8329999446868896;
 
 const controlBarMargin = 9;
 
 const playButtonWidth = 30;
 const playButtonHeight = 40;
 const muteButtonWidth = 30;
 const muteButtonHeight = 40;
-const positionAndDurationWidth = 85;
+const positionAndDurationWidth = 75;
 const fullscreenButtonWidth = 30;
 const fullscreenButtonHeight = 40;
 const volumeSliderWidth = 48;
 const volumeSliderMarginStart = 4;
 const volumeSliderMarginEnd = 6;
 const scrubberMargin = 9;
 const scrubberWidth = videoWidth - controlBarMargin - playButtonWidth - scrubberMargin * 2 - positionAndDurationWidth - muteButtonWidth - volumeSliderMarginStart - volumeSliderWidth - volumeSliderMarginEnd - fullscreenButtonWidth - controlBarMargin;
 const scrubberHeight = 40;
--- a/toolkit/content/widgets/videocontrols.xml
+++ b/toolkit/content/widgets/videocontrols.xml
@@ -240,16 +240,23 @@
         if (this._isAudioOnly) {
           this.video.style.height = this.controlBar.minHeight + "px";
           this.video.style.width = "66%";
         } else {
           this.video.style.removeProperty("height");
           this.video.style.removeProperty("width");
         }
       },
+
+      get isControlBarHidden() {
+        return this.controlBar.hidden ||
+               this.controlBar.hideByAdjustment ||
+               this.controlBar.getAttribute("fadeout") === "true";
+      },
+
       suppressError : false,
 
       setupStatusFader(immediate) {
         // Since the play button will be showing, we don't want to
         // show the throbber behind it. The throbber here will
         // only show if needed after the play button has been pressed.
         if (!this.clickToPlay.hidden) {
           this.startFadeOut(this.statusOverlay, true);
@@ -379,16 +386,26 @@
             },
             isAdjustableControl: {
               value: true
             },
             isWanted: {
               value: true,
               writable: true
             },
+            resized: {
+              value: false,
+              writable: true
+            },
+            resizedHandler: {
+              value: () => {
+                control.minWidth = control.clientWidth;
+              },
+              writable: true
+            },
             hideByAdjustment: {
               set: (v) => {
                 if (v) {
                   control.setAttribute("hidden", "true");
                 } else {
                   control.removeAttribute("hidden");
                 }
 
@@ -404,19 +421,21 @@
         }
         // 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.durationSpan.resized = true;
+        this.positionDurationBox.resized = true;
+        this.positionDurationBox.resizedHandler = () => {
+          this.positionDurationBox.minWidth = this.positionDurationBox.clientWidth - this.durationSpan.clientWidth;
+        };
 
         this.adjustControlSize();
         this.controlBar.hidden = true;
 
         // Can only update the volume controls once we've computed
         // _volumeControlWidth, since the volume slider implementation
         // depends on it.
         this.updateVolumeControls();
@@ -521,31 +540,33 @@
             // been hidden (we don't hide controls when the overlay is visible).
             if (this.clickToPlay.hidden && !this.isAudioOnly) {
               this.startFadeIn(this.controlBar);
               clearTimeout(this._hideControlsTimeout);
               this._hideControlsTimeout = setTimeout(this._hideControlsFn, this.HIDE_CONTROLS_TIMEOUT_MS);
             }
             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;
               this.clickToPlay.hidden = true;
               this.startFadeIn(this.controlBar);
               this.setFullscreenButtonState();
             }
-            this.showDuration(Math.round(this.video.duration * 1000));
+            this.showPosition(Math.round(this.video.currentTime * 1000), Math.round(this.video.duration * 1000));
+            this.positionDurationBox.resized = true;
+            this.durationSpan.resized = true;
             if (!this.isAudioOnly && !this.video.mozHasAudio) {
               this.muteButton.setAttribute("noAudio", "true");
               this.muteButton.setAttribute("disabled", "true");
             }
+            this.adjustControlSize();
             break;
           case "loadeddata":
             this.firstFrameShown = true;
             this.setupStatusFader();
             break;
           case "loadstart":
             this.maxCurrentTimeSeen = 0;
             this.controlsSpacer.removeAttribute("aria-label");
@@ -730,27 +751,27 @@
           return; // No error found.
         }
 
         let label = document.getAnonymousElementByAttribute(this.videocontrols, "anonid", error);
         this.controlsSpacer.setAttribute("aria-label", label.textContent);
         this.statusOverlay.setAttribute("error", error);
       },
 
-      formatTime(aTime) {
+      formatTime(aTime, showHour = false) {
         // Format the duration as "h:mm:ss" or "m:ss"
         aTime = Math.round(aTime / 1000);
         let hours = Math.floor(aTime / 3600);
         let mins  = Math.floor((aTime % 3600) / 60);
         let secs  = Math.floor(aTime % 60);
         let timeString;
         if (secs < 10) {
           secs = "0" + secs;
         }
-        if (hours) {
+        if (hours || showHour) {
           if (mins < 10) {
             mins = "0" + mins;
           }
           timeString = hours + ":" + mins + ":" + secs;
         } else {
           timeString = mins + ":" + secs;
         }
         return timeString;
@@ -872,24 +893,26 @@
         this.video.volume = newVolume;
         this.video.muted = false;
       },
 
       showPosition(currentTime, duration) {
         // If the duration is unknown (because the server didn't provide
         // it, or the video is a stream), then we want to fudge the duration
         // by using the maximum playback position that's been seen.
+        let showHour = Math.floor(Math.round(duration / 1000) / 3600);
+
         if (currentTime > this.maxCurrentTimeSeen) {
           this.maxCurrentTimeSeen = currentTime;
         }
         this.showDuration(duration);
 
         this.log("time update @ " + currentTime + "ms of " + duration + "ms");
 
-        let positionTime = this.formatTime(currentTime);
+        let positionTime = this.formatTime(currentTime, showHour);
 
         this.scrubber.value = currentTime;
         if (this.videocontrols.isTouchControls) {
           this.positionLabel.setAttribute("value", positionTime);
         } else {
           this.positionDurationBox.position = positionTime;
           this.updateScrubberProgress();
         }
@@ -1489,16 +1512,17 @@
 
         this.textTrackList.setAttribute("hidden", "true");
         this.setClosedCaptionButtonState();
       },
 
       onControlBarTransitioned() {
         this.textTrackList.setAttribute("hidden", "true");
         this.video.dispatchEvent(new CustomEvent("controlbarchange"));
+        this.adjustControlSize();
       },
 
       toggleClosedCaption() {
         if (this.textTrackList.hasAttribute("hidden")) {
           this.textTrackList.removeAttribute("hidden");
         } else {
           this.textTrackList.setAttribute("hidden", "true");
         }
@@ -1606,37 +1630,36 @@
         if (this.muteButton.hasAttribute("noAudio")) {
           this.volumeStack.isWanted = false;
         }
 
         let widthUsed = minControlBarPaddingWidth;
         let preventAppendControl = false;
 
         for (let control of prioritizedControls) {
+          if (!this.isControlBarHidden && control.resized && !control.hideByAdjustment) {
+            control.resizedHandler();
+            control.resized = false;
+          }
+
           if (!control.isWanted) {
             control.hideByAdjustment = true;
             continue;
           }
 
           control.hideByAdjustment = preventAppendControl ||
           widthUsed + control.minWidth > videoWidth;
 
           if (control.hideByAdjustment) {
             preventAppendControl = true;
           } else {
             widthUsed += control.minWidth;
           }
         }
 
-        if (this.durationSpan.hideByAdjustment) {
-          this.positionDurationBox.setAttribute("positionOnly", "true");
-        } else {
-          this.positionDurationBox.removeAttribute("positionOnly");
-        }
-
         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;
         }
--- a/toolkit/themes/shared/media/videocontrols.css
+++ b/toolkit/themes/shared/media/videocontrols.css
@@ -335,31 +335,26 @@ audio > xul|videocontrols {
 }
 
 .positionLabel,
 .durationLabel {
   display: none;
 }
 
 .positionDurationBox {
-  min-width: 9ch;
   text-align: center;
   padding-inline-start: 1px;
   padding-inline-end: 9px;
   white-space: nowrap;
   font: message-box;
   font-size: 13px;
-  font-size-adjust: 0.6;
+  font-size-adjust: 0.55;
   color: #ffffff;
 }
 
-.positionDurationBox[positionOnly] {
-  min-width: 4ch;
-}
-
 %ifdef XP_MACOSX
 .positionDurationBox {
   font-size-adjust: unset;
   font-family: "Helvetica Neue", "Helvetica", sans-serif;
 }
 %endif
 
 .duration {