@@ -404,28 +404,15 @@ function mapPrivateUseChars(code) {
404
404
}
405
405
406
406
var FontLoader = {
407
- listeningForFontLoad : false ,
407
+ loadingContext : {
408
+ requests : [],
409
+ nextRequestId : 0
410
+ },
408
411
409
412
bind : function fontLoaderBind (fonts , callback ) {
410
- function checkFontsLoaded () {
411
- for (var i = 0 , ii = fonts .length ; i < ii ; i ++) {
412
- var fontObj = fonts [i ];
413
- if (fontObj .loading ) {
414
- return false ;
415
- }
416
- }
417
-
418
- document .documentElement .removeEventListener (
419
- 'pdfjsFontLoad' , checkFontsLoaded , false );
420
-
421
- // Use timeout to fix chrome intermittent failures on font loading.
422
- setTimeout (callback , 0 );
423
- return true ;
424
- }
425
-
426
- var rules = [], names = [], fontsToLoad = [];
427
- var fontCreateTimer = 0 ;
413
+ assert (!isWorker , 'bind() shall be called from main thread' );
428
414
415
+ var rules = [], fontsToLoad = [];
429
416
for (var i = 0 , ii = fonts .length ; i < ii ; i ++) {
430
417
var font = fonts [i ];
431
418
@@ -436,8 +423,6 @@ var FontLoader = {
436
423
}
437
424
font .attached = true ;
438
425
439
- fontsToLoad .push (font );
440
-
441
426
var str = '';
442
427
var data = font .data ;
443
428
if (data ) {
@@ -448,28 +433,51 @@ var FontLoader = {
448
433
var rule = font .bindDOM (str );
449
434
if (rule ) {
450
435
rules .push (rule );
451
- names .push (font . loadedName );
436
+ fontsToLoad .push (font );
452
437
}
453
438
}
454
439
}
455
440
456
- this .listeningForFontLoad = false ;
457
- if (!isWorker && rules .length ) {
458
- FontLoader .prepareFontLoadEvent (rules , names , fontsToLoad );
441
+ var request = FontLoader .queueLoadingCallback (callback );
442
+ if (rules .length > 0 ) {
443
+ FontLoader .prepareFontLoadEvent (rules , fontsToLoad , request );
444
+ } else {
445
+ request .complete ();
459
446
}
447
+ },
460
448
461
- if (!checkFontsLoaded ()) {
462
- document .documentElement .addEventListener (
463
- 'pdfjsFontLoad' , checkFontsLoaded , false );
449
+ queueLoadingCallback : function FontLoader_queueLoadingCallback (callback ) {
450
+ function LoadLoader_completeRequest () {
451
+ assert (!request .end , 'completeRequest() cannot be called twice' );
452
+ request .end = Date .now ();
453
+
454
+ // sending all completed requests in order how they were queued
455
+ while (context .requests .length > 0 && context .requests [0 ].end ) {
456
+ var otherRequest = context .requests .shift ();
457
+ setTimeout (otherRequest .callback , 0 );
458
+ }
464
459
}
460
+
461
+ var context = FontLoader .loadingContext ;
462
+ var requestId = 'pdfjs-font-loading-' + (context .nextRequestId ++);
463
+ var request = {
464
+ id : requestId ,
465
+ complete : LoadLoader_completeRequest ,
466
+ callback : callback ,
467
+ started : Date .now ()
468
+ };
469
+ context .requests .push (request );
470
+ return request ;
465
471
},
472
+
466
473
// Set things up so that at least one pdfjsFontLoad event is
467
- // dispatched when all the @font-face |rules| for |names | have been
474
+ // dispatched when all the @font-face |rules| for |fonts | have been
468
475
// loaded in a subdocument. It's expected that the load of |rules|
469
476
// has already started in this (outer) document, so that they should
470
477
// be ordered before the load in the subdocument.
471
- prepareFontLoadEvent : function fontLoaderPrepareFontLoadEvent (rules , names ,
472
- fonts ) {
478
+ prepareFontLoadEvent : function fontLoaderPrepareFontLoadEvent (rules ,
479
+ fonts ,
480
+ request ) {
473
481
/** Hack begin */
474
482
// There's no event when a font has finished downloading so the
475
483
// following code is a dirty hack to 'guess' when a font is
@@ -493,6 +501,20 @@ var FontLoader = {
493
501
// The postMessage() hackery was added to work around chrome bug
494
502
// 82402.
495
503
504
+ var requestId = request .id ;
505
+ // Validate the requestId parameter -- the value used to construct HTML.
506
+ if (!/^[\w\-]+$ /.test (requestId )) {
507
+ error ('Invalid request id: ' + requestId );
508
+
509
+ // Normally the error-function throws. But if a malicious code
510
+ // intercepts the function call then the return is needed.
511
+ return ;
512
+ }
513
+
514
+ var names = [];
515
+ for (var i = 0 , ii = fonts .length ; i < ii ; i ++)
516
+ names .push (fonts [i ].loadedName );
517
+
496
518
// Validate the names parameter -- the values can used to construct HTML.
497
519
if (!/^\w+$ /.test (names .join (''))) {
498
520
error ('Invalid font name(s): ' + names .join ());
@@ -514,22 +536,21 @@ var FontLoader = {
514
536
div .innerHTML = html ;
515
537
document .body .appendChild (div );
516
538
517
- if (!this .listeningForFontLoad ) {
518
- window .addEventListener (
519
- 'message' ,
520
- function fontLoaderMessage (e ) {
521
- var fontNames = JSON .parse (e .data );
522
- for (var i = 0 , ii = fonts .length ; i < ii ; ++i ) {
523
- var font = fonts [i ];
524
- font .loading = false ;
525
- }
526
- var evt = document .createEvent ('Events' );
527
- evt .initEvent ('pdfjsFontLoad' , true , false );
528
- document .documentElement .dispatchEvent (evt );
529
- },
530
- false );
531
- this .listeningForFontLoad = true ;
532
- }
539
+ window .addEventListener (
540
+ 'message' ,
541
+ function fontLoaderMessage (e ) {
542
+ if (e .data !== requestId )
543
+ return ;
544
+ for (var i = 0 , ii = fonts .length ; i < ii ; ++i ) {
545
+ var font = fonts [i ];
546
+ font .loading = false ;
547
+ }
548
+ request .complete ();
549
+ // cleanup
550
+ document .body .removeChild (frame );
551
+ window .removeEventListener ('message' , fontLoaderMessage , false );
552
+ },
553
+ false );
533
554
534
555
// XXX we should have a time-out here too, and maybe fire
535
556
// pdfjsFontLoadFailed?
@@ -540,13 +561,8 @@ var FontLoader = {
540
561
}
541
562
src += '</style>' ;
542
563
src += '<script type="application/javascript">' ;
543
- var fontNamesArray = '';
544
- for (var i = 0 , ii = names .length ; i < ii ; ++i ) {
545
- fontNamesArray += '"' + names [i ] + '", ' ;
546
- }
547
- src += ' var fontNames=[' + fontNamesArray + '];\n' ;
548
564
src += ' window.onload = function fontLoaderOnload() {\n' ;
549
- src += ' parent.postMessage(JSON.stringify(fontNames) , "*");\n' ;
565
+ src += ' parent.postMessage("' + requestId + '" , "*");\n' ;
550
566
src += ' }' ;
551
567
// Hack so the end script tag isn't counted if this is inline JS.
552
568
src += '</scr' + 'ipt></head><body>' ;
0 commit comments