Bug 1608261 - Shade untraversed and unscanned regions differently on timeline, r=jlast.

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Brian Hackett 2020-01-10 20:39:03 +00:00
parent b0f0989ac5
commit ecd563dce4
6 changed files with 56 additions and 74 deletions

View File

@ -702,6 +702,13 @@
opacity: 0.5;
}
.webreplay-player .untraversed {
position: absolute;
height: 100%;
background: #000000;
opacity: 0.2;
}
.webreplay-player .unscanned {
position: absolute;
height: 100%;

View File

@ -159,7 +159,7 @@ class WebReplayPlayer extends Component {
this.overlayWidth = this.updateOverlayWidth();
this.threadFront.on("paused", this.onPaused.bind(this));
this.threadFront.on("resumed", this.onResumed.bind(this));
this.threadFront.on("progress", this.onProgress.bind(this));
this.threadFront.on("replayStatusUpdate", this.onStatusUpdate.bind(this));
this.toolbox.getPanelWhenReady("webconsole").then(panel => {
const consoleFrame = panel.hud.ui;
@ -270,13 +270,13 @@ class WebReplayPlayer extends Component {
this.setState({ paused: false, closestMessage: null, pausedMessage: null });
}
onProgress(packet) {
onStatusUpdate({ status }) {
const {
recording,
executionPoint,
unscannedRegions,
cachedPoints,
} = packet;
} = status;
log(`progress: ${recording ? "rec" : "play"} ${executionPoint.progress}`);
if (this.state.seeking) {
@ -689,7 +689,7 @@ class WebReplayPlayer extends Component {
);
}
renderUnscannedRegion({ start, end }) {
renderUnscannedRegion({ start, end, traversed }) {
let startOffset = this.getVisibleOffset({ progress: start });
let endOffset = this.getVisibleOffset({ progress: end });
@ -706,7 +706,7 @@ class WebReplayPlayer extends Component {
}
return dom.span({
className: classname("unscanned"),
className: traversed ? classname("unscanned") : classname("untraversed"),
style: {
left: `${startOffset}px`,
width: `${endOffset - startOffset}px`,

View File

@ -556,7 +556,7 @@ function spawnTrunkChild() {
assert(gLastSavedCheckpoint == InvalidCheckpointId);
}
function forkBranchChild(lastSavedCheckpoint, nextSavedCheckpoint) {
async function forkBranchChild(lastSavedCheckpoint, nextSavedCheckpoint) {
if (!RecordReplayControl.canRewind()) {
return;
}
@ -574,7 +574,7 @@ function forkBranchChild(lastSavedCheckpoint, nextSavedCheckpoint) {
gBranchChildren.push({ child, point });
const endpoint = checkpointExecutionPoint(nextSavedCheckpoint);
gTrunkChild.sendManifest({
await gTrunkChild.sendManifest({
kind: "runToPoint",
endpoint,
@ -582,6 +582,8 @@ function forkBranchChild(lastSavedCheckpoint, nextSavedCheckpoint) {
// from throughout the recording will be cached in the root child.
flushExternalCalls: true,
});
updateStatus();
}
function respawnCrashedChild(child) {
@ -861,9 +863,7 @@ async function scanRecording(checkpoint) {
gScannedSavedCheckpoints.add(checkpoint);
// Update the unscanned regions in the UI.
if (gDebugger) {
gDebugger._callOnPositionChange();
}
updateStatus();
resolve(child);
return child;
@ -872,14 +872,24 @@ async function scanRecording(checkpoint) {
function unscannedRegions() {
const result = [];
const traversedCheckpoint =
gTrunkChild && gTrunkChild.lastPausePoint
? gTrunkChild.lastPausePoint.checkpoint
: FirstCheckpointId;
function addRegion(startCheckpoint, endCheckpoint) {
const start = checkpointExecutionPoint(startCheckpoint).progress;
const end = checkpointExecutionPoint(endCheckpoint).progress;
const traversed = endCheckpoint <= traversedCheckpoint;
if (result.length && result[result.length - 1].end == start) {
if (
result.length &&
result[result.length - 1].end == start &&
result[result.length - 1].traversed == traversed
) {
result[result.length - 1].end = end;
} else {
result.push({ start, end });
result.push({ start, end, traversed });
}
}
@ -1060,9 +1070,7 @@ function addPauseData(point, data, trackCached) {
if (trackCached) {
gCachedPoints.set(pointToString(point), point);
if (gDebugger) {
gDebugger._callOnPositionChange();
}
updateStatus();
}
}
@ -1134,6 +1142,7 @@ function setReplayingPauseTarget(point) {
const child = newLeafChild(point);
setPauseState(PauseModes.PAUSED, point, child);
updateStatus();
gDebugger._onPause();
findFrameSteps(point);
@ -1230,7 +1239,7 @@ async function finishResume() {
assert(forward);
RecordReplayControl.restoreMainGraphics();
setPauseState(PauseModes.RUNNING, gMainChild.pausePoint(), gMainChild);
gDebugger._callOnPositionChange();
updateStatus();
maybeResumeRecording();
} else {
// We searched backward to the beginning of the recording, so restore the
@ -1720,6 +1729,7 @@ function maybeResumeRecording() {
gPausePoint = gMainChild.pausePoint();
if (gDebugger) {
updateStatus();
gDebugger._onPause();
} else {
Services.tm.dispatchToMainThread(maybeResumeRecording);
@ -1876,11 +1886,6 @@ const gControl = {
return point;
},
// Return whether the active child is currently recording.
childIsRecording() {
return gActiveChild && gActiveChild.recording;
},
// Ensure the active child is paused.
waitUntilPaused() {
// The debugger should not use this method while we are actively resuming.
@ -2007,9 +2012,6 @@ const gControl = {
setActiveEventBreakpoints,
unscannedRegions,
cachedPoints,
debuggerRequests() {
return gDebuggerRequests;
},
@ -2060,6 +2062,17 @@ const gControl = {
},
};
function updateStatus() {
if (gDebugger && gDebugger.replayingOnStatusUpdate) {
gDebugger.replayingOnStatusUpdate({
recording: gActiveChild && gActiveChild.recording,
executionPoint: gPausePoint,
cachedPoints: cachedPoints(),
unscannedRegions: unscannedRegions(),
});
}
}
///////////////////////////////////////////////////////////////////////////////
// Utilities
///////////////////////////////////////////////////////////////////////////////

View File

@ -229,8 +229,8 @@ function ReplayDebugger() {
// a time warp target has been reached.
this.replayingOnForcedPause = null;
// Handler called when the child pauses for any reason.
this.replayingOnPositionChange = null;
// Handler called when the status changes and the UI needs to be updated.
this.replayingOnStatusUpdate = null;
}
// Frame index used to refer to the newest frame in the child process.
@ -265,18 +265,6 @@ ReplayDebugger.prototype = {
return this._control.recordingEndpoint();
},
replayIsRecording() {
return this._control.childIsRecording();
},
replayUnscannedRegions() {
return this._control.unscannedRegions();
},
replayCachedPoints() {
return this._control.cachedPoints();
},
replayDebuggerRequests() {
return this._control.debuggerRequests();
},
@ -416,11 +404,6 @@ ReplayDebugger.prototype = {
// within a control method (resume, timeWarp, waitUntilPaused) or be
// delivered via the event loop.
_onPause() {
// The position change handler is always called on pause notifications.
if (this.replayingOnPositionChange) {
this.replayingOnPositionChange();
}
// Call _performPause() soon via the event loop to check for breakpoint
// handlers at this point.
this._cancelPerformPause = false;
@ -477,15 +460,6 @@ ReplayDebugger.prototype = {
}
},
// This hook is called whenever control state changes which affects something
// the position change handler listens to (more than just position changes,
// alas).
_callOnPositionChange() {
if (this.replayingOnPositionChange) {
this.replayingOnPositionChange();
}
},
replayPushThreadPause() {
// The thread has paused so that the user can interact with it. The child
// will stay paused until this thread-wide pause has been popped.
@ -539,7 +513,7 @@ ReplayDebugger.prototype = {
},
replayPaintCurrentPoint() {
if (this.replayIsRecording()) {
if (this._control.childIsRecording()) {
return RecordReplayControl.restoreMainGraphics();
}

View File

@ -357,7 +357,7 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
this.dbg.onNewDebuggee = this._onNewDebuggee;
if (this.dbg.replaying) {
this.dbg.replayingOnForcedPause = this.replayingOnForcedPause.bind(this);
this.dbg.replayingOnPositionChange = this._makeReplayingOnPositionChange();
this.dbg.replayingOnStatusUpdate = this._makeReplayingOnStatusUpdate();
}
this._debuggerSourcesSeen = new WeakSet();
@ -1944,23 +1944,14 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
},
/*
* A function that the engine calls when a recording/replaying process has
* changed its position: a checkpoint was reached or a switch between a
* recording and replaying child process occurred.
* A function that the engine calls when replaying and the status has changed
* in a way that affects the UI, such as switching between a recording and
* replaying process or a change to the current execution point.
*/
_makeReplayingOnPositionChange() {
return throttle(() => {
_makeReplayingOnStatusUpdate() {
return throttle(status => {
if (this.attached) {
const recording = this.dbg.replayIsRecording();
const executionPoint = this.dbg.replayCurrentExecutionPoint();
const unscannedRegions = this.dbg.replayUnscannedRegions();
const cachedPoints = this.dbg.replayCachedPoints();
this.emit("progress", {
recording,
executionPoint,
unscannedRegions,
cachedPoints,
});
this.emit("replayStatusUpdate", { status });
}
}, 100);
},

View File

@ -66,11 +66,8 @@ const threadSpec = generateActorSpec({
newSource: {
source: Option(0, "json"),
},
progress: {
recording: Option(0, "json"),
executionPoint: Option(0, "json"),
unscannedRegions: Option(0, "json"),
cachedPoints: Option(0, "json"),
replayStatusUpdate: {
status: Option(0, "json"),
},
replayFramePositions: {
positions: Option(0, "array:json"),