Add constants for defining the initial BBox and Float32 BBox

Nowadays there's a lot of places in the code-base where we need to initialize or reset bounding boxes. Rather than spelling this out repeatedly, this patch adds new `Array`/`Float32Array` constants that can be copied or used as-is where appropriate.
This commit is contained in:
Jonas Jenwald 2026-04-02 22:28:17 +02:00
parent a67b952118
commit 654985c621
10 changed files with 48 additions and 60 deletions

View File

@ -23,6 +23,8 @@ import {
AnnotationType, AnnotationType,
assert, assert,
BASELINE_FACTOR, BASELINE_FACTOR,
BBOX_INIT,
F32_BBOX_INIT,
FeatureTest, FeatureTest,
getModificationDate, getModificationDate,
info, info,
@ -637,7 +639,7 @@ function getQuadPoints(dict, rect) {
function getTransformMatrix(rect, bbox, matrix) { function getTransformMatrix(rect, bbox, matrix) {
// 12.5.5: Algorithm: Appearance streams // 12.5.5: Algorithm: Appearance streams
const minMax = new Float32Array([Infinity, Infinity, -Infinity, -Infinity]); const minMax = F32_BBOX_INIT.slice();
Util.axialAlignedBoundingBox(bbox, matrix, minMax); Util.axialAlignedBoundingBox(bbox, matrix, minMax);
const [minX, minY, maxX, maxY] = minMax; const [minX, minY, maxX, maxY] = minMax;
if (minX === maxX || minY === maxY) { if (minX === maxX || minY === maxY) {
@ -1724,7 +1726,7 @@ class MarkupAnnotation extends Annotation {
fillAlpha, fillAlpha,
pointsCallback, pointsCallback,
}) { }) {
const bbox = (this.data.rect = [Infinity, Infinity, -Infinity, -Infinity]); const bbox = (this.data.rect = BBOX_INIT.slice());
const buffer = ["q"]; const buffer = ["q"];
if (extra) { if (extra) {
@ -4463,7 +4465,7 @@ class PolylineAnnotation extends MarkupAnnotation {
// If the /Rect-entry is empty/wrong, create a fallback rectangle so that // If the /Rect-entry is empty/wrong, create a fallback rectangle so that
// we get similar rendering/highlighting behaviour as in Adobe Reader. // we get similar rendering/highlighting behaviour as in Adobe Reader.
const bbox = [Infinity, Infinity, -Infinity, -Infinity]; const bbox = BBOX_INIT.slice();
for (let i = 0, ii = vertices.length; i < ii; i += 2) { for (let i = 0, ii = vertices.length; i < ii; i += 2) {
Util.rectBoundingBox( Util.rectBoundingBox(
vertices[i] - borderAdjust, vertices[i] - borderAdjust,
@ -4551,7 +4553,7 @@ class InkAnnotation extends MarkupAnnotation {
// If the /Rect-entry is empty/wrong, create a fallback rectangle so that // If the /Rect-entry is empty/wrong, create a fallback rectangle so that
// we get similar rendering/highlighting behaviour as in Adobe Reader. // we get similar rendering/highlighting behaviour as in Adobe Reader.
const bbox = [Infinity, Infinity, -Infinity, -Infinity]; const bbox = BBOX_INIT.slice();
for (const inkList of this.data.inkLists) { for (const inkList of this.data.inkLists) {
for (let i = 0, ii = inkList.length; i < ii; i += 2) { for (let i = 0, ii = inkList.length; i < ii; i += 2) {
Util.rectBoundingBox( Util.rectBoundingBox(

View File

@ -16,7 +16,9 @@
import { import {
AbortException, AbortException,
assert, assert,
BBOX_INIT,
DrawOPS, DrawOPS,
F32_BBOX_INIT,
FONT_IDENTITY_MATRIX, FONT_IDENTITY_MATRIX,
FormatError, FormatError,
info, info,
@ -2309,7 +2311,7 @@ class PartialEvaluator {
pathMinMax.slice(), pathMinMax.slice(),
]); ]);
pathBuffer.length = 0; pathBuffer.length = 0;
pathMinMax.set([Infinity, Infinity, -Infinity, -Infinity], 0); pathMinMax.set(BBOX_INIT, 0);
} }
continue; continue;
} }
@ -4980,7 +4982,7 @@ class TranslatedFont {
// Override the fontBBox when it's undefined/empty, or when it's at least // Override the fontBBox when it's undefined/empty, or when it's at least
// (approximately) one order of magnitude smaller than the charBBox // (approximately) one order of magnitude smaller than the charBBox
// (fixes issue14999_reduced.pdf). // (fixes issue14999_reduced.pdf).
this._bbox ??= [Infinity, Infinity, -Infinity, -Infinity]; this._bbox ??= BBOX_INIT.slice();
Util.rectBoundingBox(...charBBox, this._bbox); Util.rectBoundingBox(...charBBox, this._bbox);
} }
@ -5050,7 +5052,7 @@ class TranslatedFont {
case OPS.constructPath: case OPS.constructPath:
const minMax = operatorList.argsArray[i][2]; const minMax = operatorList.argsArray[i][2];
// Override the fontBBox when it's undefined/empty (fixes 19624.pdf). // Override the fontBBox when it's undefined/empty (fixes 19624.pdf).
this._bbox ??= [Infinity, Infinity, -Infinity, -Infinity]; this._bbox ??= BBOX_INIT.slice();
Util.rectBoundingBox(...minMax, this._bbox); Util.rectBoundingBox(...minMax, this._bbox);
break; break;
} }
@ -5176,7 +5178,7 @@ class EvalState {
currentPointY = 0; currentPointY = 0;
pathMinMax = new Float32Array([Infinity, Infinity, -Infinity, -Infinity]); pathMinMax = F32_BBOX_INIT.slice();
pathBuffer = []; pathBuffer = [];
@ -5200,12 +5202,7 @@ class EvalState {
const clone = Object.create(this); const clone = Object.create(this);
if (newPath) { if (newPath) {
clone.pathBuffer = []; clone.pathBuffer = [];
clone.pathMinMax = new Float32Array([ clone.pathMinMax = F32_BBOX_INIT.slice();
Infinity,
Infinity,
-Infinity,
-Infinity,
]);
} }
return clone; return clone;
} }

View File

@ -15,6 +15,7 @@
import { import {
assert, assert,
BBOX_INIT,
FormatError, FormatError,
info, info,
MeshFigureType, MeshFigureType,
@ -426,7 +427,7 @@ class FunctionBasedShading extends BaseShading {
const matrix = lookupMatrix(dict.getArray("Matrix"), IDENTITY_MATRIX); const matrix = lookupMatrix(dict.getArray("Matrix"), IDENTITY_MATRIX);
// Transform the four domain corners to find the user-space bounding box. // Transform the four domain corners to find the user-space bounding box.
this.bounds = [Infinity, Infinity, -Infinity, -Infinity]; this.bounds = BBOX_INIT.slice();
Util.axialAlignedBoundingBox([x0, y0, x1, y1], matrix, this.bounds); Util.axialAlignedBoundingBox([x0, y0, x1, y1], matrix, this.bounds);
const bboxW = this.bounds[2] - this.bounds[0]; const bboxW = this.bounds[2] - this.bounds[0];

View File

@ -18,6 +18,7 @@ import {
Dependencies, Dependencies,
} from "./canvas_dependency_tracker.js"; } from "./canvas_dependency_tracker.js";
import { import {
F32_BBOX_INIT,
FeatureTest, FeatureTest,
FONT_IDENTITY_MATRIX, FONT_IDENTITY_MATRIX,
ImageKind, ImageKind,
@ -66,14 +67,6 @@ const SCALE_MATRIX = new DOMMatrix();
// Used to get some coordinates. // Used to get some coordinates.
const XY = new Float32Array(2); const XY = new Float32Array(2);
// Initial rectangle values for the minMax array.
const MIN_MAX_INIT = new Float32Array([
Infinity,
Infinity,
-Infinity,
-Infinity,
]);
/** /**
* Overrides certain methods on a 2d ctx so that when they are called they * Overrides certain methods on a 2d ctx so that when they are called they
* will also call the same method on the destCtx. The methods that are * will also call the same method on the destCtx. The methods that are
@ -335,7 +328,7 @@ class CanvasExtraState {
transferMaps = "none"; transferMaps = "none";
minMax = MIN_MAX_INIT.slice(); minMax = F32_BBOX_INIT.slice();
constructor(width, height) { constructor(width, height) {
this.clipBox = new Float32Array([0, 0, width, height]); this.clipBox = new Float32Array([0, 0, width, height]);
@ -379,7 +372,7 @@ class CanvasExtraState {
startNewPathAndClipBox(box) { startNewPathAndClipBox(box) {
this.clipBox.set(box, 0); this.clipBox.set(box, 0);
this.minMax.set(MIN_MAX_INIT, 0); this.minMax.set(F32_BBOX_INIT, 0);
} }
getClippedPathBoundingBox(pathType = PathType.FILL, transform = null) { getClippedPathBoundingBox(pathType = PathType.FILL, transform = null) {
@ -1056,7 +1049,7 @@ class CanvasGraphics {
0, 0,
]); ]);
maskToCanvas = Util.transform(maskToCanvas, [1, 0, 0, 1, 0, -height]); maskToCanvas = Util.transform(maskToCanvas, [1, 0, 0, 1, 0, -height]);
const minMax = MIN_MAX_INIT.slice(); const minMax = F32_BBOX_INIT.slice();
Util.axialAlignedBoundingBox([0, 0, width, height], maskToCanvas, minMax); Util.axialAlignedBoundingBox([0, 0, width, height], maskToCanvas, minMax);
const [minX, minY, maxX, maxY] = minMax; const [minX, minY, maxX, maxY] = minMax;
const drawnWidth = Math.round(maxX - minX) || 1; const drawnWidth = Math.round(maxX - minX) || 1;
@ -2529,7 +2522,7 @@ class CanvasGraphics {
const inv = getCurrentTransformInverse(ctx); const inv = getCurrentTransformInverse(ctx);
if (inv) { if (inv) {
const { width, height } = ctx.canvas; const { width, height } = ctx.canvas;
const minMax = MIN_MAX_INIT.slice(); const minMax = F32_BBOX_INIT.slice();
Util.axialAlignedBoundingBox([0, 0, width, height], inv, minMax); Util.axialAlignedBoundingBox([0, 0, width, height], inv, minMax);
const [x0, y0, x1, y1] = minMax; const [x0, y0, x1, y1] = minMax;
@ -2675,7 +2668,7 @@ class CanvasGraphics {
let bounds; let bounds;
if (group.bbox) { if (group.bbox) {
bounds = MIN_MAX_INIT.slice(); bounds = F32_BBOX_INIT.slice();
Util.axialAlignedBoundingBox( Util.axialAlignedBoundingBox(
group.bbox, group.bbox,
getCurrentTransform(currentCtx), getCurrentTransform(currentCtx),
@ -2804,7 +2797,7 @@ class CanvasGraphics {
this.restore(opIdx); this.restore(opIdx);
this.ctx.save(); this.ctx.save();
this.ctx.setTransform(...currentMtx); this.ctx.setTransform(...currentMtx);
const dirtyBox = MIN_MAX_INIT.slice(); const dirtyBox = F32_BBOX_INIT.slice();
Util.axialAlignedBoundingBox( Util.axialAlignedBoundingBox(
[0, 0, groupCtx.canvas.width, groupCtx.canvas.height], [0, 0, groupCtx.canvas.width, groupCtx.canvas.height],
currentMtx, currentMtx,

View File

@ -13,7 +13,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { FeatureTest, Util } from "../shared/util.js"; import { BBOX_INIT, FeatureTest, Util } from "../shared/util.js";
import { MathClamp } from "../shared/math_clamp.js"; import { MathClamp } from "../shared/math_clamp.js";
const FORCED_DEPENDENCY_LABEL = "__forcedDependency"; const FORCED_DEPENDENCY_LABEL = "__forcedDependency";
@ -81,7 +81,7 @@ class CanvasBBoxTracker {
#clipBox = [-Infinity, -Infinity, Infinity, Infinity]; #clipBox = [-Infinity, -Infinity, Infinity, Infinity];
// Float32Array<minX, minY, maxX, maxY> // Float32Array<minX, minY, maxX, maxY>
#pendingBBox = new Float64Array([Infinity, Infinity, -Infinity, -Infinity]); #pendingBBox = new Float64Array(BBOX_INIT);
_pendingBBoxIdx = -1; _pendingBBoxIdx = -1;
@ -209,10 +209,7 @@ class CanvasBBoxTracker {
resetBBox(idx) { resetBBox(idx) {
if (this._pendingBBoxIdx !== idx) { if (this._pendingBBoxIdx !== idx) {
this._pendingBBoxIdx = idx; this._pendingBBoxIdx = idx;
this.#pendingBBox[0] = Infinity; this.#pendingBBox.set(BBOX_INIT, 0);
this.#pendingBBox[1] = Infinity;
this.#pendingBBox[2] = -Infinity;
this.#pendingBBox[3] = -Infinity;
} }
return this; return this;
} }
@ -222,7 +219,7 @@ class CanvasBBoxTracker {
this.#baseTransformStack.at(-1), this.#baseTransformStack.at(-1),
ctx.getTransform() ctx.getTransform()
); );
const clipBox = [Infinity, Infinity, -Infinity, -Infinity]; const clipBox = BBOX_INIT.slice();
Util.axialAlignedBoundingBox([minX, minY, maxX, maxY], transform, clipBox); Util.axialAlignedBoundingBox([minX, minY, maxX, maxY], transform, clipBox);
const intersection = Util.intersect(this.#clipBox, clipBox); const intersection = Util.intersect(this.#clipBox, clipBox);
if (intersection) { if (intersection) {
@ -256,7 +253,7 @@ class CanvasBBoxTracker {
return this; return this;
} }
const bbox = [Infinity, Infinity, -Infinity, -Infinity]; const bbox = BBOX_INIT.slice();
Util.axialAlignedBoundingBox([minX, minY, maxX, maxY], transform, bbox); Util.axialAlignedBoundingBox([minX, minY, maxX, maxY], transform, bbox);
this.#pendingBBox[0] = MathClamp(bbox[0], clipBox[0], this.#pendingBBox[0]); this.#pendingBBox[0] = MathClamp(bbox[0], clipBox[0], this.#pendingBBox[0]);
@ -1130,7 +1127,7 @@ class CanvasImagesTracker {
let coords; let coords;
if (clipBox[0] !== Infinity) { if (clipBox[0] !== Infinity) {
const bbox = [Infinity, Infinity, -Infinity, -Infinity]; const bbox = BBOX_INIT.slice();
Util.axialAlignedBoundingBox([0, -height, width, 0], transform, bbox); Util.axialAlignedBoundingBox([0, -height, width, 0], transform, bbox);
const finalBBox = Util.intersect(clipBox, bbox); const finalBBox = Util.intersect(clipBox, bbox);

View File

@ -13,8 +13,8 @@
* limitations under the License. * limitations under the License.
*/ */
import { BBOX_INIT, Util } from "../../../shared/util.js";
import { Outline } from "./outline.js"; import { Outline } from "./outline.js";
import { Util } from "../../../shared/util.js";
class FreeDrawOutliner { class FreeDrawOutliner {
#box; #box;
@ -588,22 +588,14 @@ class FreeDrawOutline extends Outline {
lastPointX = ltrCallback(lastPointX, x); lastPointX = ltrCallback(lastPointX, x);
} }
} else { } else {
bezierBbox[0] = bezierBbox[1] = Infinity; bezierBbox.set(BBOX_INIT, 0);
bezierBbox[2] = bezierBbox[3] = -Infinity;
Util.bezierBoundingBox( Util.bezierBoundingBox(
lastX, lastX,
lastY, lastY,
...outline.slice(i, i + 6), ...outline.slice(i, i + 6),
bezierBbox bezierBbox
); );
Util.rectBoundingBox(...bezierBbox, minMax);
Util.rectBoundingBox(
bezierBbox[0],
bezierBbox[1],
bezierBbox[2],
bezierBbox[3],
minMax
);
if (firstPointY > bezierBbox[1]) { if (firstPointY > bezierBbox[1]) {
firstPointX = bezierBbox[0]; firstPointX = bezierBbox[0];

View File

@ -13,9 +13,9 @@
* limitations under the License. * limitations under the License.
*/ */
import { BBOX_INIT, Util } from "../../../shared/util.js";
import { FreeDrawOutline, FreeDrawOutliner } from "./freedraw.js"; import { FreeDrawOutline, FreeDrawOutliner } from "./freedraw.js";
import { Outline } from "./outline.js"; import { Outline } from "./outline.js";
import { Util } from "../../../shared/util.js";
class HighlightOutliner { class HighlightOutliner {
#box; #box;
@ -41,7 +41,7 @@ class HighlightOutliner {
* the last point of the boxes. * the last point of the boxes.
*/ */
constructor(boxes, borderWidth = 0, innerMargin = 0, isLTR = true) { constructor(boxes, borderWidth = 0, innerMargin = 0, isLTR = true) {
const minMax = [Infinity, Infinity, -Infinity, -Infinity]; const minMax = BBOX_INIT.slice();
// We round the coordinates to slightly reduce the number of edges in the // We round the coordinates to slightly reduce the number of edges in the
// final outlines. // final outlines.

View File

@ -13,9 +13,9 @@
* limitations under the License. * limitations under the License.
*/ */
import { F32_BBOX_INIT, Util } from "../../../shared/util.js";
import { MathClamp } from "../../../shared/math_clamp.js"; import { MathClamp } from "../../../shared/math_clamp.js";
import { Outline } from "./outline.js"; import { Outline } from "./outline.js";
import { Util } from "../../../shared/util.js";
class InkDrawOutliner { class InkDrawOutliner {
// The last 3 points of the line. // The last 3 points of the line.
@ -587,12 +587,7 @@ class InkDrawOutline extends Outline {
} }
#computeBbox() { #computeBbox() {
const bbox = (this.#bbox = new Float32Array([ const bbox = (this.#bbox = F32_BBOX_INIT.slice());
Infinity,
Infinity,
-Infinity,
-Infinity,
]));
for (const { line } of this.#lines) { for (const { line } of this.#lines) {
if (line.length <= 12) { if (line.length <= 12) {

View File

@ -13,7 +13,13 @@
* limitations under the License. * limitations under the License.
*/ */
import { assert, FeatureTest, MeshFigureType, Util } from "../shared/util.js"; import {
assert,
BBOX_INIT,
FeatureTest,
MeshFigureType,
Util,
} from "../shared/util.js";
import { import {
CSS_FONT_INFO, CSS_FONT_INFO,
FONT_INFO, FONT_INFO,
@ -438,7 +444,7 @@ class PatternInfo {
const shadingType = this.data[PATTERN_INFO.SHADING_TYPE]; const shadingType = this.data[PATTERN_INFO.SHADING_TYPE];
let bounds = null; let bounds = null;
if (coords.length > 0) { if (coords.length > 0) {
bounds = [Infinity, Infinity, -Infinity, -Infinity]; bounds = BBOX_INIT.slice();
for (let i = 0, ii = coords.length; i < ii; i += 2) { for (let i = 0, ii = coords.length; i < ii; i += 2) {
Util.pointBoundingBox(coords[i], coords[i + 1], bounds); Util.pointBoundingBox(coords[i], coords[i + 1], bounds);

View File

@ -25,6 +25,9 @@ const isNodeJS =
!process.versions.nw && !process.versions.nw &&
!(process.versions.electron && process.type && process.type !== "browser"); !(process.versions.electron && process.type && process.type !== "browser");
const BBOX_INIT = [Infinity, Infinity, -Infinity, -Infinity];
const F32_BBOX_INIT = new Float32Array(BBOX_INIT);
const FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0]; const FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
// Represent the percentage of the height of a single-line field over // Represent the percentage of the height of a single-line field over
@ -1310,10 +1313,12 @@ export {
assert, assert,
BaseException, BaseException,
BASELINE_FACTOR, BASELINE_FACTOR,
BBOX_INIT,
bytesToString, bytesToString,
createValidAbsoluteUrl, createValidAbsoluteUrl,
DocumentActionEventType, DocumentActionEventType,
DrawOPS, DrawOPS,
F32_BBOX_INIT,
FeatureTest, FeatureTest,
FONT_IDENTITY_MATRIX, FONT_IDENTITY_MATRIX,
FormatError, FormatError,