1
0
Fork 0
mirror of https://github.com/mozilla/pdf.js.git synced 2025-04-20 15:18:08 +02:00

[api-minor] Introduce a PrintAnnotationStorage with *frozen* serializable data

Given that printing is triggered *synchronously* in browsers, it's thus possible for scripting (in PDF documents) to modify the Annotation-data while printing is currently ongoing.
To work-around that we add a new printing-specific `AnnotationStorage`, where the serializable data is *frozen* upon initialization, which the viewer can thus create/utilize during printing.
This commit is contained in:
Jonas Jenwald 2022-06-13 13:35:58 +02:00
parent c5dc082da4
commit 1cc7cecc7b
6 changed files with 196 additions and 41 deletions

View file

@ -254,6 +254,7 @@ const PDFViewerApplication = {
_wheelUnusedTicks: 0,
_idleCallbacks: new Set(),
_PDFBug: null,
_printAnnotationStoragePromise: null,
// Called once when the document is loaded.
async initialize(appConfig) {
@ -1790,9 +1791,14 @@ const PDFViewerApplication = {
},
beforePrint() {
// Given that the "beforeprint" browser event is synchronous, we
// unfortunately cannot await the scripting event dispatching here.
this.pdfScriptingManager.dispatchWillPrint();
this._printAnnotationStoragePromise = this.pdfScriptingManager
.dispatchWillPrint()
.catch(() => {
/* Avoid breaking printing; ignoring errors. */
})
.then(() => {
return this.pdfDocument?.annotationStorage.print;
});
if (this.printService) {
// There is no way to suppress beforePrint/afterPrint events,
@ -1830,6 +1836,7 @@ const PDFViewerApplication = {
printContainer,
printResolution,
optionalContentConfigPromise,
this._printAnnotationStoragePromise,
this.l10n
);
this.printService = printService;
@ -1843,9 +1850,12 @@ const PDFViewerApplication = {
},
afterPrint() {
// Given that the "afterprint" browser event is synchronous, we
// unfortunately cannot await the scripting event dispatching here.
this.pdfScriptingManager.dispatchDidPrint();
if (this._printAnnotationStoragePromise) {
this._printAnnotationStoragePromise.then(() => {
this.pdfScriptingManager.dispatchDidPrint();
});
this._printAnnotationStoragePromise = null;
}
if (this.printService) {
this.printService.destroy();

View file

@ -29,7 +29,8 @@ function composePage(
size,
printContainer,
printResolution,
optionalContentConfigPromise
optionalContentConfigPromise,
printAnnotationStoragePromise
) {
const canvas = document.createElement("canvas");
@ -61,9 +62,12 @@ function composePage(
ctx.restore();
let thisRenderTask = null;
pdfDocument
.getPage(pageNumber)
.then(function (pdfPage) {
Promise.all([
pdfDocument.getPage(pageNumber),
printAnnotationStoragePromise,
])
.then(function ([pdfPage, printAnnotationStorage]) {
if (currentRenderTask) {
currentRenderTask.cancel();
currentRenderTask = null;
@ -75,6 +79,7 @@ function composePage(
intent: "print",
annotationMode: AnnotationMode.ENABLE_STORAGE,
optionalContentConfigPromise,
printAnnotationStorage,
};
currentRenderTask = thisRenderTask = pdfPage.render(renderContext);
return thisRenderTask.promise;
@ -114,7 +119,8 @@ function FirefoxPrintService(
pagesOverview,
printContainer,
printResolution,
optionalContentConfigPromise = null
optionalContentConfigPromise = null,
printAnnotationStoragePromise = null
) {
this.pdfDocument = pdfDocument;
this.pagesOverview = pagesOverview;
@ -122,6 +128,8 @@ function FirefoxPrintService(
this._printResolution = printResolution || 150;
this._optionalContentConfigPromise =
optionalContentConfigPromise || pdfDocument.getOptionalContentConfig();
this._optionalContentConfigPromise =
printAnnotationStoragePromise || Promise.resolve();
}
FirefoxPrintService.prototype = {
@ -132,6 +140,7 @@ FirefoxPrintService.prototype = {
printContainer,
_printResolution,
_optionalContentConfigPromise,
_printAnnotationStoragePromise,
} = this;
const body = document.querySelector("body");
@ -149,7 +158,8 @@ FirefoxPrintService.prototype = {
pagesOverview[i],
printContainer,
_printResolution,
_optionalContentConfigPromise
_optionalContentConfigPromise,
_printAnnotationStoragePromise
);
}
},
@ -175,14 +185,16 @@ PDFPrintServiceFactory.instance = {
pagesOverview,
printContainer,
printResolution,
optionalContentConfigPromise
optionalContentConfigPromise,
printAnnotationStoragePromise
) {
return new FirefoxPrintService(
pdfDocument,
pagesOverview,
printContainer,
printResolution,
optionalContentConfigPromise
optionalContentConfigPromise,
printAnnotationStoragePromise
);
},
};

View file

@ -29,7 +29,8 @@ function renderPage(
pageNumber,
size,
printResolution,
optionalContentConfigPromise
optionalContentConfigPromise,
printAnnotationStoragePromise
) {
const scratchCanvas = activeService.scratchCanvas;
@ -44,7 +45,10 @@ function renderPage(
ctx.fillRect(0, 0, scratchCanvas.width, scratchCanvas.height);
ctx.restore();
return pdfDocument.getPage(pageNumber).then(function (pdfPage) {
return Promise.all([
pdfDocument.getPage(pageNumber),
printAnnotationStoragePromise,
]).then(function ([pdfPage, printAnnotationStorage]) {
const renderContext = {
canvasContext: ctx,
transform: [PRINT_UNITS, 0, 0, PRINT_UNITS, 0, 0],
@ -52,6 +56,7 @@ function renderPage(
intent: "print",
annotationMode: AnnotationMode.ENABLE_STORAGE,
optionalContentConfigPromise,
printAnnotationStorage,
};
return pdfPage.render(renderContext).promise;
});
@ -63,6 +68,7 @@ function PDFPrintService(
printContainer,
printResolution,
optionalContentConfigPromise = null,
printAnnotationStoragePromise = null,
l10n
) {
this.pdfDocument = pdfDocument;
@ -71,6 +77,8 @@ function PDFPrintService(
this._printResolution = printResolution || 150;
this._optionalContentConfigPromise =
optionalContentConfigPromise || pdfDocument.getOptionalContentConfig();
this._printAnnotationStoragePromise =
printAnnotationStoragePromise || Promise.resolve();
this.l10n = l10n;
this.currentPage = -1;
// The temporary canvas where renderPage paints one page at a time.
@ -160,7 +168,8 @@ PDFPrintService.prototype = {
/* pageNumber = */ index + 1,
this.pagesOverview[index],
this._printResolution,
this._optionalContentConfigPromise
this._optionalContentConfigPromise,
this._printAnnotationStoragePromise
)
.then(this.useRenderedPage.bind(this))
.then(function () {
@ -359,6 +368,7 @@ PDFPrintServiceFactory.instance = {
printContainer,
printResolution,
optionalContentConfigPromise,
printAnnotationStoragePromise,
l10n
) {
if (activeService) {
@ -370,6 +380,7 @@ PDFPrintServiceFactory.instance = {
printContainer,
printResolution,
optionalContentConfigPromise,
printAnnotationStoragePromise,
l10n
);
return activeService;