Merge pull request #16961 from Snuffleupagus/debugger-rm-closure

Remove (some) closures from `web/debugger.js`
This commit is contained in:
Tim van der Meij 2023-09-17 11:45:14 +02:00 committed by GitHub
commit 518590ac7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 263 additions and 260 deletions

View File

@ -13,6 +13,10 @@
* limitations under the License. * limitations under the License.
*/ */
:root {
--panel-width: 300px;
}
#PDFBug, #PDFBug,
#PDFBug :is(input, button, select) { #PDFBug :is(input, button, select) {
font: message-box; font: message-box;
@ -26,7 +30,7 @@
bottom: 0; bottom: 0;
font-size: 10px; font-size: 10px;
padding: 0; padding: 0;
width: 300px; width: var(--panel-width);
} }
#PDFBug .controls { #PDFBug .controls {
background: rgba(238, 238, 238, 1); background: rgba(238, 238, 238, 1);

View File

@ -225,9 +225,9 @@ const StepperManager = (function StepperManagerClosure() {
})(); })();
// The stepper for each page's operatorList. // The stepper for each page's operatorList.
const Stepper = (function StepperClosure() { class Stepper {
// Shorter way to create element and optionally set textContent. // Shorter way to create element and optionally set textContent.
function c(tag, textContent) { #c(tag, textContent) {
const d = document.createElement(tag); const d = document.createElement(tag);
if (textContent) { if (textContent) {
d.textContent = textContent; d.textContent = textContent;
@ -235,7 +235,7 @@ const Stepper = (function StepperClosure() {
return d; return d;
} }
function simplifyArgs(args) { #simplifyArgs(args) {
if (typeof args === "string") { if (typeof args === "string") {
const MAX_STRING_LENGTH = 75; const MAX_STRING_LENGTH = 75;
return args.length <= MAX_STRING_LENGTH return args.length <= MAX_STRING_LENGTH
@ -251,7 +251,7 @@ const Stepper = (function StepperClosure() {
simpleArgs = []; simpleArgs = [];
let i, ii; let i, ii;
for (i = 0, ii = Math.min(MAX_ITEMS, args.length); i < ii; i++) { for (i = 0, ii = Math.min(MAX_ITEMS, args.length); i < ii; i++) {
simpleArgs.push(simplifyArgs(args[i])); simpleArgs.push(this.#simplifyArgs(args[i]));
} }
if (i < args.length) { if (i < args.length) {
simpleArgs.push("..."); simpleArgs.push("...");
@ -260,183 +260,179 @@ const Stepper = (function StepperClosure() {
} }
const simpleObj = {}; const simpleObj = {};
for (const key in args) { for (const key in args) {
simpleObj[key] = simplifyArgs(args[key]); simpleObj[key] = this.#simplifyArgs(args[key]);
} }
return simpleObj; return simpleObj;
} }
// eslint-disable-next-line no-shadow constructor(panel, pageIndex, initialBreakPoints) {
class Stepper { this.panel = panel;
constructor(panel, pageIndex, initialBreakPoints) { this.breakPoint = 0;
this.panel = panel; this.nextBreakPoint = null;
this.breakPoint = 0; this.pageIndex = pageIndex;
this.nextBreakPoint = null; this.breakPoints = initialBreakPoints;
this.pageIndex = pageIndex; this.currentIdx = -1;
this.breakPoints = initialBreakPoints; this.operatorListIdx = 0;
this.currentIdx = -1; this.indentLevel = 0;
this.operatorListIdx = 0; }
this.indentLevel = 0;
init(operatorList) {
const panel = this.panel;
const content = this.#c("div", "c=continue, s=step");
const table = this.#c("table");
content.append(table);
table.cellSpacing = 0;
const headerRow = this.#c("tr");
table.append(headerRow);
headerRow.append(
this.#c("th", "Break"),
this.#c("th", "Idx"),
this.#c("th", "fn"),
this.#c("th", "args")
);
panel.append(content);
this.table = table;
this.updateOperatorList(operatorList);
}
updateOperatorList(operatorList) {
const self = this;
function cboxOnClick() {
const x = +this.dataset.idx;
if (this.checked) {
self.breakPoints.push(x);
} else {
self.breakPoints.splice(self.breakPoints.indexOf(x), 1);
}
StepperManager.saveBreakPoints(self.pageIndex, self.breakPoints);
} }
init(operatorList) { const MAX_OPERATORS_COUNT = 15000;
const panel = this.panel; if (this.operatorListIdx > MAX_OPERATORS_COUNT) {
const content = c("div", "c=continue, s=step"); return;
const table = c("table");
content.append(table);
table.cellSpacing = 0;
const headerRow = c("tr");
table.append(headerRow);
headerRow.append(
c("th", "Break"),
c("th", "Idx"),
c("th", "fn"),
c("th", "args")
);
panel.append(content);
this.table = table;
this.updateOperatorList(operatorList);
} }
updateOperatorList(operatorList) { const chunk = document.createDocumentFragment();
const self = this; const operatorsToDisplay = Math.min(
MAX_OPERATORS_COUNT,
operatorList.fnArray.length
);
for (let i = this.operatorListIdx; i < operatorsToDisplay; i++) {
const line = this.#c("tr");
line.className = "line";
line.dataset.idx = i;
chunk.append(line);
const checked = this.breakPoints.includes(i);
const args = operatorList.argsArray[i] || [];
function cboxOnClick() { const breakCell = this.#c("td");
const x = +this.dataset.idx; const cbox = this.#c("input");
if (this.checked) { cbox.type = "checkbox";
self.breakPoints.push(x); cbox.className = "points";
} else { cbox.checked = checked;
self.breakPoints.splice(self.breakPoints.indexOf(x), 1); cbox.dataset.idx = i;
} cbox.onclick = cboxOnClick;
StepperManager.saveBreakPoints(self.pageIndex, self.breakPoints);
}
const MAX_OPERATORS_COUNT = 15000; breakCell.append(cbox);
if (this.operatorListIdx > MAX_OPERATORS_COUNT) { line.append(breakCell, this.#c("td", i.toString()));
return; const fn = opMap[operatorList.fnArray[i]];
} let decArgs = args;
if (fn === "showText") {
const chunk = document.createDocumentFragment(); const glyphs = args[0];
const operatorsToDisplay = Math.min( const charCodeRow = this.#c("tr");
MAX_OPERATORS_COUNT, const fontCharRow = this.#c("tr");
operatorList.fnArray.length const unicodeRow = this.#c("tr");
); for (const glyph of glyphs) {
for (let i = this.operatorListIdx; i < operatorsToDisplay; i++) { if (typeof glyph === "object" && glyph !== null) {
const line = c("tr"); charCodeRow.append(this.#c("td", glyph.originalCharCode));
line.className = "line"; fontCharRow.append(this.#c("td", glyph.fontChar));
line.dataset.idx = i; unicodeRow.append(this.#c("td", glyph.unicode));
chunk.append(line); } else {
const checked = this.breakPoints.includes(i); // null or number
const args = operatorList.argsArray[i] || []; const advanceEl = this.#c("td", glyph);
advanceEl.classList.add("advance");
const breakCell = c("td"); charCodeRow.append(advanceEl);
const cbox = c("input"); fontCharRow.append(this.#c("td"));
cbox.type = "checkbox"; unicodeRow.append(this.#c("td"));
cbox.className = "points";
cbox.checked = checked;
cbox.dataset.idx = i;
cbox.onclick = cboxOnClick;
breakCell.append(cbox);
line.append(breakCell, c("td", i.toString()));
const fn = opMap[operatorList.fnArray[i]];
let decArgs = args;
if (fn === "showText") {
const glyphs = args[0];
const charCodeRow = c("tr");
const fontCharRow = c("tr");
const unicodeRow = c("tr");
for (const glyph of glyphs) {
if (typeof glyph === "object" && glyph !== null) {
charCodeRow.append(c("td", glyph.originalCharCode));
fontCharRow.append(c("td", glyph.fontChar));
unicodeRow.append(c("td", glyph.unicode));
} else {
// null or number
const advanceEl = c("td", glyph);
advanceEl.classList.add("advance");
charCodeRow.append(advanceEl);
fontCharRow.append(c("td"));
unicodeRow.append(c("td"));
}
} }
decArgs = c("td");
const table = c("table");
table.classList.add("showText");
decArgs.append(table);
table.append(charCodeRow, fontCharRow, unicodeRow);
} else if (fn === "restore" && this.indentLevel > 0) {
this.indentLevel--;
}
line.append(c("td", " ".repeat(this.indentLevel * 2) + fn));
if (fn === "save") {
this.indentLevel++;
}
if (decArgs instanceof HTMLElement) {
line.append(decArgs);
} else {
line.append(c("td", JSON.stringify(simplifyArgs(decArgs))));
} }
decArgs = this.#c("td");
const table = this.#c("table");
table.classList.add("showText");
decArgs.append(table);
table.append(charCodeRow, fontCharRow, unicodeRow);
} else if (fn === "restore" && this.indentLevel > 0) {
this.indentLevel--;
} }
if (operatorsToDisplay < operatorList.fnArray.length) { line.append(this.#c("td", " ".repeat(this.indentLevel * 2) + fn));
const lastCell = c("td", "..."); if (fn === "save") {
lastCell.colspan = 4; this.indentLevel++;
chunk.append(lastCell);
} }
this.operatorListIdx = operatorList.fnArray.length;
this.table.append(chunk);
}
getNextBreakPoint() { if (decArgs instanceof HTMLElement) {
this.breakPoints.sort(function (a, b) { line.append(decArgs);
return a - b; } else {
}); line.append(this.#c("td", JSON.stringify(this.#simplifyArgs(decArgs))));
for (const breakPoint of this.breakPoints) {
if (breakPoint > this.currentIdx) {
return breakPoint;
}
} }
return null;
} }
if (operatorsToDisplay < operatorList.fnArray.length) {
breakIt(idx, callback) { const lastCell = this.#c("td", "...");
StepperManager.selectStepper(this.pageIndex, true); lastCell.colspan = 4;
this.currentIdx = idx; chunk.append(lastCell);
const listener = evt => {
switch (evt.keyCode) {
case 83: // step
document.removeEventListener("keydown", listener);
this.nextBreakPoint = this.currentIdx + 1;
this.goTo(-1);
callback();
break;
case 67: // continue
document.removeEventListener("keydown", listener);
this.nextBreakPoint = this.getNextBreakPoint();
this.goTo(-1);
callback();
break;
}
};
document.addEventListener("keydown", listener);
this.goTo(idx);
} }
this.operatorListIdx = operatorList.fnArray.length;
this.table.append(chunk);
}
goTo(idx) { getNextBreakPoint() {
const allRows = this.panel.getElementsByClassName("line"); this.breakPoints.sort(function (a, b) {
for (const row of allRows) { return a - b;
if ((row.dataset.idx | 0) === idx) { });
row.style.backgroundColor = "rgb(251,250,207)"; for (const breakPoint of this.breakPoints) {
row.scrollIntoView(); if (breakPoint > this.currentIdx) {
} else { return breakPoint;
row.style.backgroundColor = null; }
} }
return null;
}
breakIt(idx, callback) {
StepperManager.selectStepper(this.pageIndex, true);
this.currentIdx = idx;
const listener = evt => {
switch (evt.keyCode) {
case 83: // step
document.removeEventListener("keydown", listener);
this.nextBreakPoint = this.currentIdx + 1;
this.goTo(-1);
callback();
break;
case 67: // continue
document.removeEventListener("keydown", listener);
this.nextBreakPoint = this.getNextBreakPoint();
this.goTo(-1);
callback();
break;
}
};
document.addEventListener("keydown", listener);
this.goTo(idx);
}
goTo(idx) {
const allRows = this.panel.getElementsByClassName("line");
for (const row of allRows) {
if ((row.dataset.idx | 0) === idx) {
row.style.backgroundColor = "rgb(251,250,207)";
row.scrollIntoView();
} else {
row.style.backgroundColor = null;
} }
} }
} }
return Stepper; }
})();
const Stats = (function Stats() { const Stats = (function Stats() {
let stats = []; let stats = [];
@ -495,115 +491,118 @@ const Stats = (function Stats() {
})(); })();
// Manages all the debugging tools. // Manages all the debugging tools.
const PDFBug = (function PDFBugClosure() { class PDFBug {
const panelWidth = 300; static #buttons = [];
const buttons = [];
let activePanel = null;
return { static #activePanel = null;
tools: [FontInspector, StepperManager, Stats],
enable(ids) {
const all = ids.length === 1 && ids[0] === "all";
const tools = this.tools;
for (const tool of tools) {
if (all || ids.includes(tool.id)) {
tool.enabled = true;
}
}
if (!all) {
// Sort the tools by the order they are enabled.
tools.sort(function (a, b) {
let indexA = ids.indexOf(a.id);
indexA = indexA < 0 ? tools.length : indexA;
let indexB = ids.indexOf(b.id);
indexB = indexB < 0 ? tools.length : indexB;
return indexA - indexB;
});
}
},
init(container, ids) {
this.loadCSS();
this.enable(ids);
/*
* Basic Layout:
* PDFBug
* Controls
* Panels
* Panel
* Panel
* ...
*/
const ui = document.createElement("div");
ui.id = "PDFBug";
const controls = document.createElement("div"); static tools = [FontInspector, StepperManager, Stats];
controls.setAttribute("class", "controls");
ui.append(controls);
const panels = document.createElement("div"); static enable(ids) {
panels.setAttribute("class", "panels"); const all = ids.length === 1 && ids[0] === "all";
ui.append(panels); const tools = this.tools;
for (const tool of tools) {
if (all || ids.includes(tool.id)) {
tool.enabled = true;
}
}
if (!all) {
// Sort the tools by the order they are enabled.
tools.sort(function (a, b) {
let indexA = ids.indexOf(a.id);
indexA = indexA < 0 ? tools.length : indexA;
let indexB = ids.indexOf(b.id);
indexB = indexB < 0 ? tools.length : indexB;
return indexA - indexB;
});
}
}
container.append(ui); static init(container, ids) {
container.style.right = panelWidth + "px"; this.loadCSS();
this.enable(ids);
/*
* Basic Layout:
* PDFBug
* Controls
* Panels
* Panel
* Panel
* ...
*/
const ui = document.createElement("div");
ui.id = "PDFBug";
// Initialize all the debugging tools. const controls = document.createElement("div");
for (const tool of this.tools) { controls.setAttribute("class", "controls");
const panel = document.createElement("div"); ui.append(controls);
const panelButton = document.createElement("button");
panelButton.textContent = tool.name;
panelButton.addEventListener("click", event => {
event.preventDefault();
this.selectPanel(tool);
});
controls.append(panelButton);
panels.append(panel);
tool.panel = panel;
tool.manager = this;
if (tool.enabled) {
tool.init();
} else {
panel.textContent =
`${tool.name} is disabled. To enable add "${tool.id}" to ` +
"the pdfBug parameter and refresh (separate multiple by commas).";
}
buttons.push(panelButton);
}
this.selectPanel(0);
},
loadCSS() {
const { url } = import.meta;
const link = document.createElement("link"); const panels = document.createElement("div");
link.rel = "stylesheet"; panels.setAttribute("class", "panels");
link.href = url.replace(/.js$/, ".css"); ui.append(panels);
document.head.append(link); container.append(ui);
}, container.style.right = "var(--panel-width)";
cleanup() {
for (const tool of this.tools) { // Initialize all the debugging tools.
if (tool.enabled) { for (const tool of this.tools) {
tool.cleanup(); const panel = document.createElement("div");
} const panelButton = document.createElement("button");
panelButton.textContent = tool.name;
panelButton.addEventListener("click", event => {
event.preventDefault();
this.selectPanel(tool);
});
controls.append(panelButton);
panels.append(panel);
tool.panel = panel;
tool.manager = this;
if (tool.enabled) {
tool.init();
} else {
panel.textContent =
`${tool.name} is disabled. To enable add "${tool.id}" to ` +
"the pdfBug parameter and refresh (separate multiple by commas).";
} }
}, this.#buttons.push(panelButton);
selectPanel(index) { }
if (typeof index !== "number") { this.selectPanel(0);
index = this.tools.indexOf(index); }
static loadCSS() {
const { url } = import.meta;
const link = document.createElement("link");
link.rel = "stylesheet";
link.href = url.replace(/.js$/, ".css");
document.head.append(link);
}
static cleanup() {
for (const tool of this.tools) {
if (tool.enabled) {
tool.cleanup();
} }
if (index === activePanel) { }
return; }
}
activePanel = index; static selectPanel(index) {
for (const [j, tool] of this.tools.entries()) { if (typeof index !== "number") {
const isActive = j === index; index = this.tools.indexOf(index);
buttons[j].classList.toggle("active", isActive); }
tool.active = isActive; if (index === this.#activePanel) {
tool.panel.hidden = !isActive; return;
} }
}, this.#activePanel = index;
}; for (const [j, tool] of this.tools.entries()) {
})(); const isActive = j === index;
this.#buttons[j].classList.toggle("active", isActive);
tool.active = isActive;
tool.panel.hidden = !isActive;
}
}
}
globalThis.FontInspector = FontInspector; globalThis.FontInspector = FontInspector;
globalThis.StepperManager = StepperManager; globalThis.StepperManager = StepperManager;