☠☠ backed out by 60af44ebfa62 ☠ ☠ | |
author | Ray Lin <ralin@mozilla.com> |
Wed, 12 Oct 2016 13:31:32 +0800 | |
changeset 321590 | 02d34b18d76bf7d59d09149385b00586111146e7 |
parent 321589 | 08811364762917e139d7459faf3b324f076c5e95 |
child 321591 | 235ea1c681db5aaec4b81466d65a4dcfe374c9ce |
push id | 83647 |
push user | kwierso@gmail.com |
push date | Tue, 08 Nov 2016 22:08:41 +0000 |
treeherder | mozilla-inbound@1d0b02250149 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jaws |
bugs | 1271765 |
milestone | 52.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/dom/media/webvtt/vtt.jsm +++ b/dom/media/webvtt/vtt.jsm @@ -1146,17 +1146,17 @@ this.EXPORTED_SYMBOLS = ["WebVTT"]; overlay.removeChild(overlay.firstChild); } var controlBar; var controlBarShown; if (controls) { controlBar = controls.ownerDocument.getAnonymousElementByAttribute( - controls, "class", "controlBar"); + controls, "anonid", "controlBar"); controlBarShown = controlBar ? !!controlBar.clientHeight : false; } var paddedOverlay = window.document.createElement("div"); paddedOverlay.style.position = "absolute"; paddedOverlay.style.left = "0"; paddedOverlay.style.right = "0"; paddedOverlay.style.top = "0";
--- a/toolkit/content/widgets/videocontrols.xml +++ b/toolkit/content/widgets/videocontrols.xml @@ -41,16 +41,17 @@ </getter> <setter> <![CDATA[ this.setAttribute("showhours", val); // If the duration becomes known while we're still showing the value // 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"); else if (!val && displayedTime == "0:00:00") this.timeLabel.setAttribute("value", "0:00"); ]]> </setter> </property> @@ -126,17 +127,21 @@ switch (which) { case "curpos": if (this.type == "scrubber") { // Update the time shown in the thumb. this.thumb.setTime(newValue); 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, // but not when pressing an arrow key. However, the base binding sets // ._userChanged in its keypress handlers, so we just need to check both. if (!userChanged && !this._userChanged) return; this.setAttribute("value", newValue); @@ -198,84 +203,89 @@ <binding id="videoControls"> <resources> <stylesheet src="chrome://global/content/bindings/videocontrols.css"/> <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 = { debug : false, video : null, videocontrols : null, controlBar : null, playButton : null, muteButton : null, volumeControl : null, durationLabel : null, positionLabel : null, - scrubberThumb : null, scrubber : null, progressBar : null, bufferBar : null, statusOverlay : null, controlsSpacer : null, clickToPlay : null, controlsOverlay : null, fullscreenButton : null, @@ -288,26 +298,27 @@ "playing", "waiting", "canplay", "canplaythrough", "seeking", "seeked", "emptied", "loadedmetadata", "error", "suspend", "stalled", "mozinterruptbegin", "mozinterruptend" ], firstFrameShown : false, timeUpdateCount : 0, maxCurrentTimeSeen : 0, + isPausedByDragging: false, _isAudioOnly : false, get isAudioOnly() { return this._isAudioOnly; }, set isAudioOnly(val) { this._isAudioOnly = val; this.setFullscreenButtonState(); 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"); this.video.style.removeProperty("width"); } }, suppressError : false, @@ -361,16 +372,17 @@ this.setFullscreenButtonState(); var duration = Math.round(this.video.duration * 1000); // in ms var currentTime = Math.round(this.video.currentTime * 1000); // in ms 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); // If we have metadata, check if this is a <video> without // video data, or a video with no audio track. if (this.video.readyState >= this.video.HAVE_METADATA) { if (this.video instanceof HTMLVideoElement && (this.video.videoWidth == 0 || this.video.videoHeight == 0)) @@ -391,41 +403,92 @@ // If the first frame hasn't loaded, kick off a throbber fade-in. if (this.video.readyState >= this.video.HAVE_CURRENT_DATA) this.firstFrameShown = true; // 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()) { this.clickToPlay.hidden = true; this.statusIcon.setAttribute("type", "error"); this.updateErrorText(); this.setupStatusFader(true); } // An event handler for |onresize| should be added when bug 227495 is fixed. this.controlBar.hidden = false; - this._playButtonWidth = this.playButton.clientWidth; - this._durationLabelWidth = this.durationLabel.clientWidth; - this._muteButtonWidth = this.muteButton.clientWidth; - this._volumeControlWidth = this.volumeControl.clientWidth; - this._closedCaptionButtonWidth = this.closedCaptionButton.clientWidth; - this._fullscreenButtonWidth = this.fullscreenButton.clientWidth; - this._controlBarHeight = this.controlBar.clientHeight; + + 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; - this.adjustControlSize(); // Can only update the volume controls once we've computed // _volumeControlWidth, since the volume slider implementation // depends on it. this.updateVolumeControls(); }, setupNewLoadState : function() { @@ -438,18 +501,20 @@ // so that they don't get in the way of the playing video. Otherwise we'll // go ahead and reveal the controls now, so they're an obvious user cue. // // (Note: the |controls| attribute is already handled via layout/style/html.css) var shouldShow = !this.dynamicControls || (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); }, get dynamicControls() { // Don't fade controls for <audio> elements. var enabled = !this.isAudioOnly; // Allow tests to explicitly suppress the fading of controls. @@ -459,39 +524,43 @@ // If the video hits an error, suppress controls if it // hasn't managed to do anything else yet. if (!this.firstFrameShown && this.hasError()) enabled = false; 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) { this.log("Got media event ----> " + aEvent.type); // If the binding is detached (or has been replaced by a // newer instance of the binding), nuke our event-listeners. if (this.videocontrols.randomID != this.randomID) { this.terminateEventListeners(); return; } switch (aEvent.type) { 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; this._triggeredByControls = false; break; case "pause": // Little white lie: if we've internally paused the video // while dragging the scrubber, don't change the button state. @@ -580,20 +649,21 @@ // statusOverlay while we wait for HAVE_ENOUGH_DATA). // If we've seen more than 2 timeupdate events, // the count is no longer relevant to setupStatusFader. if (this.timeUpdateCount <= 2) this.setupStatusFader(); // 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; this.showPosition(0, 0); break; case "seeking": this.showBuffered(); this.statusIcon.setAttribute("type", "throbber"); @@ -739,41 +809,120 @@ mins = "0" + mins; timeString = hours + ":" + mins + ":" + secs; } else { timeString = mins + ":" + secs; } 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"); if (isNaN(duration) || isInfinite) duration = this.maxCurrentTimeSeen; // 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 // snapping when dragging with the mouse, so we can't just set a value for // the arrow-keys. 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); if (this.videocontrols.isGonk) { // We use fastSeek() on B2G, and an accurate (but slower) // seek on other platforms (that are likely to be higher // perf). this.video.fastSeek(newPosition); @@ -793,18 +942,25 @@ // it, or the video is a stream), then we want to fudge the duration // by using the maximum playback position that's been seen. if (currentTime > this.maxCurrentTimeSeen) this.maxCurrentTimeSeen = currentTime; this.showDuration(duration); 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() { function bsearch(haystack, needle, cmp) { var length = haystack.length; var low = 0; var high = length; while (low < high) { @@ -826,18 +982,19 @@ return 1; } else if (time >= buffered.start(i)) { return 0; } return -1; } 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 // displayed in the bar. var currentTime = this.video.currentTime; var buffered = this.video.buffered; var index = bsearch(buffered, currentTime, bufferedCompare); var endTime = 0; @@ -865,18 +1022,19 @@ Utils.startFade(Utils.controlBar, false); Utils._hideControlsTimeout = 0; Utils._controlsHiddenByTimeout = true; } }, 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. if (!this.dynamicControls) return; clearTimeout(this._hideControlsTimeout); @@ -954,25 +1112,29 @@ }, startFade : function (element, fadeIn, immediate) { if (element.classList.contains("controlBar") && fadeIn) { // Bug 493523, the scrubber doesn't call valueChanged while hidden, // 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) element.setAttribute("immediate", true); 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. element.clientTop; element.removeAttribute("fadeout"); if (element.classList.contains("controlBar")) this.controlsSpacer.removeAttribute("hideCursor"); } else { @@ -990,17 +1152,19 @@ return; var element = event.originalTarget; // Nothing to do when a fade *in* finishes. if (!element.hasAttribute("fadeout")) return; - this.scrubber.dragStateChanged(false); + if (this.videocontrols.isTouchControls) { + this.scrubber.dragStateChanged(false); + } element.hidden = true; }, _triggeredByControls: false, startPlay : function () { this._triggeredByControls = true; this.hideClickToPlay(); @@ -1097,24 +1261,27 @@ hideClickToPlay : function () { let videoHeight = this.video.clientHeight; let videoWidth = this.video.clientWidth; // The play button will animate to 3x its size. This // 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) { if (aPaused) this.playButton.setAttribute("paused", "true"); else this.playButton.removeAttribute("paused"); @@ -1248,43 +1415,48 @@ event.preventDefault(); // Prevent page scrolling }, isSupportedTextTrack : function(textTrack) { return textTrack.kind == "subtitles" || textTrack.kind == "captions"; }, + get isClosedCaptionAvailable() { + return this.overlayableTextTracks.length && !this.videocontrols.isTouchControls; + }, + get overlayableTextTracks() { return Array.prototype.filter.call(this.video.textTracks, this.isSupportedTextTrack); }, isClosedCaptionOn : function () { for (let tt of this.overlayableTextTracks) { if (tt.mode === "showing") { return true; } } return false; }, setClosedCaptionButtonState : function () { - if (!this.overlayableTextTracks.length || this.videocontrols.isTouchControl) { + if (!this.isClosedCaptionAvailable) { this.closedCaptionButton.setAttribute("hidden", "true"); return; } this.closedCaptionButton.removeAttribute("hidden"); if (this.isClosedCaptionOn()) { this.closedCaptionButton.setAttribute("enabled", "true"); } else { this.closedCaptionButton.removeAttribute("enabled"); } + this.adjustControlSize(); let ttItems = this.textTrackList.childNodes; for (let tti of ttItems) { const idx = +tti.getAttribute("index"); if (idx == this.currentTextTrackIndex) { tti.setAttribute("on", "true"); @@ -1348,43 +1520,21 @@ }, onControlBarTransitioned : function () { this.textTrackList.setAttribute("hidden", "true"); this.video.dispatchEvent(new CustomEvent("controlbarchange")); }, 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) { this.addNewTextTrack(trackEvent.track); this.setClosedCaptionButtonState(); }, onTextTrackRemove : function (trackEvent) { @@ -1409,16 +1559,21 @@ this.video.dispatchEvent(new CustomEvent("texttrackchange")); } } this.setClosedCaptionButtonState(); }, initTextTracks : function () { + if (!this.isClosedCaptionAvailable) { + this.closedCaptionButton.setAttribute("hidden", "true"); + return; + } + const offLabel = this.textTrackList.getAttribute("offlabel"); this.addNewTextTrack({ label: offLabel, kind: "subtitles" }); for (let tt of this.overlayableTextTracks) { @@ -1446,118 +1601,156 @@ }, get isTopLevelSyntheticDocument() { let doc = this.video.ownerDocument; let win = doc.defaultView; 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; + } + + let videoWidth = this.video.clientWidth; + let videoHeight = this.video.clientHeight; + const minControlBarPaddingWidth = 18; + + 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`; - // 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; + 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 + ]; - 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.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; - - let isAudioOnly = this.isAudioOnly; - let videoHeight = isAudioOnly ? minHeightForControlBar : this.video.clientHeight; - let videoWidth = isAudioOnly ? minWidthAllControls : this.video.clientWidth; + control.hideByAdjustment = preventAppendControl || + widthUsed + control.minWidth > videoWidth; - // 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); + if (control.hideByAdjustment) { + preventAppendControl = true; + } else { + widthUsed += control.minWidth; + } + } + + if (this.durationSpan.hideByAdjustment) { + this.positionDurationBox.setAttribute("positionOnly", "true"); + } else { + this.positionDurationBox.removeAttribute("positionOnly"); + } - 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 (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; - 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; + // 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(); this.initTextTracks(); // Use the handleEvent() callback for all media events. // Only the "error" event listener must capture, so that it can trap error // events from <source> children, which don't bubble. But we use capture @@ -1574,40 +1767,47 @@ // Helper function to add an event listener to the given element function addListener(elem, eventName, func) { let boundFunc = func.bind(self); self.controlListeners.push({ item: elem, event: eventName, func: boundFunc }); 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); 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> <destructor> <![CDATA[ this.Utils.terminateEventListeners(); // randomID used to be a <field>, which meant that the XBL machinery // undefined the property when the element was unbound. The code in @@ -1616,89 +1816,91 @@ delete this.randomID; ]]> </destructor> </implementation> <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> </binding> <binding id="touchControls" extends="chrome://global/content/bindings/videocontrols.xml#videoControls"> <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> <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> - <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> </vbox> </vbox> </stack> </xbl:content> <implementation> - <constructor> <![CDATA[ - this.isTouchControl = true; + this.isTouchControls = true; this.TouchUtils = { videocontrols: null, video: null, controlsTimer: null, controlsTimeout: 5000, positionLabel: null, castingButton: null, @@ -1823,17 +2025,17 @@ this.Utils.scrubber.addEventListener("touchstart", function() { self.clearTimer(); }, false); this.Utils.scrubber.addEventListener("touchend", function() { self.delayHideControls(self.controlsTimeout); }, 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); this.video.addEventListener("media-videoCasting", function (e) { if (!e.isTrusted) return; self.updateCasting(e.detail); @@ -1853,17 +2055,18 @@ // transitioned into or out of fullscreen mode, and we don't want // the controls to remain visible. this.controlsTimeout is a full // 5s, which feels too long after the transition. if (this.video.currentTime !== 0) { this.delayHideControls(this.Utils.HIDE_CONTROLS_TIMEOUT_MS); } } }; - this.TouchUtils.init(this); + + this.TouchUtils.init(this) this.dispatchEvent(new CustomEvent("VideoBindingAttached")); ]]> </constructor> <destructor> <![CDATA[ // XBL destructors don't appear to be inherited properly, so we need // to do this here in addition to the videoControls destructor. :-( delete this.randomID;
--- a/toolkit/locales/en-US/chrome/global/videocontrols.dtd +++ b/toolkit/locales/en-US/chrome/global/videocontrols.dtd @@ -32,8 +32,18 @@ <!ENTITY error.generic "Video playback aborted due to an unknown error."> <!-- LOCALIZATION NOTE (scrubberScale.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 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>">
--- a/toolkit/themes/shared/jar.inc.mn +++ b/toolkit/themes/shared/jar.inc.mn @@ -59,41 +59,24 @@ toolkit.jar: skin/classic/global/reader/RM-Content-Width-Plus-44x16.svg (../../shared/reader/RM-Content-Width-Plus-44x16.svg) skin/classic/global/reader/RM-Line-Height-Minus-38x14.svg (../../shared/reader/RM-Line-Height-Minus-38x14.svg) skin/classic/global/reader/RM-Line-Height-Plus-38x24.svg (../../shared/reader/RM-Line-Height-Plus-38x24.svg) skin/classic/global/media/TopLevelImageDocument.css (../../shared/media/TopLevelImageDocument.css) skin/classic/global/media/TopLevelVideoDocument.css (../../shared/media/TopLevelVideoDocument.css) 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 skin/classic/mozapps/places/defaultFavicon.png (../../shared/places/defaultFavicon.png) skin/classic/mozapps/places/defaultFavicon@2x.png (../../shared/places/defaultFavicon@2x.png) skin/classic/mozapps/places/defaultFavicon-inverted.png (../../shared/places/defaultFavicon-inverted.png) skin/classic/mozapps/places/defaultFavicon-inverted@2x.png (../../shared/places/defaultFavicon-inverted@2x.png) #endif
--- a/toolkit/themes/shared/media/TopLevelVideoDocument.css +++ b/toolkit/themes/shared/media/TopLevelVideoDocument.css @@ -3,10 +3,11 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ body { background-image: url("chrome://global/skin/media/imagedoc-darknoise.png"); background-color: rgb(33,33,33); /* Average color of that ^ image. */ } video { - box-shadow: 0 0 15px #000; + border: 1px #000000 solid; + box-shadow: 0 0 5px rgba(0,0,0,0.6); }
deleted file mode 100644 index 469310fb1b21ed705925decd18710dd0df37d915..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch literal 0 Hc$@<O00001
deleted file mode 100644 index 03350789221b94d830ebc4dafb1b6e4447f79f71..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch literal 0 Hc$@<O00001
new file mode 100644 --- /dev/null +++ b/toolkit/themes/shared/media/closedCaptionButton.svg @@ -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>
index 58e37283a73eff086420d0969544fa8bc5dd7924..362a293f223fe1c29751b711de8c48de950ebd49 GIT binary patch literal 20345 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 D)qq~X
deleted file mode 100644 index ffbc3d5ae4627d9beb7c4e8c6ef80542e7e1414c..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch literal 0 Hc$@<O00001
new file mode 100644 --- /dev/null +++ b/toolkit/themes/shared/media/fullscreenButton.svg @@ -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>
deleted file mode 100644 index b09ebbd43ce8dd62741992a0d00df1018897d164..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch literal 0 Hc$@<O00001
deleted file mode 100644 index 894480761d0742015ffcfcc2d28bc10e88cbe4a9..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch literal 0 Hc$@<O00001
new file mode 100644 --- /dev/null +++ b/toolkit/themes/shared/media/muteButton.svg @@ -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>
deleted file mode 100644 index b2cd21c5ebc271dbe97d72207827cb48e0b0fa05..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch literal 0 Hc$@<O00001
deleted file mode 100644 index 3db8c973b6594cb8820661564eb8dacb673c09b9..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch literal 0 Hc$@<O00001
deleted file mode 100644 index 7de728b2d7a17a75cc0e5b44da308e7a9e8db013..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch literal 0 Hc$@<O00001
deleted file mode 100644 index 944098ca19a4f63331ae852606c3907285e7e203..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch literal 0 Hc$@<O00001
new file mode 100644 --- /dev/null +++ b/toolkit/themes/shared/media/pauseButton.svg @@ -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>
deleted file mode 100644 index df22919419082d251064811ac730eea234008ad6..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch literal 0 Hc$@<O00001
deleted file mode 100644 index 11e2731df64f9dd00623f263150d8a651ee1b1bc..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch literal 0 Hc$@<O00001
new file mode 100644 --- /dev/null +++ b/toolkit/themes/shared/media/playButton.svg @@ -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>
deleted file mode 100644 index fb20075b24af20c17d2ab0f301e04b74c0fbdb50..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch literal 0 Hc$@<O00001
deleted file mode 100644 index f159627631c536f0def829f45f3715f198db1a5e..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch literal 0 Hc$@<O00001
deleted file mode 100644 index f8790f46724c449f053f490ff840f279da03964b..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch literal 0 Hc$@<O00001
deleted file mode 100644 index 96d2ed75140584a92940e65b4f5d1f7a60a133c3..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch literal 0 Hc$@<O00001
deleted file mode 100644 index 52c9d72727e8d6c263c288454003b06cb2e819b9..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch literal 0 Hc$@<O00001
deleted file mode 100644 index 5b76e2fa45d8481ca0a81e524c4a20508adfc284..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch literal 0 Hc$@<O00001
deleted file mode 100644 index 86f21859eee91db51bab2e89ce0b05f2378f2dd3..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch literal 0 Hc$@<O00001
--- a/toolkit/themes/shared/media/videocontrols.css +++ b/toolkit/themes/shared/media/videocontrols.css @@ -1,440 +1,487 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * 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[muted]:hover { + background-image: url(chrome://global/skin/media/muteButton.svg#mute-hover); } - -.muteButton[noAudio] { - background-image: url(chrome://global/skin/media/noAudio.png); +.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: 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); +} + +.controlBarSpacer { + flex-grow: 1; +} + +.volumeControl::-moz-range-thumb, +.scrubber::-moz-range-thumb { + height: 13px; + width: 13px; + border: none; + border-radius: 50%; + background-color: #ffffff; + filter: drop-shadow(0px 0px 5px rgba(0,0,0,0.65)); } -.fullscreenButton[fullscreened] { - background-image: -moz-image-rect(url("chrome://global/skin/media/fullscreenButton.png"), 0, 32, 16, 16); +.volumeControl::-moz-focus-outer, +.scrubber::-moz-focus-outer { + border: 0; +} + +.progressBackgroundBar { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; } -.volumeControl { - width: 32px; - opacity: 0; +.progressStack { + position: relative; + width: 100%; + height: 5px; +} + +.scrubberStack { + min-width: 48px; + flex-basis: 48px; + flex-grow: 2; + flex-shrink: 0; + margin: 0 9px; +} + +.volumeStack { + max-width: 60px; + min-width: 48px; + flex-grow: 1; + flex-shrink: 0; + margin-right: 6px; + margin-left: 4px; } +.bufferBar, +.progressBar, +.scrubber, .volumeBackground, -.volumeForeground { - background-repeat: no-repeat; - background-position: center; - width: 32px; +.volumeControl { + bottom: 0; + left: 0; + position: absolute; + width: 100%; + height: 100%; + padding: 0; + border: 0; + border-radius: 2.5px; + margin: 0; + background: none; + background-color: transparent; +} + +.bufferBar, +.volumeBackground { + background-color: rgba(0,0,0,0.7); +} + +.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; } -.volumeBackground { - background-image: url(chrome://global/skin/media/volume-empty.png); +.scrubber::-moz-range-thumb, +.volumeControl::-moz-range-thumb { + width: 13px; + height: 13px; + background-color: #ffffff; + filter: drop-shadow(5px #000000) +} + +.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; } -.volumeForeground { - background-image: url(chrome://global/skin/media/volume-full.png); - background-clip: content-box; +.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 { - display: -moz-box; - -moz-appearance: none; - -moz-box-pack: end; - -moz-box-align: end; - padding: 0; + 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[hidden] { +.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; +} + +.textTrackList > .textTrackItem:hover { + background-color: #444444; +} + +.textTrackList > .textTrackItem[on] { + color: #00b6f0; +} + +.positionLabel, +.durationLabel { 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; - border: none; - color: rgba(255,255,255,.5); - background-color: rgba(35,31,32,.74); +.positionDurationBox { + min-width: 9ch; + text-align: center; + padding-inline-start: 1px; + padding-inline-end: 9px; white-space: nowrap; -} - -.textTrackList > html|*.textTrackItem[on] { - color: white; - background-color: black; + font: message-box; + font-size: 13px; + font-size-adjust: 0.6; + color: #ffffff; } -.textTrackList > html|*.textTrackItem:hover { - background-color: rgba(0,0,0,.55); -} - -.controlBar[fullscreen-unavailable] { - /* This value is duplicated in the videocontrols.xml adjustControlSize function. */ - padding-inline-end: 8px; -} - -.volumeControl .scale-thumb { - min-width: 0; - opacity: 0; -} - -.durationBox { - -moz-box-pack: center; -} - -.durationLabel { - margin-left: -22px; /* 1/2 of scrubber thumb width, for overhang. */ - padding-left: 8px; /* don't bump into the scrubber bar */ - color: rgba(255,255,255,.75); - font: message-box; - font-size: 11px; +.positionDurationBox[positionOnly] { + min-width: 4ch; } %ifdef XP_MACOSX -.durationLabel { - padding-top: 2px; /* center vertically with scrubber bar */ -} -%else -.durationLabel { - padding-top: 0; /* center vertically with scrubber bar */ +.positionDurationBox { + font-size-adjust: unset; } %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; -} - -.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); - 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; -} - -.scrubber .scale-slider { - /* abs(margin-top) + margin-bottom + bar height == timeThumb height */ - margin-top: -10px; - margin-bottom: 10px; -} -/* .scale-thumb is an element inside the <scale> implementation. */ -.scrubber .scale-thumb, -.volumeControl .scale-thumb { - /* Override the default thumb appearance with a custom image. */ - -moz-appearance: none; - background: transparent; - border: none; -} - -.timeThumb { - background: url(chrome://global/skin/media/scrubberThumb.png) no-repeat center; - min-width: 45px; - min-height: 28px; - -moz-box-pack: center; -} - -.timeThumb[showhours="true"] { - background-image: url(chrome://global/skin/media/scrubberThumbWide.png); -} - -.timeLabel { - color: rgba(255,255,255,.75); - font: message-box; - font-size: 10px; - text-shadow: rgba(0,0,0,.3) 0 1px; - padding-top: 7px; -} - -%ifdef XP_MACOSX -.timeLabel { - padding-top: 7px; /* center vertically with scrubber bar */ -} -%else -.timeLabel { - padding-top: 5px; /* center vertically with scrubber bar */ -} -%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"] { background: url(chrome://global/skin/media/throbber.png) no-repeat center; } .statusIcon[type="throbber"][stalled] { background: url(chrome://global/skin/media/stalled.png) no-repeat center; } .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; -} -html|td { - height: 1em; - max-height: 1em; - padding: 0 2px; +.controlsSpacerStack:hover > .clickToPlay, +.clickToPlay:hover { + opacity: 0.55; } -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; + +.controlsSpacerStack:hover > .clickToPlay[fadeout] { + opacity: 0; +} + +.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; } .controlBar:not([immediate]) { transition-property: opacity; transition-duration: 200ms; } .controlBar[fadeout] { opacity: 0; } .volumeStack:not([immediate]) { 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; transition-delay: 750ms; } .statusOverlay[fadeout] { opacity: 0; } /* 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; +}
deleted file mode 100644 index 589abfbd5816bb3ec179a3fdf6530106356dba8e..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch literal 0 Hc$@<O00001
deleted file mode 100644 index ca494e89366563cbb509761eb1f8f3bcae60e2cd..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch literal 0 Hc$@<O00001