Merge pull request #20888 from calixteman/debugger_skip_ops

Add the possibility to skip some ops in the debug view
This commit is contained in:
Tim van der Meij 2026-03-16 20:36:48 +01:00 committed by GitHub
commit 0a2c030c8b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 77 additions and 23 deletions

View File

@ -786,9 +786,15 @@ class CanvasGraphics {
let fnId, fnArgs; let fnId, fnArgs;
while (true) { while (true) {
if (stepper !== undefined && i === stepper.nextBreakPoint) { if (stepper !== undefined) {
stepper.breakIt(i, continueCallback); if (i === stepper.nextBreakPoint) {
return i; stepper.breakIt(i, continueCallback);
return i;
}
if (stepper.shouldSkip(i)) {
i++;
continue;
}
} }
if (!operationsFilter || operationsFilter(i)) { if (!operationsFilter || operationsFilter(i)) {

View File

@ -659,6 +659,10 @@ class Stepper {
this.goTo(idx); this.goTo(idx);
} }
shouldSkip(idx) {
return false;
}
goTo(idx) { goTo(idx) {
const allRows = this.panel.getElementsByClassName("line"); const allRows = this.panel.getElementsByClassName("line");
for (const row of allRows) { for (const row of allRows) {

View File

@ -159,7 +159,7 @@
&::before { &::before {
content: "●"; content: "●";
color: var(--changed-color); color: var(--changed-color);
font-size: 0.75em; font-size: 0.9em;
opacity: 0; opacity: 0;
} }
@ -167,9 +167,17 @@
opacity: 0.4; opacity: 0.4;
} }
&.active::before { &[data-bp="pause"]::before {
opacity: 1; opacity: 1;
} }
&[data-bp="skip"]::before {
content: "✕";
opacity: 1;
}
}
.op-line.op-skipped > :not(.bp-gutter) {
opacity: 0.4;
} }
.op-line.paused { .op-line.paused {
background: var(--paused-bg); background: var(--paused-bg);
@ -194,9 +202,16 @@
.bp-gutter:hover::before { .bp-gutter:hover::before {
color: ButtonBorder; color: ButtonBorder;
} }
.bp-gutter.active::before { .bp-gutter[data-bp="pause"]::before {
color: ButtonText; color: ButtonText;
} }
.bp-gutter[data-bp="skip"]::before {
color: ButtonText;
}
.op-line.op-skipped > :not(.bp-gutter) {
opacity: 1;
color: GrayText;
}
/* Color swatch preserves the actual PDF color value. */ /* Color swatch preserves the actual PDF color value. */
.color-swatch { .color-swatch {

View File

@ -23,6 +23,11 @@ for (const [name, id] of Object.entries(OPS)) {
OPS_TO_NAME[id] = name; OPS_TO_NAME[id] = name;
} }
const BreakpointType = {
PAUSE: 0,
SKIP: 1,
};
// Single hidden color input reused for all swatch pickers. // Single hidden color input reused for all swatch pickers.
const colorPickerInput = document.createElement("input"); const colorPickerInput = document.createElement("input");
colorPickerInput.type = "color"; colorPickerInput.type = "color";
@ -408,7 +413,8 @@ class DrawOpsView {
#selectedLine = null; #selectedLine = null;
#breakpoints = new Set(); // Map<opIndex, BreakpointType>
#breakpoints = new Map();
#originalColors = new Map(); #originalColors = new Map();
@ -553,27 +559,40 @@ class DrawOpsView {
line.ariaSelected = "false"; line.ariaSelected = "false";
line.tabIndex = i === 0 ? 0 : -1; line.tabIndex = i === 0 ? 0 : -1;
// Breakpoint gutter — click to toggle a red-bullet breakpoint. // Breakpoint gutter — click cycles: none → pause (●) → skip (✕) → none.
const gutter = document.createElement("span"); const gutter = document.createElement("span");
gutter.className = "bp-gutter"; gutter.className = "bp-gutter";
gutter.role = "checkbox"; gutter.role = "checkbox";
gutter.tabIndex = 0; gutter.tabIndex = 0;
gutter.ariaLabel = "Breakpoint"; gutter.ariaLabel = "Breakpoint";
const isInitiallyActive = this.#breakpoints.has(i); const initBpType = this.#breakpoints.get(i);
gutter.ariaChecked = String(isInitiallyActive); if (initBpType === BreakpointType.PAUSE) {
if (isInitiallyActive) { gutter.dataset.bp = "pause";
gutter.classList.add("active"); gutter.ariaChecked = "true";
} else if (initBpType === BreakpointType.SKIP) {
gutter.dataset.bp = "skip";
gutter.ariaChecked = "mixed";
line.classList.add("op-skipped");
} else {
gutter.ariaChecked = "false";
} }
gutter.addEventListener("click", e => { gutter.addEventListener("click", e => {
e.stopPropagation(); e.stopPropagation();
if (this.#breakpoints.has(i)) { const current = this.#breakpoints.get(i);
this.#breakpoints.delete(i); if (current === undefined) {
gutter.classList.remove("active"); this.#breakpoints.set(i, BreakpointType.PAUSE);
gutter.ariaChecked = "false"; gutter.dataset.bp = "pause";
} else {
this.#breakpoints.add(i);
gutter.classList.add("active");
gutter.ariaChecked = "true"; gutter.ariaChecked = "true";
} else if (current === BreakpointType.PAUSE) {
this.#breakpoints.set(i, BreakpointType.SKIP);
gutter.dataset.bp = "skip";
gutter.ariaChecked = "mixed";
line.classList.add("op-skipped");
} else {
this.#breakpoints.delete(i);
delete gutter.dataset.bp;
gutter.ariaChecked = "false";
line.classList.remove("op-skipped");
} }
}); });
gutter.addEventListener("keydown", e => { gutter.addEventListener("keydown", e => {
@ -656,4 +675,4 @@ class DrawOpsView {
} }
} }
export { DrawOpsView }; export { BreakpointType, DrawOpsView };

View File

@ -13,9 +13,9 @@
* limitations under the License. * limitations under the License.
*/ */
import { BreakpointType, DrawOpsView } from "./draw_ops_view.js";
import { CanvasContextDetailsView } from "./canvas_context_details_view.js"; import { CanvasContextDetailsView } from "./canvas_context_details_view.js";
import { DOMCanvasFactory } from "pdfjs/display/canvas_factory.js"; import { DOMCanvasFactory } from "pdfjs/display/canvas_factory.js";
import { DrawOpsView } from "./draw_ops_view.js";
import { SplitView } from "./split_view.js"; import { SplitView } from "./split_view.js";
// Stepper for pausing/stepping through op list rendering. // Stepper for pausing/stepping through op list rendering.
@ -61,10 +61,20 @@ class ViewerStepper {
cb(); cb();
} }
shouldSkip(i) {
return (
globalThis.StepperManager._breakpoints.get(i) === BreakpointType.SKIP
);
}
#findNextAfter(idx) { #findNextAfter(idx) {
let next = null; let next = null;
for (const bp of globalThis.StepperManager._breakpoints) { for (const [bp, type] of globalThis.StepperManager._breakpoints) {
if (bp > idx && (next === null || bp < next)) { if (
type === BreakpointType.PAUSE &&
bp > idx &&
(next === null || bp < next)
) {
next = bp; next = bp;
} }
} }