Bug 1311605 - Support save page for RDM content. r=ochameau

MozReview-Commit-ID: J8d9J2GRkf5

--HG--
extra : rebase_source : 4948d1dc518a85239cd86fbcd73cd1e4d55b76ca
This commit is contained in:
J. Ryan Stinnett 2016-10-25 12:54:26 -05:00
Родитель 14a2b3bc99
Коммит b158ffd8b6
1 изменённых файлов: 42 добавлений и 40 удалений

Просмотреть файл

@ -9,6 +9,10 @@ const Services = require("Services");
const { Task } = require("devtools/shared/task");
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
const { BrowserElementWebNavigation } = require("./web-navigation");
const { getStack } = require("devtools/shared/platform/stack");
// A symbol used to hold onto the frame loader from the outer browser while tunneling.
const FRAME_LOADER = Symbol("devtools/responsive/frame-loader");
function debug(msg) {
// console.log(msg);
@ -77,6 +81,34 @@ function tunnelToInnerBrowser(outer, inner) {
throw new Error("The inner browser must be remote.");
}
// Various browser methods access the `frameLoader` property, including:
// * `saveBrowser` from contentAreaUtils.js
// * `docShellIsActive` from remote-browser.xml
// * `hasContentOpener` from remote-browser.xml
// * `preserveLayers` from remote-browser.xml
// * `receiveMessage` from SessionStore.jsm
// In general, these methods are interested in the `frameLoader` for the content,
// so we redirect them to the inner browser's `frameLoader`.
outer[FRAME_LOADER] = outer.frameLoader;
Object.defineProperty(outer, "frameLoader", {
get() {
let stack = getStack();
// One exception is `receiveMessage` from SessionStore.jsm. SessionStore
// expects data updates to come in as messages targeted to a <xul:browser>.
// In addition, it verifies[1] correctness by checking that the received
// message's `targetFrameLoader` property matches the `frameLoader` of the
// <xul:browser>. To keep SessionStore functioning as expected, we give it the
// outer `frameLoader` as if nothing has changed.
// [1]: https://dxr.mozilla.org/mozilla-central/rev/b1b18f25c0ea69d9ee57c4198d577dfcd0129ce1/browser/components/sessionstore/SessionStore.jsm#716
if (stack.caller.filename.endsWith("SessionStore.jsm")) {
return outer[FRAME_LOADER];
}
return inner.frameLoader;
},
configurable: true,
enumerable: true,
});
// The `permanentKey` property on a <xul:browser> is used to index into various maps
// held by the session store. When you swap content around with
// `_swapBrowserDocShells`, these keys are also swapped so they follow the content.
@ -152,35 +184,6 @@ function tunnelToInnerBrowser(outer, inner) {
outer[property] = inner[property];
}
// Wants to access the content's `frameLoader`, so we'll redirect it to
// inner browser.
Object.defineProperty(outer, "hasContentOpener", {
get() {
return inner.frameLoader.tabParent.hasContentOpener;
},
configurable: true,
enumerable: true,
});
// Wants to access the content's `frameLoader`, so we'll redirect it to
// inner browser.
Object.defineProperty(outer, "docShellIsActive", {
get() {
return inner.frameLoader.tabParent.docShellIsActive;
},
set(value) {
inner.frameLoader.tabParent.docShellIsActive = value;
},
configurable: true,
enumerable: true,
});
// Wants to access the content's `frameLoader`, so we'll redirect it to
// inner browser.
outer.preserveLayers = value => {
inner.frameLoader.tabParent.preserveLayers(value);
};
// Expose `PopupNotifications` on the content's owner global.
// This is used by PermissionUI.jsm for permission doorhangers.
// Note: This pollutes the responsive.html tool UI's global.
@ -253,13 +256,6 @@ function tunnelToInnerBrowser(outer, inner) {
outer.destroy();
outer.style.MozBinding = "";
// Reset overridden XBL properties and methods. Deleting the override
// means it will fallback to the original XBL binding definitions which
// are on the prototype.
delete outer.hasContentOpener;
delete outer.docShellIsActive;
delete outer.preserveLayers;
// Reset @remote since this is now back to a regular, non-remote browser
outer.setAttribute("remote", "false");
@ -273,6 +269,12 @@ function tunnelToInnerBrowser(outer, inner) {
mmTunnel.destroy();
mmTunnel = null;
// Reset overridden XBL properties and methods. Deleting the override
// means it will fallback to the original XBL binding definitions which
// are on the prototype.
delete outer.frameLoader;
delete outer[FRAME_LOADER];
// Invalidate outer's permanentKey so that SessionStore stops associating
// things that happen to the outer browser with the content inside in the
// inner browser.
@ -296,7 +298,7 @@ function copyPermanentKey(outer, inner) {
// no direct mechanism to do so. As a workaround, we wait until the one errant message
// has gone by, and then we copy the permanentKey after that, since the permanentKey is
// what SessionStore uses to identify each browser.
let outerMM = outer.frameLoader.messageManager;
let outerMM = outer[FRAME_LOADER].messageManager;
let onHistoryEntry = message => {
let history = message.data.data.history;
if (!history || !history.entries) {
@ -427,17 +429,17 @@ MessageManagerTunnel.prototype = {
],
get outerParentMM() {
if (!this.outer.frameLoader) {
if (!this.outer[FRAME_LOADER]) {
return null;
}
return this.outer.frameLoader.messageManager;
return this.outer[FRAME_LOADER].messageManager;
},
get outerChildMM() {
// This is only possible because we require the outer browser to be
// non-remote, so we're able to reach into its window and use the child
// side message manager there.
let docShell = this.outer.frameLoader.docShell;
let docShell = this.outer[FRAME_LOADER].docShell;
return docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIContentFrameMessageManager);
},