Bug 1353104 - use HiddenFrame.jsm to create frames for add-on sdk add-ons, r=kmag

MozReview-Commit-ID: CfR9xMPVr9H
This commit is contained in:
Gijs Kruitbosch
2017-04-03 21:25:16 +01:00
parent 47ed189c6f
commit d7c46bd33b
4 changed files with 101 additions and 55 deletions

View File

@@ -7,59 +7,75 @@ module.metadata = {
"stability": "experimental"
};
const { Ci, Cc } = require("chrome");
const { make: makeWindow, getHiddenWindow } = require("../window/utils");
const { create: makeFrame, getDocShell } = require("../frame/utils");
const { defer } = require("../core/promise");
const { Ci, Cc, Cu } = require("chrome");
const { when: unload } = require("../system/unload");
const cfxArgs = require("../test/options");
const prefs = require("../preferences/service");
var addonPrincipal = Cc["@mozilla.org/systemprincipal;1"].
createInstance(Ci.nsIPrincipal);
if (!prefs.get("extensions.usehiddenwindow", false)) {
const {HiddenFrame} = require("resource:///modules/HiddenFrame.jsm", {});
let hiddenFrame = new HiddenFrame();
exports.window = hiddenFrame.getWindow();
exports.ready = hiddenFrame.get();
var hiddenWindow = getHiddenWindow();
// Still destroy frame on unload to claim memory back early.
// NOTE: this doesn't seem to work and just doesn't get called. :-\
unload(function() {
hiddenFrame.destroy();
hiddenFrame = null;
});
} else {
const { make: makeWindow, getHiddenWindow } = require("../window/utils");
const { create: makeFrame, getDocShell } = require("../frame/utils");
const { defer } = require("../core/promise");
const cfxArgs = require("../test/options");
if (cfxArgs.parseable) {
console.info("hiddenWindow document.documentURI:" +
hiddenWindow.document.documentURI);
console.info("hiddenWindow document.readyState:" +
hiddenWindow.document.readyState);
var addonPrincipal = Cc["@mozilla.org/systemprincipal;1"].
createInstance(Ci.nsIPrincipal);
var hiddenWindow = getHiddenWindow();
if (cfxArgs.parseable) {
console.info("hiddenWindow document.documentURI:" +
hiddenWindow.document.documentURI);
console.info("hiddenWindow document.readyState:" +
hiddenWindow.document.readyState);
}
// Once Bug 565388 is fixed and shipped we'll be able to make invisible,
// permanent docShells. Meanwhile we create hidden top level window and
// use it's docShell.
var frame = makeFrame(hiddenWindow.document, {
nodeName: "iframe",
namespaceURI: "http://www.w3.org/1999/xhtml",
allowJavascript: true,
allowPlugins: true
})
var docShell = getDocShell(frame);
var eventTarget = docShell.chromeEventHandler;
// We need to grant docShell system principals in order to load XUL document
// from data URI into it.
docShell.createAboutBlankContentViewer(addonPrincipal);
// Get a reference to the DOM window of the given docShell and load
// such document into that would allow us to create XUL iframes, that
// are necessary for hidden frames etc..
var window = docShell.contentViewer.DOMDocument.defaultView;
window.location = "data:application/vnd.mozilla.xul+xml;charset=utf-8,<window/>";
// Create a promise that is delivered once add-on window is interactive,
// used by add-on runner to defer add-on loading until window is ready.
var { promise, resolve } = defer();
eventTarget.addEventListener("DOMContentLoaded", function(event) {
resolve();
}, {once: true});
exports.ready = promise;
exports.window = window;
// Still close window on unload to claim memory back early.
unload(function() {
window.close()
frame.remove();
});
}
// Once Bug 565388 is fixed and shipped we'll be able to make invisible,
// permanent docShells. Meanwhile we create hidden top level window and
// use it's docShell.
var frame = makeFrame(hiddenWindow.document, {
nodeName: "iframe",
namespaceURI: "http://www.w3.org/1999/xhtml",
allowJavascript: true,
allowPlugins: true
})
var docShell = getDocShell(frame);
var eventTarget = docShell.chromeEventHandler;
// We need to grant docShell system principals in order to load XUL document
// from data URI into it.
docShell.createAboutBlankContentViewer(addonPrincipal);
// Get a reference to the DOM window of the given docShell and load
// such document into that would allow us to create XUL iframes, that
// are necessary for hidden frames etc..
var window = docShell.contentViewer.DOMDocument.defaultView;
window.location = "data:application/vnd.mozilla.xul+xml;charset=utf-8,<window/>";
// Create a promise that is delivered once add-on window is interactive,
// used by add-on runner to defer add-on loading until window is ready.
var { promise, resolve } = defer();
eventTarget.addEventListener("DOMContentLoaded", function(event) {
resolve();
}, {once: true});
exports.ready = promise;
exports.window = window;
// Still close window on unload to claim memory back early.
unload(function() {
window.close()
frame.remove();
});

View File

@@ -8,8 +8,9 @@ module.metadata = {
};
const { deprecateFunction } = require("../util/deprecate");
const { Cc, Ci } = require("chrome");
const XMLHttpRequest = require("../addon/window").window.XMLHttpRequest;
const { Ci, Cu } = require("chrome");
Cu.importGlobalProperties(["XMLHttpRequest"]);
Object.defineProperties(XMLHttpRequest.prototype, {
mozBackgroundRequest: {

View File

@@ -13,7 +13,7 @@ const { Services } = require("resource://gre/modules/Services.jsm");
const { setTimeout } = require("../timers");
const { platform } = require("../system");
const { getMostRecentBrowserWindow, getOwnerBrowserWindow,
getHiddenWindow, getScreenPixelsPerCSSPixel } = require("../window/utils");
getScreenPixelsPerCSSPixel } = require("../window/utils");
const { create: createFrame, swapFrameLoaders, getDocShell } = require("../frame/utils");
const { window: addonWindow } = require("../addon/window");

View File

@@ -14,11 +14,27 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const XUL_PAGE = "data:application/vnd.mozilla.xul+xml;charset=utf-8,<window%20id='win'/>";
const gAllHiddenFrames = new WeakSet();
let cleanupRegistered = false;
function ensureCleanupRegistered() {
if (!cleanupRegistered) {
cleanupRegistered = true;
Services.obs.addObserver(function() {
for (let hiddenFrame of ChromeUtils.nondeterministicGetWeakSetKeys(gAllHiddenFrames)) {
hiddenFrame.destroy();
}
}, "xpcom-shutdown", false);
}
}
/**
* An hidden frame object. It takes care of creating a windowless browser and
* passing the window containing a blank XUL <window> back.
*/
function HiddenFrame() {}
function HiddenFrame() {
}
HiddenFrame.prototype = {
_frame: null,
@@ -41,6 +57,16 @@ HiddenFrame.prototype = {
return this._deferred.promise;
},
/**
* Fetch a sync ref to the window inside the frame (needed for the add-on SDK).
*/
getWindow() {
this.get();
this._browser.QueryInterface(Ci.nsIInterfaceRequestor);
return this._browser.getInterface(Ci.nsIDOMWindow);
},
destroy() {
if (this._browser) {
if (this._listener) {
@@ -51,14 +77,17 @@ HiddenFrame.prototype = {
this._frame = null;
this._deferred = null;
gAllHiddenFrames.delete(this);
this._browser.close();
this._browser = null;
}
},
_create() {
ensureCleanupRegistered();
this._browser = Services.appShell.createWindowlessBrowser(true);
this._browser.QueryInterface(Ci.nsIInterfaceRequestor);
gAllHiddenFrames.add(this);
this._webProgress = this._browser.getInterface(Ci.nsIWebProgress);
this._listener = {
QueryInterface: XPCOMUtils.generateQI([