mirror of
https://github.com/mozilla/pdf.js.git
synced 2026-07-07 23:55:49 +02:00
Separate bbox tracking from dependencies tracking
When recording bboxes for images, it's enough to record their clip box / bounding box without needing to run the full bbox tracking of the image's dependencies.
This commit is contained in:
parent
886c90d1a5
commit
4f7a025e21
@ -39,6 +39,7 @@ import {
|
|||||||
SerializableEmpty,
|
SerializableEmpty,
|
||||||
} from "./annotation_storage.js";
|
} from "./annotation_storage.js";
|
||||||
import {
|
import {
|
||||||
|
CanvasBBoxTracker,
|
||||||
CanvasDependencyTracker,
|
CanvasDependencyTracker,
|
||||||
CanvasImagesTracker,
|
CanvasImagesTracker,
|
||||||
} from "./canvas_dependency_tracker.js";
|
} from "./canvas_dependency_tracker.js";
|
||||||
@ -1594,20 +1595,28 @@ class PDFPageProxy {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let dependencyTracker = null;
|
||||||
|
let bboxTracker = null;
|
||||||
|
if (shouldRecordOperations || shouldRecordImages) {
|
||||||
|
bboxTracker = new CanvasBBoxTracker(
|
||||||
|
canvas,
|
||||||
|
intentState.operatorList.length
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (shouldRecordOperations) {
|
||||||
|
dependencyTracker = new CanvasDependencyTracker(
|
||||||
|
bboxTracker,
|
||||||
|
recordForDebugger
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const internalRenderTask = new InternalRenderTask({
|
const internalRenderTask = new InternalRenderTask({
|
||||||
callback: complete,
|
callback: complete,
|
||||||
// Only include the required properties, and *not* the entire object.
|
// Only include the required properties, and *not* the entire object.
|
||||||
params: {
|
params: {
|
||||||
canvas,
|
canvas,
|
||||||
canvasContext,
|
canvasContext,
|
||||||
dependencyTracker:
|
dependencyTracker: dependencyTracker ?? bboxTracker,
|
||||||
shouldRecordOperations || shouldRecordImages
|
|
||||||
? new CanvasDependencyTracker(
|
|
||||||
canvas,
|
|
||||||
intentState.operatorList.length,
|
|
||||||
recordForDebugger
|
|
||||||
)
|
|
||||||
: null,
|
|
||||||
imagesTracker: shouldRecordImages
|
imagesTracker: shouldRecordImages
|
||||||
? new CanvasImagesTracker(canvas)
|
? new CanvasImagesTracker(canvas)
|
||||||
: null,
|
: null,
|
||||||
|
|||||||
@ -71,6 +71,323 @@ const ensureDebugMetadata = (map, key) =>
|
|||||||
isRenderingOperation: false,
|
isRenderingOperation: false,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// NOTE: CanvasBBoxTracker, CanvasDependencyTracker and
|
||||||
|
// CanvasNestedDependencyTracker must all have the same interface.
|
||||||
|
|
||||||
|
class CanvasBBoxTracker {
|
||||||
|
#baseTransformStack = [[1, 0, 0, 1, 0, 0]];
|
||||||
|
|
||||||
|
#clipBox = [-Infinity, -Infinity, Infinity, Infinity];
|
||||||
|
|
||||||
|
// Float32Array<minX, minY, maxX, maxY>
|
||||||
|
#pendingBBox = new Float64Array([Infinity, Infinity, -Infinity, -Infinity]);
|
||||||
|
|
||||||
|
_pendingBBoxIdx = -1;
|
||||||
|
|
||||||
|
#canvasWidth;
|
||||||
|
|
||||||
|
#canvasHeight;
|
||||||
|
|
||||||
|
// Uint8ClampedArray<minX, minY, maxX, maxY>
|
||||||
|
#bboxesCoords;
|
||||||
|
|
||||||
|
#bboxes;
|
||||||
|
|
||||||
|
_savesStack = [];
|
||||||
|
|
||||||
|
_markedContentStack = [];
|
||||||
|
|
||||||
|
constructor(canvas, operationsCount) {
|
||||||
|
this.#canvasWidth = canvas.width;
|
||||||
|
this.#canvasHeight = canvas.height;
|
||||||
|
this.#initializeBBoxes(operationsCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
growOperationsCount(operationsCount) {
|
||||||
|
if (operationsCount >= this.#bboxes.length) {
|
||||||
|
this.#initializeBBoxes(operationsCount, this.#bboxes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#initializeBBoxes(operationsCount, oldBBoxes) {
|
||||||
|
const buffer = new ArrayBuffer(operationsCount * 4);
|
||||||
|
this.#bboxesCoords = new Uint8ClampedArray(buffer);
|
||||||
|
this.#bboxes = new Uint32Array(buffer);
|
||||||
|
if (oldBBoxes && oldBBoxes.length > 0) {
|
||||||
|
this.#bboxes.set(oldBBoxes);
|
||||||
|
this.#bboxes.fill(EMPTY_BBOX, oldBBoxes.length);
|
||||||
|
} else {
|
||||||
|
this.#bboxes.fill(EMPTY_BBOX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get clipBox() {
|
||||||
|
return this.#clipBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
save(opIdx) {
|
||||||
|
this.#clipBox = { __proto__: this.#clipBox };
|
||||||
|
this._savesStack.push(opIdx);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
restore(opIdx, onSavePopped) {
|
||||||
|
const previous = Object.getPrototypeOf(this.#clipBox);
|
||||||
|
if (previous === null) {
|
||||||
|
// Sometimes we call more .restore() than .save(), for
|
||||||
|
// example when using CanvasGraphics' #restoreInitialState()
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
this.#clipBox = previous;
|
||||||
|
|
||||||
|
const lastSave = this._savesStack.pop();
|
||||||
|
if (lastSave !== undefined) {
|
||||||
|
onSavePopped?.(lastSave, opIdx);
|
||||||
|
this.#bboxes[opIdx] = this.#bboxes[lastSave];
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} idx
|
||||||
|
*/
|
||||||
|
recordOpenMarker(idx) {
|
||||||
|
this._savesStack.push(idx);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
getOpenMarker() {
|
||||||
|
if (this._savesStack.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return this._savesStack.at(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
recordCloseMarker(opIdx, onSavePopped) {
|
||||||
|
const lastSave = this._savesStack.pop();
|
||||||
|
if (lastSave !== undefined) {
|
||||||
|
onSavePopped?.(lastSave, opIdx);
|
||||||
|
this.#bboxes[opIdx] = this.#bboxes[lastSave];
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marked content needs a separate stack from save/restore, because they
|
||||||
|
// form two independent trees.
|
||||||
|
beginMarkedContent(opIdx) {
|
||||||
|
this._markedContentStack.push(opIdx);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
endMarkedContent(opIdx, onSavePopped) {
|
||||||
|
const lastSave = this._markedContentStack.pop();
|
||||||
|
if (lastSave !== undefined) {
|
||||||
|
onSavePopped?.(lastSave, opIdx);
|
||||||
|
this.#bboxes[opIdx] = this.#bboxes[lastSave];
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
pushBaseTransform(ctx) {
|
||||||
|
this.#baseTransformStack.push(
|
||||||
|
Util.multiplyByDOMMatrix(
|
||||||
|
this.#baseTransformStack.at(-1),
|
||||||
|
ctx.getTransform()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
popBaseTransform() {
|
||||||
|
if (this.#baseTransformStack.length > 1) {
|
||||||
|
this.#baseTransformStack.pop();
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
resetBBox(idx) {
|
||||||
|
if (this._pendingBBoxIdx !== idx) {
|
||||||
|
this._pendingBBoxIdx = idx;
|
||||||
|
this.#pendingBBox[0] = Infinity;
|
||||||
|
this.#pendingBBox[1] = Infinity;
|
||||||
|
this.#pendingBBox[2] = -Infinity;
|
||||||
|
this.#pendingBBox[3] = -Infinity;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
recordClipBox(idx, ctx, minX, maxX, minY, maxY) {
|
||||||
|
const transform = Util.multiplyByDOMMatrix(
|
||||||
|
this.#baseTransformStack.at(-1),
|
||||||
|
ctx.getTransform()
|
||||||
|
);
|
||||||
|
const clipBox = [Infinity, Infinity, -Infinity, -Infinity];
|
||||||
|
Util.axialAlignedBoundingBox([minX, minY, maxX, maxY], transform, clipBox);
|
||||||
|
const intersection = Util.intersect(this.#clipBox, clipBox);
|
||||||
|
if (intersection) {
|
||||||
|
this.#clipBox[0] = intersection[0];
|
||||||
|
this.#clipBox[1] = intersection[1];
|
||||||
|
this.#clipBox[2] = intersection[2];
|
||||||
|
this.#clipBox[3] = intersection[3];
|
||||||
|
} else {
|
||||||
|
this.#clipBox[0] = this.#clipBox[1] = Infinity;
|
||||||
|
this.#clipBox[2] = this.#clipBox[3] = -Infinity;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
recordBBox(idx, ctx, minX, maxX, minY, maxY) {
|
||||||
|
const clipBox = this.#clipBox;
|
||||||
|
if (clipBox[0] === Infinity) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const transform = Util.multiplyByDOMMatrix(
|
||||||
|
this.#baseTransformStack.at(-1),
|
||||||
|
ctx.getTransform()
|
||||||
|
);
|
||||||
|
if (clipBox[0] === -Infinity) {
|
||||||
|
Util.axialAlignedBoundingBox(
|
||||||
|
[minX, minY, maxX, maxY],
|
||||||
|
transform,
|
||||||
|
this.#pendingBBox
|
||||||
|
);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bbox = [Infinity, Infinity, -Infinity, -Infinity];
|
||||||
|
Util.axialAlignedBoundingBox([minX, minY, maxX, maxY], transform, bbox);
|
||||||
|
this.#pendingBBox[0] = Math.min(
|
||||||
|
this.#pendingBBox[0],
|
||||||
|
Math.max(bbox[0], clipBox[0])
|
||||||
|
);
|
||||||
|
this.#pendingBBox[1] = Math.min(
|
||||||
|
this.#pendingBBox[1],
|
||||||
|
Math.max(bbox[1], clipBox[1])
|
||||||
|
);
|
||||||
|
this.#pendingBBox[2] = Math.max(
|
||||||
|
this.#pendingBBox[2],
|
||||||
|
Math.min(bbox[2], clipBox[2])
|
||||||
|
);
|
||||||
|
this.#pendingBBox[3] = Math.max(
|
||||||
|
this.#pendingBBox[3],
|
||||||
|
Math.min(bbox[3], clipBox[3])
|
||||||
|
);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
recordFullPageBBox(idx) {
|
||||||
|
this.#pendingBBox[0] = Math.max(0, this.#clipBox[0]);
|
||||||
|
this.#pendingBBox[1] = Math.max(0, this.#clipBox[1]);
|
||||||
|
this.#pendingBBox[2] = Math.min(this.#canvasWidth, this.#clipBox[2]);
|
||||||
|
this.#pendingBBox[3] = Math.min(this.#canvasHeight, this.#clipBox[3]);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} idx
|
||||||
|
*/
|
||||||
|
recordOperation(idx, preserve = false, dependencyLists) {
|
||||||
|
if (this._pendingBBoxIdx !== idx) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const minX = floor((this.#pendingBBox[0] * 256) / this.#canvasWidth);
|
||||||
|
const minY = floor((this.#pendingBBox[1] * 256) / this.#canvasHeight);
|
||||||
|
const maxX = ceil((this.#pendingBBox[2] * 256) / this.#canvasWidth);
|
||||||
|
const maxY = ceil((this.#pendingBBox[3] * 256) / this.#canvasHeight);
|
||||||
|
|
||||||
|
expandBBox(this.#bboxesCoords, idx, minX, minY, maxX, maxY);
|
||||||
|
if (dependencyLists) {
|
||||||
|
for (const dependencies of dependencyLists) {
|
||||||
|
for (const depIdx of dependencies) {
|
||||||
|
if (depIdx !== idx) {
|
||||||
|
expandBBox(this.#bboxesCoords, depIdx, minX, minY, maxX, maxY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!preserve) {
|
||||||
|
this._pendingBBoxIdx = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bboxToClipBoxDropOperation(idx) {
|
||||||
|
if (this._pendingBBoxIdx === idx) {
|
||||||
|
this._pendingBBoxIdx = -1;
|
||||||
|
|
||||||
|
this.#clipBox[0] = Math.max(this.#clipBox[0], this.#pendingBBox[0]);
|
||||||
|
this.#clipBox[1] = Math.max(this.#clipBox[1], this.#pendingBBox[1]);
|
||||||
|
this.#clipBox[2] = Math.min(this.#clipBox[2], this.#pendingBBox[2]);
|
||||||
|
this.#clipBox[3] = Math.min(this.#clipBox[3], this.#pendingBBox[3]);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
take() {
|
||||||
|
return new BBoxReader(this.#bboxes, this.#bboxesCoords);
|
||||||
|
}
|
||||||
|
|
||||||
|
takeDebugMetadata() {
|
||||||
|
throw new Error("Unreachable");
|
||||||
|
}
|
||||||
|
|
||||||
|
recordSimpleData(name, idx) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
recordIncrementalData(name, idx) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
resetIncrementalData(name, idx) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
recordNamedData(name, idx) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
recordSimpleDataFromNamed(name, depName, fallbackIdx) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
recordFutureForcedDependency(name, idx) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inheritSimpleDataAsFutureForcedDependencies(names) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inheritPendingDependenciesAsFutureForcedDependencies() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
recordCharacterBBox(idx, ctx, font, scale = 1, x = 0, y = 0, getMeasure) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
getSimpleIndex(dependencyName) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
recordDependencies(idx, dependencyNames) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
recordNamedDependency(idx, name) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
recordShowTextOperation(idx, preserve = false) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {"lineWidth" | "lineCap" | "lineJoin" | "miterLimit" | "dash" |
|
* @typedef {"lineWidth" | "lineCap" | "lineJoin" | "miterLimit" | "dash" |
|
||||||
* "strokeAlpha" | "fillColor" | "fillAlpha" | "globalCompositeOperation" |
|
* "strokeAlpha" | "fillColor" | "fillAlpha" | "globalCompositeOperation" |
|
||||||
@ -100,65 +417,34 @@ class CanvasDependencyTracker {
|
|||||||
|
|
||||||
#namedDependencies = new Map();
|
#namedDependencies = new Map();
|
||||||
|
|
||||||
#savesStack = [];
|
|
||||||
|
|
||||||
#markedContentStack = [];
|
|
||||||
|
|
||||||
#baseTransformStack = [[1, 0, 0, 1, 0, 0]];
|
|
||||||
|
|
||||||
#clipBox = [-Infinity, -Infinity, Infinity, Infinity];
|
|
||||||
|
|
||||||
// Float32Array<minX, minY, maxX, maxY>
|
|
||||||
#pendingBBox = new Float64Array([Infinity, Infinity, -Infinity, -Infinity]);
|
|
||||||
|
|
||||||
#pendingBBoxIdx = -1;
|
|
||||||
|
|
||||||
#pendingDependencies = new Set();
|
#pendingDependencies = new Set();
|
||||||
|
|
||||||
#operations = new Map();
|
|
||||||
|
|
||||||
#fontBBoxTrustworthy = new Map();
|
#fontBBoxTrustworthy = new Map();
|
||||||
|
|
||||||
#canvasWidth;
|
|
||||||
|
|
||||||
#canvasHeight;
|
|
||||||
|
|
||||||
// Uint8ClampedArray<minX, minY, maxX, maxY>
|
|
||||||
#bboxesCoords;
|
|
||||||
|
|
||||||
#bboxes;
|
|
||||||
|
|
||||||
#debugMetadata;
|
#debugMetadata;
|
||||||
|
|
||||||
constructor(canvas, operationsCount, recordDebugMetadata = false) {
|
#recordDebugMetadataDepenencyAfterRestore;
|
||||||
this.#canvasWidth = canvas.width;
|
|
||||||
this.#canvasHeight = canvas.height;
|
#bboxTracker;
|
||||||
this.#initializeBBoxes(operationsCount);
|
|
||||||
|
constructor(bboxTracker, recordDebugMetadata = false) {
|
||||||
|
this.#bboxTracker = bboxTracker;
|
||||||
if (recordDebugMetadata) {
|
if (recordDebugMetadata) {
|
||||||
this.#debugMetadata = new Map();
|
this.#debugMetadata = new Map();
|
||||||
|
this.#recordDebugMetadataDepenencyAfterRestore = (lastSave, opIdx) => {
|
||||||
|
ensureDebugMetadata(this.#debugMetadata, opIdx).dependencies.add(
|
||||||
|
lastSave
|
||||||
|
);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get clipBox() {
|
get clipBox() {
|
||||||
return this.#clipBox;
|
return this.#bboxTracker.clipBox;
|
||||||
}
|
}
|
||||||
|
|
||||||
growOperationsCount(operationsCount) {
|
growOperationsCount(operationsCount) {
|
||||||
if (operationsCount >= this.#bboxes.length) {
|
this.#bboxTracker.growOperationsCount(operationsCount);
|
||||||
this.#initializeBBoxes(operationsCount, this.#bboxes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#initializeBBoxes(operationsCount, oldBBoxes) {
|
|
||||||
const buffer = new ArrayBuffer(operationsCount * 4);
|
|
||||||
this.#bboxesCoords = new Uint8ClampedArray(buffer);
|
|
||||||
this.#bboxes = new Uint32Array(buffer);
|
|
||||||
if (oldBBoxes && oldBBoxes.length > 0) {
|
|
||||||
this.#bboxes.set(oldBBoxes);
|
|
||||||
this.#bboxes.fill(EMPTY_BBOX, oldBBoxes.length);
|
|
||||||
} else {
|
|
||||||
this.#bboxes.fill(EMPTY_BBOX);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
save(opIdx) {
|
save(opIdx) {
|
||||||
@ -172,13 +458,17 @@ class CanvasDependencyTracker {
|
|||||||
__proto__: this.#incremental[FORCED_DEPENDENCY_LABEL],
|
__proto__: this.#incremental[FORCED_DEPENDENCY_LABEL],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
this.#clipBox = { __proto__: this.#clipBox };
|
this.#bboxTracker.save(opIdx);
|
||||||
this.#savesStack.push(opIdx);
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
restore(opIdx) {
|
restore(opIdx) {
|
||||||
|
this.#bboxTracker.restore(
|
||||||
|
opIdx,
|
||||||
|
this.#recordDebugMetadataDepenencyAfterRestore
|
||||||
|
);
|
||||||
|
|
||||||
const previous = Object.getPrototypeOf(this.#simple);
|
const previous = Object.getPrototypeOf(this.#simple);
|
||||||
if (previous === null) {
|
if (previous === null) {
|
||||||
// Sometimes we call more .restore() than .save(), for
|
// Sometimes we call more .restore() than .save(), for
|
||||||
@ -187,77 +477,53 @@ class CanvasDependencyTracker {
|
|||||||
}
|
}
|
||||||
this.#simple = previous;
|
this.#simple = previous;
|
||||||
this.#incremental = Object.getPrototypeOf(this.#incremental);
|
this.#incremental = Object.getPrototypeOf(this.#incremental);
|
||||||
this.#clipBox = Object.getPrototypeOf(this.#clipBox);
|
|
||||||
|
|
||||||
const lastSave = this.#savesStack.pop();
|
|
||||||
if (lastSave !== undefined) {
|
|
||||||
ensureDebugMetadata(this.#debugMetadata, opIdx)?.dependencies.add(
|
|
||||||
lastSave
|
|
||||||
);
|
|
||||||
this.#bboxes[opIdx] = this.#bboxes[lastSave];
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
recordOpenMarker(opIdx) {
|
||||||
* @param {number} idx
|
this.#bboxTracker.recordOpenMarker(
|
||||||
*/
|
opIdx,
|
||||||
recordOpenMarker(idx) {
|
this.#recordDebugMetadataDepenencyAfterRestore
|
||||||
this.#savesStack.push(idx);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
getOpenMarker() {
|
|
||||||
if (this.#savesStack.length === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return this.#savesStack.at(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
recordCloseMarker(opIdx) {
|
|
||||||
const lastSave = this.#savesStack.pop();
|
|
||||||
if (lastSave !== undefined) {
|
|
||||||
ensureDebugMetadata(this.#debugMetadata, opIdx)?.dependencies.add(
|
|
||||||
lastSave
|
|
||||||
);
|
|
||||||
this.#bboxes[opIdx] = this.#bboxes[lastSave];
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Marked content needs a separate stack from save/restore, because they
|
|
||||||
// form two independent trees.
|
|
||||||
beginMarkedContent(opIdx) {
|
|
||||||
this.#markedContentStack.push(opIdx);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
endMarkedContent(opIdx) {
|
|
||||||
const lastSave = this.#markedContentStack.pop();
|
|
||||||
if (lastSave !== undefined) {
|
|
||||||
ensureDebugMetadata(this.#debugMetadata, opIdx)?.dependencies.add(
|
|
||||||
lastSave
|
|
||||||
);
|
|
||||||
this.#bboxes[opIdx] = this.#bboxes[lastSave];
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
pushBaseTransform(ctx) {
|
|
||||||
this.#baseTransformStack.push(
|
|
||||||
Util.multiplyByDOMMatrix(
|
|
||||||
this.#baseTransformStack.at(-1),
|
|
||||||
ctx.getTransform()
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getOpenMarker() {
|
||||||
|
return this.#bboxTracker.getOpenMarker();
|
||||||
|
}
|
||||||
|
|
||||||
|
recordCloseMarker(opIdx) {
|
||||||
|
this.#bboxTracker.recordCloseMarker(
|
||||||
|
opIdx,
|
||||||
|
this.#recordDebugMetadataDepenencyAfterRestore
|
||||||
|
);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} opIdx
|
||||||
|
*/
|
||||||
|
beginMarkedContent(opIdx) {
|
||||||
|
this.#bboxTracker.beginMarkedContent(opIdx);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
endMarkedContent(opIdx) {
|
||||||
|
this.#bboxTracker.endMarkedContent(
|
||||||
|
opIdx,
|
||||||
|
this.#recordDebugMetadataDepenencyAfterRestore
|
||||||
|
);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
pushBaseTransform(ctx) {
|
||||||
|
this.#bboxTracker.pushBaseTransform(ctx);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
popBaseTransform() {
|
popBaseTransform() {
|
||||||
if (this.#baseTransformStack.length > 1) {
|
this.#bboxTracker.popBaseTransform();
|
||||||
this.#baseTransformStack.pop();
|
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -327,73 +593,17 @@ class CanvasDependencyTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resetBBox(idx) {
|
resetBBox(idx) {
|
||||||
if (this.#pendingBBoxIdx !== idx) {
|
this.#bboxTracker.resetBBox(idx);
|
||||||
this.#pendingBBoxIdx = idx;
|
|
||||||
this.#pendingBBox[0] = Infinity;
|
|
||||||
this.#pendingBBox[1] = Infinity;
|
|
||||||
this.#pendingBBox[2] = -Infinity;
|
|
||||||
this.#pendingBBox[3] = -Infinity;
|
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
recordClipBox(idx, ctx, minX, maxX, minY, maxY) {
|
recordClipBox(idx, ctx, minX, maxX, minY, maxY) {
|
||||||
const transform = Util.multiplyByDOMMatrix(
|
this.#bboxTracker.recordClipBox(idx, ctx, minX, maxX, minY, maxY);
|
||||||
this.#baseTransformStack.at(-1),
|
|
||||||
ctx.getTransform()
|
|
||||||
);
|
|
||||||
const clipBox = [Infinity, Infinity, -Infinity, -Infinity];
|
|
||||||
Util.axialAlignedBoundingBox([minX, minY, maxX, maxY], transform, clipBox);
|
|
||||||
const intersection = Util.intersect(this.#clipBox, clipBox);
|
|
||||||
if (intersection) {
|
|
||||||
this.#clipBox[0] = intersection[0];
|
|
||||||
this.#clipBox[1] = intersection[1];
|
|
||||||
this.#clipBox[2] = intersection[2];
|
|
||||||
this.#clipBox[3] = intersection[3];
|
|
||||||
} else {
|
|
||||||
this.#clipBox[0] = this.#clipBox[1] = Infinity;
|
|
||||||
this.#clipBox[2] = this.#clipBox[3] = -Infinity;
|
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
recordBBox(idx, ctx, minX, maxX, minY, maxY) {
|
recordBBox(idx, ctx, minX, maxX, minY, maxY) {
|
||||||
const clipBox = this.#clipBox;
|
this.#bboxTracker.recordBBox(idx, ctx, minX, maxX, minY, maxY);
|
||||||
if (clipBox[0] === Infinity) {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
const transform = Util.multiplyByDOMMatrix(
|
|
||||||
this.#baseTransformStack.at(-1),
|
|
||||||
ctx.getTransform()
|
|
||||||
);
|
|
||||||
if (clipBox[0] === -Infinity) {
|
|
||||||
Util.axialAlignedBoundingBox(
|
|
||||||
[minX, minY, maxX, maxY],
|
|
||||||
transform,
|
|
||||||
this.#pendingBBox
|
|
||||||
);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
const bbox = [Infinity, Infinity, -Infinity, -Infinity];
|
|
||||||
Util.axialAlignedBoundingBox([minX, minY, maxX, maxY], transform, bbox);
|
|
||||||
this.#pendingBBox[0] = Math.min(
|
|
||||||
this.#pendingBBox[0],
|
|
||||||
Math.max(bbox[0], clipBox[0])
|
|
||||||
);
|
|
||||||
this.#pendingBBox[1] = Math.min(
|
|
||||||
this.#pendingBBox[1],
|
|
||||||
Math.max(bbox[1], clipBox[1])
|
|
||||||
);
|
|
||||||
this.#pendingBBox[2] = Math.max(
|
|
||||||
this.#pendingBBox[2],
|
|
||||||
Math.min(bbox[2], clipBox[2])
|
|
||||||
);
|
|
||||||
this.#pendingBBox[3] = Math.max(
|
|
||||||
this.#pendingBBox[3],
|
|
||||||
Math.min(bbox[3], clipBox[3])
|
|
||||||
);
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -475,11 +685,7 @@ class CanvasDependencyTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
recordFullPageBBox(idx) {
|
recordFullPageBBox(idx) {
|
||||||
this.#pendingBBox[0] = Math.max(0, this.#clipBox[0]);
|
this.#bboxTracker.recordFullPageBBox(idx);
|
||||||
this.#pendingBBox[1] = Math.max(0, this.#clipBox[1]);
|
|
||||||
this.#pendingBBox[2] = Math.min(this.#canvasWidth, this.#clipBox[2]);
|
|
||||||
this.#pendingBBox[3] = Math.min(this.#canvasHeight, this.#clipBox[3]);
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -520,39 +726,25 @@ class CanvasDependencyTracker {
|
|||||||
const metadata = ensureDebugMetadata(this.#debugMetadata, idx);
|
const metadata = ensureDebugMetadata(this.#debugMetadata, idx);
|
||||||
const { dependencies } = metadata;
|
const { dependencies } = metadata;
|
||||||
this.#pendingDependencies.forEach(dependencies.add, dependencies);
|
this.#pendingDependencies.forEach(dependencies.add, dependencies);
|
||||||
this.#savesStack.forEach(dependencies.add, dependencies);
|
this.#bboxTracker._savesStack.forEach(dependencies.add, dependencies);
|
||||||
this.#markedContentStack.forEach(dependencies.add, dependencies);
|
this.#bboxTracker._markedContentStack.forEach(
|
||||||
|
dependencies.add,
|
||||||
|
dependencies
|
||||||
|
);
|
||||||
dependencies.delete(idx);
|
dependencies.delete(idx);
|
||||||
metadata.isRenderingOperation = true;
|
metadata.isRenderingOperation = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.#pendingBBoxIdx === idx) {
|
const needsCleanup = !preserve && idx === this.#bboxTracker._pendingBBoxIdx;
|
||||||
const minX = floor((this.#pendingBBox[0] * 256) / this.#canvasWidth);
|
|
||||||
const minY = floor((this.#pendingBBox[1] * 256) / this.#canvasHeight);
|
|
||||||
const maxX = ceil((this.#pendingBBox[2] * 256) / this.#canvasWidth);
|
|
||||||
const maxY = ceil((this.#pendingBBox[3] * 256) / this.#canvasHeight);
|
|
||||||
|
|
||||||
expandBBox(this.#bboxesCoords, idx, minX, minY, maxX, maxY);
|
this.#bboxTracker.recordOperation(idx, preserve, [
|
||||||
for (const depIdx of this.#pendingDependencies) {
|
this.#pendingDependencies,
|
||||||
if (depIdx !== idx) {
|
this.#bboxTracker._savesStack,
|
||||||
expandBBox(this.#bboxesCoords, depIdx, minX, minY, maxX, maxY);
|
this.#bboxTracker._markedContentStack,
|
||||||
}
|
]);
|
||||||
}
|
|
||||||
for (const saveIdx of this.#savesStack) {
|
|
||||||
if (saveIdx !== idx) {
|
|
||||||
expandBBox(this.#bboxesCoords, saveIdx, minX, minY, maxX, maxY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const saveIdx of this.#markedContentStack) {
|
|
||||||
if (saveIdx !== idx) {
|
|
||||||
expandBBox(this.#bboxesCoords, saveIdx, minX, minY, maxX, maxY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!preserve) {
|
if (needsCleanup) {
|
||||||
this.#pendingDependencies.clear();
|
this.#pendingDependencies.clear();
|
||||||
this.#pendingBBoxIdx = -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
@ -569,42 +761,17 @@ class CanvasDependencyTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bboxToClipBoxDropOperation(idx, preserve = false) {
|
bboxToClipBoxDropOperation(idx, preserve = false) {
|
||||||
if (this.#pendingBBoxIdx === idx) {
|
const needsCleanup = !preserve && idx === this.#bboxTracker._pendingBBoxIdx;
|
||||||
this.#pendingBBoxIdx = -1;
|
this.#bboxTracker.bboxToClipBoxDropOperation(idx);
|
||||||
|
if (needsCleanup) {
|
||||||
this.#clipBox[0] = Math.max(this.#clipBox[0], this.#pendingBBox[0]);
|
this.#pendingDependencies.clear();
|
||||||
this.#clipBox[1] = Math.max(this.#clipBox[1], this.#pendingBBox[1]);
|
|
||||||
this.#clipBox[2] = Math.min(this.#clipBox[2], this.#pendingBBox[2]);
|
|
||||||
this.#clipBox[3] = Math.min(this.#clipBox[3], this.#pendingBBox[3]);
|
|
||||||
|
|
||||||
if (!preserve) {
|
|
||||||
this.#pendingDependencies.clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
_takePendingDependencies() {
|
|
||||||
const pendingDependencies = this.#pendingDependencies;
|
|
||||||
this.#pendingDependencies = new Set();
|
|
||||||
return pendingDependencies;
|
|
||||||
}
|
|
||||||
|
|
||||||
_extractOperation(idx) {
|
|
||||||
const operation = this.#operations.get(idx);
|
|
||||||
this.#operations.delete(idx);
|
|
||||||
return operation;
|
|
||||||
}
|
|
||||||
|
|
||||||
_pushPendingDependencies(dependencies) {
|
|
||||||
for (const dep of dependencies) {
|
|
||||||
this.#pendingDependencies.add(dep);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
take() {
|
take() {
|
||||||
this.#fontBBoxTrustworthy.clear();
|
this.#fontBBoxTrustworthy.clear();
|
||||||
return new BBoxReader(this.#bboxes, this.#bboxesCoords);
|
return this.#bboxTracker.take();
|
||||||
}
|
}
|
||||||
|
|
||||||
takeDebugMetadata() {
|
takeDebugMetadata() {
|
||||||
@ -1073,6 +1240,7 @@ class CanvasImagesTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
CanvasBBoxTracker,
|
||||||
CanvasDependencyTracker,
|
CanvasDependencyTracker,
|
||||||
CanvasImagesTracker,
|
CanvasImagesTracker,
|
||||||
CanvasNestedDependencyTracker,
|
CanvasNestedDependencyTracker,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user