Bug 1271765 - Part 2: Desktop media control visual refresh. r=jaws
MozReview-Commit-ID: 1GfyGmrhgCs --HG-- extra : rebase_source : e3b49788ddac0537281c8e2fb33c66b31e631db3
@ -1151,7 +1151,7 @@ this.EXPORTED_SYMBOLS = ["WebVTT"];
|
||||
|
||||
if (controls) {
|
||||
controlBar = controls.ownerDocument.getAnonymousElementByAttribute(
|
||||
controls, "class", "controlBar");
|
||||
controls, "anonid", "controlBar");
|
||||
controlBarShown = controlBar ? !!controlBar.clientHeight : false;
|
||||
}
|
||||
|
||||
|
@ -46,6 +46,7 @@
|
||||
// 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");
|
||||
@ -131,7 +132,11 @@
|
||||
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,
|
||||
@ -203,61 +208,67 @@
|
||||
<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 = {
|
||||
@ -270,7 +281,6 @@
|
||||
volumeControl : null,
|
||||
durationLabel : null,
|
||||
positionLabel : null,
|
||||
scrubberThumb : null,
|
||||
scrubber : null,
|
||||
progressBar : null,
|
||||
bufferBar : null,
|
||||
@ -293,6 +303,7 @@
|
||||
firstFrameShown : false,
|
||||
timeUpdateCount : 0,
|
||||
maxCurrentTimeSeen : 0,
|
||||
isPausedByDragging: false,
|
||||
_isAudioOnly : false,
|
||||
get isAudioOnly() { return this._isAudioOnly; },
|
||||
set isAudioOnly(val) {
|
||||
@ -302,7 +313,7 @@
|
||||
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");
|
||||
@ -366,6 +377,7 @@
|
||||
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);
|
||||
|
||||
@ -396,11 +408,11 @@
|
||||
// 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()) {
|
||||
@ -412,15 +424,66 @@
|
||||
|
||||
// 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;
|
||||
this.controlBar.hidden = true;
|
||||
|
||||
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;
|
||||
|
||||
// Can only update the volume controls once we've computed
|
||||
// _volumeControlWidth, since the volume slider implementation
|
||||
@ -443,8 +506,10 @@
|
||||
(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);
|
||||
},
|
||||
|
||||
@ -464,12 +529,16 @@
|
||||
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) {
|
||||
@ -486,7 +555,7 @@
|
||||
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;
|
||||
@ -585,10 +654,11 @@
|
||||
|
||||
// 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;
|
||||
@ -744,6 +814,37 @@
|
||||
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");
|
||||
@ -753,14 +854,17 @@
|
||||
|
||||
// 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
|
||||
@ -769,6 +873,51 @@
|
||||
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);
|
||||
@ -798,8 +947,15 @@
|
||||
|
||||
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() {
|
||||
@ -831,8 +987,9 @@
|
||||
}
|
||||
|
||||
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
|
||||
@ -870,8 +1027,9 @@
|
||||
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.
|
||||
@ -959,7 +1117,11 @@
|
||||
// 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)
|
||||
@ -967,7 +1129,7 @@
|
||||
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.
|
||||
@ -995,7 +1157,9 @@
|
||||
if (!element.hasAttribute("fadeout"))
|
||||
return;
|
||||
|
||||
this.scrubber.dragStateChanged(false);
|
||||
if (this.videocontrols.isTouchControls) {
|
||||
this.scrubber.dragStateChanged(false);
|
||||
}
|
||||
element.hidden = true;
|
||||
},
|
||||
|
||||
@ -1102,14 +1266,17 @@
|
||||
// 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) {
|
||||
@ -1253,6 +1420,10 @@
|
||||
textTrack.kind == "captions";
|
||||
},
|
||||
|
||||
get isClosedCaptionAvailable() {
|
||||
return this.overlayableTextTracks.length && !this.videocontrols.isTouchControls;
|
||||
},
|
||||
|
||||
get overlayableTextTracks() {
|
||||
return Array.prototype.filter.call(this.video.textTracks, this.isSupportedTextTrack);
|
||||
},
|
||||
@ -1268,7 +1439,7 @@
|
||||
},
|
||||
|
||||
setClosedCaptionButtonState : function() {
|
||||
if (!this.overlayableTextTracks.length || this.videocontrols.isTouchControl) {
|
||||
if (!this.isClosedCaptionAvailable) {
|
||||
this.closedCaptionButton.setAttribute("hidden", "true");
|
||||
return;
|
||||
}
|
||||
@ -1280,6 +1451,7 @@
|
||||
} else {
|
||||
this.closedCaptionButton.removeAttribute("enabled");
|
||||
}
|
||||
this.adjustControlSize();
|
||||
|
||||
let ttItems = this.textTrackList.childNodes;
|
||||
|
||||
@ -1353,33 +1525,11 @@
|
||||
},
|
||||
|
||||
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) {
|
||||
@ -1414,6 +1564,11 @@
|
||||
},
|
||||
|
||||
initTextTracks : function() {
|
||||
if (!this.isClosedCaptionAvailable) {
|
||||
this.closedCaptionButton.setAttribute("hidden", "true");
|
||||
return;
|
||||
}
|
||||
|
||||
const offLabel = this.textTrackList.getAttribute("offlabel");
|
||||
|
||||
this.addNewTextTrack({
|
||||
@ -1451,108 +1606,146 @@
|
||||
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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
let videoWidth = this.video.clientWidth;
|
||||
let videoHeight = this.video.clientHeight;
|
||||
const minControlBarPaddingWidth = 18;
|
||||
|
||||
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.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`;
|
||||
|
||||
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
|
||||
];
|
||||
|
||||
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;
|
||||
control.hideByAdjustment = preventAppendControl ||
|
||||
widthUsed + control.minWidth > videoWidth;
|
||||
|
||||
let isAudioOnly = this.isAudioOnly;
|
||||
let videoHeight = isAudioOnly ? minHeightForControlBar : this.video.clientHeight;
|
||||
let videoWidth = isAudioOnly ? minWidthAllControls : this.video.clientWidth;
|
||||
|
||||
// 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);
|
||||
|
||||
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 (control.hideByAdjustment) {
|
||||
preventAppendControl = true;
|
||||
} else {
|
||||
widthUsed += control.minWidth;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
// 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();
|
||||
@ -1579,10 +1772,10 @@
|
||||
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);
|
||||
@ -1590,19 +1783,26 @@
|
||||
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>
|
||||
@ -1621,15 +1821,15 @@
|
||||
|
||||
<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>
|
||||
@ -1639,8 +1839,8 @@
|
||||
|
||||
<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>
|
||||
@ -1649,38 +1849,41 @@
|
||||
<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>
|
||||
@ -1690,10 +1893,9 @@
|
||||
</xbl:content>
|
||||
|
||||
<implementation>
|
||||
|
||||
<constructor>
|
||||
<![CDATA[
|
||||
this.isTouchControl = true;
|
||||
this.isTouchControls = true;
|
||||
this.TouchUtils = {
|
||||
videocontrols: null,
|
||||
video: null,
|
||||
@ -1828,7 +2030,7 @@
|
||||
}, 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);
|
||||
@ -1858,7 +2060,8 @@
|
||||
}
|
||||
}
|
||||
};
|
||||
this.TouchUtils.init(this);
|
||||
|
||||
this.TouchUtils.init(this)
|
||||
this.dispatchEvent(new CustomEvent("VideoBindingAttached"));
|
||||
]]>
|
||||
</constructor>
|
||||
|
@ -37,3 +37,13 @@ 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>">
|
||||
|
@ -64,31 +64,14 @@ toolkit.jar:
|
||||
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
|
||||
|
@ -8,5 +8,6 @@ body {
|
||||
}
|
||||
|
||||
video {
|
||||
box-shadow: 0 0 15px #000;
|
||||
border: 1px #000000 solid;
|
||||
box-shadow: 0 0 5px rgba(0,0,0,0.6);
|
||||
}
|
||||
|
Before Width: | Height: | Size: 583 B |
Before Width: | Height: | Size: 1.3 KiB |
55
toolkit/themes/shared/media/closedCaptionButton.svg
Normal file
@ -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>
|
After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 433 B After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 733 B |
47
toolkit/themes/shared/media/fullscreenButton.svg
Normal file
@ -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>
|
After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 619 B |
56
toolkit/themes/shared/media/muteButton.svg
Normal file
@ -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>
|
After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 930 B |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 269 B |
36
toolkit/themes/shared/media/pauseButton.svg
Normal file
@ -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>
|
After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 434 B |
Before Width: | Height: | Size: 448 B |
37
toolkit/themes/shared/media/playButton.svg
Normal file
@ -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>
|
After Width: | Height: | Size: 1015 B |
Before Width: | Height: | Size: 831 B |
Before Width: | Height: | Size: 562 B |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 563 B |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 324 B |
Before Width: | Height: | Size: 542 B |
@ -2,283 +2,375 @@
|
||||
* 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[noAudio] {
|
||||
background-image: url(chrome://global/skin/media/noAudio.png);
|
||||
.muteButton[muted]:hover {
|
||||
background-image: url(chrome://global/skin/media/muteButton.svg#mute-hover);
|
||||
}
|
||||
.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: -moz-image-rect(url("chrome://global/skin/media/fullscreenButton.png"), 0, 32, 16, 16);
|
||||
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);
|
||||
}
|
||||
|
||||
.volumeControl {
|
||||
width: 32px;
|
||||
opacity: 0;
|
||||
.controlBarSpacer {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.volumeBackground,
|
||||
.volumeForeground {
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.textTrackList {
|
||||
display: -moz-box;
|
||||
-moz-appearance: none;
|
||||
-moz-box-pack: end;
|
||||
-moz-box-align: end;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.textTrackList[hidden] {
|
||||
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;
|
||||
.volumeControl::-moz-range-thumb,
|
||||
.scrubber::-moz-range-thumb {
|
||||
height: 13px;
|
||||
width: 13px;
|
||||
border: none;
|
||||
color: rgba(255,255,255,.5);
|
||||
background-color: rgba(35,31,32,.74);
|
||||
white-space: nowrap;
|
||||
border-radius: 50%;
|
||||
background-color: #ffffff;
|
||||
filter: drop-shadow(0px 0px 5px rgba(0,0,0,0.65));
|
||||
}
|
||||
|
||||
.textTrackList > html|*.textTrackItem[on] {
|
||||
color: white;
|
||||
background-color: black;
|
||||
.volumeControl::-moz-focus-outer,
|
||||
.scrubber::-moz-focus-outer {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.textTrackList > html|*.textTrackItem:hover {
|
||||
background-color: rgba(0,0,0,.55);
|
||||
.progressBackgroundBar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.controlBar[fullscreen-unavailable] {
|
||||
/* This value is duplicated in the videocontrols.xml adjustControlSize function. */
|
||||
padding-inline-end: 8px;
|
||||
.progressStack {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 5px;
|
||||
}
|
||||
|
||||
.volumeControl .scale-thumb {
|
||||
min-width: 0;
|
||||
opacity: 0;
|
||||
.scrubberStack {
|
||||
min-width: 48px;
|
||||
flex-basis: 48px;
|
||||
flex-grow: 2;
|
||||
flex-shrink: 0;
|
||||
margin: 0 9px;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
%ifdef XP_MACOSX
|
||||
.durationLabel {
|
||||
padding-top: 2px; /* center vertically with scrubber bar */
|
||||
}
|
||||
%else
|
||||
.durationLabel {
|
||||
padding-top: 0; /* center vertically with scrubber bar */
|
||||
}
|
||||
%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;
|
||||
.volumeStack {
|
||||
max-width: 60px;
|
||||
min-width: 48px;
|
||||
flex-grow: 1;
|
||||
flex-shrink: 0;
|
||||
margin-right: 6px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.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);
|
||||
.progressBar,
|
||||
.scrubber,
|
||||
.volumeBackground,
|
||||
.volumeControl {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
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;
|
||||
background: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.scrubber .scale-slider {
|
||||
/* abs(margin-top) + margin-bottom + bar height == timeThumb height */
|
||||
margin-top: -10px;
|
||||
margin-bottom: 10px;
|
||||
.bufferBar,
|
||||
.volumeBackground {
|
||||
background-color: rgba(0,0,0,0.7);
|
||||
}
|
||||
/* .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;
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.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 {
|
||||
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 > .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;
|
||||
}
|
||||
|
||||
.timeThumb {
|
||||
background: url(chrome://global/skin/media/scrubberThumb.png) no-repeat center;
|
||||
min-width: 45px;
|
||||
min-height: 28px;
|
||||
-moz-box-pack: center;
|
||||
.textTrackList > .textTrackItem:hover {
|
||||
background-color: #444444;
|
||||
}
|
||||
|
||||
.timeThumb[showhours="true"] {
|
||||
background-image: url(chrome://global/skin/media/scrubberThumbWide.png);
|
||||
.textTrackList > .textTrackItem[on] {
|
||||
color: #00b6f0;
|
||||
}
|
||||
|
||||
.timeLabel {
|
||||
color: rgba(255,255,255,.75);
|
||||
.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: 10px;
|
||||
text-shadow: rgba(0,0,0,.3) 0 1px;
|
||||
padding-top: 7px;
|
||||
font-size: 13px;
|
||||
font-size-adjust: 0.6;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.positionDurationBox[positionOnly] {
|
||||
min-width: 4ch;
|
||||
}
|
||||
|
||||
%ifdef XP_MACOSX
|
||||
.timeLabel {
|
||||
padding-top: 7px; /* center vertically with scrubber bar */
|
||||
}
|
||||
%else
|
||||
.timeLabel {
|
||||
padding-top: 5px; /* center vertically with scrubber bar */
|
||||
.positionDurationBox {
|
||||
font-size-adjust: unset;
|
||||
}
|
||||
%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"] {
|
||||
@ -290,61 +382,55 @@
|
||||
}
|
||||
|
||||
.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;
|
||||
.controlsSpacerStack:hover > .clickToPlay,
|
||||
.clickToPlay:hover {
|
||||
opacity: 0.55;
|
||||
}
|
||||
html|td {
|
||||
height: 1em;
|
||||
max-height: 1em;
|
||||
padding: 0 2px;
|
||||
|
||||
.controlsSpacerStack:hover > .clickToPlay[fadeout] {
|
||||
opacity: 0;
|
||||
}
|
||||
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;
|
||||
|
||||
.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;
|
||||
@ -360,10 +446,6 @@ html|table {
|
||||
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;
|
||||
@ -375,66 +457,22 @@ html|table {
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 295 B |
Before Width: | Height: | Size: 268 B |
Before Width: | Height: | Size: 297 B |
Before Width: | Height: | Size: 267 B |