Merge pull request #13867 from Snuffleupagus/RenderingIntentFlag

[api-minor] Re-factor the *internal* renderingIntent, and change the default `intent` value in the `PDFPageProxy.getAnnotations` method
This commit is contained in:
Tim van der Meij 2021-08-07 19:25:51 +02:00 committed by GitHub
commit 952f6366bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 96 additions and 43 deletions

View File

@ -25,6 +25,7 @@ import {
isString,
OPS,
PageActionEventType,
RenderingIntentFlag,
shadow,
stringToBytes,
stringToPDFString,
@ -319,14 +320,7 @@ class Page {
});
}
getOperatorList({
handler,
sink,
task,
intent,
renderInteractiveForms,
annotationStorage,
}) {
getOperatorList({ handler, sink, task, intent, annotationStorage }) {
const contentStreamPromise = this.getContentStream(handler);
const resourcesPromise = this.loadResources([
"ColorSpace",
@ -383,26 +377,26 @@ class Page {
pageOpList.flush(true);
return { length: pageOpList.totalLength };
}
const renderForms = !!(intent & RenderingIntentFlag.ANNOTATION_FORMS),
intentAny = !!(intent & RenderingIntentFlag.ANY),
intentDisplay = !!(intent & RenderingIntentFlag.DISPLAY),
intentPrint = !!(intent & RenderingIntentFlag.PRINT);
// Collect the operator list promises for the annotations. Each promise
// is resolved with the complete operator list for a single annotation.
const annotationIntent = intent.startsWith("oplist-")
? intent.split("-")[1]
: intent;
const opListPromises = [];
for (const annotation of annotations) {
if (
(annotationIntent === "display" &&
annotation.mustBeViewed(annotationStorage)) ||
(annotationIntent === "print" &&
annotation.mustBePrinted(annotationStorage))
intentAny ||
(intentDisplay && annotation.mustBeViewed(annotationStorage)) ||
(intentPrint && annotation.mustBePrinted(annotationStorage))
) {
opListPromises.push(
annotation
.getOperatorList(
partialEvaluator,
task,
renderInteractiveForms,
renderForms,
annotationStorage
)
.catch(function (reason) {
@ -496,15 +490,23 @@ class Page {
getAnnotationsData(intent) {
return this._parsedAnnotations.then(function (annotations) {
const annotationsData = [];
for (let i = 0, ii = annotations.length; i < ii; i++) {
if (annotations.length === 0) {
return annotationsData;
}
const intentAny = !!(intent & RenderingIntentFlag.ANY),
intentDisplay = !!(intent & RenderingIntentFlag.DISPLAY),
intentPrint = !!(intent & RenderingIntentFlag.PRINT);
for (const annotation of annotations) {
// Get the annotation even if it's hidden because
// JS can change its display.
if (
!intent ||
(intent === "display" && annotations[i].viewable) ||
(intent === "print" && annotations[i].printable)
intentAny ||
(intentDisplay && annotation.viewable) ||
(intentPrint && annotation.printable)
) {
annotationsData.push(annotations[i].data);
annotationsData.push(annotation.data);
}
}
return annotationsData;

View File

@ -13,7 +13,14 @@
* limitations under the License.
*/
import { assert, ImageKind, OPS, shadow, warn } from "../shared/util.js";
import {
assert,
ImageKind,
OPS,
RenderingIntentFlag,
shadow,
warn,
} from "../shared/util.js";
function addState(parentState, pattern, checkFn, iterateFn, processFn) {
let state = parentState;
@ -597,11 +604,11 @@ class OperatorList {
return shadow(this, "CHUNK_SIZE_ABOUT", this.CHUNK_SIZE - 5);
}
constructor(intent, streamSink) {
constructor(intent = 0, streamSink) {
this._streamSink = streamSink;
this.fnArray = [];
this.argsArray = [];
if (streamSink && !(intent && intent.startsWith("oplist-"))) {
if (streamSink && !(intent & RenderingIntentFlag.OPLIST)) {
this.optimizer = new QueueOptimizer(this);
} else {
this.optimizer = new NullOptimizer(this);

View File

@ -688,7 +688,6 @@ class WorkerMessageHandler {
sink,
task,
intent: data.intent,
renderInteractiveForms: data.renderInteractiveForms,
annotationStorage: data.annotationStorage,
})
.then(

View File

@ -28,6 +28,7 @@ import {
isSameOrigin,
MissingPDFException,
PasswordException,
RenderingIntentFlag,
setVerbosityLevel,
shadow,
stringToBytes,
@ -514,6 +515,29 @@ function _fetchDocument(worker, source, pdfDataRangeTransport, docId) {
});
}
function getRenderingIntent(intent, { renderForms = false, isOpList = false }) {
let renderingIntent = RenderingIntentFlag.DISPLAY; // Default value.
switch (intent) {
case "any":
renderingIntent = RenderingIntentFlag.ANY;
break;
case "display":
break;
case "print":
renderingIntent = RenderingIntentFlag.PRINT;
break;
default:
warn(`getRenderingIntent - invalid intent: ${intent}`);
}
if (renderForms) {
renderingIntent += RenderingIntentFlag.ANNOTATION_FORMS;
}
if (isOpList) {
renderingIntent += RenderingIntentFlag.OPLIST;
}
return renderingIntent;
}
/**
* @typedef {Object} OnProgressParameters
* @property {number} loaded - Currently loaded number of bytes.
@ -1120,8 +1144,8 @@ class PDFDocumentProxy {
*
* @typedef {Object} GetAnnotationsParameters
* @property {string} [intent] - Determines the annotations that are fetched,
* can be either 'display' (viewable annotations) or 'print' (printable
* annotations). If the parameter is omitted, all annotations are fetched.
* can be 'display' (viewable annotations), 'print' (printable annotations),
* or 'any' (all annotations). The default value is 'display'.
*/
/**
@ -1131,8 +1155,8 @@ class PDFDocumentProxy {
* @property {Object} canvasContext - A 2D context of a DOM Canvas object.
* @property {PageViewport} viewport - Rendering viewport obtained by calling
* the `PDFPageProxy.getViewport` method.
* @property {string} [intent] - Rendering intent, can be 'display' or 'print'.
* The default value is 'display'.
* @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`.
@ -1161,8 +1185,8 @@ class PDFDocumentProxy {
* Page getOperatorList parameters.
*
* @typedef {Object} GetOperatorListParameters
* @property {string} [intent] - Rendering intent, can be 'display' or 'print'.
* The default value is 'display'.
* @property {string} [intent] - Rendering intent, can be 'display', 'print',
* or 'any'. The default value is 'display'.
*/
/**
@ -1276,9 +1300,8 @@ class PDFPageProxy {
* @returns {Promise<Array<any>>} A promise that is resolved with an
* {Array} of the annotation objects.
*/
getAnnotations({ intent = null } = {}) {
const renderingIntent =
intent === "display" || intent === "print" ? intent : null;
getAnnotations({ intent = "display" } = {}) {
const renderingIntent = getRenderingIntent(intent, {});
if (
!this._annotationsPromise ||
@ -1336,7 +1359,9 @@ class PDFPageProxy {
this._stats.time("Overall");
}
const renderingIntent = intent === "print" ? "print" : "display";
const renderingIntent = getRenderingIntent(intent, {
renderForms: renderInteractiveForms === true,
});
// If there was a pending destroy, cancel it so no cleanup happens during
// this call to render.
this.pendingCleanup = false;
@ -1380,7 +1405,6 @@ class PDFPageProxy {
this._pumpOperatorList({
pageIndex: this._pageIndex,
intent: renderingIntent,
renderInteractiveForms: renderInteractiveForms === true,
annotationStorage,
});
}
@ -1390,7 +1414,10 @@ class PDFPageProxy {
// Attempt to reduce memory usage during *printing*, by always running
// cleanup once rendering has finished (regardless of cleanupAfterRender).
if (this.cleanupAfterRender || renderingIntent === "print") {
if (
this.cleanupAfterRender ||
renderingIntent & RenderingIntentFlag.PRINT
) {
this.pendingCleanup = true;
}
this._tryCleanup();
@ -1426,7 +1453,7 @@ class PDFPageProxy {
operatorList: intentState.operatorList,
pageIndex: this._pageIndex,
canvasFactory: canvasFactoryInstance,
useRequestAnimationFrame: renderingIntent !== "print",
useRequestAnimationFrame: !(renderingIntent & RenderingIntentFlag.PRINT),
pdfBug: this._pdfBug,
});
@ -1471,9 +1498,7 @@ class PDFPageProxy {
}
}
const renderingIntent = `oplist-${
intent === "print" ? "print" : "display"
}`;
const renderingIntent = getRenderingIntent(intent, { isOpList: true });
let intentState = this._intentStates.get(renderingIntent);
if (!intentState) {
intentState = Object.create(null);
@ -1588,7 +1613,7 @@ class PDFPageProxy {
force: true,
});
if (intent.startsWith("oplist-")) {
if (intent & RenderingIntentFlag.OPLIST) {
// Avoid errors below, since the renderTasks are just stubs.
continue;
}

View File

@ -18,6 +18,14 @@ import "./compatibility.js";
const IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
const FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
const RenderingIntentFlag = {
ANY: 0x01,
DISPLAY: 0x02,
PRINT: 0x04,
ANNOTATION_FORMS: 0x20,
OPLIST: 0x100,
};
// Permission flags from Table 22, Section 7.6.3.2 of the PDF specification.
const PermissionFlag = {
PRINT: 0x04,
@ -1033,6 +1041,7 @@ export {
PasswordResponses,
PermissionFlag,
removeNullCharacters,
RenderingIntentFlag,
setVerbosityLevel,
shadow,
StreamType,

View File

@ -1443,6 +1443,12 @@ describe("api", function () {
expect(data.length).toEqual(4);
});
const anyPromise = page
.getAnnotations({ intent: "any" })
.then(function (data) {
expect(data.length).toEqual(4);
});
const displayPromise = page
.getAnnotations({ intent: "display" })
.then(function (data) {
@ -1455,7 +1461,12 @@ describe("api", function () {
expect(data.length).toEqual(4);
});
await Promise.all([defaultPromise, displayPromise, printPromise]);
await Promise.all([
defaultPromise,
anyPromise,
displayPromise,
printPromise,
]);
});
it("gets annotations containing relative URLs (bug 766086)", async function () {