[api-minor] Introduce a new annotationMode-option, in PDFPageProxy.{render, getOperatorList}

*This is a follow-up to PRs 13867 and 13899.*

This patch is tagged `api-minor` for the following reasons:
 - It replaces the `renderInteractiveForms`/`includeAnnotationStorage`-options, in the `PDFPageProxy.render`-method, with the single `annotationMode`-option that controls which annotations are being rendered and how. Note that the old options were mutually exclusive, and setting both to `true` would result in undefined behaviour.

 - For improved consistency in the API, the `annotationMode`-option will also work together with the `PDFPageProxy.getOperatorList`-method.

 - It's now also possible to disable *all* annotation rendering in both the API and the Viewer, since the other changes meant that this could now be supported with a single added line on the worker-thread[1]; fixes 7282.

---
[1] Please note that in order to simplify the overall implementation, we'll purposely only support disabling of *all* annotations and that the option is being shared between the API and the Viewer. For any more "specialized" use-cases, where e.g. only some annotation-types are being rendered and/or the API and Viewer render different sets of annotations, that'll have to be handled in third-party implementations/forks of the PDF.js code-base.
This commit is contained in:
Jonas Jenwald 2021-08-08 14:36:28 +02:00
parent 56e7bb626c
commit 41efa3c071
16 changed files with 272 additions and 134 deletions

View file

