gecko-dev/browser/actors/DOMFullscreenParent.jsm

211 строки
6.9 KiB
JavaScript

/* vim: set ts=2 sw=2 sts=2 et tw=80: */
/* 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";
var EXPORTED_SYMBOLS = ["DOMFullscreenParent"];
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
class DOMFullscreenParent extends JSWindowActorParent {
waitingForChildFullscreen = false;
updateFullscreenWindowReference(aWindow) {
if (aWindow.document.documentElement.hasAttribute("inDOMFullscreen")) {
this._fullscreenWindow = aWindow;
} else {
delete this._fullscreenWindow;
}
}
didDestroy() {
let window = this._fullscreenWindow;
if (!window) {
return;
}
if (this.waitingForChildFullscreen) {
// We were killed while waiting for our DOMFullscreenChild
// to transition to fullscreen so we abort the entire
// fullscreen transition to prevent getting stuck in a
// partial fullscreen state. We need to go through the
// document since window.Fullscreen could be undefined
// at this point.
//
// This could reject if we're not currently in fullscreen
// so just ignore rejection.
window.document.exitFullscreen().catch(() => {});
return;
}
// Need to resume Chrome UI if the window is still in fullscreen UI
// to avoid the window stays in fullscreen problem. (See Bug 1620341)
if (window.document.documentElement.hasAttribute("inDOMFullscreen")) {
if (window.FullScreen) {
window.FullScreen.cleanupDomFullscreen(this);
}
if (window.windowUtils) {
window.windowUtils.remoteFrameFullscreenReverted();
}
}
this.updateFullscreenWindowReference(window);
}
receiveMessage(aMessage) {
let topBrowsingContext = this.browsingContext.top;
let browser = topBrowsingContext.embedderElement;
if (!browser) {
// No need to go further when the browser is not accessible anymore
// (which can happen when the tab is closed for instance),
return;
}
let window = browser.ownerGlobal;
switch (aMessage.name) {
case "DOMFullscreen:Request": {
this.requestOrigin = this;
this.addListeners(window);
window.windowUtils.remoteFrameFullscreenChanged(browser);
break;
}
case "DOMFullscreen:NewOrigin": {
// Don't show the warning if we've already exited fullscreen.
if (window.document.fullscreen) {
window.PointerlockFsWarning.showFullScreen(
aMessage.data.originNoSuffix
);
}
break;
}
case "DOMFullscreen:Entered": {
this.waitingForChildFullscreen = false;
window.FullScreen.enterDomFullscreen(browser, this);
this.updateFullscreenWindowReference(window);
break;
}
case "DOMFullscreen:Exit": {
window.windowUtils.remoteFrameFullscreenReverted();
break;
}
case "DOMFullscreen:Exited": {
window.FullScreen.cleanupDomFullscreen(this);
this.updateFullscreenWindowReference(window);
break;
}
case "DOMFullscreen:Painted": {
Services.obs.notifyObservers(window, "fullscreen-painted");
this.sendAsyncMessage("DOMFullscreen:Painted", {});
TelemetryStopwatch.finish("FULLSCREEN_CHANGE_MS");
break;
}
}
}
handleEvent(aEvent) {
let window = aEvent.currentTarget.ownerGlobal;
switch (aEvent.type) {
case "MozDOMFullscreen:Entered": {
// The event target is the element which requested the DOM
// fullscreen. If we were entering DOM fullscreen for a remote
// browser, the target would be the browser which was the parameter of
// `remoteFrameFullscreenChanged` call. If the fullscreen
// request was initiated from an in-process browser, we need
// to get its corresponding browser here.
let browser;
if (aEvent.target.ownerGlobal == window) {
browser = aEvent.target;
} else {
browser = aEvent.target.ownerGlobal.docShell.chromeEventHandler;
}
// Addon installation should be cancelled when entering fullscreen for security and usability reasons.
// Installation prompts in fullscreen can trick the user into installing unwanted addons.
// In fullscreen the notification box does not have a clear visual association with its parent anymore.
if (window.gXPInstallObserver) {
window.gXPInstallObserver.removeAllNotifications(browser);
}
TelemetryStopwatch.start("FULLSCREEN_CHANGE_MS");
window.FullScreen.enterDomFullscreen(browser, this);
this.updateFullscreenWindowReference(window);
break;
}
case "MozDOMFullscreen:Exited": {
TelemetryStopwatch.start("FULLSCREEN_CHANGE_MS");
// Make sure that the actor has not been destroyed before
// accessing its browsing context. Otherwise, a error may
// occur and hence cleanupDomFullscreen not executed, resulting
// in the browser window being in an unstable state.
// (Bug 1590138).
if (!this.hasBeenDestroyed() && !this.requestOrigin) {
this.requestOrigin = this;
}
window.FullScreen.cleanupDomFullscreen(this);
this.updateFullscreenWindowReference(window);
this.removeListeners(window);
break;
}
}
}
addListeners(aWindow) {
aWindow.addEventListener(
"MozDOMFullscreen:Entered",
this,
/* useCapture */ true,
/* wantsUntrusted */
false
);
aWindow.addEventListener(
"MozDOMFullscreen:Exited",
this,
/* useCapture */ true,
/* wantsUntrusted */ false
);
}
removeListeners(aWindow) {
aWindow.removeEventListener("MozDOMFullscreen:Entered", this, true);
aWindow.removeEventListener("MozDOMFullscreen:Exited", this, true);
}
/**
* Get the actor where the original fullscreen
* enter or exit request comes from.
*/
get requestOrigin() {
let requestOrigin = this.browsingContext.top.fullscreenRequestOrigin;
return requestOrigin && requestOrigin.get();
}
/**
* Store the actor where the original fullscreen
* enter or exit request comes from in the top level
* browsing context.
*/
set requestOrigin(aActor) {
if (aActor) {
this.browsingContext.top.fullscreenRequestOrigin = Cu.getWeakReference(
aActor
);
} else {
delete this.browsingContext.top.fullscreenRequestOrigin;
}
}
hasBeenDestroyed() {
// The 'didDestroy' callback is not always getting called.
// So we can't rely on it here. Instead, we will try to access
// the browsing context to judge wether the actor has
// been destroyed or not.
try {
return !this.browsingContext;
} catch {
return true;
}
}
}