--- a/toolkit/content/widgets/videocontrols.xml
+++ b/toolkit/content/widgets/videocontrols.xml
@@ -383,29 +383,17 @@
isAdjustableControl: {
value: true
},
isWanted: {
value: true,
writable: true
},
resized: {
- value: false,
- writable: true
- },
- resizedHandler: {
- value: () => {
- let width = control.clientWidth;
-
- if (width === 0) {
- return;
- }
-
- control.minWidth = width;
- },
+ value: true,
writable: true
},
hideByAdjustment: {
set: (v) => {
if (v) {
control.setAttribute("hidden", "true");
} else {
control.removeAttribute("hidden");
@@ -421,26 +409,23 @@
}
});
}
// Cannot get minimal width of flexible scrubber and clickToPlay.
// Rewrite to empirical value for now.
this.scrubberStack.minWidth = 64;
this.volumeStack.minWidth = 48;
this.clickToPlay.minWidth = 48;
-
- if (this.positionDurationBox) {
- this.positionDurationBox.resizedHandler = () => {
- let durationWidth = this.durationSpan.hideByAdjustment ? 0 : this.durationSpan.clientWidth;
-
- this.positionDurationBox.minWidth = this.positionDurationBox.clientWidth - durationWidth;
- };
-
- this.positionDurationBox.resized = true;
- }
+ this.scrubberStack.resized = false;
+ this.volumeStack.resized = false;
+ this.clickToPlay.resized = false;
+ // durationLabel and positionLabel are no longer be needed for
+ // desktop media controls adjustment.
+ this.durationLabel.resized = false;
+ this.positionLabel.resized = false;
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();
@@ -1172,36 +1157,16 @@
}
if (this.videocontrols.isTouchControls) {
this.scrubber.dragStateChanged(false);
}
element.hidden = true;
},
- onVideoControlsResized() {
- // Do not adjust again if resize event is caused by adjustControls(). Audio
- // might be resized by adjustControls(), so we should skip this handler if
- // current size is the same as the adjusted size.
- let {width, height} = this.video.getBoundingClientRect();
- if (width === this.adjustedVideoSize.width && height === this.adjustedVideoSize.height) {
- return;
- }
-
- // For the controls which haven't got correct computed size yet, force
- // them to re-cache their minWidth when the media is resized (reflow).
- this.layoutControls.forEach(control => {
- if (control) {
- control.resized = control.resized || (control.minWidth === 0);
- }
- });
-
- this.adjustControlSize();
- },
-
_triggeredByControls: false,
startPlay() {
this._triggeredByControls = true;
this.hideClickToPlay();
this.video.play();
},
@@ -1661,63 +1626,85 @@
get isTopLevelSyntheticDocument() {
let doc = this.video.ownerDocument;
let win = doc.defaultView;
return doc.mozSyntheticDocument && win === win.top;
},
controlBarMinHeight: 40,
- adjustedVideoSize: {},
adjustControlSize() {
if (this.videocontrols.isTouchControls) {
return;
}
- let controlHidden = this.isControlBarHidden;
-
- if (this.layoutControls.some(control => control.resized)) {
- this.controlBar.hidden = false;
+ this.fullscreenButton.isWanted = !this.controlBar.hasAttribute("fullscreen-unavailable");
+ this.closedCaptionButton.isWanted = this.isClosedCaptionAvailable;
+ this.volumeStack.isWanted = !this.muteButton.hasAttribute("noAudio");
- for (let control of this.layoutControls) {
- if (control.resized && !control.hideByAdjustment) {
- control.resizedHandler();
- control.resized = false;
- }
+ // For the controls which haven't got correct computed size yet, force
+ // them to re-cache their minWidth when the media is resized (reflow).
+ for (const control of this.layoutControls) {
+ const controlWidth = control.clientWidth;
+
+ if (controlWidth === 0 || !control.resized) {
+ continue;
}
-
- this.controlBar.hidden = controlHidden;
+ control.minWidth = controlWidth;
+ control.resized = false;
}
// Check minWidth of controlBar before adjusting. If the layout information
// isn't ready yet, the minWidth of controlBar would be undefined or 0, so early
// return to avoid invalid adjustment.
if (!this.controlBar.minWidth) {
return;
}
- let videoWidth = this.video.clientWidth;
- let videoHeight = this.video.clientHeight;
- const minControlBarPaddingWidth = 18;
+ // Duration label is only a bit wider than position label. So we could roughly
+ // treat them as the same wide that also increase the responsiveness tolerance.
+ if (!this.durationSpan.resized) {
+ this.positionDurationBox.minWidth = this.durationSpan.minWidth;
+ }
// Hide and show control in order.
const prioritizedControls = [
this.playButton,
this.muteButton,
this.fullscreenButton,
this.closedCaptionButton,
this.positionDurationBox,
this.scrubberStack,
this.durationSpan,
this.volumeStack
];
- this.fullscreenButton.isWanted = !this.controlBar.hasAttribute("fullscreen-unavailable");
- this.closedCaptionButton.isWanted = this.isClosedCaptionAvailable;
- this.volumeStack.isWanted = !this.muteButton.hasAttribute("noAudio");
+ const minControlBarPaddingWidth = 18;
+ const minRequiredWidth = prioritizedControls
+ .filter(control => control.isWanted)
+ .reduce((pv, cv) => pv + cv.minWidth, minControlBarPaddingWidth);
+
+ const givenWidth = this.video.clientWidth;
+ const computedControlBarWidth = this.controlBar.clientWidth;
+ const videoWidth = this.isAudioOnly ? (givenWidth || minRequiredWidth) : givenWidth;
+ const videoHeight = this.video.clientHeight;
+ // Notice: Don't flush sytle after this comment to avoid recursively calling synchronous
+ // resize handling.
+
+ // For audio, if the given width is 0 and the audio controls does not expand
+ // to normal set of layouts, we make the entire audio controls transparent instead
+ // of collapsing it to 0 size.
+ if (this.isAudioOnly &&
+ givenWidth === 0 &&
+ computedControlBarWidth === minControlBarPaddingWidth) {
+ this.controlBar.style.opacity = 0;
+ return;
+ } else {
+ this.controlBar.style.opacity = "";
+ }
let widthUsed = minControlBarPaddingWidth;
let preventAppendControl = false;
for (let control of prioritizedControls) {
if (!control.isWanted) {
control.hideByAdjustment = true;
continue;
@@ -1728,26 +1715,20 @@
if (control.hideByAdjustment) {
preventAppendControl = true;
} else {
widthUsed += control.minWidth;
}
}
- if (this.durationSpan.hideByAdjustment) {
- this.positionDurationBox.resized = true;
- }
-
- if (videoHeight < this.controlBarMinHeight ||
- widthUsed === minControlBarPaddingWidth) {
- this.controlBar.setAttribute("size", "hidden");
+ if ((!this.isAudioOnly && videoHeight < this.controlBarMinHeight) ||
+ widthUsed <= minControlBarPaddingWidth) {
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;
@@ -1762,18 +1743,16 @@
this.clickToPlay.hideByAdjustment = true;
} else {
if (this.clickToPlay.hidden && !this.video.played.length && this.video.paused) {
this.clickToPlay.hideByAdjustment = false;
}
this.clickToPlay.style.width = `${clickToPlayScaledSize}px`;
this.clickToPlay.style.height = `${clickToPlayScaledSize}px`;
}
- // Record new size after adjustment
- this.adjustedVideoSize = this.video.getBoundingClientRect();
},
init(binding) {
this.video = binding.parentNode;
this.videocontrols = binding;
this.controlsContainer = document.getAnonymousElementByAttribute(binding, "anonid", "controlsContainer");
this.statusIcon = document.getAnonymousElementByAttribute(binding, "anonid", "statusIcon");
@@ -1846,17 +1825,17 @@
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.clickToPlay, "click", this.clickToPlayClickHandler);
addListener(this.controlsSpacer, "click", this.clickToPlayClickHandler);
addListener(this.controlsSpacer, "dblclick", this.toggleFullscreen);
- addListener(this.videocontrols, "resizevideocontrols", this.onVideoControlsResized);
+ addListener(this.videocontrols, "resizevideocontrols", this.adjustControlSize);
addListener(this.videocontrols, "transitionend", this.onTransitionEnd);
addListener(this.video.ownerDocument, "mozfullscreenchange", this.onFullscreenChange);
addListener(this.controlBar, "transitionend", this.onControlBarTransitioned);
addListener(this.video.ownerDocument, "fullscreenchange", this.onFullscreenChange);
addListener(this.video, "keypress", this.keyHandler, true);
addListener(this.videocontrols, "dragstart", function(event) {
event.preventDefault(); // prevent dragging of controls image (bug 517114)