232 lines
8.9 KiB
Diff
232 lines
8.9 KiB
Diff
# HG changeset patch
|
|
# User Steven MacLeod <steven@smacleod.ca>
|
|
# Date 1601937483 0
|
|
# Mon Oct 05 22:38:03 2020 +0000
|
|
# Node ID 3e884c48633fb4017402ef2c7053f8d947676dd5
|
|
# Parent b4b7e943b93cdc77a479bd5484f7661985bdb7d4
|
|
Bug 1656741, r=Gijs
|
|
|
|
Differential Revision: https://phabricator.services.mozilla.com/D91760
|
|
|
|
diff -r b4b7e943b93c -r 3e884c48633f browser/actors/DOMFullscreenParent.jsm
|
|
--- a/browser/actors/DOMFullscreenParent.jsm Mon Oct 05 22:20:41 2020 +0000
|
|
+++ b/browser/actors/DOMFullscreenParent.jsm Mon Oct 05 22:38:03 2020 +0000
|
|
@@ -9,6 +9,8 @@
|
|
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;
|
|
@@ -23,6 +25,20 @@
|
|
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")) {
|
|
@@ -64,6 +80,7 @@
|
|
break;
|
|
}
|
|
case "DOMFullscreen:Entered": {
|
|
+ this.waitingForChildFullscreen = false;
|
|
window.FullScreen.enterDomFullscreen(browser, this);
|
|
this.updateFullscreenWindowReference(window);
|
|
break;
|
|
diff -r b4b7e943b93c -r 3e884c48633f browser/base/content/browser-fullScreenAndPointerLock.js
|
|
--- a/browser/base/content/browser-fullScreenAndPointerLock.js Mon Oct 05 22:20:41 2020 +0000
|
|
+++ b/browser/base/content/browser-fullScreenAndPointerLock.js Mon Oct 05 22:38:03 2020 +0000
|
|
@@ -420,12 +420,27 @@
|
|
// before the check is fine since we also check the activeness of
|
|
// the requesting document in content-side handling code.
|
|
if (this._isRemoteBrowser(aBrowser)) {
|
|
- if (
|
|
- !this._sendMessageToTheRightContent(aActor, "DOMFullscreen:Entered")
|
|
- ) {
|
|
+ let [targetActor, inProcessBC] = this._getNextMsgRecipientActor(aActor);
|
|
+ if (!targetActor) {
|
|
+ // If there is no appropriate actor to send the message we have
|
|
+ // no way to complete the transition and should abort by exiting
|
|
+ // fullscreen.
|
|
+ this._abortEnterFullscreen();
|
|
+ return;
|
|
+ }
|
|
+ targetActor.sendAsyncMessage("DOMFullscreen:Entered", {
|
|
+ remoteFrameBC: inProcessBC,
|
|
+ });
|
|
+
|
|
+ // Record that the actor is waiting for its child to enter
|
|
+ // fullscreen so that if it dies we can abort.
|
|
+ targetActor.waitingForChildFullscreen = true;
|
|
+ if (inProcessBC) {
|
|
+ // We aren't messaging the request origin yet, skip this time.
|
|
return;
|
|
}
|
|
}
|
|
+
|
|
// If we've received a fullscreen notification, we have to ensure that the
|
|
// element that's requesting fullscreen belongs to the browser that's currently
|
|
// active. If not, we exit fullscreen since the "full-screen document" isn't
|
|
@@ -437,9 +452,7 @@
|
|
// full-screen was made. Cancel full-screen.
|
|
Services.focus.activeWindow != window
|
|
) {
|
|
- // This function is called synchronously in fullscreen change, so
|
|
- // we have to avoid calling exitFullscreen synchronously here.
|
|
- setTimeout(() => document.exitFullscreen(), 0);
|
|
+ this._abortEnterFullscreen();
|
|
return;
|
|
}
|
|
|
|
@@ -453,7 +466,6 @@
|
|
this._logWarningPermissionPromptFS("promptCanceled");
|
|
}
|
|
}
|
|
-
|
|
document.documentElement.setAttribute("inDOMFullscreen", true);
|
|
|
|
if (gFindBarInitialized) {
|
|
@@ -488,9 +500,25 @@
|
|
}
|
|
},
|
|
|
|
+ /**
|
|
+ * Clean up full screen, starting from the request origin's first ancestor
|
|
+ * frame that is OOP.
|
|
+ *
|
|
+ * If there are OOP ancestor frames, we notify the first of those and then bail to
|
|
+ * be called again in that process when it has dealt with the change. This is
|
|
+ * repeated until all ancestor processes have been updated. Once that has happened
|
|
+ * we remove our handlers and attributes and notify the request origin to complete
|
|
+ * the cleanup.
|
|
+ */
|
|
cleanupDomFullscreen(aActor) {
|
|
- if (!this._sendMessageToTheRightContent(aActor, "DOMFullscreen:CleanUp")) {
|
|
- return;
|
|
+ let [target, inProcessBC] = this._getNextMsgRecipientActor(aActor);
|
|
+ if (target) {
|
|
+ target.sendAsyncMessage("DOMFullscreen:CleanUp", {
|
|
+ remoteFrameBC: inProcessBC,
|
|
+ });
|
|
+ if (inProcessBC) {
|
|
+ return;
|
|
+ }
|
|
}
|
|
|
|
PopupNotifications.panel.removeEventListener(
|
|
@@ -508,40 +536,43 @@
|
|
document.documentElement.removeAttribute("inDOMFullscreen");
|
|
},
|
|
|
|
+ _abortEnterFullscreen() {
|
|
+ // This function is called synchronously in fullscreen change, so
|
|
+ // we have to avoid calling exitFullscreen synchronously here.
|
|
+ setTimeout(() => document.exitFullscreen(), 0);
|
|
+ if (TelemetryStopwatch.running("FULLSCREEN_CHANGE_MS")) {
|
|
+ // Cancel the stopwatch for any fullscreen change to avoid
|
|
+ // errors if it is started again.
|
|
+ TelemetryStopwatch.cancel("FULLSCREEN_CHANGE_MS");
|
|
+ }
|
|
+ },
|
|
+
|
|
/**
|
|
* Search for the first ancestor of aActor that lives in a different process.
|
|
- * If found, that ancestor is sent the message and return false.
|
|
- * Otherwise, the recipient should be the actor of the request origin and return true
|
|
- * from this function.
|
|
- *
|
|
- * The method will be called again as a result of targeted child process doing
|
|
- * "FullScreen.enterDomFullscreen()" or "FullScreen.cleanupDomFullscreen()".
|
|
- * The return value is used to postpone entering or exiting Full Screen in the parent
|
|
- * until there is no ancestor anymore.
|
|
+ * If found, that ancestor actor and the browsing context for its child which
|
|
+ * was in process are returned. Otherwise [request origin, null].
|
|
*
|
|
*
|
|
* @param {JSWindowActorParent} aActor
|
|
* The actor that called this function.
|
|
- * @param {String} message
|
|
- * Message to be sent.
|
|
*
|
|
- * @return {boolean}
|
|
- * The return value is used to postpone entering or exiting Full Screen in the
|
|
- * parent until there is no ancestor anymore.
|
|
- * Return false if the message is send to the first ancestor of aActor that
|
|
- * lives in a different process
|
|
- * Return true if the message is sent to the request source
|
|
- * or false otherwise.
|
|
+ * @return {[JSWindowActorParent, BrowsingContext]}
|
|
+ * The parent actor which should be sent the next msg and the
|
|
+ * in process browsing context which is its child. Will be
|
|
+ * [null, null] if there is no OOP parent actor and request origin
|
|
+ * is unset. [null, null] is also returned if the intended actor or
|
|
+ * the calling actor has been destroyed.
|
|
*/
|
|
- _sendMessageToTheRightContent(aActor, aMessage) {
|
|
+ _getNextMsgRecipientActor(aActor) {
|
|
if (aActor.hasBeenDestroyed()) {
|
|
- // Just restore the chrome UI when the actor is dead.
|
|
- return true;
|
|
+ return [null, null];
|
|
}
|
|
|
|
let childBC = aActor.browsingContext;
|
|
let parentBC = childBC.parent;
|
|
|
|
+ // Walk up the browsing context tree from aActor's browsing context
|
|
+ // to find the first ancestor browsing context that's in a different process.
|
|
while (parentBC) {
|
|
if (!childBC.currentWindowGlobal || !parentBC.currentWindowGlobal) {
|
|
break;
|
|
@@ -557,24 +588,20 @@
|
|
}
|
|
}
|
|
|
|
+ let target = null;
|
|
+ let inProcessBC = null;
|
|
+
|
|
if (parentBC && parentBC.currentWindowGlobal) {
|
|
- let parentActor = parentBC.currentWindowGlobal.getActor("DOMFullscreen");
|
|
- parentActor.sendAsyncMessage(aMessage, {
|
|
- remoteFrameBC: childBC,
|
|
- });
|
|
- return false;
|
|
+ target = parentBC.currentWindowGlobal.getActor("DOMFullscreen");
|
|
+ inProcessBC = childBC;
|
|
+ } else {
|
|
+ target = aActor.requestOrigin;
|
|
}
|
|
|
|
- // All content frames living outside the process where
|
|
- // the element requesting fullscreen lives should
|
|
- // have entered or exited fullscreen at this point.
|
|
- // So let's notify the process where the original request
|
|
- // comes from.
|
|
- if (!aActor.requestOrigin.hasBeenDestroyed()) {
|
|
- aActor.requestOrigin.sendAsyncMessage(aMessage, {});
|
|
- aActor.requestOrigin = null;
|
|
+ if (!target || target.hasBeenDestroyed()) {
|
|
+ return [null, null];
|
|
}
|
|
- return true;
|
|
+ return [target, inProcessBC];
|
|
},
|
|
|
|
_isRemoteBrowser(aBrowser) {
|