[api-minor] Implement basic support for OptionalContent Usage dicts (issue 5764, bug 1826783)

The following are some highlights of this patch:
 - In the Worker we only extract a *subset* of the potential contents of the `Usage` dictionary, to avoid having to implement/test a bunch of code that'd be completely unused in the viewer.

 - In order to still allow the user to *manually* override the default visible layers in the viewer, the viewable/printable state is purposely *not* enforced during initialization in the `OptionalContentConfig` constructor.

 - Printing will now always use the *default* visible layers, rather than using the same state as the viewer (as was the case previously).
   This ensures that the printing-output will correctly take the `Usage` dictionary into account, and in practice toggling of visible layers rarely seem to be necessary except in the viewer itself (if at all).[1]

---
[1] In the unlikely case that it'd ever be deemed necessary to support fine-grained control of optional content visibility during printing, some new (additional) UI would likely be needed to support that case.
This commit is contained in:
Jonas Jenwald 2024-02-25 14:12:36 +01:00
parent e647311a89
commit 3c78ff5fb0
13 changed files with 186 additions and 62 deletions

View file

@ -949,12 +949,26 @@ class PDFDocumentProxy {
}
/**
* @typedef {Object} GetOptionalContentConfigParameters
* @property {string} [intent] - Determines the optional content groups that
* are visible by default; valid values are:
* - 'display' (viewable groups).
* - 'print' (printable groups).
* - 'any' (all groups).
* The default value is 'display'.
*/
/**
* @param {GetOptionalContentConfigParameters} [params] - Optional content
* config parameters.
* @returns {Promise<OptionalContentConfig>} A promise that is resolved with
* an {@link OptionalContentConfig} that contains all the optional content
* groups (assuming that the document has any).
*/
getOptionalContentConfig() {
return this._transport.getOptionalContentConfig();
getOptionalContentConfig({ intent = "display" } = {}) {
const { renderingIntent } = this._transport.getRenderingIntent(intent);
return this._transport.getOptionalContentConfig(renderingIntent);
}
/**
@ -1340,17 +1354,14 @@ class PDFPageProxy {
}
/**
* @param {GetAnnotationsParameters} params - Annotation parameters.
* @param {GetAnnotationsParameters} [params] - Annotation parameters.
* @returns {Promise<Array<any>>} A promise that is resolved with an
* {Array} of the annotation objects.
*/
getAnnotations({ intent = "display" } = {}) {
const intentArgs = this._transport.getRenderingIntent(intent);
const { renderingIntent } = this._transport.getRenderingIntent(intent);
return this._transport.getAnnotations(
this._pageIndex,
intentArgs.renderingIntent
);
return this._transport.getAnnotations(this._pageIndex, renderingIntent);
}
/**
@ -1411,20 +1422,20 @@ class PDFPageProxy {
annotationMode,
printAnnotationStorage
);
const { renderingIntent, cacheKey } = intentArgs;
// If there was a pending destroy, cancel it so no cleanup happens during
// this call to render...
this.#pendingCleanup = false;
// ... and ensure that a delayed cleanup is always aborted.
this.#abortDelayedCleanup();
if (!optionalContentConfigPromise) {
optionalContentConfigPromise = this._transport.getOptionalContentConfig();
}
optionalContentConfigPromise ||=
this._transport.getOptionalContentConfig(renderingIntent);
let intentState = this._intentStates.get(intentArgs.cacheKey);
let intentState = this._intentStates.get(cacheKey);
if (!intentState) {
intentState = Object.create(null);
this._intentStates.set(intentArgs.cacheKey, intentState);
this._intentStates.set(cacheKey, intentState);
}
// Ensure that a pending `streamReader` cancel timeout is always aborted.
@ -1433,9 +1444,7 @@ class PDFPageProxy {
intentState.streamReaderCancelTimeout = null;
}
const intentPrint = !!(
intentArgs.renderingIntent & RenderingIntentFlag.PRINT
);
const intentPrint = !!(renderingIntent & RenderingIntentFlag.PRINT);
// If there's no displayReadyCapability yet, then the operatorList
// was never requested before. Make the request and create the promise.
@ -1512,6 +1521,12 @@ class PDFPageProxy {
}
this._stats?.time("Rendering");
if (!(optionalContentConfig.renderingIntent & renderingIntent)) {
throw new Error(
"Must use the same `intent`-argument when calling the `PDFPageProxy.render` " +
"and `PDFDocumentProxy.getOptionalContentConfig` methods."
);
}
internalRenderTask.initializeGraphics({
transparency,
optionalContentConfig,
@ -2994,10 +3009,10 @@ class WorkerTransport {
return this.messageHandler.sendWithPromise("GetOutline", null);
}
getOptionalContentConfig() {
return this.messageHandler
.sendWithPromise("GetOptionalContentConfig", null)
.then(results => new OptionalContentConfig(results));
getOptionalContentConfig(renderingIntent) {
return this.#cacheSimpleMethod("GetOptionalContentConfig").then(
data => new OptionalContentConfig(data, renderingIntent)
);
}
getPermissions() {