Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 20 additions & 24 deletions external/eslint_plugins/prefer-math-clamp.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,16 @@
* Detected patterns and their fixes:
* Math.min(Math.max(A, B), C) → MathClamp(A, B, C)
* Math.min(C, Math.max(A, B)) → MathClamp(A, B, C)
* Math.max(Math.min(A, B), C) → MathClamp(A, C, B)
* Math.max(C, Math.min(A, B)) → MathClamp(A, C, B)
* Math.max(Math.min(A, B), C) → flagged as a possible clamp, not fixed
* Math.max(C, Math.min(A, B)) → flagged as a possible clamp, not fixed
*
* The min-outer patterns are exact: `Math.min(Math.max(A, B), C)` is what
* `MathClamp(A, B, C)` expands to, whichever inner operand is the value.
*
* The max-outer ones are not. `Math.min` is commutative, so the value can be A
* or B, and `MathClamp(A, C, B)` only agrees with `Math.max(C, Math.min(A, B))`
* when C <= B. The rule can't tell, so it reports these with a message saying
* as much and leaves the rewrite to a human.
*/

function isMathCall(node, method) {
Expand Down Expand Up @@ -39,6 +47,9 @@ const preferMathClampRule = {
messages: {
useClamp:
"Use MathClamp(v, min, max) instead of nested Math.min/Math.max.",
maybeClamp:
"Math.max(C, Math.min(A, B)) is MathClamp(A, C, B) only when C <= B; " +
"rewrite it by hand if that holds.",
},
schema: [],
},
Expand Down Expand Up @@ -79,32 +90,17 @@ const preferMathClampRule = {
}

// Pattern: Math.max(Math.min(A, B), C) or Math.max(C, Math.min(A, B)).
// Fix as MathClamp(A, C, B) where A,B are inner args, C is outer arg.
// Only a clamp when the bounds are ordered, so this is reported as a
// candidate and not fixed, see the file header.
if (isMathCall(node, "max")) {
const [arg0, arg1] = node.arguments;
let outerArg, innerNode;

if (isMathCall(arg0, "min") && !isMathMinMax(arg1)) {
innerNode = arg0;
outerArg = arg1;
} else if (isMathCall(arg1, "min") && !isMathMinMax(arg0)) {
innerNode = arg1;
outerArg = arg0;
} else {
return;
if (
(isMathCall(arg0, "min") && !isMathMinMax(arg1)) ||
(isMathCall(arg1, "min") && !isMathMinMax(arg0))
) {
context.report({ node, messageId: "maybeClamp" });
}

const v = src.getText(innerNode.arguments[0]);
const max = src.getText(innerNode.arguments[1]);
const min = src.getText(outerArg);

context.report({
node,
messageId: "useClamp",
fix(fixer) {
return fixer.replaceText(node, `MathClamp(${v}, ${min}, ${max})`);
},
});
}
},
};
Expand Down
2 changes: 1 addition & 1 deletion src/core/postscript/js_evaluator.js
Original file line number Diff line number Diff line change
Expand Up @@ -781,7 +781,7 @@ class PSStackBasedInterpreter {
const base = this.#sp - nOut;
for (let i = 0; i < nOut; i++) {
const v = base + i >= 0 ? this.#stack[base + i] : 0;
dest[destOffset + i] = MathClamp(range[i * 2 + 1], range[i * 2], v);
dest[destOffset + i] = MathClamp(v, range[i * 2], range[i * 2 + 1]);
}
};
}
Expand Down
32 changes: 16 additions & 16 deletions src/core/struct_tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -691,7 +691,7 @@ class StructElementNode {
return null;
}

const result = Object.create(null);
const map = new Map();
for (const attributes of this.attributes) {
if (!isName(attributes.get("O"), "Table")) {
continue;
Expand All @@ -701,9 +701,9 @@ class StructElementNode {
if (attributes.has("Summary")) {
const summary = attributes.get("Summary");
if (typeof summary === "string" && summary) {
result.summary = stringToPDFString(summary);
map.set("summary", stringToPDFString(summary));
} else {
delete result.summary;
map.delete("summary");
}
}
continue;
Expand All @@ -715,46 +715,46 @@ class StructElementNode {
}
const value = attributes.get(key);
if (Number.isInteger(value) && value > 1) {
result[name] = value;
map.set(name, value);
} else {
// Omit default and invalid values, clearing any earlier class value.
delete result[name];
map.delete(name);
}
}

if (attributes.has("Headers")) {
delete result.headers;
map.delete("headers");
const headers = attributes.getArray("Headers");
if (Array.isArray(headers)) {
const ids = headers
.filter(header => typeof header === "string")
.map(header => stringToPDFString(header));
if (ids.length > 0) {
result.headers = ids;
map.set("headers", ids);
}
}
}

if (role === "TH" && attributes.has("Scope")) {
delete result.scope;
map.delete("scope");
const scope = attributes.get("Scope");
if (
scope instanceof Name &&
["Row", "Column", "Both"].includes(scope.name)
) {
result.scope = scope.name;
map.set("scope", scope.name);
}
}

if (role === "TH" && attributes.has("Short")) {
delete result.short;
map.delete("short");
const short = attributes.get("Short");
if (typeof short === "string" && short) {
result.short = stringToPDFString(short);
map.set("short", stringToPDFString(short));
}
}
}
return Object.keys(result).length > 0 ? result : null;
return map.size ? map : null;
}

