зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1532773 - Add player controls for PictureInPicture. r=mconley
Differential Revision: https://phabricator.services.mozilla.com/D25435 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
22ed97f045
Коммит
70cf4e4c3c
|
@ -517,6 +517,8 @@ const listeners = {
|
|||
"FormValidation:HidePopup": ["FormValidationHandler"],
|
||||
"PictureInPicture:Request": ["PictureInPicture"],
|
||||
"PictureInPicture:Close": ["PictureInPicture"],
|
||||
"PictureInPicture:Playing": ["PictureInPicture"],
|
||||
"PictureInPicture:Paused": ["PictureInPicture"],
|
||||
"Prompt:Open": ["RemotePrompt"],
|
||||
"Reader:FaviconRequest": ["ReaderParent"],
|
||||
"Reader:UpdateReaderButton": ["ReaderParent"],
|
||||
|
|
|
@ -16,6 +16,10 @@ var gWeakVideo = null;
|
|||
var gWeakPlayerContent = null;
|
||||
|
||||
class PictureInPictureChild extends ActorChild {
|
||||
static videoIsPlaying(video) {
|
||||
return !!(video.currentTime > 0 && !video.paused && !video.ended && video.readyState > 2);
|
||||
}
|
||||
|
||||
handleEvent(event) {
|
||||
switch (event.type) {
|
||||
case "MozTogglePictureInPicture": {
|
||||
|
@ -30,6 +34,14 @@ class PictureInPictureChild extends ActorChild {
|
|||
this.closePictureInPicture();
|
||||
break;
|
||||
}
|
||||
case "play": {
|
||||
this.mm.sendAsyncMessage("PictureInPicture:Playing");
|
||||
break;
|
||||
}
|
||||
case "pause": {
|
||||
this.mm.sendAsyncMessage("PictureInPicture:Paused");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,6 +85,7 @@ class PictureInPictureChild extends ActorChild {
|
|||
|
||||
gWeakVideo = Cu.getWeakReference(video);
|
||||
this.mm.sendAsyncMessage("PictureInPicture:Request", {
|
||||
playing: PictureInPictureChild.videoIsPlaying(video),
|
||||
videoHeight: video.videoHeight,
|
||||
videoWidth: video.videoWidth,
|
||||
});
|
||||
|
@ -128,6 +141,14 @@ class PictureInPictureChild extends ActorChild {
|
|||
this.setupPlayer();
|
||||
break;
|
||||
}
|
||||
case "PictureInPicture:Play": {
|
||||
this.play();
|
||||
break;
|
||||
}
|
||||
case "PictureInPicture:Pause": {
|
||||
this.pause();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,6 +161,8 @@ class PictureInPictureChild extends ActorChild {
|
|||
let originatingWindow = originatingVideo.ownerGlobal;
|
||||
if (originatingWindow) {
|
||||
originatingWindow.addEventListener("pagehide", this);
|
||||
originatingVideo.addEventListener("play", this);
|
||||
originatingVideo.addEventListener("pause", this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -153,6 +176,8 @@ class PictureInPictureChild extends ActorChild {
|
|||
let originatingWindow = originatingVideo.ownerGlobal;
|
||||
if (originatingWindow) {
|
||||
originatingWindow.removeEventListener("pagehide", this);
|
||||
originatingVideo.removeEventListener("play", this);
|
||||
originatingVideo.removeEventListener("pause", this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -224,4 +249,18 @@ class PictureInPictureChild extends ActorChild {
|
|||
|
||||
gWeakPlayerContent = Cu.getWeakReference(this.content);
|
||||
}
|
||||
|
||||
play() {
|
||||
let video = this.weakVideo;
|
||||
if (video) {
|
||||
video.play();
|
||||
}
|
||||
}
|
||||
|
||||
pause() {
|
||||
let video = this.weakVideo;
|
||||
if (video) {
|
||||
video.pause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,9 +35,25 @@ var PictureInPicture = {
|
|||
this.closePipWindow();
|
||||
break;
|
||||
}
|
||||
case "PictureInPicture:Playing": {
|
||||
this.weakPipControls.classList.add("playing");
|
||||
break;
|
||||
}
|
||||
case "PictureInPicture:Paused": {
|
||||
this.weakPipControls.classList.remove("playing");
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
focusTabAndClosePip() {
|
||||
let gBrowser = this.browser.ownerGlobal.gBrowser;
|
||||
let tab = gBrowser.getTabForBrowser(this.browser);
|
||||
gBrowser.selectedTab = tab;
|
||||
this.unload();
|
||||
this.closePipWindow();
|
||||
},
|
||||
|
||||
/**
|
||||
* Find and close any pre-existing Picture in Picture windows.
|
||||
*/
|
||||
|
@ -48,7 +64,6 @@ var PictureInPicture = {
|
|||
if (win.closed) {
|
||||
continue;
|
||||
}
|
||||
|
||||
win.close();
|
||||
}
|
||||
},
|
||||
|
@ -74,12 +89,26 @@ var PictureInPicture = {
|
|||
* the player component inside it has finished loading.
|
||||
*/
|
||||
async handlePictureInPictureRequest(browser, videoData) {
|
||||
this.browser = browser;
|
||||
let parentWin = browser.ownerGlobal;
|
||||
this.closePipWindow();
|
||||
let win = await this.openPipWindow(parentWin, videoData);
|
||||
this.weakPipControls = win.document.getElementById("controls");
|
||||
if (videoData.playing) {
|
||||
this.weakPipControls.classList.add("playing");
|
||||
}
|
||||
win.setupPlayer(browser, videoData);
|
||||
},
|
||||
|
||||
/**
|
||||
* unload event has been called in player.js, cleanup our preserved
|
||||
* browser object.
|
||||
*/
|
||||
unload() {
|
||||
delete this.weakPipControls;
|
||||
delete this.browser;
|
||||
},
|
||||
|
||||
/**
|
||||
* Open a Picture in Picture window on the same screen as parentWin,
|
||||
* sized based on the information in videoData.
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
* 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/. */
|
||||
|
||||
const {PictureInPicture} = ChromeUtils.import("resource://gre/modules/PictureInPicture.jsm");
|
||||
|
||||
async function setupPlayer(originatingBrowser, videoData) {
|
||||
window.windowUtils.setChromeMargin(0, 0, 0, 0);
|
||||
let holder = document.querySelector(".player-holder");
|
||||
|
@ -19,12 +21,33 @@ async function setupPlayer(originatingBrowser, videoData) {
|
|||
let mm = browser.frameLoader.messageManager;
|
||||
mm.sendAsyncMessage("PictureInPicture:SetupPlayer");
|
||||
|
||||
document.getElementById("play").addEventListener("click", () => {
|
||||
mm.sendAsyncMessage("PictureInPicture:Play");
|
||||
});
|
||||
|
||||
document.getElementById("pause").addEventListener("click", () => {
|
||||
mm.sendAsyncMessage("PictureInPicture:Pause");
|
||||
});
|
||||
|
||||
document.getElementById("unpip").addEventListener("click", () => {
|
||||
PictureInPicture.focusTabAndClosePip();
|
||||
});
|
||||
|
||||
// If the content process hosting the video crashes, let's
|
||||
// just close the window for now.
|
||||
browser.addEventListener("oop-browser-crashed", () => {
|
||||
window.close();
|
||||
});
|
||||
|
||||
browser.addEventListener("unload", () => {
|
||||
PictureInPicture.unload();
|
||||
});
|
||||
|
||||
await window.promiseDocumentFlushed(() => {});
|
||||
browser.style.MozWindowDragging = "drag";
|
||||
|
||||
let close = document.getElementById("close");
|
||||
close.addEventListener("click", () => {
|
||||
window.close();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -21,5 +21,11 @@
|
|||
<div class="player-holder">
|
||||
<xul:browser type="content" primary="true" remote="true" remoteType="web" id="browser"></xul:browser>
|
||||
</div>
|
||||
<div id="controls">
|
||||
<div id="close" class="control-item"></div>
|
||||
<div id="unpip" class="control-item"></div>
|
||||
<div id="pause" class="control-item"></div>
|
||||
<div id="play" class="control-item"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -225,6 +225,8 @@ let ACTORS = {
|
|||
|
||||
messages: [
|
||||
"PictureInPicture:SetupPlayer",
|
||||
"PictureInPicture:Play",
|
||||
"PictureInPicture:Pause",
|
||||
],
|
||||
},
|
||||
},
|
||||
|
|
|
@ -32,6 +32,7 @@ toolkit.jar:
|
|||
skin/classic/global/icons/check.svg (../../shared/icons/check.svg)
|
||||
skin/classic/global/icons/check-partial.svg (../../shared/icons/check-partial.svg)
|
||||
skin/classic/global/icons/close.svg (../../shared/icons/close.svg)
|
||||
skin/classic/global/pictureinpicture/close-pip.svg (../../shared/pictureinpicture/close-pip.svg)
|
||||
skin/classic/global/icons/columnpicker.svg (../../shared/icons/columnpicker.svg)
|
||||
skin/classic/global/icons/delete.svg (../../shared/icons/delete.svg)
|
||||
skin/classic/global/icons/error.svg (../../shared/icons/error.svg)
|
||||
|
@ -44,6 +45,8 @@ toolkit.jar:
|
|||
skin/classic/global/icons/loading@2x.png (../../shared/icons/loading@2x.png)
|
||||
skin/classic/global/icons/more.svg (../../shared/icons/more.svg)
|
||||
skin/classic/global/icons/performance.svg (../../shared/icons/performance.svg)
|
||||
skin/classic/global/pictureinpicture/pause.svg (../../shared/pictureinpicture/pause.svg)
|
||||
skin/classic/global/pictureinpicture/play.svg (../../shared/pictureinpicture/play.svg)
|
||||
skin/classic/global/icons/resizer.svg (../../shared/icons/resizer.svg)
|
||||
skin/classic/global/icons/shortcut.svg (../../shared/icons/shortcut.svg)
|
||||
skin/classic/global/icons/spinner-arrow-down.svg (../../shared/icons/spinner-arrow-down.svg)
|
||||
|
@ -54,6 +57,7 @@ toolkit.jar:
|
|||
skin/classic/global/icons/arrow-dropdown-12.svg (../../shared/icons/arrow-dropdown-12.svg)
|
||||
skin/classic/global/icons/arrow-dropdown-16.svg (../../shared/icons/arrow-dropdown-16.svg)
|
||||
skin/classic/global/icons/arrow-up-12.svg (../../shared/icons/arrow-up-12.svg)
|
||||
skin/classic/global/pictureinpicture/unpip.svg (../../shared/pictureinpicture/unpip.svg)
|
||||
skin/classic/global/icons/warning.svg (../../shared/icons/warning.svg)
|
||||
skin/classic/global/illustrations/about-rights.svg (../../shared/illustrations/about-rights.svg)
|
||||
skin/classic/global/icons/blocked.svg (../../shared/incontent-icons/blocked.svg)
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<!-- 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/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path d="M9.061 8l3.47-3.47a.75.75 0 0 0-1.061-1.06L8 6.939 4.53 3.47a.75.75 0 1 0-1.06 1.06L6.939 8 3.47 11.47a.75.75 0 1 0 1.06 1.06L8 9.061l3.47 3.47a.75.75 0 0 0 1.06-1.061z"/></svg>
|
||||
|
После Ширина: | Высота: | Размер: 460 B |
|
@ -0,0 +1,4 @@
|
|||
<!-- 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/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g fill="#F9F9FA" fill-rule="evenodd" fill-opacity=".8"><rect x="3" y="3" width="4" height="10" rx=".5"/><rect x="9" y="3" width="4" height="10" rx=".5"/></g></svg>
|
После Ширина: | Высота: | Размер: 437 B |
|
@ -0,0 +1,4 @@
|
|||
<!-- 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/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="#F9F9FA" d="M4 3.995c0-.55.386-.754.856-.46l6.288 3.93c.473.295.47.776 0 1.07l-6.288 3.93c-.473.295-.856.08-.856-.46v-8.01z"/></svg>
|
После Ширина: | Высота: | Размер: 417 B |
|
@ -2,6 +2,11 @@
|
|||
* 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/. */
|
||||
|
||||
:root {
|
||||
--btn-bg-color: rgba(50,50,50,0.55);
|
||||
--close-btn-bg-color: rgb(211,216,220);
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
@ -14,5 +19,67 @@ body {
|
|||
}
|
||||
|
||||
browser {
|
||||
-moz-window-dragging: drag;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
#controls {
|
||||
height: 100%;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.control-item {
|
||||
-moz-window-dragging: no-drag;
|
||||
background: var(--btn-bg-color);
|
||||
border-radius: 4px;
|
||||
bottom: 15px;
|
||||
cursor: pointer;
|
||||
height: 15%;
|
||||
max-height: 32px;
|
||||
max-width: 32px;
|
||||
min-height: 16px;
|
||||
min-width: 16px;
|
||||
position: absolute;
|
||||
width: 10%;
|
||||
}
|
||||
|
||||
#close {
|
||||
background-color: var(--close-btn-bg-color);
|
||||
background-image: url("chrome://global/skin/pictureinpicture/close-pip.svg");
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
}
|
||||
|
||||
#play {
|
||||
background-image: url("chrome://global/skin/pictureinpicture/play.svg");
|
||||
display: block;
|
||||
left: 55%;
|
||||
}
|
||||
|
||||
#pause {
|
||||
background-image: url("chrome://global/skin/pictureinpicture/pause.svg");
|
||||
display: none;
|
||||
left: 55%;
|
||||
}
|
||||
|
||||
.playing #play {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.playing #pause {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#unpip {
|
||||
left: 45%;
|
||||
}
|
||||
|
||||
#unpip {
|
||||
background-image: url("chrome://global/skin/pictureinpicture/unpip.svg");
|
||||
background-position: 60%;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 80%;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
<!-- 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/. -->
|
||||
<svg width="80%" height="80%" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path fill="#FFF" d="M0 0h16v12H0z"/><path d="M30 21h-3V2a1 1 0 0 0-1-1H2a1 1 0 0 0-1 1v24a1 1 0 0 0 1 1h15v3a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-8a1 1 0 0 0-1-1z" stroke="#FFF" stroke-width="2"/><path stroke="#FFF" stroke-width="2" d="M17 21h14v10H17z"/></g></svg>
|
После Ширина: | Высота: | Размер: 594 B |
Загрузка…
Ссылка в новой задаче