Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

XFA - Add support to print XFA forms #13411

Merged
merged 1 commit into from
Jun 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/display/xfa_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 });
Expand Down Expand Up @@ -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.
Expand Down
7 changes: 7 additions & 0 deletions web/firefox_print_service.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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);

Expand Down Expand Up @@ -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,
Expand Down
13 changes: 11 additions & 2 deletions web/pdf_print_service.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand All @@ -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);
};
Expand All @@ -181,6 +189,7 @@ PDFPrintService.prototype = {
}

const wrapper = document.createElement("div");
wrapper.setAttribute("class", "printedPage");
wrapper.appendChild(img);
this.printContainer.appendChild(wrapper);

Expand Down
26 changes: 26 additions & 0 deletions web/ui_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand All @@ -1010,6 +1035,7 @@ export {
getOutputScale,
getPageSizeInches,
getVisibleElements,
getXfaHtmlForPrinting,
isPortraitOrientation,
isValidRotation,
isValidScrollMode,
Expand Down
18 changes: 14 additions & 4 deletions web/viewer.css
Original file line number Diff line number Diff line change
Expand Up @@ -1772,7 +1772,8 @@ html[dir="rtl"] #documentPropertiesOverlay .row > * {
.toolbar,
#loadingBox,
#errorWrapper,
.textLayer {
.textLayer,
.canvasWrapper {
display: none;
}
#viewerContainer {
Expand Down Expand Up @@ -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;

Expand All @@ -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%;
Expand Down
7 changes: 7 additions & 0 deletions web/xfa_layer_builder.css
Original file line number Diff line number Diff line change
Expand Up @@ -262,3 +262,10 @@
.xfaTable .xfaRlRow > div {
flex: 1;
}

@media print {
.xfaTextfield,
.xfaSelect {
background-color: transparent;
}
}
85 changes: 57 additions & 28 deletions web/xfa_layer_builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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() {
Expand All @@ -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,
});
}
}
Expand Down