Bug 1288901 - Create ExtensionContext at document-element-inserted draft
authorRob Wu <rob@robwu.nl>
Sun, 07 Aug 2016 19:10:01 -0700
changeset 400304 861a899d6f6df0616d7d1c610764c157ab5210c1
parent 400303 f7322064af47a27942c1772a46368e8391344549
child 528182 d331631d587b7edf546cf3208c051eeb8f2dc980
push id26123
push userbmo:rob@robwu.nl
push dateFri, 12 Aug 2016 23:04:18 +0000
bugs1288901
milestone51.0a1
Bug 1288901 - Create ExtensionContext at document-element-inserted MozReview-Commit-ID: 9ZQWmNjoAXA
toolkit/components/extensions/Extension.jsm
toolkit/components/extensions/test/mochitest/test_ext_tab_teardown.html
--- 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>