@@ -25,27 +25,60 @@ const STANDARD_FONT_DATA_URL = "/build/generic/web/standard_fonts/";
25
25
const IMAGE_RESOURCES_PATH = "/web/images/" ;
26
26
const WORKER_SRC = "../build/generic/build/pdf.worker.js" ;
27
27
const RENDER_TASK_ON_CONTINUE_DELAY = 5 ; // ms
28
+ const SVG_NS = "http://www.w3.org/2000/svg" ;
28
29
29
- /**
30
- * @class
31
- */
32
- var rasterizeTextLayer = ( function rasterizeTextLayerClosure ( ) {
33
- var SVG_NS = "http://www.w3.org/2000/svg" ;
30
+ function loadStyles ( styles ) {
31
+ styles = Object . values ( styles ) ;
32
+ if ( styles . every ( style => style . promise ) ) {
33
+ return Promise . all ( styles . map ( style => style . promise ) ) ;
34
+ }
34
35
35
- var textLayerStylePromise = null ;
36
- function getTextLayerStyle ( ) {
37
- if ( textLayerStylePromise ) {
38
- return textLayerStylePromise ;
39
- }
40
- textLayerStylePromise = new Promise ( function ( resolve ) {
41
- var xhr = new XMLHttpRequest ( ) ;
42
- xhr . open ( "GET" , "./text_layer_test.css" ) ;
36
+ for ( const style of styles ) {
37
+ style . promise = new Promise ( function ( resolve , reject ) {
38
+ const xhr = new XMLHttpRequest ( ) ;
39
+ xhr . open ( "GET" , style . file ) ;
43
40
xhr . onload = function ( ) {
44
41
resolve ( xhr . responseText ) ;
45
42
} ;
43
+ xhr . onerror = function ( e ) {
44
+ reject ( new Error ( `Error fetching style (${ style . file } ): ${ e } ` ) ) ;
45
+ } ;
46
46
xhr . send ( null ) ;
47
47
} ) ;
48
- return textLayerStylePromise ;
48
+ }
49
+
50
+ return Promise . all ( styles . map ( style => style . promise ) ) ;
51
+ }
52
+
53
+ function writeSVG ( svgElement , ctx , resolve , reject ) {
54
+ // We need to have UTF-8 encoded XML.
55
+ const svg_xml = unescape (
56
+ encodeURIComponent ( new XMLSerializer ( ) . serializeToString ( svgElement ) )
57
+ ) ;
58
+ const img = new Image ( ) ;
59
+ img . src = "data:image/svg+xml;base64," + btoa ( svg_xml ) ;
60
+ img . onload = function ( ) {
61
+ ctx . drawImage ( img , 0 , 0 ) ;
62
+ resolve ( ) ;
63
+ } ;
64
+ img . onerror = function ( e ) {
65
+ reject ( new Error ( "Error rasterizing text layer " + e ) ) ;
66
+ } ;
67
+ }
68
+
69
+ /**
70
+ * @class
71
+ */
72
+ var rasterizeTextLayer = ( function rasterizeTextLayerClosure ( ) {
73
+ const styles = {
74
+ common : {
75
+ file : "./text_layer_test.css" ,
76
+ promise : null ,
77
+ } ,
78
+ } ;
79
+
80
+ function getTextLayerStyle ( ) {
81
+ return loadStyles ( styles ) ;
49
82
}
50
83
51
84
// eslint-disable-next-line no-shadow
@@ -92,19 +125,7 @@ var rasterizeTextLayer = (function rasterizeTextLayerClosure() {
92
125
task . expandTextDivs ( true ) ;
93
126
svg . appendChild ( foreignObject ) ;
94
127
95
- // We need to have UTF-8 encoded XML.
96
- var svg_xml = unescape (
97
- encodeURIComponent ( new XMLSerializer ( ) . serializeToString ( svg ) )
98
- ) ;
99
- var img = new Image ( ) ;
100
- img . src = "data:image/svg+xml;base64," + btoa ( svg_xml ) ;
101
- img . onload = function ( ) {
102
- ctx . drawImage ( img , 0 , 0 ) ;
103
- resolve ( ) ;
104
- } ;
105
- img . onerror = function ( e ) {
106
- reject ( new Error ( "Error rasterizing text layer " + e ) ) ;
107
- } ;
128
+ writeSVG ( svg , ctx , resolve , reject ) ;
108
129
} )
109
130
. catch ( reason => {
110
131
reject ( new Error ( `rasterizeTextLayer: "${ reason ?. message } ".` ) ) ;
@@ -119,8 +140,6 @@ var rasterizeTextLayer = (function rasterizeTextLayerClosure() {
119
140
* @class
120
141
*/
121
142
var rasterizeAnnotationLayer = ( function rasterizeAnnotationLayerClosure ( ) {
122
- const SVG_NS = "http://www.w3.org/2000/svg" ;
123
-
124
143
/**
125
144
* For the reference tests, the entire annotation layer must be visible. To
126
145
* achieve this, we load the common styles as used by the viewer and extend
@@ -142,27 +161,7 @@ var rasterizeAnnotationLayer = (function rasterizeAnnotationLayerClosure() {
142
161
} ;
143
162
144
163
function getAnnotationLayerStyle ( ) {
145
- // Use the cached promises if they are available.
146
- if ( styles . common . promise && styles . overrides . promise ) {
147
- return Promise . all ( [ styles . common . promise , styles . overrides . promise ] ) ;
148
- }
149
-
150
- // Load the style files and cache the results.
151
- for ( const key in styles ) {
152
- styles [ key ] . promise = new Promise ( function ( resolve , reject ) {
153
- const xhr = new XMLHttpRequest ( ) ;
154
- xhr . open ( "GET" , styles [ key ] . file ) ;
155
- xhr . onload = function ( ) {
156
- resolve ( xhr . responseText ) ;
157
- } ;
158
- xhr . onerror = function ( e ) {
159
- reject ( new Error ( "Error fetching annotation style " + e ) ) ;
160
- } ;
161
- xhr . send ( null ) ;
162
- } ) ;
163
- }
164
-
165
- return Promise . all ( [ styles . common . promise , styles . overrides . promise ] ) ;
164
+ return loadStyles ( styles ) ;
166
165
}
167
166
168
167
function inlineAnnotationImages ( images ) {
@@ -256,19 +255,7 @@ var rasterizeAnnotationLayer = (function rasterizeAnnotationLayerClosure() {
256
255
foreignObject . appendChild ( div ) ;
257
256
svg . appendChild ( foreignObject ) ;
258
257
259
- // We need to have UTF-8 encoded XML.
260
- var svg_xml = unescape (
261
- encodeURIComponent ( new XMLSerializer ( ) . serializeToString ( svg ) )
262
- ) ;
263
- var img = new Image ( ) ;
264
- img . src = "data:image/svg+xml;base64," + btoa ( svg_xml ) ;
265
- img . onload = function ( ) {
266
- ctx . drawImage ( img , 0 , 0 ) ;
267
- resolve ( ) ;
268
- } ;
269
- img . onerror = function ( e ) {
270
- reject ( new Error ( "Error rasterizing annotation layer " + e ) ) ;
271
- } ;
258
+ writeSVG ( svg , ctx , resolve , reject ) ;
272
259
} )
273
260
. catch ( reason => {
274
261
reject ( new Error ( `rasterizeAnnotationLayer: "${ reason ?. message } ".` ) ) ;
@@ -279,6 +266,65 @@ var rasterizeAnnotationLayer = (function rasterizeAnnotationLayerClosure() {
279
266
return rasterizeAnnotationLayer ;
280
267
} ) ( ) ;
281
268
269
+ /**
270
+ * @class
271
+ */
272
+ var rasterizeXfaLayer = ( function rasterizeXfaLayerClosure ( ) {
273
+ const styles = {
274
+ common : {
275
+ file : "../web/xfa_layer_builder.css" ,
276
+ promise : null ,
277
+ } ,
278
+ } ;
279
+
280
+ function getXfaLayerStyle ( ) {
281
+ return loadStyles ( styles ) ;
282
+ }
283
+
284
+ // eslint-disable-next-line no-shadow
285
+ function rasterizeXfaLayer ( ctx , viewport , xfa , fontRules ) {
286
+ return new Promise ( function ( resolve , reject ) {
287
+ // Building SVG with size of the viewport.
288
+ const svg = document . createElementNS ( SVG_NS , "svg:svg" ) ;
289
+ svg . setAttribute ( "width" , viewport . width + "px" ) ;
290
+ svg . setAttribute ( "height" , viewport . height + "px" ) ;
291
+ const foreignObject = document . createElementNS (
292
+ SVG_NS ,
293
+ "svg:foreignObject"
294
+ ) ;
295
+ foreignObject . setAttribute ( "x" , "0" ) ;
296
+ foreignObject . setAttribute ( "y" , "0" ) ;
297
+ foreignObject . setAttribute ( "width" , viewport . width + "px" ) ;
298
+ foreignObject . setAttribute ( "height" , viewport . height + "px" ) ;
299
+ const style = document . createElement ( "style" ) ;
300
+ const stylePromise = getXfaLayerStyle ( ) ;
301
+ foreignObject . appendChild ( style ) ;
302
+ const div = document . createElement ( "div" ) ;
303
+ foreignObject . appendChild ( div ) ;
304
+
305
+ stylePromise
306
+ . then ( async cssRules => {
307
+ style . textContent = fontRules + "\n" + cssRules ;
308
+
309
+ pdfjsLib . XfaLayer . render ( {
310
+ xfa,
311
+ div,
312
+ viewport : viewport . clone ( { dontFlip : true } ) ,
313
+ } ) ;
314
+
315
+ svg . appendChild ( foreignObject ) ;
316
+
317
+ writeSVG ( svg , ctx , resolve , reject ) ;
318
+ } )
319
+ . catch ( reason => {
320
+ reject ( new Error ( `rasterizeXfaLayer: "${ reason ?. message } ".` ) ) ;
321
+ } ) ;
322
+ } ) ;
323
+ }
324
+
325
+ return rasterizeXfaLayer ;
326
+ } ) ( ) ;
327
+
282
328
/**
283
329
* @typedef {Object } DriverOptions
284
330
* @property {HTMLSpanElement } inflight - Field displaying the number of
@@ -392,6 +438,7 @@ var Driver = (function DriverClosure() {
392
438
task . round = 0 ;
393
439
task . pageNum = task . firstPage || 1 ;
394
440
task . stats = { times : [ ] } ;
441
+ task . enableXfa = task . enableXfa === true ;
395
442
396
443
// Support *linked* test-cases for the other suites, e.g. unit- and
397
444
// integration-tests, without needing to run them as reference-tests.
@@ -411,6 +458,17 @@ var Driver = (function DriverClosure() {
411
458
412
459
const absoluteUrl = new URL ( task . file , window . location ) . href ;
413
460
try {
461
+ let xfaStyleElement = null ;
462
+ if ( task . enableXfa ) {
463
+ // Need to get the font definitions to inject them in the SVG.
464
+ // So we create this element and those definitions will be
465
+ // appended in font_loader.js.
466
+ xfaStyleElement = document . createElement ( "style" ) ;
467
+ document . documentElement
468
+ . getElementsByTagName ( "head" ) [ 0 ]
469
+ . appendChild ( xfaStyleElement ) ;
470
+ }
471
+
414
472
const loadingTask = pdfjsLib . getDocument ( {
415
473
url : absoluteUrl ,
416
474
password : task . password ,
@@ -422,9 +480,18 @@ var Driver = (function DriverClosure() {
422
480
pdfBug : true ,
423
481
useSystemFonts : task . useSystemFonts ,
424
482
useWorkerFetch : task . useWorkerFetch ,
483
+ enableXfa : task . enableXfa ,
484
+ styleElement : xfaStyleElement ,
425
485
} ) ;
426
486
loadingTask . promise . then (
427
487
doc => {
488
+ if ( task . enableXfa ) {
489
+ task . fontRules = "" ;
490
+ for ( const rule of xfaStyleElement . sheet . cssRules ) {
491
+ task . fontRules += rule . cssText + "\n" ;
492
+ }
493
+ }
494
+
428
495
task . pdfDoc = doc ;
429
496
task . optionalContentConfigPromise =
430
497
doc . getOptionalContentConfig ( ) ;
@@ -552,7 +619,8 @@ var Driver = (function DriverClosure() {
552
619
// Initialize various `eq` test subtypes, see comment below.
553
620
var renderAnnotations = false ,
554
621
renderForms = false ,
555
- renderPrint = false ;
622
+ renderPrint = false ,
623
+ renderXfa = false ;
556
624
557
625
var textLayerCanvas , annotationLayerCanvas ;
558
626
var initPromise ;
@@ -594,9 +662,10 @@ var Driver = (function DriverClosure() {
594
662
renderAnnotations = ! ! task . annotations ;
595
663
renderForms = ! ! task . forms ;
596
664
renderPrint = ! ! task . print ;
665
+ renderXfa = ! ! task . enableXfa ;
597
666
598
667
// Render the annotation layer if necessary.
599
- if ( renderAnnotations || renderForms ) {
668
+ if ( renderAnnotations || renderForms || renderXfa ) {
600
669
// Create a dummy canvas for the drawing operations.
601
670
annotationLayerCanvas = self . annotationLayerCanvas ;
602
671
if ( ! annotationLayerCanvas ) {
@@ -614,19 +683,31 @@ var Driver = (function DriverClosure() {
614
683
annotationLayerCanvas . height
615
684
) ;
616
685
617
- // The annotation builder will draw its content on the canvas.
618
- initPromise = page
619
- . getAnnotations ( { intent : "display" } )
620
- . then ( function ( annotations ) {
621
- return rasterizeAnnotationLayer (
686
+ if ( ! renderXfa ) {
687
+ // The annotation builder will draw its content
688
+ // on the canvas.
689
+ initPromise = page
690
+ . getAnnotations ( { intent : "display" } )
691
+ . then ( function ( annotations ) {
692
+ return rasterizeAnnotationLayer (
693
+ annotationLayerContext ,
694
+ viewport ,
695
+ annotations ,
696
+ page ,
697
+ IMAGE_RESOURCES_PATH ,
698
+ renderForms
699
+ ) ;
700
+ } ) ;
701
+ } else {
702
+ initPromise = page . getXfa ( ) . then ( function ( xfa ) {
703
+ return rasterizeXfaLayer (
622
704
annotationLayerContext ,
623
705
viewport ,
624
- annotations ,
625
- page ,
626
- IMAGE_RESOURCES_PATH ,
627
- renderForms
706
+ xfa ,
707
+ task . fontRules
628
708
) ;
629
709
} ) ;
710
+ }
630
711
} else {
631
712
annotationLayerCanvas = null ;
632
713
initPromise = Promise . resolve ( ) ;
0 commit comments