Bug 1444489 - Part VI, Enlarge the size of controls on mobile
Enlarge controls by around 1.3x, which is the size of the original touch controls.
MozReview-Commit-ID: kpgFFIW2hh
--- a/browser/base/content/test/static/browser_parsable_css.js
+++ b/browser/base/content/test/static/browser_parsable_css.js
@@ -111,16 +111,18 @@ let propNameWhitelist = [
// Bug 1442300
{propName: "--in-content-category-background",
isFromDevTools: false},
// These custom properties are retrieved directly from CSSOM
// in videocontrols.xml to get pre-defined style instead of computed
// dimensions, which is why they are not referenced by CSS.
{propName: "--clickToPlay-width",
isFromDevTools: false},
+ {propName: "--playButton-width",
+ isFromDevTools: false},
{propName: "--muteButton-width",
isFromDevTools: false},
{propName: "--castingButton-width",
isFromDevTools: false},
{propName: "--closedCaptionButton-width",
isFromDevTools: false},
{propName: "--fullscreenButton-width",
isFromDevTools: false},
--- a/toolkit/content/tests/widgets/test_videocontrols_size.html
+++ b/toolkit/content/tests/widgets/test_videocontrols_size.html
@@ -28,21 +28,23 @@
<pre id="test">
<script clas="testbody" type="application/javascript">
SimpleTest.waitForExplicitFinish();
const videoElems = [...document.getElementsByTagName("video")];
const testCases = [];
- const buttonWidth = 30;
- const minSrubberWidth = 48;
- const minControlBarHeight = 40;
- const minControlBarWidth = 48;
- const minClickToPlaySize = 48;
+ const isTouchControl = navigator.appVersion.includes("Android");
+
+ const buttonWidth = isTouchControl ? 40 : 30;
+ const minSrubberWidth = isTouchControl ? 64 : 48;
+ const minControlBarHeight = isTouchControl ? 52 : 40;
+ const minControlBarWidth = isTouchControl ? 58 : 48;
+ const minClickToPlaySize = isTouchControl ? 64 : 48;
function getElementName(elem) {
return elem.getAttribute("anonid") || elem.getAttribute("class");
}
function testButton(btn) {
if (btn.hidden) return;
--- a/toolkit/content/widgets/videocontrols.xml
+++ b/toolkit/content/widgets/videocontrols.xml
@@ -34,17 +34,17 @@
<div anonid="controlsOverlay" class="controlsOverlay stackItem">
<div class="controlsSpacerStack">
<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"
+ class="button playButton"
playlabel="&playButton.playLabel;"
pauselabel="&playButton.pauseLabel;"
tabindex="-1"/>
<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" tabindex="-1"></progress>
<progress anonid="progressBar" class="progressBar" value="0" max="100" tabindex="-1"></progress>
@@ -54,28 +54,28 @@
</div>
<span anonid="positionLabel" class="positionLabel" role="presentation"></span>
<span anonid="durationLabel" class="durationLabel" role="presentation"></span>
<span anonid="positionDurationBox" class="positionDurationBox" aria-hidden="true">
&positionAndDuration.nameFormat;
</span>
<div anonid="controlBarSpacer" class="controlBarSpacer" hidden="true" role="none"></div>
<button anonid="muteButton"
- class="muteButton"
+ class="button muteButton"
mutelabel="&muteButton.muteLabel;"
unmutelabel="&muteButton.unmuteLabel;"
tabindex="-1"/>
<div anonid="volumeStack" class="volumeStack progressContainer" role="none">
<input type="range" anonid="volumeControl" class="volumeControl" min="0" max="100" step="1" tabindex="-1"/>
</div>
- <button anonid="castingButton" class="castingButton"
+ <button anonid="castingButton" class="button castingButton"
aria-label="&castingButton.castingLabel;"/>
- <button anonid="closedCaptionButton" class="closedCaptionButton"/>
+ <button anonid="closedCaptionButton" class="button closedCaptionButton"/>
<button anonid="fullscreenButton"
- class="fullscreenButton"
+ class="button fullscreenButton"
enterfullscreenlabel="&fullscreenButton.enterfullscreenlabel;"
exitfullscreenlabel="&fullscreenButton.exitfullscreenlabel;"/>
</div>
<div anonid="textTrackList" class="textTrackList" hidden="true" offlabel="&closedCaption.off;"></div>
</div>
</div>
</xbl:content>
@@ -1698,33 +1698,37 @@
this.castingButton = document.getAnonymousElementByAttribute(binding, "anonid", "castingButton");
this.closedCaptionButton = document.getAnonymousElementByAttribute(binding, "anonid", "closedCaptionButton");
this.textTrackList = document.getAnonymousElementByAttribute(binding, "anonid", "textTrackList");
if (this.positionDurationBox) {
this.durationSpan = this.positionDurationBox.getElementsByTagName("span")[0];
}
+ this.videocontrols.isTouchControls =
+ navigator.appVersion.includes("Android");
+ if (this.videocontrols.isTouchControls) {
+ this.controlsContainer.classList.add("touch");
+ }
+
this.controlBarComputedStyles = getComputedStyle(this.controlBar);
// Hide and show control in certain order.
this.prioritizedControls = [
this.playButton,
this.muteButton,
this.fullscreenButton,
this.castingButton,
this.closedCaptionButton,
this.positionDurationBox,
this.scrubberStack,
this.durationSpan,
this.volumeStack
];
- this.videocontrols.isTouchControls =
- navigator.appVersion.includes("Android");
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
@@ -2020,62 +2024,69 @@
hasError() {
return (this.video.error != null || this.video.networkState == this.video.NETWORK_NO_SOURCE);
},
handleEvent(aEvent) {
// If the binding is detached (or has been replaced by a
// newer instance of the binding), nuke our event-listeners.
- if (this.binding.randomID != this.randomID) {
+ if (this.videocontrols.randomID != this.randomID) {
this.terminateEventListeners();
return;
}
switch (aEvent.type) {
case "play":
this.noControlsOverlay.hidden = true;
break;
case "playing":
this.noControlsOverlay.hidden = true;
break;
}
},
blockedVideoHandler() {
- if (this.binding.randomID != this.randomID) {
+ if (this.videocontrols.randomID != this.randomID) {
this.terminateEventListeners();
return;
} else if (this.hasError()) {
this.noControlsOverlay.hidden = true;
return;
}
this.noControlsOverlay.hidden = false;
},
clickToPlayClickHandler(e) {
- if (this.binding.randomID != this.randomID) {
+ if (this.videocontrols.randomID != this.randomID) {
this.terminateEventListeners();
return;
} else if (e.button != 0) {
return;
}
this.noControlsOverlay.hidden = true;
this.video.play();
},
init(binding) {
- this.binding = binding;
+ this.videocontrols = binding;
this.randomID = Math.random();
- this.binding.randomID = this.randomID;
+ this.videocontrols.randomID = this.randomID;
this.video = binding.parentNode;
+ this.controlsContainer = document.getAnonymousElementByAttribute(binding, "anonid", "controlsContainer");
this.clickToPlay = document.getAnonymousElementByAttribute(binding, "anonid", "clickToPlay");
this.noControlsOverlay = document.getAnonymousElementByAttribute(binding, "anonid", "controlsContainer");
+ this.videocontrols.isTouchControls =
+ navigator.appVersion.includes("Android");
+ if (this.videocontrols.isTouchControls) {
+ this.controlsContainer.classList.add("touch");
+ }
+
let self = this;
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.clickToPlay, "click", this.clickToPlayClickHandler);
addListener(this.video, "MozNoControlsBlockedVideo", this.blockedVideoHandler);
--- a/toolkit/themes/shared/media/videocontrols.css
+++ b/toolkit/themes/shared/media/videocontrols.css
@@ -18,35 +18,56 @@ audio > xul|videocontrols {
text-align: left;
list-style-image: none !important;
font: normal normal normal 100%/normal sans-serif !important;
text-decoration: none !important;
}
.controlsContainer {
--clickToPlay-size: 48px;
+ --button-size: 30px;
+ --timer-size: 40px;
+ --timer-long-size: 60px;
+ --track-size: 5px;
+ --thumb-size: 13px;
+ --label-font-size: 13px;
+}
+.controlsContainer.touch {
+ --clickToPlay-size: 64px;
+ --button-size: 40px;
+ --timer-size: 52px;
+ --timer-long-size: 78px;
+ --track-size: 7px;
+ --thumb-size: 16px;
+ --label-font-size: 16px;
}
/* Some CSS custom properties defined here are referenced by videocontrols.xml in JavaScript */
.controlBar {
/* Do not delete: these variables are accessed by JavaScript directly.
see videocontrols.xml and search for |-width|. */
--clickToPlay-width: var(--clickToPlay-size);
- --playButton-width: 30px;
- --playButton-height: var(--playButton-width);
+ --playButton-width: var(--button-size);
--scrubberStack-width: 64px;
- --muteButton-width: 30px;
+ --muteButton-width: var(--button-size);
--volumeStack-width: 48px;
- --castingButton-width: 30px;
- --closedCaptionButton-width: 30px;
- --fullscreenButton-width: 30px;
- --positionDurationBox-width: 40px;
- --durationSpan-width: 40px;
- --positionDurationBox-width-long: 60px;
- --durationSpan-width-long: 60px;
+ --castingButton-width: var(--button-size);
+ --closedCaptionButton-width: var(--button-size);
+ --fullscreenButton-width: var(--button-size);
+ --positionDurationBox-width: var(--timer-size);
+ --durationSpan-width: var(--timer-size);
+ --positionDurationBox-width-long: var(--timer-long-size);
+ --durationSpan-width-long: var(--timer-long-size);
+}
+
+.touch .controlBar {
+ /* Do not delete: these variables are accessed by JavaScript directly.
+ see videocontrols.xml and search for |-width|. */
+ --scrubberStack-width: 84px;
+ --volumeStack-width: 64px;
}
.controlsContainer [hidden="true"],
.controlBar[hidden] {
display: none;
}
.controlBar[size="hidden"] {
@@ -101,49 +122,45 @@ audio > xul|videocontrols {
justify-content: center;
align-items: center;
overflow: hidden;
height: 40px;
padding: 0 9px;
background-color: rgba(26,26,26,.8);
}
-.playButton,
-.muteButton,
-.castingButton,
-.closedCaptionButton,
-.fullscreenButton {
+.touch .controlBar {
+ height: 52px;
+}
+
+.controlBar > .button {
height: 100%;
- min-width: var(--playButton-width);
- min-height: var(--playButton-height);
+ min-width: var(--button-size);
+ min-height: var(--button-size);
padding: 6px;
border: 0;
margin: 0;
background-color: transparent;
background-repeat: no-repeat;
background-position: center;
background-origin: content-box;
background-clip: content-box;
-moz-context-properties: fill;
fill: #ffffff;
}
-.playButton:hover,
-.muteButton:hover,
-.castingButton:hover,
-.closedCaptionButton:hover,
-.fullscreenButton:hover {
+.touch .controlBar > .button {
+ background-size: 24px 24px;
+}
+
+.controlBar > .button:hover {
fill: #48a0f7;
}
-.playButton:hover:active,
-.muteButton:hover:active,
-.castingButton:hover:active,
-.closedCaptionButton:hover:active,
-.fullscreenButton:hover:active {
+.controlBar > .button:hover:active {
fill: #2d89e6;
}
.playButton {
background-image: url(chrome://global/skin/media/pauseButton.svg);
}
.playButton[paused] {
background-image: url(chrome://global/skin/media/playButton.svg);
@@ -188,18 +205,18 @@ audio > xul|videocontrols {
}
.controlBarSpacer {
flex-grow: 1;
}
.volumeControl::-moz-range-thumb,
.scrubber::-moz-range-thumb {
- height: 13px;
- width: 13px;
+ height: var(--thumb-size);
+ width: var(--thumb-size);
border: none;
border-radius: 50%;
background-color: #ffffff;
filter: drop-shadow(0px 0px 2px rgba(0,0,0,0.65));
}
.volumeControl::-moz-focus-outer,
.scrubber::-moz-focus-outer {
@@ -211,17 +228,17 @@ audio > xul|videocontrols {
flex-direction: column;
justify-content: center;
align-items: center;
}
.progressStack {
position: relative;
width: 100%;
- height: 5px;
+ height: var(--track-size);
}
.scrubberStack {
/* minus margin to get basis of required width */
min-width: calc(var(--scrubberStack-width) - 18px);
flex-basis: calc(var(--scrubberStack-width) - 18px);
flex-grow: 2;
flex-shrink: 0;
@@ -244,17 +261,17 @@ audio > xul|videocontrols {
.volumeControl {
bottom: 0;
left: 0;
position: absolute;
width: 100%;
height: 100%;
padding: 0;
border: 0;
- border-radius: 2.5px;
+ border-radius: calc(var(--track-size) / 2);
margin: 0;
background: none;
background-color: transparent;
}
.bufferBar,
.volumeBackground {
background-color: rgba(0,0,0,0.7);
@@ -262,17 +279,17 @@ audio > xul|videocontrols {
.bufferBar::-moz-progress-bar,
.progressBar::-moz-progress-bar,
.volumeBackground::-moz-meter-bar {
height: 100%;
padding: 0;
margin: 0;
border: 0;
- border-radius: 2.5px;
+ border-radius: calc(var(--track-size) / 2);
background: none;
}
.scrubber:hover::-moz-range-thumb,
.volumeControl:hover::-moz-range-thumb {
background-color: #48a0f7;
}
@@ -283,56 +300,60 @@ audio > xul|videocontrols {
.scrubber::-moz-range-track,
.scrubber::-moz-range-progress {
background-color: transparent;
}
.volumeControl::-moz-range-progress,
.volumeControl::-moz-range-track {
- height: 5px;
- border-radius: 2.5px;
+ height: var(--track-size);
+ border-radius: calc(var(--track-size) / 2);
}
.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;
+ border-radius: calc(var(--track-size) / 2);
}
.progressBar::-moz-progress-bar {
background-color: #00b6f0;
}
.textTrackList {
position: absolute;
right: 5px;
bottom: 45px;
max-width: 80%;
border: 1px solid #000000;
border-radius: 2.5px;
padding: 5px 0;
vertical-align: middle;
- font-size: 12px;
background-color: #000000;
opacity: 0.7;
}
+.touch .textTrackList {
+ bottom: 58px;
+}
+
.textTrackList > .textTrackItem {
display: block;
width: 100%;
- height: 30px;
+ height: var(--button-size);
+ font-size: var(--label-font-size);
padding: 2px 10px;
border: none;
margin: 0;
white-space: nowrap;
overflow: hidden;
text-align: left;
text-overflow: ellipsis;
color: #ffffff;
@@ -353,17 +374,17 @@ audio > xul|videocontrols {
}
.positionDurationBox {
text-align: center;
padding-inline-start: 1px;
padding-inline-end: 9px;
white-space: nowrap;
font: message-box;
- font-size: 13px;
+ font-size: var(--label-font-size);
font-size-adjust: 0.55;
color: #ffffff;
}
%ifdef XP_MACOSX
.positionDurationBox {
font-size-adjust: unset;
font-family: "Helvetica Neue", "Helvetica", sans-serif;