[api-minor] Re-factor the *internal* renderingIntent, and change the default intent
value in the PDFPageProxy.getAnnotations
method
With the changes made in PR 13746 the *internal* renderingIntent handling became somewhat "messy", since we're now having to do string-matching in various spots in order to handle the "oplist"-intent correctly. Hence this patch, which implements the idea from PR 13746 to convert the `intent`-strings, used in various API-methods, into an *internal* renderingIntent that's implemented using a bit-field instead. *Please note:* This part of the patch, in itself, does *not* change the public API (but see below). This patch is tagged `api-minor` for the following reasons: 1. It changes the *default* value for the `intent` parameter, in the `PDFPageProxy.getAnnotations` method, to "display" in order to be consistent across the API. 2. In order to get *all* annotations, with the `PDFPageProxy.getAnnotations` method, you now need to explicitly set "any" as the `intent` parameter. 3. The `PDFPageProxy.getOperatorList` method will now also support the new "any" intent, to allow accessing the operatorList of all annotations (limited to those types that have one). 4. Finally, for consistency across the API, the `PDFPageProxy.render` method also support the new "any" intent (although I'm not sure how useful that'll be). Points 1 and 2 above are the significant, and thus breaking, changes in *default* behaviour here. However, unfortunately I cannot see a good way to improve the overall API while also keeping `PDFPageProxy.getAnnotations` unchanged.
This commit is contained in:
parent
849bab973c
commit
47f94235ab
@ -25,6 +25,7 @@ import {
|
|||||||
isString,
|
isString,
|
||||||
OPS,
|
OPS,
|
||||||
PageActionEventType,
|
PageActionEventType,
|
||||||
|
RenderingIntentFlag,
|
||||||
shadow,
|
shadow,
|
||||||
stringToBytes,
|
stringToBytes,
|
||||||
stringToPDFString,
|
stringToPDFString,
|
||||||
@ -383,19 +384,18 @@ class Page {
|
|||||||
pageOpList.flush(true);
|
pageOpList.flush(true);
|
||||||
return { length: pageOpList.totalLength };
|
return { length: pageOpList.totalLength };
|
||||||
}
|
}
|
||||||
|
const intentAny = !!(intent & RenderingIntentFlag.ANY),
|
||||||
|
intentDisplay = !!(intent & RenderingIntentFlag.DISPLAY),
|
||||||
|
intentPrint = !!(intent & RenderingIntentFlag.PRINT);
|
||||||
|
|
||||||
// Collect the operator list promises for the annotations. Each promise
|
// Collect the operator list promises for the annotations. Each promise
|
||||||
// is resolved with the complete operator list for a single annotation.
|
// is resolved with the complete operator list for a single annotation.
|
||||||
const annotationIntent = intent.startsWith("oplist-")
|
|
||||||
? intent.split("-")[1]
|
|
||||||
: intent;
|
|
||||||
const opListPromises = [];
|
const opListPromises = [];
|
||||||
for (const annotation of annotations) {
|
for (const annotation of annotations) {
|
||||||
if (
|
if (
|
||||||
(annotationIntent === "display" &&
|
intentAny ||
|
||||||
annotation.mustBeViewed(annotationStorage)) ||
|
(intentDisplay && annotation.mustBeViewed(annotationStorage)) ||
|
||||||
(annotationIntent === "print" &&
|
(intentPrint && annotation.mustBePrinted(annotationStorage))
|
||||||
annotation.mustBePrinted(annotationStorage))
|
|
||||||
) {
|
) {
|
||||||
opListPromises.push(
|
opListPromises.push(
|
||||||
annotation
|
annotation
|
||||||
@ -496,15 +496,23 @@ class Page {
|
|||||||
getAnnotationsData(intent) {
|
getAnnotationsData(intent) {
|
||||||
return this._parsedAnnotations.then(function (annotations) {
|
return this._parsedAnnotations.then(function (annotations) {
|
||||||
const annotationsData = [];
|
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
|
// Get the annotation even if it's hidden because
|
||||||
// JS can change its display.
|
// JS can change its display.
|
||||||
if (
|
if (
|
||||||
!intent ||
|
intentAny ||
|
||||||
(intent === "display" && annotations[i].viewable) ||
|
(intentDisplay && annotation.viewable) ||
|
||||||
(intent === "print" && annotations[i].printable)
|
(intentPrint && annotation.printable)
|
||||||
) {
|
) {
|
||||||
annotationsData.push(annotations[i].data);
|
annotationsData.push(annotation.data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return annotationsData;
|
return annotationsData;
|
||||||
|
@ -13,7 +13,14 @@
|
|||||||
* limitations under the License.
|
* 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) {
|
function addState(parentState, pattern, checkFn, iterateFn, processFn) {
|
||||||
let state = parentState;
|
let state = parentState;
|
||||||
@ -597,11 +604,11 @@ class OperatorList {
|
|||||||
return shadow(this, "CHUNK_SIZE_ABOUT", this.CHUNK_SIZE - 5);
|
return shadow(this, "CHUNK_SIZE_ABOUT", this.CHUNK_SIZE - 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(intent, streamSink) {
|
constructor(intent = 0, streamSink) {
|
||||||
this._streamSink = streamSink;
|
this._streamSink = streamSink;
|
||||||
this.fnArray = [];
|
this.fnArray = [];
|
||||||
this.argsArray = [];
|
this.argsArray = [];
|
||||||
if (streamSink && !(intent && intent.startsWith("oplist-"))) {
|
if (streamSink && !(intent & RenderingIntentFlag.OPLIST)) {
|
||||||
this.optimizer = new QueueOptimizer(this);
|
this.optimizer = new QueueOptimizer(this);
|
||||||
} else {
|
} else {
|
||||||
this.optimizer = new NullOptimizer(this);
|
this.optimizer = new NullOptimizer(this);
|
||||||
|
@ -28,6 +28,7 @@ import {
|
|||||||
isSameOrigin,
|
isSameOrigin,
|
||||||
MissingPDFException,
|
MissingPDFException,
|
||||||
PasswordException,
|
PasswordException,
|
||||||
|
RenderingIntentFlag,
|
||||||
setVerbosityLevel,
|
setVerbosityLevel,
|
||||||
shadow,
|
shadow,
|
||||||
stringToBytes,
|
stringToBytes,
|
||||||
@ -514,6 +515,26 @@ function _fetchDocument(worker, source, pdfDataRangeTransport, docId) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getRenderingIntent(intent, { 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 (isOpList) {
|
||||||
|
renderingIntent += RenderingIntentFlag.OPLIST;
|
||||||
|
}
|
||||||
|
return renderingIntent;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} OnProgressParameters
|
* @typedef {Object} OnProgressParameters
|
||||||
* @property {number} loaded - Currently loaded number of bytes.
|
* @property {number} loaded - Currently loaded number of bytes.
|
||||||
@ -1120,8 +1141,8 @@ class PDFDocumentProxy {
|
|||||||
*
|
*
|
||||||
* @typedef {Object} GetAnnotationsParameters
|
* @typedef {Object} GetAnnotationsParameters
|
||||||
* @property {string} [intent] - Determines the annotations that are fetched,
|
* @property {string} [intent] - Determines the annotations that are fetched,
|
||||||
* can be either 'display' (viewable annotations) or 'print' (printable
|
* can be 'display' (viewable annotations), 'print' (printable annotations),
|
||||||
* annotations). If the parameter is omitted, all annotations are fetched.
|
* or 'any' (all annotations). The default value is 'display'.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1131,8 +1152,8 @@ class PDFDocumentProxy {
|
|||||||
* @property {Object} canvasContext - A 2D context of a DOM Canvas object.
|
* @property {Object} canvasContext - A 2D context of a DOM Canvas object.
|
||||||
* @property {PageViewport} viewport - Rendering viewport obtained by calling
|
* @property {PageViewport} viewport - Rendering viewport obtained by calling
|
||||||
* the `PDFPageProxy.getViewport` method.
|
* the `PDFPageProxy.getViewport` method.
|
||||||
* @property {string} [intent] - Rendering intent, can be 'display' or 'print'.
|
* @property {string} [intent] - Rendering intent, can be 'display', 'print',
|
||||||
* The default value is 'display'.
|
* or 'any'. The default value is 'display'.
|
||||||
* @property {boolean} [renderInteractiveForms] - Whether or not interactive
|
* @property {boolean} [renderInteractiveForms] - Whether or not interactive
|
||||||
* form elements are rendered in the display layer. If so, we do not render
|
* 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`.
|
* them on the canvas as well. The default value is `false`.
|
||||||
@ -1161,8 +1182,8 @@ class PDFDocumentProxy {
|
|||||||
* Page getOperatorList parameters.
|
* Page getOperatorList parameters.
|
||||||
*
|
*
|
||||||
* @typedef {Object} GetOperatorListParameters
|
* @typedef {Object} GetOperatorListParameters
|
||||||
* @property {string} [intent] - Rendering intent, can be 'display' or 'print'.
|
* @property {string} [intent] - Rendering intent, can be 'display', 'print',
|
||||||
* The default value is 'display'.
|
* or 'any'. The default value is 'display'.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1276,9 +1297,8 @@ class PDFPageProxy {
|
|||||||
* @returns {Promise<Array<any>>} A promise that is resolved with an
|
* @returns {Promise<Array<any>>} A promise that is resolved with an
|
||||||
* {Array} of the annotation objects.
|
* {Array} of the annotation objects.
|
||||||
*/
|
*/
|
||||||
getAnnotations({ intent = null } = {}) {
|
getAnnotations({ intent = "display" } = {}) {
|
||||||
const renderingIntent =
|
const renderingIntent = getRenderingIntent(intent, {});
|
||||||
intent === "display" || intent === "print" ? intent : null;
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!this._annotationsPromise ||
|
!this._annotationsPromise ||
|
||||||
@ -1336,7 +1356,7 @@ class PDFPageProxy {
|
|||||||
this._stats.time("Overall");
|
this._stats.time("Overall");
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderingIntent = intent === "print" ? "print" : "display";
|
const renderingIntent = getRenderingIntent(intent, {});
|
||||||
// If there was a pending destroy, cancel it so no cleanup happens during
|
// If there was a pending destroy, cancel it so no cleanup happens during
|
||||||
// this call to render.
|
// this call to render.
|
||||||
this.pendingCleanup = false;
|
this.pendingCleanup = false;
|
||||||
@ -1390,7 +1410,10 @@ class PDFPageProxy {
|
|||||||
|
|
||||||
// Attempt to reduce memory usage during *printing*, by always running
|
// Attempt to reduce memory usage during *printing*, by always running
|
||||||
// cleanup once rendering has finished (regardless of cleanupAfterRender).
|
// cleanup once rendering has finished (regardless of cleanupAfterRender).
|
||||||
if (this.cleanupAfterRender || renderingIntent === "print") {
|
if (
|
||||||
|
this.cleanupAfterRender ||
|
||||||
|
renderingIntent & RenderingIntentFlag.PRINT
|
||||||
|
) {
|
||||||
this.pendingCleanup = true;
|
this.pendingCleanup = true;
|
||||||
}
|
}
|
||||||
this._tryCleanup();
|
this._tryCleanup();
|
||||||
@ -1426,7 +1449,7 @@ class PDFPageProxy {
|
|||||||
operatorList: intentState.operatorList,
|
operatorList: intentState.operatorList,
|
||||||
pageIndex: this._pageIndex,
|
pageIndex: this._pageIndex,
|
||||||
canvasFactory: canvasFactoryInstance,
|
canvasFactory: canvasFactoryInstance,
|
||||||
useRequestAnimationFrame: renderingIntent !== "print",
|
useRequestAnimationFrame: !(renderingIntent & RenderingIntentFlag.PRINT),
|
||||||
pdfBug: this._pdfBug,
|
pdfBug: this._pdfBug,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1471,9 +1494,7 @@ class PDFPageProxy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderingIntent = `oplist-${
|
const renderingIntent = getRenderingIntent(intent, { isOpList: true });
|
||||||
intent === "print" ? "print" : "display"
|
|
||||||
}`;
|
|
||||||
let intentState = this._intentStates.get(renderingIntent);
|
let intentState = this._intentStates.get(renderingIntent);
|
||||||
if (!intentState) {
|
if (!intentState) {
|
||||||
intentState = Object.create(null);
|
intentState = Object.create(null);
|
||||||
@ -1588,7 +1609,7 @@ class PDFPageProxy {
|
|||||||
force: true,
|
force: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (intent.startsWith("oplist-")) {
|
if (intent & RenderingIntentFlag.OPLIST) {
|
||||||
// Avoid errors below, since the renderTasks are just stubs.
|
// Avoid errors below, since the renderTasks are just stubs.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,13 @@ import "./compatibility.js";
|
|||||||
const IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
|
const IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
|
||||||
const FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
|
const FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
|
||||||
|
|
||||||
|
const RenderingIntentFlag = {
|
||||||
|
ANY: 0x01,
|
||||||
|
DISPLAY: 0x02,
|
||||||
|
PRINT: 0x04,
|
||||||
|
OPLIST: 0x100,
|
||||||
|
};
|
||||||
|
|
||||||
// Permission flags from Table 22, Section 7.6.3.2 of the PDF specification.
|
// Permission flags from Table 22, Section 7.6.3.2 of the PDF specification.
|
||||||
const PermissionFlag = {
|
const PermissionFlag = {
|
||||||
PRINT: 0x04,
|
PRINT: 0x04,
|
||||||
@ -1033,6 +1040,7 @@ export {
|
|||||||
PasswordResponses,
|
PasswordResponses,
|
||||||
PermissionFlag,
|
PermissionFlag,
|
||||||
removeNullCharacters,
|
removeNullCharacters,
|
||||||
|
RenderingIntentFlag,
|
||||||
setVerbosityLevel,
|
setVerbosityLevel,
|
||||||
shadow,
|
shadow,
|
||||||
StreamType,
|
StreamType,
|
||||||
|
@ -1443,6 +1443,12 @@ describe("api", function () {
|
|||||||
expect(data.length).toEqual(4);
|
expect(data.length).toEqual(4);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const anyPromise = page
|
||||||
|
.getAnnotations({ intent: "any" })
|
||||||
|
.then(function (data) {
|
||||||
|
expect(data.length).toEqual(4);
|
||||||
|
});
|
||||||
|
|
||||||
const displayPromise = page
|
const displayPromise = page
|
||||||
.getAnnotations({ intent: "display" })
|
.getAnnotations({ intent: "display" })
|
||||||
.then(function (data) {
|
.then(function (data) {
|
||||||
@ -1455,7 +1461,12 @@ describe("api", function () {
|
|||||||
expect(data.length).toEqual(4);
|
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 () {
|
it("gets annotations containing relative URLs (bug 766086)", async function () {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user