Bug 1533948, change BrowserTabChild to inherit from JSWindowActor, r=mconley

This commit is contained in:
Neil Deakin
2019-06-11 09:05:33 -04:00
parent 5d9ecb0615
commit c1eb92539d
12 changed files with 223 additions and 130 deletions

View File

@@ -6,64 +6,66 @@
var EXPORTED_SYMBOLS = ["BrowserTabChild"]; var EXPORTED_SYMBOLS = ["BrowserTabChild"];
const {ActorChild} = ChromeUtils.import("resource://gre/modules/ActorChild.jsm");
ChromeUtils.defineModuleGetter(this, "E10SUtils", ChromeUtils.defineModuleGetter(this, "E10SUtils",
"resource://gre/modules/E10SUtils.jsm"); "resource://gre/modules/E10SUtils.jsm");
class BrowserTabChild extends ActorChild { class BrowserTabChild extends JSWindowActorChild {
constructor() {
super();
this.handledWindowCreated = false;
this.handledFirstPaint = false;
}
handleEvent(event) { handleEvent(event) {
switch (event.type) { switch (event.type) {
case "DOMWindowCreated": case "DOMWindowCreated": {
let loadContext = this.mm.docShell.QueryInterface(Ci.nsILoadContext); if (this.handledWindowCreated) {
return;
}
this.handledWindowCreated = true;
let context = this.manager.browsingContext;
let loadContext = context.docShell.QueryInterface(Ci.nsILoadContext);
let userContextId = loadContext.originAttributes.userContextId; let userContextId = loadContext.originAttributes.userContextId;
this.mm.sendAsyncMessage("Browser:WindowCreated", { userContextId }); this.sendAsyncMessage("Browser:WindowCreated", { userContextId });
break; break;
}
case "MozAfterPaint": case "MozAfterPaint":
this.mm.sendAsyncMessage("Browser:FirstPaint"); if (this.handledFirstPaint) {
return;
}
this.handledFirstPaint = true;
this.sendAsyncMessage("Browser:FirstPaint", {});
break; break;
case "MozDOMPointerLock:Entered": case "MozDOMPointerLock:Entered":
this.mm.sendAsyncMessage("PointerLock:Entered", { this.sendAsyncMessage("PointerLock:Entered", {
originNoSuffix: event.target.nodePrincipal.originNoSuffix, originNoSuffix: event.target.nodePrincipal.originNoSuffix,
}); });
break; break;
case "MozDOMPointerLock:Exited": case "MozDOMPointerLock:Exited":
this.mm.sendAsyncMessage("PointerLock:Exited"); this.sendAsyncMessage("PointerLock:Exited");
break; break;
} }
} }
switchDocumentDirection(window = this.content) {
// document.dir can also be "auto", in which case it won't change
if (window.document.dir == "ltr" || window.document.dir == "") {
window.document.dir = "rtl";
} else if (window.document.dir == "rtl") {
window.document.dir = "ltr";
}
for (let i = 0; i < window.frames.length; i++) {
this.switchDocumentDirection(window.frames[i]);
}
}
receiveMessage(message) { receiveMessage(message) {
switch (message.name) { let context = this.manager.browsingContext;
case "AllowScriptsToClose": let docShell = context.docShell;
this.content.windowUtils.allowScriptsToClose();
break;
switch (message.name) {
case "Browser:AppTab": case "Browser:AppTab":
if (this.docShell) { if (docShell) {
this.docShell.isAppTab = message.data.isAppTab; docShell.isAppTab = message.data.isAppTab;
} }
break; break;
case "Browser:HasSiblings": case "Browser:HasSiblings":
try { try {
let browserChild = this.docShell.QueryInterface(Ci.nsIInterfaceRequestor) let browserChild = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIBrowserChild); .getInterface(Ci.nsIBrowserChild);
let hasSiblings = message.data; let hasSiblings = message.data;
browserChild.hasSiblings = hasSiblings; browserChild.hasSiblings = hasSiblings;
@@ -78,8 +80,7 @@ class BrowserTabChild extends ActorChild {
* window (such as view-source) that has no session history, fall * window (such as view-source) that has no session history, fall
* back on using the web navigation's reload method. * back on using the web navigation's reload method.
*/ */
let webNav = docShell.QueryInterface(Ci.nsIWebNavigation);
let webNav = this.docShell.QueryInterface(Ci.nsIWebNavigation);
try { try {
if (webNav.sessionHistory) { if (webNav.sessionHistory) {
webNav = webNav.sessionHistory; webNav = webNav.sessionHistory;
@@ -89,23 +90,20 @@ class BrowserTabChild extends ActorChild {
let reloadFlags = message.data.flags; let reloadFlags = message.data.flags;
try { try {
E10SUtils.wrapHandlingUserInput(this.content, message.data.handlingUserInput, E10SUtils.wrapHandlingUserInput(this.document.defaultView,
message.data.handlingUserInput,
() => webNav.reload(reloadFlags)); () => webNav.reload(reloadFlags));
} catch (e) { } catch (e) {
} }
break; break;
case "MixedContent:ReenableProtection": case "MixedContent:ReenableProtection":
this.docShell.mixedContentChannel = null; docShell.mixedContentChannel = null;
break;
case "SwitchDocumentDirection":
this.switchDocumentDirection();
break; break;
case "UpdateCharacterSet": case "UpdateCharacterSet":
this.docShell.charset = message.data.value; docShell.charset = message.data.value;
this.docShell.gatherCharsetMenuTelemetry(); docShell.gatherCharsetMenuTelemetry();
break; break;
} }
} }

View File

@@ -0,0 +1,46 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
var EXPORTED_SYMBOLS = ["BrowserTabParent"];
class BrowserTabParent extends JSWindowActorParent {
receiveMessage(message) {
let browser = this.manager.browsingContext.embedderElement;
if (!browser) {
return; // Can happen sometimes if browser is being destroyed
}
let gBrowser = browser.ownerGlobal.gBrowser;
if (!gBrowser) {
// Note: gBrowser might be null because this message might be received
// from the extension process. There's still an embedderElement involved,
// but it's the one coming from dummy.xul.
// This should probably be fixed by adding support to specifying "group: 'browsers"
// in the registerWindowActor options/. See bug 1557118.
return;
}
switch (message.name) {
case "Browser:WindowCreated": {
gBrowser.announceWindowCreated(browser, message.data.userContextId);
break;
}
case "Browser:FirstPaint": {
browser.ownerGlobal.gBrowserInit._firstBrowserPaintDeferred.resolve();
break;
}
case "MozDOMPointerLock:Entered": {
browser.ownerGlobal.PointerLock.entered(message.data.originNoSuffix);
break;
}
case "MozDOMPointerLock:Exited":
browser.ownerGlobal.PointerLock.exited();
break;
}
}
}

View File

@@ -0,0 +1,30 @@
/* vim: set ts=2 sw=2 sts=2 et tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
var EXPORTED_SYMBOLS = ["SwitchDocumentDirectionChild"];
class SwitchDocumentDirectionChild extends JSWindowActorChild {
receiveMessage(message) {
if (message.name == "SwitchDocumentDirection") {
let docShell = this.manager.browsingContext.docShell;
let document = docShell.QueryInterface(Ci.nsIWebNavigation).document;
this.switchDocumentDirection(document);
}
}
switchDocumentDirection(document) {
// document.dir can also be "auto", in which case it won't change
if (document.dir == "ltr" || document.dir == "") {
document.dir = "rtl";
} else if (document.dir == "rtl") {
document.dir = "ltr";
}
for (let frame of document.defaultView.frames) {
this.switchDocumentDirection(frame.document);
}
}
}

View File

@@ -26,6 +26,7 @@ FINAL_TARGET_FILES.actors += [
'AboutReaderChild.jsm', 'AboutReaderChild.jsm',
'BlockedSiteChild.jsm', 'BlockedSiteChild.jsm',
'BrowserTabChild.jsm', 'BrowserTabChild.jsm',
'BrowserTabParent.jsm',
'ClickHandlerChild.jsm', 'ClickHandlerChild.jsm',
'ContentSearchChild.jsm', 'ContentSearchChild.jsm',
'ContextMenuChild.jsm', 'ContextMenuChild.jsm',
@@ -44,6 +45,7 @@ FINAL_TARGET_FILES.actors += [
'SearchTelemetryChild.jsm', 'SearchTelemetryChild.jsm',
'SubframeCrashChild.jsm', 'SubframeCrashChild.jsm',
'SubframeCrashParent.jsm', 'SubframeCrashParent.jsm',
'SwitchDocumentDirectionChild.jsm',
'URIFixupChild.jsm', 'URIFixupChild.jsm',
'WebRTCChild.jsm', 'WebRTCChild.jsm',
] ]

View File

@@ -224,24 +224,13 @@ var PointerlockFsWarning = {
}; };
var PointerLock = { var PointerLock = {
entered(originNoSuffix) {
PointerlockFsWarning.showPointerLock(originNoSuffix);
},
init() { exited() {
window.messageManager.addMessageListener("PointerLock:Entered", this); PointerlockFsWarning.close();
window.messageManager.addMessageListener("PointerLock:Exited", this); },
},
receiveMessage(aMessage) {
switch (aMessage.name) {
case "PointerLock:Entered": {
PointerlockFsWarning.showPointerLock(aMessage.data.originNoSuffix);
break;
}
case "PointerLock:Exited": {
PointerlockFsWarning.close();
break;
}
}
},
}; };
var FullScreen = { var FullScreen = {

View File

@@ -315,9 +315,7 @@
hidden="true" hidden="true"
label="&bidiSwitchPageDirectionItem.label;" label="&bidiSwitchPageDirectionItem.label;"
accesskey="&bidiSwitchPageDirectionItem.accesskey;" accesskey="&bidiSwitchPageDirectionItem.accesskey;"
oncommand="gBrowser.selectedBrowser oncommand="gBrowser.selectedBrowser.sendMessageToActor('SwitchDocumentDirection', {}, 'SwitchDocumentDirection', true);"/>
.messageManager
.sendAsyncMessage('SwitchDocumentDirection');"/>
</menupopup> </menupopup>
</menu> </menu>

View File

@@ -325,8 +325,7 @@ var gIdentityHandler = {
}, },
enableMixedContentProtection() { enableMixedContentProtection() {
gBrowser.selectedBrowser.messageManager.sendAsyncMessage( gBrowser.selectedBrowser.sendMessageToActor("MixedContent:ReenableProtection", {}, "BrowserTab");
"MixedContent:ReenableProtection", {});
BrowserReload(); BrowserReload();
PanelMultiView.hidePopup(this._identityPopup); PanelMultiView.hidePopup(this._identityPopup);
}, },

View File

@@ -1705,7 +1705,6 @@ var gBrowserInit = {
} }
FullScreen.init(); FullScreen.init();
PointerLock.init();
if (AppConstants.isPlatformAndVersionAtLeast("win", "10")) { if (AppConstants.isPlatformAndVersionAtLeast("win", "10")) {
MenuTouchModeObserver.init(); MenuTouchModeObserver.init();
@@ -1774,17 +1773,12 @@ var gBrowserInit = {
_setInitialFocus() { _setInitialFocus() {
let initiallyFocusedElement = document.commandDispatcher.focusedElement; let initiallyFocusedElement = document.commandDispatcher.focusedElement;
let firstBrowserPaintDeferred = {}; this._firstBrowserPaintDeferred = {};
firstBrowserPaintDeferred.promise = new Promise(resolve => { this._firstBrowserPaintDeferred.promise = new Promise(resolve => {
firstBrowserPaintDeferred.resolve = resolve; this._firstBrowserPaintDeferred.resolve = resolve;
}); });
let mm = window.messageManager; let mm = window.messageManager;
mm.addMessageListener("Browser:FirstPaint", function onFirstPaint() {
mm.removeMessageListener("Browser:FirstPaint", onFirstPaint);
firstBrowserPaintDeferred.resolve();
});
let initialBrowser = gBrowser.selectedBrowser; let initialBrowser = gBrowser.selectedBrowser;
mm.addMessageListener("Browser:FirstNonBlankPaint", mm.addMessageListener("Browser:FirstNonBlankPaint",
function onFirstNonBlankPaint() { function onFirstNonBlankPaint() {
@@ -1807,7 +1801,7 @@ var gBrowserInit = {
if (gBrowser.selectedBrowser.isRemoteBrowser) { if (gBrowser.selectedBrowser.isRemoteBrowser) {
// If the initial browser is remote, in order to optimize for first paint, // If the initial browser is remote, in order to optimize for first paint,
// we'll defer switching focus to that browser until it has painted. // we'll defer switching focus to that browser until it has painted.
firstBrowserPaintDeferred.promise.then(() => { this._firstBrowserPaintDeferred.promise.then(() => {
// If focus didn't move while we were waiting for first paint, we're okay // If focus didn't move while we were waiting for first paint, we're okay
// to move to the browser. // to move to the browser.
if (document.commandDispatcher.focusedElement == initiallyFocusedElement) { if (document.commandDispatcher.focusedElement == initiallyFocusedElement) {
@@ -3484,10 +3478,8 @@ function BrowserReloadWithFlags(reloadFlags) {
} }
function sendReloadMessage(tab) { function sendReloadMessage(tab) {
tab.linkedBrowser tab.linkedBrowser.sendMessageToActor("Browser:Reload",
.messageManager { flags: reloadFlags, handlingUserInput }, "BrowserTab");
.sendAsyncMessage("Browser:Reload",
{ flags: reloadFlags, handlingUserInput });
} }
} }

View File

@@ -1458,7 +1458,7 @@ nsContextMenu.prototype = {
}, },
switchPageDirection: function CM_switchPageDirection() { switchPageDirection: function CM_switchPageDirection() {
this.browser.messageManager.sendAsyncMessage("SwitchDocumentDirection"); gBrowser.selectedBrowser.sendMessageToActor("SwitchDocumentDirection", {}, "SwitchDocumentDirection", true);
}, },
mediaCommand: function CM_mediaCommand(command, data) { mediaCommand: function CM_mediaCommand(command, data) {

View File

@@ -53,7 +53,6 @@ window._gBrowser = {
this.selectedBrowser); this.selectedBrowser);
} }
messageManager.addMessageListener("RefreshBlocker:Blocked", this); messageManager.addMessageListener("RefreshBlocker:Blocked", this);
messageManager.addMessageListener("Browser:WindowCreated", this);
// To correctly handle keypresses for potential FindAsYouType, while // To correctly handle keypresses for potential FindAsYouType, while
// the tab's find bar is not yet initialized. // the tab's find bar is not yet initialized.
@@ -601,7 +600,7 @@ window._gBrowser = {
}, },
_notifyPinnedStatus(aTab) { _notifyPinnedStatus(aTab) {
this.getBrowserForTab(aTab).messageManager.sendAsyncMessage("Browser:AppTab", { isAppTab: aTab.pinned }); aTab.linkedBrowser.sendMessageToActor("Browser:AppTab", { isAppTab: aTab.pinned }, "BrowserTab");
let event = document.createEvent("Events"); let event = document.createEvent("Events");
event.initEvent(aTab.pinned ? "TabPinned" : "TabUnpinned", true, false); event.initEvent(aTab.pinned ? "TabPinned" : "TabUnpinned", true, false);
@@ -1780,7 +1779,7 @@ window._gBrowser = {
// crashed. // crashed.
tab.removeAttribute("crashed"); tab.removeAttribute("crashed");
} else { } else {
aBrowser.messageManager.sendAsyncMessage("Browser:AppTab", { isAppTab: tab.pinned }); aBrowser.sendMessageToActor("Browser:AppTab", { isAppTab: tab.pinned }, "BrowserTab");
// Register the new outerWindowID. // Register the new outerWindowID.
this._outerWindowIDBrowserMap.set(aBrowser.outerWindowID, aBrowser); this._outerWindowIDBrowserMap.set(aBrowser.outerWindowID, aBrowser);
@@ -1794,9 +1793,7 @@ window._gBrowser = {
this.getCachedFindBar(tab).browser = aBrowser; this.getCachedFindBar(tab).browser = aBrowser;
} }
tab.linkedBrowser tab.linkedBrowser.sendMessageToActor("Browser:HasSiblings", this.tabs.length > 1, "BrowserTab");
.messageManager
.sendAsyncMessage("Browser:HasSiblings", this.tabs.length > 1);
evt = document.createEvent("Events"); evt = document.createEvent("Events");
evt.initEvent("TabRemotenessChange", true, false); evt.initEvent("TabRemotenessChange", true, false);
@@ -2142,12 +2139,10 @@ window._gBrowser = {
// If we transitioned from one browser to two browsers, we need to set // If we transitioned from one browser to two browsers, we need to set
// hasSiblings=false on both the existing browser and the new browser. // hasSiblings=false on both the existing browser and the new browser.
if (this.tabs.length == 2) { if (this.tabs.length == 2) {
window.messageManager this.tabs[0].linkedBrowser.sendMessageToActor("Browser:HasSiblings", true, "BrowserTab");
.broadcastAsyncMessage("Browser:HasSiblings", true); this.tabs[1].linkedBrowser.sendMessageToActor("Browser:HasSiblings", true, "BrowserTab");
} else { } else {
aTab.linkedBrowser aTab.linkedBrowser.sendMessageToActor("Browser:HasSiblings", this.tabs.length > 1, "BrowserTab");
.messageManager
.sendAsyncMessage("Browser:HasSiblings", this.tabs.length > 1);
} }
var evt = new CustomEvent("TabBrowserInserted", { bubbles: true, detail: { insertedOnTabCreation: aInsertedOnTabCreation } }); var evt = new CustomEvent("TabBrowserInserted", { bubbles: true, detail: { insertedOnTabCreation: aInsertedOnTabCreation } });
@@ -3006,8 +3001,8 @@ window._gBrowser = {
if (this.tabs.length == 2) { if (this.tabs.length == 2) {
// We're closing one of our two open tabs, inform the other tab that its // We're closing one of our two open tabs, inform the other tab that its
// sibling is going away. // sibling is going away.
window.messageManager this.tabs[0].linkedBrowser.sendMessageToActor("Browser:HasSiblings", false, "BrowserTab");
.broadcastAsyncMessage("Browser:HasSiblings", false); this.tabs[1].linkedBrowser.sendMessageToActor("Browser:HasSiblings", false, "BrowserTab");
} }
if (aTab.linkedPanel) { if (aTab.linkedPanel) {
@@ -3475,6 +3470,20 @@ window._gBrowser = {
} }
}, },
announceWindowCreated(browser, userContextId) {
let tab = this.getTabForBrowser(browser);
if (tab && userContextId) {
ContextualIdentityService.telemetry(userContextId);
tab.setUserContextId(userContextId);
}
// We don't want to update the container icon and identifier if
// this is not the selected browser.
if (browser == gBrowser.selectedBrowser) {
updateUserContextUIIndicator();
}
},
reloadMultiSelectedTabs() { reloadMultiSelectedTabs() {
this.reloadTabs(this.selectedTabs); this.reloadTabs(this.selectedTabs);
}, },
@@ -4348,23 +4357,7 @@ window._gBrowser = {
return undefined; return undefined;
this._outerWindowIDBrowserMap.set(browser.outerWindowID, browser); this._outerWindowIDBrowserMap.set(browser.outerWindowID, browser);
browser.messageManager.sendAsyncMessage("Browser:AppTab", { isAppTab: tab.pinned }); browser.sendMessageToActor("Browser:AppTab", { isAppTab: tab.pinned }, "BrowserTab");
break;
}
case "Browser:WindowCreated":
{
let tab = this.getTabForBrowser(browser);
if (tab && data.userContextId) {
ContextualIdentityService.telemetry(data.userContextId);
tab.setUserContextId(data.userContextId);
}
// We don't want to update the container icon and identifier if
// this is not the selected browser.
if (browser == gBrowser.selectedBrowser) {
updateUserContextUIIndicator();
}
break; break;
} }
case "Findbar:Keypress": case "Findbar:Keypress":

View File

@@ -16,6 +16,29 @@ ChromeUtils.defineModuleGetter(this, "ActorManagerParent",
const PREF_PDFJS_ENABLED_CACHE_STATE = "pdfjs.enabledCache.state"; const PREF_PDFJS_ENABLED_CACHE_STATE = "pdfjs.enabledCache.state";
let ACTORS = { let ACTORS = {
BrowserTab: {
parent: {
moduleURI: "resource:///actors/BrowserTabParent.jsm",
},
child: {
moduleURI: "resource:///actors/BrowserTabChild.jsm",
events: {
"DOMWindowCreated": {},
"MozAfterPaint": {},
"MozDOMPointerLock:Entered": {},
"MozDOMPointerLock:Exited": {},
},
messages: [
"Browser:Reload",
"Browser:AppTab",
"Browser:HasSiblings",
"MixedContent:ReenableProtection",
"UpdateCharacterSet",
],
},
},
ContextMenu: { ContextMenu: {
parent: { parent: {
moduleURI: "resource:///actors/ContextMenuParent.jsm", moduleURI: "resource:///actors/ContextMenuParent.jsm",
@@ -31,6 +54,18 @@ let ACTORS = {
allFrames: true, allFrames: true,
}, },
SwitchDocumentDirection: {
child: {
moduleURI: "resource:///actors/SwitchDocumentDirectionChild.jsm",
messages: [
"SwitchDocumentDirection",
],
},
allFrames: true,
},
SubframeCrash: { SubframeCrash: {
parent: { parent: {
moduleURI: "resource:///actors/SubframeCrashParent.jsm", moduleURI: "resource:///actors/SubframeCrashParent.jsm",
@@ -99,30 +134,6 @@ let LEGACY_ACTORS = {
}, },
}, },
BrowserTab: {
child: {
module: "resource:///actors/BrowserTabChild.jsm",
group: "browsers",
events: {
"DOMWindowCreated": {once: true},
"MozAfterPaint": {once: true},
"MozDOMPointerLock:Entered": {},
"MozDOMPointerLock:Exited": {},
},
messages: [
"AllowScriptsToClose",
"Browser:AppTab",
"Browser:HasSiblings",
"Browser:Reload",
"MixedContent:ReenableProtection",
"SwitchDocumentDirection",
"UpdateCharacterSet",
],
},
},
ClickHandler: { ClickHandler: {
child: { child: {
module: "resource:///actors/ClickHandlerChild.jsm", module: "resource:///actors/ClickHandlerChild.jsm",

View File

@@ -599,7 +599,7 @@ class MozBrowser extends MozElements.MozElementMixin(XULFrameElement) {
set characterSet(val) { set characterSet(val) {
if (this.isRemoteBrowser) { if (this.isRemoteBrowser) {
this.messageManager.sendAsyncMessage("UpdateCharacterSet", { value: val }); this.sendMessageToActor("UpdateCharacterSet", { value: val }, "BrowserTab");
this._characterSet = val; this._characterSet = val;
} else { } else {
this.docShell.charset = val; this.docShell.charset = val;
@@ -1860,6 +1860,41 @@ class MozBrowser extends MozElements.MozElementMixin(XULFrameElement) {
this.docShell.getContentBlockingLog() : this.docShell.getContentBlockingLog() :
Promise.reject("docshell isn't available"); Promise.reject("docshell isn't available");
} }
// Send an asynchronous message to the remote child via an actor.
// Note: use this only for messages through an actor. For old-style
// messages, use the message manager. If 'all' is true, then send
// a message to all descendant processes.
sendMessageToActor(messageName, args, actorName, all) {
if (!this.frameLoader) {
return;
}
let windowGlobal = this.browsingContext.currentWindowGlobal;
if (!windowGlobal) {
// Workaround for bug 1523638 where about:blank is loaded in a tab.
if (messageName == "Browser:AppTab") {
setTimeout(() => { this.sendMessageToActor(messageName, args, actorName); }, 0);
}
return;
}
function sendToChildren(browsingContext, checkRoot) {
let windowGlobal = browsingContext.currentWindowGlobal;
if (windowGlobal && (!checkRoot || windowGlobal.isProcessRoot)) {
windowGlobal.getActor(actorName).sendAsyncMessage(messageName, args);
}
if (all) {
let contexts = browsingContext.getChildren();
for (let context of contexts) {
sendToChildren(context, true);
}
}
}
sendToChildren(this.browsingContext, false);
}
} }
MozXULElement.implementCustomInterface(MozBrowser, [Ci.nsIBrowser]); MozXULElement.implementCustomInterface(MozBrowser, [Ci.nsIBrowser]);