Bug 1288901 - Create ExtensionContext at document-element-inserted
MozReview-Commit-ID: 9ZQWmNjoAXA
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -593,29 +593,29 @@ var UninstallObserver = {
GlobalManager = {
// Map[extension ID -> Extension]. Determines which extension is
// responsible for content under a particular extension ID.
extensionMap: new Map(),
initialized: false,
init(extension) {
if (this.extensionMap.size == 0) {
- Services.obs.addObserver(this, "content-document-global-created", false);
+ Services.obs.addObserver(this, "document-element-inserted", false);
UninstallObserver.init();
this.initialized = true;
}
this.extensionMap.set(extension.id, extension);
},
uninit(extension) {
this.extensionMap.delete(extension.id);
if (this.extensionMap.size == 0 && this.initialized) {
- Services.obs.removeObserver(this, "content-document-global-created");
+ Services.obs.removeObserver(this, "document-element-inserted");
this.initialized = false;
}
},
getExtension(extensionId) {
return this.extensionMap.get(extensionId);
},
@@ -691,17 +691,22 @@ GlobalManager = {
},
hasListener(path, name, listener) {
return findPathInObject(schemaApi, path)[name].hasListener.call(null, listener);
},
};
Schemas.inject(dest, schemaWrapper);
},
- observe(contentWindow, topic, data) {
+ observe(document, topic, data) {
+ let contentWindow = document.defaultView;
+ if (!contentWindow) {
+ return;
+ }
+
let inject = (extension, context) => {
// We create two separate sets of bindings, one for the `chrome`
// global, and one for the `browser` global. The latter returns
// Promise objects if a callback is not passed, while the former
// does not.
let injectObject = (name, defaultCallback) => {
let browserObj = Cu.createObjectIn(contentWindow, {defineAs: name});
this.injectInObject(extension, context, defaultCallback, browserObj);
@@ -720,17 +725,16 @@ GlobalManager = {
}
// We don't inject privileged APIs if the addonId is null
// or doesn't exist.
if (!this.extensionMap.has(id)) {
return;
}
-
let docShell = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell);
let parentDocument = docShell.parent.QueryInterface(Ci.nsIDocShell)
.contentViewer.DOMDocument;
let browser = docShell.chromeEventHandler;
// If this is a sub-frame of the add-on manager, use that <browser>
@@ -744,19 +748,18 @@ GlobalManager = {
type = browser.getAttribute("webextension-view-type");
} else if (browser.classList.contains("inline-options-browser")) {
// Options pages are currently displayed inline, but in Chrome
// and in our UI mock-ups for a later milestone, they're
// pop-ups.
type = "popup";
}
-
let extension = this.extensionMap.get(id);
- let uri = contentWindow.document.documentURIObject;
+ let uri = document.documentURIObject;
let incognito = PrivateBrowsingUtils.isContentWindowPrivate(contentWindow);
let context = new ExtensionContext(extension, {type, contentWindow, uri, docShell, incognito});
inject(extension, context);
if (type == "background") {
this._initializeBackgroundPage(contentWindow);
}
--- a/toolkit/components/extensions/test/mochitest/test_ext_tab_teardown.html
+++ b/toolkit/components/extensions/test/mochitest/test_ext_tab_teardown.html
@@ -9,17 +9,17 @@
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
</head>
<body>
<script>
"use strict";
// Test for tabs opened using tabs.create and window.open
-function* runTabReloadAndCloseTest({extension, isInitiallyBlankUrl}) {
+function* runTabReloadAndCloseTest(extension) {
let chromeScript = SpecialPowers.loadChromeScript(
SimpleTest.getTestFileURL("file_teardown_test.js"));
yield chromeScript.promiseOneMessage("chromescript-startup");
function* getContextEvents() {
chromeScript.sendAsyncMessage("get-context-events");
let contextEvents = yield chromeScript.promiseOneMessage("context-events");
dump(JSON.stringify(contextEvents));
return contextEvents.filter(event => event.extensionId == extension.id);
@@ -32,27 +32,18 @@ function* runTabReloadAndCloseTest({exte
is(contextEvents.length, 1, "ExtensionContext change for opening a tab");
is(contextEvents[0].eventType, "load", "create ExtensionContext for tab");
is(contextEvents[0].url, extensionPageUrl,
"ExtensionContext URL after tab creation should be tab URL");
extension.sendMessage("reload extension page");
let extensionPageUrl2 = yield extension.awaitMessage("extension page loaded");
- // When the tab is opened with window.open, the initial URL happens to be
- // about:blank.
- if (isInitiallyBlankUrl) {
- is(extensionPageUrl, "about:blank",
- "The tab URL before reload should be about:blank");
- isnot(extensionPageUrl, extensionPageUrl2,
- "After a page reload the tab URL shouldn't be blank.");
- } else {
- is(extensionPageUrl, extensionPageUrl2,
- "The tab's URL is expected to not change after a page reload");
- }
+ is(extensionPageUrl, extensionPageUrl2,
+ "The tab's URL is expected to not change after a page reload");
contextEvents = yield* getContextEvents();
is(contextEvents.length, 2, "ExtensionContext change after tab reload");
is(contextEvents[0].eventType, "unload", "unload old ExtensionContext");
is(contextEvents[0].url, extensionPageUrl,
"ExtensionContext URL before reload should be tab URL");
is(contextEvents[1].eventType, "load", "create new ExtensionContext for tab");
is(contextEvents[1].url, extensionPageUrl2,
@@ -100,17 +91,17 @@ add_task(function* test_extension_page_t
"page.html": `<!DOCTYPE html><meta charset="utf-8"><script src="page.js"><\/script>`,
"page.js": `(${pageScript})();`,
},
};
let extension = ExtensionTestUtils.loadExtension(extensionData);
yield extension.startup();
- yield* runTabReloadAndCloseTest({extension});
+ yield* runTabReloadAndCloseTest(extension);
});
add_task(function* test_extension_page_window_open_reload_and_close() {
// This tests whether a context that is opened via window.open is properly
// disposed when the tab closes.
// The background page cannot use window.open (bugzil.la/1282021), so we open
// another extension page that manages the window.open-tab for testing.
function backgroundScript() {
@@ -131,38 +122,29 @@ add_task(function* test_extension_page_w
});
win.close();
}
});
browser.test.sendMessage("setup-intermediate-tab");
}
function pageScript() {
- if (performance.navigation.type === 0) { // TYPE_NAVIGATION
- // The ExtensionContext URL happens to be "about:blank" when the page is
- // loaded via window.open().
- browser.test.sendMessage("extension page loaded", "about:blank");
- } else if (performance.navigation.type === 1) { // TYPE_RELOAD
- browser.test.sendMessage("extension page loaded", document.URL);
- } else {
- browser.test.notifyFail(
- "Unexpected navigation type: " + performance.navigation.type);
- }
+ browser.test.sendMessage("extension page loaded", document.URL);
}
let extensionData = {
background: `(${backgroundScript})();`,
files: {
"page.html": `<!DOCTYPE html><meta charset="utf-8"><script src="page.js"><\/script>`,
"page.js": `(${pageScript})();`,
"window.open.html": `<!DOCTYPE html><meta charset="utf-8"><script src="window.open.js"><\/script>`,
"window.open.js": `(${windowOpenScript})();`,
},
};
let extension = ExtensionTestUtils.loadExtension(extensionData);
yield extension.startup();
yield extension.awaitMessage("setup-intermediate-tab");
- yield* runTabReloadAndCloseTest({extension, isInitiallyBlankUrl: true});
+ yield* runTabReloadAndCloseTest(extension);
});
</script>
</body>
</html>