parseKids() {
Expand Down Expand Up @@ -1044,10 +1044,10 @@ class StructTreePage {
if (obj.role === "TH" && typeof structId === "string" && structId) {
obj.structId = stringToPDFString(structId);
}
const tableAttributes = node.tableAttributes;
if (tableAttributes) {
Object.assign(obj, tableAttributes);
}
node.tableAttributes?.forEach((val, key) => {
obj[key] = val;
});

if (obj.role === "Formula") {
try {
const { mathML } = node;
Expand Down
26 changes: 18 additions & 8 deletions src/display/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,15 @@ class PDFDocumentProxy {
this._pdfInfo = pdfInfo;
this._transport = transport;

if (
typeof PDFJSDev === "undefined" ||
PDFJSDev.test("TESTING || INTERNAL_VIEWER")
) {
// For the PDF debugger.
Object.defineProperty(this, "getRawData", {
value: data => this._transport.getRawData(data),
});
}
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
// For testing purposes.
Object.defineProperty(this, "getNetworkStreamName", {
Expand Down Expand Up @@ -1029,10 +1038,6 @@ class PDFDocumentProxy {
return this._transport.downloadInfoCapability.promise;
}

getRawData(data) {
return this._transport.getRawData(data);
}

/**
* Cleans up resources allocated by the document on both the main and worker
* threads.
Expand Down Expand Up @@ -2458,6 +2463,15 @@ class WorkerTransport {

this.setupMessageHandler();

if (
typeof PDFJSDev === "undefined" ||
PDFJSDev.test("TESTING || INTERNAL_VIEWER")
) {
// For the PDF debugger.
Object.defineProperty(this, "getRawData", {
value: data => this.messageHandler.sendWithPromise("GetRawData", data),
});
}
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
// For testing purposes.
Object.defineProperty(this, "getNetworkStreamName", {
Expand Down Expand Up @@ -3204,10 +3218,6 @@ class WorkerTransport {
return this.messageHandler.sendWithPromise("GetMarkInfo", null);
}

getRawData(data) {
return this.messageHandler.sendWithPromise("GetRawData", data);
}

async startCleanup(keepLoadedFonts = false) {
if (this.destroyed) {
return; // No need to manually clean-up when destruction has started.
Expand Down
8 changes: 1 addition & 7 deletions src/scripting_api/field.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,13 +109,7 @@ class Field extends PDFObject {
indices = [indices];
}
if (
!indices.every(
i =>
typeof i === "number" &&
Number.isInteger(i) &&
i >= 0 &&
i < this.numItems
)
!indices.every(i => Number.isInteger(i) && i >= 0 && i < this.numItems)
) {
return;
}
Expand Down
2 changes: 1 addition & 1 deletion src/shared/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -722,7 +722,7 @@ class Util {
return shadow(
this,
"hexNums",
Array.from(Array(256).keys(), n => n.toString(16).padStart(2, "0"))
Array.from({ length: 256 }, (_, n) => n.toString(16).padStart(2, "0"))
);
}

Expand Down
4 changes: 1 addition & 3 deletions test/integration/freetext_editor_spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3729,9 +3729,7 @@ describe("FreeText Editor", () => {
const { map } =
window.PDFViewerApplication.pdfDocument.annotationStorage
.serializable;
return (
map.size === 4 && [...map.values()].every(entry => entry.deleted)
);
return map.size === 4 && map.values().every(entry => entry.deleted);
});

// Disable editing mode.
Expand Down
6 changes: 6 additions & 0 deletions test/unit/postscript_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,12 @@ describe("PostScript Type 4 lexer, parser, and Wasm compiler", function () {
expect(r).toBeCloseTo(0.5, 9);
});

it("clamps output to the bottom of the declared range", async function () {
// sub falls below range [0, 1] → result clamped
const r = compileAndRun("{ sub }", [0, 1, 0, 1], [0, 1], [0.25, 0.75]);
expect(r).toBeCloseTo(0, 9);
});

// Bitwise.

it("compiles bitshift left (literal shift)", async function () {
Expand Down
7 changes: 1 addition & 6 deletions web/debugger.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -624,12 +624,7 @@ class Stepper {

getNextBreakPoint() {
this.breakPoints.sort((a, b) => a - b);
for (const breakPoint of this.breakPoints) {
if (breakPoint > this.currentIdx) {
return breakPoint;
}
}
return null;
return this.breakPoints.find(idx => idx > this.currentIdx) ?? null;
}

breakIt(idx, callback) {
Expand Down
4 changes: 2 additions & 2 deletions web/internal/split_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,9 @@ class SplitView {
return 0;
}
if (total <= this.#minSize * 2) {
return MathClamp(0, requestedFirst, total);
return MathClamp(requestedFirst, 0, total);
}
return MathClamp(total - this.#minSize, this.#minSize, requestedFirst);
return MathClamp(requestedFirst, this.#minSize, total - this.#minSize);
}

#resize(newFirst) {
Expand Down
Loading