From eb94d71b712e9ce39741df13c7561709d4e31896 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Fri, 18 Jun 2021 11:48:29 +0200 Subject: [PATCH 1/3] Move the `getXfaHtmlForPrinting` helper function to its own file (PR 13411 follow-up) The `web/ui_utils.js` file should be usable from basically anywhere in the `web/`-folder, hence it should ideally not have any dependecies on its own and particularily *not* onces that pull in entire (large) factories. --- web/firefox_print_service.js | 2 +- web/pdf_print_service.js | 2 +- web/print_utils.js | 42 ++++++++++++++++++++++++++++++++++++ web/ui_utils.js | 26 ---------------------- 4 files changed, 44 insertions(+), 28 deletions(-) create mode 100644 web/print_utils.js diff --git a/web/firefox_print_service.js b/web/firefox_print_service.js index d4b1e16cd..5fb6dba4e 100644 --- a/web/firefox_print_service.js +++ b/web/firefox_print_service.js @@ -14,7 +14,7 @@ */ import { RenderingCancelledException, shadow } from "pdfjs-lib"; -import { getXfaHtmlForPrinting } from "./ui_utils.js"; +import { getXfaHtmlForPrinting } from "./print_utils.js"; import { PDFPrintServiceFactory } from "./app.js"; // Creates a placeholder with div and canvas with right size for the page. diff --git a/web/pdf_print_service.js b/web/pdf_print_service.js index a74ca3374..592607fb3 100644 --- a/web/pdf_print_service.js +++ b/web/pdf_print_service.js @@ -14,7 +14,7 @@ */ import { PDFPrintServiceFactory, PDFViewerApplication } from "./app.js"; -import { getXfaHtmlForPrinting } from "./ui_utils.js"; +import { getXfaHtmlForPrinting } from "./print_utils.js"; import { viewerCompatibilityParams } from "./viewer_compatibility.js"; let activeService = null; diff --git a/web/print_utils.js b/web/print_utils.js new file mode 100644 index 000000000..50725fa99 --- /dev/null +++ b/web/print_utils.js @@ -0,0 +1,42 @@ +/* Copyright 2021 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CSS_UNITS } from "./ui_utils.js"; +import { DefaultXfaLayerFactory } from "./xfa_layer_builder.js"; + +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.className = "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( + /* pageDiv = */ page, + /* pdfPage = */ null, + /* annotationStorage = */ pdfDocument.annotationStorage, + /* xfaHtml = */ xfaPage + ); + builder.render(viewport, "print"); + } +} + +export { getXfaHtmlForPrinting }; diff --git a/web/ui_utils.js b/web/ui_utils.js index e93511211..672c56f69 100644 --- a/web/ui_utils.js +++ b/web/ui_utils.js @@ -13,8 +13,6 @@ * 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; @@ -995,29 +993,6 @@ 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.className = "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, @@ -1034,7 +1009,6 @@ export { getOutputScale, getPageSizeInches, getVisibleElements, - getXfaHtmlForPrinting, isPortraitOrientation, isValidRotation, isValidScrollMode, From 45c1390c4280e3b8ecc2e1fafd700cd09f911c44 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Fri, 18 Jun 2021 11:59:50 +0200 Subject: [PATCH 2/3] Switch the order of the "display"/"print" intent handling in `XfaLayerBuilder.render` Given that the "print"-intent is special, and that we should always fallback to the "display"-intent, let's ensure that the code actually reflects that. Also, ensure that the method always returns a `Promise` since that's what the documentation says. --- web/xfa_layer_builder.js | 87 ++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 44 deletions(-) diff --git a/web/xfa_layer_builder.js b/web/xfa_layer_builder.js index 99c95c5de..43ffbe917 100644 --- a/web/xfa_layer_builder.js +++ b/web/xfa_layer_builder.js @@ -43,56 +43,55 @@ class XfaLayerBuilder { * annotations is complete. */ render(viewport, intent = "display") { - 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 (intent === "print") { + viewport.dontFlip = true; + const parameters = { + viewport, + div: this.div, + xfa: this.xfaHtml, + page: null, + annotationStorage: this.annotationStorage, + intent, + }; - 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; + // Create an xfa layer div and render the form + const div = document.createElement("div"); + this.pageDiv.appendChild(div); + parameters.div = div; - XfaLayer.render(parameters); - } - }) - .catch(error => { - console.error(error); - }); + XfaLayer.render(parameters); + return Promise.resolve(); } - // intent === "print". - viewport.dontFlip = true; - const parameters = { - viewport, - div: this.div, - xfa: this.xfaHtml, - page: null, - annotationStorage: this.annotationStorage, - intent, - }; + // 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, + }; - // Create an xfa layer div and render the form - const div = document.createElement("div"); - this.pageDiv.appendChild(div); - parameters.div = 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); - - return null; + XfaLayer.render(parameters); + } + }) + .catch(error => { + console.error(error); + }); } cancel() { From 87be43c193bfeb69f8bb13f28b7217ad955e3b30 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Fri, 18 Jun 2021 12:31:58 +0200 Subject: [PATCH 3/3] [api-minor] Add a new `getXfaPageViewport` helper function to support printing This patch provides an overall simpler *and* more consistent way of handling the `viewport` parameter during printing of XFA forms, since it's now again guaranteed to always be an instance of `PageViewport`. Furthermore, for anyone attempting to e.g. implement custom printing of XFA forms this probably cannot hurt either. --- src/display/api.js | 4 +++- src/display/display_utils.js | 15 +++++++++++++++ src/display/xfa_layer.js | 11 ++--------- src/pdf.js | 2 ++ web/print_utils.js | 8 ++++---- web/xfa_layer_builder.js | 4 ++-- 6 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/display/api.js b/src/display/api.js index a27a2b500..2cf8f9ad2 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -743,8 +743,10 @@ class PDFDocumentProxy { } /** + * NOTE: This is (mostly) intended to support printing of XFA forms. + * * @type {Object | null} An object representing a HTML tree structure - * to render the XFA, or `null` when no XFA form exists. + * to render the XFA, or `null` when no XFA form exists. */ get allXfaHtml() { return this._transport._htmlForXfa; diff --git a/src/display/display_utils.js b/src/display/display_utils.js index fbf9a5e69..e4cc62085 100644 --- a/src/display/display_utils.js +++ b/src/display/display_utils.js @@ -606,6 +606,20 @@ class PDFDateString { } } +/** + * NOTE: This is (mostly) intended to support printing of XFA forms. + */ +function getXfaPageViewport(xfaPage, { scale = 1, rotation = 0 }) { + const { width, height } = xfaPage.attributes.style; + const viewBox = [0, 0, parseInt(width), parseInt(height)]; + + return new PageViewport({ + viewBox, + scale, + rotation, + }); +} + export { addLinkAttributes, DEFAULT_LINK_REL, @@ -616,6 +630,7 @@ export { DOMSVGFactory, getFilenameFromUrl, getPdfFilenameFromUrl, + getXfaPageViewport, isDataScheme, isPdfFile, isValidFetchUrl, diff --git a/src/display/xfa_layer.js b/src/display/xfa_layer.js index 5b3e16005..cd068b92d 100644 --- a/src/display/xfa_layer.js +++ b/src/display/xfa_layer.js @@ -13,8 +13,6 @@ * limitations under the License. */ -import { PageViewport } from "./display_utils.js"; - class XfaLayer { static setupStorage(html, fieldId, element, storage, intent) { const storedData = storage.getValue(fieldId, { value: null }); @@ -134,13 +132,8 @@ class XfaLayer { const rootDiv = parameters.div; rootDiv.appendChild(rootHtml); - - let { viewport } = parameters; - if (!(viewport instanceof PageViewport)) { - viewport = new PageViewport(viewport); - } - const coeffs = viewport.transform.join(","); - rootDiv.style.transform = `matrix(${coeffs})`; + const transform = `matrix(${parameters.viewport.transform.join(",")})`; + rootDiv.style.transform = transform; // Set defaults. rootDiv.setAttribute("class", "xfaLayer xfaFont"); diff --git a/src/pdf.js b/src/pdf.js index b5d4d38d1..9a1bfce30 100644 --- a/src/pdf.js +++ b/src/pdf.js @@ -18,6 +18,7 @@ import { addLinkAttributes, getFilenameFromUrl, getPdfFilenameFromUrl, + getXfaPageViewport, isPdfFile, isValidFetchUrl, LinkTarget, @@ -108,6 +109,7 @@ export { loadScript, PDFDateString, RenderingCancelledException, + getXfaPageViewport, // From "./display/api.js": build, getDocument, diff --git a/web/print_utils.js b/web/print_utils.js index 50725fa99..3c1d8c85f 100644 --- a/web/print_utils.js +++ b/web/print_utils.js @@ -15,26 +15,26 @@ import { CSS_UNITS } from "./ui_utils.js"; import { DefaultXfaLayerFactory } from "./xfa_layer_builder.js"; +import { getXfaPageViewport } from "pdfjs-lib"; 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.className = "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( /* pageDiv = */ page, /* pdfPage = */ null, /* annotationStorage = */ pdfDocument.annotationStorage, /* xfaHtml = */ xfaPage ); + const viewport = getXfaPageViewport(xfaPage, { scale }); + builder.render(viewport, "print"); } } diff --git a/web/xfa_layer_builder.js b/web/xfa_layer_builder.js index 43ffbe917..17f891c19 100644 --- a/web/xfa_layer_builder.js +++ b/web/xfa_layer_builder.js @@ -44,9 +44,8 @@ class XfaLayerBuilder { */ render(viewport, intent = "display") { if (intent === "print") { - viewport.dontFlip = true; const parameters = { - viewport, + viewport: viewport.clone({ dontFlip: true }), div: this.div, xfa: this.xfaHtml, page: null, @@ -76,6 +75,7 @@ class XfaLayerBuilder { xfa, page: this.pdfPage, annotationStorage: this.annotationStorage, + intent, }; if (this.div) {