diff --git a/src/pdf.js b/src/pdf.js index 59a2ce0d48e2c3..c185a67de5b79d 100644 --- a/src/pdf.js +++ b/src/pdf.js @@ -23,6 +23,7 @@ import { isValidFetchUrl, LinkTarget, loadScript, + PageViewport, PDFDateString, RenderingCancelledException, } from "./display/display_utils.js"; @@ -135,6 +136,7 @@ export { isPdfFile, LinkTarget, loadScript, + PageViewport, PDFDateString, RenderingCancelledException, // From "./display/api.js": diff --git a/web/firefox_print_service.js b/web/firefox_print_service.js index 2008f7dd3381ad..7829bad66544cc 100644 --- a/web/firefox_print_service.js +++ b/web/firefox_print_service.js @@ -14,6 +14,7 @@ */ import { RenderingCancelledException, shadow } from "pdfjs-lib"; +import { getXfaHtmlForPrinting } from "./ui_utils.js"; import { PDFPrintServiceFactory } from "./app.js"; // Creates a placeholder with div and canvas with right size for the page. @@ -33,6 +34,7 @@ function composePage( canvas.height = Math.floor(size.height * PRINT_UNITS); const canvasWrapper = document.createElement("div"); + canvasWrapper.setAttribute("class", "printedPage"); canvasWrapper.appendChild(canvas); printContainer.appendChild(canvasWrapper); @@ -130,6 +132,11 @@ FirefoxPrintService.prototype = { const body = document.querySelector("body"); body.setAttribute("data-pdfjsprinting", true); + if (pdfDocument.isPureXfa) { + getXfaHtmlForPrinting(printContainer, pdfDocument); + return; + } + for (let i = 0, ii = pagesOverview.length; i < ii; ++i) { composePage( pdfDocument, diff --git a/web/pdf_print_service.js b/web/pdf_print_service.js index f24b66ab3fee8f..a92c000cc9444b 100644 --- a/web/pdf_print_service.js +++ b/web/pdf_print_service.js @@ -14,6 +14,7 @@ */ import { PDFPrintServiceFactory, PDFViewerApplication } from "./app.js"; +import { getXfaHtmlForPrinting } from "./ui_utils.js"; import { viewerCompatibilityParams } from "./viewer_compatibility.js"; let activeService = null; @@ -139,6 +140,11 @@ PDFPrintService.prototype = { }, renderPages() { + if (this.pdfDocument.isPureXfa) { + getXfaHtmlForPrinting(this.printContainer, this.pdfDocument); + return Promise.resolve(); + } + const pageCount = this.pagesOverview.length; const renderNextPage = (resolve, reject) => { this.throwIfInactive(); @@ -157,8 +163,12 @@ PDFPrintService.prototype = { this._printResolution, this._optionalContentConfigPromise ) - .then(this.useRenderedPage.bind(this)) - .then(function () { + .then(() => { + if (!this.pdfDocument.isPureXfa) { + this.useRenderedPage.bind(this); + } + }) + .then(() => { renderNextPage(resolve, reject); }, reject); }; @@ -181,6 +191,7 @@ PDFPrintService.prototype = { } const wrapper = document.createElement("div"); + wrapper.setAttribute("class", "printedPage"); wrapper.appendChild(img); this.printContainer.appendChild(wrapper); diff --git a/web/ui_utils.js b/web/ui_utils.js index d9af9235b76461..c6e9742ff33484 100644 --- a/web/ui_utils.js +++ b/web/ui_utils.js @@ -13,6 +13,9 @@ * limitations under the License. */ +import { DefaultXfaLayerFactory } from "./xfa_layer_builder.js"; +import { PageViewport } from "pdfjs-lib"; + const CSS_UNITS = 96.0 / 72.0; const DEFAULT_SCALE_VALUE = "auto"; const DEFAULT_SCALE = 1.0; @@ -994,6 +997,29 @@ function apiPageModeToSidebarView(mode) { return SidebarView.NONE; // Default value. } +function getXfaHtmlForPrinting(printContainer, pdfDocument) { + const xfaHtml = pdfDocument.allXfaHtml; + const factory = new DefaultXfaLayerFactory(); + const scale = Math.round(CSS_UNITS * 100) / 100; + for (const xfaPage of xfaHtml.children) { + const page = document.createElement("div"); + page.setAttribute("class", "xfaPrintedPage"); + printContainer.appendChild(page); + + const { width, height } = xfaPage.attributes.style; + const viewBox = [0, 0, parseInt(width), parseInt(height)]; + const viewport = new PageViewport({ viewBox, scale, rotation: 0 }); + + const builder = factory.createXfaLayerBuilder( + page, + null, + pdfDocument.annotationStorage, + xfaPage + ); + builder.render(viewport, "print"); + } +} + export { animationStarted, apiPageLayoutToSpreadMode, @@ -1010,6 +1036,7 @@ export { getOutputScale, getPageSizeInches, getVisibleElements, + getXfaHtmlForPrinting, isPortraitOrientation, isValidRotation, isValidScrollMode, diff --git a/web/viewer.css b/web/viewer.css index c5a933a812684d..2f42449995845c 100644 --- a/web/viewer.css +++ b/web/viewer.css @@ -1772,7 +1772,8 @@ html[dir="rtl"] #documentPropertiesOverlay .row > * { .toolbar, #loadingBox, #errorWrapper, - .textLayer { + .textLayer, + .canvasWrapper { display: none; } #viewerContainer { @@ -1816,7 +1817,7 @@ html[dir="rtl"] #documentPropertiesOverlay .row > * { height: 100%; } /* wrapper around (scaled) print canvas elements */ - #printContainer > div { + #printContainer > .printedPage { page-break-after: always; page-break-inside: avoid; @@ -1829,8 +1830,17 @@ html[dir="rtl"] #documentPropertiesOverlay .row > * { justify-content: center; align-items: center; } - #printContainer canvas, - #printContainer img { + + #printContainer > .xfaPrintedPage { + page-break-after: always; + page-break-inside: avoid; + width: 100%; + height: 100%; + position: relative; + } + + .printedPage canvas, + .printedPage img { /* The intrinsic canvas / image size will make sure that we fit the page. */ max-width: 100%; max-height: 100%; diff --git a/web/xfa_layer_builder.css b/web/xfa_layer_builder.css index a5e01bdf7455cd..19a897660efd86 100644 --- a/web/xfa_layer_builder.css +++ b/web/xfa_layer_builder.css @@ -262,3 +262,10 @@ .xfaTable .xfaRlRow > div { flex: 1; } + +@media print { + .xfaTextfield, + .xfaSelect { + background-color: transparent; + } +} diff --git a/web/xfa_layer_builder.js b/web/xfa_layer_builder.js index e7d2ae2ea5c0dd..9993c61225a28c 100644 --- a/web/xfa_layer_builder.js +++ b/web/xfa_layer_builder.js @@ -26,9 +26,10 @@ class XfaLayerBuilder { /** * @param {XfaLayerBuilderOptions} options */ - constructor({ pageDiv, pdfPage, annotationStorage }) { + constructor({ pageDiv, pdfPage, xfaHtml, annotationStorage }) { this.pageDiv = pageDiv; this.pdfPage = pdfPage; + this.xfaHtml = xfaHtml; this.annotationStorage = annotationStorage; this.div = null; @@ -42,34 +43,54 @@ class XfaLayerBuilder { * annotations is complete. */ render(viewport, intent = "display") { - return this.pdfPage - .getXfa() - .then(xfa => { - if (this._cancelled) { - return; - } - const parameters = { - viewport: viewport.clone({ dontFlip: true }), - div: this.div, - xfa, - page: this.pdfPage, - annotationStorage: this.annotationStorage, - }; + if (intent === "display") { + return this.pdfPage + .getXfa() + .then(xfa => { + if (this._cancelled) { + return; + } + const parameters = { + viewport: viewport.clone({ dontFlip: true }), + div: this.div, + xfa, + page: this.pdfPage, + annotationStorage: this.annotationStorage, + }; - if (this.div) { - XfaLayer.update(parameters); - } else { - // Create an xfa layer div and render the form - this.div = document.createElement("div"); - this.pageDiv.appendChild(this.div); - parameters.div = this.div; + if (this.div) { + XfaLayer.update(parameters); + } else { + // Create an xfa layer div and render the form + this.div = document.createElement("div"); + this.pageDiv.appendChild(this.div); + parameters.div = this.div; - XfaLayer.render(parameters); - } - }) - .catch(error => { - console.error(error); - }); + XfaLayer.render(parameters); + } + }) + .catch(error => { + console.error(error); + }); + } + + // intent === "print". + const parameters = { + viewport: viewport.clone({ dontFlip: true }), + div: this.div, + xfa: this.xfaHtml, + page: null, + annotationStorage: this.annotationStorage, + }; + + // Create an xfa layer div and render the form + const div = document.createElement("div"); + this.pageDiv.appendChild(div); + parameters.div = div; + + XfaLayer.render(parameters); + + return null; } cancel() { @@ -92,12 +113,19 @@ class DefaultXfaLayerFactory { * @param {HTMLDivElement} pageDiv * @param {PDFPage} pdfPage * @param {AnnotationStorage} [annotationStorage] + * @param {Object} [xfaHtml] */ - createXfaLayerBuilder(pageDiv, pdfPage, annotationStorage = null) { + createXfaLayerBuilder( + pageDiv, + pdfPage, + annotationStorage = null, + xfaHtml = null + ) { return new XfaLayerBuilder({ pageDiv, pdfPage, annotationStorage, + xfaHtml, }); } }