Bug 1354679 - Use highlighter actor from client instead of from the server
MozReview-Commit-ID: J8DEwNJgpE9
--- a/devtools/client/framework/attach-thread.js
+++ b/devtools/client/framework/attach-thread.js
@@ -5,42 +5,50 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const {Cc, Ci, Cu} = require("chrome");
const Services = require("Services");
const defer = require("devtools/shared/defer");
const {LocalizationHelper} = require("devtools/shared/l10n");
const L10N = new LocalizationHelper("devtools/client/locales/toolbox.properties");
+const debuggerL10N = new LocalizationHelper("devtools/client/locales/debugger.properties");
function handleThreadState(toolbox, event, packet) {
// Suppress interrupted events by default because the thread is
// paused/resumed a lot for various actions.
if (event !== "paused" || packet.why.type !== "interrupted") {
// TODO: Bug 1225492, we continue emitting events on the target
// like we used to, but we should emit these only on the
// threadClient now.
toolbox.target.emit("thread-" + event);
}
if (event === "paused") {
toolbox.highlightTool("jsdebugger");
if (packet.why.type === "debuggerStatement" ||
packet.why.type === "breakpoint" ||
- packet.why.type === "exception") {
+ packet.why.type === "exception")
+ {
toolbox.raise();
toolbox.selectTool("jsdebugger");
- toolbox._threadClient.clientPaused();
+
+ // TODO: move this to the frontend so we can make use of the paused reason
+ // directly
+ const reason = debuggerL10N.getStr("defaultPausedReason");
+ toolbox.highlighterUtils.showPausedOverlay(reason);
}
} else if (event === "resumed") {
+ toolbox.highlighterUtils.hidePausedOverlay();
toolbox.unhighlightTool("jsdebugger");
}
}
+
function attachThread(toolbox) {
let deferred = defer();
let target = toolbox.target;
let { form: { chromeDebugger, actor } } = target;
// Sourcemaps are always turned off when using the new debugger
// frontend. This is because it does sourcemapping on the
--- a/devtools/client/framework/toolbox-highlighter-utils.js
+++ b/devtools/client/framework/toolbox-highlighter-utils.js
@@ -84,16 +84,53 @@ exports.getHighlighterUtils = function (
yield toolbox.initInspector();
isInspectorInitialized = true;
}
return yield generator.apply(null, args);
});
};
/**
+ * Show/hide the paused overlays for a collection of tabs
+ * @param {TabActor} tabActor - Optionally focus the content area once the picker is
+ */
+
+ /*
+ * Manage a collection of PausedDebuggerOverlay highlighters and their HighlighterEnvironments indexed
+ * by TabActors (export it so it the paused state can be tested).
+ */
+ const pausedStateOverlays = new Map();
+
+ async function _getPausedStateOverlay(tabActor) {
+ if (pausedStateOverlays.has(tabActor)) {
+ return pausedStateOverlays.get(tabActor).overlay;
+ }
+ const overlay = await exported.getHighlighterByType("PausedDebuggerOverlay");
+ pausedStateOverlays.set(tabActor, { overlay });
+
+ return overlay;
+ }
+
+ exported.showPausedOverlay = async function (reason) {
+ let overlay = await _getPausedStateOverlay(target.activeTab);
+ // get the root node for the tab, where the highlighter will be displayed
+ let nodeFront = await toolbox.inspector.walker.getRootNode();
+ overlay.show(nodeFront, {reason});
+ };
+
+ exported.hidePausedOverlay = function () {
+ const overlayAndEnvironment = pausedStateOverlays.get(target.activeTab);
+ if (!overlayAndEnvironment) {
+ return;
+ }
+
+ overlayAndEnvironment.overlay.hide();
+ };
+
+ /**
* Start/stop the element picker on the debuggee target.
* @param {Boolean} doFocus - Optionally focus the content area once the picker is
* activated.
* @return A promise that resolves when done
*/
exported.togglePicker = function (doFocus) {
if (isPicking) {
return cancelPicker();
--- a/devtools/client/framework/toolbox.js
+++ b/devtools/client/framework/toolbox.js
@@ -428,19 +428,19 @@ Toolbox.prototype = {
// Start tracking network activity on toolbox open for targets such as tabs.
// (Workers and potentially others don't manage the console client in the target.)
if (this._target.activeConsole) {
yield this._target.activeConsole.startListeners([
"NetworkActivity",
]);
}
+ yield domReady.promise;
// Attach the thread
this._threadClient = yield attachThread(this);
- yield domReady.promise;
this.isReady = true;
let framesPromise = this._listFrames();
Services.prefs.addObserver("devtools.cache.disabled", this._applyCacheSettings);
Services.prefs.addObserver("devtools.serviceWorkers.testing.enabled",
this._applyServiceWorkersTestingSettings);
--- a/devtools/client/locales/en-US/debugger.properties
+++ b/devtools/client/locales/en-US/debugger.properties
@@ -543,16 +543,21 @@ ignoreExceptions=Ignore exceptions. Clic
# LOCALIZATION NOTE (pauseOnUncaughtExceptions): The pause on exceptions button
# tooltip when the debugger will pause on uncaught exceptions.
pauseOnUncaughtExceptions=Pause on uncaught exceptions. Click to pause on all exceptions
# LOCALIZATION NOTE (pauseOnExceptions): The pause on exceptions button tooltip
# when the debugger will pause on all exceptions.
pauseOnExceptions=Pause on all exceptions. Click to ignore exceptions
+# LOCALIZATION NOTE (defaultPausedReason): Text displayed inside the content page, in an
+# overlay, when the debugger is paused (so script execution is paused), explaining to the
+# user why the page is paused.
+defaultPausedReason=Paused in debugger
+
# LOCALIZATION NOTE (loadingText): The text that is displayed in the script
# editor when the loading process has started but there is no file to display
# yet.
loadingText=Loading\u2026
# LOCALIZATION NOTE (errorLoadingText3): The text that is displayed in the debugger
# viewer when there is an error loading a file
errorLoadingText3=Error loading this URI: %S
--- a/devtools/server/actors/script.js
+++ b/devtools/server/actors/script.js
@@ -424,18 +424,16 @@ const ThreadActor = ActorClassWithSpec(t
this._frameActors = [];
this._parent = parent;
this._dbg = null;
this._gripDepth = 0;
this._threadLifetimePool = null;
this._tabClosed = false;
this._scripts = null;
this._pauseOnDOMEvents = null;
- EventEmitter.decorate(this);
- attachPauseStateListeners(this)
this._options = {
useSourceMaps: false,
autoBlackBox: false
};
this.breakpointActorMap = new BreakpointActorMap();
this.sourceActorStore = new SourceActorStore();
@@ -602,17 +600,16 @@ const ThreadActor = ActorClassWithSpec(t
this._dbg.enabled = false;
this._dbg = null;
},
/**
* destroy the debugger and put the actor in the exited state.
*/
exit: function () {
- this.emit("exited");
this.destroy();
this._state = "exited";
},
// Request handlers
onAttach: function (request) {
if (this.state === "exited") {
return { type: "exited" };
@@ -1223,24 +1220,16 @@ const ThreadActor = ActorClassWithSpec(t
_getNextStepFrame: function (frame) {
let stepFrame = frame.reportedPop ? frame.older : frame;
if (!stepFrame || !stepFrame.script) {
stepFrame = null;
}
return stepFrame;
},
- /**
- * Client informs the server that we have a user significant pause.
- */
- onClientPaused: function () {
- this.emit("clientPaused");
- return { type: "clientPaused" };
- },
-
onClientEvaluate: function (request) {
if (this.state !== "paused") {
return { error: "wrongState",
message: "Debuggee must be paused to evaluate code." };
}
let frame = this._requestFrame(request.frame);
if (!frame) {
@@ -1604,17 +1593,16 @@ const ThreadActor = ActorClassWithSpec(t
if (poppedFrames) {
packet.poppedFrames = poppedFrames;
}
return packet;
},
_resumed: function () {
- this.emit('resumed');
this._state = "running";
// Drop the actors in the pause actor pool.
this.conn.removeActorPool(this._pausePool);
this._pausePool = null;
this._pauseActor = null;
@@ -2391,101 +2379,8 @@ exports.unwrapDebuggerObjectGlobal = wra
// that any dead object proxies make themselves known.
let global = wrappedGlobal.unsafeDereference();
Object.getPrototypeOf(global) + "";
return global;
} catch (e) {
return undefined;
}
};
-
-// Manage a collection of PausedDebuggerOverlays and their HighlighterEnvironments indexed
-// by TabActors (export it so it the paused state can be tested).
-const pausedStateOverlays = exports.pausedStateOverlays = new Map();
-
-function attachPauseStateListeners(threadActor) {
- EventEmitter.on(threadActor, "clientPaused", () => showPausedStateOverlay(threadActor._parent));
- EventEmitter.on(threadActor, "resumed",() => hidePausedStateOverlay(threadActor._parent));
- EventEmitter.on(threadActor, "exiting",() => destroyPausedStateOverlay(threadActor._parent));
-}
-
-/**
- * Get the instance of the PausedDebuggerOverlay for a TabActor.
- *
- * @param {TabActor} tabActor
- * The parent of the threadActor.
- *
- * @return {PausedDebuggerOverlay}
- * The instance of the overlay, or null if it can't be created in this TabActor.
- * For instance, we can't insert an overlay when debugging the whole browser UI
- * from the Browser Toolbox or a worker.
- */
-function getPausedStateOverlay(tabActor) {
- if (pausedStateOverlays.has(tabActor)) {
- return pausedStateOverlays.get(tabActor).overlay;
- }
-
- if (!tabActor.window || !tabActor.window.document) {
- return null;
- }
-
- const principal = tabActor.window.document.nodePrincipal;
- if (Services.scriptSecurityManager.isSystemPrincipal(principal)) {
- return null;
- }
-
- require("devtools/server/actors/inspector");
- const { HighlighterEnvironment } = require("devtools/server/actors/highlighters");
- const { PausedDebuggerOverlay } = require("devtools/server/actors/highlighters/paused-debugger");
-
- const environment = new HighlighterEnvironment();
- environment.initFromTabActor(tabActor);
-
- const overlay = new PausedDebuggerOverlay(environment);
- pausedStateOverlays.set(tabActor, { overlay, environment });
-
- return overlay;
-}
-
-/**
- * Show the PausedDebuggerOverlay, creating it first if it doesn't exist.
- *
- * @param {TabActor} tabActor
- * The parent of the threadActor.
- */
-function showPausedStateOverlay(tabActor) {
- let overlay = getPausedStateOverlay(tabActor);
- if (overlay) {
- // TODO: for now, the same reason is always shown. In the future, we would like to
- // show the same reason that is also shown inside the debugger panel UI (using the
- // code in aReason.type). See the following issue for why we didn't do this already:
- // https://github.com/devtools-html/debugger.html/pull/2581
- overlay.show(null, {reason: l10n.GetStringFromName("debuggerPausedReason")});
- }
-}
-
-/**
- * Hide the PausedDebuggerOverlay, if it was shown before.
- *
- * @param {TabActor} tabActor
- * The parent of the threadActor.
- */
-function hidePausedStateOverlay(tabActor) {
- // Check if it even exists first, if not we don't need to do anything.
- const overlayAndEnvironment = pausedStateOverlays.get(tabActor);
- if (!overlayAndEnvironment) {
- return;
- }
-
- overlayAndEnvironment.overlay.hide();
-}
-
-/**
- * Destroy all PausedDebuggerOverlays instances and their HighlighterEnvironments too.
- * This is needed when we exit the debugger.
- */
-function destroyPausedStateOverlays() {
- for (let { overlay, environment } of pausedStateOverlays.values()) {
- overlay.destroy();
- environment.destroy();
- }
- pausedStateOverlays.clear();
-}
--- a/devtools/shared/locales/en-US/debugger.properties
+++ b/devtools/shared/locales/en-US/debugger.properties
@@ -52,13 +52,8 @@ clientSendOOBHash=My Cert: %1$S
clientSendOOBToken=Token: %1$S
# LOCALIZATION NOTE (serverReceiveOOBTitle): The title displayed on the dialog
# that instructs the user to provide an authentication token from the client.
serverReceiveOOBTitle=Provide Client Token
# LOCALIZATION NOTE (serverReceiveOOBBody): Main text displayed on the dialog
# that instructs the user to provide an authentication token from the client.
serverReceiveOOBBody=The client should be displaying a token value. Enter that token value here to complete authentication with this client.
-
-# LOCALIZATION NOTE (debuggerPausedReason): Text displayed inside the content page, in an
-# overlay, when the debugger is paused (so script execution is paused), explaining to the
-# user why the page is paused.
-debuggerPausedReason=Paused in debugger