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