mirror of
https://github.com/mozilla/pdf.js.git
synced 2026-04-09 14:54:04 +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,
|
||||
} from "./annotation_storage.js";
|
||||
import {
|
||||
CanvasBBoxTracker,
|
||||
CanvasDependencyTracker,
|
||||
CanvasImagesTracker,
|
||||
} 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({
|
||||
callback: complete,
|
||||
// Only include the required properties, and *not* the entire object.
|
||||
params: {
|
||||
canvas,
|
||||
canvasContext,
|
||||
dependencyTracker:
|
||||
shouldRecordOperations || shouldRecordImages
|
||||
? new CanvasDependencyTracker(
|
||||
canvas,
|
||||
intentState.operatorList.length,
|
||||
recordForDebugger
|
||||
)
|
||||
: null,
|
||||
dependencyTracker: dependencyTracker ?? bboxTracker,
|
||||
imagesTracker: shouldRecordImages
|
||||
? new CanvasImagesTracker(canvas)
|
||||
: null,
|
||||
|
||||
@ -71,6 +71,323 @@ const ensureDebugMetadata = (map, key) =>
|
||||
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" |
|
||||
* "strokeAlpha" | "fillColor" | "fillAlpha" | "globalCompositeOperation" |
|
||||
@ -100,65 +417,34 @@ class CanvasDependencyTracker {
|
||||
|
||||
#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();
|
||||
|
||||
#operations = new Map();
|
||||
|
||||
#fontBBoxTrustworthy = new Map();
|
||||
|
||||
#canvasWidth;
|
||||
|
||||
#canvasHeight;
|
||||
|
||||
// Uint8ClampedArray<minX, minY, maxX, maxY>
|
||||
#bboxesCoords;
|
||||
|
||||
#bboxes;
|
||||
|
||||
#debugMetadata;
|
||||
|
||||
constructor(canvas, operationsCount, recordDebugMetadata = false) {
|
||||
this.#canvasWidth = canvas.width;
|
||||
this.#canvasHeight = canvas.height;
|
||||
this.#initializeBBoxes(operationsCount);
|
||||
#recordDebugMetadataDepenencyAfterRestore;
|
||||
|
||||
#bboxTracker;
|
||||
|
||||
constructor(bboxTracker, recordDebugMetadata = false) {
|
||||
this.#bboxTracker = bboxTracker;
|
||||
if (recordDebugMetadata) {
|
||||
this.#debugMetadata = new Map();
|
||||
this.#recordDebugMetadataDepenencyAfterRestore = (lastSave, opIdx) => {
|
||||
ensureDebugMetadata(this.#debugMetadata, opIdx).dependencies.add(
|
||||
lastSave
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
get clipBox() {
|
||||
return this.#clipBox;
|
||||
return this.#bboxTracker.clipBox;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
this.#bboxTracker.growOperationsCount(operationsCount);
|
||||
}
|
||||
|
||||
save(opIdx) {
|
||||
@ -172,13 +458,17 @@ class CanvasDependencyTracker {
|
||||
__proto__: this.#incremental[FORCED_DEPENDENCY_LABEL],
|
||||
},
|
||||
};
|
||||
this.#clipBox = { __proto__: this.#clipBox };
|
||||
this.#savesStack.push(opIdx);
|
||||
this.#bboxTracker.save(opIdx);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
restore(opIdx) {
|
||||
this.#bboxTracker.restore(
|
||||
opIdx,
|
||||
this.#recordDebugMetadataDepenencyAfterRestore
|
||||
);
|
||||
|
||||
const previous = Object.getPrototypeOf(this.#simple);
|
||||
if (previous === null) {
|
||||
// Sometimes we call more .restore() than .save(), for
|
||||
@ -187,77 +477,53 @@ class CanvasDependencyTracker {
|
||||
}
|
||||
this.#simple = previous;
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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) {
|
||||
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()
|
||||
)
|
||||
recordOpenMarker(opIdx) {
|
||||
this.#bboxTracker.recordOpenMarker(
|
||||
opIdx,
|
||||
this.#recordDebugMetadataDepenencyAfterRestore
|
||||
);
|
||||
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() {
|
||||
if (this.#baseTransformStack.length > 1) {
|
||||
this.#baseTransformStack.pop();
|
||||
}
|
||||
this.#bboxTracker.popBaseTransform();
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -327,73 +593,17 @@ class CanvasDependencyTracker {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
this.#bboxTracker.resetBBox(idx);
|
||||
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;
|
||||
}
|
||||
this.#bboxTracker.recordClipBox(idx, ctx, minX, maxX, minY, maxY);
|
||||
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])
|
||||
);
|
||||
this.#bboxTracker.recordBBox(idx, ctx, minX, maxX, minY, maxY);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -475,11 +685,7 @@ class CanvasDependencyTracker {
|
||||
}
|
||||
|
||||
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]);
|
||||
|
||||
this.#bboxTracker.recordFullPageBBox(idx);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -520,39 +726,25 @@ class CanvasDependencyTracker {
|
||||
const metadata = ensureDebugMetadata(this.#debugMetadata, idx);
|
||||
const { dependencies } = metadata;
|
||||
this.#pendingDependencies.forEach(dependencies.add, dependencies);
|
||||
this.#savesStack.forEach(dependencies.add, dependencies);
|
||||
this.#markedContentStack.forEach(dependencies.add, dependencies);
|
||||
this.#bboxTracker._savesStack.forEach(dependencies.add, dependencies);
|
||||
this.#bboxTracker._markedContentStack.forEach(
|
||||
dependencies.add,
|
||||
dependencies
|
||||
);
|
||||
dependencies.delete(idx);
|
||||
metadata.isRenderingOperation = true;
|
||||
}
|
||||
|
||||
if (this.#pendingBBoxIdx === idx) {
|
||||
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);
|
||||
const needsCleanup = !preserve && idx === this.#bboxTracker._pendingBBoxIdx;
|
||||
|
||||
expandBBox(this.#bboxesCoords, idx, minX, minY, maxX, maxY);
|
||||
for (const depIdx of this.#pendingDependencies) {
|
||||
if (depIdx !== idx) {
|
||||
expandBBox(this.#bboxesCoords, depIdx, minX, minY, maxX, maxY);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
this.#bboxTracker.recordOperation(idx, preserve, [
|
||||
this.#pendingDependencies,
|
||||
this.#bboxTracker._savesStack,
|
||||
this.#bboxTracker._markedContentStack,
|
||||
]);
|
||||
|
||||
if (!preserve) {
|
||||
this.#pendingDependencies.clear();
|
||||
this.#pendingBBoxIdx = -1;
|
||||
}
|
||||
if (needsCleanup) {
|
||||
this.#pendingDependencies.clear();
|
||||
}
|
||||
|
||||
return this;
|
||||
@ -569,42 +761,17 @@ class CanvasDependencyTracker {
|
||||
}
|
||||
|
||||
bboxToClipBoxDropOperation(idx, preserve = false) {
|
||||
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]);
|
||||
|
||||
if (!preserve) {
|
||||
this.#pendingDependencies.clear();
|
||||
}
|
||||
const needsCleanup = !preserve && idx === this.#bboxTracker._pendingBBoxIdx;
|
||||
this.#bboxTracker.bboxToClipBoxDropOperation(idx);
|
||||
if (needsCleanup) {
|
||||
this.#pendingDependencies.clear();
|
||||
}
|
||||
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() {
|
||||
this.#fontBBoxTrustworthy.clear();
|
||||
return new BBoxReader(this.#bboxes, this.#bboxesCoords);
|
||||
return this.#bboxTracker.take();
|
||||
}
|
||||
|
||||
takeDebugMetadata() {
|
||||
@ -1073,6 +1240,7 @@ class CanvasImagesTracker {
|
||||
}
|
||||
|
||||
export {
|
||||
CanvasBBoxTracker,
|
||||
CanvasDependencyTracker,
|
||||
CanvasImagesTracker,
|
||||
CanvasNestedDependencyTracker,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user