Skip to content

Commit f2ade67

Browse files
authored
Merge pull request #13411 from calixteman/xfa_print
XFA - Add support to print XFA forms
2 parents 3456ed2 + a434011 commit f2ade67

7 files changed

+130
-35
lines changed

src/display/xfa_layer.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
* limitations under the License.
1414
*/
1515

16+
import { PageViewport } from "./display_utils.js";
17+
1618
class XfaLayer {
1719
static setupStorage(html, fieldId, element, storage) {
1820
const storedData = storage.getValue(fieldId, { value: null });
@@ -100,7 +102,12 @@ class XfaLayer {
100102

101103
const rootDiv = parameters.div;
102104
rootDiv.appendChild(rootHtml);
103-
const coeffs = parameters.viewport.transform.join(",");
105+
106+
let { viewport } = parameters;
107+
if (!(viewport instanceof PageViewport)) {
108+
viewport = new PageViewport(viewport);
109+
}
110+
const coeffs = viewport.transform.join(",");
104111
rootDiv.style.transform = `matrix(${coeffs})`;
105112

106113
// Set defaults.

web/firefox_print_service.js

+7
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
*/
1515

1616
import { RenderingCancelledException, shadow } from "pdfjs-lib";
17+
import { getXfaHtmlForPrinting } from "./ui_utils.js";
1718
import { PDFPrintServiceFactory } from "./app.js";
1819

1920
// Creates a placeholder with div and canvas with right size for the page.
@@ -33,6 +34,7 @@ function composePage(
3334
canvas.height = Math.floor(size.height * PRINT_UNITS);
3435

3536
const canvasWrapper = document.createElement("div");
37+
canvasWrapper.setAttribute("class", "printedPage");
3638
canvasWrapper.appendChild(canvas);
3739
printContainer.appendChild(canvasWrapper);
3840

@@ -130,6 +132,11 @@ FirefoxPrintService.prototype = {
130132
const body = document.querySelector("body");
131133
body.setAttribute("data-pdfjsprinting", true);
132134

135+
if (pdfDocument.isPureXfa) {
136+
getXfaHtmlForPrinting(printContainer, pdfDocument);
137+
return;
138+
}
139+
133140
for (let i = 0, ii = pagesOverview.length; i < ii; ++i) {
134141
composePage(
135142
pdfDocument,

web/pdf_print_service.js

+11-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
*/
1515

1616
import { PDFPrintServiceFactory, PDFViewerApplication } from "./app.js";
17+
import { getXfaHtmlForPrinting } from "./ui_utils.js";
1718
import { viewerCompatibilityParams } from "./viewer_compatibility.js";
1819

1920
let activeService = null;
@@ -139,6 +140,11 @@ PDFPrintService.prototype = {
139140
},
140141

141142
renderPages() {
143+
if (this.pdfDocument.isPureXfa) {
144+
getXfaHtmlForPrinting(this.printContainer, this.pdfDocument);
145+
return Promise.resolve();
146+
}
147+
142148
const pageCount = this.pagesOverview.length;
143149
const renderNextPage = (resolve, reject) => {
144150
this.throwIfInactive();
@@ -157,8 +163,10 @@ PDFPrintService.prototype = {
157163
this._printResolution,
158164
this._optionalContentConfigPromise
159165
)
160-
.then(this.useRenderedPage.bind(this))
161-
.then(function () {
166+
.then(() => {
167+
this.useRenderedPage.bind(this);
168+
})
169+
.then(() => {
162170
renderNextPage(resolve, reject);
163171
}, reject);
164172
};
@@ -181,6 +189,7 @@ PDFPrintService.prototype = {
181189
}
182190

183191
const wrapper = document.createElement("div");
192+
wrapper.setAttribute("class", "printedPage");
184193
wrapper.appendChild(img);
185194
this.printContainer.appendChild(wrapper);
186195

web/ui_utils.js

+26
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
* limitations under the License.
1414
*/
1515

16+
import { DefaultXfaLayerFactory } from "./xfa_layer_builder.js";
17+
1618
const CSS_UNITS = 96.0 / 72.0;
1719
const DEFAULT_SCALE_VALUE = "auto";
1820
const DEFAULT_SCALE = 1.0;
@@ -994,6 +996,29 @@ function apiPageModeToSidebarView(mode) {
994996
return SidebarView.NONE; // Default value.
995997
}
996998

999+
function getXfaHtmlForPrinting(printContainer, pdfDocument) {
1000+
const xfaHtml = pdfDocument.allXfaHtml;
1001+
const factory = new DefaultXfaLayerFactory();
1002+
const scale = Math.round(CSS_UNITS * 100) / 100;
1003+
for (const xfaPage of xfaHtml.children) {
1004+
const page = document.createElement("div");
1005+
page.setAttribute("class", "xfaPrintedPage");
1006+
printContainer.appendChild(page);
1007+
1008+
const { width, height } = xfaPage.attributes.style;
1009+
const viewBox = [0, 0, parseInt(width), parseInt(height)];
1010+
const viewport = { viewBox, scale, rotation: 0 };
1011+
1012+
const builder = factory.createXfaLayerBuilder(
1013+
page,
1014+
null,
1015+
pdfDocument.annotationStorage,
1016+
xfaPage
1017+
);
1018+
builder.render(viewport, "print");
1019+
}
1020+
}
1021+
9971022
export {
9981023
animationStarted,
9991024
apiPageLayoutToSpreadMode,
@@ -1010,6 +1035,7 @@ export {
10101035
getOutputScale,
10111036
getPageSizeInches,
10121037
getVisibleElements,
1038+
getXfaHtmlForPrinting,
10131039
isPortraitOrientation,
10141040
isValidRotation,
10151041
isValidScrollMode,

web/viewer.css

+14-4
Original file line numberDiff line numberDiff line change
@@ -1772,7 +1772,8 @@ html[dir="rtl"] #documentPropertiesOverlay .row > * {
17721772
.toolbar,
17731773
#loadingBox,
17741774
#errorWrapper,
1775-
.textLayer {
1775+
.textLayer,
1776+
.canvasWrapper {
17761777
display: none;
17771778
}
17781779
#viewerContainer {
@@ -1816,7 +1817,7 @@ html[dir="rtl"] #documentPropertiesOverlay .row > * {
18161817
height: 100%;
18171818
}
18181819
/* wrapper around (scaled) print canvas elements */
1819-
#printContainer > div {
1820+
#printContainer > .printedPage {
18201821
page-break-after: always;
18211822
page-break-inside: avoid;
18221823

@@ -1829,8 +1830,17 @@ html[dir="rtl"] #documentPropertiesOverlay .row > * {
18291830
justify-content: center;
18301831
align-items: center;
18311832
}
1832-
#printContainer canvas,
1833-
#printContainer img {
1833+
1834+
#printContainer > .xfaPrintedPage {
1835+
page-break-after: always;
1836+
page-break-inside: avoid;
1837+
width: 100%;
1838+
height: 100%;
1839+
position: relative;
1840+
}
1841+
1842+
.printedPage canvas,
1843+
.printedPage img {
18341844
/* The intrinsic canvas / image size will make sure that we fit the page. */
18351845
max-width: 100%;
18361846
max-height: 100%;

web/xfa_layer_builder.css

+7
Original file line numberDiff line numberDiff line change
@@ -262,3 +262,10 @@
262262
.xfaTable .xfaRlRow > div {
263263
flex: 1;
264264
}
265+
266+
@media print {
267+
.xfaTextfield,
268+
.xfaSelect {
269+
background-color: transparent;
270+
}
271+
}

web/xfa_layer_builder.js

+57-28
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@ class XfaLayerBuilder {
2626
/**
2727
* @param {XfaLayerBuilderOptions} options
2828
*/
29-
constructor({ pageDiv, pdfPage, annotationStorage }) {
29+
constructor({ pageDiv, pdfPage, xfaHtml, annotationStorage }) {
3030
this.pageDiv = pageDiv;
3131
this.pdfPage = pdfPage;
32+
this.xfaHtml = xfaHtml;
3233
this.annotationStorage = annotationStorage;
3334

3435
this.div = null;
@@ -42,34 +43,55 @@ class XfaLayerBuilder {
4243
* annotations is complete.
4344
*/
4445
render(viewport, intent = "display") {
45-
return this.pdfPage
46-
.getXfa()
47-
.then(xfa => {
48-
if (this._cancelled) {
49-
return;
50-
}
51-
const parameters = {
52-
viewport: viewport.clone({ dontFlip: true }),
53-
div: this.div,
54-
xfa,
55-
page: this.pdfPage,
56-
annotationStorage: this.annotationStorage,
57-
};
46+
if (intent === "display") {
47+
return this.pdfPage
48+
.getXfa()
49+
.then(xfa => {
50+
if (this._cancelled) {
51+
return;
52+
}
53+
const parameters = {
54+
viewport: viewport.clone({ dontFlip: true }),
55+
div: this.div,
56+
xfa,
57+
page: this.pdfPage,
58+
annotationStorage: this.annotationStorage,
59+
};
5860

59-
if (this.div) {
60-
XfaLayer.update(parameters);
61-
} else {
62-
// Create an xfa layer div and render the form
63-
this.div = document.createElement("div");
64-
this.pageDiv.appendChild(this.div);
65-
parameters.div = this.div;
61+
if (this.div) {
62+
XfaLayer.update(parameters);
63+
} else {
64+
// Create an xfa layer div and render the form
65+
this.div = document.createElement("div");
66+
this.pageDiv.appendChild(this.div);
67+
parameters.div = this.div;
6668

67-
XfaLayer.render(parameters);
68-
}
69-
})
70-
.catch(error => {
71-
console.error(error);
72-
});
69+
XfaLayer.render(parameters);
70+
}
71+
})
72+
.catch(error => {
73+
console.error(error);
74+
});
75+
}
76+
77+
// intent === "print".
78+
viewport.dontFlip = true;
79+
const parameters = {
80+
viewport,
81+
div: this.div,
82+
xfa: this.xfaHtml,
83+
page: null,
84+
annotationStorage: this.annotationStorage,
85+
};
86+
87+
// Create an xfa layer div and render the form
88+
const div = document.createElement("div");
89+
this.pageDiv.appendChild(div);
90+
parameters.div = div;
91+
92+
XfaLayer.render(parameters);
93+
94+
return null;
7395
}
7496

7597
cancel() {
@@ -92,12 +114,19 @@ class DefaultXfaLayerFactory {
92114
* @param {HTMLDivElement} pageDiv
93115
* @param {PDFPage} pdfPage
94116
* @param {AnnotationStorage} [annotationStorage]
117+
* @param {Object} [xfaHtml]
95118
*/
96-
createXfaLayerBuilder(pageDiv, pdfPage, annotationStorage = null) {
119+
createXfaLayerBuilder(
120+
pageDiv,
121+
pdfPage,
122+
annotationStorage = null,
123+
xfaHtml = null
124+
) {
97125
return new XfaLayerBuilder({
98126
pageDiv,
99127
pdfPage,
100128
annotationStorage,
129+
xfaHtml,
101130
});
102131
}
103132
}

0 commit comments

Comments
 (0)