--- a/toolkit/content/widgets/videocontrols.xml
+++ b/toolkit/content/widgets/videocontrols.xml
@@ -215,16 +215,17 @@
<label class="errorLabel" anonid="errorNoSource">&error.noSource2;</label>
<label class="errorLabel" anonid="errorGeneric">&error.generic;</label>
</vbox>
<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"
playlabel="&playButton.playLabel;"
pauselabel="&playButton.pauseLabel;"/>
<stack class="scrubberStack" flex="1">
<box class="backgroundBar"/>
<progressmeter class="bufferBar"/>
@@ -238,16 +239,17 @@
<button 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"
enterfullscreenlabel="&fullscreenButton.enterfullscreenlabel;"
exitfullscreenlabel="&fullscreenButton.exitfullscreenlabel;"/>
</hbox>
</vbox>
</stack>
</xbl:content>
@@ -272,17 +274,19 @@
scrubber : null,
progressBar : null,
bufferBar : null,
statusOverlay : null,
controlsSpacer : null,
clickToPlay : null,
controlsOverlay : null,
fullscreenButton : null,
+ currentTextTrackIndex: 0,
+ textTracksCount: 0,
randomID : 0,
videoEvents : ["play", "pause", "ended", "volumechange", "loadeddata",
"loadstart", "timeupdate", "progress",
"playing", "waiting", "canplay", "canplaythrough",
"seeking", "seeked", "emptied", "loadedmetadata",
"error", "suspend", "stalled",
"mozinterruptbegin", "mozinterruptend" ],
@@ -407,16 +411,17 @@
}
// 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;
this.adjustControlSize();
// Can only update the volume controls once we've computed
// _volumeControlWidth, since the volume slider implementation
// depends on it.
@@ -902,16 +907,17 @@
if (!isMouseOver && !isMouseInControls) {
this.adjustControlSize();
// Keep the controls visible if the click-to-play is visible.
if (!this.clickToPlay.hidden)
return;
this.startFadeOut(this.controlBar, false);
+ this.textTrackList.setAttribute("hidden", "true");
clearTimeout(this._showControlsTimeout);
Utils._controlsHiddenByTimeout = false;
}
},
startFadeIn : function (element, immediate) {
this.startFade(element, true, immediate);
},
@@ -1211,16 +1217,192 @@
default:
return;
}
} catch(e) { /* ignore any exception from setting .currentTime */ }
event.preventDefault(); // Prevent page scrolling
},
+ get videoSubtitles() {
+ return Array.prototype.filter.call(this.video.textTracks, function (tt) {
+ return tt.kind === "subtitles";
+ });
+ },
+
+ isClosedCaptionOn : function () {
+ for (let tt of this.videoSubtitles) {
+ if (tt.mode === "showing") {
+ return true;
+ }
+ }
+
+ return false;
+ },
+
+ setClosedCaptionButtonState : function () {
+ if (!this.videoSubtitles.length || this.videocontrols.isTouchControl) {
+ this.closedCaptionButton.setAttribute("hidden", "true");
+ return;
+ }
+
+ this.closedCaptionButton.removeAttribute("hidden");
+
+ if (this.isClosedCaptionOn()) {
+ this.closedCaptionButton.setAttribute("enabled", "true");
+ } else {
+ this.closedCaptionButton.removeAttribute("enabled");
+ }
+
+ let ttItems = this.textTrackList.childNodes;
+
+ for (let tti of ttItems) {
+ const idx = +tti.getAttribute("index");
+
+ if (idx == this.currentTextTrackIndex) {
+ tti.setAttribute("on", "true");
+ } else {
+ tti.removeAttribute("on");
+ }
+ }
+ },
+
+ addNewTextTrack : function (tt) {
+ if (tt.kind !== "subtitles") {
+ return;
+ }
+
+ if (tt.index && tt.index < this.textTracksCount) {
+ return;
+ }
+
+ tt.index = this.textTracksCount++;
+
+ const label = tt.label || "";
+ const ttText = document.createTextNode(label);
+ const ttBtn = document.createElement("button");
+
+ ttBtn.classList.add("textTrackItem");
+ ttBtn.setAttribute("index", tt.index);
+
+ ttBtn.addEventListener("click", function (event) {
+ event.stopPropagation();
+
+ this.changeTextTrack(tt.index);
+ }.bind(this));
+
+ ttBtn.appendChild(ttText);
+
+ this.textTrackList.appendChild(ttBtn);
+
+ if (tt.mode === "showing" && tt.index) {
+ this.changeTextTrack(tt.index);
+ }
+ },
+
+ changeTextTrack : function (index) {
+ for (let tt of this.videoSubtitles) {
+ if (tt.index === index) {
+ tt.mode = "showing";
+
+ this.currentTextTrackIndex = tt.index;
+ } else {
+ tt.mode = "disabled";
+ }
+ }
+
+ // should fallback to off
+ if (this.currentTextTrackIndex !== index) {
+ this.currentTextTrackIndex = 0;
+ }
+
+ this.textTrackList.setAttribute("hidden", "true");
+ this.setClosedCaptionButtonState();
+ },
+
+ onControlBarTransitioned : function () {
+ this.textTrackList.setAttribute("hidden", "true");
+ },
+
+ toggleClosedCaption : function () {
+ if (this.videoSubtitles.length === 1) {
+ const lastTTIdx = this.videoSubtitles[0].index;
+
+ return this.changeTextTrack(this.isClosedCaptionOn() ? 0 : lastTTIdx);
+ }
+
+ 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) {
+ const toRemoveIndex = trackEvent.track.index;
+ const ttItems = this.textTrackList.childNodes;
+
+ if (!ttItems) {
+ return;
+ }
+
+ for (let tti of ttItems) {
+ const idx = +tti.getAttribute("index");
+
+ if (idx === toRemoveIndex) {
+ tti.remove();
+ this.textTracksCount--;
+ }
+
+ if (idx === this.currentTextTrackIndex) {
+ this.currentTextTrackIndex = 0;
+
+ this.video.dispatchEvent(new CustomEvent("texttrackchange"));
+ }
+ }
+
+ this.setClosedCaptionButtonState();
+ },
+
+ initTextTracks : function () {
+ const offLabel = this.textTrackList.getAttribute("offlabel");
+
+ this.addNewTextTrack({
+ label: offLabel,
+ kind: "subtitles"
+ });
+
+ for (let tt of this.videoSubtitles) {
+ this.addNewTextTrack(tt);
+ }
+
+ this.setClosedCaptionButtonState();
+ },
+
isEventWithin : function (event, parent1, parent2) {
function isDescendant (node) {
while (node) {
if (node == parent1 || node == parent2)
return true;
node = node.parentNode;
}
return false;
@@ -1238,32 +1420,34 @@
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,
_volumeStackMarginEnd : 8,
adjustControlSize : function adjustControlSize() {
let doc = this.video.ownerDocument;
// 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 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._volumeStackMarginEnd;
}
@@ -1331,54 +1515,61 @@
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.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
// for all events in order to simplify the event listener add/remove.
for (let event of this.videoEvents) {
this.video.addEventListener(event, this, {
capture: true,
mozSystemGroup: true
});
}
var self = this;
-
this.controlListeners = [];
// 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.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.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)
});
this.log("--- videocontrols initialized ---");
}
};
@@ -1427,16 +1618,17 @@
<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"/>
<box flex="1" hidden="true">
<box class="clickToPlay" hidden="true" flex="1"/>
+ <vbox class="textTrackList" hidden="true" offlabel="&closedCaption.off;"></vbox>
</box>
<vbox class="controlBar" hidden="true">
<hbox class="buttonsBar">
<button class="playButton"
playlabel="&playButton.playLabel;"
pauselabel="&playButton.pauseLabel;"/>
<label class="positionLabel" role="presentation"/>
<stack class="scrubberStack">
@@ -1452,16 +1644,17 @@
unmutelabel="&muteButton.unmuteLabel;"/>
<stack class="volumeStack">
<box class="volumeBackground"/>
<box class="volumeForeground" anonid="volumeForeground"/>
<scale class="volumeControl" movetoclick="true"/>
</stack>
<button class="castingButton" hidden="true"
aria-label="&castingButton.castingLabel;"/>
+ <button class="closedCaptionButton" hidden="true"/>
<button class="fullscreenButton"
enterfullscreenlabel="&fullscreenButton.enterfullscreenlabel;"
exitfullscreenlabel="&fullscreenButton.exitfullscreenlabel;"/>
</hbox>
</vbox>
</vbox>
</stack>
</xbl:content>
--- a/toolkit/locales/en-US/chrome/global/videocontrols.dtd
+++ b/toolkit/locales/en-US/chrome/global/videocontrols.dtd
@@ -4,16 +4,17 @@
<!ENTITY playButton.playLabel "Play">
<!ENTITY playButton.pauseLabel "Pause">
<!ENTITY muteButton.muteLabel "Mute">
<!ENTITY muteButton.unmuteLabel "Unmute">
<!ENTITY fullscreenButton.enterfullscreenlabel "Full Screen">
<!ENTITY fullscreenButton.exitfullscreenlabel "Exit Full Screen">
<!ENTITY castingButton.castingLabel "Cast to Screen">
+<!ENTITY closedCaption.off "Off">
<!ENTITY stats.media "Media">
<!ENTITY stats.size "Size">
<!ENTITY stats.activity "Activity">
<!ENTITY stats.activityPaused "Paused">
<!ENTITY stats.activityPlaying "Playing">
<!ENTITY stats.activityEnded "Ended">
<!ENTITY stats.activitySeeking "(seeking)">
--- a/toolkit/themes/osx/global/jar.mn
+++ b/toolkit/themes/osx/global/jar.mn
@@ -142,16 +142,18 @@ toolkit.jar:
skin/classic/global/media/playButton.png (media/playButton.png)
skin/classic/global/media/playButton@2x.png (media/playButton@2x.png)
skin/classic/global/media/muteButton.png (media/muteButton.png)
skin/classic/global/media/muteButton@2x.png (media/muteButton@2x.png)
skin/classic/global/media/unmuteButton.png (media/unmuteButton.png)
skin/classic/global/media/unmuteButton@2x.png (media/unmuteButton@2x.png)
skin/classic/global/media/noAudio.png (media/noAudio.png)
skin/classic/global/media/noAudio@2x.png (media/noAudio@2x.png)
+ skin/classic/global/media/closeCaptionButton.png (media/closeCaptionButton.png)
+ skin/classic/global/media/closeCaptionButton@2x.png (media/closeCaptionButton@2x.png)
skin/classic/global/media/fullscreenButton.png (media/fullscreenButton.png)
skin/classic/global/media/fullscreenButton@2x.png (media/fullscreenButton@2x.png)
skin/classic/global/media/scrubberThumb.png (media/scrubberThumb.png)
skin/classic/global/media/scrubberThumb@2x.png (media/scrubberThumb@2x.png)
skin/classic/global/media/scrubberThumbWide.png (media/scrubberThumbWide.png)
skin/classic/global/media/scrubberThumbWide@2x.png (media/scrubberThumbWide@2x.png)
skin/classic/global/media/error.png (media/error.png)
skin/classic/global/media/throbber.png (media/throbber.png)
new file mode 100644
index 0000000000000000000000000000000000000000..469310fb1b21ed705925decd18710dd0df37d915
GIT binary patch
literal 583
zc$@)80=WH&P)<h;3K|Lk000e1NJLTq000~S000~a1ONa4*aR0J0006GNkl<ZcmeH_
zKWGzS7{;HWWDq2_UZH9T=^)YuOG`9SDy8)=Hh<duyKu?feMb@vv1wYdT)?42a1mWy
zTy=DE5phU6NWoM~#X=Mp!6_6AHa%!kdA$qS@=;fZKELI?=jF!@-;1OCpRw&0>G9$0
z7GXnI1j>_Uv8{b)8|;(1qO2(E=JZXgTfIdd0=nWPM(pX`zAR)U5JLpBCJ}Q=AZ5=!
z$ys|i(G?e|4R$<a_f*rZ^4{{h2pl-`I<U9gDu2$Mx^OJ`n~@3^PgFKljC>4Jv7t6K
zdhlxO<$2N%v>ir;FA_%987X{GUen<IHP=)e*=re+-)n0c$;piU&W^I3huiw%i^&Re
z_=weHO!QpopFVkgGeb#l0KQ)Tz$DxiMoGRXt*WQTN&2c_(9xG0zU=*=k#y6CUisX;
zA-GmmlK7%nRdMNu*i`&Ol~H=Q!Cs_De10oF&?*`87_6!!^2KN^1y5O|*nX*bpQ2Lm
zMx3I5ibl!Q18{GpD9RVZ2h#9Z&-kN6J@zv;C&Gt|lDHMG$DbumOq?AxBntDz5Y5!m
zx>uNLKfe$C5a7Wq;`Xca-ddVwD8v{2CK4@>-qMYw#-dR$3XKJ0X<sLu7D=-9Jkj|k
zM7KLkQ^5Lvn}8{F`nN&e$qAT*46O}=3I%c-6|B?BnBpC|%`Ba89fA`AZ1{JM@)uMS
V3)yh#?6?2`002ovPDHLkV1fX94?q9_
new file mode 100644
index 0000000000000000000000000000000000000000..03350789221b94d830ebc4dafb1b6e4447f79f71
GIT binary patch
literal 1335
zc$@(@1<3k|P)<h;3K|Lk000e1NJLTq001}u001}$1ONa40*~{R000F3Nkl<ZcmeIz
zTWB0_9metR%saE^O`2?zHqEK6w8_6`C6U&)Y6Yu^rCM90h)`OKih5BH!Mj4mB7$NM
zH-##Q7fPj4L9`x_YS9wf(r6FqHmA+TY?E}eNoIFvX6Nt<n*=Gry1Th_KR?)oxq0}#
z&pW%+)z#J2)%{Njt08+hMVz%UxW!9WQRM1J!uz%wW6k`$xQtiHhB0}83@&S<(Wd;6
z{OZT6#ovx|lwpw)Gr~~vYE}hHu@%aMj7ezl<1#K=y>4%t8<MPW$q=tBFo46dpND_2
zZZJ^t@$iuN_)z{{qLfFVmPgZ+oz6EF&lOnW5P(Vo6(nWXqhF7)ND+$?4(?mA0LpTd
zKtm_!1_vWwidph&h5ufd$~$~t<rM?m-#swoS-tY0w|{ZVU*>tj;L6;7o$K}v$b<II
zQSI}Oxz7N}@2Xyvuf=A07$B+k%<+`z2U`DGwUrgP_qa=$?9)Gk`kz}l_mh?dTG=(w
z((eK&e`UOi4WB@Y4CdaG>Uw4wVTdGY^4dp?-3A7W9r|%>CP^~H2-9k4-RX-ZGNcAs
zQCWu|0Supc?6IEEX2!5RejDoc%1MdP$0E;>i=V_GgPahLf=8`rmIbZr?E5c1Bv*8i
zlvUNC?PH^aKFAa{d|~~u4f{6zIt*mP;j0^dx<1}U200@3w4Z1_&<40nian^<whPq-
zN+eQxxP;;f4CHI|md%)-z7{|tncdX2sfQVS<dyJ3hLL~H|2}}k4u=TgN(Wh<>W&m2
z|KsbT77_*&Kgk&3zrVMm!w-h1rTwE$41nPRPs!1Kepk3fwKk3up%n0u)pc0rxX3LH
z6an%+DJBTz11~fhFp#AnK7cpJ1oPMvQ96(>@_;OOHC-B2!a|S|KvbcCi%E(+AuK#o
zA^{RbOg!d!&Lk=Z1%y`hh8{pnMS0}n0W|4&fPdHS4;NKEa-%roA_2N29$-xgp*u>X
zu{lkoLEzPJqyiXr(@Lj=_p}(0r+;hHi6-FCAAeOs2k37AKxsWH+QBz?Mp<=%K0ruC
z;{HiF<3Wr3O)oRobghpCfUCtJ%M$`P(s?<8edK+ji3Lbc6M?XbUqgq@I#BurXCz>L
z_@jRBp@<3-@KCueFm5-UvZ0A@otJNvHd2`IJ%<QpLc^;eFd<Mde>Z=t`IJS8oVo!R
zN5VHFSeW10`e{2X$*PUCQ=|xg3;fu|M`_k^YY5z?At*Bam5v5JVKPY;7YDwaxHn4{
z{~y`UcK&iEW|Jg{iF~P_j@zS{1hxk$*3e<xx!Hd1DX-_Ij`e)XK9lRS;1AL3iAQ<T
zEZ{S7H_^N0Z0@+xX{N=`8gDijBV;hIbhWrObx84ZAL<+4J4ez{?{wYiLI-TJydsT-
zWRmc|{7WsDHX`sSkRnO;&-&iOyg}BmA%3I2>%4sYYWBwX&0H=)6p6tUljQJ#MUoh_
z(}Yeb^yXyl0((B7?o&1FYX5+DvLwV-1Z8f?a~xNebW8Vz!~%3gNp%7;D0Drb=_mmB
zjIA`NJY&4Fz#Xj6XeL5{01EFWaVSw_4u@sRbH*z=(v;Hev&3PVB?5t39smJI{N+y%
zk5#{)DYeoL<rm{O3cU_*b8)G{GySVkWMv(;v7haPP^g{6BFO_Xm27A*0>n|NozEhp
t7*I)|$tbe~*0^B_1C##;b#--h{|0<^JW)j^8BzcM002ovPDHLkV1f*Ie}e!3
--- a/toolkit/themes/osx/global/media/videocontrols.css
+++ b/toolkit/themes/osx/global/media/videocontrols.css
@@ -7,37 +7,40 @@
.controlBar {
height: 28px;
background-color: rgba(35,31,32,.74);
}
.playButton,
.muteButton,
+.closedCaptionButton,
.fullscreenButton {
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;
}
.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. */
@@ -58,16 +61,28 @@
.muteButton[noAudio] {
background-image: url(chrome://global/skin/media/noAudio.png);
}
.muteButton[noAudio] + .volumeStack {
display: none;
}
+.closedCaptionButton {
+ background-image: url(chrome://global/skin/media/closeCaptionButton.png);
+}
+
+.closedCaptionButton[enabled] {
+ opacity: 1;
+}
+
+.closedCaptionButton[hidden] {
+ display: none;
+}
+
.fullscreenButton {
background-image: -moz-image-rect(url("chrome://global/skin/media/fullscreenButton.png"), 0, 16, 16, 0);
}
.fullscreenButton[fullscreened] {
background-image: -moz-image-rect(url("chrome://global/skin/media/fullscreenButton.png"), 0, 32, 16, 16);
}
@@ -87,16 +102,51 @@
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;
+ border: none;
+ color: rgba(255,255,255,.5);
+ background-color: rgba(35,31,32,.74);
+ white-space: nowrap;
+}
+
+.textTrackList > html|*.textTrackItem[on] {
+ color: white;
+ background-color: black;
+}
+
+.textTrackList > html|*.textTrackItem:hover {
+ background-color: rgba(0,0,0,.55);
+}
+
.controlBar[fullscreen-unavailable] > .volumeStack {
/* This value is duplicated in the videocontrols.xml adjustControlSize function. */
margin-inline-end: 8px;
}
.volumeControl .scale-thumb {
min-width: 0;
opacity: 0;
@@ -335,16 +385,20 @@ html|table {
.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;
}
+ .closeCaptionButton {
+ background-image: url(chrome://global/skin/media/closeCaptionButton@2x.png);
+ 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;
}
--- a/toolkit/themes/shared/non-mac.jar.inc.mn
+++ b/toolkit/themes/shared/non-mac.jar.inc.mn
@@ -96,16 +96,18 @@
skin/classic/global/media/imagedoc-lightnoise.png (../../windows/global/media/imagedoc-lightnoise.png)
skin/classic/global/media/imagedoc-darknoise.png (../../windows/global/media/imagedoc-darknoise.png)
skin/classic/global/media/videocontrols.css (../../windows/global/media/videocontrols.css)
skin/classic/global/media/pauseButton.png (../../windows/global/media/pauseButton.png)
skin/classic/global/media/playButton.png (../../windows/global/media/playButton.png)
skin/classic/global/media/muteButton.png (../../windows/global/media/muteButton.png)
skin/classic/global/media/unmuteButton.png (../../windows/global/media/unmuteButton.png)
skin/classic/global/media/noAudio.png (../../windows/global/media/noAudio.png)
+ skin/classic/global/media/closeCaptionButton.png (../../windows/global/media/closeCaptionButton.png)
+ skin/classic/global/media/closeCaptionButton@2x.png (../../windows/global/media/closeCaptionButton@2x.png)
skin/classic/global/media/fullscreenButton.png (../../windows/global/media/fullscreenButton.png)
skin/classic/global/media/scrubberThumb.png (../../windows/global/media/scrubberThumb.png)
skin/classic/global/media/scrubberThumbWide.png (../../windows/global/media/scrubberThumbWide.png)
skin/classic/global/media/throbber.png (../../windows/global/media/throbber.png)
skin/classic/global/media/stalled.png (../../windows/global/media/stalled.png)
skin/classic/global/media/volume-empty.png (../../windows/global/media/volume-empty.png)
skin/classic/global/media/volume-full.png (../../windows/global/media/volume-full.png)
skin/classic/global/media/error.png (../../windows/global/media/error.png)
new file mode 100644
index 0000000000000000000000000000000000000000..469310fb1b21ed705925decd18710dd0df37d915
GIT binary patch
literal 583
zc$@)80=WH&P)<h;3K|Lk000e1NJLTq000~S000~a1ONa4*aR0J0006GNkl<ZcmeH_
zKWGzS7{;HWWDq2_UZH9T=^)YuOG`9SDy8)=Hh<duyKu?feMb@vv1wYdT)?42a1mWy
zTy=DE5phU6NWoM~#X=Mp!6_6AHa%!kdA$qS@=;fZKELI?=jF!@-;1OCpRw&0>G9$0
z7GXnI1j>_Uv8{b)8|;(1qO2(E=JZXgTfIdd0=nWPM(pX`zAR)U5JLpBCJ}Q=AZ5=!
z$ys|i(G?e|4R$<a_f*rZ^4{{h2pl-`I<U9gDu2$Mx^OJ`n~@3^PgFKljC>4Jv7t6K
zdhlxO<$2N%v>ir;FA_%987X{GUen<IHP=)e*=re+-)n0c$;piU&W^I3huiw%i^&Re
z_=weHO!QpopFVkgGeb#l0KQ)Tz$DxiMoGRXt*WQTN&2c_(9xG0zU=*=k#y6CUisX;
zA-GmmlK7%nRdMNu*i`&Ol~H=Q!Cs_De10oF&?*`87_6!!^2KN^1y5O|*nX*bpQ2Lm
zMx3I5ibl!Q18{GpD9RVZ2h#9Z&-kN6J@zv;C&Gt|lDHMG$DbumOq?AxBntDz5Y5!m
zx>uNLKfe$C5a7Wq;`Xca-ddVwD8v{2CK4@>-qMYw#-dR$3XKJ0X<sLu7D=-9Jkj|k
zM7KLkQ^5Lvn}8{F`nN&e$qAT*46O}=3I%c-6|B?BnBpC|%`Ba89fA`AZ1{JM@)uMS
V3)yh#?6?2`002ovPDHLkV1fX94?q9_
new file mode 100644
index 0000000000000000000000000000000000000000..03350789221b94d830ebc4dafb1b6e4447f79f71
GIT binary patch
literal 1335
zc$@(@1<3k|P)<h;3K|Lk000e1NJLTq001}u001}$1ONa40*~{R000F3Nkl<ZcmeIz
zTWB0_9metR%saE^O`2?zHqEK6w8_6`C6U&)Y6Yu^rCM90h)`OKih5BH!Mj4mB7$NM
zH-##Q7fPj4L9`x_YS9wf(r6FqHmA+TY?E}eNoIFvX6Nt<n*=Gry1Th_KR?)oxq0}#
z&pW%+)z#J2)%{Njt08+hMVz%UxW!9WQRM1J!uz%wW6k`$xQtiHhB0}83@&S<(Wd;6
z{OZT6#ovx|lwpw)Gr~~vYE}hHu@%aMj7ezl<1#K=y>4%t8<MPW$q=tBFo46dpND_2
zZZJ^t@$iuN_)z{{qLfFVmPgZ+oz6EF&lOnW5P(Vo6(nWXqhF7)ND+$?4(?mA0LpTd
zKtm_!1_vWwidph&h5ufd$~$~t<rM?m-#swoS-tY0w|{ZVU*>tj;L6;7o$K}v$b<II
zQSI}Oxz7N}@2Xyvuf=A07$B+k%<+`z2U`DGwUrgP_qa=$?9)Gk`kz}l_mh?dTG=(w
z((eK&e`UOi4WB@Y4CdaG>Uw4wVTdGY^4dp?-3A7W9r|%>CP^~H2-9k4-RX-ZGNcAs
zQCWu|0Supc?6IEEX2!5RejDoc%1MdP$0E;>i=V_GgPahLf=8`rmIbZr?E5c1Bv*8i
zlvUNC?PH^aKFAa{d|~~u4f{6zIt*mP;j0^dx<1}U200@3w4Z1_&<40nian^<whPq-
zN+eQxxP;;f4CHI|md%)-z7{|tncdX2sfQVS<dyJ3hLL~H|2}}k4u=TgN(Wh<>W&m2
z|KsbT77_*&Kgk&3zrVMm!w-h1rTwE$41nPRPs!1Kepk3fwKk3up%n0u)pc0rxX3LH
z6an%+DJBTz11~fhFp#AnK7cpJ1oPMvQ96(>@_;OOHC-B2!a|S|KvbcCi%E(+AuK#o
zA^{RbOg!d!&Lk=Z1%y`hh8{pnMS0}n0W|4&fPdHS4;NKEa-%roA_2N29$-xgp*u>X
zu{lkoLEzPJqyiXr(@Lj=_p}(0r+;hHi6-FCAAeOs2k37AKxsWH+QBz?Mp<=%K0ruC
z;{HiF<3Wr3O)oRobghpCfUCtJ%M$`P(s?<8edK+ji3Lbc6M?XbUqgq@I#BurXCz>L
z_@jRBp@<3-@KCueFm5-UvZ0A@otJNvHd2`IJ%<QpLc^;eFd<Mde>Z=t`IJS8oVo!R
zN5VHFSeW10`e{2X$*PUCQ=|xg3;fu|M`_k^YY5z?At*Bam5v5JVKPY;7YDwaxHn4{
z{~y`UcK&iEW|Jg{iF~P_j@zS{1hxk$*3e<xx!Hd1DX-_Ij`e)XK9lRS;1AL3iAQ<T
zEZ{S7H_^N0Z0@+xX{N=`8gDijBV;hIbhWrObx84ZAL<+4J4ez{?{wYiLI-TJydsT-
zWRmc|{7WsDHX`sSkRnO;&-&iOyg}BmA%3I2>%4sYYWBwX&0H=)6p6tUljQJ#MUoh_
z(}Yeb^yXyl0((B7?o&1FYX5+DvLwV-1Z8f?a~xNebW8Vz!~%3gNp%7;D0Drb=_mmB
zjIA`NJY&4Fz#Xj6XeL5{01EFWaVSw_4u@sRbH*z=(v;Hev&3PVB?5t39smJI{N+y%
zk5#{)DYeoL<rm{O3cU_*b8)G{GySVkWMv(;v7haPP^g{6BFO_Xm27A*0>n|NozEhp
t7*I)|$tbe~*0^B_1C##;b#--h{|0<^JW)j^8BzcM002ovPDHLkV1f*Ie}e!3
--- a/toolkit/themes/windows/global/media/videocontrols.css
+++ b/toolkit/themes/windows/global/media/videocontrols.css
@@ -7,37 +7,40 @@
.controlBar {
height: 28px;
background-color: rgba(35,31,32,.74);
}
.playButton,
.muteButton,
+.closedCaptionButton,
.fullscreenButton {
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;
}
.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. */
@@ -58,16 +61,28 @@
.muteButton[noAudio] {
background-image: url(chrome://global/skin/media/noAudio.png);
}
.muteButton[noAudio] + .volumeStack {
display: none;
}
+.closedCaptionButton {
+ background-image: url(chrome://global/skin/media/closeCaptionButton.png);
+}
+
+.closedCaptionButton[enabled] {
+ opacity: 1;
+}
+
+.closedCaptionButton[hidden] {
+ display: none;
+}
+
.fullscreenButton {
background-image: -moz-image-rect(url("chrome://global/skin/media/fullscreenButton.png"), 0, 16, 16, 0);
}
.fullscreenButton[fullscreened] {
background-image: -moz-image-rect(url("chrome://global/skin/media/fullscreenButton.png"), 0, 32, 16, 16);
}
@@ -87,16 +102,51 @@
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;
+ border: none;
+ color: rgba(255,255,255,.5);
+ background-color: rgba(35,31,32,.74);
+ white-space: nowrap;
+}
+
+.textTrackList > html|*.textTrackItem[on] {
+ color: white;
+ background-color: black;
+}
+
+.textTrackList > html|*.textTrackItem:hover {
+ background-color: rgba(0,0,0,.55);
+}
+
.controlBar[fullscreen-unavailable] > .volumeStack {
/* This value is duplicated in the videocontrols.xml adjustControlSize function. */
margin-inline-end: 8px;
}
.volumeControl .scale-thumb {
min-width: 0;
opacity: 0;