зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1166961 - Show click to play button on Fennec when autoplay is blocked. r=mfinkle
--HG-- extra : rebase_source : c2e78e8c5720e14cdcab1be8f12c92b60055a996
This commit is contained in:
Родитель
4b7b981193
Коммит
b1c0d79c4e
|
@ -2223,6 +2223,13 @@ HTMLMediaElement::Play(ErrorResult& aRv)
|
|||
&& !EventStateManager::IsHandlingUserInput()
|
||||
&& !nsContentUtils::IsCallerChrome()) {
|
||||
LOG(LogLevel::Debug, ("%p Blocked attempt to autoplay media.", this));
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
nsContentUtils::DispatchTrustedEvent(OwnerDoc(),
|
||||
static_cast<nsIContent*>(this),
|
||||
NS_LITERAL_STRING("MozAutoplayMediaBlocked"),
|
||||
false,
|
||||
false);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -63,6 +63,8 @@ var CastingApps = {
|
|||
_castMenuId: -1,
|
||||
mirrorStartMenuId: -1,
|
||||
mirrorStopMenuId: -1,
|
||||
_blocked: null,
|
||||
_bound: null,
|
||||
|
||||
init: function ca_init() {
|
||||
if (!this.isCastingEnabled()) {
|
||||
|
@ -96,6 +98,9 @@ var CastingApps = {
|
|||
BrowserApp.deck.addEventListener("pageshow", this, true);
|
||||
BrowserApp.deck.addEventListener("playing", this, true);
|
||||
BrowserApp.deck.addEventListener("ended", this, true);
|
||||
BrowserApp.deck.addEventListener("MozAutoplayMediaBlocked", this, true);
|
||||
// Note that the XBL binding is untrusted
|
||||
BrowserApp.deck.addEventListener("MozNoControlsVideoBindingAttached", this, true, true);
|
||||
},
|
||||
|
||||
_mirrorStarted: function(stopMirrorCallback) {
|
||||
|
@ -223,6 +228,28 @@ var CastingApps = {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case "MozAutoplayMediaBlocked": {
|
||||
if (this._bound && this._bound.has(aEvent.target)) {
|
||||
aEvent.target.dispatchEvent(new CustomEvent("MozNoControlsBlockedVideo"));
|
||||
} else {
|
||||
if (!this._blocked) {
|
||||
this._blocked = new WeakMap;
|
||||
}
|
||||
this._blocked.set(aEvent.target, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "MozNoControlsVideoBindingAttached": {
|
||||
if (!this._bound) {
|
||||
this._bound = new WeakMap;
|
||||
}
|
||||
this._bound.set(aEvent.target, true);
|
||||
if (this._blocked && this._blocked.has(aEvent.target)) {
|
||||
this._blocked.delete(aEvent.target);
|
||||
aEvent.target.dispatchEvent(new CustomEvent("MozNoControlsBlockedVideo"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -304,6 +304,12 @@ select:disabled > button {
|
|||
-moz-binding: url("chrome://global/content/bindings/videocontrols.xml#touchControls");
|
||||
}
|
||||
|
||||
/* display click to play when autoplay is blocked for videos */
|
||||
video:not([controls]) > xul|videocontrols {
|
||||
visibility: visible;
|
||||
-moz-binding: url("chrome://global/content/bindings/videocontrols.xml#noControls");
|
||||
}
|
||||
|
||||
*:-moz-any-link:active,
|
||||
*[role=button]:active,
|
||||
button:not(:disabled):active,
|
||||
|
|
|
@ -220,3 +220,17 @@
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
|
|
@ -1805,4 +1805,128 @@
|
|||
</handlers>
|
||||
|
||||
</binding>
|
||||
|
||||
<binding id="noControls">
|
||||
|
||||
<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">
|
||||
<vbox flex="1" class="statusOverlay" hidden="true">
|
||||
<box flex="1">
|
||||
<box class="clickToPlay" flex="1"/>
|
||||
</box>
|
||||
</vbox>
|
||||
</xbl:content>
|
||||
|
||||
<implementation>
|
||||
<constructor>
|
||||
<![CDATA[
|
||||
this.randomID = 0;
|
||||
this.Utils = {
|
||||
randomID : 0,
|
||||
videoEvents : ["play",
|
||||
"playing"],
|
||||
controlListeners: [],
|
||||
terminateEventListeners : function () {
|
||||
for each (let event in this.videoEvents)
|
||||
this.video.removeEventListener(event, this, false);
|
||||
|
||||
for each(let element in this.controlListeners)
|
||||
element.item.removeEventListener(element.event, element.func, false);
|
||||
|
||||
delete this.controlListeners;
|
||||
},
|
||||
|
||||
hasError : function () {
|
||||
return (this.video.error != null || this.video.networkState == this.video.NETWORK_NO_SOURCE);
|
||||
},
|
||||
|
||||
handleEvent : function (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) {
|
||||
this.terminateEventListeners();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (aEvent.type) {
|
||||
case "play":
|
||||
this.noControlsOverlay.hidden = true;
|
||||
break;
|
||||
case "playing":
|
||||
this.noControlsOverlay.hidden = true;
|
||||
break;
|
||||
default:
|
||||
//this.log("!!! event " + aEvent.type + " not handled!");
|
||||
}
|
||||
},
|
||||
|
||||
blockedVideoHandler : function () {
|
||||
if (this.binding.randomID != this.randomID) {
|
||||
this.terminateEventListeners();
|
||||
return;
|
||||
} else if (this.hasError()) {
|
||||
this.noControlsOverlay.hidden = true;
|
||||
return;
|
||||
}
|
||||
this.noControlsOverlay.hidden = false;
|
||||
},
|
||||
|
||||
clickToPlayClickHandler : function (e) {
|
||||
if (this.binding.randomID != this.randomID) {
|
||||
this.terminateEventListeners();
|
||||
return;
|
||||
} else if (e.button != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.noControlsOverlay.hidden = true;
|
||||
this.video.play();
|
||||
},
|
||||
|
||||
init : function (binding) {
|
||||
this.binding = binding;
|
||||
this.randomID = Math.random();
|
||||
this.binding.randomID = this.randomID;
|
||||
this.video = binding.parentNode;
|
||||
this.clickToPlay = document.getAnonymousElementByAttribute(binding, "class", "clickToPlay");
|
||||
this.noControlsOverlay = document.getAnonymousElementByAttribute(binding, "class", "statusOverlay");
|
||||
|
||||
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, false);
|
||||
}
|
||||
addListener(this.clickToPlay, "click", this.clickToPlayClickHandler);
|
||||
addListener(this.video, "MozNoControlsBlockedVideo", this.blockedVideoHandler);
|
||||
|
||||
for each (let event in this.videoEvents) {
|
||||
this.video.addEventListener(event, this, false);
|
||||
}
|
||||
|
||||
if (this.video.autoplay && !this.video.mozAutoplayEnabled) {
|
||||
this.blockedVideoHandler();
|
||||
}
|
||||
}
|
||||
};
|
||||
this.Utils.init(this);
|
||||
this.Utils.video.dispatchEvent(new CustomEvent("MozNoControlsVideoBindingAttached"));
|
||||
]]>
|
||||
</constructor>
|
||||
<destructor>
|
||||
<![CDATA[
|
||||
// randomID used to be a <field>, which meant that the XBL machinery
|
||||
// undefined the property when the element was unbound. The code in
|
||||
// this file actually depends on this, so now that randomID is an
|
||||
// expando, we need to make sure to explicitly delete it.
|
||||
delete this.randomID;
|
||||
]]>
|
||||
</destructor>
|
||||
</implementation>
|
||||
</binding>
|
||||
|
||||
</bindings>
|
||||
|
|
Загрузка…
Ссылка в новой задаче