1 /***************************************************************************/ |
|
2 /* */ |
|
3 /* t1load.c */ |
|
4 /* */ |
|
5 /* Type 1 font loader (body). */ |
|
6 /* */ |
|
7 /* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, */ |
|
8 /* 2010 by */ |
|
9 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ |
|
10 /* */ |
|
11 /* This file is part of the FreeType project, and may only be used, */ |
|
12 /* modified, and distributed under the terms of the FreeType project */ |
|
13 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ |
|
14 /* this file you indicate that you have read the license and */ |
|
15 /* understand and accept it fully. */ |
|
16 /* */ |
|
17 /***************************************************************************/ |
|
18 |
|
19 |
|
20 /*************************************************************************/ |
|
21 /* */ |
|
22 /* This is the new and improved Type 1 data loader for FreeType 2. The */ |
|
23 /* old loader has several problems: it is slow, complex, difficult to */ |
|
24 /* maintain, and contains incredible hacks to make it accept some */ |
|
25 /* ill-formed Type 1 fonts without hiccup-ing. Moreover, about 5% of */ |
|
26 /* the Type 1 fonts on my machine still aren't loaded correctly by it. */ |
|
27 /* */ |
|
28 /* This version is much simpler, much faster and also easier to read and */ |
|
29 /* maintain by a great order of magnitude. The idea behind it is to */ |
|
30 /* _not_ try to read the Type 1 token stream with a state machine (i.e. */ |
|
31 /* a Postscript-like interpreter) but rather to perform simple pattern */ |
|
32 /* matching. */ |
|
33 /* */ |
|
34 /* Indeed, nearly all data definitions follow a simple pattern like */ |
|
35 /* */ |
|
36 /* ... /Field <data> ... */ |
|
37 /* */ |
|
38 /* where <data> can be a number, a boolean, a string, or an array of */ |
|
39 /* numbers. There are a few exceptions, namely the encoding, font name, */ |
|
40 /* charstrings, and subrs; they are handled with a special pattern */ |
|
41 /* matching routine. */ |
|
42 /* */ |
|
43 /* All other common cases are handled very simply. The matching rules */ |
|
44 /* are defined in the file `t1tokens.h' through the use of several */ |
|
45 /* macros calls PARSE_XXX. This file is included twice here; the first */ |
|
46 /* time to generate parsing callback functions, the second time to */ |
|
47 /* generate a table of keywords (with pointers to the associated */ |
|
48 /* callback functions). */ |
|
49 /* */ |
|
50 /* The function `parse_dict' simply scans *linearly* a given dictionary */ |
|
51 /* (either the top-level or private one) and calls the appropriate */ |
|
52 /* callback when it encounters an immediate keyword. */ |
|
53 /* */ |
|
54 /* This is by far the fastest way one can find to parse and read all */ |
|
55 /* data. */ |
|
56 /* */ |
|
57 /* This led to tremendous code size reduction. Note that later, the */ |
|
58 /* glyph loader will also be _greatly_ simplified, and the automatic */ |
|
59 /* hinter will replace the clumsy `t1hinter'. */ |
|
60 /* */ |
|
61 /*************************************************************************/ |
|
62 |
|
63 |
|
64 #include <ft2build.h> |
|
65 #include FT_INTERNAL_DEBUG_H |
|
66 #include FT_CONFIG_CONFIG_H |
|
67 #include FT_MULTIPLE_MASTERS_H |
|
68 #include FT_INTERNAL_TYPE1_TYPES_H |
|
69 #include FT_INTERNAL_CALC_H |
|
70 |
|
71 #include "t1load.h" |
|
72 #include "t1errors.h" |
|
73 |
|
74 |
|
75 /*************************************************************************/ |
|
76 /* */ |
|
77 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ |
|
78 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ |
|
79 /* messages during execution. */ |
|
80 /* */ |
|
81 #undef FT_COMPONENT |
|
82 #define FT_COMPONENT trace_t1load |
|
83 |
|
84 |
|
85 #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT |
|
86 |
|
87 |
|
88 /*************************************************************************/ |
|
89 /*************************************************************************/ |
|
90 /***** *****/ |
|
91 /***** MULTIPLE MASTERS SUPPORT *****/ |
|
92 /***** *****/ |
|
93 /*************************************************************************/ |
|
94 /*************************************************************************/ |
|
95 |
|
96 static FT_Error |
|
97 t1_allocate_blend( T1_Face face, |
|
98 FT_UInt num_designs, |
|
99 FT_UInt num_axis ) |
|
100 { |
|
101 PS_Blend blend; |
|
102 FT_Memory memory = face->root.memory; |
|
103 FT_Error error = T1_Err_Ok; |
|
104 |
|
105 |
|
106 blend = face->blend; |
|
107 if ( !blend ) |
|
108 { |
|
109 if ( FT_NEW( blend ) ) |
|
110 goto Exit; |
|
111 |
|
112 blend->num_default_design_vector = 0; |
|
113 |
|
114 face->blend = blend; |
|
115 } |
|
116 |
|
117 /* allocate design data if needed */ |
|
118 if ( num_designs > 0 ) |
|
119 { |
|
120 if ( blend->num_designs == 0 ) |
|
121 { |
|
122 FT_UInt nn; |
|
123 |
|
124 |
|
125 /* allocate the blend `private' and `font_info' dictionaries */ |
|
126 if ( FT_NEW_ARRAY( blend->font_infos[1], num_designs ) || |
|
127 FT_NEW_ARRAY( blend->privates[1], num_designs ) || |
|
128 FT_NEW_ARRAY( blend->bboxes[1], num_designs ) || |
|
129 FT_NEW_ARRAY( blend->weight_vector, num_designs * 2 ) ) |
|
130 goto Exit; |
|
131 |
|
132 blend->default_weight_vector = blend->weight_vector + num_designs; |
|
133 |
|
134 blend->font_infos[0] = &face->type1.font_info; |
|
135 blend->privates [0] = &face->type1.private_dict; |
|
136 blend->bboxes [0] = &face->type1.font_bbox; |
|
137 |
|
138 for ( nn = 2; nn <= num_designs; nn++ ) |
|
139 { |
|
140 blend->privates[nn] = blend->privates [nn - 1] + 1; |
|
141 blend->font_infos[nn] = blend->font_infos[nn - 1] + 1; |
|
142 blend->bboxes[nn] = blend->bboxes [nn - 1] + 1; |
|
143 } |
|
144 |
|
145 blend->num_designs = num_designs; |
|
146 } |
|
147 else if ( blend->num_designs != num_designs ) |
|
148 goto Fail; |
|
149 } |
|
150 |
|
151 /* allocate axis data if needed */ |
|
152 if ( num_axis > 0 ) |
|
153 { |
|
154 if ( blend->num_axis != 0 && blend->num_axis != num_axis ) |
|
155 goto Fail; |
|
156 |
|
157 blend->num_axis = num_axis; |
|
158 } |
|
159 |
|
160 /* allocate the blend design pos table if needed */ |
|
161 num_designs = blend->num_designs; |
|
162 num_axis = blend->num_axis; |
|
163 if ( num_designs && num_axis && blend->design_pos[0] == 0 ) |
|
164 { |
|
165 FT_UInt n; |
|
166 |
|
167 |
|
168 if ( FT_NEW_ARRAY( blend->design_pos[0], num_designs * num_axis ) ) |
|
169 goto Exit; |
|
170 |
|
171 for ( n = 1; n < num_designs; n++ ) |
|
172 blend->design_pos[n] = blend->design_pos[0] + num_axis * n; |
|
173 } |
|
174 |
|
175 Exit: |
|
176 return error; |
|
177 |
|
178 Fail: |
|
179 error = T1_Err_Invalid_File_Format; |
|
180 goto Exit; |
|
181 } |
|
182 |
|
183 |
|
184 FT_LOCAL_DEF( FT_Error ) |
|
185 T1_Get_Multi_Master( T1_Face face, |
|
186 FT_Multi_Master* master ) |
|
187 { |
|
188 PS_Blend blend = face->blend; |
|
189 FT_UInt n; |
|
190 FT_Error error; |
|
191 |
|
192 |
|
193 error = T1_Err_Invalid_Argument; |
|
194 |
|
195 if ( blend ) |
|
196 { |
|
197 master->num_axis = blend->num_axis; |
|
198 master->num_designs = blend->num_designs; |
|
199 |
|
200 for ( n = 0; n < blend->num_axis; n++ ) |
|
201 { |
|
202 FT_MM_Axis* axis = master->axis + n; |
|
203 PS_DesignMap map = blend->design_map + n; |
|
204 |
|
205 |
|
206 axis->name = blend->axis_names[n]; |
|
207 axis->minimum = map->design_points[0]; |
|
208 axis->maximum = map->design_points[map->num_points - 1]; |
|
209 } |
|
210 |
|
211 error = T1_Err_Ok; |
|
212 } |
|
213 |
|
214 return error; |
|
215 } |
|
216 |
|
217 |
|
218 /*************************************************************************/ |
|
219 /* */ |
|
220 /* Given a normalized (blend) coordinate, figure out the design */ |
|
221 /* coordinate appropriate for that value. */ |
|
222 /* */ |
|
223 FT_LOCAL_DEF( FT_Fixed ) |
|
224 mm_axis_unmap( PS_DesignMap axismap, |
|
225 FT_Fixed ncv ) |
|
226 { |
|
227 int j; |
|
228 |
|
229 |
|
230 if ( ncv <= axismap->blend_points[0] ) |
|
231 return INT_TO_FIXED( axismap->design_points[0] ); |
|
232 |
|
233 for ( j = 1; j < axismap->num_points; ++j ) |
|
234 { |
|
235 if ( ncv <= axismap->blend_points[j] ) |
|
236 { |
|
237 FT_Fixed t = FT_MulDiv( ncv - axismap->blend_points[j - 1], |
|
238 0x10000L, |
|
239 axismap->blend_points[j] - |
|
240 axismap->blend_points[j - 1] ); |
|
241 |
|
242 return INT_TO_FIXED( axismap->design_points[j - 1] ) + |
|
243 FT_MulDiv( t, |
|
244 axismap->design_points[j] - |
|
245 axismap->design_points[j - 1], |
|
246 1L ); |
|
247 } |
|
248 } |
|
249 |
|
250 return INT_TO_FIXED( axismap->design_points[axismap->num_points - 1] ); |
|
251 } |
|
252 |
|
253 |
|
254 /*************************************************************************/ |
|
255 /* */ |
|
256 /* Given a vector of weights, one for each design, figure out the */ |
|
257 /* normalized axis coordinates which gave rise to those weights. */ |
|
258 /* */ |
|
259 FT_LOCAL_DEF( void ) |
|
260 mm_weights_unmap( FT_Fixed* weights, |
|
261 FT_Fixed* axiscoords, |
|
262 FT_UInt axis_count ) |
|
263 { |
|
264 FT_ASSERT( axis_count <= T1_MAX_MM_AXIS ); |
|
265 |
|
266 if ( axis_count == 1 ) |
|
267 axiscoords[0] = weights[1]; |
|
268 |
|
269 else if ( axis_count == 2 ) |
|
270 { |
|
271 axiscoords[0] = weights[3] + weights[1]; |
|
272 axiscoords[1] = weights[3] + weights[2]; |
|
273 } |
|
274 |
|
275 else if ( axis_count == 3 ) |
|
276 { |
|
277 axiscoords[0] = weights[7] + weights[5] + weights[3] + weights[1]; |
|
278 axiscoords[1] = weights[7] + weights[6] + weights[3] + weights[2]; |
|
279 axiscoords[2] = weights[7] + weights[6] + weights[5] + weights[4]; |
|
280 } |
|
281 |
|
282 else |
|
283 { |
|
284 axiscoords[0] = weights[15] + weights[13] + weights[11] + weights[9] + |
|
285 weights[7] + weights[5] + weights[3] + weights[1]; |
|
286 axiscoords[1] = weights[15] + weights[14] + weights[11] + weights[10] + |
|
287 weights[7] + weights[6] + weights[3] + weights[2]; |
|
288 axiscoords[2] = weights[15] + weights[14] + weights[13] + weights[12] + |
|
289 weights[7] + weights[6] + weights[5] + weights[4]; |
|
290 axiscoords[3] = weights[15] + weights[14] + weights[13] + weights[12] + |
|
291 weights[11] + weights[10] + weights[9] + weights[8]; |
|
292 } |
|
293 } |
|
294 |
|
295 |
|
296 /*************************************************************************/ |
|
297 /* */ |
|
298 /* Just a wrapper around T1_Get_Multi_Master to support the different */ |
|
299 /* arguments needed by the GX var distortable fonts. */ |
|
300 /* */ |
|
301 FT_LOCAL_DEF( FT_Error ) |
|
302 T1_Get_MM_Var( T1_Face face, |
|
303 FT_MM_Var* *master ) |
|
304 { |
|
305 FT_Memory memory = face->root.memory; |
|
306 FT_MM_Var *mmvar; |
|
307 FT_Multi_Master mmaster; |
|
308 FT_Error error; |
|
309 FT_UInt i; |
|
310 FT_Fixed axiscoords[T1_MAX_MM_AXIS]; |
|
311 PS_Blend blend = face->blend; |
|
312 |
|
313 |
|
314 error = T1_Get_Multi_Master( face, &mmaster ); |
|
315 if ( error ) |
|
316 goto Exit; |
|
317 if ( FT_ALLOC( mmvar, |
|
318 sizeof ( FT_MM_Var ) + |
|
319 mmaster.num_axis * sizeof ( FT_Var_Axis ) ) ) |
|
320 goto Exit; |
|
321 |
|
322 mmvar->num_axis = mmaster.num_axis; |
|
323 mmvar->num_designs = mmaster.num_designs; |
|
324 mmvar->num_namedstyles = (FT_UInt)-1; /* Does not apply */ |
|
325 mmvar->axis = (FT_Var_Axis*)&mmvar[1]; |
|
326 /* Point to axes after MM_Var struct */ |
|
327 mmvar->namedstyle = NULL; |
|
328 |
|
329 for ( i = 0 ; i < mmaster.num_axis; ++i ) |
|
330 { |
|
331 mmvar->axis[i].name = mmaster.axis[i].name; |
|
332 mmvar->axis[i].minimum = INT_TO_FIXED( mmaster.axis[i].minimum); |
|
333 mmvar->axis[i].maximum = INT_TO_FIXED( mmaster.axis[i].maximum); |
|
334 mmvar->axis[i].def = ( mmvar->axis[i].minimum + |
|
335 mmvar->axis[i].maximum ) / 2; |
|
336 /* Does not apply. But this value is in range */ |
|
337 mmvar->axis[i].strid = (FT_UInt)-1; /* Does not apply */ |
|
338 mmvar->axis[i].tag = (FT_ULong)-1; /* Does not apply */ |
|
339 |
|
340 if ( ft_strcmp( mmvar->axis[i].name, "Weight" ) == 0 ) |
|
341 mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'g', 'h', 't' ); |
|
342 else if ( ft_strcmp( mmvar->axis[i].name, "Width" ) == 0 ) |
|
343 mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'd', 't', 'h' ); |
|
344 else if ( ft_strcmp( mmvar->axis[i].name, "OpticalSize" ) == 0 ) |
|
345 mmvar->axis[i].tag = FT_MAKE_TAG( 'o', 'p', 's', 'z' ); |
|
346 } |
|
347 |
|
348 if ( blend->num_designs == ( 1U << blend->num_axis ) ) |
|
349 { |
|
350 mm_weights_unmap( blend->default_weight_vector, |
|
351 axiscoords, |
|
352 blend->num_axis ); |
|
353 |
|
354 for ( i = 0; i < mmaster.num_axis; ++i ) |
|
355 mmvar->axis[i].def = mm_axis_unmap( &blend->design_map[i], |
|
356 axiscoords[i] ); |
|
357 } |
|
358 |
|
359 *master = mmvar; |
|
360 |
|
361 Exit: |
|
362 return error; |
|
363 } |
|
364 |
|
365 |
|
366 FT_LOCAL_DEF( FT_Error ) |
|
367 T1_Set_MM_Blend( T1_Face face, |
|
368 FT_UInt num_coords, |
|
369 FT_Fixed* coords ) |
|
370 { |
|
371 PS_Blend blend = face->blend; |
|
372 FT_Error error; |
|
373 FT_UInt n, m; |
|
374 |
|
375 |
|
376 error = T1_Err_Invalid_Argument; |
|
377 |
|
378 if ( blend && blend->num_axis == num_coords ) |
|
379 { |
|
380 /* recompute the weight vector from the blend coordinates */ |
|
381 error = T1_Err_Ok; |
|
382 |
|
383 for ( n = 0; n < blend->num_designs; n++ ) |
|
384 { |
|
385 FT_Fixed result = 0x10000L; /* 1.0 fixed */ |
|
386 |
|
387 |
|
388 for ( m = 0; m < blend->num_axis; m++ ) |
|
389 { |
|
390 FT_Fixed factor; |
|
391 |
|
392 |
|
393 /* get current blend axis position */ |
|
394 factor = coords[m]; |
|
395 if ( factor < 0 ) factor = 0; |
|
396 if ( factor > 0x10000L ) factor = 0x10000L; |
|
397 |
|
398 if ( ( n & ( 1 << m ) ) == 0 ) |
|
399 factor = 0x10000L - factor; |
|
400 |
|
401 result = FT_MulFix( result, factor ); |
|
402 } |
|
403 blend->weight_vector[n] = result; |
|
404 } |
|
405 |
|
406 error = T1_Err_Ok; |
|
407 } |
|
408 |
|
409 return error; |
|
410 } |
|
411 |
|
412 |
|
413 FT_LOCAL_DEF( FT_Error ) |
|
414 T1_Set_MM_Design( T1_Face face, |
|
415 FT_UInt num_coords, |
|
416 FT_Long* coords ) |
|
417 { |
|
418 PS_Blend blend = face->blend; |
|
419 FT_Error error; |
|
420 FT_UInt n, p; |
|
421 |
|
422 |
|
423 error = T1_Err_Invalid_Argument; |
|
424 if ( blend && blend->num_axis == num_coords ) |
|
425 { |
|
426 /* compute the blend coordinates through the blend design map */ |
|
427 FT_Fixed final_blends[T1_MAX_MM_DESIGNS]; |
|
428 |
|
429 |
|
430 for ( n = 0; n < blend->num_axis; n++ ) |
|
431 { |
|
432 FT_Long design = coords[n]; |
|
433 FT_Fixed the_blend; |
|
434 PS_DesignMap map = blend->design_map + n; |
|
435 FT_Long* designs = map->design_points; |
|
436 FT_Fixed* blends = map->blend_points; |
|
437 FT_Int before = -1, after = -1; |
|
438 |
|
439 |
|
440 for ( p = 0; p < (FT_UInt)map->num_points; p++ ) |
|
441 { |
|
442 FT_Long p_design = designs[p]; |
|
443 |
|
444 |
|
445 /* exact match? */ |
|
446 if ( design == p_design ) |
|
447 { |
|
448 the_blend = blends[p]; |
|
449 goto Found; |
|
450 } |
|
451 |
|
452 if ( design < p_design ) |
|
453 { |
|
454 after = p; |
|
455 break; |
|
456 } |
|
457 |
|
458 before = p; |
|
459 } |
|
460 |
|
461 /* now interpolate if necessary */ |
|
462 if ( before < 0 ) |
|
463 the_blend = blends[0]; |
|
464 |
|
465 else if ( after < 0 ) |
|
466 the_blend = blends[map->num_points - 1]; |
|
467 |
|
468 else |
|
469 the_blend = FT_MulDiv( design - designs[before], |
|
470 blends [after] - blends [before], |
|
471 designs[after] - designs[before] ); |
|
472 |
|
473 Found: |
|
474 final_blends[n] = the_blend; |
|
475 } |
|
476 |
|
477 error = T1_Set_MM_Blend( face, num_coords, final_blends ); |
|
478 } |
|
479 |
|
480 return error; |
|
481 } |
|
482 |
|
483 |
|
484 /*************************************************************************/ |
|
485 /* */ |
|
486 /* Just a wrapper around T1_Set_MM_Design to support the different */ |
|
487 /* arguments needed by the GX var distortable fonts. */ |
|
488 /* */ |
|
489 FT_LOCAL_DEF( FT_Error ) |
|
490 T1_Set_Var_Design( T1_Face face, |
|
491 FT_UInt num_coords, |
|
492 FT_Fixed* coords ) |
|
493 { |
|
494 FT_Long lcoords[4]; /* maximum axis count is 4 */ |
|
495 FT_UInt i; |
|
496 FT_Error error; |
|
497 |
|
498 |
|
499 error = T1_Err_Invalid_Argument; |
|
500 if ( num_coords <= 4 && num_coords > 0 ) |
|
501 { |
|
502 for ( i = 0; i < num_coords; ++i ) |
|
503 lcoords[i] = FIXED_TO_INT( coords[i] ); |
|
504 error = T1_Set_MM_Design( face, num_coords, lcoords ); |
|
505 } |
|
506 |
|
507 return error; |
|
508 } |
|
509 |
|
510 |
|
511 FT_LOCAL_DEF( void ) |
|
512 T1_Done_Blend( T1_Face face ) |
|
513 { |
|
514 FT_Memory memory = face->root.memory; |
|
515 PS_Blend blend = face->blend; |
|
516 |
|
517 |
|
518 if ( blend ) |
|
519 { |
|
520 FT_UInt num_designs = blend->num_designs; |
|
521 FT_UInt num_axis = blend->num_axis; |
|
522 FT_UInt n; |
|
523 |
|
524 |
|
525 /* release design pos table */ |
|
526 FT_FREE( blend->design_pos[0] ); |
|
527 for ( n = 1; n < num_designs; n++ ) |
|
528 blend->design_pos[n] = 0; |
|
529 |
|
530 /* release blend `private' and `font info' dictionaries */ |
|
531 FT_FREE( blend->privates[1] ); |
|
532 FT_FREE( blend->font_infos[1] ); |
|
533 FT_FREE( blend->bboxes[1] ); |
|
534 |
|
535 for ( n = 0; n < num_designs; n++ ) |
|
536 { |
|
537 blend->privates [n] = 0; |
|
538 blend->font_infos[n] = 0; |
|
539 blend->bboxes [n] = 0; |
|
540 } |
|
541 |
|
542 /* release weight vectors */ |
|
543 FT_FREE( blend->weight_vector ); |
|
544 blend->default_weight_vector = 0; |
|
545 |
|
546 /* release axis names */ |
|
547 for ( n = 0; n < num_axis; n++ ) |
|
548 FT_FREE( blend->axis_names[n] ); |
|
549 |
|
550 /* release design map */ |
|
551 for ( n = 0; n < num_axis; n++ ) |
|
552 { |
|
553 PS_DesignMap dmap = blend->design_map + n; |
|
554 |
|
555 |
|
556 FT_FREE( dmap->design_points ); |
|
557 dmap->num_points = 0; |
|
558 } |
|
559 |
|
560 FT_FREE( face->blend ); |
|
561 } |
|
562 } |
|
563 |
|
564 |
|
565 static void |
|
566 parse_blend_axis_types( T1_Face face, |
|
567 T1_Loader loader ) |
|
568 { |
|
569 T1_TokenRec axis_tokens[T1_MAX_MM_AXIS]; |
|
570 FT_Int n, num_axis; |
|
571 FT_Error error = T1_Err_Ok; |
|
572 PS_Blend blend; |
|
573 FT_Memory memory; |
|
574 |
|
575 |
|
576 /* take an array of objects */ |
|
577 T1_ToTokenArray( &loader->parser, axis_tokens, |
|
578 T1_MAX_MM_AXIS, &num_axis ); |
|
579 if ( num_axis < 0 ) |
|
580 { |
|
581 error = T1_Err_Ignore; |
|
582 goto Exit; |
|
583 } |
|
584 if ( num_axis == 0 || num_axis > T1_MAX_MM_AXIS ) |
|
585 { |
|
586 FT_ERROR(( "parse_blend_axis_types: incorrect number of axes: %d\n", |
|
587 num_axis )); |
|
588 error = T1_Err_Invalid_File_Format; |
|
589 goto Exit; |
|
590 } |
|
591 |
|
592 /* allocate blend if necessary */ |
|
593 error = t1_allocate_blend( face, 0, (FT_UInt)num_axis ); |
|
594 if ( error ) |
|
595 goto Exit; |
|
596 |
|
597 blend = face->blend; |
|
598 memory = face->root.memory; |
|
599 |
|
600 /* each token is an immediate containing the name of the axis */ |
|
601 for ( n = 0; n < num_axis; n++ ) |
|
602 { |
|
603 T1_Token token = axis_tokens + n; |
|
604 FT_Byte* name; |
|
605 FT_PtrDist len; |
|
606 |
|
607 |
|
608 /* skip first slash, if any */ |
|
609 if ( token->start[0] == '/' ) |
|
610 token->start++; |
|
611 |
|
612 len = token->limit - token->start; |
|
613 if ( len == 0 ) |
|
614 { |
|
615 error = T1_Err_Invalid_File_Format; |
|
616 goto Exit; |
|
617 } |
|
618 |
|
619 if ( FT_ALLOC( blend->axis_names[n], len + 1 ) ) |
|
620 goto Exit; |
|
621 |
|
622 name = (FT_Byte*)blend->axis_names[n]; |
|
623 FT_MEM_COPY( name, token->start, len ); |
|
624 name[len] = 0; |
|
625 } |
|
626 |
|
627 Exit: |
|
628 loader->parser.root.error = error; |
|
629 } |
|
630 |
|
631 |
|
632 static void |
|
633 parse_blend_design_positions( T1_Face face, |
|
634 T1_Loader loader ) |
|
635 { |
|
636 T1_TokenRec design_tokens[T1_MAX_MM_DESIGNS]; |
|
637 FT_Int num_designs; |
|
638 FT_Int num_axis; |
|
639 T1_Parser parser = &loader->parser; |
|
640 |
|
641 FT_Error error = T1_Err_Ok; |
|
642 PS_Blend blend; |
|
643 |
|
644 |
|
645 /* get the array of design tokens -- compute number of designs */ |
|
646 T1_ToTokenArray( parser, design_tokens, |
|
647 T1_MAX_MM_DESIGNS, &num_designs ); |
|
648 if ( num_designs < 0 ) |
|
649 { |
|
650 error = T1_Err_Ignore; |
|
651 goto Exit; |
|
652 } |
|
653 if ( num_designs == 0 || num_designs > T1_MAX_MM_DESIGNS ) |
|
654 { |
|
655 FT_ERROR(( "parse_blend_design_positions:" |
|
656 " incorrect number of designs: %d\n", |
|
657 num_designs )); |
|
658 error = T1_Err_Invalid_File_Format; |
|
659 goto Exit; |
|
660 } |
|
661 |
|
662 { |
|
663 FT_Byte* old_cursor = parser->root.cursor; |
|
664 FT_Byte* old_limit = parser->root.limit; |
|
665 FT_Int n; |
|
666 |
|
667 |
|
668 blend = face->blend; |
|
669 num_axis = 0; /* make compiler happy */ |
|
670 |
|
671 for ( n = 0; n < num_designs; n++ ) |
|
672 { |
|
673 T1_TokenRec axis_tokens[T1_MAX_MM_AXIS]; |
|
674 T1_Token token; |
|
675 FT_Int axis, n_axis; |
|
676 |
|
677 |
|
678 /* read axis/coordinates tokens */ |
|
679 token = design_tokens + n; |
|
680 parser->root.cursor = token->start; |
|
681 parser->root.limit = token->limit; |
|
682 T1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &n_axis ); |
|
683 |
|
684 if ( n == 0 ) |
|
685 { |
|
686 if ( n_axis <= 0 || n_axis > T1_MAX_MM_AXIS ) |
|
687 { |
|
688 FT_ERROR(( "parse_blend_design_positions:" |
|
689 " invalid number of axes: %d\n", |
|
690 n_axis )); |
|
691 error = T1_Err_Invalid_File_Format; |
|
692 goto Exit; |
|
693 } |
|
694 |
|
695 num_axis = n_axis; |
|
696 error = t1_allocate_blend( face, num_designs, num_axis ); |
|
697 if ( error ) |
|
698 goto Exit; |
|
699 blend = face->blend; |
|
700 } |
|
701 else if ( n_axis != num_axis ) |
|
702 { |
|
703 FT_ERROR(( "parse_blend_design_positions: incorrect table\n" )); |
|
704 error = T1_Err_Invalid_File_Format; |
|
705 goto Exit; |
|
706 } |
|
707 |
|
708 /* now read each axis token into the design position */ |
|
709 for ( axis = 0; axis < n_axis; axis++ ) |
|
710 { |
|
711 T1_Token token2 = axis_tokens + axis; |
|
712 |
|
713 |
|
714 parser->root.cursor = token2->start; |
|
715 parser->root.limit = token2->limit; |
|
716 blend->design_pos[n][axis] = T1_ToFixed( parser, 0 ); |
|
717 } |
|
718 } |
|
719 |
|
720 loader->parser.root.cursor = old_cursor; |
|
721 loader->parser.root.limit = old_limit; |
|
722 } |
|
723 |
|
724 Exit: |
|
725 loader->parser.root.error = error; |
|
726 } |
|
727 |
|
728 |
|
729 static void |
|
730 parse_blend_design_map( T1_Face face, |
|
731 T1_Loader loader ) |
|
732 { |
|
733 FT_Error error = T1_Err_Ok; |
|
734 T1_Parser parser = &loader->parser; |
|
735 PS_Blend blend; |
|
736 T1_TokenRec axis_tokens[T1_MAX_MM_AXIS]; |
|
737 FT_Int n, num_axis; |
|
738 FT_Byte* old_cursor; |
|
739 FT_Byte* old_limit; |
|
740 FT_Memory memory = face->root.memory; |
|
741 |
|
742 |
|
743 T1_ToTokenArray( parser, axis_tokens, |
|
744 T1_MAX_MM_AXIS, &num_axis ); |
|
745 if ( num_axis < 0 ) |
|
746 { |
|
747 error = T1_Err_Ignore; |
|
748 goto Exit; |
|
749 } |
|
750 if ( num_axis == 0 || num_axis > T1_MAX_MM_AXIS ) |
|
751 { |
|
752 FT_ERROR(( "parse_blend_design_map: incorrect number of axes: %d\n", |
|
753 num_axis )); |
|
754 error = T1_Err_Invalid_File_Format; |
|
755 goto Exit; |
|
756 } |
|
757 |
|
758 old_cursor = parser->root.cursor; |
|
759 old_limit = parser->root.limit; |
|
760 |
|
761 error = t1_allocate_blend( face, 0, num_axis ); |
|
762 if ( error ) |
|
763 goto Exit; |
|
764 blend = face->blend; |
|
765 |
|
766 /* now read each axis design map */ |
|
767 for ( n = 0; n < num_axis; n++ ) |
|
768 { |
|
769 PS_DesignMap map = blend->design_map + n; |
|
770 T1_Token axis_token; |
|
771 T1_TokenRec point_tokens[T1_MAX_MM_MAP_POINTS]; |
|
772 FT_Int p, num_points; |
|
773 |
|
774 |
|
775 axis_token = axis_tokens + n; |
|
776 |
|
777 parser->root.cursor = axis_token->start; |
|
778 parser->root.limit = axis_token->limit; |
|
779 T1_ToTokenArray( parser, point_tokens, |
|
780 T1_MAX_MM_MAP_POINTS, &num_points ); |
|
781 |
|
782 if ( num_points <= 0 || num_points > T1_MAX_MM_MAP_POINTS ) |
|
783 { |
|
784 FT_ERROR(( "parse_blend_design_map: incorrect table\n" )); |
|
785 error = T1_Err_Invalid_File_Format; |
|
786 goto Exit; |
|
787 } |
|
788 |
|
789 /* allocate design map data */ |
|
790 if ( FT_NEW_ARRAY( map->design_points, num_points * 2 ) ) |
|
791 goto Exit; |
|
792 map->blend_points = map->design_points + num_points; |
|
793 map->num_points = (FT_Byte)num_points; |
|
794 |
|
795 for ( p = 0; p < num_points; p++ ) |
|
796 { |
|
797 T1_Token point_token; |
|
798 |
|
799 |
|
800 point_token = point_tokens + p; |
|
801 |
|
802 /* don't include delimiting brackets */ |
|
803 parser->root.cursor = point_token->start + 1; |
|
804 parser->root.limit = point_token->limit - 1; |
|
805 |
|
806 map->design_points[p] = T1_ToInt( parser ); |
|
807 map->blend_points [p] = T1_ToFixed( parser, 0 ); |
|
808 } |
|
809 } |
|
810 |
|
811 parser->root.cursor = old_cursor; |
|
812 parser->root.limit = old_limit; |
|
813 |
|
814 Exit: |
|
815 parser->root.error = error; |
|
816 } |
|
817 |
|
818 |
|
819 static void |
|
820 parse_weight_vector( T1_Face face, |
|
821 T1_Loader loader ) |
|
822 { |
|
823 T1_TokenRec design_tokens[T1_MAX_MM_DESIGNS]; |
|
824 FT_Int num_designs; |
|
825 FT_Error error = T1_Err_Ok; |
|
826 T1_Parser parser = &loader->parser; |
|
827 PS_Blend blend = face->blend; |
|
828 T1_Token token; |
|
829 FT_Int n; |
|
830 FT_Byte* old_cursor; |
|
831 FT_Byte* old_limit; |
|
832 |
|
833 |
|
834 T1_ToTokenArray( parser, design_tokens, |
|
835 T1_MAX_MM_DESIGNS, &num_designs ); |
|
836 if ( num_designs < 0 ) |
|
837 { |
|
838 error = T1_Err_Ignore; |
|
839 goto Exit; |
|
840 } |
|
841 if ( num_designs == 0 || num_designs > T1_MAX_MM_DESIGNS ) |
|
842 { |
|
843 FT_ERROR(( "parse_weight_vector:" |
|
844 " incorrect number of designs: %d\n", |
|
845 num_designs )); |
|
846 error = T1_Err_Invalid_File_Format; |
|
847 goto Exit; |
|
848 } |
|
849 |
|
850 if ( !blend || !blend->num_designs ) |
|
851 { |
|
852 error = t1_allocate_blend( face, num_designs, 0 ); |
|
853 if ( error ) |
|
854 goto Exit; |
|
855 blend = face->blend; |
|
856 } |
|
857 else if ( blend->num_designs != (FT_UInt)num_designs ) |
|
858 { |
|
859 FT_ERROR(( "parse_weight_vector:" |
|
860 " /BlendDesignPosition and /WeightVector have\n" |
|
861 " " |
|
862 " different number of elements\n" )); |
|
863 error = T1_Err_Invalid_File_Format; |
|
864 goto Exit; |
|
865 } |
|
866 |
|
867 old_cursor = parser->root.cursor; |
|
868 old_limit = parser->root.limit; |
|
869 |
|
870 for ( n = 0; n < num_designs; n++ ) |
|
871 { |
|
872 token = design_tokens + n; |
|
873 parser->root.cursor = token->start; |
|
874 parser->root.limit = token->limit; |
|
875 |
|
876 blend->default_weight_vector[n] = |
|
877 blend->weight_vector[n] = T1_ToFixed( parser, 0 ); |
|
878 } |
|
879 |
|
880 parser->root.cursor = old_cursor; |
|
881 parser->root.limit = old_limit; |
|
882 |
|
883 Exit: |
|
884 parser->root.error = error; |
|
885 } |
|
886 |
|
887 |
|
888 /* e.g., /BuildCharArray [0 0 0 0 0 0 0 0] def */ |
|
889 /* we're only interested in the number of array elements */ |
|
890 static void |
|
891 parse_buildchar( T1_Face face, |
|
892 T1_Loader loader ) |
|
893 { |
|
894 face->len_buildchar = T1_ToFixedArray( &loader->parser, 0, NULL, 0 ); |
|
895 |
|
896 return; |
|
897 } |
|
898 |
|
899 |
|
900 #endif /* T1_CONFIG_OPTION_NO_MM_SUPPORT */ |
|
901 |
|
902 |
|
903 |
|
904 |
|
905 /*************************************************************************/ |
|
906 /*************************************************************************/ |
|
907 /***** *****/ |
|
908 /***** TYPE 1 SYMBOL PARSING *****/ |
|
909 /***** *****/ |
|
910 /*************************************************************************/ |
|
911 /*************************************************************************/ |
|
912 |
|
913 static FT_Error |
|
914 t1_load_keyword( T1_Face face, |
|
915 T1_Loader loader, |
|
916 const T1_Field field ) |
|
917 { |
|
918 FT_Error error; |
|
919 void* dummy_object; |
|
920 void** objects; |
|
921 FT_UInt max_objects; |
|
922 PS_Blend blend = face->blend; |
|
923 |
|
924 |
|
925 /* if the keyword has a dedicated callback, call it */ |
|
926 if ( field->type == T1_FIELD_TYPE_CALLBACK ) |
|
927 { |
|
928 field->reader( (FT_Face)face, loader ); |
|
929 error = loader->parser.root.error; |
|
930 goto Exit; |
|
931 } |
|
932 |
|
933 /* now, the keyword is either a simple field, or a table of fields; */ |
|
934 /* we are now going to take care of it */ |
|
935 switch ( field->location ) |
|
936 { |
|
937 case T1_FIELD_LOCATION_FONT_INFO: |
|
938 dummy_object = &face->type1.font_info; |
|
939 objects = &dummy_object; |
|
940 max_objects = 0; |
|
941 |
|
942 if ( blend ) |
|
943 { |
|
944 objects = (void**)blend->font_infos; |
|
945 max_objects = blend->num_designs; |
|
946 } |
|
947 break; |
|
948 |
|
949 case T1_FIELD_LOCATION_FONT_EXTRA: |
|
950 dummy_object = &face->type1.font_extra; |
|
951 objects = &dummy_object; |
|
952 max_objects = 0; |
|
953 break; |
|
954 |
|
955 case T1_FIELD_LOCATION_PRIVATE: |
|
956 dummy_object = &face->type1.private_dict; |
|
957 objects = &dummy_object; |
|
958 max_objects = 0; |
|
959 |
|
960 if ( blend ) |
|
961 { |
|
962 objects = (void**)blend->privates; |
|
963 max_objects = blend->num_designs; |
|
964 } |
|
965 break; |
|
966 |
|
967 case T1_FIELD_LOCATION_BBOX: |
|
968 dummy_object = &face->type1.font_bbox; |
|
969 objects = &dummy_object; |
|
970 max_objects = 0; |
|
971 |
|
972 if ( blend ) |
|
973 { |
|
974 objects = (void**)blend->bboxes; |
|
975 max_objects = blend->num_designs; |
|
976 } |
|
977 break; |
|
978 |
|
979 case T1_FIELD_LOCATION_LOADER: |
|
980 dummy_object = loader; |
|
981 objects = &dummy_object; |
|
982 max_objects = 0; |
|
983 break; |
|
984 |
|
985 case T1_FIELD_LOCATION_FACE: |
|
986 dummy_object = face; |
|
987 objects = &dummy_object; |
|
988 max_objects = 0; |
|
989 break; |
|
990 |
|
991 #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT |
|
992 case T1_FIELD_LOCATION_BLEND: |
|
993 dummy_object = face->blend; |
|
994 objects = &dummy_object; |
|
995 max_objects = 0; |
|
996 break; |
|
997 #endif |
|
998 |
|
999 default: |
|
1000 dummy_object = &face->type1; |
|
1001 objects = &dummy_object; |
|
1002 max_objects = 0; |
|
1003 } |
|
1004 |
|
1005 if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY || |
|
1006 field->type == T1_FIELD_TYPE_FIXED_ARRAY ) |
|
1007 error = T1_Load_Field_Table( &loader->parser, field, |
|
1008 objects, max_objects, 0 ); |
|
1009 else |
|
1010 error = T1_Load_Field( &loader->parser, field, |
|
1011 objects, max_objects, 0 ); |
|
1012 |
|
1013 Exit: |
|
1014 return error; |
|
1015 } |
|
1016 |
|
1017 |
|
1018 static void |
|
1019 parse_private( T1_Face face, |
|
1020 T1_Loader loader ) |
|
1021 { |
|
1022 FT_UNUSED( face ); |
|
1023 |
|
1024 loader->keywords_encountered |= T1_PRIVATE; |
|
1025 } |
|
1026 |
|
1027 |
|
1028 static int |
|
1029 read_binary_data( T1_Parser parser, |
|
1030 FT_Long* size, |
|
1031 FT_Byte** base ) |
|
1032 { |
|
1033 FT_Byte* cur; |
|
1034 FT_Byte* limit = parser->root.limit; |
|
1035 |
|
1036 |
|
1037 /* the binary data has one of the following formats */ |
|
1038 /* */ |
|
1039 /* `size' [white*] RD white ....... ND */ |
|
1040 /* `size' [white*] -| white ....... |- */ |
|
1041 /* */ |
|
1042 |
|
1043 T1_Skip_Spaces( parser ); |
|
1044 |
|
1045 cur = parser->root.cursor; |
|
1046 |
|
1047 if ( cur < limit && ft_isdigit( *cur ) ) |
|
1048 { |
|
1049 FT_Long s = T1_ToInt( parser ); |
|
1050 |
|
1051 |
|
1052 T1_Skip_PS_Token( parser ); /* `RD' or `-|' or something else */ |
|
1053 |
|
1054 /* there is only one whitespace char after the */ |
|
1055 /* `RD' or `-|' token */ |
|
1056 *base = parser->root.cursor + 1; |
|
1057 |
|
1058 if ( s >= 0 && s < limit - *base ) |
|
1059 { |
|
1060 parser->root.cursor += s + 1; |
|
1061 *size = s; |
|
1062 return !parser->root.error; |
|
1063 } |
|
1064 } |
|
1065 |
|
1066 FT_ERROR(( "read_binary_data: invalid size field\n" )); |
|
1067 parser->root.error = T1_Err_Invalid_File_Format; |
|
1068 return 0; |
|
1069 } |
|
1070 |
|
1071 |
|
1072 /* We now define the routines to handle the `/Encoding', `/Subrs', */ |
|
1073 /* and `/CharStrings' dictionaries. */ |
|
1074 |
|
1075 static void |
|
1076 parse_font_matrix( T1_Face face, |
|
1077 T1_Loader loader ) |
|
1078 { |
|
1079 T1_Parser parser = &loader->parser; |
|
1080 FT_Matrix* matrix = &face->type1.font_matrix; |
|
1081 FT_Vector* offset = &face->type1.font_offset; |
|
1082 FT_Face root = (FT_Face)&face->root; |
|
1083 FT_Fixed temp[6]; |
|
1084 FT_Fixed temp_scale; |
|
1085 FT_Int result; |
|
1086 |
|
1087 |
|
1088 result = T1_ToFixedArray( parser, 6, temp, 3 ); |
|
1089 |
|
1090 if ( result < 0 ) |
|
1091 { |
|
1092 parser->root.error = T1_Err_Invalid_File_Format; |
|
1093 return; |
|
1094 } |
|
1095 |
|
1096 temp_scale = FT_ABS( temp[3] ); |
|
1097 |
|
1098 if ( temp_scale == 0 ) |
|
1099 { |
|
1100 FT_ERROR(( "parse_font_matrix: invalid font matrix\n" )); |
|
1101 parser->root.error = T1_Err_Invalid_File_Format; |
|
1102 return; |
|
1103 } |
|
1104 |
|
1105 /* Set Units per EM based on FontMatrix values. We set the value to */ |
|
1106 /* 1000 / temp_scale, because temp_scale was already multiplied by */ |
|
1107 /* 1000 (in t1_tofixed, from psobjs.c). */ |
|
1108 |
|
1109 root->units_per_EM = (FT_UShort)( FT_DivFix( 1000 * 0x10000L, |
|
1110 temp_scale ) >> 16 ); |
|
1111 |
|
1112 /* we need to scale the values by 1.0/temp_scale */ |
|
1113 if ( temp_scale != 0x10000L ) |
|
1114 { |
|
1115 temp[0] = FT_DivFix( temp[0], temp_scale ); |
|
1116 temp[1] = FT_DivFix( temp[1], temp_scale ); |
|
1117 temp[2] = FT_DivFix( temp[2], temp_scale ); |
|
1118 temp[4] = FT_DivFix( temp[4], temp_scale ); |
|
1119 temp[5] = FT_DivFix( temp[5], temp_scale ); |
|
1120 temp[3] = temp[3] < 0 ? -0x10000L : 0x10000L; |
|
1121 } |
|
1122 |
|
1123 matrix->xx = temp[0]; |
|
1124 matrix->yx = temp[1]; |
|
1125 matrix->xy = temp[2]; |
|
1126 matrix->yy = temp[3]; |
|
1127 |
|
1128 /* note that the offsets must be expressed in integer font units */ |
|
1129 offset->x = temp[4] >> 16; |
|
1130 offset->y = temp[5] >> 16; |
|
1131 } |
|
1132 |
|
1133 |
|
1134 static void |
|
1135 parse_encoding( T1_Face face, |
|
1136 T1_Loader loader ) |
|
1137 { |
|
1138 T1_Parser parser = &loader->parser; |
|
1139 FT_Byte* cur; |
|
1140 FT_Byte* limit = parser->root.limit; |
|
1141 |
|
1142 PSAux_Service psaux = (PSAux_Service)face->psaux; |
|
1143 |
|
1144 |
|
1145 T1_Skip_Spaces( parser ); |
|
1146 cur = parser->root.cursor; |
|
1147 if ( cur >= limit ) |
|
1148 { |
|
1149 FT_ERROR(( "parse_encoding: out of bounds\n" )); |
|
1150 parser->root.error = T1_Err_Invalid_File_Format; |
|
1151 return; |
|
1152 } |
|
1153 |
|
1154 /* if we have a number or `[', the encoding is an array, */ |
|
1155 /* and we must load it now */ |
|
1156 if ( ft_isdigit( *cur ) || *cur == '[' ) |
|
1157 { |
|
1158 T1_Encoding encode = &face->type1.encoding; |
|
1159 FT_Int count, n; |
|
1160 PS_Table char_table = &loader->encoding_table; |
|
1161 FT_Memory memory = parser->root.memory; |
|
1162 FT_Error error; |
|
1163 FT_Bool only_immediates = 0; |
|
1164 |
|
1165 |
|
1166 /* read the number of entries in the encoding; should be 256 */ |
|
1167 if ( *cur == '[' ) |
|
1168 { |
|
1169 count = 256; |
|
1170 only_immediates = 1; |
|
1171 parser->root.cursor++; |
|
1172 } |
|
1173 else |
|
1174 count = (FT_Int)T1_ToInt( parser ); |
|
1175 |
|
1176 T1_Skip_Spaces( parser ); |
|
1177 if ( parser->root.cursor >= limit ) |
|
1178 return; |
|
1179 |
|
1180 /* we use a T1_Table to store our charnames */ |
|
1181 loader->num_chars = encode->num_chars = count; |
|
1182 if ( FT_NEW_ARRAY( encode->char_index, count ) || |
|
1183 FT_NEW_ARRAY( encode->char_name, count ) || |
|
1184 FT_SET_ERROR( psaux->ps_table_funcs->init( |
|
1185 char_table, count, memory ) ) ) |
|
1186 { |
|
1187 parser->root.error = error; |
|
1188 return; |
|
1189 } |
|
1190 |
|
1191 /* We need to `zero' out encoding_table.elements */ |
|
1192 for ( n = 0; n < count; n++ ) |
|
1193 { |
|
1194 char* notdef = (char *)".notdef"; |
|
1195 |
|
1196 |
|
1197 T1_Add_Table( char_table, n, notdef, 8 ); |
|
1198 } |
|
1199 |
|
1200 /* Now we need to read records of the form */ |
|
1201 /* */ |
|
1202 /* ... charcode /charname ... */ |
|
1203 /* */ |
|
1204 /* for each entry in our table. */ |
|
1205 /* */ |
|
1206 /* We simply look for a number followed by an immediate */ |
|
1207 /* name. Note that this ignores correctly the sequence */ |
|
1208 /* that is often seen in type1 fonts: */ |
|
1209 /* */ |
|
1210 /* 0 1 255 { 1 index exch /.notdef put } for dup */ |
|
1211 /* */ |
|
1212 /* used to clean the encoding array before anything else. */ |
|
1213 /* */ |
|
1214 /* Alternatively, if the array is directly given as */ |
|
1215 /* */ |
|
1216 /* /Encoding [ ... ] */ |
|
1217 /* */ |
|
1218 /* we only read immediates. */ |
|
1219 |
|
1220 n = 0; |
|
1221 T1_Skip_Spaces( parser ); |
|
1222 |
|
1223 while ( parser->root.cursor < limit ) |
|
1224 { |
|
1225 cur = parser->root.cursor; |
|
1226 |
|
1227 /* we stop when we encounter a `def' or `]' */ |
|
1228 if ( *cur == 'd' && cur + 3 < limit ) |
|
1229 { |
|
1230 if ( cur[1] == 'e' && |
|
1231 cur[2] == 'f' && |
|
1232 IS_PS_DELIM( cur[3] ) ) |
|
1233 { |
|
1234 FT_TRACE6(( "encoding end\n" )); |
|
1235 cur += 3; |
|
1236 break; |
|
1237 } |
|
1238 } |
|
1239 if ( *cur == ']' ) |
|
1240 { |
|
1241 FT_TRACE6(( "encoding end\n" )); |
|
1242 cur++; |
|
1243 break; |
|
1244 } |
|
1245 |
|
1246 /* check whether we've found an entry */ |
|
1247 if ( ft_isdigit( *cur ) || only_immediates ) |
|
1248 { |
|
1249 FT_Int charcode; |
|
1250 |
|
1251 |
|
1252 if ( only_immediates ) |
|
1253 charcode = n; |
|
1254 else |
|
1255 { |
|
1256 charcode = (FT_Int)T1_ToInt( parser ); |
|
1257 T1_Skip_Spaces( parser ); |
|
1258 } |
|
1259 |
|
1260 cur = parser->root.cursor; |
|
1261 |
|
1262 if ( *cur == '/' && cur + 2 < limit && n < count ) |
|
1263 { |
|
1264 FT_PtrDist len; |
|
1265 |
|
1266 |
|
1267 cur++; |
|
1268 |
|
1269 parser->root.cursor = cur; |
|
1270 T1_Skip_PS_Token( parser ); |
|
1271 if ( parser->root.error ) |
|
1272 return; |
|
1273 |
|
1274 len = parser->root.cursor - cur; |
|
1275 |
|
1276 parser->root.error = T1_Add_Table( char_table, charcode, |
|
1277 cur, len + 1 ); |
|
1278 if ( parser->root.error ) |
|
1279 return; |
|
1280 char_table->elements[charcode][len] = '\0'; |
|
1281 |
|
1282 n++; |
|
1283 } |
|
1284 else if ( only_immediates ) |
|
1285 { |
|
1286 /* Since the current position is not updated for */ |
|
1287 /* immediates-only mode we would get an infinite loop if */ |
|
1288 /* we don't do anything here. */ |
|
1289 /* */ |
|
1290 /* This encoding array is not valid according to the type1 */ |
|
1291 /* specification (it might be an encoding for a CID type1 */ |
|
1292 /* font, however), so we conclude that this font is NOT a */ |
|
1293 /* type1 font. */ |
|
1294 parser->root.error = FT_Err_Unknown_File_Format; |
|
1295 return; |
|
1296 } |
|
1297 } |
|
1298 else |
|
1299 { |
|
1300 T1_Skip_PS_Token( parser ); |
|
1301 if ( parser->root.error ) |
|
1302 return; |
|
1303 } |
|
1304 |
|
1305 T1_Skip_Spaces( parser ); |
|
1306 } |
|
1307 |
|
1308 face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY; |
|
1309 parser->root.cursor = cur; |
|
1310 } |
|
1311 |
|
1312 /* Otherwise, we should have either `StandardEncoding', */ |
|
1313 /* `ExpertEncoding', or `ISOLatin1Encoding' */ |
|
1314 else |
|
1315 { |
|
1316 if ( cur + 17 < limit && |
|
1317 ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 ) |
|
1318 face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD; |
|
1319 |
|
1320 else if ( cur + 15 < limit && |
|
1321 ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 ) |
|
1322 face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT; |
|
1323 |
|
1324 else if ( cur + 18 < limit && |
|
1325 ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 ) |
|
1326 face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1; |
|
1327 |
|
1328 else |
|
1329 parser->root.error = T1_Err_Ignore; |
|
1330 } |
|
1331 } |
|
1332 |
|
1333 |
|
1334 static void |
|
1335 parse_subrs( T1_Face face, |
|
1336 T1_Loader loader ) |
|
1337 { |
|
1338 T1_Parser parser = &loader->parser; |
|
1339 PS_Table table = &loader->subrs; |
|
1340 FT_Memory memory = parser->root.memory; |
|
1341 FT_Error error; |
|
1342 FT_Int num_subrs; |
|
1343 |
|
1344 PSAux_Service psaux = (PSAux_Service)face->psaux; |
|
1345 |
|
1346 |
|
1347 T1_Skip_Spaces( parser ); |
|
1348 |
|
1349 /* test for empty array */ |
|
1350 if ( parser->root.cursor < parser->root.limit && |
|
1351 *parser->root.cursor == '[' ) |
|
1352 { |
|
1353 T1_Skip_PS_Token( parser ); |
|
1354 T1_Skip_Spaces ( parser ); |
|
1355 if ( parser->root.cursor >= parser->root.limit || |
|
1356 *parser->root.cursor != ']' ) |
|
1357 parser->root.error = T1_Err_Invalid_File_Format; |
|
1358 return; |
|
1359 } |
|
1360 |
|
1361 num_subrs = (FT_Int)T1_ToInt( parser ); |
|
1362 |
|
1363 /* position the parser right before the `dup' of the first subr */ |
|
1364 T1_Skip_PS_Token( parser ); /* `array' */ |
|
1365 if ( parser->root.error ) |
|
1366 return; |
|
1367 T1_Skip_Spaces( parser ); |
|
1368 |
|
1369 /* initialize subrs array -- with synthetic fonts it is possible */ |
|
1370 /* we get here twice */ |
|
1371 if ( !loader->num_subrs ) |
|
1372 { |
|
1373 error = psaux->ps_table_funcs->init( table, num_subrs, memory ); |
|
1374 if ( error ) |
|
1375 goto Fail; |
|
1376 } |
|
1377 |
|
1378 /* the format is simple: */ |
|
1379 /* */ |
|
1380 /* `index' + binary data */ |
|
1381 /* */ |
|
1382 for (;;) |
|
1383 { |
|
1384 FT_Long idx, size; |
|
1385 FT_Byte* base; |
|
1386 |
|
1387 |
|
1388 /* If the next token isn't `dup' we are done. */ |
|
1389 if ( ft_strncmp( (char*)parser->root.cursor, "dup", 3 ) != 0 ) |
|
1390 break; |
|
1391 |
|
1392 T1_Skip_PS_Token( parser ); /* `dup' */ |
|
1393 |
|
1394 idx = T1_ToInt( parser ); |
|
1395 |
|
1396 if ( !read_binary_data( parser, &size, &base ) ) |
|
1397 return; |
|
1398 |
|
1399 /* The binary string is followed by one token, e.g. `NP' */ |
|
1400 /* (bound to `noaccess put') or by two separate tokens: */ |
|
1401 /* `noaccess' & `put'. We position the parser right */ |
|
1402 /* before the next `dup', if any. */ |
|
1403 T1_Skip_PS_Token( parser ); /* `NP' or `|' or `noaccess' */ |
|
1404 if ( parser->root.error ) |
|
1405 return; |
|
1406 T1_Skip_Spaces ( parser ); |
|
1407 |
|
1408 if ( ft_strncmp( (char*)parser->root.cursor, "put", 3 ) == 0 ) |
|
1409 { |
|
1410 T1_Skip_PS_Token( parser ); /* skip `put' */ |
|
1411 T1_Skip_Spaces ( parser ); |
|
1412 } |
|
1413 |
|
1414 /* with synthetic fonts it is possible we get here twice */ |
|
1415 if ( loader->num_subrs ) |
|
1416 continue; |
|
1417 |
|
1418 /* some fonts use a value of -1 for lenIV to indicate that */ |
|
1419 /* the charstrings are unencoded */ |
|
1420 /* */ |
|
1421 /* thanks to Tom Kacvinsky for pointing this out */ |
|
1422 /* */ |
|
1423 if ( face->type1.private_dict.lenIV >= 0 ) |
|
1424 { |
|
1425 FT_Byte* temp; |
|
1426 |
|
1427 |
|
1428 /* some fonts define empty subr records -- this is not totally */ |
|
1429 /* compliant to the specification (which says they should at */ |
|
1430 /* least contain a `return'), but we support them anyway */ |
|
1431 if ( size < face->type1.private_dict.lenIV ) |
|
1432 { |
|
1433 error = T1_Err_Invalid_File_Format; |
|
1434 goto Fail; |
|
1435 } |
|
1436 |
|
1437 /* t1_decrypt() shouldn't write to base -- make temporary copy */ |
|
1438 if ( FT_ALLOC( temp, size ) ) |
|
1439 goto Fail; |
|
1440 FT_MEM_COPY( temp, base, size ); |
|
1441 psaux->t1_decrypt( temp, size, 4330 ); |
|
1442 size -= face->type1.private_dict.lenIV; |
|
1443 error = T1_Add_Table( table, (FT_Int)idx, |
|
1444 temp + face->type1.private_dict.lenIV, size ); |
|
1445 FT_FREE( temp ); |
|
1446 } |
|
1447 else |
|
1448 error = T1_Add_Table( table, (FT_Int)idx, base, size ); |
|
1449 if ( error ) |
|
1450 goto Fail; |
|
1451 } |
|
1452 |
|
1453 if ( !loader->num_subrs ) |
|
1454 loader->num_subrs = num_subrs; |
|
1455 |
|
1456 return; |
|
1457 |
|
1458 Fail: |
|
1459 parser->root.error = error; |
|
1460 } |
|
1461 |
|
1462 |
|
1463 #define TABLE_EXTEND 5 |
|
1464 |
|
1465 |
|
1466 static void |
|
1467 parse_charstrings( T1_Face face, |
|
1468 T1_Loader loader ) |
|
1469 { |
|
1470 T1_Parser parser = &loader->parser; |
|
1471 PS_Table code_table = &loader->charstrings; |
|
1472 PS_Table name_table = &loader->glyph_names; |
|
1473 PS_Table swap_table = &loader->swap_table; |
|
1474 FT_Memory memory = parser->root.memory; |
|
1475 FT_Error error; |
|
1476 |
|
1477 PSAux_Service psaux = (PSAux_Service)face->psaux; |
|
1478 |
|
1479 FT_Byte* cur; |
|
1480 FT_Byte* limit = parser->root.limit; |
|
1481 FT_Int n, num_glyphs; |
|
1482 FT_UInt notdef_index = 0; |
|
1483 FT_Byte notdef_found = 0; |
|
1484 |
|
1485 |
|
1486 num_glyphs = (FT_Int)T1_ToInt( parser ); |
|
1487 /* some fonts like Optima-Oblique not only define the /CharStrings */ |
|
1488 /* array but access it also */ |
|
1489 if ( num_glyphs == 0 || parser->root.error ) |
|
1490 return; |
|
1491 |
|
1492 /* initialize tables, leaving space for addition of .notdef, */ |
|
1493 /* if necessary, and a few other glyphs to handle buggy */ |
|
1494 /* fonts which have more glyphs than specified. */ |
|
1495 |
|
1496 /* for some non-standard fonts like `Optima' which provides */ |
|
1497 /* different outlines depending on the resolution it is */ |
|
1498 /* possible to get here twice */ |
|
1499 if ( !loader->num_glyphs ) |
|
1500 { |
|
1501 error = psaux->ps_table_funcs->init( |
|
1502 code_table, num_glyphs + 1 + TABLE_EXTEND, memory ); |
|
1503 if ( error ) |
|
1504 goto Fail; |
|
1505 |
|
1506 error = psaux->ps_table_funcs->init( |
|
1507 name_table, num_glyphs + 1 + TABLE_EXTEND, memory ); |
|
1508 if ( error ) |
|
1509 goto Fail; |
|
1510 |
|
1511 /* Initialize table for swapping index notdef_index and */ |
|
1512 /* index 0 names and codes (if necessary). */ |
|
1513 |
|
1514 error = psaux->ps_table_funcs->init( swap_table, 4, memory ); |
|
1515 if ( error ) |
|
1516 goto Fail; |
|
1517 } |
|
1518 |
|
1519 n = 0; |
|
1520 |
|
1521 for (;;) |
|
1522 { |
|
1523 FT_Long size; |
|
1524 FT_Byte* base; |
|
1525 |
|
1526 |
|
1527 /* the format is simple: */ |
|
1528 /* `/glyphname' + binary data */ |
|
1529 |
|
1530 T1_Skip_Spaces( parser ); |
|
1531 |
|
1532 cur = parser->root.cursor; |
|
1533 if ( cur >= limit ) |
|
1534 break; |
|
1535 |
|
1536 /* we stop when we find a `def' or `end' keyword */ |
|
1537 if ( cur + 3 < limit && IS_PS_DELIM( cur[3] ) ) |
|
1538 { |
|
1539 if ( cur[0] == 'd' && |
|
1540 cur[1] == 'e' && |
|
1541 cur[2] == 'f' ) |
|
1542 { |
|
1543 /* There are fonts which have this: */ |
|
1544 /* */ |
|
1545 /* /CharStrings 118 dict def */ |
|
1546 /* Private begin */ |
|
1547 /* CharStrings begin */ |
|
1548 /* ... */ |
|
1549 /* */ |
|
1550 /* To catch this we ignore `def' if */ |
|
1551 /* no charstring has actually been */ |
|
1552 /* seen. */ |
|
1553 if ( n ) |
|
1554 break; |
|
1555 } |
|
1556 |
|
1557 if ( cur[0] == 'e' && |
|
1558 cur[1] == 'n' && |
|
1559 cur[2] == 'd' ) |
|
1560 break; |
|
1561 } |
|
1562 |
|
1563 T1_Skip_PS_Token( parser ); |
|
1564 if ( parser->root.error ) |
|
1565 return; |
|
1566 |
|
1567 if ( *cur == '/' ) |
|
1568 { |
|
1569 FT_PtrDist len; |
|
1570 |
|
1571 |
|
1572 if ( cur + 1 >= limit ) |
|
1573 { |
|
1574 error = T1_Err_Invalid_File_Format; |
|
1575 goto Fail; |
|
1576 } |
|
1577 |
|
1578 cur++; /* skip `/' */ |
|
1579 len = parser->root.cursor - cur; |
|
1580 |
|
1581 if ( !read_binary_data( parser, &size, &base ) ) |
|
1582 return; |
|
1583 |
|
1584 /* for some non-standard fonts like `Optima' which provides */ |
|
1585 /* different outlines depending on the resolution it is */ |
|
1586 /* possible to get here twice */ |
|
1587 if ( loader->num_glyphs ) |
|
1588 continue; |
|
1589 |
|
1590 error = T1_Add_Table( name_table, n, cur, len + 1 ); |
|
1591 if ( error ) |
|
1592 goto Fail; |
|
1593 |
|
1594 /* add a trailing zero to the name table */ |
|
1595 name_table->elements[n][len] = '\0'; |
|
1596 |
|
1597 /* record index of /.notdef */ |
|
1598 if ( *cur == '.' && |
|
1599 ft_strcmp( ".notdef", |
|
1600 (const char*)(name_table->elements[n]) ) == 0 ) |
|
1601 { |
|
1602 notdef_index = n; |
|
1603 notdef_found = 1; |
|
1604 } |
|
1605 |
|
1606 if ( face->type1.private_dict.lenIV >= 0 && |
|
1607 n < num_glyphs + TABLE_EXTEND ) |
|
1608 { |
|
1609 FT_Byte* temp; |
|
1610 |
|
1611 |
|
1612 if ( size <= face->type1.private_dict.lenIV ) |
|
1613 { |
|
1614 error = T1_Err_Invalid_File_Format; |
|
1615 goto Fail; |
|
1616 } |
|
1617 |
|
1618 /* t1_decrypt() shouldn't write to base -- make temporary copy */ |
|
1619 if ( FT_ALLOC( temp, size ) ) |
|
1620 goto Fail; |
|
1621 FT_MEM_COPY( temp, base, size ); |
|
1622 psaux->t1_decrypt( temp, size, 4330 ); |
|
1623 size -= face->type1.private_dict.lenIV; |
|
1624 error = T1_Add_Table( code_table, n, |
|
1625 temp + face->type1.private_dict.lenIV, size ); |
|
1626 FT_FREE( temp ); |
|
1627 } |
|
1628 else |
|
1629 error = T1_Add_Table( code_table, n, base, size ); |
|
1630 if ( error ) |
|
1631 goto Fail; |
|
1632 |
|
1633 n++; |
|
1634 } |
|
1635 } |
|
1636 |
|
1637 loader->num_glyphs = n; |
|
1638 |
|
1639 /* if /.notdef is found but does not occupy index 0, do our magic. */ |
|
1640 if ( notdef_found && |
|
1641 ft_strcmp( ".notdef", (const char*)name_table->elements[0] ) ) |
|
1642 { |
|
1643 /* Swap glyph in index 0 with /.notdef glyph. First, add index 0 */ |
|
1644 /* name and code entries to swap_table. Then place notdef_index */ |
|
1645 /* name and code entries into swap_table. Then swap name and code */ |
|
1646 /* entries at indices notdef_index and 0 using values stored in */ |
|
1647 /* swap_table. */ |
|
1648 |
|
1649 /* Index 0 name */ |
|
1650 error = T1_Add_Table( swap_table, 0, |
|
1651 name_table->elements[0], |
|
1652 name_table->lengths [0] ); |
|
1653 if ( error ) |
|
1654 goto Fail; |
|
1655 |
|
1656 /* Index 0 code */ |
|
1657 error = T1_Add_Table( swap_table, 1, |
|
1658 code_table->elements[0], |
|
1659 code_table->lengths [0] ); |
|
1660 if ( error ) |
|
1661 goto Fail; |
|
1662 |
|
1663 /* Index notdef_index name */ |
|
1664 error = T1_Add_Table( swap_table, 2, |
|
1665 name_table->elements[notdef_index], |
|
1666 name_table->lengths [notdef_index] ); |
|
1667 if ( error ) |
|
1668 goto Fail; |
|
1669 |
|
1670 /* Index notdef_index code */ |
|
1671 error = T1_Add_Table( swap_table, 3, |
|
1672 code_table->elements[notdef_index], |
|
1673 code_table->lengths [notdef_index] ); |
|
1674 if ( error ) |
|
1675 goto Fail; |
|
1676 |
|
1677 error = T1_Add_Table( name_table, notdef_index, |
|
1678 swap_table->elements[0], |
|
1679 swap_table->lengths [0] ); |
|
1680 if ( error ) |
|
1681 goto Fail; |
|
1682 |
|
1683 error = T1_Add_Table( code_table, notdef_index, |
|
1684 swap_table->elements[1], |
|
1685 swap_table->lengths [1] ); |
|
1686 if ( error ) |
|
1687 goto Fail; |
|
1688 |
|
1689 error = T1_Add_Table( name_table, 0, |
|
1690 swap_table->elements[2], |
|
1691 swap_table->lengths [2] ); |
|
1692 if ( error ) |
|
1693 goto Fail; |
|
1694 |
|
1695 error = T1_Add_Table( code_table, 0, |
|
1696 swap_table->elements[3], |
|
1697 swap_table->lengths [3] ); |
|
1698 if ( error ) |
|
1699 goto Fail; |
|
1700 |
|
1701 } |
|
1702 else if ( !notdef_found ) |
|
1703 { |
|
1704 /* notdef_index is already 0, or /.notdef is undefined in */ |
|
1705 /* charstrings dictionary. Worry about /.notdef undefined. */ |
|
1706 /* We take index 0 and add it to the end of the table(s) */ |
|
1707 /* and add our own /.notdef glyph to index 0. */ |
|
1708 |
|
1709 /* 0 333 hsbw endchar */ |
|
1710 FT_Byte notdef_glyph[] = { 0x8B, 0xF7, 0xE1, 0x0D, 0x0E }; |
|
1711 char* notdef_name = (char *)".notdef"; |
|
1712 |
|
1713 |
|
1714 error = T1_Add_Table( swap_table, 0, |
|
1715 name_table->elements[0], |
|
1716 name_table->lengths [0] ); |
|
1717 if ( error ) |
|
1718 goto Fail; |
|
1719 |
|
1720 error = T1_Add_Table( swap_table, 1, |
|
1721 code_table->elements[0], |
|
1722 code_table->lengths [0] ); |
|
1723 if ( error ) |
|
1724 goto Fail; |
|
1725 |
|
1726 error = T1_Add_Table( name_table, 0, notdef_name, 8 ); |
|
1727 if ( error ) |
|
1728 goto Fail; |
|
1729 |
|
1730 error = T1_Add_Table( code_table, 0, notdef_glyph, 5 ); |
|
1731 |
|
1732 if ( error ) |
|
1733 goto Fail; |
|
1734 |
|
1735 error = T1_Add_Table( name_table, n, |
|
1736 swap_table->elements[0], |
|
1737 swap_table->lengths [0] ); |
|
1738 if ( error ) |
|
1739 goto Fail; |
|
1740 |
|
1741 error = T1_Add_Table( code_table, n, |
|
1742 swap_table->elements[1], |
|
1743 swap_table->lengths [1] ); |
|
1744 if ( error ) |
|
1745 goto Fail; |
|
1746 |
|
1747 /* we added a glyph. */ |
|
1748 loader->num_glyphs += 1; |
|
1749 } |
|
1750 |
|
1751 return; |
|
1752 |
|
1753 Fail: |
|
1754 parser->root.error = error; |
|
1755 } |
|
1756 |
|
1757 |
|
1758 /*************************************************************************/ |
|
1759 /* */ |
|
1760 /* Define the token field static variables. This is a set of */ |
|
1761 /* T1_FieldRec variables. */ |
|
1762 /* */ |
|
1763 /*************************************************************************/ |
|
1764 |
|
1765 |
|
1766 static |
|
1767 const T1_FieldRec t1_keywords[] = |
|
1768 { |
|
1769 |
|
1770 #include "t1tokens.h" |
|
1771 |
|
1772 /* now add the special functions... */ |
|
1773 T1_FIELD_CALLBACK( "FontMatrix", parse_font_matrix, |
|
1774 T1_FIELD_DICT_FONTDICT ) |
|
1775 T1_FIELD_CALLBACK( "Encoding", parse_encoding, |
|
1776 T1_FIELD_DICT_FONTDICT ) |
|
1777 T1_FIELD_CALLBACK( "Subrs", parse_subrs, |
|
1778 T1_FIELD_DICT_PRIVATE ) |
|
1779 T1_FIELD_CALLBACK( "CharStrings", parse_charstrings, |
|
1780 T1_FIELD_DICT_PRIVATE ) |
|
1781 T1_FIELD_CALLBACK( "Private", parse_private, |
|
1782 T1_FIELD_DICT_FONTDICT ) |
|
1783 |
|
1784 #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT |
|
1785 T1_FIELD_CALLBACK( "BlendDesignPositions", parse_blend_design_positions, |
|
1786 T1_FIELD_DICT_FONTDICT ) |
|
1787 T1_FIELD_CALLBACK( "BlendDesignMap", parse_blend_design_map, |
|
1788 T1_FIELD_DICT_FONTDICT ) |
|
1789 T1_FIELD_CALLBACK( "BlendAxisTypes", parse_blend_axis_types, |
|
1790 T1_FIELD_DICT_FONTDICT ) |
|
1791 T1_FIELD_CALLBACK( "WeightVector", parse_weight_vector, |
|
1792 T1_FIELD_DICT_FONTDICT ) |
|
1793 T1_FIELD_CALLBACK( "BuildCharArray", parse_buildchar, |
|
1794 T1_FIELD_DICT_PRIVATE ) |
|
1795 #endif |
|
1796 |
|
1797 { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0, 0 } |
|
1798 }; |
|
1799 |
|
1800 |
|
1801 #define T1_FIELD_COUNT \ |
|
1802 ( sizeof ( t1_keywords ) / sizeof ( t1_keywords[0] ) ) |
|
1803 |
|
1804 |
|
1805 static FT_Error |
|
1806 parse_dict( T1_Face face, |
|
1807 T1_Loader loader, |
|
1808 FT_Byte* base, |
|
1809 FT_Long size ) |
|
1810 { |
|
1811 T1_Parser parser = &loader->parser; |
|
1812 FT_Byte *limit, *start_binary = NULL; |
|
1813 FT_Bool have_integer = 0; |
|
1814 |
|
1815 |
|
1816 parser->root.cursor = base; |
|
1817 parser->root.limit = base + size; |
|
1818 parser->root.error = T1_Err_Ok; |
|
1819 |
|
1820 limit = parser->root.limit; |
|
1821 |
|
1822 T1_Skip_Spaces( parser ); |
|
1823 |
|
1824 while ( parser->root.cursor < limit ) |
|
1825 { |
|
1826 FT_Byte* cur; |
|
1827 |
|
1828 |
|
1829 cur = parser->root.cursor; |
|
1830 |
|
1831 /* look for `eexec' */ |
|
1832 if ( IS_PS_TOKEN( cur, limit, "eexec" ) ) |
|
1833 break; |
|
1834 |
|
1835 /* look for `closefile' which ends the eexec section */ |
|
1836 else if ( IS_PS_TOKEN( cur, limit, "closefile" ) ) |
|
1837 break; |
|
1838 |
|
1839 /* in a synthetic font the base font starts after a */ |
|
1840 /* `FontDictionary' token that is placed after a Private dict */ |
|
1841 else if ( IS_PS_TOKEN( cur, limit, "FontDirectory" ) ) |
|
1842 { |
|
1843 if ( loader->keywords_encountered & T1_PRIVATE ) |
|
1844 loader->keywords_encountered |= |
|
1845 T1_FONTDIR_AFTER_PRIVATE; |
|
1846 parser->root.cursor += 13; |
|
1847 } |
|
1848 |
|
1849 /* check whether we have an integer */ |
|
1850 else if ( ft_isdigit( *cur ) ) |
|
1851 { |
|
1852 start_binary = cur; |
|
1853 T1_Skip_PS_Token( parser ); |
|
1854 if ( parser->root.error ) |
|
1855 goto Exit; |
|
1856 have_integer = 1; |
|
1857 } |
|
1858 |
|
1859 /* in valid Type 1 fonts we don't see `RD' or `-|' directly */ |
|
1860 /* since those tokens are handled by parse_subrs and */ |
|
1861 /* parse_charstrings */ |
|
1862 else if ( *cur == 'R' && cur + 6 < limit && *(cur + 1) == 'D' && |
|
1863 have_integer ) |
|
1864 { |
|
1865 FT_Long s; |
|
1866 FT_Byte* b; |
|
1867 |
|
1868 |
|
1869 parser->root.cursor = start_binary; |
|
1870 if ( !read_binary_data( parser, &s, &b ) ) |
|
1871 return T1_Err_Invalid_File_Format; |
|
1872 have_integer = 0; |
|
1873 } |
|
1874 |
|
1875 else if ( *cur == '-' && cur + 6 < limit && *(cur + 1) == '|' && |
|
1876 have_integer ) |
|
1877 { |
|
1878 FT_Long s; |
|
1879 FT_Byte* b; |
|
1880 |
|
1881 |
|
1882 parser->root.cursor = start_binary; |
|
1883 if ( !read_binary_data( parser, &s, &b ) ) |
|
1884 return T1_Err_Invalid_File_Format; |
|
1885 have_integer = 0; |
|
1886 } |
|
1887 |
|
1888 /* look for immediates */ |
|
1889 else if ( *cur == '/' && cur + 2 < limit ) |
|
1890 { |
|
1891 FT_PtrDist len; |
|
1892 |
|
1893 |
|
1894 cur++; |
|
1895 |
|
1896 parser->root.cursor = cur; |
|
1897 T1_Skip_PS_Token( parser ); |
|
1898 if ( parser->root.error ) |
|
1899 goto Exit; |
|
1900 |
|
1901 len = parser->root.cursor - cur; |
|
1902 |
|
1903 if ( len > 0 && len < 22 && parser->root.cursor < limit ) |
|
1904 { |
|
1905 /* now compare the immediate name to the keyword table */ |
|
1906 T1_Field keyword = (T1_Field)t1_keywords; |
|
1907 |
|
1908 |
|
1909 for (;;) |
|
1910 { |
|
1911 FT_Byte* name; |
|
1912 |
|
1913 |
|
1914 name = (FT_Byte*)keyword->ident; |
|
1915 if ( !name ) |
|
1916 break; |
|
1917 |
|
1918 if ( cur[0] == name[0] && |
|
1919 len == (FT_PtrDist)ft_strlen( (const char *)name ) && |
|
1920 ft_memcmp( cur, name, len ) == 0 ) |
|
1921 { |
|
1922 /* We found it -- run the parsing callback! */ |
|
1923 /* We record every instance of every field */ |
|
1924 /* (until we reach the base font of a */ |
|
1925 /* synthetic font) to deal adequately with */ |
|
1926 /* multiple master fonts; this is also */ |
|
1927 /* necessary because later PostScript */ |
|
1928 /* definitions override earlier ones. */ |
|
1929 |
|
1930 /* Once we encounter `FontDirectory' after */ |
|
1931 /* `/Private', we know that this is a synthetic */ |
|
1932 /* font; except for `/CharStrings' we are not */ |
|
1933 /* interested in anything that follows this */ |
|
1934 /* `FontDirectory'. */ |
|
1935 |
|
1936 /* MM fonts have more than one /Private token at */ |
|
1937 /* the top level; let's hope that all the junk */ |
|
1938 /* that follows the first /Private token is not */ |
|
1939 /* interesting to us. */ |
|
1940 |
|
1941 /* According to Adobe Tech Note #5175 (CID-Keyed */ |
|
1942 /* Font Installation for ATM Software) a `begin' */ |
|
1943 /* must be followed by exactly one `end', and */ |
|
1944 /* `begin' -- `end' pairs must be accurately */ |
|
1945 /* paired. We could use this to distinguish */ |
|
1946 /* between the global Private and the Private */ |
|
1947 /* dict that is a member of the Blend dict. */ |
|
1948 |
|
1949 const FT_UInt dict = |
|
1950 ( loader->keywords_encountered & T1_PRIVATE ) |
|
1951 ? T1_FIELD_DICT_PRIVATE |
|
1952 : T1_FIELD_DICT_FONTDICT; |
|
1953 |
|
1954 if ( !( dict & keyword->dict ) ) |
|
1955 { |
|
1956 FT_TRACE1(( "parse_dict: found %s but ignoring it " |
|
1957 "since it is in the wrong dictionary\n", |
|
1958 keyword->ident )); |
|
1959 break; |
|
1960 } |
|
1961 |
|
1962 if ( !( loader->keywords_encountered & |
|
1963 T1_FONTDIR_AFTER_PRIVATE ) || |
|
1964 ft_strcmp( (const char*)name, "CharStrings" ) == 0 ) |
|
1965 { |
|
1966 parser->root.error = t1_load_keyword( face, |
|
1967 loader, |
|
1968 keyword ); |
|
1969 if ( parser->root.error != T1_Err_Ok ) |
|
1970 { |
|
1971 if ( FT_ERROR_BASE( parser->root.error ) == FT_Err_Ignore ) |
|
1972 parser->root.error = T1_Err_Ok; |
|
1973 else |
|
1974 return parser->root.error; |
|
1975 } |
|
1976 } |
|
1977 break; |
|
1978 } |
|
1979 |
|
1980 keyword++; |
|
1981 } |
|
1982 } |
|
1983 |
|
1984 have_integer = 0; |
|
1985 } |
|
1986 else |
|
1987 { |
|
1988 T1_Skip_PS_Token( parser ); |
|
1989 if ( parser->root.error ) |
|
1990 goto Exit; |
|
1991 have_integer = 0; |
|
1992 } |
|
1993 |
|
1994 T1_Skip_Spaces( parser ); |
|
1995 } |
|
1996 |
|
1997 Exit: |
|
1998 return parser->root.error; |
|
1999 } |
|
2000 |
|
2001 |
|
2002 static void |
|
2003 t1_init_loader( T1_Loader loader, |
|
2004 T1_Face face ) |
|
2005 { |
|
2006 FT_UNUSED( face ); |
|
2007 |
|
2008 FT_MEM_ZERO( loader, sizeof ( *loader ) ); |
|
2009 loader->num_glyphs = 0; |
|
2010 loader->num_chars = 0; |
|
2011 |
|
2012 /* initialize the tables -- simply set their `init' field to 0 */ |
|
2013 loader->encoding_table.init = 0; |
|
2014 loader->charstrings.init = 0; |
|
2015 loader->glyph_names.init = 0; |
|
2016 loader->subrs.init = 0; |
|
2017 loader->swap_table.init = 0; |
|
2018 loader->fontdata = 0; |
|
2019 loader->keywords_encountered = 0; |
|
2020 } |
|
2021 |
|
2022 |
|
2023 static void |
|
2024 t1_done_loader( T1_Loader loader ) |
|
2025 { |
|
2026 T1_Parser parser = &loader->parser; |
|
2027 |
|
2028 |
|
2029 /* finalize tables */ |
|
2030 T1_Release_Table( &loader->encoding_table ); |
|
2031 T1_Release_Table( &loader->charstrings ); |
|
2032 T1_Release_Table( &loader->glyph_names ); |
|
2033 T1_Release_Table( &loader->swap_table ); |
|
2034 T1_Release_Table( &loader->subrs ); |
|
2035 |
|
2036 /* finalize parser */ |
|
2037 T1_Finalize_Parser( parser ); |
|
2038 } |
|
2039 |
|
2040 |
|
2041 FT_LOCAL_DEF( FT_Error ) |
|
2042 T1_Open_Face( T1_Face face ) |
|
2043 { |
|
2044 T1_LoaderRec loader; |
|
2045 T1_Parser parser; |
|
2046 T1_Font type1 = &face->type1; |
|
2047 PS_Private priv = &type1->private_dict; |
|
2048 FT_Error error; |
|
2049 |
|
2050 PSAux_Service psaux = (PSAux_Service)face->psaux; |
|
2051 |
|
2052 |
|
2053 t1_init_loader( &loader, face ); |
|
2054 |
|
2055 /* default values */ |
|
2056 face->ndv_idx = -1; |
|
2057 face->cdv_idx = -1; |
|
2058 face->len_buildchar = 0; |
|
2059 |
|
2060 priv->blue_shift = 7; |
|
2061 priv->blue_fuzz = 1; |
|
2062 priv->lenIV = 4; |
|
2063 priv->expansion_factor = (FT_Fixed)( 0.06 * 0x10000L ); |
|
2064 priv->blue_scale = (FT_Fixed)( 0.039625 * 0x10000L * 1000 ); |
|
2065 |
|
2066 parser = &loader.parser; |
|
2067 error = T1_New_Parser( parser, |
|
2068 face->root.stream, |
|
2069 face->root.memory, |
|
2070 psaux ); |
|
2071 if ( error ) |
|
2072 goto Exit; |
|
2073 |
|
2074 error = parse_dict( face, &loader, |
|
2075 parser->base_dict, parser->base_len ); |
|
2076 if ( error ) |
|
2077 goto Exit; |
|
2078 |
|
2079 error = T1_Get_Private_Dict( parser, psaux ); |
|
2080 if ( error ) |
|
2081 goto Exit; |
|
2082 |
|
2083 error = parse_dict( face, &loader, |
|
2084 parser->private_dict, parser->private_len ); |
|
2085 if ( error ) |
|
2086 goto Exit; |
|
2087 |
|
2088 /* ensure even-ness of `num_blue_values' */ |
|
2089 priv->num_blue_values &= ~1; |
|
2090 |
|
2091 #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT |
|
2092 |
|
2093 if ( face->blend && |
|
2094 face->blend->num_default_design_vector != 0 && |
|
2095 face->blend->num_default_design_vector != face->blend->num_axis ) |
|
2096 { |
|
2097 /* we don't use it currently so just warn, reset, and ignore */ |
|
2098 FT_ERROR(( "T1_Open_Face(): /DesignVector contains %u entries " |
|
2099 "while there are %u axes.\n", |
|
2100 face->blend->num_default_design_vector, |
|
2101 face->blend->num_axis )); |
|
2102 |
|
2103 face->blend->num_default_design_vector = 0; |
|
2104 } |
|
2105 |
|
2106 /* the following can happen for MM instances; we then treat the */ |
|
2107 /* font as a normal PS font */ |
|
2108 if ( face->blend && |
|
2109 ( !face->blend->num_designs || !face->blend->num_axis ) ) |
|
2110 T1_Done_Blend( face ); |
|
2111 |
|
2112 /* another safety check */ |
|
2113 if ( face->blend ) |
|
2114 { |
|
2115 FT_UInt i; |
|
2116 |
|
2117 |
|
2118 for ( i = 0; i < face->blend->num_axis; i++ ) |
|
2119 if ( !face->blend->design_map[i].num_points ) |
|
2120 { |
|
2121 T1_Done_Blend( face ); |
|
2122 break; |
|
2123 } |
|
2124 } |
|
2125 |
|
2126 if ( face->blend ) |
|
2127 { |
|
2128 if ( face->len_buildchar > 0 ) |
|
2129 { |
|
2130 FT_Memory memory = face->root.memory; |
|
2131 |
|
2132 |
|
2133 if ( FT_NEW_ARRAY( face->buildchar, face->len_buildchar ) ) |
|
2134 { |
|
2135 FT_ERROR(( "T1_Open_Face: cannot allocate BuildCharArray\n" )); |
|
2136 face->len_buildchar = 0; |
|
2137 goto Exit; |
|
2138 } |
|
2139 } |
|
2140 } |
|
2141 |
|
2142 #endif /* T1_CONFIG_OPTION_NO_MM_SUPPORT */ |
|
2143 |
|
2144 /* now, propagate the subrs, charstrings, and glyphnames tables */ |
|
2145 /* to the Type1 data */ |
|
2146 type1->num_glyphs = loader.num_glyphs; |
|
2147 |
|
2148 if ( loader.subrs.init ) |
|
2149 { |
|
2150 loader.subrs.init = 0; |
|
2151 type1->num_subrs = loader.num_subrs; |
|
2152 type1->subrs_block = loader.subrs.block; |
|
2153 type1->subrs = loader.subrs.elements; |
|
2154 type1->subrs_len = loader.subrs.lengths; |
|
2155 } |
|
2156 |
|
2157 #ifdef FT_CONFIG_OPTION_INCREMENTAL |
|
2158 if ( !face->root.internal->incremental_interface ) |
|
2159 #endif |
|
2160 if ( !loader.charstrings.init ) |
|
2161 { |
|
2162 FT_ERROR(( "T1_Open_Face: no `/CharStrings' array in face\n" )); |
|
2163 error = T1_Err_Invalid_File_Format; |
|
2164 } |
|
2165 |
|
2166 loader.charstrings.init = 0; |
|
2167 type1->charstrings_block = loader.charstrings.block; |
|
2168 type1->charstrings = loader.charstrings.elements; |
|
2169 type1->charstrings_len = loader.charstrings.lengths; |
|
2170 |
|
2171 /* we copy the glyph names `block' and `elements' fields; */ |
|
2172 /* the `lengths' field must be released later */ |
|
2173 type1->glyph_names_block = loader.glyph_names.block; |
|
2174 type1->glyph_names = (FT_String**)loader.glyph_names.elements; |
|
2175 loader.glyph_names.block = 0; |
|
2176 loader.glyph_names.elements = 0; |
|
2177 |
|
2178 /* we must now build type1.encoding when we have a custom array */ |
|
2179 if ( type1->encoding_type == T1_ENCODING_TYPE_ARRAY ) |
|
2180 { |
|
2181 FT_Int charcode, idx, min_char, max_char; |
|
2182 FT_Byte* char_name; |
|
2183 FT_Byte* glyph_name; |
|
2184 |
|
2185 |
|
2186 /* OK, we do the following: for each element in the encoding */ |
|
2187 /* table, look up the index of the glyph having the same name */ |
|
2188 /* the index is then stored in type1.encoding.char_index, and */ |
|
2189 /* the name to type1.encoding.char_name */ |
|
2190 |
|
2191 min_char = 0; |
|
2192 max_char = 0; |
|
2193 |
|
2194 charcode = 0; |
|
2195 for ( ; charcode < loader.encoding_table.max_elems; charcode++ ) |
|
2196 { |
|
2197 type1->encoding.char_index[charcode] = 0; |
|
2198 type1->encoding.char_name [charcode] = (char *)".notdef"; |
|
2199 |
|
2200 char_name = loader.encoding_table.elements[charcode]; |
|
2201 if ( char_name ) |
|
2202 for ( idx = 0; idx < type1->num_glyphs; idx++ ) |
|
2203 { |
|
2204 glyph_name = (FT_Byte*)type1->glyph_names[idx]; |
|
2205 if ( ft_strcmp( (const char*)char_name, |
|
2206 (const char*)glyph_name ) == 0 ) |
|
2207 { |
|
2208 type1->encoding.char_index[charcode] = (FT_UShort)idx; |
|
2209 type1->encoding.char_name [charcode] = (char*)glyph_name; |
|
2210 |
|
2211 /* Change min/max encoded char only if glyph name is */ |
|
2212 /* not /.notdef */ |
|
2213 if ( ft_strcmp( (const char*)".notdef", |
|
2214 (const char*)glyph_name ) != 0 ) |
|
2215 { |
|
2216 if ( charcode < min_char ) |
|
2217 min_char = charcode; |
|
2218 if ( charcode >= max_char ) |
|
2219 max_char = charcode + 1; |
|
2220 } |
|
2221 break; |
|
2222 } |
|
2223 } |
|
2224 } |
|
2225 |
|
2226 type1->encoding.code_first = min_char; |
|
2227 type1->encoding.code_last = max_char; |
|
2228 type1->encoding.num_chars = loader.num_chars; |
|
2229 } |
|
2230 |
|
2231 Exit: |
|
2232 t1_done_loader( &loader ); |
|
2233 return error; |
|
2234 } |
|
2235 |
|
2236 |
|
2237 /* END */ |
|