Bug 1450956 - Convert TabActor to protocol.js; r=ochameau
MozReview-Commit-ID: EOkuPfDB7rg
--- a/devtools/server/actors/chrome.js
+++ b/devtools/server/actors/chrome.js
@@ -2,21 +2,21 @@
* 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";
const { Ci } = require("chrome");
const Services = require("Services");
const { DebuggerServer } = require("../main");
-const { getChildDocShells, TabActor } = require("./tab");
+const { getChildDocShells, TabActor, tabPrototype } = require("./tab");
const makeDebugger = require("./utils/make-debugger");
const { extend } = require("devtools/shared/extend");
-const { ActorClassWithSpec, Actor } = require("devtools/shared/protocol");
+const { ActorClassWithSpec } = require("devtools/shared/protocol");
const { tabSpec } = require("devtools/shared/specs/tab");
/**
* Creates a TabActor for debugging all the chrome content in the
* current process. Most of the implementation is inherited from TabActor.
* ChromeActor is a child of RootActor, it can be instanciated via
* RootActor.getProcess request.
* ChromeActor exposes all tab actors via its form() request, like TabActor.
@@ -36,22 +36,20 @@ const { tabSpec } = require("devtools/sh
*/
/**
* Protocol.js expects only the prototype object, and does not maintain the prototype
* chain when it constructs the ActorClass. For this reason we are using `extend` to
* maintain the properties of TabActor.prototype
* */
-const chromePrototype = extend({}, TabActor.prototype);
+const chromePrototype = extend({}, tabPrototype);
chromePrototype.initialize = function(connection) {
- Actor.prototype.initialize.call(this, connection);
- TabActor.call(this, connection);
-
+ TabActor.prototype.initialize.call(this, connection);
// This creates a Debugger instance for chrome debugging all globals.
this.makeDebugger = makeDebugger.bind(null, {
findDebuggees: dbg => dbg.findAllGlobals(),
shouldAddNewGlobalAsDebuggee: () => true
});
// Ensure catching the creation of any new content docshell
this.listenForNewDocShells = true;
--- a/devtools/server/actors/content.js
+++ b/devtools/server/actors/content.js
@@ -1,19 +1,19 @@
/* 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 { Cr } = require("chrome");
-var { TabActor } = require("devtools/server/actors/tab");
+var { TabActor, tabPrototype } = require("devtools/server/actors/tab");
const { extend } = require("devtools/shared/extend");
-const { ActorClassWithSpec, Actor } = require("devtools/shared/protocol");
+const { ActorClassWithSpec } = require("devtools/shared/protocol");
const { tabSpec } = require("devtools/shared/specs/tab");
/**
* Tab actor for documents living in a child process.
*
* Depends on TabActor, defined in tab.js.
*/
@@ -32,22 +32,21 @@ const { tabSpec } = require("devtools/sh
*/
/**
* Protocol.js expects only the prototype object, and does not maintain the prototype
* chain when it constructs the ActorClass. For this reason we are using `extend` to
* maintain the properties of TabActor.prototype
* */
-const contentPrototype = extend({}, TabActor.prototype);
+const contentPrototype = extend({}, tabPrototype);
contentPrototype.initialize = function(connection, chromeGlobal) {
this._chromeGlobal = chromeGlobal;
- Actor.prototype.initialize.call(this, connection);
- TabActor.call(this, connection, chromeGlobal);
+ TabActor.prototype.initialize.call(this, connection, chromeGlobal);
this.traits.reconfigure = false;
this._sendForm = this._sendForm.bind(this);
this._chromeGlobal.addMessageListener("debug:form", this._sendForm);
Object.defineProperty(this, "docShell", {
value: this._chromeGlobal.docShell,
configurable: true
});
--- a/devtools/server/actors/tab.js
+++ b/devtools/server/actors/tab.js
@@ -18,21 +18,23 @@ const ChromeUtils = require("ChromeUtils
var {
ActorPool, createExtraActors, appendExtraActors
} = require("devtools/server/actors/common");
var { DebuggerServer } = require("devtools/server/main");
var DevToolsUtils = require("devtools/shared/DevToolsUtils");
var { assert } = DevToolsUtils;
var { TabSources } = require("./utils/TabSources");
var makeDebugger = require("./utils/make-debugger");
-const EventEmitter = require("devtools/shared/event-emitter");
const InspectorUtils = require("InspectorUtils");
const EXTENSION_CONTENT_JSM = "resource://gre/modules/ExtensionContent.jsm";
+const { ActorClassWithSpec, Actor } = require("devtools/shared/protocol");
+const { tabSpec } = require("devtools/shared/specs/tab");
+
loader.lazyRequireGetter(this, "ThreadActor", "devtools/server/actors/thread", true);
loader.lazyRequireGetter(this, "unwrapDebuggerObjectGlobal", "devtools/server/actors/thread", true);
loader.lazyRequireGetter(this, "WorkerActorList", "devtools/server/actors/worker-list", true);
loader.lazyImporter(this, "ExtensionContent", EXTENSION_CONTENT_JSM);
loader.lazyRequireGetter(this, "StyleSheetActor", "devtools/server/actors/stylesheets", true);
loader.lazyRequireGetter(this, "getSheetText", "devtools/server/actors/stylesheets", true);
@@ -79,172 +81,170 @@ exports.getChildDocShells = getChildDocS
* Browser-specific actors.
*/
function getInnerId(window) {
return window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
}
-/**
- * Creates a TabActor whose main goal is to manage lifetime and
- * expose the tab actors being registered via DebuggerServer.registerModule.
- * But also track the lifetime of the document being tracked.
- *
- * ### Main requests:
- *
- * `attach`/`detach` requests:
- * - start/stop document watching:
- * Starts watching for new documents and emits `tabNavigated` and
- * `frameUpdate` over RDP.
- * - retrieve the thread actor:
- * Instantiates a ThreadActor that can be later attached to in order to
- * debug JS sources in the document.
- * `switchToFrame`:
- * Change the targeted document of the whole TabActor, and its child tab actors
- * to an iframe or back to its original document.
- *
- * Most of the TabActor properties (like `chromeEventHandler` or `docShells`)
- * are meant to be used by the various child tab actors.
- *
- * ### RDP events:
- *
- * - `tabNavigated`:
- * Sent when the tab is about to navigate or has just navigated to
- * a different document.
- * This event contains the following attributes:
- * * url (string) The new URI being loaded.
- * * nativeConsoleAPI (boolean) `false` if the console API of the page has
- * been overridden (e.g. by Firebug),
- * `true` if the Gecko implementation is used.
- * * state (string) `start` if we just start requesting the new URL,
- * `stop` if the new URL is done loading.
- * * isFrameSwitching (boolean) Indicates the event is dispatched when
- * switching the TabActor context to
- * a different frame. When we switch to
- * an iframe, there is no document load.
- * The targeted document is most likely
- * going to be already done loading.
- * * title (string) The document title being loaded.
- * (sent only on state=stop)
- *
- * - `frameUpdate`:
- * Sent when there was a change in the child frames contained in the document
- * or when the tab's context was switched to another frame.
- * This event can have four different forms depending on the type of change:
- * * One or many frames are updated:
- * { frames: [{ id, url, title, parentID }, ...] }
- * * One frame got destroyed:
- * { frames: [{ id, destroy: true }]}
- * * All frames got destroyed:
- * { destroyAll: true }
- * * We switched the context of the TabActor to a specific frame:
- * { selected: #id }
- *
- * ### Internal, non-rdp events:
- * Various events are also dispatched on the TabActor itself that are not
- * related to RDP, so, not sent to the client. They all relate to the documents
- * tracked by the TabActor (its main targeted document, but also any of its
- * iframes).
- * - will-navigate
- * This event fires once navigation starts.
- * All pending user prompts are dealt with,
- * but it is fired before the first request starts.
- * - navigate
- * This event is fired once the document's readyState is "complete".
- * - window-ready
- * This event is fired in various distinct scenarios:
- * * When a new Window object is crafted, equivalent of `DOMWindowCreated`.
- * It is dispatched before any page script is executed.
- * * We will have already received a window-ready event for this window
- * when it was created, but we received a window-destroyed event when
- * it was frozen into the bfcache, and now the user navigated back to
- * this page, so it's now live again and we should resume handling it.
- * * For each existing document, when an `attach` request is received.
- * At this point scripts in the page will be already loaded.
- * * When `swapFrameLoaders` is used, such as with moving tabs between
- * windows or toggling Responsive Design Mode.
- * - window-destroyed
- * This event is fired in two cases:
- * * When the window object is destroyed, i.e. when the related document
- * is garbage collected. This can happen when the tab is closed or the
- * iframe is removed from the DOM.
- * It is equivalent of `inner-window-destroyed` event.
- * * When the page goes into the bfcache and gets frozen.
- * The equivalent of `pagehide`.
- * - changed-toplevel-document
- * This event fires when we switch the TabActor targeted document
- * to one of its iframes, or back to its original top document.
- * It is dispatched between window-destroyed and window-ready.
- * - stylesheet-added
- * This event is fired when a StyleSheetActor is created.
- * It contains the following attribute :
- * * actor (StyleSheetActor) The created actor.
- *
- * Note that *all* these events are dispatched in the following order
- * when we switch the context of the TabActor to a given iframe:
- * - will-navigate
- * - window-destroyed
- * - changed-toplevel-document
- * - window-ready
- * - navigate
- *
- * This class is subclassed by ContentActor and others.
- * Subclasses are expected to implement a getter for the docShell property.
- *
- * @param connection DebuggerServerConnection
- * The conection to the client.
- */
-function TabActor(connection) {
- // This usage of decorate should be removed in favor of using ES6 extends EventEmitter.
- // See Bug 1394816.
- EventEmitter.decorate(this);
+const tabPrototype = {
- this.conn = connection;
- this._tabActorPool = null;
- // A map of actor names to actor instances provided by extensions.
- this._extraActors = {};
- this._exited = false;
- this._sources = null;
-
- // Map of DOM stylesheets to StyleSheetActors
- this._styleSheetActors = new Map();
-
- this._shouldAddNewGlobalAsDebuggee =
- this._shouldAddNewGlobalAsDebuggee.bind(this);
-
- this.makeDebugger = makeDebugger.bind(null, {
- findDebuggees: () => {
- return this.windows.concat(this.webextensionsContentScriptGlobals);
- },
- shouldAddNewGlobalAsDebuggee: this._shouldAddNewGlobalAsDebuggee
- });
+ /**
+ * Creates a TabActor whose main goal is to manage lifetime and
+ * expose the tab actors being registered via DebuggerServer.registerModule.
+ * But also track the lifetime of the document being tracked.
+ *
+ * ### Main requests:
+ *
+ * `attach`/`detach` requests:
+ * - start/stop document watching:
+ * Starts watching for new documents and emits `tabNavigated` and
+ * `frameUpdate` over RDP.
+ * - retrieve the thread actor:
+ * Instantiates a ThreadActor that can be later attached to in order to
+ * debug JS sources in the document.
+ * `switchToFrame`:
+ * Change the targeted document of the whole TabActor, and its child tab actors
+ * to an iframe or back to its original document.
+ *
+ * Most of the TabActor properties (like `chromeEventHandler` or `docShells`)
+ * are meant to be used by the various child tab actors.
+ *
+ * ### RDP events:
+ *
+ * - `tabNavigated`:
+ * Sent when the tab is about to navigate or has just navigated to
+ * a different document.
+ * This event contains the following attributes:
+ * * url (string) The new URI being loaded.
+ * * nativeConsoleAPI (boolean) `false` if the console API of the page has
+ * been overridden (e.g. by Firebug),
+ * `true` if the Gecko implementation is used.
+ * * state (string) `start` if we just start requesting the new URL,
+ * `stop` if the new URL is done loading.
+ * * isFrameSwitching (boolean) Indicates the event is dispatched when
+ * switching the TabActor context to
+ * a different frame. When we switch to
+ * an iframe, there is no document load.
+ * The targeted document is most likely
+ * going to be already done loading.
+ * * title (string) The document title being loaded.
+ * (sent only on state=stop)
+ *
+ * - `frameUpdate`:
+ * Sent when there was a change in the child frames contained in the document
+ * or when the tab's context was switched to another frame.
+ * This event can have four different forms depending on the type of change:
+ * * One or many frames are updated:
+ * { frames: [{ id, url, title, parentID }, ...] }
+ * * One frame got destroyed:
+ * { frames: [{ id, destroy: true }]}
+ * * All frames got destroyed:
+ * { destroyAll: true }
+ * * We switched the context of the TabActor to a specific frame:
+ * { selected: #id }
+ *
+ * ### Internal, non-rdp events:
+ * Various events are also dispatched on the TabActor itself that are not
+ * related to RDP, so, not sent to the client. They all relate to the documents
+ * tracked by the TabActor (its main targeted document, but also any of its
+ * iframes).
+ * - will-navigate
+ * This event fires once navigation starts.
+ * All pending user prompts are dealt with,
+ * but it is fired before the first request starts.
+ * - navigate
+ * This event is fired once the document's readyState is "complete".
+ * - window-ready
+ * This event is fired in various distinct scenarios:
+ * * When a new Window object is crafted, equivalent of `DOMWindowCreated`.
+ * It is dispatched before any page script is executed.
+ * * We will have already received a window-ready event for this window
+ * when it was created, but we received a window-destroyed event when
+ * it was frozen into the bfcache, and now the user navigated back to
+ * this page, so it's now live again and we should resume handling it.
+ * * For each existing document, when an `attach` request is received.
+ * At this point scripts in the page will be already loaded.
+ * * When `swapFrameLoaders` is used, such as with moving tabs between
+ * windows or toggling Responsive Design Mode.
+ * - window-destroyed
+ * This event is fired in two cases:
+ * * When the window object is destroyed, i.e. when the related document
+ * is garbage collected. This can happen when the tab is closed or the
+ * iframe is removed from the DOM.
+ * It is equivalent of `inner-window-destroyed` event.
+ * * When the page goes into the bfcache and gets frozen.
+ * The equivalent of `pagehide`.
+ * - changed-toplevel-document
+ * This event fires when we switch the TabActor targeted document
+ * to one of its iframes, or back to its original top document.
+ * It is dispatched between window-destroyed and window-ready.
+ * - stylesheet-added
+ * This event is fired when a StyleSheetActor is created.
+ * It contains the following attribute :
+ * * actor (StyleSheetActor) The created actor.
+ *
+ * Note that *all* these events are dispatched in the following order
+ * when we switch the context of the TabActor to a given iframe:
+ * - will-navigate
+ * - window-destroyed
+ * - changed-toplevel-document
+ * - window-ready
+ * - navigate
+ *
+ * This class is subclassed by ContentActor and others.
+ * Subclasses are expected to implement a getter for the docShell property.
+ *
+ * @param connection DebuggerServerConnection
+ * The conection to the client.
+ */
+ initialize: function(connection) {
+ Actor.prototype.initialize.call(this, connection);
- // Flag eventually overloaded by sub classes in order to watch new docshells
- // Used by the ChromeActor to list all frames in the Browser Toolbox
- this.listenForNewDocShells = false;
+ this._tabActorPool = null;
+ // A map of actor names to actor instances provided by extensions.
+ this._extraActors = {};
+ this._exited = false;
+ this._sources = null;
+
+ // Map of DOM stylesheets to StyleSheetActors
+ this._styleSheetActors = new Map();
+
+ this._shouldAddNewGlobalAsDebuggee =
+ this._shouldAddNewGlobalAsDebuggee.bind(this);
+
+ this.makeDebugger = makeDebugger.bind(null, {
+ findDebuggees: () => {
+ return this.windows.concat(this.webextensionsContentScriptGlobals);
+ },
+ shouldAddNewGlobalAsDebuggee: this._shouldAddNewGlobalAsDebuggee
+ });
- this.traits = {
- reconfigure: true,
- // Supports frame listing via `listFrames` request and `frameUpdate` events
- // as well as frame switching via `switchToFrame` request
- frames: true,
- // Do not require to send reconfigure request to reset the document state
- // to what it was before using the TabActor
- noTabReconfigureOnClose: true,
- // Supports the logInPage request.
- logInPage: true,
- };
+ // Flag eventually overloaded by sub classes in order to watch new docshells
+ // Used by the ChromeActor to list all frames in the Browser Toolbox
+ this.listenForNewDocShells = false;
- this._workerActorList = null;
- this._workerActorPool = null;
- this._onWorkerActorListChanged = this._onWorkerActorListChanged.bind(this);
-}
+ this.traits = {
+ reconfigure: true,
+ // Supports frame listing via `listFrames` request and `frameUpdate` events
+ // as well as frame switching via `switchToFrame` request
+ frames: true,
+ // Do not require to send reconfigure request to reset the document state
+ // to what it was before using the TabActor
+ noTabReconfigureOnClose: true,
+ // Supports the logInPage request.
+ logInPage: true,
+ };
-TabActor.prototype = {
+ this._workerActorList = null;
+ this._workerActorPool = null;
+ this._onWorkerActorListChanged = this._onWorkerActorListChanged.bind(this);
+ },
+
traits: null,
// Optional console API listener options (e.g. used by the WebExtensionActor to
// filter console messages by addonID), set to an empty (no options) object by default.
consoleAPIListenerOptions: {},
// Optional TabSources filter function (e.g. used by the WebExtensionActor to filter
// sources by addonID), allow all sources by default.
@@ -487,16 +487,17 @@ TabActor.prototype = {
this._appendExtraActors(response);
return response;
},
/**
* Called when the actor is removed from the connection.
*/
destroy() {
+ Actor.prototype.destroy.call(this);
this.exit();
},
/**
* Called by the root actor when the underlying tab is closed.
*/
exit() {
if (this.exited) {
@@ -1455,34 +1456,18 @@ TabActor.prototype = {
if (this._tabActorPool.has(actor)) {
this._tabActorPool.removeActor(actor);
}
delete this._extraActors[name];
}
},
};
-/**
- * The request types this actor can handle.
- */
-TabActor.prototype.requestTypes = {
- "attach": TabActor.prototype.attach,
- "detach": TabActor.prototype.detach,
- "focus": TabActor.prototype.focus,
- "reload": TabActor.prototype.reload,
- "navigateTo": TabActor.prototype.navigateTo,
- "reconfigure": TabActor.prototype.reconfigure,
- "ensureCSSErrorReportingEnabled": TabActor.prototype.ensureCSSErrorReportingEnabled,
- "switchToFrame": TabActor.prototype.switchToFrame,
- "listFrames": TabActor.prototype.listFrames,
- "listWorkers": TabActor.prototype.listWorkers,
- "logInPage": TabActor.prototype.logInPage,
-};
-
-exports.TabActor = TabActor;
+exports.tabPrototype = tabPrototype;
+exports.TabActor = ActorClassWithSpec(tabSpec, tabPrototype);
/**
* The DebuggerProgressListener object is an nsIWebProgressListener which
* handles onStateChange events for the inspected browser. If the user tries to
* navigate away from a paused page, the listener makes sure that the debuggee
* is resumed before the navigation begins.
*
* @param TabActor aTabActor
--- a/devtools/server/actors/window.js
+++ b/devtools/server/actors/window.js
@@ -1,20 +1,20 @@
/* 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";
const { Ci } = require("chrome");
const Services = require("Services");
-const { TabActor } = require("./tab");
+const { TabActor, tabPrototype } = require("./tab");
const { extend } = require("devtools/shared/extend");
-const { ActorClassWithSpec, Actor } = require("devtools/shared/protocol");
+const { ActorClassWithSpec } = require("devtools/shared/protocol");
const { tabSpec } = require("devtools/shared/specs/tab");
/**
* Creates a WindowActor for debugging a single window, like a browser window in Firefox,
* but it can be used to reach any window in the process. (Currently this is parent
* process only because the root actor's `onGetWindow` doesn't try to cross process
* boundaries.) Both chrome and content windows are supported.
*
@@ -29,21 +29,20 @@ const { tabSpec } = require("devtools/sh
* maintain the properties of TabActor.prototype
*
* @param connection DebuggerServerConnection
* The connection to the client.
* @param window DOMWindow
* The window.
*/
-const windowPrototype = extend({}, TabActor.prototype);
+const windowPrototype = extend({}, tabPrototype);
windowPrototype.initialize = function(connection, window) {
- Actor.prototype.initialize.call(this, connection);
- TabActor.call(this, connection);
+ TabActor.prototype.initialize.call(this, connection);
let docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell);
Object.defineProperty(this, "docShell", {
value: docShell,
configurable: true
});
};
--- a/devtools/shared/specs/tab.js
+++ b/devtools/shared/specs/tab.js
@@ -104,12 +104,12 @@ const tabSpec = generateActorSpec({
logInPage: {
request: {
text: Option(0, "string"),
category: Option(0, "string"),
flags: Option(0, "string")
},
response: {}
}
- },
+ }
});
exports.tabSpec = tabSpec;