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 363320 6661e2f65c07db3f4ecd3741ca7723e9e20c8bd2
parent 363319 492847b731713ad596d2759e5a0b8725bc5da207
child 363321 c08cb388baee030a47ac0852dba459602bbce761
push id32
push userfmarier@mozilla.com
push dateTue, 07 Feb 2017 08:55:50 +0000
reviewersjaws
bugs1328060
milestone54.0a1
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 {