Bug 1593937 - Make the BrowsingContextTargetActor optionally follow the WindowGlobal lifecycle. r=jdescottes

The new `followWindowGlobalLifeCycle` argument and field makes the actor behaves like a WindowGlobalTargetActor and only care about the current global (and all its inner iframes, still).
But it ignores the previous/next document. We still uses the DebuggerProgressListener, but mostly for iframes.
will-navigate and navigate are irrelevant for this actor now.
The plan would be to eventually switch all codepaths to this WindowGlobalTargetActor and rename it.
For now, this would only be used for remoted iframes, only additional frame targets.
But not for top level document, nor top level target switching.

Differential Revision: https://phabricator.services.mozilla.com/D65521
This commit is contained in:
Alexandre Poirot 2020-04-30 07:59:28 +00:00
Родитель 9bb2b682ac
Коммит 734e59b63d
3 изменённых файлов: 75 добавлений и 11 удалений

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

@ -237,10 +237,25 @@ const browsingContextTargetPrototype = {
* *
* @param connection DevToolsServerConnection * @param connection DevToolsServerConnection
* The conection to the client. * The conection to the client.
* @param options Object
* Object with following attributes:
* - followWindowGlobalLifeCycle Boolean
* If true, the target actor will only inspect the current WindowGlobal (and its children windows).
* But won't inspect next document loaded in the same BrowsingContext.
* The actor will behave more like a WindowGlobalTarget rather than a BrowsingContextTarget.
* We may eventually switch everything to this, i.e. uses only WindowGlobalTarget.
* But for now, we restrict this behavior to remoted iframes.
* - doNotFireFrameUpdates Boolean
* If true, omit emitting `frameUpdate` events. This is only useful
* for the top level target, in order to populate the toolbox iframe selector dropdown.
* But we can avoid sending these RDP messages for any additional remote target.
*/ */
initialize: function(connection) { initialize: function(connection, options = {}) {
Actor.prototype.initialize.call(this, connection); Actor.prototype.initialize.call(this, connection);
this.followWindowGlobalLifeCycle = options.followWindowGlobalLifeCycle;
this.doNotFireFrameUpdates = options.doNotFireFrameUpdates;
// A map of actor names to actor instances provided by extensions. // A map of actor names to actor instances provided by extensions.
this._extraActors = {}; this._extraActors = {};
this._exited = false; this._exited = false;
@ -870,6 +885,12 @@ const browsingContextTargetPrototype = {
}, },
_notifyDocShellsUpdate(docshells) { _notifyDocShellsUpdate(docshells) {
// Only top level target uses frameUpdate in order to update the iframe dropdown.
// This may eventually be replaced by Target listening and target switching.
if (this.doNotFireFrameUpdates) {
return;
}
const windows = this._docShellsToWindows(docshells); const windows = this._docShellsToWindows(docshells);
// Do not send the `frameUpdate` event if the windows array is empty. // Do not send the `frameUpdate` event if the windows array is empty.
@ -887,6 +908,12 @@ const browsingContextTargetPrototype = {
}, },
_notifyDocShellDestroy(webProgress) { _notifyDocShellDestroy(webProgress) {
// Only top level target uses frameUpdate in order to update the iframe dropdown.
// This may eventually be replaced by Target listening and target switching.
if (this.doNotFireFrameUpdates) {
return;
}
webProgress = webProgress.QueryInterface(Ci.nsIWebProgress); webProgress = webProgress.QueryInterface(Ci.nsIWebProgress);
const id = webProgress.DOMWindow.windowUtils.outerWindowID; const id = webProgress.DOMWindow.windowUtils.outerWindowID;
this.emit("frameUpdate", { this.emit("frameUpdate", {
@ -900,6 +927,12 @@ const browsingContextTargetPrototype = {
}, },
_notifyDocShellDestroyAll() { _notifyDocShellDestroyAll() {
// Only top level target uses frameUpdate in order to update the iframe dropdown.
// This may eventually be replaced by Target listening and target switching.
if (this.doNotFireFrameUpdates) {
return;
}
this.emit("frameUpdate", { this.emit("frameUpdate", {
destroyAll: true, destroyAll: true,
}); });
@ -981,6 +1014,13 @@ const browsingContextTargetPrototype = {
this._attached = false; this._attached = false;
// When the target actor acts as a WindowGlobalTarget, the actor will be destroyed
// without having to send an RDP event. The parent process will receive a window-global-destroyed
// and report the target actor as destroyed via the Watcher actor.
if (this.followWindowGlobalLifeCycle) {
return true;
}
this.emit("tabDetached"); this.emit("tabDetached");
return true; return true;
@ -1391,12 +1431,16 @@ const browsingContextTargetPrototype = {
return; return;
} }
this.emit("tabNavigated", { // When the actor acts as a WindowGlobalTarget, will-navigate won't fired.
url: newURI, // Instead we will receive a new top level target with isTargetSwitching=true.
nativeConsoleAPI: true, if (!this.followWindowGlobalLifeCycle) {
state: "start", this.emit("tabNavigated", {
isFrameSwitching: isFrameSwitching, url: newURI,
}); nativeConsoleAPI: true,
state: "start",
isFrameSwitching: isFrameSwitching,
});
}
if (reset) { if (reset) {
this._setWindow(this._originalWindow); this._setWindow(this._originalWindow);
@ -1425,6 +1469,17 @@ const browsingContextTargetPrototype = {
return; return;
} }
// We may still significate when the document is done loading, via navigate.
// But as we no longer fire the "will-navigate", may be it is better to find
// other ways to get to our means.
// Listening to "navigate" is misleading as the document may already be loaded
// if we just opened the DevTools. So it is better to use "watch" pattern
// and instead have the actor either emit immediately resources as they are
// already available, or later on as the load progresses.
if (this.followWindowGlobalLifeCycle) {
return;
}
this.emit("tabNavigated", { this.emit("tabNavigated", {
url: this.url, url: this.url,
title: this.title, title: this.title,

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

@ -34,11 +34,17 @@ const frameTargetPrototype = extend({}, browsingContextTargetPrototype);
* *
* @param connection DevToolsServerConnection * @param connection DevToolsServerConnection
* The conection to the client. * The conection to the client.
* @param docShell * @param docShell nsIDocShell
* The |docShell| for the debugged frame. * The |docShell| for the debugged frame.
* @param options Object
* See BrowsingContextTargetActor.initialize doc.
*/ */
frameTargetPrototype.initialize = function(connection, docShell) { frameTargetPrototype.initialize = function(connection, docShell, options) {
BrowsingContextTargetActor.prototype.initialize.call(this, connection); BrowsingContextTargetActor.prototype.initialize.call(
this,
connection,
options
);
this.traits.reconfigure = false; this.traits.reconfigure = false;

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

@ -70,7 +70,10 @@ class DevToolsFrameChild extends JSWindowActorChild {
const connection = DevToolsServer.connectToParentWindowActor(prefix, this); const connection = DevToolsServer.connectToParentWindowActor(prefix, this);
// Create the actual target actor. // Create the actual target actor.
const targetActor = new FrameTargetActor(connection, this.docShell); const targetActor = new FrameTargetActor(connection, this.docShell, {
followWindowGlobalLifeCycle: true,
doNotFireFrameUpdates: true,
});
// Add the newly created actor to the connection pool. // Add the newly created actor to the connection pool.
const actorPool = new ActorPool(connection, "frame-child"); const actorPool = new ActorPool(connection, "frame-child");