mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-20 23:37:33 +09:00
PiP initial commit
This commit is contained in:
parent
5ec3ae4a4c
commit
9a1d4edaa9
14 changed files with 377 additions and 1 deletions
84
browser/modules/PictureInPicture.jsm
Normal file
84
browser/modules/PictureInPicture.jsm
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/* 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/. */
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["PictureInPicture"];
|
||||
|
||||
const {utils: Cu} = Components;
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Timer.jsm");
|
||||
|
||||
// Each content process has its own module instance. Only a weak reference to
|
||||
// the source crosses between frame scripts; DOM objects never cross processes.
|
||||
this.PictureInPicture = {
|
||||
source: null,
|
||||
window: null,
|
||||
request: 0,
|
||||
|
||||
register(video, id) {
|
||||
if (!video || video.localName != "video" || video.error ||
|
||||
!video.videoWidth || !video.videoHeight || video.mediaKeys) {
|
||||
throw new Error("This video is not available for Picture-in-Picture");
|
||||
}
|
||||
this.source = {id, video: Cu.getWeakReference(video)};
|
||||
return {id, width: video.videoWidth, height: video.videoHeight};
|
||||
},
|
||||
|
||||
takeSource(id) {
|
||||
if (!this.source || this.source.id != id) {
|
||||
throw new Error("Picture-in-Picture source process is unavailable");
|
||||
}
|
||||
let video = this.source.video.get();
|
||||
this.source = null;
|
||||
if (!video || !video.isConnected) {
|
||||
throw new Error("Picture-in-Picture source has been removed");
|
||||
}
|
||||
return video;
|
||||
},
|
||||
|
||||
open(browser, video) {
|
||||
let id = Services.uuid.generateUUID().toString();
|
||||
let request = ++this.request;
|
||||
let mm = browser.messageManager;
|
||||
let timer;
|
||||
let ready = message => {
|
||||
if (message.data.id != id) {
|
||||
return;
|
||||
}
|
||||
mm.removeMessageListener("PictureInPicture:Prepared", ready);
|
||||
clearTimeout(timer);
|
||||
if (request != this.request || !browser.isConnected) {
|
||||
return;
|
||||
}
|
||||
if (message.data.error) {
|
||||
Cu.reportError(message.data.error);
|
||||
return;
|
||||
}
|
||||
this.openWindow(browser, message.data);
|
||||
};
|
||||
mm.addMessageListener("PictureInPicture:Prepared", ready);
|
||||
timer = setTimeout(() => {
|
||||
mm.removeMessageListener("PictureInPicture:Prepared", ready);
|
||||
}, 10000);
|
||||
mm.sendAsyncMessage("ContextMenu:MediaCommand",
|
||||
{command: "pictureinpicture", data: id},
|
||||
{element: video});
|
||||
},
|
||||
|
||||
openWindow(browser, data) {
|
||||
if (this.window && !this.window.closed) {
|
||||
this.window.close();
|
||||
}
|
||||
let screen = browser.ownerGlobal.screen;
|
||||
let width = Math.min(480, screen.availWidth);
|
||||
let height = Math.min(Math.round(width * data.height / data.width) + 48,
|
||||
Math.round(screen.availHeight * 0.8));
|
||||
this.window = browser.ownerGlobal.openDialog(
|
||||
"chrome://browser/content/pictureInPicture.xul", "",
|
||||
"chrome,dialog=no,resizable,alwaysRaised,width=" + width +
|
||||
",height=" + height,
|
||||
{browser, id: data.id});
|
||||
return this.window;
|
||||
},
|
||||
};
|
||||
|
|
@ -22,6 +22,7 @@ EXTRA_JS_MODULES += [
|
|||
'NetworkPrioritizer.jsm',
|
||||
'offlineAppCache.jsm',
|
||||
'PermissionUI.jsm',
|
||||
'PictureInPicture.jsm',
|
||||
'PluginContent.jsm',
|
||||
'ProcessHangMonitor.jsm',
|
||||
'ReaderParent.jsm',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue