Bug 1059308 - Make frame selection button to work in browser toolbox. r=jryans,past

This commit is contained in:
Alexandre Poirot 2015-03-04 05:47:00 +01:00
Родитель 2b002a6748
Коммит 69947869b3
20 изменённых файлов: 468 добавлений и 303 удалений

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

@ -178,6 +178,11 @@ let RemoteDebugger = {
let restrictPrivileges = Services.prefs.getBoolPref("devtools.debugger.forbid-certified-apps"); let restrictPrivileges = Services.prefs.getBoolPref("devtools.debugger.forbid-certified-apps");
DebuggerServer.addBrowserActors("navigator:browser", restrictPrivileges); DebuggerServer.addBrowserActors("navigator:browser", restrictPrivileges);
// Allow debugging of chrome for any process
if (!restrictPrivileges) {
DebuggerServer.allowChromeProcess = true;
}
/** /**
* Construct a root actor appropriate for use in a server running in B2G. * Construct a root actor appropriate for use in a server running in B2G.
* The returned root actor respects the factories registered with * The returned root actor respects the factories registered with

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

@ -110,6 +110,7 @@ devtoolsCommandlineHandler.prototype = {
let debuggerServer = serverLoader.DebuggerServer; let debuggerServer = serverLoader.DebuggerServer;
debuggerServer.init(); debuggerServer.init();
debuggerServer.addBrowserActors(); debuggerServer.addBrowserActors();
debuggerServer.allowChromeProcess = true;
let listener = debuggerServer.createListener(); let listener = debuggerServer.createListener();
listener.portOrPath = portOrPath; listener.portOrPath = portOrPath;

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

@ -116,29 +116,31 @@ BrowserToolboxProcess.prototype = {
* Initializes the debugger server. * Initializes the debugger server.
*/ */
_initServer: function() { _initServer: function() {
if (this.debuggerServer) {
dumpn("The chrome toolbox server is already running.");
return;
}
dumpn("Initializing the chrome toolbox server."); dumpn("Initializing the chrome toolbox server.");
if (!this.loader) { // Create a separate loader instance, so that we can be sure to receive a
// Create a separate loader instance, so that we can be sure to receive a // separate instance of the DebuggingServer from the rest of the devtools.
// separate instance of the DebuggingServer from the rest of the devtools. // This allows us to safely use the tools against even the actors and
// This allows us to safely use the tools against even the actors and // DebuggingServer itself, especially since we can mark this loader as
// DebuggingServer itself, especially since we can mark this loader as // invisible to the debugger (unlike the usual loader settings).
// invisible to the debugger (unlike the usual loader settings). this.loader = new DevToolsLoader();
this.loader = new DevToolsLoader(); this.loader.invisibleToDebugger = true;
this.loader.invisibleToDebugger = true; this.loader.main("devtools/server/main");
this.loader.main("devtools/server/main"); this.debuggerServer = this.loader.DebuggerServer;
this.debuggerServer = this.loader.DebuggerServer; dumpn("Created a separate loader instance for the DebuggerServer.");
dumpn("Created a separate loader instance for the DebuggerServer.");
// Forward interesting events. // Forward interesting events.
this.debuggerServer.on("connectionchange", this.emit.bind(this)); this.debuggerServer.on("connectionchange", this.emit.bind(this));
}
if (!this.debuggerServer.initialized) { this.debuggerServer.init();
this.debuggerServer.init(); this.debuggerServer.addBrowserActors();
this.debuggerServer.addBrowserActors(); this.debuggerServer.allowChromeProcess = true;
dumpn("initialized and added the browser actors for the DebuggerServer."); dumpn("initialized and added the browser actors for the DebuggerServer.");
}
let chromeDebuggingPort = let chromeDebuggingPort =
Services.prefs.getIntPref("devtools.debugger.chrome-debugging-port"); Services.prefs.getIntPref("devtools.debugger.chrome-debugging-port");

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

@ -129,11 +129,19 @@ let onConnectionReady = Task.async(function*(aType, aTraits) {
let gParent = document.getElementById("globalActors"); let gParent = document.getElementById("globalActors");
// Build the Remote Process button // Build the Remote Process button
if (Object.keys(globals).length > 1) { // If Fx<37, tab actors were used to be exposed on RootActor
// but in Fx>=37, chrome is debuggable via attachProcess() and ChromeActor
if (globals.consoleActor || gClient.mainRoot.traits.allowChromeProcess) {
let a = document.createElement("a"); let a = document.createElement("a");
a.onclick = function() { a.onclick = function() {
openToolbox(globals, true); if (gClient.mainRoot.traits.allowChromeProcess) {
gClient.attachProcess()
.then(aResponse => {
openToolbox(aResponse.form, true);
});
} else if (globals.consoleActor) {
openToolbox(globals, true, "webconsole", false);
}
} }
a.title = a.textContent = window.l10n.GetStringFromName("mainProcess"); a.title = a.textContent = window.l10n.GetStringFromName("mainProcess");
a.className = "remote-process"; a.className = "remote-process";

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

@ -697,6 +697,7 @@ let gDevToolsBrowser = {
DebuggerServer.init(); DebuggerServer.init();
DebuggerServer.addBrowserActors(); DebuggerServer.addBrowserActors();
} }
DebuggerServer.allowChromeProcess = true;
let transport = DebuggerServer.connectPipe(); let transport = DebuggerServer.connectPipe();
let client = new DebuggerClient(transport); let client = new DebuggerClient(transport);

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

@ -41,7 +41,9 @@ let connect = Task.async(function*() {
openToolbox({ form: addonActor, chrome: true, isTabActor: false }); openToolbox({ form: addonActor, chrome: true, isTabActor: false });
}); });
} else { } else {
gClient.listTabs(openToolbox); gClient.attachProcess().then(aResponse => {
openToolbox({ form: aResponse.form, chrome: true });
});
} }
}); });
}); });
@ -52,6 +54,7 @@ function setPrefDefaults() {
Services.prefs.setBoolPref("devtools.profiler.ui.show-platform-data", true); Services.prefs.setBoolPref("devtools.profiler.ui.show-platform-data", true);
Services.prefs.setBoolPref("browser.devedition.theme.showCustomizeButton", false); Services.prefs.setBoolPref("browser.devedition.theme.showCustomizeButton", false);
Services.prefs.setBoolPref("devtools.inspector.showAllAnonymousContent", true); Services.prefs.setBoolPref("devtools.inspector.showAllAnonymousContent", true);
Services.prefs.setBoolPref("browser.dom.window.dump.enabled", true);
} }
window.addEventListener("load", function() { window.addEventListener("load", function() {

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

@ -2152,16 +2152,17 @@ ScratchpadWindow.prototype = Heritage.extend(ScratchpadTab.prototype, {
DebuggerServer.init(); DebuggerServer.init();
DebuggerServer.addBrowserActors(); DebuggerServer.addBrowserActors();
} }
DebuggerServer.allowChromeProcess = true;
let client = new DebuggerClient(DebuggerServer.connectPipe()); let client = new DebuggerClient(DebuggerServer.connectPipe());
client.connect(() => { client.connect(() => {
client.listTabs(aResponse => { client.attachProcess().then(aResponse => {
if (aResponse.error) { if (aResponse.error) {
reportError("listTabs", aResponse); reportError("listTabs", aResponse);
deferred.reject(aResponse); deferred.reject(aResponse);
} }
else { else {
deferred.resolve({ form: aResponse, client: client }); deferred.resolve({ form: aResponse.form, client: client });
} }
}); });
}); });

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

@ -187,22 +187,16 @@ HUD_SERVICE.prototype =
DebuggerServer.init(); DebuggerServer.init();
DebuggerServer.addBrowserActors(); DebuggerServer.addBrowserActors();
} }
DebuggerServer.allowChromeProcess = true;
let client = new DebuggerClient(DebuggerServer.connectPipe()); let client = new DebuggerClient(DebuggerServer.connectPipe());
client.connect(() => client.connect(() => {
client.listTabs((aResponse) => { client.attachProcess().then(aResponse => {
// Add Global Process debugging... // Set chrome:false in order to attach to the target
let globals = Cu.cloneInto(aResponse, {}); // (i.e. send an `attach` request to the chrome actor)
delete globals.tabs; deferred.resolve({ form: aResponse.form, client: client, chrome: false });
delete globals.selected; }, deferred.reject);
// ...only if there are appropriate actors (a 'from' property will });
// always be there).
if (Object.keys(globals).length > 1) {
deferred.resolve({ form: globals, client: client, chrome: true });
} else {
deferred.reject("Global console not found!");
}
}));
return deferred.promise; return deferred.promise;
} }
@ -210,13 +204,7 @@ HUD_SERVICE.prototype =
let target; let target;
function getTarget(aConnection) function getTarget(aConnection)
{ {
let options = { return devtools.TargetFactory.forRemoteTab(aConnection);
form: aConnection.form,
client: aConnection.client,
chrome: true,
};
return devtools.TargetFactory.forRemoteTab(options);
} }
function openWindow(aTarget) function openWindow(aTarget)
@ -241,12 +229,12 @@ HUD_SERVICE.prototype =
} }
connect().then(getTarget).then(openWindow).then((aWindow) => { connect().then(getTarget).then(openWindow).then((aWindow) => {
this.openBrowserConsole(target, aWindow, aWindow) return this.openBrowserConsole(target, aWindow, aWindow)
.then((aBrowserConsole) => { .then((aBrowserConsole) => {
this._browserConsoleDefer.resolve(aBrowserConsole); this._browserConsoleDefer.resolve(aBrowserConsole);
this._browserConsoleDefer = null; this._browserConsoleDefer = null;
}) })
}, console.error); }, console.error.bind(console));
return this._browserConsoleDefer.promise; return this._browserConsoleDefer.promise;
}, },
@ -640,10 +628,13 @@ WebConsole.prototype = {
this._destroyer = promise.defer(); this._destroyer = promise.defer();
let popupset = this.mainPopupSet; // The document may already be removed
let panels = popupset.querySelectorAll("panel[hudId=" + this.hudId + "]"); if (this.chromeUtilsWindow && this.mainPopupSet) {
for (let panel of panels) { let popupset = this.mainPopupSet;
panel.hidePopup(); let panels = popupset.querySelectorAll("panel[hudId=" + this.hudId + "]");
for (let panel of panels) {
panel.hidePopup();
}
} }
let onDestroy = function WC_onDestroyUI() { let onDestroy = function WC_onDestroyUI() {

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

@ -440,7 +440,11 @@ WebConsoleFrame.prototype = {
* @type boolean * @type boolean
*/ */
get persistLog() { get persistLog() {
return Services.prefs.getBoolPref(PREF_PERSISTLOG); // For the browser console, we receive tab navigation
// when the original top level window we attached to is closed,
// but we don't want to reset console history and just switch to
// the next available window.
return this.owner._browserConsole || Services.prefs.getBoolPref(PREF_PERSISTLOG);
}, },
/** /**
@ -3426,7 +3430,7 @@ JSTerm.prototype = {
let selectedNodeActor = null; let selectedNodeActor = null;
let inspectorSelection = this.hud.owner.getInspectorSelection(); let inspectorSelection = this.hud.owner.getInspectorSelection();
if (inspectorSelection) { if (inspectorSelection && inspectorSelection.nodeFront) {
selectedNodeActor = inspectorSelection.nodeFront.actorID; selectedNodeActor = inspectorSelection.nodeFront.actorID;
} }

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

@ -941,9 +941,9 @@ let UI = {
this.toolboxPromise = null; this.toolboxPromise = null;
return toolboxPromise.then(toolbox => { return toolboxPromise.then(toolbox => {
return toolbox.destroy(); return toolbox.destroy();
}).catch(console.error) }).then(null, console.error)
.then(() => this._closeToolboxUI()) .then(() => this._closeToolboxUI())
.catch(console.error); .then(null, console.error);
} }
return promise.resolve(); return promise.resolve();
}, },

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

@ -217,11 +217,25 @@ let AppManager = exports.AppManager = {
getTarget: function() { getTarget: function() {
if (this.selectedProject.type == "mainProcess") { if (this.selectedProject.type == "mainProcess") {
return devtools.TargetFactory.forRemoteTab({ // Fx >=37 exposes a ChromeActor to debug the main process
form: this._listTabsResponse, if (this.connection.client.mainRoot.traits.allowChromeProcess) {
client: this.connection.client, return this.connection.client.attachProcess()
chrome: true .then(aResponse => {
}); return devtools.TargetFactory.forRemoteTab({
form: aResponse.form,
client: this.connection.client,
chrome: true
});
});
} else {
// Fx <37 exposes tab actors on the root actor
return devtools.TargetFactory.forRemoteTab({
form: this._listTabsResponse,
client: this.connection.client,
chrome: true,
isTabActor: false
});
}
} }
if (this.selectedProject.type == "tab") { if (this.selectedProject.type == "tab") {
@ -414,8 +428,12 @@ let AppManager = exports.AppManager = {
}, },
isMainProcessDebuggable: function() { isMainProcessDebuggable: function() {
return this._listTabsResponse && // Fx <37 exposes chrome tab actors on RootActor
this._listTabsResponse.consoleActor; // Fx >=37 exposes a dedicated actor via attachProcess request
return this.connection.client &&
this.connection.client.mainRoot.traits.allowChromeProcess ||
(this._listTabsResponse &&
this._listTabsResponse.consoleActor);
}, },
get deviceFront() { get deviceFront() {

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

@ -575,6 +575,7 @@ let gLocalRuntime = {
DebuggerServer.init(); DebuggerServer.init();
DebuggerServer.addBrowserActors(); DebuggerServer.addBrowserActors();
} }
DebuggerServer.allowChromeProcess = true;
connection.host = null; // Force Pipe transport connection.host = null; // Force Pipe transport
connection.port = null; connection.port = null;
connection.connect(); connection.connect();

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

@ -7416,6 +7416,7 @@ var RemoteDebugger = {
DebuggerServer.init(); DebuggerServer.init();
DebuggerServer.addBrowserActors(); DebuggerServer.addBrowserActors();
DebuggerServer.registerModule("resource://gre/modules/dbg-browser-actors.js"); DebuggerServer.registerModule("resource://gre/modules/dbg-browser-actors.js");
DebuggerServer.allowChromeProcess = true;
} }
let pathOrPort = this._getPath(); let pathOrPort = this._getPath();

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

@ -624,14 +624,17 @@ DebuggerClient.prototype = {
/** /**
* Attach to a process in order to get the form of a ChildProcessActor. * Attach to a process in order to get the form of a ChildProcessActor.
* *
* @param string aId * @param number aId
* The ID for the process to attach (returned by `listProcesses`). * The ID for the process to attach (returned by `listProcesses`).
* Connected to the main process if omitted, or is 0.
*/ */
attachProcess: function (aId) { attachProcess: function (aId) {
let packet = { let packet = {
to: 'root', to: "root",
type: 'attachProcess', type: "attachProcess"
id: aId }
if (typeof(aId) == "number") {
packet.id = aId;
} }
return this.request(packet); return this.request(packet);
}, },

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

@ -0,0 +1,185 @@
/* 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 { DebuggerServer } = require("../main");
const { getChildDocShells, TabActor } = require("./webbrowser");
const makeDebugger = require("./utils/make-debugger");
/**
* 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.attachProcess request.
* ChromeActor exposes all tab actors via its form() request, like TabActor.
*
* History lecture:
* All tab actors used to also be registered as global actors,
* so that the root actor was also exposing tab actors for the main process.
* Tab actors ended up having RootActor as parent actor,
* but more and more features of the tab actors were relying on TabActor.
* So we are now exposing a process actor that offers the same API as TabActor
* by inheriting its functionality.
* Global actors are now only the actors that are meant to be global,
* and are no longer related to any specific scope/document.
*
* @param aConnection DebuggerServerConnection
* The connection to the client.
*/
function ChromeActor(aConnection) {
TabActor.call(this, aConnection);
// 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;
// Defines the default docshell selected for the tab actor
let window = Services.wm.getMostRecentWindow(DebuggerServer.chromeWindowType);
// Default to any available top level window if there is no expected window
// (for example when we open firefox with -webide argument)
if (!window) {
window = Services.wm.getMostRecentWindow(null);
}
// On xpcshell, there is no window/docshell
let docShell = window ? window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell)
: null;
Object.defineProperty(this, "docShell", {
value: docShell,
configurable: true
});
}
exports.ChromeActor = ChromeActor;
ChromeActor.prototype = Object.create(TabActor.prototype);
ChromeActor.prototype.constructor = ChromeActor;
ChromeActor.prototype.isRootActor = true;
/**
* Getter for the list of all docshells in this tabActor
* @return {Array}
*/
Object.defineProperty(ChromeActor.prototype, "docShells", {
get: function () {
// Iterate over all top-level windows and all their docshells.
let docShells = [];
let e = Services.ww.getWindowEnumerator();
while (e.hasMoreElements()) {
let window = e.getNext();
let docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
docShells = docShells.concat(getChildDocShells(docShell));
}
return docShells;
}
});
ChromeActor.prototype.observe = function(aSubject, aTopic, aData) {
TabActor.prototype.observe.call(this, aSubject, aTopic, aData);
if (!this.attached) {
return;
}
if (aTopic == "chrome-webnavigation-create") {
aSubject.QueryInterface(Ci.nsIDocShell);
this._onDocShellCreated(aSubject);
} else if (aTopic == "chrome-webnavigation-destroy") {
this._onDocShellDestroy(aSubject);
}
}
ChromeActor.prototype._attach = function() {
if (this.attached) {
return false;
}
TabActor.prototype._attach.call(this);
// Listen for any new/destroyed chrome docshell
Services.obs.addObserver(this, "chrome-webnavigation-create", false);
Services.obs.addObserver(this, "chrome-webnavigation-destroy", false);
// Iterate over all top-level windows.
let docShells = [];
let e = Services.ww.getWindowEnumerator();
while (e.hasMoreElements()) {
let window = e.getNext();
let docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
if (docShell == this.docShell) {
continue;
}
this._progressListener.watch(docShell);
}
};
ChromeActor.prototype._detach = function() {
if (!this.attached) {
return false;
}
Services.obs.removeObserver(this, "chrome-webnavigation-create");
Services.obs.removeObserver(this, "chrome-webnavigation-destroy");
// Iterate over all top-level windows.
let docShells = [];
let e = Services.ww.getWindowEnumerator();
while (e.hasMoreElements()) {
let window = e.getNext();
let docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
if (docShell == this.docShell) {
continue;
}
this._progressListener.unwatch(docShell);
}
TabActor.prototype._detach.call(this);
};
/* ThreadActor hooks. */
/**
* Prepare to enter a nested event loop by disabling debuggee events.
*/
ChromeActor.prototype.preNest = function() {
// Disable events in all open windows.
let e = Services.wm.getEnumerator(null);
while (e.hasMoreElements()) {
let win = e.getNext();
let windowUtils = win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
windowUtils.suppressEventHandling(true);
windowUtils.suspendTimeouts();
}
}
/**
* Prepare to exit a nested event loop by enabling debuggee events.
*/
ChromeActor.prototype.postNest = function(aNestData) {
// Enable events in all open windows.
let e = Services.wm.getEnumerator(null);
while (e.hasMoreElements()) {
let win = e.getNext();
let windowUtils = win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
windowUtils.resumeTimeouts();
windowUtils.suppressEventHandling(false);
}
}

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

@ -10,9 +10,6 @@ const { Cc, Ci, Cu } = require("chrome");
const Services = require("Services"); const Services = require("Services");
const { ActorPool, appendExtraActors, createExtraActors } = require("devtools/server/actors/common"); const { ActorPool, appendExtraActors, createExtraActors } = require("devtools/server/actors/common");
const { DebuggerServer } = require("devtools/server/main"); const { DebuggerServer } = require("devtools/server/main");
const makeDebugger = require("./utils/make-debugger");
loader.lazyRequireGetter(this, "StyleSheetActor", "devtools/server/actors/stylesheets", true);
loader.lazyGetter(this, "ppmm", () => { loader.lazyGetter(this, "ppmm", () => {
return Cc["@mozilla.org/parentprocessmessagemanager;1"].getService(Ci.nsIMessageBroadcaster); return Cc["@mozilla.org/parentprocessmessagemanager;1"].getService(Ci.nsIMessageBroadcaster);
@ -99,14 +96,10 @@ function RootActor(aConnection, aParameters) {
this._onAddonListChanged = this.onAddonListChanged.bind(this); this._onAddonListChanged = this.onAddonListChanged.bind(this);
this._extraActors = {}; this._extraActors = {};
// Map of DOM stylesheets to StyleSheetActors this._globalActorPool = new ActorPool(this.conn);
this._styleSheetActors = new Map(); this.conn.addActorPool(this._globalActorPool);
// This creates a Debugger instance for chrome debugging all globals. this._chromeActor = null;
this.makeDebugger = makeDebugger.bind(null, {
findDebuggees: dbg => dbg.findAllGlobals(),
shouldAddNewGlobalAsDebuggee: () => true
});
} }
RootActor.prototype = { RootActor.prototype = {
@ -160,7 +153,16 @@ RootActor.prototype = {
getUsedFontFaces: true, getUsedFontFaces: true,
// Trait added in Gecko 38, indicating that all features necessary for // Trait added in Gecko 38, indicating that all features necessary for
// grabbing allocations from the MemoryActor are available for the performance tool // grabbing allocations from the MemoryActor are available for the performance tool
memoryActorAllocations: true memoryActorAllocations: true,
// Whether root actor exposes tab actors
// if allowChromeProcess is true, you can fetch a ChromeActor instance
// to debug chrome and any non-content ressource via attachProcess request
// if allocChromeProcess is defined, but not true, it means that root actor
// no longer expose tab actors, but also that attachProcess forbids
// exposing actors for security reasons
get allowChromeProcess() {
return DebuggerServer.allowChromeProcess;
},
}, },
/** /**
@ -176,66 +178,6 @@ RootActor.prototype = {
}; };
}, },
/**
* This is true for the root actor only, used by some child actors
*/
get isRootActor() true,
/**
* The (chrome) window, for use by child actors
*/
get window() isWorker ? null : Services.wm.getMostRecentWindow(DebuggerServer.chromeWindowType),
/**
* The list of all windows
*/
get windows() {
return this.docShells.map(docShell => {
return docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
});
},
/**
* URL of the chrome window.
*/
get url() { return this.window ? this.window.document.location.href : null; },
/**
* The top level window's docshell
*/
get docShell() {
return this.window
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell);
},
/**
* The list of all docshells
*/
get docShells() {
let docShellsEnum = this.docShell.getDocShellEnumerator(
Ci.nsIDocShellTreeItem.typeAll,
Ci.nsIDocShell.ENUMERATE_FORWARDS
);
let docShells = [];
while (docShellsEnum.hasMoreElements()) {
docShells.push(docShellsEnum.getNext());
}
return docShells;
},
/**
* Getter for the best nsIWebProgress for to watching this window.
*/
get webProgress() {
return this.docShell
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebProgress);
},
/** /**
* Disconnects the actor from the browser window. * Disconnects the actor from the browser window.
*/ */
@ -251,8 +193,6 @@ RootActor.prototype = {
this._parameters.onShutdown(); this._parameters.onShutdown();
} }
this._extraActors = null; this._extraActors = null;
this._styleSheetActors.clear();
this._styleSheetActors = null;
}, },
/* The 'listTabs' request and the 'tabListChanged' notification. */ /* The 'listTabs' request and the 'tabListChanged' notification. */
@ -380,13 +320,34 @@ RootActor.prototype = {
}, },
onAttachProcess: function (aRequest) { onAttachProcess: function (aRequest) {
let mm = ppmm.getChildAt(aRequest.id); if (!DebuggerServer.allowChromeProcess) {
if (!mm) { return { error: "forbidden",
return { error: "noProcess", message: "You are not allowed to debug chrome." };
message: "There is no process with id '" + aRequest.id + "'." }; }
if (("id" in aRequest) && typeof(aRequest.id) != "number") {
return { error: "wrongParameter",
message: "attachProcess requires a valid `id` attribute." };
}
// If the request doesn't contains id parameter or id is 0
// (id == 0, based on onListProcesses implementation)
if ((!("id" in aRequest)) || aRequest.id === 0) {
if (!this._chromeActor) {
// Create a ChromeActor for the parent process
let { ChromeActor } = require("devtools/server/actors/chrome");
this._chromeActor = new ChromeActor(this.conn);
this._globalActorPool.addActor(this._chromeActor);
}
return { form: this._chromeActor.form() };
} else {
let mm = ppmm.getChildAt(aRequest.id);
if (!mm) {
return { error: "noProcess",
message: "There is no process with id '" + aRequest.id + "'." };
}
return DebuggerServer.connectToContent(this.conn, mm)
.then(form => ({ form }));
} }
return DebuggerServer.connectToContent(this.conn, mm)
.then(form => ({ form: form }));
}, },
/* This is not in the spec, but it's used by tests. */ /* This is not in the spec, but it's used by tests. */
@ -406,60 +367,6 @@ RootActor.prototype = {
_createExtraActors: createExtraActors, _createExtraActors: createExtraActors,
_appendExtraActors: appendExtraActors, _appendExtraActors: appendExtraActors,
/* ThreadActor hooks. */
/**
* Prepare to enter a nested event loop by disabling debuggee events.
*/
preNest: function() {
// Disable events in all open windows.
let e = Services.wm.getEnumerator(null);
while (e.hasMoreElements()) {
let win = e.getNext();
let windowUtils = win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
windowUtils.suppressEventHandling(true);
windowUtils.suspendTimeouts();
}
},
/**
* Prepare to exit a nested event loop by enabling debuggee events.
*/
postNest: function(aNestData) {
// Enable events in all open windows.
let e = Services.wm.getEnumerator(null);
while (e.hasMoreElements()) {
let win = e.getNext();
let windowUtils = win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
windowUtils.resumeTimeouts();
windowUtils.suppressEventHandling(false);
}
},
/**
* Create or return the StyleSheetActor for a style sheet. This method
* is here because the Style Editor and Inspector share style sheet actors.
*
* @param DOMStyleSheet styleSheet
* The style sheet to create an actor for.
* @return StyleSheetActor actor
* The actor for this style sheet.
*
*/
createStyleSheetActor: function(styleSheet) {
if (this._styleSheetActors.has(styleSheet)) {
return this._styleSheetActors.get(styleSheet);
}
let actor = new StyleSheetActor(styleSheet, this);
this._styleSheetActors.set(styleSheet, actor);
this._globalActorPool.addActor(actor);
return actor;
},
/** /**
* Remove the extra actor (added by DebuggerServer.addGlobalActor or * Remove the extra actor (added by DebuggerServer.addGlobalActor or
* DebuggerServer.addTabActor) name |aName|. * DebuggerServer.addTabActor) name |aName|.

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

@ -36,6 +36,35 @@ function getWindowID(window) {
.currentInnerWindowID; .currentInnerWindowID;
} }
function getDocShellChromeEventHandler(docShell) {
let handler = docShell.chromeEventHandler;
if (!handler) {
try {
// toplevel xul window's docshell doesn't have chromeEventHandler attribute
// the chrome event handler is just the global window object
handler = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
} catch(e) {}
}
return handler;
}
function getChildDocShells(docShell) {
let docShellsEnum = docShell.getDocShellEnumerator(
Ci.nsIDocShellTreeItem.typeAll,
Ci.nsIDocShell.ENUMERATE_FORWARDS
);
let docShells = [];
while (docShellsEnum.hasMoreElements()) {
let docShell = docShellsEnum.getNext();
docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebProgress);
docShells.push(docShell);
}
return docShells;
}
exports.getChildDocShells = getChildDocShells;
/** /**
* Browser-specific actors. * Browser-specific actors.
*/ */
@ -580,6 +609,10 @@ function TabActor(aConnection)
shouldAddNewGlobalAsDebuggee: this._shouldAddNewGlobalAsDebuggee shouldAddNewGlobalAsDebuggee: this._shouldAddNewGlobalAsDebuggee
}); });
// Flag eventually overloaded by sub classes in order to watch new docshells
// Used on b2g to catch activity frames and in chrome to list all frames
this.listenForNewDocShells = Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT;
this.traits = { reconfigure: true, frames: true }; this.traits = { reconfigure: true, frames: true };
} }
@ -607,10 +640,7 @@ TabActor.prototype = {
* An object on which listen for DOMWindowCreated and pageshow events. * An object on which listen for DOMWindowCreated and pageshow events.
*/ */
get chromeEventHandler() { get chromeEventHandler() {
// TODO: bug 992778, fix docShell.chromeEventHandler in child processes return getDocShellChromeEventHandler(this.docShell);
return this.docShell.chromeEventHandler ||
this.docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIContentFrameMessageManager);
}, },
/** /**
@ -634,29 +664,20 @@ TabActor.prototype = {
* @return {Array} * @return {Array}
*/ */
get docShells() { get docShells() {
let docShellsEnum = this.docShell.getDocShellEnumerator( return getChildDocShells(this.docShell);
Ci.nsIDocShellTreeItem.typeAll,
Ci.nsIDocShell.ENUMERATE_FORWARDS
);
let docShells = [];
while (docShellsEnum.hasMoreElements()) {
let docShell = docShellsEnum.getNext();
docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebProgress);
docShells.push(docShell);
}
return docShells;
}, },
/** /**
* Getter for the tab content's DOM window. * Getter for the tab content's DOM window.
*/ */
get window() { get window() {
return this.docShell // On xpcshell, there is no document
.QueryInterface(Ci.nsIInterfaceRequestor) if (this.docShell) {
.getInterface(Ci.nsIDOMWindow); return this.docShell
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
}
return null;
}, },
/** /**
@ -761,17 +782,21 @@ TabActor.prototype = {
dbg_assert(this.actorID, dbg_assert(this.actorID,
"tab should have an actorID."); "tab should have an actorID.");
let windowUtils = this.window
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
let response = { let response = {
actor: this.actorID, actor: this.actorID
title: this.title,
url: this.url,
outerWindowID: windowUtils.outerWindowID
}; };
// On xpcshell we are using tabactor even if there is no valid document.
// Actors like chrome debugger can work.
if (this.window) {
response.title = this.title;
response.url = this.url;
let windowUtils = this.window
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
response.outerWindowID = windowUtils.outerWindowID;
}
// Walk over tab actors added by extensions and add them to a new ActorPool. // Walk over tab actors added by extensions and add them to a new ActorPool.
let actorPool = new ActorPool(this.conn); let actorPool = new ActorPool(this.conn);
this._createExtraActors(DebuggerServer.tabActorFactories, actorPool); this._createExtraActors(DebuggerServer.tabActorFactories, actorPool);
@ -869,21 +894,24 @@ TabActor.prototype = {
// ... and a pool for context-lifetime actors. // ... and a pool for context-lifetime actors.
this._pushContext(); this._pushContext();
this._progressListener = new DebuggerProgressListener(this); // on xpcshell, there is no document
if (this.window) {
this._progressListener = new DebuggerProgressListener(this);
// Save references to the original document we attached to // Save references to the original document we attached to
this._originalWindow = this.window; this._originalWindow = this.window;
// Ensure replying to attach() request first // Ensure replying to attach() request first
// before notifying about new docshells. // before notifying about new docshells.
DevToolsUtils.executeSoon(() => this._watchDocshells()); DevToolsUtils.executeSoon(() => this._watchDocshells());
}
this._attached = true; this._attached = true;
}, },
_watchDocshells: function BTA_watchDocshells() { _watchDocshells: function BTA_watchDocshells() {
// In child processes, we watch all docshells living in the process. // In child processes, we watch all docshells living in the process.
if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) { if (this.listenForNewDocShells) {
Services.obs.addObserver(this, "webnavigation-create", false); Services.obs.addObserver(this, "webnavigation-create", false);
} }
Services.obs.addObserver(this, "webnavigation-destroy", false); Services.obs.addObserver(this, "webnavigation-destroy", false);
@ -927,28 +955,36 @@ TabActor.prototype = {
} }
if (aTopic == "webnavigation-create") { if (aTopic == "webnavigation-create") {
aSubject.QueryInterface(Ci.nsIDocShell); aSubject.QueryInterface(Ci.nsIDocShell);
// webnavigation-create is fired very early during docshell construction. this._onDocShellCreated(aSubject);
// In new root docshells within child processes, involving TabChild,
// this event is from within this call:
// http://hg.mozilla.org/mozilla-central/annotate/74d7fb43bb44/dom/ipc/TabChild.cpp#l912
// whereas the chromeEventHandler (and most likely other stuff) is set later:
// http://hg.mozilla.org/mozilla-central/annotate/74d7fb43bb44/dom/ipc/TabChild.cpp#l944
// So wait a tick before watching it:
DevToolsUtils.executeSoon(() => {
// In child processes, we have new root docshells,
// let's watch them and all their child docshells.
if (this._isRootDocShell(aSubject)) {
this._progressListener.watch(aSubject);
}
this._notifyDocShellsUpdate([aSubject]);
});
} else if (aTopic == "webnavigation-destroy") { } else if (aTopic == "webnavigation-destroy") {
let webProgress = aSubject.QueryInterface(Ci.nsIInterfaceRequestor) this._onDocShellDestroy(aSubject);
.getInterface(Ci.nsIWebProgress);
this._notifyDocShellDestroy(webProgress);
} }
}, },
_onDocShellCreated: function (docShell) {
// (chrome-)webnavigation-create is fired very early during docshell construction.
// In new root docshells within child processes, involving TabChild,
// this event is from within this call:
// http://hg.mozilla.org/mozilla-central/annotate/74d7fb43bb44/dom/ipc/TabChild.cpp#l912
// whereas the chromeEventHandler (and most likely other stuff) is set later:
// http://hg.mozilla.org/mozilla-central/annotate/74d7fb43bb44/dom/ipc/TabChild.cpp#l944
// So wait a tick before watching it:
DevToolsUtils.executeSoon(() => {
// In child processes, we have new root docshells,
// let's watch them and all their child docshells.
if (this._isRootDocShell(docShell)) {
this._progressListener.watch(docShell);
}
this._notifyDocShellsUpdate([docShell]);
});
},
_onDocShellDestroy: function (docShell) {
let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebProgress);
this._notifyDocShellDestroy(webProgress);
},
_isRootDocShell: function (docShell) { _isRootDocShell: function (docShell) {
// Root docshells like top level xul windows don't have chromeEventHandler. // Root docshells like top level xul windows don't have chromeEventHandler.
// Root docshells in child processes have one, it is TabChildGlobal, // Root docshells in child processes have one, it is TabChildGlobal,
@ -962,7 +998,9 @@ TabActor.prototype = {
// Convert docShell list to windows objects list being sent to the client // Convert docShell list to windows objects list being sent to the client
_docShellsToWindows: function (docshells) { _docShellsToWindows: function (docshells) {
return docshells.map(docShell => { return docshells.map(docShell => {
let window = docShell.DOMWindow; let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebProgress);
let window = webProgress.DOMWindow;
let id = window.QueryInterface(Ci.nsIInterfaceRequestor) let id = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils) .getInterface(Ci.nsIDOMWindowUtils)
.outerWindowID; .outerWindowID;
@ -997,6 +1035,7 @@ TabActor.prototype = {
}, },
_notifyDocShellDestroy: function (webProgress) { _notifyDocShellDestroy: function (webProgress) {
webProgress = webProgress.QueryInterface(Ci.nsIWebProgress);
let id = webProgress.DOMWindow let id = webProgress.DOMWindow
.QueryInterface(Ci.nsIInterfaceRequestor) .QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils) .getInterface(Ci.nsIDOMWindowUtils)
@ -1096,15 +1135,17 @@ TabActor.prototype = {
if (this.docShell) { if (this.docShell) {
this._progressListener.unwatch(this.docShell); this._progressListener.unwatch(this.docShell);
} }
this._progressListener.destroy(); if (this._progressListener) {
this._progressListener = null; this._progressListener.destroy();
this._originalWindow = null; this._progressListener = null;
this._originalWindow = null;
// Removes the observers being set in _watchDocShells // Removes the observers being set in _watchDocShells
if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) { if (this.listenForNewDocShells) {
Services.obs.removeObserver(this, "webnavigation-create", false); Services.obs.removeObserver(this, "webnavigation-create");
}
Services.obs.removeObserver(this, "webnavigation-destroy");
} }
Services.obs.removeObserver(this, "webnavigation-destroy", false);
this._popContext(); this._popContext();
@ -1304,9 +1345,11 @@ TabActor.prototype = {
this._windowDestroyed(this.window, null, true); this._windowDestroyed(this.window, null, true);
DevToolsUtils.executeSoon(() => { // Immediately change the window as this window, if in process of unload
this._setWindow(window); // may already be non working on the next cycle and start throwing
this._setWindow(window);
DevToolsUtils.executeSoon(() => {
// Then fake window-ready and navigate on the given document // Then fake window-ready and navigate on the given document
this._windowReady(window, true); this._windowReady(window, true);
DevToolsUtils.executeSoon(() => { DevToolsUtils.executeSoon(() => {
@ -2018,11 +2061,7 @@ DebuggerProgressListener.prototype = {
Ci.nsIWebProgress.NOTIFY_STATE_WINDOW | Ci.nsIWebProgress.NOTIFY_STATE_WINDOW |
Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT); Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
// TODO: fix docShell.chromeEventHandler in child processes! let handler = getDocShellChromeEventHandler(docShell);
let handler = docShell.chromeEventHandler ||
docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIContentFrameMessageManager);
handler.addEventListener("DOMWindowCreated", this._onWindowCreated, true); handler.addEventListener("DOMWindowCreated", this._onWindowCreated, true);
handler.addEventListener("pageshow", this._onWindowCreated, true); handler.addEventListener("pageshow", this._onWindowCreated, true);
handler.addEventListener("pagehide", this._onWindowHidden, true); handler.addEventListener("pagehide", this._onWindowHidden, true);
@ -2042,11 +2081,7 @@ DebuggerProgressListener.prototype = {
webProgress.removeProgressListener(this); webProgress.removeProgressListener(this);
} catch(e) {} } catch(e) {}
// TODO: fix docShell.chromeEventHandler in child processes! let handler = getDocShellChromeEventHandler(docShell);
let handler = docShell.chromeEventHandler ||
docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIContentFrameMessageManager);
handler.removeEventListener("DOMWindowCreated", this._onWindowCreated, true); handler.removeEventListener("DOMWindowCreated", this._onWindowCreated, true);
handler.removeEventListener("pageshow", this._onWindowCreated, true); handler.removeEventListener("pageshow", this._onWindowCreated, true);
handler.removeEventListener("pagehide", this._onWindowHidden, true); handler.removeEventListener("pagehide", this._onWindowHidden, true);
@ -2057,18 +2092,10 @@ DebuggerProgressListener.prototype = {
}, },
_getWindowsInDocShell: function(docShell) { _getWindowsInDocShell: function(docShell) {
let docShellsEnum = docShell.getDocShellEnumerator( return getChildDocShells(docShell).map(d => {
Ci.nsIDocShellTreeItem.typeAll, return d.QueryInterface(Ci.nsIInterfaceRequestor)
Ci.nsIDocShell.ENUMERATE_FORWARDS .getInterface(Ci.nsIDOMWindow);
); });
let windows = [];
while (docShellsEnum.hasMoreElements()) {
let w = docShellsEnum.getNext().QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
windows.push(w);
}
return windows;
}, },
onWindowCreated: DevToolsUtils.makeInfallible(function(evt) { onWindowCreated: DevToolsUtils.makeInfallible(function(evt) {

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

@ -1503,6 +1503,9 @@ WebConsoleActor.prototype =
// This method is called after this.window is changed, // This method is called after this.window is changed,
// so we register new listener on this new window // so we register new listener on this new window
this.onStartListeners({listeners: listeners}); this.onStartListeners({listeners: listeners});
// Also reset the cached top level chrome window being targeted
this._lastChromeWindow = null;
}, },
}; };

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

@ -165,6 +165,11 @@ var DebuggerServer = {
*/ */
chromeWindowType: null, chromeWindowType: null,
/**
* Allow debugging chrome of (parent or child) processes.
*/
allowChromeProcess: false,
/** /**
* Initialize the debugger server. * Initialize the debugger server.
*/ */
@ -366,8 +371,6 @@ var DebuggerServer = {
if (!restrictPrivileges) { if (!restrictPrivileges) {
this.addTabActors(); this.addTabActors();
let { ChromeDebuggerActor } = require("devtools/server/actors/script");
this.addGlobalActor(ChromeDebuggerActor, "chromeDebugger");
this.registerModule("devtools/server/actors/preference", { this.registerModule("devtools/server/actors/preference", {
prefix: "preference", prefix: "preference",
constructor: "PreferenceActor", constructor: "PreferenceActor",
@ -430,12 +433,12 @@ var DebuggerServer = {
this.registerModule("devtools/server/actors/webconsole", { this.registerModule("devtools/server/actors/webconsole", {
prefix: "console", prefix: "console",
constructor: "WebConsoleActor", constructor: "WebConsoleActor",
type: { global: true, tab: true } type: { tab: true }
}); });
this.registerModule("devtools/server/actors/inspector", { this.registerModule("devtools/server/actors/inspector", {
prefix: "inspector", prefix: "inspector",
constructor: "InspectorActor", constructor: "InspectorActor",
type: { global: true, tab: true } type: { tab: true }
}); });
this.registerModule("devtools/server/actors/call-watcher", { this.registerModule("devtools/server/actors/call-watcher", {
prefix: "callWatcher", prefix: "callWatcher",
@ -445,27 +448,27 @@ var DebuggerServer = {
this.registerModule("devtools/server/actors/canvas", { this.registerModule("devtools/server/actors/canvas", {
prefix: "canvas", prefix: "canvas",
constructor: "CanvasActor", constructor: "CanvasActor",
type: { global: true, tab: true } type: { tab: true }
}); });
this.registerModule("devtools/server/actors/webgl", { this.registerModule("devtools/server/actors/webgl", {
prefix: "webgl", prefix: "webgl",
constructor: "WebGLActor", constructor: "WebGLActor",
type: { global: true, tab: true } type: { tab: true }
}); });
this.registerModule("devtools/server/actors/webaudio", { this.registerModule("devtools/server/actors/webaudio", {
prefix: "webaudio", prefix: "webaudio",
constructor: "WebAudioActor", constructor: "WebAudioActor",
type: { global: true, tab: true } type: { tab: true }
}); });
this.registerModule("devtools/server/actors/stylesheets", { this.registerModule("devtools/server/actors/stylesheets", {
prefix: "styleSheets", prefix: "styleSheets",
constructor: "StyleSheetsActor", constructor: "StyleSheetsActor",
type: { global: true, tab: true } type: { tab: true }
}); });
this.registerModule("devtools/server/actors/styleeditor", { this.registerModule("devtools/server/actors/styleeditor", {
prefix: "styleEditor", prefix: "styleEditor",
constructor: "StyleEditorActor", constructor: "StyleEditorActor",
type: { global: true, tab: true } type: { tab: true }
}); });
this.registerModule("devtools/server/actors/storage", { this.registerModule("devtools/server/actors/storage", {
prefix: "storage", prefix: "storage",
@ -485,17 +488,17 @@ var DebuggerServer = {
this.registerModule("devtools/server/actors/memory", { this.registerModule("devtools/server/actors/memory", {
prefix: "memory", prefix: "memory",
constructor: "MemoryActor", constructor: "MemoryActor",
type: { global: true, tab: true } type: { tab: true }
}); });
this.registerModule("devtools/server/actors/framerate", { this.registerModule("devtools/server/actors/framerate", {
prefix: "framerate", prefix: "framerate",
constructor: "FramerateActor", constructor: "FramerateActor",
type: { global: true, tab: true } type: { tab: true }
}); });
this.registerModule("devtools/server/actors/eventlooplag", { this.registerModule("devtools/server/actors/eventlooplag", {
prefix: "eventLoopLag", prefix: "eventLoopLag",
constructor: "EventLoopLagActor", constructor: "EventLoopLagActor",
type: { global: true, tab: true } type: { tab: true }
}); });
this.registerModule("devtools/server/actors/layout", { this.registerModule("devtools/server/actors/layout", {
prefix: "reflow", prefix: "reflow",
@ -505,17 +508,17 @@ var DebuggerServer = {
this.registerModule("devtools/server/actors/csscoverage", { this.registerModule("devtools/server/actors/csscoverage", {
prefix: "cssUsage", prefix: "cssUsage",
constructor: "CSSUsageActor", constructor: "CSSUsageActor",
type: { global: true, tab: true } type: { tab: true }
}); });
this.registerModule("devtools/server/actors/monitor", { this.registerModule("devtools/server/actors/monitor", {
prefix: "monitor", prefix: "monitor",
constructor: "MonitorActor", constructor: "MonitorActor",
type: { global: true, tab: true } type: { tab: true }
}); });
this.registerModule("devtools/server/actors/timeline", { this.registerModule("devtools/server/actors/timeline", {
prefix: "timeline", prefix: "timeline",
constructor: "TimelineActor", constructor: "TimelineActor",
type: { global: true, tab: true } type: { tab: true }
}); });
this.registerModule("devtools/server/actors/director-manager", { this.registerModule("devtools/server/actors/director-manager", {
prefix: "directorManager", prefix: "directorManager",
@ -526,13 +529,13 @@ var DebuggerServer = {
this.registerModule("devtools/server/actors/profiler", { this.registerModule("devtools/server/actors/profiler", {
prefix: "profiler", prefix: "profiler",
constructor: "ProfilerActor", constructor: "ProfilerActor",
type: { global: true, tab: true } type: { tab: true }
}); });
} }
this.registerModule("devtools/server/actors/animation", { this.registerModule("devtools/server/actors/animation", {
prefix: "animations", prefix: "animations",
constructor: "AnimationsActor", constructor: "AnimationsActor",
type: { global: true, tab: true } type: { tab: true }
}); });
}, },

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

@ -39,6 +39,7 @@ EXTRA_JS_MODULES.devtools.server.actors += [
'actors/canvas.js', 'actors/canvas.js',
'actors/child-process.js', 'actors/child-process.js',
'actors/childtab.js', 'actors/childtab.js',
'actors/chrome.js',
'actors/common.js', 'actors/common.js',
'actors/csscoverage.js', 'actors/csscoverage.js',
'actors/device.js', 'actors/device.js',