import changes from `dev' branch of rmottola/Arctic-Fox:

- Bug 1167459 - Skip rendering function name nodes if there's no name available (e.g. for C++ pseudoframes), r=jsantell (4a69ed224)
- missing bits Bug 1102219 - Part 4: Replace String.prototype.contains with `String.prototype.includes` in chrome code. r=till (73cd2d2b1)
- Bug 1165045 - Don't create nodes with empty text in the call tree, r=jsantell (b013aa82d)
- Bug 1166122 - Fix regression in the call tree caused by bug 1165045, r=jsantell (ee3f16901)
- Bug 1167975 - CallView._displaySelf sets this.document just because other functions use it; it should pass it as an argument instead, r=jsantell (5ef560c4f)
- Bug 1122662 - Resize graphs when window resizes;r=vporof (25c108e4e)
- Bug 1164784 - Eliminate CSS duplication with perf tool record button r=jsantell (43c9bb999)
- Bug 1150761 - Rename the performance tool's details view names to better describe the data visualizations. r=vp (04ceb6a37)
- Bug 1144424 - Rename '{self,total} allocations' to '{self,total} sampled allocations' in the performance tool. r=jsantell (ae79ad54f)
- Bug 1069910 - Add tooltips explaining what each column in the profiler's tree view represents; r=jsantell (8756f88b6)
- Bug 1107849 - Define a min/max width for the performance panel sidebar. r=vporof (e1769e831)
- Bug 11663354 - A locked recording button should appear disabled in the performance tool. r=vp (4a359d39e)
- Bug 1023546 - DevTools - Support HDPI resolutions for Windows. r=bgrins (ef1a3ecb8)
- Bug 1168125 - Cleanup performance xul and css, r=jsantell (8ec794e46)
- Bug 1168125 - Replace the waterfall view with a tree, r=jsantell (ea76514fe)
- Bug 1168125 - Add marker folding logic, r=jsantell (1d3748d2a)
- Bug 862341 Part 1: Move the network request storage from the console frontend to the console client so the netmonitor can reuse it. r=vporof (d29fb2b73)
- remove gre from resource path (126b00df1)
- Bug 943306 - Allow persisting console input history between sessions;r=past (146ebb486)
- Bug 1134845 - Add clearHistory jsterm helper to remove persisted console input history. r=past (22237e95b)
- Bug 1143497 - Offer a way to extend WebConsole commands. r=bgrins (84e2d2957)
- Bug 1125205 - Display console API messages from shared or service workers to the web console, r=past (b4b701a2c)
- Bug 1169342 - Remove nsIDOMDeviceStorage. Cleanup nsDOMDeviceStorage event wrappers. r=dhylands (41338e16f)
- Bug 1151610 - Manage the case where two extensions fight over the same command. r=bgrins (63f9d2064)
- Bug 862341 Part 2: Display cached network requests in the web console. r=vporof (83c0e7263)
- Bug 1144211 - Improve code coverage of camera mochitests. r=mikeh (ba9f3de89)
- Bug 1152500 - Fix how stop recording may be handled out-of-order. r=dhylands (d8bdd379c)
- Bug 862341 Part 3: Display cached network requests in the network panel. r=vporof (a1a6f151d)
- Bug 862341 Part 4: Start recording network requests when the toolbox opens. r=vporof (7a2bdf847)
- Bug 1151499 - Correct the FM playable state. r=baku (8af26fff2)
- Bug 1180347 - Split media.useAudioChannelService to support turning the service on without turning the Firefox OS specific APIs on; r=baku (3fa29291a)
- Bug 862341 Part 5: Tests. r=vporof (82fb944c6)
This commit is contained in:
2021-05-29 22:53:37 +08:00
parent 98894236c9
commit b9843e0358
100 changed files with 4707 additions and 2466 deletions
+149 -123
View File
@@ -8,7 +8,7 @@
const {Cc, Ci, Cu} = require("chrome");
let WebConsoleUtils = require("devtools/toolkit/webconsole/utils").Utils;
const {Utils: WebConsoleUtils, CONSOLE_WORKER_IDS} = require("devtools/toolkit/webconsole/utils");
loader.lazyServiceGetter(this, "clipboardHelper",
"@mozilla.org/widget/clipboardhelper;1",
@@ -26,6 +26,8 @@ loader.lazyGetter(this, "ConsoleOutput",
() => require("devtools/webconsole/console-output").ConsoleOutput);
loader.lazyGetter(this, "Messages",
() => require("devtools/webconsole/console-output").Messages);
loader.lazyGetter(this, "asyncStorage",
() => require("devtools/toolkit/shared/async-storage"));
loader.lazyImporter(this, "EnvironmentClient", "resource://gre/modules/devtools/dbg-client.jsm");
loader.lazyImporter(this, "ObjectClient", "resource://gre/modules/devtools/dbg-client.jsm");
loader.lazyImporter(this, "VariablesView", "resource://gre/modules/devtools/VariablesView.jsm");
@@ -136,6 +138,10 @@ const LEVELS = {
count: SEVERITY_LOG
};
// This array contains the prefKey for the workers and it must keep them in the
// same order as CONSOLE_WORKER_IDS
const WORKERTYPES_PREFKEYS = [ 'sharedworkers', 'serviceworkers', 'windowlessworkers' ];
// The lowest HTTP response code (inclusive) that is considered an error.
const MIN_HTTP_ERROR_CODE = 400;
// The highest HTTP response code (inclusive) that is considered an error.
@@ -176,6 +182,7 @@ const MIN_FONT_SIZE = 10;
const PREF_CONNECTION_TIMEOUT = "devtools.debugger.remote-timeout";
const PREF_PERSISTLOG = "devtools.webconsole.persistlog";
const PREF_MESSAGE_TIMESTAMP = "devtools.webconsole.timestampMessages";
const PREF_INPUT_HISTORY_COUNT = "devtools.webconsole.inputHistoryCount";
/**
* A WebConsoleFrame instance is an interactive console initialized *per target*
@@ -199,7 +206,6 @@ function WebConsoleFrame(aWebConsoleOwner)
this._outputQueue = [];
this._itemDestroyQueue = [];
this._pruneCategoriesQueue = {};
this._networkRequests = {};
this.filterPrefs = {};
this.output = new ConsoleOutput(this);
@@ -247,14 +253,6 @@ WebConsoleFrame.prototype = {
*/
_initDefer: null,
/**
* Holds the network requests currently displayed by the Web Console. Each key
* represents the connection ID and the value is network request information.
* @private
* @type object
*/
_networkRequests: null,
/**
* Last time when we displayed any message in the output.
*
@@ -447,12 +445,29 @@ WebConsoleFrame.prototype = {
/**
* Initialize the WebConsoleFrame instance.
* @return object
* A promise object for the initialization.
* A promise object that resolves once the frame is ready to use.
*/
init: function WCF_init()
init: function()
{
this._initUI();
return this._initConnection();
let connectionInited = this._initConnection();
// Don't reject if the history fails to load for some reason.
// This would be fine, the panel will just start with empty history.
let allReady = this.jsterm.historyLoaded.catch(() => {}).then(() => {
return connectionInited;
});
// This notification is only used in tests. Don't chain it onto
// the returned promise because the console panel needs to be attached
// to the toolbox before the web-console-created event is receieved.
let notifyObservers = () => {
let id = WebConsoleUtils.supportsString(this.hudId);
Services.obs.notifyObservers(id, "web-console-created", null);
};
allReady.then(notifyObservers, notifyObservers);
return allReady;
},
/**
@@ -479,9 +494,6 @@ WebConsoleFrame.prototype = {
aReason.error + ": " + aReason.message);
this.outputMessage(CATEGORY_JS, node, [aReason]);
this._initDefer.reject(aReason);
}).then(() => {
let id = WebConsoleUtils.supportsString(this.hudId);
Services.obs.notifyObservers(id, "web-console-created", null);
});
return this._initDefer.promise;
@@ -632,7 +644,8 @@ WebConsoleFrame.prototype = {
{
let prefs = ["network", "networkinfo", "csserror", "cssparser", "csslog",
"exception", "jswarn", "jslog", "error", "info", "warn", "log",
"secerror", "secwarn", "netwarn", "netxhr"];
"secerror", "secwarn", "netwarn", "netxhr", "sharedworkers",
"serviceworkers", "windowlessworkers"];
for (let pref of prefs) {
this.filterPrefs[pref] = Services.prefs
.getBoolPref(this._filterPrefsPrefix + pref);
@@ -1009,8 +1022,11 @@ WebConsoleFrame.prototype = {
// (filter="error", filter="cssparser", etc.) and add or remove the
// "filtered-by-type" class, which turns on or off the display.
let attribute = WORKERTYPES_PREFKEYS.indexOf(aPrefKey) == -1
? 'filter' : 'workerType';
let xpath = ".//*[contains(@class, 'message') and " +
"@filter='" + aPrefKey + "']";
"@" + attribute + "='" + aPrefKey + "']";
let result = doc.evaluate(xpath, outputNode, null,
Ci.nsIDOMXPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
for (let i = 0; i < result.snapshotLength; i++) {
@@ -1071,6 +1087,12 @@ WebConsoleFrame.prototype = {
isFiltered = true;
}
// Filter by worker type
if ("workerType" in aNode && !this.getFilterState(aNode.workerType)) {
aNode.classList.add("filtered-by-type");
isFiltered = true;
}
// Filter on the search string.
let search = this.filterBox.value;
let text = aNode.clipboardText;
@@ -1192,6 +1214,9 @@ WebConsoleFrame.prototype = {
this.outputMessage(CATEGORY_WEBDEV, this.logConsoleAPIMessage,
[aMessage]);
break;
case "NetworkEvent":
this.outputMessage(CATEGORY_NETWORK, this.logNetEvent, [aMessage]);
break;
}
}, this);
},
@@ -1348,6 +1373,12 @@ WebConsoleFrame.prototype = {
}
}
let workerTypeID = CONSOLE_WORKER_IDS.indexOf(aMessage.workerType);
if (workerTypeID != -1) {
node.workerType = WORKERTYPES_PREFKEYS[workerTypeID];
node.setAttribute('workerType', WORKERTYPES_PREFKEYS[workerTypeID]);
}
return node;
},
@@ -1486,19 +1517,14 @@ WebConsoleFrame.prototype = {
/**
* Log network event.
*
* @param object aActor
* The network event actor to log.
* @param object networkInfo
* The network request information to log.
* @return nsIDOMElement|null
* The message element to display in the Web Console output.
*/
logNetEvent: function WCF_logNetEvent(aActor)
logNetEvent: function(networkInfo)
{
let actorId = aActor.actor;
let networkInfo = this._networkRequests[actorId];
if (!networkInfo) {
return null;
}
let actorId = networkInfo.actor;
let request = networkInfo.request;
let clipboardText = request.method + " " + request.url;
let severity = SEVERITY_LOG;
@@ -1518,7 +1544,8 @@ WebConsoleFrame.prototype = {
let messageNode = this.createMessageNode(CATEGORY_NETWORK, severity,
methodNode, null, null,
clipboardText);
clipboardText, null,
networkInfo.timeStamp);
if (networkInfo.private) {
messageNode.setAttribute("private", true);
}
@@ -1756,84 +1783,29 @@ WebConsoleFrame.prototype = {
/**
* Handle the network events coming from the remote Web Console.
*
* @param object aActor
* The NetworkEventActor grip.
* @param object networkInfo
* The network request information.
*/
handleNetworkEvent: function WCF_handleNetworkEvent(aActor)
handleNetworkEvent: function(networkInfo)
{
let networkInfo = {
node: null,
actor: aActor.actor,
discardRequestBody: true,
discardResponseBody: true,
startedDateTime: aActor.startedDateTime,
request: {
url: aActor.url,
method: aActor.method,
},
isXHR: aActor.isXHR,
response: {},
timings: {},
updates: [], // track the list of network event updates
private: aActor.private,
};
this._networkRequests[aActor.actor] = networkInfo;
this.outputMessage(CATEGORY_NETWORK, this.logNetEvent, [aActor]);
this.outputMessage(CATEGORY_NETWORK, this.logNetEvent, [networkInfo]);
},
/**
* Handle network event updates coming from the server.
*
* @param string aActorId
* The network event actor ID.
* @param string aType
* Update type.
* @param object aPacket
* @param object networkInfo
* The network request information.
* @param object packet
* Update details.
*/
handleNetworkEventUpdate:
function WCF_handleNetworkEventUpdate(aActorId, aType, aPacket)
handleNetworkEventUpdate: function(networkInfo, packet)
{
let networkInfo = this._networkRequests[aActorId];
if (!networkInfo) {
return;
}
networkInfo.updates.push(aType);
switch (aType) {
case "requestHeaders":
networkInfo.request.headersSize = aPacket.headersSize;
break;
case "requestPostData":
networkInfo.discardRequestBody = aPacket.discardRequestBody;
networkInfo.request.bodySize = aPacket.dataSize;
break;
case "responseStart":
networkInfo.response.httpVersion = aPacket.response.httpVersion;
networkInfo.response.status = aPacket.response.status;
networkInfo.response.statusText = aPacket.response.statusText;
networkInfo.response.headersSize = aPacket.response.headersSize;
networkInfo.discardResponseBody = aPacket.response.discardResponseBody;
break;
case "responseContent":
networkInfo.response.content = {
mimeType: aPacket.mimeType,
};
networkInfo.response.bodySize = aPacket.contentSize;
networkInfo.discardResponseBody = aPacket.discardResponseBody;
break;
case "eventTimings":
networkInfo.totalTime = aPacket.totalTime;
break;
}
if (networkInfo.node && this._updateNetMessage(aActorId)) {
if (networkInfo.node && this._updateNetMessage(packet.from)) {
this.emit("new-messages", new Set([{
update: true,
node: networkInfo.node,
response: aPacket,
response: packet,
}]));
}
@@ -1858,7 +1830,7 @@ WebConsoleFrame.prototype = {
*/
_updateNetMessage: function WCF__updateNetMessage(aActorId)
{
let networkInfo = this._networkRequests[aActorId];
let networkInfo = this.webConsoleClient.getNetworkRequest(aActorId);
if (!networkInfo || !networkInfo.node) {
return;
}
@@ -2404,8 +2376,8 @@ WebConsoleFrame.prototype = {
else if (typeof methodOrNode != "function") {
connectionId = methodOrNode._connectionId;
}
if (connectionId && connectionId in this._networkRequests) {
delete this._networkRequests[connectionId];
if (connectionId && this.webConsoleClient.hasNetworkRequest(connectionId)) {
this.webConsoleClient.removeNetworkRequest(connectionId);
this._releaseObject(connectionId);
}
}
@@ -2482,7 +2454,7 @@ WebConsoleFrame.prototype = {
}
else if (aNode._connectionId &&
aNode.category == CATEGORY_NETWORK) {
delete this._networkRequests[aNode._connectionId];
this.webConsoleClient.removeNetworkRequest(aNode._connectionId);
this._releaseObject(aNode._connectionId);
}
else if (aNode.classList.contains("inlined-variables-view")) {
@@ -2979,7 +2951,7 @@ WebConsoleFrame.prototype = {
this._itemDestroyQueue.forEach(this._destroyItem, this);
this._itemDestroyQueue = [];
this._pruneCategoriesQueue = {};
this._networkRequests = {};
this.webConsoleClient.clearNetworkRequests();
if (this._outputTimerInitialized) {
this._outputTimerInitialized = false;
@@ -3058,17 +3030,11 @@ function JSTerm(aWebConsoleFrame)
{
this.hud = aWebConsoleFrame;
this.hudId = this.hud.hudId;
this.inputHistoryCount = Services.prefs.getIntPref(PREF_INPUT_HISTORY_COUNT);
this.lastCompletion = { value: null };
this.history = [];
this._loadHistory();
// Holds the number of entries in history. This value is incremented in
// this.execute().
this.historyIndex = 0; // incremented on this.execute()
// Holds the index of the history entry that the user is currently viewing.
// This is reset to this.history.length when this.execute() is invoked.
this.historyPlaceHolder = 0;
this._objectActorsInVariablesViews = new Map();
this._keyPress = this._keyPress.bind(this);
@@ -3083,6 +3049,53 @@ function JSTerm(aWebConsoleFrame)
JSTerm.prototype = {
SELECTED_FRAME: -1,
/**
* Load the console history from previous sessions.
* @private
*/
_loadHistory: function() {
this.history = [];
this.historyIndex = this.historyPlaceHolder = 0;
this.historyLoaded = asyncStorage.getItem("webConsoleHistory").then(value => {
if (Array.isArray(value)) {
// Since it was gotten asynchronously, there could be items already in
// the history. It's not likely but stick them onto the end anyway.
this.history = value.concat(this.history);
// Holds the number of entries in history. This value is incremented in
// this.execute().
this.historyIndex = this.history.length;
// Holds the index of the history entry that the user is currently viewing.
// This is reset to this.history.length when this.execute() is invoked.
this.historyPlaceHolder = this.history.length;
}
}, console.error);
},
/**
* Clear the console history altogether. Note that this will not affect
* other consoles that are already opened (since they have their own copy),
* but it will reset the array for all newly-opened consoles.
* @returns Promise
* Resolves once the changes have been persisted.
*/
clearHistory: function() {
this.history = [];
this.historyIndex = this.historyPlaceHolder = 0;
return this.storeHistory();
},
/**
* Stores the console history for future console instances.
* @returns Promise
* Resolves once the changes have been persisted.
*/
storeHistory: function() {
return asyncStorage.setItem("webConsoleHistory", this.history);
},
/**
* Stores the data for the last completion.
* @type object
@@ -3273,6 +3286,9 @@ JSTerm.prototype = {
case "clearOutput":
this.clearOutput();
break;
case "clearHistory":
this.clearHistory();
break;
case "inspectObject":
if (aAfterMessage) {
if (!aAfterMessage._objectActors) {
@@ -3392,6 +3408,12 @@ JSTerm.prototype = {
// value that was not evaluated yet.
this.history[this.historyIndex++] = aExecuteString;
this.historyPlaceHolder = this.history.length;
if (this.history.length > this.inputHistoryCount) {
this.history.splice(0, this.history.length - this.inputHistoryCount);
this.historyIndex = this.historyPlaceHolder = this.history.length;
}
this.storeHistory();
WebConsoleUtils.usageCount++;
this.setInputValue("");
this.clearCompletion();
@@ -3883,7 +3905,7 @@ JSTerm.prototype = {
hud.groupDepth = 0;
hud._outputQueue.forEach(hud._destroyItem, hud);
hud._outputQueue = [];
hud._networkRequests = {};
this.webConsoleClient.clearNetworkRequests();
hud._repeatNodes = {};
if (aClearStorage) {
@@ -5023,8 +5045,6 @@ WebConsoleConnectionProxy.prototype = {
client.addListener("logMessage", this._onLogMessage);
client.addListener("pageError", this._onPageError);
client.addListener("consoleAPICall", this._onConsoleAPICall);
client.addListener("networkEvent", this._onNetworkEvent);
client.addListener("networkEventUpdate", this._onNetworkEventUpdate);
client.addListener("fileActivity", this._onFileActivity);
client.addListener("reflowActivity", this._onReflowActivity);
client.addListener("lastPrivateContextExited", this._onLastPrivateContextExited);
@@ -5089,6 +5109,8 @@ WebConsoleConnectionProxy.prototype = {
this.webConsoleClient = aWebConsoleClient;
this._hasNativeConsoleAPI = aResponse.nativeConsoleAPI;
this.webConsoleClient.on("networkEvent", this._onNetworkEvent);
this.webConsoleClient.on("networkEventUpdate", this._onNetworkEventUpdate);
let msgs = ["PageError", "ConsoleAPI"];
this.webConsoleClient.getCachedMessages(msgs, this._onCachedMessages);
@@ -5118,7 +5140,10 @@ WebConsoleConnectionProxy.prototype = {
Cu.reportError("Web Console getCachedMessages error: invalid state.");
}
this.owner.displayCachedMessages(aResponse.messages);
let messages = aResponse.messages.concat(...this.webConsoleClient.getNetworkEvents());
messages.sort((a, b) => a.timeStamp - b.timeStamp);
this.owner.displayCachedMessages(messages);
if (!this._hasNativeConsoleAPI) {
this.owner.logWarningAboutReplacedAPI();
@@ -5184,15 +5209,15 @@ WebConsoleConnectionProxy.prototype = {
* the UI for displaying.
*
* @private
* @param string aType
* @param string type
* Message type.
* @param object aPacket
* The message received from the server.
* @param object networkInfo
* The network request information.
*/
_onNetworkEvent: function WCCP__onNetworkEvent(aType, aPacket)
_onNetworkEvent: function(type, networkInfo)
{
if (this.owner && aPacket.from == this._consoleActor) {
this.owner.handleNetworkEvent(aPacket.eventActor);
if (this.owner) {
this.owner.handleNetworkEvent(networkInfo);
}
},
@@ -5201,16 +5226,17 @@ WebConsoleConnectionProxy.prototype = {
* the UI for displaying.
*
* @private
* @param string aType
* @param string type
* Message type.
* @param object aPacket
* @param object packet
* The message received from the server.
* @param object networkInfo
* The network request information.
*/
_onNetworkEventUpdate: function WCCP__onNetworkEvenUpdatet(aType, aPacket)
_onNetworkEventUpdate: function(type, { packet, networkInfo })
{
if (this.owner) {
this.owner.handleNetworkEventUpdate(aPacket.from, aPacket.updateType,
aPacket);
this.owner.handleNetworkEventUpdate(networkInfo, packet);
}
},
@@ -5310,11 +5336,11 @@ WebConsoleConnectionProxy.prototype = {
this.client.removeListener("logMessage", this._onLogMessage);
this.client.removeListener("pageError", this._onPageError);
this.client.removeListener("consoleAPICall", this._onConsoleAPICall);
this.client.removeListener("networkEvent", this._onNetworkEvent);
this.client.removeListener("networkEventUpdate", this._onNetworkEventUpdate);
this.client.removeListener("fileActivity", this._onFileActivity);
this.client.removeListener("reflowActivity", this._onReflowActivity);
this.client.removeListener("lastPrivateContextExited", this._onLastPrivateContextExited);
this.webConsoleClient.off("networkEvent", this._onNetworkEvent);
this.webConsoleClient.off("networkEventUpdate", this._onNetworkEventUpdate);
this.target.off("will-navigate", this._onTabNavigated);
this.target.off("navigate", this._onTabNavigated);