@ -19,6 +19,7 @@
import {
AbortException,
AnnotationMode,
assert,
createPromiseCapability,
getVerbosityLevel,
@ -1135,9 +1136,18 @@ class PDFDocumentProxy {
* the `PDFPageProxy.getViewport` method.
* @property {string} [intent] - Rendering intent, can be 'display', 'print',
* or 'any'. The default value is 'display'.
* @property {boolean} [renderInteractiveForms] - Whether or not interactive
* form elements are rendered in the display layer. If so, we do not render
* them on the canvas as well. The default value is `false`.
* @property {number} [annotationMode] Controls which annotations are rendered
* onto the canvas, for annotations with appearance-data; the values from
* {@link AnnotationMode} should be used. The following values are supported:
* - `AnnotationMode.DISABLE`, which disables all annotations.
* - `AnnotationMode.ENABLE`, which includes all possible annotations (thus
* it also depends on the `intent`-option, see above).
* - `AnnotationMode.ENABLE_FORMS`, which excludes annotations that contain
* interactive form elements (those will be rendered in the display layer).
* - `AnnotationMode.ENABLE_STORAGE`, which includes all possible annotations
* (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 {Array<any>} [transform] - Additional transform, applied just
* before viewport transform.
* @property {Object} [imageLayer] - An object that has `beginLayout`,
@ -1149,9 +1159,6 @@ class PDFDocumentProxy {
* <color> value, a `CanvasGradient` object (a linear or radial gradient) or
* a `CanvasPattern` object (a repetitive image). The default value is
* 'rgb(255,255,255)'.
* @property {boolean} [includeAnnotationStorage] - Render stored interactive
* form element data, from the {@link AnnotationStorage}-instance, onto the
* canvas itself; useful e.g. for printing. The default value is `false`.
* @property {Promise<OptionalContentConfig>} [optionalContentConfigPromise] -
* A promise that should resolve with an {@link OptionalContentConfig}
* created from `PDFDocumentProxy.getOptionalContentConfig`. If `null`,
@ -1165,6 +1172,18 @@ class PDFDocumentProxy {
* @typedef {Object} GetOperatorListParameters
* @property {string} [intent] - Rendering intent, can be 'display', 'print',
* or 'any'. The default value is 'display'.
* @property {number} [annotationMode] Controls which annotations are included
* in the operatorList, for annotations with appearance-data; the values from
* {@link AnnotationMode} should be used. The following values are supported:
* - `AnnotationMode.DISABLE`, which disables all annotations.
* - `AnnotationMode.ENABLE`, which includes all possible annotations (thus
* it also depends on the `intent`-option, see above).
* - `AnnotationMode.ENABLE_FORMS`, which excludes annotations that contain
* interactive form elements (those will be rendered in the display layer).
* - `AnnotationMode.ENABLE_STORAGE`, which includes all possible annotations
* (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`.
*/
/**
@ -1280,7 +1299,7 @@ class PDFPageProxy {
* {Array} of the annotation objects.
*/
getAnnotations({ intent = "display" } = {}) {
const intentArgs = this._transport.getRenderingIntent(intent, {});
const intentArgs = this._transport.getRenderingIntent(intent);
let promise = this._annotationPromises.get(intentArgs.cacheKey);
if (!promise) {
@ -1324,22 +1343,21 @@ class PDFPageProxy {
canvasContext,
viewport,
intent = "display",
renderInteractiveForms = false,
annotationMode = AnnotationMode.ENABLE,
transform = null,
imageLayer = null,
canvasFactory = null,
background = null,
includeAnnotationStorage = false,
optionalContentConfigPromise = null,
}) {
if (this._stats) {
this._stats.time("Overall");
}
const intentArgs = this._transport.getRenderingIntent(intent, {
renderForms: renderInteractiveForms === true,
includeAnnotationStorage: includeAnnotationStorage === true,
});
const intentArgs = this._transport.getRenderingIntent(
intent,
annotationMode
);
// If there was a pending destroy, cancel it so no cleanup happens during
// this call to render.
this.pendingCleanup = false;
@ -1460,7 +1478,10 @@ class PDFPageProxy {
* @returns {Promise<PDFOperatorList>} A promise resolved with an
* {@link PDFOperatorList} object that represents the page's operator list.
*/
getOperatorList({ intent = "display" } = {}) {
getOperatorList({
intent = "display",
annotationMode = AnnotationMode.ENABLE,
} = {}) {
function operatorListChanged() {
if (intentState.operatorList.lastChunk) {
intentState.opListReadCapability.resolve(intentState.operatorList);
@ -1469,9 +1490,11 @@ class PDFPageProxy {
}
}
const intentArgs = this._transport.getRenderingIntent(intent, {
isOpList: true,
});
const intentArgs = this._transport.getRenderingIntent(
intent,
annotationMode,
/* isOpList = */ true
);
let intentState = this._intentStates.get(intentArgs.cacheKey);
if (!intentState) {
intentState = Object.create(null);
@ -1792,7 +1815,7 @@ class PDFPageProxy {
}
}
intentState.streamReader
.cancel(new AbortException(reason?.message))
.cancel(new AbortException(reason.message))
.catch(() => {
// Avoid "Uncaught promise" messages in the console.
});
@ -2351,7 +2374,8 @@ class WorkerTransport {
getRenderingIntent(
intent,
{ renderForms = false, includeAnnotationStorage = false, isOpList = false }
annotationMode = AnnotationMode.ENABLE,
isOpList = false
) {
let renderingIntent = RenderingIntentFlag.DISPLAY; // Default value.
let lastModified = "";
@ -2369,13 +2393,22 @@ class WorkerTransport {
warn(`getRenderingIntent - invalid intent: ${intent}`);
}
if (renderForms) {
renderingIntent += RenderingIntentFlag.ANNOTATIONS_FORMS;
}
if (includeAnnotationStorage) {
renderingIntent += RenderingIntentFlag.ANNOTATIONS_STORAGE;
switch (annotationMode) {
case AnnotationMode.DISABLE:
renderingIntent += RenderingIntentFlag.ANNOTATIONS_DISABLE;
break;
case AnnotationMode.ENABLE:
break;
case AnnotationMode.ENABLE_FORMS:
renderingIntent += RenderingIntentFlag.ANNOTATIONS_FORMS;
break;
case AnnotationMode.ENABLE_STORAGE:
renderingIntent += RenderingIntentFlag.ANNOTATIONS_STORAGE;
lastModified = this.annotationStorage.lastModified;
lastModified = this.annotationStorage.lastModified;
break;
default:
warn(`getRenderingIntent - invalid annotationMode: ${annotationMode}`);
}
if (isOpList) {