Bug 1354679 - Automatically display the PausedDebuggerOverlay when the debugger is paused. r=gl

Differential Revision: https://phabricator.services.mozilla.com/D35162

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Jason Laster 2019-07-09 22:01:34 +00:00
Родитель 20ee1b2284
Коммит 5970b1a8fe
8 изменённых файлов: 202 добавлений и 33 удалений

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

@ -69,6 +69,7 @@ if (isDevelopment()) {
pref("devtools.debugger.features.event-listeners-breakpoints", true);
pref("devtools.debugger.features.log-points", true);
pref("devtools.debugger.log-actions", true);
pref("devtools.debugger.features.overlay-step-buttons", false);
}
export const prefs = new PrefsHelper("devtools", {
@ -128,6 +129,7 @@ export const features = new PrefsHelper("devtools.debugger.features", {
originalBlackbox: ["Bool", "original-blackbox"],
eventListenersBreakpoints: ["Bool", "event-listeners-breakpoints"],
logPoints: ["Bool", "log-points"],
showOverlayStepButtons: ["Bool", "debugger.features.overlay-step-buttons"],
});
export const asyncStore = asyncStoreHelper("debugger", {

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

@ -583,6 +583,9 @@ Toolbox.prototype = {
ignoreCaughtExceptions: Services.prefs.getBoolPref(
"devtools.debugger.ignore-caught-exceptions"
),
showOverlayStepButtons: Services.prefs.getBoolPref(
"devtools.debugger.features.overlay-step-buttons"
),
};
const [, threadClient] = await this._target.attachThread(threadOptions);

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

@ -76,3 +76,4 @@ pref("devtools.debugger.features.original-blackbox", true);
pref("devtools.debugger.features.windowless-workers", true);
pref("devtools.debugger.features.event-listeners-breakpoints", true);
pref("devtools.debugger.features.log-points", true);
pref("devtools.debugger.features.overlay-step-buttons", false);

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

@ -584,8 +584,12 @@
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
zoom: 1;
right: 0;
bottom: 0;
width: 100vw;
height: 100vh;
display: flex;
align-items: center;
@ -596,7 +600,7 @@
--text-color: #585959; /* --theme-body-color-alt */
--toolbar-background: #fcfcfc; /* --theme-toolbar-background */;
--toolbar-border: #dde1e4; /* --theme-splitter-color */
--toolbar-box-shadow: 0 4px 4px 0 rgba(155, 155, 155, 0.26); /* --rdm-box-shadow */
--toolbar-box-shadow: 0 2px 2px 0 rgba(155, 155, 155, 0.26); /* --rdm-box-shadow */
--overlay-background: #dde1e4a8;
}
@ -607,21 +611,64 @@
:-moz-native-anonymous .paused-dbg-toolbar {
margin-top: 15px;
padding: 4px 5px;
display: inline-flex;
-moz-user-select: none;
pointer-events: auto;
color: var(--text-color);
border-radius: 2px;
box-shadow: var(--toolbar-box-shadow);
background-color: var(--toolbar-background);
border: 1px solid var(--toolbar-border);
border-radius: 4px;
font: var(--highlighter-font-family);
font-size: var(--highlighter-font-size);
}
:-moz-native-anonymous .paused-dbg-toolbar button {
margin: 8px 4px 6px 6px;
width: 14px;
height: 14px;
mask-size: contain;
mask-repeat: no-repeat;
mask-position: center;
mask-size: 14px 14px;
background-color: var(--text-color);
border: 0px;
-moz-appearance: none;
}
:-moz-native-anonymous .paused-dbg-toolbar button:hover {
cursor: pointer;
}
:-moz-native-anonymous .paused-dbg-divider {
width: 1px;
height: 14px;
margin-top: 8px;
background-color: var(--toolbar-border);
}
:-moz-native-anonymous button.paused-dbg-step-button {
margin-left: 10px;
mask-image: url(resource://devtools/client/debugger/images/stepOver.svg);
}
:-moz-native-anonymous button.paused-dbg-resume-button {
margin-right: 10px;
mask-image: url(resource://devtools/client/debugger/images/resume.svg);
}
:-moz-native-anonymous .paused-dbg-reason {
padding: 1px 16px;
margin: 6px 0px;
line-height: 16px;
font-size: 14px;
font: var(--highlighter-font-family);
font-size: var(--highlighter-font-size);
}
/* Shapes highlighter */
:-moz-native-anonymous .shapes-root {

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

@ -257,6 +257,10 @@ exports.HighlighterActor = protocol.ActorClassWithSpec(highlighterSpec, {
_currentNode: null,
pick: function() {
if (this._targetActor.threadActor) {
this._targetActor.threadActor.hideOverlay();
}
if (this._isPicking) {
return null;
}
@ -484,6 +488,9 @@ exports.HighlighterActor = protocol.ActorClassWithSpec(highlighterSpec, {
},
cancelPick: function() {
if (this._targetActor.threadActor) {
this._targetActor.threadActor.showOverlay();
}
if (this._isPicking) {
this._highlighter.hide();
this._stopPickerListeners();

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

@ -9,6 +9,10 @@ const {
createNode,
} = require("./utils/markup");
const { LocalizationHelper } = require("devtools/shared/l10n");
const STRINGS_URI = "devtools/client/shared/locales/debugger.properties";
const L10N = new LocalizationHelper(STRINGS_URI);
/**
* The PausedDebuggerOverlay is a class that displays a semi-transparent mask on top of
* the whole page and a toolbar at the top of the page.
@ -16,8 +20,12 @@ const {
* The toolbar is used to display the reason for the pause in script execution as well as
* buttons to resume or step through the program.
*/
function PausedDebuggerOverlay(highlighterEnv) {
function PausedDebuggerOverlay(highlighterEnv, options) {
this.env = highlighterEnv;
this.showOverlayStepButtons = options.showOverlayStepButtons;
this.resume = options.resume;
this.stepOver = options.stepOver;
this.markup = new CanvasFrameAnonymousContentHelper(
highlighterEnv,
this._buildMarkup.bind(this)
@ -68,6 +76,37 @@ PausedDebuggerOverlay.prototype = {
prefix,
});
if (this.showOverlayStepButtons) {
createNode(window, {
parent: toolbar,
attributes: {
id: "divider",
class: "divider",
},
prefix,
});
createNode(window, {
nodeType: "button",
parent: toolbar,
attributes: {
id: "step-button",
class: "step-button",
},
prefix,
});
createNode(window, {
nodeType: "button",
parent: toolbar,
attributes: {
id: "resume-button",
class: "resume-button",
},
prefix,
});
}
return container;
},
@ -77,35 +116,55 @@ PausedDebuggerOverlay.prototype = {
this.env = null;
},
onClick(target) {
if (target.id == "paused-dbg-step-button") {
this.stepOver();
} else if (target.id == "paused-dbg-resume-button") {
this.resume();
}
},
handleEvent(e) {
switch (e.type) {
case "click":
case "mouseup":
this.onClick(e.target);
break;
case "DOMMouseScroll":
// Prevent scrolling. That's because we only took a screenshot of the viewport, so
// scrolling out of the viewport wouldn't draw the expected things. In the future
// we can take the screenshot again on scroll, but for now it doesn't seem
// important.
e.preventDefault();
break;
case "mouseover":
console.log(`> mouse over ${e.target.id}`);
break;
}
},
getElement(id) {
return this.markup.getElement(this.ID_CLASS_PREFIX + id);
},
show(node, options = {}) {
if (this.env.isXUL) {
if (this.env.isXUL || !options.reason) {
return false;
}
// Show the highlighter's root element.
const root = this.getElement("root");
root.removeAttribute("hidden");
// The page overlay is only shown upon request. Sometimes we just want the toolbar.
if (options.onlyToolbar) {
root.removeAttribute("overlay");
} else {
root.setAttribute("overlay", "true");
}
root.setAttribute("overlay", "true");
// Set the text to appear in the toolbar.
const toolbar = this.getElement("toolbar");
if (options.reason) {
this.getElement("reason").setTextContent(options.reason);
toolbar.removeAttribute("hidden");
} else {
toolbar.setAttribute("hidden", "true");
}
this.getElement("reason").setTextContent(
L10N.getStr(`whyPaused.${options.reason}`)
);
toolbar.removeAttribute("hidden");
this.env.window.document.setSuppressedEventListener(this);
return true;
},

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

@ -53,6 +53,19 @@ loader.lazyRequireGetter(
);
loader.lazyRequireGetter(this, "throttle", "devtools/shared/throttle", true);
loader.lazyRequireGetter(
this,
"HighlighterEnvironment",
"devtools/server/actors/highlighters",
true
);
loader.lazyRequireGetter(
this,
"PausedDebuggerOverlay",
"devtools/server/actors/highlighters/paused-debugger",
true
);
/**
* JSD2 actors.
*/
@ -91,6 +104,7 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
this._observingNetwork = false;
this._activeEventBreakpoints = new Set();
this._activeEventPause = null;
this._pauseOverlay = null;
this._priorPause = null;
@ -241,6 +255,10 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
}
},
isPaused() {
return this._state === "paused";
},
/**
* Remove all debuggees and clear out the thread's sources.
*/
@ -396,6 +414,40 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
}
},
get pauseOverlay() {
if (this._pauseOverlay) {
return this._pauseOverlay;
}
const env = new HighlighterEnvironment();
env.initFromTargetActor(this._parent);
const highlighter = new PausedDebuggerOverlay(env, {
showOverlayStepButtons: this._options.showOverlayStepButtons,
resume: () => this.onResume({ resumeLimit: null }),
stepOver: () => this.onResume({ resumeLimit: { type: "next" } }),
});
this._pauseOverlay = highlighter;
return highlighter;
},
showOverlay() {
if (
this._parent.on &&
this.pauseOverlay &&
!this._parent.window.isChromeWindow &&
this.isPaused()
) {
const reason = this._priorPause.why.type;
this.pauseOverlay.show(null, { reason });
}
},
hideOverlay(msg) {
if (this._parent.on && !this._parent.window.isChromeWindow) {
this.pauseOverlay.hide();
}
},
/**
* Tell the thread to automatically add a breakpoint on the first line of
* a given file, when it is first loaded.
@ -712,6 +764,7 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
this._priorPause = pkt;
this.conn.sendActorEvent(this.actorID, "paused", pkt);
this.showOverlay();
} catch (error) {
reportError(error);
this.conn.send({
@ -1229,6 +1282,7 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
// Tell anyone who cares of the resume (as of now, that's the xpcshell harness and
// devtools-startup.js when handling the --wait-for-jsdebugger flag)
this.conn.sendActorEvent(this.actorID, "resumed");
this.hideOverlay();
if (Services.obs) {
Services.obs.notifyObservers(this, "devtools-thread-resumed");

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

@ -25,7 +25,7 @@ window.onload = function() {
const env = new HighlighterEnvironment();
env.initFromWindow(window);
const highlighter = new PausedDebuggerOverlay(env);
const highlighter = new PausedDebuggerOverlay(env, {});
const anonymousContent = highlighter.markup.content;
const id = elementID => `${highlighter.ID_CLASS_PREFIX}${elementID}`;
@ -53,32 +53,28 @@ window.onload = function() {
ok(isHidden("root"), "The highlighter is hidden");
info("Show the highlighter with overlay and toolbar");
let didShow = highlighter.show(null, {"reason": "Paused in debugger"});
let didShow = highlighter.show(null, { "reason": "breakpoint" });
ok(didShow, "Calling show returned true");
ok(!isHidden("root"), "The highlighter is shown");
ok(isOverlayShown(), "The overlay is shown");
is(getReason(), "Paused in debugger", "The reason displayed in the toolbar is correct");
is(
getReason(),
"Paused on breakpoint",
"The reason displayed in the toolbar is correct"
);
info("Call show again with another reason");
didShow = highlighter.show(null, {"reason": "Paused for another reason"});
didShow = highlighter.show(null, {"reason": "debuggerStatement"});
ok(didShow, "Calling show returned true too");
ok(!isHidden("root"), "The highlighter is still shown");
is(getReason(), "Paused for another reason",
is(getReason(), "Paused on debugger statement",
"The reason displayed in the toolbar is correct again");
ok(isOverlayShown(), "The overlay is still shown too");
info("Call show again but with no reason");
highlighter.show();
ok(isHidden("toolbar"), "The toolbar is hidden");
ok(isOverlayShown(), "The overlay is shown however");
info("Call show again with a reason but no overlay");
highlighter.show(null, {reason: "no overlay this time", onlyToolbar: true});
ok(!isHidden("toolbar"), "The toolbar is shown this time");
is(getReason(), "no overlay this time",
"The reason displayed in the toolbar is correct again");
ok(!isOverlayShown(), "The overlay is hidden");
info("Hide the highlighter");
highlighter.hide();
ok(isHidden("root"), "The highlighter is now hidden");