зеркало из https://github.com/mozilla/gecko-dev.git
Bug 590715 - Fullscreen video for Fennec [r=mfinkle]
This commit is contained in:
Родитель
8d931cd756
Коммит
70f5847a73
|
@ -21,6 +21,7 @@
|
|||
*
|
||||
* Contributor(s):
|
||||
* Mark Finkle <mfinkle@mozilla.com>
|
||||
* Matt Brubeck <mbrubeck@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -482,6 +483,7 @@ var BrowserUI = {
|
|||
DownloadsView.init();
|
||||
PreferencesView.init();
|
||||
ConsoleView.init();
|
||||
FullScreenVideo.init();
|
||||
|
||||
#ifdef MOZ_IPC
|
||||
// Pre-start the content process
|
||||
|
@ -2546,14 +2548,9 @@ var ContextCommands = {
|
|||
SharingUI.show(ContextHelper.popupState.mediaURL, null);
|
||||
},
|
||||
|
||||
playMedia: function cc_playVideo() {
|
||||
sendCommand: function cc_playVideo(aCommand) {
|
||||
let browser = ContextHelper.popupState.target;
|
||||
browser.messageManager.sendAsyncMessage("Browser:MediaCommand", { command: "play"});
|
||||
},
|
||||
|
||||
pauseMedia: function cc_playVideo() {
|
||||
let browser = ContextHelper.popupState.target;
|
||||
browser.messageManager.sendAsyncMessage("Browser:MediaCommand", { command: "pause" });
|
||||
browser.messageManager.sendAsyncMessage("Browser:ContextCommand", { command: aCommand });
|
||||
},
|
||||
|
||||
editBookmark: function cc_editBookmark() {
|
||||
|
@ -2718,3 +2715,69 @@ var BadgeHandlers = {
|
|||
return aValue;
|
||||
}
|
||||
};
|
||||
|
||||
var FullScreenVideo = {
|
||||
browser: null,
|
||||
|
||||
init: function fsv_init() {
|
||||
messageManager.addMessageListener("Browser:FullScreenVideo:Start", this.show.bind(this));
|
||||
messageManager.addMessageListener("Browser:FullScreenVideo:Close", this.hide.bind(this));
|
||||
},
|
||||
|
||||
show: function fsv_show() {
|
||||
this.createBrowser();
|
||||
window.fullScreen = true;
|
||||
BrowserUI.pushPopup(this, this.browser);
|
||||
},
|
||||
|
||||
hide: function fsv_hide() {
|
||||
this.destroyBrowser();
|
||||
window.fullScreen = false;
|
||||
BrowserUI.popPopup();
|
||||
},
|
||||
|
||||
createBrowser: function fsv_createBrowser() {
|
||||
let browser = this.browser = document.createElement("browser");
|
||||
browser.className = "window-width window-height full-screen";
|
||||
browser.setAttribute("type", "content");
|
||||
browser.setAttribute("remote", "true");
|
||||
browser.setAttribute("src", "chrome://browser/content/fullscreen-video.xhtml");
|
||||
document.getElementById("main-window").appendChild(browser);
|
||||
|
||||
let mm = browser.messageManager;
|
||||
mm.loadFrameScript("chrome://browser/content/fullscreen-video.js", true);
|
||||
|
||||
browser.addEventListener("TapDown", this, true);
|
||||
browser.addEventListener("TapSingle", this, false);
|
||||
|
||||
return browser;
|
||||
},
|
||||
|
||||
destroyBrowser: function fsv_destroyBrowser() {
|
||||
let browser = this.browser;
|
||||
browser.removeEventListener("TapDown", this, false);
|
||||
browser.removeEventListener("TapSingle", this, false);
|
||||
browser.parentNode.removeChild(browser);
|
||||
this.browser = null;
|
||||
},
|
||||
|
||||
handleEvent: function fsv_handleEvent(aEvent) {
|
||||
switch (aEvent.type) {
|
||||
case "TapDown":
|
||||
this._dispatchMouseEvent("Browser:MouseDown", aEvent.clientX, aEvent.clientY);
|
||||
break;
|
||||
case "TapSingle":
|
||||
this._dispatchMouseEvent("Browser:MouseUp", aEvent.clientX, aEvent.clientY);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_dispatchMouseEvent: function fsv_dispatchMouseEvent(aName, aX, aY) {
|
||||
let pos = this.browser.transformClientToBrowser(aX, aY);
|
||||
this.browser.messageManager.sendAsyncMessage(aName, {
|
||||
x: pos.x,
|
||||
y: pos.y,
|
||||
messageId: null
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -165,8 +165,8 @@ function onDebugKeyPress(ev) {
|
|||
}
|
||||
|
||||
var Browser = {
|
||||
_tabs : [],
|
||||
_selectedTab : null,
|
||||
_tabs: [],
|
||||
_selectedTab: null,
|
||||
windowUtils: window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils),
|
||||
controlsScrollbox: null,
|
||||
|
|
|
@ -564,12 +564,15 @@
|
|||
<richlistitem class="context-command" id="context-share-image" type="image-shareable" onclick="ContextCommands.shareMedia();">
|
||||
<label value="&contextShareImage.label;"/>
|
||||
</richlistitem>
|
||||
<richlistitem class="context-command" id="context-play-media" type="media-paused" onclick="ContextCommands.playMedia();">
|
||||
<richlistitem class="context-command" id="context-play-media" type="media-paused" onclick="ContextCommands.sendCommand('play');">
|
||||
<label value="&contextPlayMedia.label;"/>
|
||||
</richlistitem>
|
||||
<richlistitem class="context-command" id="context-pause-video" type="media-playing" onclick="ContextCommands.pauseMedia();">
|
||||
<richlistitem class="context-command" id="context-pause-video" type="media-playing" onclick="ContextCommands.sendCommand('pause');">
|
||||
<label value="&contextPauseMedia.label;"/>
|
||||
</richlistitem>
|
||||
<richlistitem class="context-command" id="context-fullscreen" type="video" onclick="ContextCommands.sendCommand('fullscreen');">
|
||||
<label value="&contextFullScreen.label;"/>
|
||||
</richlistitem>
|
||||
<richlistitem class="context-command" id="context-save-video" type="video" onclick="ContextCommands.saveImage();">
|
||||
<label value="&contextSaveVideo.label;"/>
|
||||
</richlistitem>
|
||||
|
|
|
@ -656,7 +656,7 @@ var ContextHandler = {
|
|||
init: function ch_init() {
|
||||
addEventListener("contextmenu", this, false);
|
||||
addEventListener("pagehide", this, false);
|
||||
addMessageListener("Browser:MediaCommand", this, false);
|
||||
addMessageListener("Browser:ContextCommand", this, false);
|
||||
this.popupNode = null;
|
||||
},
|
||||
|
||||
|
@ -735,10 +735,23 @@ var ContextHandler = {
|
|||
},
|
||||
|
||||
receiveMessage: function ch_receiveMessage(aMessage) {
|
||||
switch (aMessage.name) {
|
||||
case "Browser:MediaCommand":
|
||||
if (this.popupNode instanceof Ci.nsIDOMHTMLMediaElement)
|
||||
this.popupNode[aMessage.json.command]();
|
||||
let node = this.popupNode;
|
||||
let command = aMessage.json.command;
|
||||
|
||||
switch (command) {
|
||||
case "play":
|
||||
case "pause":
|
||||
if (node instanceof Ci.nsIDOMHTMLMediaElement)
|
||||
node[command]();
|
||||
break;
|
||||
|
||||
case "fullscreen":
|
||||
if (node instanceof Ci.nsIDOMHTMLVideoElement) {
|
||||
node.pause();
|
||||
Cu.import("resource:///modules/video.jsm");
|
||||
Video.fullScreenSourceElement = node;
|
||||
sendAsyncMessage("Browser:FullScreenVideo:Start");
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Mobile Browser.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Matt Brubeck <mbrubeck@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
function closeFullScreen() {
|
||||
sendAsyncMessage("Browser:FullScreenVideo:Close");
|
||||
}
|
||||
|
||||
addEventListener("click", function(aEvent) {
|
||||
if (aEvent.target.id == "close")
|
||||
closeFullScreen();
|
||||
}, false);
|
||||
|
||||
addEventListener("CloseVideo", closeFullScreen, false);
|
|
@ -0,0 +1,211 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is the Mozilla Foundation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2008
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Dão Gottwald <dao@mozilla.com>
|
||||
# Matt Brubeck <mbrubeck@mozilla.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
-->
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" accelerated="11">
|
||||
<head>
|
||||
<style type="text/css"><![CDATA[
|
||||
html,
|
||||
body,
|
||||
video {
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
background: black;
|
||||
overflow: -moz-hidden-unscrollable;
|
||||
}
|
||||
body.userIdle {
|
||||
cursor: none;
|
||||
}
|
||||
video {
|
||||
width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
body.loadingdata > video,
|
||||
body.loadingdata > #close,
|
||||
body.userIdle > #close {
|
||||
visibility: hidden;
|
||||
}
|
||||
#close {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAB3RJTUUH2AUXDg4nBoBhWwAAAAlwSFlzAAAPYAAAD2ABenhFjQAAAARnQU1BAACxjwv8YQUAAAEYSURBVHjaY2BgYOAAYtXk5OQAEA3EnAzkAUYg5gFidahZikDMBpJQvXHjxqP/QHDhwoUHmpqarlCFpBou4OzsHH7nzp3XILOOHDlyHigmz1BQUBD5Hwlcu3bthYaGhhsJloANd3Jyinz8+PEnmDl//vz5Z2RkZAFSoAGzlQxLsBoOAidPnrwJlFMAKeIBeQ1dARGW4DQcpFdLS8sZFp94FeKwhBg93KRq4CFDLcmu4gViQXIMJ8oSJSWlIBsbmyRyDSdoCTCfvH/w4MFXCpM1fkuoYTiyJYLW1tbJ9+/f/4Zu+MWLF98pKysHQOMFJ2Aix2ZqAJoGEU0jmabJlKYZjaZFBc0LO5oX17StcOhRZdK20megcbMFAI0gGfYvgPhiAAAAAElFTkSuQmCC) center center no-repeat;
|
||||
}
|
||||
]]></style>
|
||||
<script type="application/javascript;version=1.8"><![CDATA[
|
||||
|
||||
Components.utils.import("resource:///modules/video.jsm");
|
||||
|
||||
var contentVideo = Video.fullScreenSourceElement;
|
||||
Video.fullScreenSourceElement = null;
|
||||
|
||||
var video;
|
||||
|
||||
function init() {
|
||||
video = document.querySelector("video");
|
||||
|
||||
video.addEventListener("loadeddata", function () {
|
||||
video.removeEventListener("loadeddata", arguments.callee, false);
|
||||
video.volume = contentVideo.volume;
|
||||
video.muted = contentVideo.muted;
|
||||
video.poster = contentVideo.poster;
|
||||
|
||||
if (contentVideo.currentTime && !contentVideo.ended) {
|
||||
video.addEventListener("seeked", function () {
|
||||
video.removeEventListener("seeked", arguments.callee, false);
|
||||
playbackStarts();
|
||||
}, false);
|
||||
|
||||
video.currentTime = contentVideo.currentTime;
|
||||
} else {
|
||||
playbackStarts();
|
||||
}
|
||||
|
||||
showUI();
|
||||
resetIdleTimer();
|
||||
|
||||
video.controls = true;
|
||||
video.play();
|
||||
}, false);
|
||||
|
||||
// Automatically close this window when the playback ended, unless the user
|
||||
// interacted with it.
|
||||
video.addEventListener("ended", close, false);
|
||||
window.addEventListener("click", cancelAutoClose, false);
|
||||
window.addEventListener("keypress", cancelAutoClose, false);
|
||||
|
||||
video.addEventListener("seeked", hideUI, false);
|
||||
video.addEventListener("seeking", showUI, false);
|
||||
video.addEventListener("pause", showUI, false);
|
||||
video.addEventListener("ended", showUI, false);
|
||||
|
||||
window.addEventListener("click", function () {
|
||||
toggleUI();
|
||||
resetIdleTimer();
|
||||
}, false);
|
||||
|
||||
video.mozLoadFrom(contentVideo);
|
||||
}
|
||||
|
||||
window.addEventListener("unload", function () {
|
||||
if (video.currentSrc) {
|
||||
contentVideo.currentTime = video.currentTime;
|
||||
contentVideo.volume = video.volume;
|
||||
contentVideo.muted = video.muted;
|
||||
if (!video.paused && !video.ended) {
|
||||
video.pause();
|
||||
contentVideo.play();
|
||||
}
|
||||
}
|
||||
}, false);
|
||||
|
||||
window.addEventListener("keypress", function (event) {
|
||||
if (event.keyCode == event.DOM_VK_ESCAPE) {
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
resetIdleTimer();
|
||||
|
||||
if (!video.controls &&
|
||||
String.fromCharCode(event.charCode) == " ")
|
||||
video.pause();
|
||||
}, false);
|
||||
|
||||
function playbackStarts() {
|
||||
// Loading the data from the content video may take a second or two. We hide
|
||||
// the video during that period.
|
||||
document.body.classList.remove("loadingdata");
|
||||
video.focus();
|
||||
}
|
||||
|
||||
function close() {
|
||||
let event = document.createEvent("Events");
|
||||
event.initEvent("CloseVideo", true, true);
|
||||
window.dispatchEvent(event);
|
||||
}
|
||||
|
||||
function cancelAutoClose() {
|
||||
video.removeEventListener("ended", close, false);
|
||||
window.removeEventListener("click", cancelAutoClose, false);
|
||||
window.removeEventListener("keypress", cancelAutoClose, false);
|
||||
}
|
||||
|
||||
var idleTimer;
|
||||
function resetIdleTimer() {
|
||||
if (idleTimer) {
|
||||
clearTimeout(idleTimer);
|
||||
idleTimer = 0;
|
||||
}
|
||||
idleTimer = setTimeout(function () {
|
||||
idleTimer = 0;
|
||||
hideUI();
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
var showingUI = false;
|
||||
|
||||
function toggleUI() {
|
||||
if (showingUI)
|
||||
hideUI();
|
||||
else
|
||||
showUI();
|
||||
}
|
||||
|
||||
function showUI() {
|
||||
showingUI = true;
|
||||
document.body.classList.remove("userIdle");
|
||||
}
|
||||
|
||||
function hideUI() {
|
||||
showingUI = false;
|
||||
document.body.classList.add("userIdle");
|
||||
}
|
||||
|
||||
]]></script>
|
||||
</head>
|
||||
<body class="loadingdata" onload="init();">
|
||||
<span id="close"/>
|
||||
<video/>
|
||||
</body>
|
||||
</html>
|
|
@ -59,5 +59,7 @@ chrome.jar:
|
|||
content/sync.js (content/sync.js)
|
||||
#endif
|
||||
content/LoginManagerChild.js (content/LoginManagerChild.js)
|
||||
content/fullscreen-video.js (content/fullscreen-video.js)
|
||||
content/fullscreen-video.xhtml (content/fullscreen-video.xhtml)
|
||||
|
||||
% override chrome://global/content/config.xul chrome://browser/content/config.xul
|
||||
|
|
|
@ -96,6 +96,7 @@
|
|||
<!ENTITY contextShareVideo.label "Share Video">
|
||||
<!ENTITY contextPlayMedia.label "Play">
|
||||
<!ENTITY contextPauseMedia.label "Pause">
|
||||
<!ENTITY contextFullScreen.label "Full Screen">
|
||||
<!ENTITY contextEditBookmark.label "Edit">
|
||||
<!ENTITY contextRemoveBookmark.label "Remove">
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ include $(DEPTH)/config/autoconf.mk
|
|||
|
||||
EXTRA_JS_MODULES = \
|
||||
linuxTypes.jsm \
|
||||
video.jsm \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_PP_JS_MODULES = \
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
var EXPORTED_SYMBOLS = ["Video"];
|
||||
|
||||
var Video = {
|
||||
fullScreenSourceElement: null
|
||||
};
|
|
@ -1525,3 +1525,9 @@ echrome-select-option[disabled="true"] {
|
|||
background: #8db8d8;
|
||||
}
|
||||
|
||||
|
||||
/* full-screen video ------------------------------------------------------- */
|
||||
.full-screen {
|
||||
position: absolute;
|
||||
z-index: 500;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче