diff options
Diffstat (limited to 'devtools/server/actors/resources/css-messages.js')
-rw-r--r-- | devtools/server/actors/resources/css-messages.js | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/devtools/server/actors/resources/css-messages.js b/devtools/server/actors/resources/css-messages.js new file mode 100644 index 0000000000..1e3f901880 --- /dev/null +++ b/devtools/server/actors/resources/css-messages.js @@ -0,0 +1,133 @@ +/* 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 nsIConsoleListenerWatcher = require("devtools/server/actors/resources/utils/nsi-console-listener-watcher"); +const { Ci } = require("chrome"); +const { DevToolsServer } = require("devtools/server/devtools-server"); +const { createStringGrip } = require("devtools/server/actors/object/utils"); +const { + getActorIdForInternalSourceId, +} = require("devtools/server/actors/utils/dbg-source"); + +const { + TYPES: { CSS_MESSAGE }, +} = require("devtools/server/actors/resources/index"); + +const { MESSAGE_CATEGORY } = require("devtools/shared/constants"); + +class CSSMessageWatcher extends nsIConsoleListenerWatcher { + /** + * Start watching for all CSS messages related to a given Target Actor. + * This will notify about existing messages, but also the one created in future. + * + * @param TargetActor targetActor + * The target actor from which we should observe messages + * @param Object options + * Dictionary object with following attributes: + * - onAvailable: mandatory function + * This will be called for each resource. + */ + async watch(targetActor, { onAvailable }) { + super.watch(targetActor, { onAvailable }); + + // Calling ensureCSSErrorReportingEnabled will make the server parse the stylesheets to + // retrieve the warnings if the docShell wasn't already watching for CSS messages. + if (targetActor.ensureCSSErrorReportingEnabled) { + targetActor.ensureCSSErrorReportingEnabled(); + } + } + + /** + * Returns true if the message is considered a CSS message, and as a result, should + * be sent to the client. + * + * @param {nsIConsoleMessage|nsIScriptError} message + */ + shouldHandleMessage(targetActor, message) { + // The listener we use can be called either with a nsIConsoleMessage or as nsIScriptError. + // In this file, we want to ignore anything but nsIScriptError. + if ( + // We only care about CSS Parser nsIScriptError + !(message instanceof Ci.nsIScriptError) || + message.category !== MESSAGE_CATEGORY.CSS_PARSER + ) { + return false; + } + + // Process targets listen for everything but messages from private windows. + if (this.isProcessTarget(targetActor)) { + return !message.isFromPrivateWindow; + } + + if (!message.innerWindowID) { + return false; + } + + const { window } = targetActor; + const win = window?.WindowGlobalChild?.getByInnerWindowId( + message.innerWindowID + ); + return targetActor.browserId === win?.browsingContext?.browserId; + } + + /** + * Prepare an nsIScriptError to be sent to the client. + * + * @param nsIScriptError error + * The page error we need to send to the client. + * @return object + * The object you can send to the remote client. + */ + buildResource(targetActor, error) { + const stack = this.prepareStackForRemote(targetActor, error.stack); + let lineText = error.sourceLine; + if ( + lineText && + lineText.length > DevToolsServer.LONG_STRING_INITIAL_LENGTH + ) { + lineText = lineText.substr(0, DevToolsServer.LONG_STRING_INITIAL_LENGTH); + } + + const notesArray = this.prepareNotesForRemote(targetActor, error.notes); + + // If there is no location information in the error but we have a stack, + // fill in the location with the first frame on the stack. + let { sourceName, sourceId, lineNumber, columnNumber } = error; + if (!sourceName && !sourceId && !lineNumber && !columnNumber && stack) { + sourceName = stack[0].filename; + sourceId = stack[0].sourceId; + lineNumber = stack[0].lineNumber; + columnNumber = stack[0].columnNumber; + } + + const pageError = { + errorMessage: createStringGrip(targetActor, error.errorMessage), + sourceName, + sourceId: getActorIdForInternalSourceId(targetActor, sourceId), + lineText, + lineNumber, + columnNumber, + category: error.category, + innerWindowID: error.innerWindowID, + timeStamp: error.timeStamp, + warning: !!(error.flags & error.warningFlag), + error: !(error.flags & (error.warningFlag | error.infoFlag)), + info: !!(error.flags & error.infoFlag), + private: error.isFromPrivateWindow, + stacktrace: stack, + notes: notesArray, + chromeContext: error.isFromChromeContext, + isForwardedFromContentProcess: error.isForwardedFromContentProcess, + }; + + return { + pageError, + resourceType: CSS_MESSAGE, + cssSelectors: error.cssSelectors, + }; + } +} +module.exports = CSSMessageWatcher; |