mirror of
https://github.com/mozilla/pdf.js.git
synced 2025-04-22 16:18:08 +02:00
Merge pull request #15043 from Snuffleupagus/PrintAnnotationStorage
[api-minor] Introduce a `PrintAnnotationStorage` with *frozen* serializable data
This commit is contained in:
commit
3fab4af949
6 changed files with 196 additions and 41 deletions
|
@ -13,9 +13,9 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { objectFromMap, unreachable } from "../shared/util.js";
|
||||
import { AnnotationEditor } from "./editor/editor.js";
|
||||
import { MurmurHash3_64 } from "../shared/murmurhash3.js";
|
||||
import { objectFromMap } from "../shared/util.js";
|
||||
|
||||
/**
|
||||
* Key/value storage for annotation data in forms.
|
||||
|
@ -98,7 +98,7 @@ class AnnotationStorage {
|
|||
this._storage.set(key, value);
|
||||
}
|
||||
if (modified) {
|
||||
this._setModified();
|
||||
this.#setModified();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,10 +110,7 @@ class AnnotationStorage {
|
|||
return this._storage.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_setModified() {
|
||||
#setModified() {
|
||||
if (!this._modified) {
|
||||
this._modified = true;
|
||||
if (typeof this.onSetModified === "function") {
|
||||
|
@ -131,6 +128,13 @@ class AnnotationStorage {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {PrintAnnotationStorage}
|
||||
*/
|
||||
get print() {
|
||||
return new PrintAnnotationStorage(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* PLEASE NOTE: Only intended for usage within the API itself.
|
||||
* @ignore
|
||||
|
@ -139,11 +143,10 @@ class AnnotationStorage {
|
|||
if (this._storage.size === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const clone = new Map();
|
||||
for (const [key, value] of this._storage) {
|
||||
const val = value instanceof AnnotationEditor ? value.serialize() : value;
|
||||
clone.set(key, val);
|
||||
|
||||
for (const [key, val] of this._storage) {
|
||||
clone.set(key, val instanceof AnnotationEditor ? val.serialize() : val);
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
@ -152,15 +155,48 @@ class AnnotationStorage {
|
|||
* PLEASE NOTE: Only intended for usage within the API itself.
|
||||
* @ignore
|
||||
*/
|
||||
get hash() {
|
||||
static getHash(map) {
|
||||
if (!map) {
|
||||
return "";
|
||||
}
|
||||
const hash = new MurmurHash3_64();
|
||||
|
||||
for (const [key, value] of this._storage) {
|
||||
const val = value instanceof AnnotationEditor ? value.serialize() : value;
|
||||
for (const [key, val] of map) {
|
||||
hash.update(`${key}:${JSON.stringify(val)}`);
|
||||
}
|
||||
return hash.hexdigest();
|
||||
}
|
||||
}
|
||||
|
||||
export { AnnotationStorage };
|
||||
/**
|
||||
* A special `AnnotationStorage` for use during printing, where the serializable
|
||||
* data is *frozen* upon initialization, to prevent scripting from modifying its
|
||||
* contents. (Necessary since printing is triggered synchronously in browsers.)
|
||||
*/
|
||||
class PrintAnnotationStorage extends AnnotationStorage {
|
||||
#serializable = null;
|
||||
|
||||
constructor(parent) {
|
||||
super();
|
||||
// Create a *copy* of the data, since Objects are passed by reference in JS.
|
||||
this.#serializable = structuredClone(parent.serializable);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {PrintAnnotationStorage}
|
||||
*/
|
||||
// eslint-disable-next-line getter-return
|
||||
get print() {
|
||||
unreachable("Should not call PrintAnnotationStorage.print");
|
||||
}
|
||||
|
||||
/**
|
||||
* PLEASE NOTE: Only intended for usage within the API itself.
|
||||
* @ignore
|
||||
*/
|
||||
get serializable() {
|
||||
return this.#serializable;
|
||||
}
|
||||
}
|
||||
|
||||
export { AnnotationStorage, PrintAnnotationStorage };
|
||||
|
|
|
@ -37,6 +37,10 @@ import {
|
|||
unreachable,
|
||||
warn,
|
||||
} from "../shared/util.js";
|
||||
import {
|
||||
AnnotationStorage,
|
||||
PrintAnnotationStorage,
|
||||
} from "./annotation_storage.js";
|
||||
import {
|
||||
deprecated,
|
||||
DOMCanvasFactory,
|
||||
|
@ -49,7 +53,6 @@ import {
|
|||
StatTimer,
|
||||
} from "./display_utils.js";
|
||||
import { FontFaceObject, FontLoader } from "./font_loader.js";
|
||||
import { AnnotationStorage } from "./annotation_storage.js";
|
||||
import { CanvasGraphics } from "./canvas.js";
|
||||
import { GlobalWorkerOptions } from "./worker_options.js";
|
||||
import { isNodeJS } from "../shared/is_node.js";
|
||||
|
@ -1181,6 +1184,7 @@ class PDFDocumentProxy {
|
|||
* states set.
|
||||
* @property {Map<string, HTMLCanvasElement>} [annotationCanvasMap] - Map some
|
||||
* annotation ids with canvases used to render them.
|
||||
* @property {PrintAnnotationStorage} [printAnnotationStorage]
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -1201,6 +1205,7 @@ class PDFDocumentProxy {
|
|||
* (as above) but where interactive form elements are updated with data
|
||||
* from the {@link AnnotationStorage}-instance; useful e.g. for printing.
|
||||
* The default value is `AnnotationMode.ENABLE`.
|
||||
* @property {PrintAnnotationStorage} [printAnnotationStorage]
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -1399,6 +1404,7 @@ class PDFPageProxy {
|
|||
optionalContentConfigPromise = null,
|
||||
annotationCanvasMap = null,
|
||||
pageColors = null,
|
||||
printAnnotationStorage = null,
|
||||
}) {
|
||||
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("GENERIC")) {
|
||||
if (arguments[0]?.renderInteractiveForms !== undefined) {
|
||||
|
@ -1433,7 +1439,8 @@ class PDFPageProxy {
|
|||
|
||||
const intentArgs = this._transport.getRenderingIntent(
|
||||
intent,
|
||||
annotationMode
|
||||
annotationMode,
|
||||
printAnnotationStorage
|
||||
);
|
||||
// If there was a pending destroy, cancel it so no cleanup happens during
|
||||
// this call to render.
|
||||
|
@ -1560,6 +1567,7 @@ class PDFPageProxy {
|
|||
getOperatorList({
|
||||
intent = "display",
|
||||
annotationMode = AnnotationMode.ENABLE,
|
||||
printAnnotationStorage = null,
|
||||
} = {}) {
|
||||
function operatorListChanged() {
|
||||
if (intentState.operatorList.lastChunk) {
|
||||
|
@ -1572,6 +1580,7 @@ class PDFPageProxy {
|
|||
const intentArgs = this._transport.getRenderingIntent(
|
||||
intent,
|
||||
annotationMode,
|
||||
printAnnotationStorage,
|
||||
/* isOpList = */ true
|
||||
);
|
||||
let intentState = this._intentStates.get(intentArgs.cacheKey);
|
||||
|
@ -1800,7 +1809,7 @@ class PDFPageProxy {
|
|||
/**
|
||||
* @private
|
||||
*/
|
||||
_pumpOperatorList({ renderingIntent, cacheKey }) {
|
||||
_pumpOperatorList({ renderingIntent, cacheKey, annotationStorageMap }) {
|
||||
if (
|
||||
typeof PDFJSDev === "undefined" ||
|
||||
PDFJSDev.test("!PRODUCTION || TESTING")
|
||||
|
@ -1817,10 +1826,7 @@ class PDFPageProxy {
|
|||
pageIndex: this._pageIndex,
|
||||
intent: renderingIntent,
|
||||
cacheKey,
|
||||
annotationStorage:
|
||||
renderingIntent & RenderingIntentFlag.ANNOTATIONS_STORAGE
|
||||
? this._transport.annotationStorage.serializable
|
||||
: null,
|
||||
annotationStorage: annotationStorageMap,
|
||||
}
|
||||
);
|
||||
const reader = readableStream.getReader();
|
||||
|
@ -2406,10 +2412,11 @@ class WorkerTransport {
|
|||
getRenderingIntent(
|
||||
intent,
|
||||
annotationMode = AnnotationMode.ENABLE,
|
||||
printAnnotationStorage = null,
|
||||
isOpList = false
|
||||
) {
|
||||
let renderingIntent = RenderingIntentFlag.DISPLAY; // Default value.
|
||||
let annotationHash = "";
|
||||
let annotationMap = null;
|
||||
|
||||
switch (intent) {
|
||||
case "any":
|
||||
|
@ -2436,7 +2443,13 @@ class WorkerTransport {
|
|||
case AnnotationMode.ENABLE_STORAGE:
|
||||
renderingIntent += RenderingIntentFlag.ANNOTATIONS_STORAGE;
|
||||
|
||||
annotationHash = this.annotationStorage.hash;
|
||||
const annotationStorage =
|
||||
renderingIntent & RenderingIntentFlag.PRINT &&
|
||||
printAnnotationStorage instanceof PrintAnnotationStorage
|
||||
? printAnnotationStorage
|
||||
: this.annotationStorage;
|
||||
|
||||
annotationMap = annotationStorage.serializable;
|
||||
break;
|
||||
default:
|
||||
warn(`getRenderingIntent - invalid annotationMode: ${annotationMode}`);
|
||||
|
@ -2448,7 +2461,10 @@ class WorkerTransport {
|
|||
|
||||
return {
|
||||
renderingIntent,
|
||||
cacheKey: `${renderingIntent}_${annotationHash}`,
|
||||
cacheKey: `${renderingIntent}_${AnnotationStorage.getHash(
|
||||
annotationMap
|
||||
)}`,
|
||||
annotationStorageMap: annotationMap,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue