From 115e2ded44ec28c76ed2fab5b652be4eab6cba7a Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Mon, 14 Jul 2014 22:10:06 -0700 Subject: [PATCH] Bug 1031609 - Docshell rootTreeItem shim (r=mconley) --- .../addoncompat/RemoteAddonsChild.jsm | 2 + .../addoncompat/RemoteAddonsParent.jsm | 45 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/toolkit/components/addoncompat/RemoteAddonsChild.jsm b/toolkit/components/addoncompat/RemoteAddonsChild.jsm index 82ee89a8713..4fa64ede3d5 100644 --- a/toolkit/components/addoncompat/RemoteAddonsChild.jsm +++ b/toolkit/components/addoncompat/RemoteAddonsChild.jsm @@ -207,6 +207,8 @@ EventTargetChild.prototype = { let RemoteAddonsChild = { init: function(global) { + global.sendAsyncMessage("Addons:RegisterGlobal", {}, {global: global}); + // Return this so it gets rooted in the content script. return [new EventTargetChild(global)]; }, diff --git a/toolkit/components/addoncompat/RemoteAddonsParent.jsm b/toolkit/components/addoncompat/RemoteAddonsParent.jsm index 6e2711f3e56..484ed8d8765 100644 --- a/toolkit/components/addoncompat/RemoteAddonsParent.jsm +++ b/toolkit/components/addoncompat/RemoteAddonsParent.jsm @@ -404,8 +404,43 @@ EventTargetInterposition.methods.removeEventListener = target.removeEventListener(type, listener, useCapture); }; +// This interposition intercepts accesses to |rootTreeItem| on a child +// process docshell. In the child, each docshell is its own +// root. However, add-ons expect the root to be the chrome docshell, +// so we make that happen here. +let ContentDocShellTreeItemInterposition = new Interposition(); + +ContentDocShellTreeItemInterposition.getters.rootTreeItem = + function(addon, target) { + // The chrome global in the child. + let chromeGlobal = target.rootTreeItem + .QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIContentFrameMessageManager); + + // Map it to a element and window. + let browser = RemoteAddonsParent.globalToBrowser.get(chromeGlobal); + if (!browser) { + // Somehow we have a CPOW from the child, but it hasn't sent us + // its global yet. That shouldn't happen, but return null just + // in case. + return null; + } + + let chromeWin = browser.ownerDocument.defaultView; + + // Return that window's docshell. + return chromeWin.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsIDocShellTreeItem); + }; + let RemoteAddonsParent = { init: function() { + let mm = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageListenerManager); + mm.addMessageListener("Addons:RegisterGlobal", this); + + this.globalToBrowser = new WeakMap(); + this.browserToGlobal = new WeakMap(); }, getInterfaceInterpositions: function() { @@ -429,7 +464,17 @@ let RemoteAddonsParent = { } register("EventTarget", EventTargetInterposition); + register("ContentDocShellTreeItem", ContentDocShellTreeItemInterposition); return result; }, + + receiveMessage: function(msg) { + switch (msg.name) { + case "Addons:RegisterGlobal": + this.browserToGlobal.set(msg.target, msg.objects.global); + this.globalToBrowser.set(msg.objects.global, msg.target); + break; + } + } };