@@ -124,30 +124,129 @@ var Fonts = (function () {
124
124
})();
125
125
126
126
var FontLoader = {
127
- bind : function (fonts ) {
128
- var ready = true ;
127
+ bind : function (fonts , callback ) {
128
+ function checkFontsLoaded () {
129
+ for (var i = 0 ; i < fonts .length ; i ++) {
130
+ var font = fonts [i ];
131
+ if (Fonts .lookup (font .name ).loading ) {
132
+ return false ;
133
+ }
134
+ }
135
+
136
+ document .documentElement .removeEventListener (
137
+ "pdfjsFontLoad" , checkFontsLoaded , false );
138
+
139
+ callback ();
140
+ return true ;
141
+ }
129
142
143
+ var rules = [ ], names = [ ];
130
144
for (var i = 0 ; i < fonts .length ; i ++) {
131
145
var font = fonts [i ];
132
- if (Fonts .lookup (font .name )) {
133
- ready = ready && !Fonts .lookup (font .name ).loading ;
134
- continue ;
146
+ if (!Fonts .lookup (font .name )) {
147
+ var obj = new Font (font .name , font .file , font .properties );
148
+
149
+ var str = "" ;
150
+ var data = Fonts .lookup (font .name ).data ;
151
+ var length = data .length ;
152
+ for (var j = 0 ; j < length ; j ++)
153
+ str += String .fromCharCode (data [j ]);
154
+
155
+ var rule = isWorker ? obj .bindWorker (str ) : obj .bindDOM (str );
156
+ if (rule ) {
157
+ rules .push (rule );
158
+ names .push (font .name );
159
+ }
135
160
}
161
+ }
136
162
137
- ready = false ;
163
+ if (!isWorker && rules .length ) {
164
+ FontLoader .prepareFontLoadEvent (rules , names );
165
+ }
138
166
139
- var obj = new Font (font .name , font .file , font .properties );
167
+ if (!checkFontsLoaded ()) {
168
+ document .documentElement .addEventListener (
169
+ "pdfjsFontLoad" , checkFontsLoaded , false );
170
+ }
140
171
141
- var str = "" ;
142
- var data = Fonts .lookup (font .name ).data ;
143
- var length = data .length ;
144
- for (var j = 0 ; j < length ; j ++)
145
- str += String .fromCharCode (data [j ]);
172
+ return ;
173
+ },
174
+ // Set things up so that at least one pdfjsFontLoad event is
175
+ // dispatched when all the @font-face |rules| for |names| have been
176
+ // loaded in a subdocument. It's expected that the load of |rules|
177
+ // has already started in this (outer) document, so that they should
178
+ // be ordered before the load in the subdocument.
179
+ prepareFontLoadEvent : function (rules , names ) {
180
+ /** Hack begin */
181
+ // There's no event when a font has finished downloading so the
182
+ // following code is a dirty hack to 'guess' when a font is
183
+ // ready. This code will be obsoleted by Mozilla bug 471915.
184
+ //
185
+ // The only reliable way to know if a font is loaded in Gecko
186
+ // (at the moment) is document.onload in a document with
187
+ // a @font-face rule defined in a "static" stylesheet. We use a
188
+ // subdocument in an <iframe>, set up properly, to know when
189
+ // our @font-face rule was loaded. However, the subdocument and
190
+ // outer document can't share CSS rules, so the inner document
191
+ // is only part of the puzzle. The second piece is an invisible
192
+ // div created in order to force loading of the @font-face in
193
+ // the *outer* document. (The font still needs to be loaded for
194
+ // its metrics, for reflow). We create the div first for the
195
+ // outer document, then create the iframe. Unless something
196
+ // goes really wonkily, we expect the @font-face for the outer
197
+ // document to be processed before the inner. That's still
198
+ // fragile, but seems to work in practice.
146
199
147
- isWorker ? obj .bindWorker (str ) : obj .bindDOM (str );
148
- }
200
+ var div = document .createElement ("div" );
201
+ div .setAttribute ("style" ,
202
+ 'visibility: hidden;' +
203
+ 'width: 10px; height: 10px;' +
204
+ 'position: absolute; top: 0px; left: 0px;' );
205
+ var html = '';
206
+ for (var i = 0 ; i < names .length ; ++i ) {
207
+ html += '<span style="font-family:' + names [i ] +'">Hi</span>' ;
208
+ }
209
+ div .innerHTML = html ;
210
+ document .body .appendChild (div );
149
211
150
- return ready ;
212
+ // XXX we should have a time-out here too, and maybe fire
213
+ // pdfjsFontLoadFailed?
214
+ var src = '<!DOCTYPE HTML><html><head>' ;
215
+ src += '<style type="text/css">' ;
216
+ for (var i = 0 ; i < rules .length ; ++i ) {
217
+ src += rules [i ];
218
+ }
219
+ src += '</style>'
220
+ src += '<script type="application/javascript">'
221
+ var fontNamesArray = '';
222
+ for (var i = 0 ; i < names .length ; ++i ) {
223
+ fontNamesArray += '"' + names [i ] + '", ' ;
224
+ }
225
+ src += ' var fontNames=[' + fontNamesArray +'];\n' ;
226
+ src += ' window.onload = function () {\n'
227
+ src += ' var Fonts = top.document.defaultView.Fonts;\n' ;
228
+ src += ' for (var i = 0; i < fontNames.length; ++i) {\n' ;
229
+ src += ' var font = Fonts.lookup(fontNames[i]);\n' ;
230
+ src += ' font.loading = false;\n' ;
231
+ src += ' }\n' ;
232
+ src += ' var doc = top.document;\n' ;
233
+ src += ' var evt = doc.createEvent("Events");\n' ;
234
+ src += ' evt.initEvent("pdfjsFontLoad", true, false);\n'
235
+ src += ' doc.documentElement.dispatchEvent(evt);\n' ;
236
+ src += ' }' ;
237
+ src += '</script></head><body>' ;
238
+ for (var i = 0 ; i < names .length ; ++i ) {
239
+ src += '<p style="font-family:\'' + fontName +'\'">Hi</p>' ;
240
+ }
241
+ src += '</body></html>' ;
242
+ var frame = document .createElement ("iframe" );
243
+ frame .src = 'data:text/html,' + src ;
244
+ frame .setAttribute ("style" ,
245
+ 'visibility: hidden;' +
246
+ 'width: 10px; height: 10px;' +
247
+ 'position: absolute; top: 0px; left: 0px;' );
248
+ document .body .appendChild (frame );
249
+ /** Hack end */
151
250
}
152
251
};
153
252
@@ -1004,60 +1103,16 @@ var Font = (function () {
1004
1103
});
1005
1104
},
1006
1105
1007
- bindDOM : function font_bindDom (data , callback ) {
1106
+ bindDOM : function font_bindDom (data ) {
1008
1107
var fontName = this .name ;
1009
1108
1010
- // Just adding the font-face to the DOM doesn't make it load. It
1011
- // seems it's loaded once Gecko notices it's used. Therefore,
1012
- // add a div on the page using the loaded font.
1013
- var div = document .createElement ("div" );
1014
- var style = 'font-family:"' + name +
1015
- '";position: absolute;top:-99999;left:-99999;z-index:-99999' ;
1016
- div .setAttribute ("style" , style );
1017
- document .body .appendChild (div );
1018
-
1019
- /** Hack begin */
1020
- // Actually there is not event when a font has finished downloading so
1021
- // the following code are a dirty hack to 'guess' when a font is ready
1022
- // This code could go away when bug 471915 has landed
1023
- var canvas = document .createElement ("canvas" );
1024
- var ctx = canvas .getContext ("2d" );
1025
- ctx .font = "bold italic 20px " + fontName + ", Symbol, Arial" ;
1026
- var testString = " " ;
1027
-
1028
- // Periodicaly check for the width of the testString, it will be
1029
- // different once the real font has loaded
1030
- var textWidth = ctx .measureText (testString ).width ;
1031
-
1032
- var interval = window .setInterval (function canvasInterval (self ) {
1033
- this .start = this .start || Date .now ();
1034
- ctx .font = "bold italic 20px " + fontName + ", Symbol, Arial" ;
1035
-
1036
- // For some reasons the font has not loaded, so mark it loaded for the
1037
- // page to proceed but cry
1038
- if (textWidth == ctx .measureText (testString ).width ) {
1039
- if ((Date .now () - this .start ) < kMaxWaitForFontFace ) {
1040
- return ;
1041
- } else {
1042
- warn ("Is " + fontName + " loaded?" );
1043
- }
1044
- }
1045
-
1046
- window .clearInterval (interval );
1047
- Fonts .lookup (fontName ).loading = false ;
1048
- this .start = 0 ;
1049
- if (callback ) {
1050
- callback ();
1051
- }
1052
- }, 30 , this );
1053
-
1054
- /** Hack end */
1055
-
1056
1109
// Add the @font-face rule to the document
1057
1110
var url = "url(data:" + this .mimetype + ";base64," + window .btoa (data ) + ");" ;
1058
1111
var rule = "@font-face { font-family:'" + fontName + "';src:" + url + "}" ;
1059
1112
var styleSheet = document .styleSheets [0 ];
1060
1113
styleSheet .insertRule (rule , styleSheet .length );
1114
+
1115
+ return rule ;
1061
1116
}
1062
1117
};
1063
1118
0 commit comments