Bug 1368289: Simplify frameloader global metadata tagging. r=mixedpuppy

MozReview-Commit-ID: 1hgTtWysmya

--HG--
extra : rebase_source : 1ef46a61bd805e9bf0573ed22db005217afb5478
This commit is contained in:
Kris Maglione 2017-05-27 17:30:53 -07:00
Родитель e3153e78e2
Коммит b31e211aa2
4 изменённых файлов: 63 добавлений и 147 удалений

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

@ -237,7 +237,7 @@ class TabTracker extends TabTrackerBase {
// Copy the ID from the old tab to the new.
this.setId(nativeTab, this.getId(adoptedTab));
adoptedTab.linkedBrowser.messageManager.sendAsyncMessage("Extension:SetTabAndWindowId", {
adoptedTab.linkedBrowser.messageManager.sendAsyncMessage("Extension:SetFrameData", {
windowId: windowTracker.getId(nativeTab.ownerGlobal),
});
}

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

@ -28,6 +28,11 @@ XPCOMUtils.defineLazyModuleGetter(this, "Schemas",
XPCOMUtils.defineLazyModuleGetter(this, "WebNavigationFrames",
"resource://gre/modules/WebNavigationFrames.jsm");
XPCOMUtils.defineLazyGetter(
this, "processScript",
() => Cc["@mozilla.org/webextensions/extension-process-script;1"]
.getService().wrappedJSObject);
const CATEGORY_EXTENSION_SCRIPTS_ADDON = "webextension-scripts-addon";
const CATEGORY_EXTENSION_SCRIPTS_DEVTOOLS = "webextension-scripts-devtools";
@ -54,6 +59,10 @@ const {
var ExtensionPageChild;
function getFrameData(global) {
return processScript.getFrameData(global, true);
}
var apiManager = new class extends SchemaAPIManager {
constructor() {
super("addon");
@ -105,7 +114,7 @@ class ExtensionBaseContextChild extends BaseContext {
}
super(params.envType, extension);
let {viewType, uri, contentWindow, tabId} = params;
let {viewType = "tab", uri, contentWindow, tabId} = params;
this.viewType = viewType;
this.uri = uri || extension.baseURI;
@ -150,8 +159,8 @@ class ExtensionBaseContextChild extends BaseContext {
get windowId() {
if (["tab", "popup", "sidebar"].includes(this.viewType)) {
let globalView = ExtensionPageChild.contentGlobals.get(this.messageManager);
return globalView ? globalView.windowId : -1;
let frameData = getFrameData(this.messageManager);
return frameData ? frameData.windowId : -1;
}
return -1;
}
@ -294,101 +303,7 @@ defineLazyGetter(DevToolsContextChild.prototype, "childManager", function() {
return childManager;
});
// All subframes in a tab, background page, popup, etc. have the same view type.
// This class keeps track of such global state.
// Note that this is created even for non-extension tabs because at present we
// do not have a way to distinguish regular tabs from extension tabs at the
// initialization of a frame script.
class ContentGlobal {
/**
* @param {nsIContentFrameMessageManager} global The frame script's global.
*/
constructor(global) {
this.global = global;
// Unless specified otherwise assume that the extension page is in a tab,
// because the majority of all class instances are going to be a tab. Any
// special views (background page, extension popup) will immediately send an
// Extension:InitExtensionView message to change the viewType.
this.viewType = "tab";
this.tabId = -1;
this.windowId = -1;
this.initialized = false;
this.global.addMessageListener("Extension:InitExtensionView", this);
this.global.addMessageListener("Extension:SetTabAndWindowId", this);
}
uninit() {
this.global.removeMessageListener("Extension:InitExtensionView", this);
this.global.removeMessageListener("Extension:SetTabAndWindowId", this);
}
ensureInitialized() {
if (!this.initialized) {
// Request tab and window ID in case "Extension:InitExtensionView" is not
// sent (e.g. when `viewType` is "tab").
let reply = this.global.sendSyncMessage("Extension:GetTabAndWindowId");
this.handleSetTabAndWindowId(reply[0] || {});
}
return this;
}
receiveMessage({name, data}) {
switch (name) {
case "Extension:InitExtensionView":
// The view type is initialized once and then fixed.
this.global.removeMessageListener("Extension:InitExtensionView", this);
this.viewType = data.viewType;
// Force external links to open in tabs.
if (["popup", "sidebar"].includes(this.viewType)) {
this.global.docShell.isAppTab = true;
}
if (data.devtoolsToolboxInfo) {
this.devtoolsToolboxInfo = data.devtoolsToolboxInfo;
}
promiseEvent(this.global, "DOMContentLoaded", true).then(() => {
let windowId = getInnerWindowID(this.global.content);
let context = ExtensionPageChild.extensionContexts.get(windowId);
this.global.sendAsyncMessage("Extension:ExtensionViewLoaded",
{childId: context && context.childManager.id});
});
/* FALLTHROUGH */
case "Extension:SetTabAndWindowId":
this.handleSetTabAndWindowId(data);
break;
}
}
handleSetTabAndWindowId(data) {
let {tabId, windowId} = data;
if (tabId) {
// Tab IDs are not expected to change.
if (this.tabId !== -1 && tabId !== this.tabId) {
throw new Error("Attempted to change a tabId after it was set");
}
this.tabId = tabId;
}
if (windowId !== undefined) {
// Window IDs may change if a tab is moved to a different location.
// Note: This is the ID of the browser window for the extension API.
// Do not confuse it with the innerWindowID of DOMWindows!
this.windowId = windowId;
}
this.initialized = true;
}
}
ExtensionPageChild = {
// Map<nsIContentFrameMessageManager, ContentGlobal>
contentGlobals: new Map(),
// Map<innerWindowId, ExtensionPageContextChild>
extensionContexts: new Map(),
@ -403,23 +318,6 @@ ExtensionPageChild = {
Services.obs.addObserver(this, "inner-window-destroyed"); // eslint-ignore-line mozilla/balanced-listeners
},
init(global) {
if (!WebExtensionPolicy.isExtensionProcess) {
throw new Error("Cannot init extension page global in current process");
}
if (!this.contentGlobals.has(global)) {
this.contentGlobals.set(global, new ContentGlobal(global));
}
},
uninit(global) {
if (this.contentGlobals.has(global)) {
this.contentGlobals.get(global).uninit();
this.contentGlobals.delete(global);
}
},
observe(subject, topic, data) {
if (topic === "inner-window-destroyed") {
let windowId = subject.QueryInterface(Ci.nsISupportsPRUint64).data;
@ -428,6 +326,20 @@ ExtensionPageChild = {
}
},
expectViewLoad(global, viewType) {
if (["popup", "sidebar"].includes(viewType)) {
global.docShell.isAppTab = true;
}
promiseEvent(global, "DOMContentLoaded", true).then(() => {
let windowId = getInnerWindowID(global.content);
let context = this.extensionContexts.get(windowId);
global.sendAsyncMessage("Extension:ExtensionViewLoaded",
{childId: context && context.childManager.id});
});
},
/**
* Create a privileged context at document-element-inserted.
*
@ -456,7 +368,7 @@ ExtensionPageChild = {
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIContentFrameMessageManager);
let {viewType, tabId, devtoolsToolboxInfo} = this.contentGlobals.get(mm).ensureInitialized();
let {viewType, tabId, devtoolsToolboxInfo} = getFrameData(mm) || {};
let uri = contentWindow.document.documentURIObject;

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

@ -144,7 +144,7 @@ let apiManager = new class extends SchemaAPIManager {
if (sync) {
return result;
}
target.messageManager.sendAsyncMessage("Extension:SetTabAndWindowId", result);
target.messageManager.sendAsyncMessage("Extension:SetFrameData", result);
}
}
}
@ -282,7 +282,7 @@ GlobalManager = {
let {tabTracker} = apiManager.global;
Object.assign(data, tabTracker.getBrowserData(browser), additionalData);
browser.messageManager.sendAsyncMessage("Extension:InitExtensionView",
browser.messageManager.sendAsyncMessage("Extension:SetFrameData",
data);
}
},

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

@ -83,6 +83,9 @@ var ExtensionManager;
class ExtensionGlobal {
constructor(global) {
this.global = global;
this.global.addMessageListener("Extension:SetFrameData", this);
this.frameData = null;
MessageChannel.addListener(global, "Extension:Capture", this);
MessageChannel.addListener(global, "Extension:DetectLanguage", this);
@ -97,7 +100,27 @@ class ExtensionGlobal {
};
}
receiveMessage({target, messageName, recipient, data}) {
getFrameData(force = false) {
if (!this.frameData && force) {
this.frameData = this.global.sendSyncMessage("Extension:GetTabAndWindowId")[0];
}
return this.frameData;
}
receiveMessage({target, messageName, recipient, data, name}) {
switch (name) {
case "Extension:SetFrameData":
if (this.frameData) {
Object.assign(this.frameData, data);
} else {
this.frameData = data;
}
if (data.viewType && WebExtensionPolicy.isExtensionProcess) {
ExtensionPageChild.expectViewLoad(this.global, data.viewType);
}
return;
}
switch (messageName) {
case "Extension:Capture":
return ExtensionContent.handleExtensionCapture(this.global, data.width, data.height, data.options);
@ -138,41 +161,17 @@ DocumentManager = {
Services.obs.addObserver(this, "tab-content-frameloader-created"); // eslint-disable-line mozilla/balanced-listeners
},
extensionProcessInitialized: false,
initExtensionProcess() {
if (this.extensionProcessInitialized || !WebExtensionPolicy.isExtensionProcess) {
return;
}
this.extensionProcessInitialized = true;
for (let global of this.globals.keys()) {
ExtensionPageChild.init(global);
}
},
// Initialize a frame script global which extension contexts may be loaded
// into.
initGlobal(global) {
// Note: {once: true} does not work as expected here.
global.addEventListener("unload", event => { // eslint-disable-line mozilla/balanced-listeners
this.uninitGlobal(global);
});
this.globals.set(global, new ExtensionGlobal(global));
if (this.extensionProcessInitialized && WebExtensionPolicy.isExtensionProcess) {
ExtensionPageChild.init(global);
}
},
uninitGlobal(global) {
if (this.extensionProcessInitialized) {
ExtensionPageChild.uninit(global);
}
this.globals.delete(global);
// eslint-disable-next-line mozilla/balanced-listeners
global.addEventListener("unload", () => {
this.globals.delete(global);
});
},
initExtension(extension) {
this.initExtensionProcess();
this.injectExtensionScripts(extension);
},
@ -384,6 +383,11 @@ ExtensionProcessScript.prototype = {
get wrappedJSObject() { return this; },
getFrameData(global, force) {
let extGlobal = DocumentManager.globals.get(global);
return extGlobal && extGlobal.getFrameData(force);
},
initExtension(data, extension) {
return ExtensionManager.initExtensionPolicy(data, extension);
},