diff --git a/src/display/xfa_layer.js b/src/display/xfa_layer.js index 85d94f860..e6dd96453 100644 --- a/src/display/xfa_layer.js +++ b/src/display/xfa_layer.js @@ -13,6 +13,8 @@ * limitations under the License. */ +import { PageViewport } from "./display_utils.js"; + class XfaLayer { static setupStorage(html, fieldId, element, storage) { const storedData = storage.getValue(fieldId, { value: null }); @@ -100,7 +102,12 @@ class XfaLayer { const rootDiv = parameters.div; rootDiv.appendChild(rootHtml); - const coeffs = parameters.viewport.transform.join(","); + + let { viewport } = parameters; + if (!(viewport instanceof PageViewport)) { + viewport = new PageViewport(viewport); + } + const coeffs = viewport.transform.join(","); rootDiv.style.transform = `matrix(${coeffs})`; // Set defaults. diff --git a/web/firefox_print_service.js b/web/firefox_print_service.js index 2008f7dd3..7829bad66 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 f24b66ab3..f8fc14e15 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,10 @@ PDFPrintService.prototype = { this._printResolution, this._optionalContentConfigPromise ) - .then(this.useRenderedPage.bind(this)) - .then(function () { + .then(() => { + this.useRenderedPage.bind(this); + }) + .then(() => { renderNextPage(resolve, reject); }, reject); }; @@ -181,6 +189,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 d9af9235b..ce2a26dfc 100644 --- a/web/ui_utils.js +++ b/web/ui_utils.js @@ -13,6 +13,8 @@ * limitations under the License. */ +import { DefaultXfaLayerFactory } from "./xfa_layer_builder.js"; + const CSS_UNITS = 96.0 / 72.0; const DEFAULT_SCALE_VALUE = "auto"; const DEFAULT_SCALE = 1.0; @@ -994,6 +996,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 = { viewBox, scale, rotation: 0 }; + + const builder = factory.createXfaLayerBuilder( + page, + null, + pdfDocument.annotationStorage, + xfaPage + ); + builder.render(viewport, "print"); + } +} + export { animationStarted, apiPageLayoutToSpreadMode, @@ -1010,6 +1035,7 @@ export { getOutputScale, getPageSizeInches, getVisibleElements, + getXfaHtmlForPrinting, isPortraitOrientation, isValidRotation, isValidScrollMode, diff --git a/web/viewer.css b/web/viewer.css index c5a933a81..2f4244999 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 a5e01bdf7..19a897660 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 e7d2ae2ea..5ef667749 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,55 @@ 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". + viewport.dontFlip = true; + const parameters = { + viewport, + 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 +114,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, }); } }