1 | /**************************************************************************** |
2 | * |
3 | * t1load.c |
4 | * |
5 | * Type 1 font loader (body). |
6 | * |
7 | * Copyright (C) 1996-2023 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 <ft2build.h> |
64 | #include <freetype/internal/ftdebug.h> |
65 | #include FT_CONFIG_CONFIG_H |
66 | #include <freetype/ftmm.h> |
67 | #include <freetype/internal/t1types.h> |
68 | #include <freetype/internal/ftcalc.h> |
69 | #include <freetype/internal/fthash.h> |
70 | |
71 | #include "t1load.h" |
72 | #include "t1errors.h" |
73 | |
74 | |
75 | #ifdef FT_CONFIG_OPTION_INCREMENTAL |
76 | #define IS_INCREMENTAL \ |
77 | FT_BOOL( FT_FACE( face )->internal->incremental_interface ) |
78 | #else |
79 | #define IS_INCREMENTAL 0 |
80 | #endif |
81 | |
82 | |
83 | /************************************************************************** |
84 | * |
85 | * The macro FT_COMPONENT is used in trace mode. It is an implicit |
86 | * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log |
87 | * messages during execution. |
88 | */ |
89 | #undef FT_COMPONENT |
90 | #define FT_COMPONENT t1load |
91 | |
92 | |
93 | #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT |
94 | |
95 | |
96 | /*************************************************************************/ |
97 | /*************************************************************************/ |
98 | /***** *****/ |
99 | /***** MULTIPLE MASTERS SUPPORT *****/ |
100 | /***** *****/ |
101 | /*************************************************************************/ |
102 | /*************************************************************************/ |
103 | |
104 | static FT_Error |
105 | t1_allocate_blend( T1_Face face, |
106 | FT_UInt num_designs, |
107 | FT_UInt num_axis ) |
108 | { |
109 | PS_Blend blend; |
110 | FT_Memory memory = face->root.memory; |
111 | FT_Error error = FT_Err_Ok; |
112 | |
113 | |
114 | blend = face->blend; |
115 | if ( !blend ) |
116 | { |
117 | if ( FT_NEW( blend ) ) |
118 | goto Exit; |
119 | |
120 | blend->num_default_design_vector = 0; |
121 | blend->weight_vector = NULL; |
122 | blend->default_weight_vector = NULL; |
123 | blend->design_pos[0] = NULL; |
124 | |
125 | face->blend = blend; |
126 | } |
127 | |
128 | /* allocate design data if needed */ |
129 | if ( num_designs > 0 ) |
130 | { |
131 | if ( blend->num_designs == 0 ) |
132 | { |
133 | FT_UInt nn; |
134 | |
135 | |
136 | /* allocate the blend `private' and `font_info' dictionaries */ |
137 | if ( FT_NEW_ARRAY( blend->font_infos[1], num_designs ) || |
138 | FT_NEW_ARRAY( blend->privates [1], num_designs ) || |
139 | FT_NEW_ARRAY( blend->bboxes [1], num_designs ) ) |
140 | goto Exit; |
141 | |
142 | blend->font_infos[0] = &face->type1.font_info; |
143 | blend->privates [0] = &face->type1.private_dict; |
144 | blend->bboxes [0] = &face->type1.font_bbox; |
145 | |
146 | for ( nn = 2; nn <= num_designs; nn++ ) |
147 | { |
148 | blend->font_infos[nn] = blend->font_infos[nn - 1] + 1; |
149 | blend->privates [nn] = blend->privates [nn - 1] + 1; |
150 | blend->bboxes [nn] = blend->bboxes [nn - 1] + 1; |
151 | } |
152 | |
153 | blend->num_designs = num_designs; |
154 | } |
155 | else if ( blend->num_designs != num_designs ) |
156 | goto Fail; |
157 | } |
158 | |
159 | /* allocate axis data if needed */ |
160 | if ( num_axis > 0 ) |
161 | { |
162 | if ( blend->num_axis != 0 && blend->num_axis != num_axis ) |
163 | goto Fail; |
164 | |
165 | blend->num_axis = num_axis; |
166 | } |
167 | |
168 | Exit: |
169 | return error; |
170 | |
171 | Fail: |
172 | error = FT_THROW( Invalid_File_Format ); |
173 | goto Exit; |
174 | } |
175 | |
176 | |
177 | FT_LOCAL_DEF( FT_Error ) |
178 | T1_Get_Multi_Master( FT_Face face, /* T1_Face */ |
179 | FT_Multi_Master* master ) |
180 | { |
181 | T1_Face t1face = (T1_Face)face; |
182 | PS_Blend blend = t1face->blend; |
183 | FT_UInt n; |
184 | FT_Error error; |
185 | |
186 | |
187 | error = FT_THROW( Invalid_Argument ); |
188 | |
189 | if ( blend ) |
190 | { |
191 | master->num_axis = blend->num_axis; |
192 | master->num_designs = blend->num_designs; |
193 | |
194 | for ( n = 0; n < blend->num_axis; n++ ) |
195 | { |
196 | FT_MM_Axis* axis = master->axis + n; |
197 | PS_DesignMap map = blend->design_map + n; |
198 | |
199 | |
200 | axis->name = blend->axis_names[n]; |
201 | axis->minimum = map->design_points[0]; |
202 | axis->maximum = map->design_points[map->num_points - 1]; |
203 | } |
204 | |
205 | error = FT_Err_Ok; |
206 | } |
207 | |
208 | return error; |
209 | } |
210 | |
211 | |
212 | /************************************************************************** |
213 | * |
214 | * Given a normalized (blend) coordinate, figure out the design |
215 | * coordinate appropriate for that value. |
216 | */ |
217 | static FT_Fixed |
218 | mm_axis_unmap( PS_DesignMap axismap, |
219 | FT_Fixed ncv ) |
220 | { |
221 | int j; |
222 | |
223 | |
224 | if ( ncv <= axismap->blend_points[0] ) |
225 | return INT_TO_FIXED( axismap->design_points[0] ); |
226 | |
227 | for ( j = 1; j < axismap->num_points; j++ ) |
228 | { |
229 | if ( ncv <= axismap->blend_points[j] ) |
230 | return INT_TO_FIXED( axismap->design_points[j - 1] + |
231 | FT_MulDiv( ncv - axismap->blend_points[j - 1], |
232 | axismap->design_points[j] - |
233 | axismap->design_points[j - 1], |
234 | axismap->blend_points[j] - |
235 | axismap->blend_points[j - 1] ) ); |
236 | } |
237 | |
238 | return INT_TO_FIXED( axismap->design_points[axismap->num_points - 1] ); |
239 | } |
240 | |
241 | |
242 | /************************************************************************** |
243 | * |
244 | * Given a vector of weights, one for each design, figure out the |
245 | * normalized axis coordinates which gave rise to those weights. |
246 | */ |
247 | static void |
248 | mm_weights_unmap( FT_Fixed* weights, |
249 | FT_Fixed* axiscoords, |
250 | FT_UInt axis_count ) |
251 | { |
252 | FT_ASSERT( axis_count <= T1_MAX_MM_AXIS ); |
253 | |
254 | if ( axis_count == 1 ) |
255 | axiscoords[0] = weights[1]; |
256 | |
257 | else if ( axis_count == 2 ) |
258 | { |
259 | axiscoords[0] = weights[3] + weights[1]; |
260 | axiscoords[1] = weights[3] + weights[2]; |
261 | } |
262 | |
263 | else if ( axis_count == 3 ) |
264 | { |
265 | axiscoords[0] = weights[7] + weights[5] + weights[3] + weights[1]; |
266 | axiscoords[1] = weights[7] + weights[6] + weights[3] + weights[2]; |
267 | axiscoords[2] = weights[7] + weights[6] + weights[5] + weights[4]; |
268 | } |
269 | |
270 | else |
271 | { |
272 | axiscoords[0] = weights[15] + weights[13] + weights[11] + weights[9] + |
273 | weights[7] + weights[5] + weights[3] + weights[1]; |
274 | axiscoords[1] = weights[15] + weights[14] + weights[11] + weights[10] + |
275 | weights[7] + weights[6] + weights[3] + weights[2]; |
276 | axiscoords[2] = weights[15] + weights[14] + weights[13] + weights[12] + |
277 | weights[7] + weights[6] + weights[5] + weights[4]; |
278 | axiscoords[3] = weights[15] + weights[14] + weights[13] + weights[12] + |
279 | weights[11] + weights[10] + weights[9] + weights[8]; |
280 | } |
281 | } |
282 | |
283 | |
284 | /************************************************************************** |
285 | * |
286 | * Just a wrapper around T1_Get_Multi_Master to support the different |
287 | * arguments needed by the GX var distortable fonts. |
288 | */ |
289 | FT_LOCAL_DEF( FT_Error ) |
290 | T1_Get_MM_Var( FT_Face face, /* T1_Face */ |
291 | FT_MM_Var* *master ) |
292 | { |
293 | T1_Face t1face = (T1_Face)face; |
294 | FT_Memory memory = FT_FACE_MEMORY( face ); |
295 | FT_MM_Var *mmvar = NULL; |
296 | FT_Multi_Master mmaster; |
297 | FT_Error error; |
298 | FT_UInt i; |
299 | FT_Fixed axiscoords[T1_MAX_MM_AXIS]; |
300 | PS_Blend blend = t1face->blend; |
301 | FT_UShort* axis_flags; |
302 | |
303 | FT_Offset mmvar_size; |
304 | FT_Offset axis_flags_size; |
305 | FT_Offset axis_size; |
306 | |
307 | |
308 | error = T1_Get_Multi_Master( face, &mmaster ); |
309 | if ( error ) |
310 | goto Exit; |
311 | |
312 | /* the various `*_size' variables, which we also use as */ |
313 | /* offsets into the `mmvar' array, must be multiples of the */ |
314 | /* pointer size (except the last one); without such an */ |
315 | /* alignment there might be runtime errors due to */ |
316 | /* misaligned addresses */ |
317 | #undef ALIGN_SIZE |
318 | #define ALIGN_SIZE( n ) \ |
319 | ( ( (n) + sizeof (void*) - 1 ) & ~( sizeof (void*) - 1 ) ) |
320 | |
321 | mmvar_size = ALIGN_SIZE( sizeof ( FT_MM_Var ) ); |
322 | axis_flags_size = ALIGN_SIZE( mmaster.num_axis * |
323 | sizeof ( FT_UShort ) ); |
324 | axis_size = mmaster.num_axis * sizeof ( FT_Var_Axis ); |
325 | |
326 | if ( FT_QALLOC( mmvar, mmvar_size + |
327 | axis_flags_size + |
328 | axis_size ) ) |
329 | goto Exit; |
330 | |
331 | mmvar->num_axis = mmaster.num_axis; |
332 | mmvar->num_designs = mmaster.num_designs; |
333 | mmvar->num_namedstyles = 0; /* Not supported */ |
334 | |
335 | /* while axis flags are meaningless here, we have to provide the array */ |
336 | /* to make `FT_Get_Var_Axis_Flags' work: the function expects that the */ |
337 | /* values directly follow the data of `FT_MM_Var' */ |
338 | axis_flags = (FT_UShort*)( (char*)mmvar + mmvar_size ); |
339 | FT_ARRAY_ZERO( axis_flags, mmaster.num_axis ); |
340 | |
341 | mmvar->axis = (FT_Var_Axis*)( (char*)axis_flags + axis_flags_size ); |
342 | mmvar->namedstyle = NULL; |
343 | |
344 | for ( i = 0; i < mmaster.num_axis; i++ ) |
345 | { |
346 | mmvar->axis[i].name = mmaster.axis[i].name; |
347 | mmvar->axis[i].minimum = INT_TO_FIXED( mmaster.axis[i].minimum ); |
348 | mmvar->axis[i].maximum = INT_TO_FIXED( mmaster.axis[i].maximum ); |
349 | mmvar->axis[i].strid = ~0U; /* Does not apply */ |
350 | mmvar->axis[i].tag = ~0U; /* Does not apply */ |
351 | |
352 | if ( !mmvar->axis[i].name ) |
353 | continue; |
354 | |
355 | if ( ft_strcmp( mmvar->axis[i].name, "Weight" ) == 0 ) |
356 | mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'g', 'h', 't' ); |
357 | else if ( ft_strcmp( mmvar->axis[i].name, "Width" ) == 0 ) |
358 | mmvar->axis[i].tag = FT_MAKE_TAG( 'w', 'd', 't', 'h' ); |
359 | else if ( ft_strcmp( mmvar->axis[i].name, "OpticalSize" ) == 0 ) |
360 | mmvar->axis[i].tag = FT_MAKE_TAG( 'o', 'p', 's', 'z' ); |
361 | else if ( ft_strcmp( mmvar->axis[i].name, "Slant" ) == 0 ) |
362 | mmvar->axis[i].tag = FT_MAKE_TAG( 's', 'l', 'n', 't' ); |
363 | else if ( ft_strcmp( mmvar->axis[i].name, "Italic" ) == 0 ) |
364 | mmvar->axis[i].tag = FT_MAKE_TAG( 'i', 't', 'a', 'l' ); |
365 | } |
366 | |
367 | mm_weights_unmap( blend->default_weight_vector, |
368 | axiscoords, |
369 | blend->num_axis ); |
370 | |
371 | for ( i = 0; i < mmaster.num_axis; i++ ) |
372 | mmvar->axis[i].def = mm_axis_unmap( &blend->design_map[i], |
373 | axiscoords[i] ); |
374 | |
375 | *master = mmvar; |
376 | |
377 | Exit: |
378 | return error; |
379 | } |
380 | |
381 | |
382 | static FT_Error |
383 | t1_set_mm_blend( T1_Face face, |
384 | FT_UInt num_coords, |
385 | FT_Fixed* coords ) |
386 | { |
387 | PS_Blend blend = face->blend; |
388 | FT_UInt n, m; |
389 | |
390 | FT_Bool have_diff = 0; |
391 | |
392 | |
393 | if ( !blend ) |
394 | return FT_THROW( Invalid_Argument ); |
395 | |
396 | if ( num_coords > blend->num_axis ) |
397 | num_coords = blend->num_axis; |
398 | |
399 | /* recompute the weight vector from the blend coordinates */ |
400 | for ( n = 0; n < blend->num_designs; n++ ) |
401 | { |
402 | FT_Fixed result = 0x10000L; /* 1.0 fixed */ |
403 | FT_Fixed factor; |
404 | |
405 | |
406 | for ( m = 0; m < blend->num_axis; m++ ) |
407 | { |
408 | /* use a default value if we don't have a coordinate */ |
409 | if ( m >= num_coords ) |
410 | { |
411 | result >>= 1; |
412 | continue; |
413 | } |
414 | |
415 | /* get current blend axis position */ |
416 | factor = coords[m]; |
417 | if ( ( n & ( 1 << m ) ) == 0 ) |
418 | factor = 0x10000L - factor; |
419 | |
420 | if ( factor <= 0 ) |
421 | { |
422 | result = 0; |
423 | break; |
424 | } |
425 | else if ( factor >= 0x10000L ) |
426 | continue; |
427 | |
428 | result = FT_MulFix( result, factor ); |
429 | } |
430 | |
431 | if ( blend->weight_vector[n] != result ) |
432 | { |
433 | blend->weight_vector[n] = result; |
434 | have_diff = 1; |
435 | } |
436 | } |
437 | |
438 | /* return value -1 indicates `no change' */ |
439 | return have_diff ? FT_Err_Ok : -1; |
440 | } |
441 | |
442 | |
443 | FT_LOCAL_DEF( FT_Error ) |
444 | T1_Set_MM_Blend( FT_Face face, /* T1_Face */ |
445 | FT_UInt num_coords, |
446 | FT_Fixed* coords ) |
447 | { |
448 | return t1_set_mm_blend( (T1_Face)face, num_coords, coords ); |
449 | } |
450 | |
451 | |
452 | FT_LOCAL_DEF( FT_Error ) |
453 | T1_Get_MM_Blend( FT_Face face, /* T1_Face */ |
454 | FT_UInt num_coords, |
455 | FT_Fixed* coords ) |
456 | { |
457 | T1_Face t1face = (T1_Face)face; |
458 | PS_Blend blend = t1face->blend; |
459 | |
460 | FT_Fixed axiscoords[4]; |
461 | FT_UInt i, nc; |
462 | |
463 | |
464 | if ( !blend ) |
465 | return FT_THROW( Invalid_Argument ); |
466 | |
467 | mm_weights_unmap( blend->weight_vector, |
468 | axiscoords, |
469 | blend->num_axis ); |
470 | |
471 | nc = num_coords; |
472 | if ( num_coords > blend->num_axis ) |
473 | { |
474 | FT_TRACE2(( "T1_Get_MM_Blend: only using first %d of %d coordinates\n" , |
475 | blend->num_axis, num_coords )); |
476 | nc = blend->num_axis; |
477 | } |
478 | |
479 | for ( i = 0; i < nc; i++ ) |
480 | coords[i] = axiscoords[i]; |
481 | for ( ; i < num_coords; i++ ) |
482 | coords[i] = 0x8000; |
483 | |
484 | return FT_Err_Ok; |
485 | } |
486 | |
487 | |
488 | FT_LOCAL_DEF( FT_Error ) |
489 | T1_Set_MM_WeightVector( FT_Face face, /* T1_Face */ |
490 | FT_UInt len, |
491 | FT_Fixed* weightvector ) |
492 | { |
493 | T1_Face t1face = (T1_Face)face; |
494 | PS_Blend blend = t1face->blend; |
495 | FT_UInt i, n; |
496 | |
497 | |
498 | if ( !blend ) |
499 | return FT_THROW( Invalid_Argument ); |
500 | |
501 | if ( !len && !weightvector ) |
502 | { |
503 | for ( i = 0; i < blend->num_designs; i++ ) |
504 | blend->weight_vector[i] = blend->default_weight_vector[i]; |
505 | } |
506 | else |
507 | { |
508 | if ( !weightvector ) |
509 | return FT_THROW( Invalid_Argument ); |
510 | |
511 | n = len < blend->num_designs ? len : blend->num_designs; |
512 | |
513 | for ( i = 0; i < n; i++ ) |
514 | blend->weight_vector[i] = weightvector[i]; |
515 | |
516 | for ( ; i < blend->num_designs; i++ ) |
517 | blend->weight_vector[i] = (FT_Fixed)0; |
518 | } |
519 | |
520 | return FT_Err_Ok; |
521 | } |
522 | |
523 | |
524 | FT_LOCAL_DEF( FT_Error ) |
525 | T1_Get_MM_WeightVector( FT_Face face, /* T1_Face */ |
526 | FT_UInt* len, |
527 | FT_Fixed* weightvector ) |
528 | { |
529 | T1_Face t1face = (T1_Face)face; |
530 | PS_Blend blend = t1face->blend; |
531 | FT_UInt i; |
532 | |
533 | |
534 | if ( !blend ) |
535 | return FT_THROW( Invalid_Argument ); |
536 | |
537 | if ( *len < blend->num_designs ) |
538 | { |
539 | *len = blend->num_designs; |
540 | return FT_THROW( Invalid_Argument ); |
541 | } |
542 | |
543 | for ( i = 0; i < blend->num_designs; i++ ) |
544 | weightvector[i] = blend->weight_vector[i]; |
545 | for ( ; i < *len; i++ ) |
546 | weightvector[i] = (FT_Fixed)0; |
547 | |
548 | *len = blend->num_designs; |
549 | |
550 | return FT_Err_Ok; |
551 | } |
552 | |
553 | |
554 | FT_LOCAL_DEF( FT_Error ) |
555 | T1_Set_MM_Design( FT_Face face, /* T1_Face */ |
556 | FT_UInt num_coords, |
557 | FT_Long* coords ) |
558 | { |
559 | T1_Face t1face = (T1_Face)face; |
560 | FT_Error error; |
561 | PS_Blend blend = t1face->blend; |
562 | FT_UInt n; |
563 | FT_Fixed final_blends[T1_MAX_MM_DESIGNS]; |
564 | |
565 | |
566 | if ( !blend ) |
567 | return FT_THROW( Invalid_Argument ); |
568 | |
569 | if ( num_coords > blend->num_axis ) |
570 | num_coords = blend->num_axis; |
571 | |
572 | /* compute the blend coordinates through the blend design map */ |
573 | |
574 | for ( n = 0; n < blend->num_axis; n++ ) |
575 | { |
576 | FT_Long design; |
577 | FT_Fixed the_blend; |
578 | PS_DesignMap map = blend->design_map + n; |
579 | FT_Long* designs = map->design_points; |
580 | FT_Fixed* blends = map->blend_points; |
581 | FT_Int p, before = -1, after = -1; |
582 | |
583 | |
584 | /* use a default value if we don't have a coordinate */ |
585 | if ( n < num_coords ) |
586 | design = coords[n]; |
587 | else |
588 | design = ( designs[map->num_points - 1] - designs[0] ) / 2; |
589 | |
590 | for ( p = 0; p < (FT_Int)map->num_points; p++ ) |
591 | { |
592 | FT_Long p_design = designs[p]; |
593 | |
594 | |
595 | /* exact match? */ |
596 | if ( design == p_design ) |
597 | { |
598 | the_blend = blends[p]; |
599 | goto Found; |
600 | } |
601 | |
602 | if ( design < p_design ) |
603 | { |
604 | after = p; |
605 | break; |
606 | } |
607 | |
608 | before = p; |
609 | } |
610 | |
611 | /* now interpolate if necessary */ |
612 | if ( before < 0 ) |
613 | the_blend = blends[0]; |
614 | |
615 | else if ( after < 0 ) |
616 | the_blend = blends[map->num_points - 1]; |
617 | |
618 | else |
619 | the_blend = FT_MulDiv( design - designs[before], |
620 | blends [after] - blends [before], |
621 | designs[after] - designs[before] ); |
622 | |
623 | Found: |
624 | final_blends[n] = the_blend; |
625 | } |
626 | |
627 | error = t1_set_mm_blend( t1face, blend->num_axis, final_blends ); |
628 | if ( error ) |
629 | return error; |
630 | |
631 | return FT_Err_Ok; |
632 | } |
633 | |
634 | |
635 | /* MM fonts don't have named instances, so only the design is reset */ |
636 | |
637 | FT_LOCAL_DEF( FT_Error ) |
638 | T1_Reset_MM_Blend( FT_Face face, |
639 | FT_UInt instance_index ) |
640 | { |
641 | FT_UNUSED( instance_index ); |
642 | |
643 | return T1_Set_MM_Blend( face, 0, NULL ); |
644 | } |
645 | |
646 | |
647 | /************************************************************************** |
648 | * |
649 | * Just a wrapper around T1_Set_MM_Design to support the different |
650 | * arguments needed by the GX var distortable fonts. |
651 | */ |
652 | FT_LOCAL_DEF( FT_Error ) |
653 | T1_Set_Var_Design( FT_Face face, /* T1_Face */ |
654 | FT_UInt num_coords, |
655 | FT_Fixed* coords ) |
656 | { |
657 | FT_Long lcoords[T1_MAX_MM_AXIS]; |
658 | FT_UInt i; |
659 | |
660 | |
661 | if ( num_coords > T1_MAX_MM_AXIS ) |
662 | num_coords = T1_MAX_MM_AXIS; |
663 | |
664 | for ( i = 0; i < num_coords; i++ ) |
665 | lcoords[i] = FIXED_TO_INT( coords[i] ); |
666 | |
667 | return T1_Set_MM_Design( face, num_coords, lcoords ); |
668 | } |
669 | |
670 | |
671 | FT_LOCAL_DEF( FT_Error ) |
672 | T1_Get_Var_Design( FT_Face face, /* T1_Face */ |
673 | FT_UInt num_coords, |
674 | FT_Fixed* coords ) |
675 | { |
676 | T1_Face t1face = (T1_Face)face; |
677 | PS_Blend blend = t1face->blend; |
678 | |
679 | FT_Fixed axiscoords[4]; |
680 | FT_UInt i, nc; |
681 | |
682 | |
683 | if ( !blend ) |
684 | return FT_THROW( Invalid_Argument ); |
685 | |
686 | mm_weights_unmap( blend->weight_vector, |
687 | axiscoords, |
688 | blend->num_axis ); |
689 | |
690 | nc = num_coords; |
691 | if ( num_coords > blend->num_axis ) |
692 | { |
693 | FT_TRACE2(( "T1_Get_Var_Design:" |
694 | " only using first %d of %d coordinates\n" , |
695 | blend->num_axis, num_coords )); |
696 | nc = blend->num_axis; |
697 | } |
698 | |
699 | for ( i = 0; i < nc; i++ ) |
700 | coords[i] = mm_axis_unmap( &blend->design_map[i], axiscoords[i] ); |
701 | for ( ; i < num_coords; i++ ) |
702 | coords[i] = 0; |
703 | |
704 | return FT_Err_Ok; |
705 | } |
706 | |
707 | |
708 | FT_LOCAL_DEF( void ) |
709 | T1_Done_Blend( FT_Face face ) /* T1_Face */ |
710 | { |
711 | T1_Face t1face = (T1_Face)face; |
712 | FT_Memory memory = FT_FACE_MEMORY( face ); |
713 | PS_Blend blend = t1face->blend; |
714 | |
715 | |
716 | if ( blend ) |
717 | { |
718 | FT_UInt num_designs = blend->num_designs; |
719 | FT_UInt num_axis = blend->num_axis; |
720 | FT_UInt n; |
721 | |
722 | |
723 | /* release design pos table */ |
724 | FT_FREE( blend->design_pos[0] ); |
725 | for ( n = 1; n < num_designs; n++ ) |
726 | blend->design_pos[n] = NULL; |
727 | |
728 | /* release blend `private' and `font info' dictionaries */ |
729 | FT_FREE( blend->privates[1] ); |
730 | FT_FREE( blend->font_infos[1] ); |
731 | FT_FREE( blend->bboxes[1] ); |
732 | |
733 | for ( n = 0; n < num_designs; n++ ) |
734 | { |
735 | blend->privates [n] = NULL; |
736 | blend->font_infos[n] = NULL; |
737 | blend->bboxes [n] = NULL; |
738 | } |
739 | |
740 | /* release weight vectors */ |
741 | FT_FREE( blend->weight_vector ); |
742 | blend->default_weight_vector = NULL; |
743 | |
744 | /* release axis names */ |
745 | for ( n = 0; n < num_axis; n++ ) |
746 | FT_FREE( blend->axis_names[n] ); |
747 | |
748 | /* release design map */ |
749 | for ( n = 0; n < num_axis; n++ ) |
750 | { |
751 | PS_DesignMap dmap = blend->design_map + n; |
752 | |
753 | |
754 | FT_FREE( dmap->design_points ); |
755 | dmap->num_points = 0; |
756 | } |
757 | |
758 | FT_FREE( t1face->blend ); |
759 | } |
760 | } |
761 | |
762 | |
763 | static void |
764 | parse_blend_axis_types( FT_Face face, /* T1_Face */ |
765 | void* loader_ ) |
766 | { |
767 | T1_Face t1face = (T1_Face)face; |
768 | T1_Loader loader = (T1_Loader)loader_; |
769 | T1_TokenRec axis_tokens[T1_MAX_MM_AXIS]; |
770 | FT_Int n, num_axis; |
771 | FT_Error error = FT_Err_Ok; |
772 | PS_Blend blend; |
773 | FT_Memory memory = FT_FACE_MEMORY( face ); |
774 | |
775 | |
776 | /* take an array of objects */ |
777 | T1_ToTokenArray( &loader->parser, axis_tokens, |
778 | T1_MAX_MM_AXIS, &num_axis ); |
779 | if ( num_axis < 0 ) |
780 | { |
781 | error = FT_ERR( Ignore ); |
782 | goto Exit; |
783 | } |
784 | if ( num_axis == 0 || num_axis > T1_MAX_MM_AXIS ) |
785 | { |
786 | FT_ERROR(( "parse_blend_axis_types: incorrect number of axes: %d\n" , |
787 | num_axis )); |
788 | error = FT_THROW( Invalid_File_Format ); |
789 | goto Exit; |
790 | } |
791 | |
792 | /* allocate blend if necessary */ |
793 | error = t1_allocate_blend( t1face, 0, (FT_UInt)num_axis ); |
794 | if ( error ) |
795 | goto Exit; |
796 | |
797 | FT_TRACE4(( " [" )); |
798 | |
799 | blend = t1face->blend; |
800 | |
801 | /* each token is an immediate containing the name of the axis */ |
802 | for ( n = 0; n < num_axis; n++ ) |
803 | { |
804 | T1_Token token = axis_tokens + n; |
805 | FT_Byte* name; |
806 | FT_UInt len; |
807 | |
808 | |
809 | /* skip first slash, if any */ |
810 | if ( token->start[0] == '/' ) |
811 | token->start++; |
812 | |
813 | len = (FT_UInt)( token->limit - token->start ); |
814 | if ( len == 0 ) |
815 | { |
816 | error = FT_THROW( Invalid_File_Format ); |
817 | goto Exit; |
818 | } |
819 | |
820 | FT_TRACE4(( " /%.*s" , len, token->start )); |
821 | |
822 | name = (FT_Byte*)blend->axis_names[n]; |
823 | if ( name ) |
824 | { |
825 | FT_TRACE0(( "parse_blend_axis_types:" |
826 | " overwriting axis name `%s' with `%.*s'\n" , |
827 | name, len, token->start )); |
828 | FT_FREE( name ); |
829 | } |
830 | |
831 | if ( FT_QALLOC( blend->axis_names[n], len + 1 ) ) |
832 | goto Exit; |
833 | |
834 | name = (FT_Byte*)blend->axis_names[n]; |
835 | FT_MEM_COPY( name, token->start, len ); |
836 | name[len] = '\0'; |
837 | } |
838 | |
839 | FT_TRACE4(( "]\n" )); |
840 | |
841 | Exit: |
842 | loader->parser.root.error = error; |
843 | } |
844 | |
845 | |
846 | static void |
847 | parse_blend_design_positions( FT_Face face, /* T1_Face */ |
848 | void* loader_ ) |
849 | { |
850 | T1_Face t1face = (T1_Face)face; |
851 | T1_Loader loader = (T1_Loader)loader_; |
852 | T1_TokenRec design_tokens[T1_MAX_MM_DESIGNS]; |
853 | FT_Int num_designs; |
854 | FT_Int num_axis = 0; /* make compiler happy */ |
855 | T1_Parser parser = &loader->parser; |
856 | FT_Memory memory = FT_FACE_MEMORY( face ); |
857 | FT_Error error = FT_Err_Ok; |
858 | FT_Fixed* design_pos[T1_MAX_MM_DESIGNS]; |
859 | |
860 | |
861 | design_pos[0] = NULL; |
862 | |
863 | /* get the array of design tokens -- compute number of designs */ |
864 | T1_ToTokenArray( parser, design_tokens, |
865 | T1_MAX_MM_DESIGNS, &num_designs ); |
866 | if ( num_designs < 0 ) |
867 | { |
868 | error = FT_ERR( Ignore ); |
869 | goto Exit; |
870 | } |
871 | if ( num_designs == 0 || num_designs > T1_MAX_MM_DESIGNS ) |
872 | { |
873 | FT_ERROR(( "parse_blend_design_positions:" |
874 | " incorrect number of designs: %d\n" , |
875 | num_designs )); |
876 | error = FT_THROW( Invalid_File_Format ); |
877 | goto Exit; |
878 | } |
879 | |
880 | { |
881 | FT_Byte* old_cursor = parser->root.cursor; |
882 | FT_Byte* old_limit = parser->root.limit; |
883 | FT_Int n, nn; |
884 | PS_Blend blend; |
885 | |
886 | |
887 | FT_TRACE4(( " [" )); |
888 | |
889 | for ( n = 0; n < num_designs; n++ ) |
890 | { |
891 | T1_TokenRec axis_tokens[T1_MAX_MM_AXIS]; |
892 | T1_Token token; |
893 | FT_Int axis, n_axis; |
894 | |
895 | |
896 | /* read axis/coordinates tokens */ |
897 | token = design_tokens + n; |
898 | parser->root.cursor = token->start; |
899 | parser->root.limit = token->limit; |
900 | T1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &n_axis ); |
901 | |
902 | if ( n == 0 ) |
903 | { |
904 | if ( n_axis <= 0 || n_axis > T1_MAX_MM_AXIS ) |
905 | { |
906 | FT_ERROR(( "parse_blend_design_positions:" |
907 | " invalid number of axes: %d\n" , |
908 | n_axis )); |
909 | error = FT_THROW( Invalid_File_Format ); |
910 | goto Exit; |
911 | } |
912 | |
913 | num_axis = n_axis; |
914 | error = t1_allocate_blend( t1face, |
915 | (FT_UInt)num_designs, |
916 | (FT_UInt)num_axis ); |
917 | if ( error ) |
918 | goto Exit; |
919 | |
920 | /* allocate a blend design pos table */ |
921 | if ( FT_QNEW_ARRAY( design_pos[0], num_designs * num_axis ) ) |
922 | goto Exit; |
923 | |
924 | for ( nn = 1; nn < num_designs; nn++ ) |
925 | design_pos[nn] = design_pos[0] + num_axis * nn; |
926 | } |
927 | else if ( n_axis != num_axis ) |
928 | { |
929 | FT_ERROR(( "parse_blend_design_positions: incorrect table\n" )); |
930 | error = FT_THROW( Invalid_File_Format ); |
931 | goto Exit; |
932 | } |
933 | |
934 | /* now read each axis token into the design position */ |
935 | FT_TRACE4(( " [" )) ; |
936 | for ( axis = 0; axis < n_axis; axis++ ) |
937 | { |
938 | T1_Token token2 = axis_tokens + axis; |
939 | |
940 | |
941 | parser->root.cursor = token2->start; |
942 | parser->root.limit = token2->limit; |
943 | design_pos[n][axis] = T1_ToFixed( parser, 0 ); |
944 | FT_TRACE4(( " %f" , (double)design_pos[n][axis] / 65536 )); |
945 | } |
946 | FT_TRACE4(( "]" )) ; |
947 | } |
948 | |
949 | FT_TRACE4(( "]\n" )); |
950 | |
951 | loader->parser.root.cursor = old_cursor; |
952 | loader->parser.root.limit = old_limit; |
953 | |
954 | /* a valid BlendDesignPosition has been parsed */ |
955 | blend = t1face->blend; |
956 | if ( blend->design_pos[0] ) |
957 | FT_FREE( blend->design_pos[0] ); |
958 | |
959 | for ( n = 0; n < num_designs; n++ ) |
960 | { |
961 | blend->design_pos[n] = design_pos[n]; |
962 | design_pos[n] = NULL; |
963 | } |
964 | } |
965 | |
966 | Exit: |
967 | FT_FREE( design_pos[0] ); |
968 | loader->parser.root.error = error; |
969 | } |
970 | |
971 | |
972 | static void |
973 | parse_blend_design_map( FT_Face face, /* T1_Face */ |
974 | void* loader_ ) |
975 | { |
976 | T1_Face t1face = (T1_Face)face; |
977 | T1_Loader loader = (T1_Loader)loader_; |
978 | FT_Error error = FT_Err_Ok; |
979 | T1_Parser parser = &loader->parser; |
980 | PS_Blend blend; |
981 | T1_TokenRec axis_tokens[T1_MAX_MM_AXIS]; |
982 | FT_Int n, num_axis; |
983 | FT_Byte* old_cursor; |
984 | FT_Byte* old_limit; |
985 | FT_Memory memory = FT_FACE_MEMORY( face ); |
986 | |
987 | |
988 | T1_ToTokenArray( parser, axis_tokens, |
989 | T1_MAX_MM_AXIS, &num_axis ); |
990 | if ( num_axis < 0 ) |
991 | { |
992 | error = FT_ERR( Ignore ); |
993 | goto Exit; |
994 | } |
995 | if ( num_axis == 0 || num_axis > T1_MAX_MM_AXIS ) |
996 | { |
997 | FT_ERROR(( "parse_blend_design_map: incorrect number of axes: %d\n" , |
998 | num_axis )); |
999 | error = FT_THROW( Invalid_File_Format ); |
1000 | goto Exit; |
1001 | } |
1002 | |
1003 | old_cursor = parser->root.cursor; |
1004 | old_limit = parser->root.limit; |
1005 | |
1006 | error = t1_allocate_blend( t1face, 0, (FT_UInt)num_axis ); |
1007 | if ( error ) |
1008 | goto Exit; |
1009 | blend = t1face->blend; |
1010 | |
1011 | FT_TRACE4(( " [" )); |
1012 | |
1013 | /* now read each axis design map */ |
1014 | for ( n = 0; n < num_axis; n++ ) |
1015 | { |
1016 | PS_DesignMap map = blend->design_map + n; |
1017 | T1_Token axis_token; |
1018 | T1_TokenRec point_tokens[T1_MAX_MM_MAP_POINTS]; |
1019 | FT_Int p, num_points; |
1020 | |
1021 | |
1022 | axis_token = axis_tokens + n; |
1023 | |
1024 | parser->root.cursor = axis_token->start; |
1025 | parser->root.limit = axis_token->limit; |
1026 | T1_ToTokenArray( parser, point_tokens, |
1027 | T1_MAX_MM_MAP_POINTS, &num_points ); |
1028 | |
1029 | FT_TRACE4(( " [" )); |
1030 | |
1031 | if ( num_points <= 0 || num_points > T1_MAX_MM_MAP_POINTS ) |
1032 | { |
1033 | FT_ERROR(( "parse_blend_design_map: incorrect table\n" )); |
1034 | error = FT_THROW( Invalid_File_Format ); |
1035 | goto Exit; |
1036 | } |
1037 | |
1038 | if ( map->design_points ) |
1039 | { |
1040 | FT_ERROR(( "parse_blend_design_map: duplicate table\n" )); |
1041 | error = FT_THROW( Invalid_File_Format ); |
1042 | goto Exit; |
1043 | } |
1044 | |
1045 | /* allocate design map data */ |
1046 | if ( FT_QNEW_ARRAY( map->design_points, num_points * 2 ) ) |
1047 | goto Exit; |
1048 | map->blend_points = map->design_points + num_points; |
1049 | map->num_points = (FT_Byte)num_points; |
1050 | |
1051 | for ( p = 0; p < num_points; p++ ) |
1052 | { |
1053 | T1_Token point_token; |
1054 | |
1055 | |
1056 | point_token = point_tokens + p; |
1057 | |
1058 | /* don't include delimiting brackets */ |
1059 | parser->root.cursor = point_token->start + 1; |
1060 | parser->root.limit = point_token->limit - 1; |
1061 | |
1062 | map->design_points[p] = T1_ToInt( parser ); |
1063 | map->blend_points [p] = T1_ToFixed( parser, 0 ); |
1064 | |
1065 | FT_TRACE4(( " [%ld %f]" , |
1066 | map->design_points[p], |
1067 | (double)map->blend_points[p] / 65536 )); |
1068 | } |
1069 | |
1070 | FT_TRACE4(( "]" )); |
1071 | } |
1072 | |
1073 | FT_TRACE4(( "]\n" )); |
1074 | |
1075 | parser->root.cursor = old_cursor; |
1076 | parser->root.limit = old_limit; |
1077 | |
1078 | Exit: |
1079 | parser->root.error = error; |
1080 | } |
1081 | |
1082 | |
1083 | static void |
1084 | parse_weight_vector( FT_Face face, /* T1_Face */ |
1085 | void* loader_ ) |
1086 | { |
1087 | T1_Face t1face = (T1_Face)face; |
1088 | T1_Loader loader = (T1_Loader)loader_; |
1089 | T1_TokenRec design_tokens[T1_MAX_MM_DESIGNS]; |
1090 | FT_Int num_designs; |
1091 | FT_Error error = FT_Err_Ok; |
1092 | FT_Memory memory = FT_FACE_MEMORY( face ); |
1093 | T1_Parser parser = &loader->parser; |
1094 | PS_Blend blend = t1face->blend; |
1095 | T1_Token token; |
1096 | FT_Int n; |
1097 | FT_Byte* old_cursor; |
1098 | FT_Byte* old_limit; |
1099 | |
1100 | |
1101 | T1_ToTokenArray( parser, design_tokens, |
1102 | T1_MAX_MM_DESIGNS, &num_designs ); |
1103 | if ( num_designs < 0 ) |
1104 | { |
1105 | error = FT_ERR( Ignore ); |
1106 | goto Exit; |
1107 | } |
1108 | if ( num_designs == 0 || num_designs > T1_MAX_MM_DESIGNS ) |
1109 | { |
1110 | FT_ERROR(( "parse_weight_vector:" |
1111 | " incorrect number of designs: %d\n" , |
1112 | num_designs )); |
1113 | error = FT_THROW( Invalid_File_Format ); |
1114 | goto Exit; |
1115 | } |
1116 | |
1117 | if ( !blend || !blend->num_designs ) |
1118 | { |
1119 | error = t1_allocate_blend( t1face, (FT_UInt)num_designs, 0 ); |
1120 | if ( error ) |
1121 | goto Exit; |
1122 | blend = t1face->blend; |
1123 | } |
1124 | else if ( blend->num_designs != (FT_UInt)num_designs ) |
1125 | { |
1126 | FT_ERROR(( "parse_weight_vector:" |
1127 | " /BlendDesignPosition and /WeightVector have\n" )); |
1128 | FT_ERROR(( " " |
1129 | " different number of elements\n" )); |
1130 | error = FT_THROW( Invalid_File_Format ); |
1131 | goto Exit; |
1132 | } |
1133 | |
1134 | if ( !blend->weight_vector ) |
1135 | if ( FT_QNEW_ARRAY( blend->weight_vector, num_designs * 2 ) ) |
1136 | goto Exit; |
1137 | |
1138 | blend->default_weight_vector = blend->weight_vector + num_designs; |
1139 | |
1140 | old_cursor = parser->root.cursor; |
1141 | old_limit = parser->root.limit; |
1142 | |
1143 | FT_TRACE4(( "[" )); |
1144 | |
1145 | for ( n = 0; n < num_designs; n++ ) |
1146 | { |
1147 | token = design_tokens + n; |
1148 | parser->root.cursor = token->start; |
1149 | parser->root.limit = token->limit; |
1150 | |
1151 | blend->default_weight_vector[n] = |
1152 | blend->weight_vector[n] = T1_ToFixed( parser, 0 ); |
1153 | |
1154 | FT_TRACE4(( " %f" , (double)blend->weight_vector[n] / 65536 )); |
1155 | } |
1156 | |
1157 | FT_TRACE4(( "]\n" )); |
1158 | |
1159 | parser->root.cursor = old_cursor; |
1160 | parser->root.limit = old_limit; |
1161 | |
1162 | Exit: |
1163 | parser->root.error = error; |
1164 | } |
1165 | |
1166 | |
1167 | /* e.g., /BuildCharArray [0 0 0 0 0 0 0 0] def */ |
1168 | /* we're only interested in the number of array elements */ |
1169 | static void |
1170 | parse_buildchar( FT_Face face, /* T1_Face */ |
1171 | void* loader_ ) |
1172 | { |
1173 | T1_Face t1face = (T1_Face)face; |
1174 | T1_Loader loader = (T1_Loader)loader_; |
1175 | |
1176 | |
1177 | t1face->len_buildchar = (FT_UInt)T1_ToFixedArray( &loader->parser, |
1178 | 0, NULL, 0 ); |
1179 | |
1180 | #ifdef FT_DEBUG_LEVEL_TRACE |
1181 | { |
1182 | FT_UInt i; |
1183 | |
1184 | |
1185 | FT_TRACE4(( " [" )); |
1186 | for ( i = 0; i < t1face->len_buildchar; i++ ) |
1187 | FT_TRACE4(( " 0" )); |
1188 | |
1189 | FT_TRACE4(( "]\n" )); |
1190 | } |
1191 | #endif |
1192 | |
1193 | return; |
1194 | } |
1195 | |
1196 | |
1197 | #endif /* !T1_CONFIG_OPTION_NO_MM_SUPPORT */ |
1198 | |
1199 | |
1200 | |
1201 | |
1202 | /*************************************************************************/ |
1203 | /*************************************************************************/ |
1204 | /***** *****/ |
1205 | /***** TYPE 1 SYMBOL PARSING *****/ |
1206 | /***** *****/ |
1207 | /*************************************************************************/ |
1208 | /*************************************************************************/ |
1209 | |
1210 | static FT_Error |
1211 | t1_load_keyword( T1_Face face, |
1212 | T1_Loader loader, |
1213 | const T1_Field field ) |
1214 | { |
1215 | FT_Error error; |
1216 | void* dummy_object; |
1217 | void** objects; |
1218 | FT_UInt max_objects; |
1219 | PS_Blend blend = face->blend; |
1220 | |
1221 | |
1222 | if ( blend && blend->num_designs == 0 ) |
1223 | blend = NULL; |
1224 | |
1225 | /* if the keyword has a dedicated callback, call it */ |
1226 | if ( field->type == T1_FIELD_TYPE_CALLBACK ) |
1227 | { |
1228 | FT_TRACE4(( " %s" , field->ident )); |
1229 | |
1230 | field->reader( (FT_Face)face, loader ); |
1231 | error = loader->parser.root.error; |
1232 | goto Exit; |
1233 | } |
1234 | |
1235 | /* now, the keyword is either a simple field, or a table of fields; */ |
1236 | /* we are now going to take care of it */ |
1237 | switch ( field->location ) |
1238 | { |
1239 | case T1_FIELD_LOCATION_FONT_INFO: |
1240 | dummy_object = &face->type1.font_info; |
1241 | objects = &dummy_object; |
1242 | max_objects = 0; |
1243 | |
1244 | if ( blend ) |
1245 | { |
1246 | objects = (void**)blend->font_infos; |
1247 | max_objects = blend->num_designs; |
1248 | } |
1249 | break; |
1250 | |
1251 | case T1_FIELD_LOCATION_FONT_EXTRA: |
1252 | dummy_object = &face->type1.font_extra; |
1253 | objects = &dummy_object; |
1254 | max_objects = 0; |
1255 | break; |
1256 | |
1257 | case T1_FIELD_LOCATION_PRIVATE: |
1258 | dummy_object = &face->type1.private_dict; |
1259 | objects = &dummy_object; |
1260 | max_objects = 0; |
1261 | |
1262 | if ( blend ) |
1263 | { |
1264 | objects = (void**)blend->privates; |
1265 | max_objects = blend->num_designs; |
1266 | } |
1267 | break; |
1268 | |
1269 | case T1_FIELD_LOCATION_BBOX: |
1270 | dummy_object = &face->type1.font_bbox; |
1271 | objects = &dummy_object; |
1272 | max_objects = 0; |
1273 | |
1274 | if ( blend ) |
1275 | { |
1276 | objects = (void**)blend->bboxes; |
1277 | max_objects = blend->num_designs; |
1278 | } |
1279 | break; |
1280 | |
1281 | case T1_FIELD_LOCATION_LOADER: |
1282 | dummy_object = loader; |
1283 | objects = &dummy_object; |
1284 | max_objects = 0; |
1285 | break; |
1286 | |
1287 | case T1_FIELD_LOCATION_FACE: |
1288 | dummy_object = face; |
1289 | objects = &dummy_object; |
1290 | max_objects = 0; |
1291 | break; |
1292 | |
1293 | #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT |
1294 | case T1_FIELD_LOCATION_BLEND: |
1295 | dummy_object = face->blend; |
1296 | objects = &dummy_object; |
1297 | max_objects = 0; |
1298 | break; |
1299 | #endif |
1300 | |
1301 | default: |
1302 | dummy_object = &face->type1; |
1303 | objects = &dummy_object; |
1304 | max_objects = 0; |
1305 | } |
1306 | |
1307 | FT_TRACE4(( " %s" , field->ident )); |
1308 | |
1309 | if ( *objects ) |
1310 | { |
1311 | if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY || |
1312 | field->type == T1_FIELD_TYPE_FIXED_ARRAY ) |
1313 | error = T1_Load_Field_Table( &loader->parser, field, |
1314 | objects, max_objects, 0 ); |
1315 | else |
1316 | error = T1_Load_Field( &loader->parser, field, |
1317 | objects, max_objects, 0 ); |
1318 | } |
1319 | else |
1320 | { |
1321 | FT_TRACE1(( "t1_load_keyword: ignoring keyword `%s'" |
1322 | " which is not valid at this point\n" , |
1323 | field->ident )); |
1324 | FT_TRACE1(( " (probably due to missing keywords)\n" )); |
1325 | error = FT_Err_Ok; |
1326 | } |
1327 | |
1328 | FT_TRACE4(( "\n" )); |
1329 | |
1330 | Exit: |
1331 | return error; |
1332 | } |
1333 | |
1334 | |
1335 | static void |
1336 | parse_private( FT_Face face, |
1337 | void* loader_ ) |
1338 | { |
1339 | T1_Loader loader = (T1_Loader)loader_; |
1340 | FT_UNUSED( face ); |
1341 | |
1342 | loader->keywords_encountered |= T1_PRIVATE; |
1343 | |
1344 | FT_TRACE4(( "\n" )); |
1345 | } |
1346 | |
1347 | |
1348 | /* return 1 in case of success */ |
1349 | |
1350 | static int |
1351 | read_binary_data( T1_Parser parser, |
1352 | FT_ULong* size, |
1353 | FT_Byte** base, |
1354 | FT_Bool incremental ) |
1355 | { |
1356 | FT_Byte* cur; |
1357 | FT_Byte* limit = parser->root.limit; |
1358 | |
1359 | |
1360 | /* the binary data has one of the following formats */ |
1361 | /* */ |
1362 | /* `size' [white*] RD white ....... ND */ |
1363 | /* `size' [white*] -| white ....... |- */ |
1364 | /* */ |
1365 | |
1366 | T1_Skip_Spaces( parser ); |
1367 | |
1368 | cur = parser->root.cursor; |
1369 | |
1370 | if ( cur < limit && ft_isdigit( *cur ) ) |
1371 | { |
1372 | FT_Long s = T1_ToInt( parser ); |
1373 | |
1374 | |
1375 | T1_Skip_PS_Token( parser ); /* `RD' or `-|' or something else */ |
1376 | |
1377 | /* there is only one whitespace char after the */ |
1378 | /* `RD' or `-|' token */ |
1379 | *base = parser->root.cursor + 1; |
1380 | |
1381 | if ( s >= 0 && s < limit - *base ) |
1382 | { |
1383 | parser->root.cursor += s + 1; |
1384 | *size = (FT_ULong)s; |
1385 | return !parser->root.error; |
1386 | } |
1387 | } |
1388 | |
1389 | if( !incremental ) |
1390 | { |
1391 | FT_ERROR(( "read_binary_data: invalid size field\n" )); |
1392 | parser->root.error = FT_THROW( Invalid_File_Format ); |
1393 | } |
1394 | |
1395 | return 0; |
1396 | } |
1397 | |
1398 | |
1399 | /* We now define the routines to handle the `/Encoding', `/Subrs', */ |
1400 | /* and `/CharStrings' dictionaries. */ |
1401 | |
1402 | static void |
1403 | t1_parse_font_matrix( FT_Face face, /* T1_Face */ |
1404 | void* loader_ ) |
1405 | { |
1406 | T1_Face t1face = (T1_Face)face; |
1407 | T1_Loader loader = (T1_Loader)loader_; |
1408 | T1_Parser parser = &loader->parser; |
1409 | FT_Matrix* matrix = &t1face->type1.font_matrix; |
1410 | FT_Vector* offset = &t1face->type1.font_offset; |
1411 | FT_Fixed temp[6]; |
1412 | FT_Fixed temp_scale; |
1413 | FT_Int result; |
1414 | |
1415 | |
1416 | /* input is scaled by 1000 to accommodate default FontMatrix */ |
1417 | result = T1_ToFixedArray( parser, 6, temp, 3 ); |
1418 | |
1419 | if ( result < 6 ) |
1420 | { |
1421 | parser->root.error = FT_THROW( Invalid_File_Format ); |
1422 | return; |
1423 | } |
1424 | |
1425 | FT_TRACE4(( " [%f %f %f %f %f %f]\n" , |
1426 | (double)temp[0] / 65536 / 1000, |
1427 | (double)temp[1] / 65536 / 1000, |
1428 | (double)temp[2] / 65536 / 1000, |
1429 | (double)temp[3] / 65536 / 1000, |
1430 | (double)temp[4] / 65536 / 1000, |
1431 | (double)temp[5] / 65536 / 1000 )); |
1432 | |
1433 | temp_scale = FT_ABS( temp[3] ); |
1434 | |
1435 | if ( temp_scale == 0 ) |
1436 | { |
1437 | FT_ERROR(( "t1_parse_font_matrix: invalid font matrix\n" )); |
1438 | parser->root.error = FT_THROW( Invalid_File_Format ); |
1439 | return; |
1440 | } |
1441 | |
1442 | /* atypical case */ |
1443 | if ( temp_scale != 0x10000L ) |
1444 | { |
1445 | /* set units per EM based on FontMatrix values */ |
1446 | face->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale ); |
1447 | |
1448 | temp[0] = FT_DivFix( temp[0], temp_scale ); |
1449 | temp[1] = FT_DivFix( temp[1], temp_scale ); |
1450 | temp[2] = FT_DivFix( temp[2], temp_scale ); |
1451 | temp[4] = FT_DivFix( temp[4], temp_scale ); |
1452 | temp[5] = FT_DivFix( temp[5], temp_scale ); |
1453 | temp[3] = temp[3] < 0 ? -0x10000L : 0x10000L; |
1454 | } |
1455 | matrix->xx = temp[0]; |
1456 | matrix->yx = temp[1]; |
1457 | matrix->xy = temp[2]; |
1458 | matrix->yy = temp[3]; |
1459 | |
1460 | if ( !FT_Matrix_Check( matrix ) ) |
1461 | { |
1462 | FT_ERROR(( "t1_parse_font_matrix: invalid font matrix\n" )); |
1463 | parser->root.error = FT_THROW( Invalid_File_Format ); |
1464 | return; |
1465 | } |
1466 | |
1467 | /* note that the offsets must be expressed in integer font units */ |
1468 | offset->x = temp[4] >> 16; |
1469 | offset->y = temp[5] >> 16; |
1470 | } |
1471 | |
1472 | |
1473 | static void |
1474 | parse_encoding( FT_Face face, /* T1_Face */ |
1475 | void* loader_ ) |
1476 | { |
1477 | T1_Face t1face = (T1_Face)face; |
1478 | T1_Loader loader = (T1_Loader)loader_; |
1479 | T1_Parser parser = &loader->parser; |
1480 | FT_Byte* cur; |
1481 | FT_Byte* limit = parser->root.limit; |
1482 | |
1483 | PSAux_Service psaux = (PSAux_Service)t1face->psaux; |
1484 | |
1485 | |
1486 | T1_Skip_Spaces( parser ); |
1487 | cur = parser->root.cursor; |
1488 | if ( cur >= limit ) |
1489 | { |
1490 | FT_ERROR(( "parse_encoding: out of bounds\n" )); |
1491 | parser->root.error = FT_THROW( Invalid_File_Format ); |
1492 | return; |
1493 | } |
1494 | |
1495 | /* if we have a number or `[', the encoding is an array, */ |
1496 | /* and we must load it now */ |
1497 | if ( ft_isdigit( *cur ) || *cur == '[' ) |
1498 | { |
1499 | T1_Encoding encode = &t1face->type1.encoding; |
1500 | FT_Int count, array_size, n; |
1501 | PS_Table char_table = &loader->encoding_table; |
1502 | FT_Memory memory = parser->root.memory; |
1503 | FT_Error error; |
1504 | FT_Bool only_immediates = 0; |
1505 | |
1506 | |
1507 | /* read the number of entries in the encoding; should be 256 */ |
1508 | if ( *cur == '[' ) |
1509 | { |
1510 | count = 256; |
1511 | only_immediates = 1; |
1512 | parser->root.cursor++; |
1513 | } |
1514 | else |
1515 | count = (FT_Int)T1_ToInt( parser ); |
1516 | |
1517 | array_size = count; |
1518 | if ( count > 256 ) |
1519 | { |
1520 | FT_TRACE2(( "parse_encoding:" |
1521 | " only using first 256 encoding array entries\n" )); |
1522 | array_size = 256; |
1523 | } |
1524 | |
1525 | T1_Skip_Spaces( parser ); |
1526 | if ( parser->root.cursor >= limit ) |
1527 | return; |
1528 | |
1529 | /* PostScript happily allows overwriting of encoding arrays */ |
1530 | if ( encode->char_index ) |
1531 | { |
1532 | FT_FREE( encode->char_index ); |
1533 | FT_FREE( encode->char_name ); |
1534 | T1_Release_Table( char_table ); |
1535 | } |
1536 | |
1537 | /* we use a T1_Table to store our charnames */ |
1538 | loader->num_chars = encode->num_chars = array_size; |
1539 | if ( FT_QNEW_ARRAY( encode->char_index, array_size ) || |
1540 | FT_QNEW_ARRAY( encode->char_name, array_size ) || |
1541 | FT_SET_ERROR( psaux->ps_table_funcs->init( |
1542 | char_table, array_size, memory ) ) ) |
1543 | { |
1544 | parser->root.error = error; |
1545 | return; |
1546 | } |
1547 | |
1548 | /* We need to `zero' out encoding_table.elements */ |
1549 | for ( n = 0; n < array_size; n++ ) |
1550 | (void)T1_Add_Table( char_table, n, ".notdef" , 8 ); |
1551 | |
1552 | /* Now we need to read records of the form */ |
1553 | /* */ |
1554 | /* ... charcode /charname ... */ |
1555 | /* */ |
1556 | /* for each entry in our table. */ |
1557 | /* */ |
1558 | /* We simply look for a number followed by an immediate */ |
1559 | /* name. Note that this ignores correctly the sequence */ |
1560 | /* that is often seen in type1 fonts: */ |
1561 | /* */ |
1562 | /* 0 1 255 { 1 index exch /.notdef put } for dup */ |
1563 | /* */ |
1564 | /* used to clean the encoding array before anything else. */ |
1565 | /* */ |
1566 | /* Alternatively, if the array is directly given as */ |
1567 | /* */ |
1568 | /* /Encoding [ ... ] */ |
1569 | /* */ |
1570 | /* we only read immediates. */ |
1571 | |
1572 | n = 0; |
1573 | T1_Skip_Spaces( parser ); |
1574 | |
1575 | while ( parser->root.cursor < limit ) |
1576 | { |
1577 | cur = parser->root.cursor; |
1578 | |
1579 | /* we stop when we encounter a `def' or `]' */ |
1580 | if ( *cur == 'd' && cur + 3 < limit ) |
1581 | { |
1582 | if ( cur[1] == 'e' && |
1583 | cur[2] == 'f' && |
1584 | IS_PS_DELIM( cur[3] ) ) |
1585 | { |
1586 | FT_TRACE6(( "encoding end\n" )); |
1587 | cur += 3; |
1588 | break; |
1589 | } |
1590 | } |
1591 | if ( *cur == ']' ) |
1592 | { |
1593 | FT_TRACE6(( "encoding end\n" )); |
1594 | cur++; |
1595 | break; |
1596 | } |
1597 | |
1598 | /* check whether we've found an entry */ |
1599 | if ( ft_isdigit( *cur ) || only_immediates ) |
1600 | { |
1601 | FT_Int charcode; |
1602 | |
1603 | |
1604 | if ( only_immediates ) |
1605 | charcode = n; |
1606 | else |
1607 | { |
1608 | charcode = (FT_Int)T1_ToInt( parser ); |
1609 | T1_Skip_Spaces( parser ); |
1610 | |
1611 | /* protect against invalid charcode */ |
1612 | if ( cur == parser->root.cursor ) |
1613 | { |
1614 | parser->root.error = FT_THROW( Unknown_File_Format ); |
1615 | return; |
1616 | } |
1617 | } |
1618 | |
1619 | cur = parser->root.cursor; |
1620 | |
1621 | if ( cur + 2 < limit && *cur == '/' && n < count ) |
1622 | { |
1623 | FT_UInt len; |
1624 | |
1625 | |
1626 | cur++; |
1627 | |
1628 | parser->root.cursor = cur; |
1629 | T1_Skip_PS_Token( parser ); |
1630 | if ( parser->root.cursor >= limit ) |
1631 | return; |
1632 | if ( parser->root.error ) |
1633 | return; |
1634 | |
1635 | len = (FT_UInt)( parser->root.cursor - cur ); |
1636 | |
1637 | if ( n < array_size ) |
1638 | { |
1639 | parser->root.error = T1_Add_Table( char_table, charcode, |
1640 | cur, len + 1 ); |
1641 | if ( parser->root.error ) |
1642 | return; |
1643 | char_table->elements[charcode][len] = '\0'; |
1644 | } |
1645 | |
1646 | n++; |
1647 | } |
1648 | else if ( only_immediates ) |
1649 | { |
1650 | /* Since the current position is not updated for */ |
1651 | /* immediates-only mode we would get an infinite loop if */ |
1652 | /* we don't do anything here. */ |
1653 | /* */ |
1654 | /* This encoding array is not valid according to the type1 */ |
1655 | /* specification (it might be an encoding for a CID type1 */ |
1656 | /* font, however), so we conclude that this font is NOT a */ |
1657 | /* type1 font. */ |
1658 | parser->root.error = FT_THROW( Unknown_File_Format ); |
1659 | return; |
1660 | } |
1661 | } |
1662 | else |
1663 | { |
1664 | T1_Skip_PS_Token( parser ); |
1665 | if ( parser->root.error ) |
1666 | return; |
1667 | } |
1668 | |
1669 | T1_Skip_Spaces( parser ); |
1670 | } |
1671 | |
1672 | #ifdef FT_DEBUG_LEVEL_TRACE |
1673 | FT_TRACE4(( " [" )); |
1674 | |
1675 | /* XXX show encoding vector */ |
1676 | FT_TRACE4(( "..." )); |
1677 | |
1678 | FT_TRACE4(( "]\n" )); |
1679 | #endif |
1680 | |
1681 | t1face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY; |
1682 | parser->root.cursor = cur; |
1683 | } |
1684 | |
1685 | /* Otherwise, we should have either `StandardEncoding', */ |
1686 | /* `ExpertEncoding', or `ISOLatin1Encoding' */ |
1687 | else |
1688 | { |
1689 | if ( cur + 17 < limit && |
1690 | ft_strncmp( (const char*)cur, "StandardEncoding" , 16 ) == 0 ) |
1691 | { |
1692 | t1face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD; |
1693 | FT_TRACE4(( " StandardEncoding\n" )); |
1694 | } |
1695 | |
1696 | else if ( cur + 15 < limit && |
1697 | ft_strncmp( (const char*)cur, "ExpertEncoding" , 14 ) == 0 ) |
1698 | { |
1699 | t1face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT; |
1700 | FT_TRACE4(( " ExpertEncoding\n" )); |
1701 | } |
1702 | |
1703 | else if ( cur + 18 < limit && |
1704 | ft_strncmp( (const char*)cur, "ISOLatin1Encoding" , 17 ) == 0 ) |
1705 | { |
1706 | t1face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1; |
1707 | FT_TRACE4(( " ISOLatin1Encoding\n" )); |
1708 | } |
1709 | |
1710 | else |
1711 | { |
1712 | parser->root.error = FT_ERR( Ignore ); |
1713 | FT_TRACE4(( "<unknown>\n" )); |
1714 | } |
1715 | } |
1716 | } |
1717 | |
1718 | |
1719 | static void |
1720 | parse_subrs( FT_Face face, /* T1_Face */ |
1721 | void* loader_ ) |
1722 | { |
1723 | T1_Face t1face = (T1_Face)face; |
1724 | T1_Loader loader = (T1_Loader)loader_; |
1725 | T1_Parser parser = &loader->parser; |
1726 | PS_Table table = &loader->subrs; |
1727 | FT_Memory memory = parser->root.memory; |
1728 | FT_Error error; |
1729 | FT_Int num_subrs; |
1730 | FT_UInt count; |
1731 | |
1732 | PSAux_Service psaux = (PSAux_Service)t1face->psaux; |
1733 | |
1734 | |
1735 | T1_Skip_Spaces( parser ); |
1736 | |
1737 | /* test for empty array */ |
1738 | if ( parser->root.cursor < parser->root.limit && |
1739 | *parser->root.cursor == '[' ) |
1740 | { |
1741 | T1_Skip_PS_Token( parser ); |
1742 | T1_Skip_Spaces ( parser ); |
1743 | if ( parser->root.cursor >= parser->root.limit || |
1744 | *parser->root.cursor != ']' ) |
1745 | parser->root.error = FT_THROW( Invalid_File_Format ); |
1746 | return; |
1747 | } |
1748 | |
1749 | num_subrs = (FT_Int)T1_ToInt( parser ); |
1750 | if ( num_subrs < 0 ) |
1751 | { |
1752 | parser->root.error = FT_THROW( Invalid_File_Format ); |
1753 | return; |
1754 | } |
1755 | |
1756 | /* we certainly need more than 8 bytes per subroutine */ |
1757 | if ( parser->root.limit >= parser->root.cursor && |
1758 | num_subrs > ( parser->root.limit - parser->root.cursor ) >> 3 ) |
1759 | { |
1760 | /* |
1761 | * There are two possibilities. Either the font contains an invalid |
1762 | * value for `num_subrs', or we have a subsetted font where the |
1763 | * subroutine indices are not adjusted, e.g. |
1764 | * |
1765 | * /Subrs 812 array |
1766 | * dup 0 { ... } NP |
1767 | * dup 51 { ... } NP |
1768 | * dup 681 { ... } NP |
1769 | * ND |
1770 | * |
1771 | * In both cases, we use a number hash that maps from subr indices to |
1772 | * actual array elements. |
1773 | */ |
1774 | |
1775 | FT_TRACE0(( "parse_subrs: adjusting number of subroutines" |
1776 | " (from %d to %zu)\n" , |
1777 | num_subrs, |
1778 | ( parser->root.limit - parser->root.cursor ) >> 3 )); |
1779 | num_subrs = ( parser->root.limit - parser->root.cursor ) >> 3; |
1780 | |
1781 | if ( !loader->subrs_hash ) |
1782 | { |
1783 | if ( FT_QNEW( loader->subrs_hash ) ) |
1784 | goto Fail; |
1785 | |
1786 | error = ft_hash_num_init( loader->subrs_hash, memory ); |
1787 | if ( error ) |
1788 | goto Fail; |
1789 | } |
1790 | } |
1791 | |
1792 | /* position the parser right before the `dup' of the first subr */ |
1793 | T1_Skip_PS_Token( parser ); /* `array' */ |
1794 | if ( parser->root.error ) |
1795 | return; |
1796 | T1_Skip_Spaces( parser ); |
1797 | |
1798 | /* initialize subrs array -- with synthetic fonts it is possible */ |
1799 | /* we get here twice */ |
1800 | if ( !loader->num_subrs ) |
1801 | { |
1802 | error = psaux->ps_table_funcs->init( table, num_subrs, memory ); |
1803 | if ( error ) |
1804 | goto Fail; |
1805 | } |
1806 | |
1807 | /* the format is simple: */ |
1808 | /* */ |
1809 | /* `index' + binary data */ |
1810 | /* */ |
1811 | for ( count = 0; ; count++ ) |
1812 | { |
1813 | FT_Long idx; |
1814 | FT_ULong size; |
1815 | FT_Byte* base; |
1816 | |
1817 | |
1818 | /* If we are out of data, or if the next token isn't `dup', */ |
1819 | /* we are done. */ |
1820 | if ( parser->root.cursor + 4 >= parser->root.limit || |
1821 | ft_strncmp( (char*)parser->root.cursor, "dup" , 3 ) != 0 ) |
1822 | break; |
1823 | |
1824 | T1_Skip_PS_Token( parser ); /* `dup' */ |
1825 | |
1826 | idx = T1_ToInt( parser ); |
1827 | |
1828 | if ( !read_binary_data( parser, &size, &base, IS_INCREMENTAL ) ) |
1829 | return; |
1830 | |
1831 | /* The binary string is followed by one token, e.g. `NP' */ |
1832 | /* (bound to `noaccess put') or by two separate tokens: */ |
1833 | /* `noaccess' & `put'. We position the parser right */ |
1834 | /* before the next `dup', if any. */ |
1835 | T1_Skip_PS_Token( parser ); /* `NP' or `|' or `noaccess' */ |
1836 | if ( parser->root.error ) |
1837 | return; |
1838 | T1_Skip_Spaces ( parser ); |
1839 | |
1840 | if ( parser->root.cursor + 4 < parser->root.limit && |
1841 | ft_strncmp( (char*)parser->root.cursor, "put" , 3 ) == 0 ) |
1842 | { |
1843 | T1_Skip_PS_Token( parser ); /* skip `put' */ |
1844 | T1_Skip_Spaces ( parser ); |
1845 | } |
1846 | |
1847 | /* if we use a hash, the subrs index is the key, and a running */ |
1848 | /* counter specified for `T1_Add_Table' acts as the value */ |
1849 | if ( loader->subrs_hash ) |
1850 | { |
1851 | ft_hash_num_insert( idx, count, loader->subrs_hash, memory ); |
1852 | idx = count; |
1853 | } |
1854 | |
1855 | /* with synthetic fonts it is possible we get here twice */ |
1856 | if ( loader->num_subrs ) |
1857 | continue; |
1858 | |
1859 | /* some fonts use a value of -1 for lenIV to indicate that */ |
1860 | /* the charstrings are unencoded */ |
1861 | /* */ |
1862 | /* thanks to Tom Kacvinsky for pointing this out */ |
1863 | /* */ |
1864 | if ( t1face->type1.private_dict.lenIV >= 0 ) |
1865 | { |
1866 | FT_Byte* temp = NULL; |
1867 | |
1868 | |
1869 | /* some fonts define empty subr records -- this is not totally */ |
1870 | /* compliant to the specification (which says they should at */ |
1871 | /* least contain a `return'), but we support them anyway */ |
1872 | if ( size < (FT_ULong)t1face->type1.private_dict.lenIV ) |
1873 | { |
1874 | error = FT_THROW( Invalid_File_Format ); |
1875 | goto Fail; |
1876 | } |
1877 | |
1878 | /* t1_decrypt() shouldn't write to base -- make temporary copy */ |
1879 | if ( FT_QALLOC( temp, size ) ) |
1880 | goto Fail; |
1881 | FT_MEM_COPY( temp, base, size ); |
1882 | psaux->t1_decrypt( temp, size, 4330 ); |
1883 | size -= (FT_ULong)t1face->type1.private_dict.lenIV; |
1884 | error = T1_Add_Table( table, |
1885 | (FT_Int)idx, |
1886 | temp + t1face->type1.private_dict.lenIV, |
1887 | size ); |
1888 | FT_FREE( temp ); |
1889 | } |
1890 | else |
1891 | error = T1_Add_Table( table, (FT_Int)idx, base, size ); |
1892 | if ( error ) |
1893 | goto Fail; |
1894 | } |
1895 | |
1896 | if ( !loader->num_subrs ) |
1897 | loader->num_subrs = num_subrs; |
1898 | |
1899 | #ifdef FT_DEBUG_LEVEL_TRACE |
1900 | FT_TRACE4(( " <" )); |
1901 | |
1902 | /* XXX show subrs? */ |
1903 | FT_TRACE4(( "%d elements" , num_subrs )); |
1904 | |
1905 | FT_TRACE4(( ">\n" )); |
1906 | #endif |
1907 | |
1908 | return; |
1909 | |
1910 | Fail: |
1911 | parser->root.error = error; |
1912 | } |
1913 | |
1914 | |
1915 | #define TABLE_EXTEND 5 |
1916 | |
1917 | |
1918 | static void |
1919 | parse_charstrings( FT_Face face, /* T1_Face */ |
1920 | void* loader_ ) |
1921 | { |
1922 | T1_Face t1face = (T1_Face)face; |
1923 | T1_Loader loader = (T1_Loader)loader_; |
1924 | T1_Parser parser = &loader->parser; |
1925 | PS_Table code_table = &loader->charstrings; |
1926 | PS_Table name_table = &loader->glyph_names; |
1927 | PS_Table swap_table = &loader->swap_table; |
1928 | FT_Memory memory = parser->root.memory; |
1929 | FT_Error error; |
1930 | |
1931 | PSAux_Service psaux = (PSAux_Service)t1face->psaux; |
1932 | |
1933 | FT_Byte* cur = parser->root.cursor; |
1934 | FT_Byte* limit = parser->root.limit; |
1935 | FT_Int n, num_glyphs; |
1936 | FT_Int notdef_index = 0; |
1937 | FT_Byte notdef_found = 0; |
1938 | |
1939 | |
1940 | num_glyphs = (FT_Int)T1_ToInt( parser ); |
1941 | if ( num_glyphs < 0 ) |
1942 | { |
1943 | error = FT_THROW( Invalid_File_Format ); |
1944 | goto Fail; |
1945 | } |
1946 | |
1947 | /* we certainly need more than 8 bytes per glyph */ |
1948 | if ( num_glyphs > ( limit - cur ) >> 3 ) |
1949 | { |
1950 | FT_TRACE0(( "parse_charstrings: adjusting number of glyphs" |
1951 | " (from %d to %zu)\n" , |
1952 | num_glyphs, ( limit - cur ) >> 3 )); |
1953 | num_glyphs = ( limit - cur ) >> 3; |
1954 | } |
1955 | |
1956 | /* some fonts like Optima-Oblique not only define the /CharStrings */ |
1957 | /* array but access it also */ |
1958 | if ( num_glyphs == 0 || parser->root.error ) |
1959 | return; |
1960 | |
1961 | /* initialize tables, leaving space for addition of .notdef, */ |
1962 | /* if necessary, and a few other glyphs to handle buggy */ |
1963 | /* fonts which have more glyphs than specified. */ |
1964 | |
1965 | /* for some non-standard fonts like `Optima' which provides */ |
1966 | /* different outlines depending on the resolution it is */ |
1967 | /* possible to get here twice */ |
1968 | if ( !loader->num_glyphs ) |
1969 | { |
1970 | error = psaux->ps_table_funcs->init( |
1971 | code_table, num_glyphs + 1 + TABLE_EXTEND, memory ); |
1972 | if ( error ) |
1973 | goto Fail; |
1974 | |
1975 | error = psaux->ps_table_funcs->init( |
1976 | name_table, num_glyphs + 1 + TABLE_EXTEND, memory ); |
1977 | if ( error ) |
1978 | goto Fail; |
1979 | |
1980 | /* Initialize table for swapping index notdef_index and */ |
1981 | /* index 0 names and codes (if necessary). */ |
1982 | |
1983 | error = psaux->ps_table_funcs->init( swap_table, 4, memory ); |
1984 | if ( error ) |
1985 | goto Fail; |
1986 | } |
1987 | |
1988 | n = 0; |
1989 | |
1990 | for (;;) |
1991 | { |
1992 | FT_ULong size; |
1993 | FT_Byte* base; |
1994 | |
1995 | |
1996 | /* the format is simple: */ |
1997 | /* `/glyphname' + binary data */ |
1998 | |
1999 | T1_Skip_Spaces( parser ); |
2000 | |
2001 | cur = parser->root.cursor; |
2002 | if ( cur >= limit ) |
2003 | break; |
2004 | |
2005 | /* we stop when we find a `def' or `end' keyword */ |
2006 | if ( cur + 3 < limit && IS_PS_DELIM( cur[3] ) ) |
2007 | { |
2008 | if ( cur[0] == 'd' && |
2009 | cur[1] == 'e' && |
2010 | cur[2] == 'f' ) |
2011 | { |
2012 | /* There are fonts which have this: */ |
2013 | /* */ |
2014 | /* /CharStrings 118 dict def */ |
2015 | /* Private begin */ |
2016 | /* CharStrings begin */ |
2017 | /* ... */ |
2018 | /* */ |
2019 | /* To catch this we ignore `def' if */ |
2020 | /* no charstring has actually been */ |
2021 | /* seen. */ |
2022 | if ( n ) |
2023 | break; |
2024 | } |
2025 | |
2026 | if ( cur[0] == 'e' && |
2027 | cur[1] == 'n' && |
2028 | cur[2] == 'd' ) |
2029 | break; |
2030 | } |
2031 | |
2032 | T1_Skip_PS_Token( parser ); |
2033 | if ( parser->root.cursor >= limit ) |
2034 | { |
2035 | error = FT_THROW( Invalid_File_Format ); |
2036 | goto Fail; |
2037 | } |
2038 | if ( parser->root.error ) |
2039 | return; |
2040 | |
2041 | if ( *cur == '/' ) |
2042 | { |
2043 | FT_UInt len; |
2044 | |
2045 | |
2046 | if ( cur + 2 >= limit ) |
2047 | { |
2048 | error = FT_THROW( Invalid_File_Format ); |
2049 | goto Fail; |
2050 | } |
2051 | |
2052 | cur++; /* skip `/' */ |
2053 | len = (FT_UInt)( parser->root.cursor - cur ); |
2054 | |
2055 | if ( !read_binary_data( parser, &size, &base, IS_INCREMENTAL ) ) |
2056 | return; |
2057 | |
2058 | /* for some non-standard fonts like `Optima' which provides */ |
2059 | /* different outlines depending on the resolution it is */ |
2060 | /* possible to get here twice */ |
2061 | if ( loader->num_glyphs ) |
2062 | continue; |
2063 | |
2064 | error = T1_Add_Table( name_table, n, cur, len + 1 ); |
2065 | if ( error ) |
2066 | goto Fail; |
2067 | |
2068 | /* add a trailing zero to the name table */ |
2069 | name_table->elements[n][len] = '\0'; |
2070 | |
2071 | /* record index of /.notdef */ |
2072 | if ( *cur == '.' && |
2073 | ft_strcmp( ".notdef" , |
2074 | (const char*)( name_table->elements[n] ) ) == 0 ) |
2075 | { |
2076 | notdef_index = n; |
2077 | notdef_found = 1; |
2078 | } |
2079 | |
2080 | if ( t1face->type1.private_dict.lenIV >= 0 && |
2081 | n < num_glyphs + TABLE_EXTEND ) |
2082 | { |
2083 | FT_Byte* temp = NULL; |
2084 | |
2085 | |
2086 | if ( size <= (FT_ULong)t1face->type1.private_dict.lenIV ) |
2087 | { |
2088 | error = FT_THROW( Invalid_File_Format ); |
2089 | goto Fail; |
2090 | } |
2091 | |
2092 | /* t1_decrypt() shouldn't write to base -- make temporary copy */ |
2093 | if ( FT_QALLOC( temp, size ) ) |
2094 | goto Fail; |
2095 | FT_MEM_COPY( temp, base, size ); |
2096 | psaux->t1_decrypt( temp, size, 4330 ); |
2097 | size -= (FT_ULong)t1face->type1.private_dict.lenIV; |
2098 | error = T1_Add_Table( code_table, |
2099 | n, |
2100 | temp + t1face->type1.private_dict.lenIV, |
2101 | size ); |
2102 | FT_FREE( temp ); |
2103 | } |
2104 | else |
2105 | error = T1_Add_Table( code_table, n, base, size ); |
2106 | if ( error ) |
2107 | goto Fail; |
2108 | |
2109 | n++; |
2110 | } |
2111 | } |
2112 | |
2113 | if ( !n ) |
2114 | { |
2115 | error = FT_THROW( Invalid_File_Format ); |
2116 | goto Fail; |
2117 | } |
2118 | |
2119 | loader->num_glyphs = n; |
2120 | |
2121 | /* if /.notdef is found but does not occupy index 0, do our magic. */ |
2122 | if ( notdef_found && |
2123 | ft_strcmp( ".notdef" , (const char*)name_table->elements[0] ) ) |
2124 | { |
2125 | /* Swap glyph in index 0 with /.notdef glyph. First, add index 0 */ |
2126 | /* name and code entries to swap_table. Then place notdef_index */ |
2127 | /* name and code entries into swap_table. Then swap name and code */ |
2128 | /* entries at indices notdef_index and 0 using values stored in */ |
2129 | /* swap_table. */ |
2130 | |
2131 | /* Index 0 name */ |
2132 | error = T1_Add_Table( swap_table, 0, |
2133 | name_table->elements[0], |
2134 | name_table->lengths [0] ); |
2135 | if ( error ) |
2136 | goto Fail; |
2137 | |
2138 | /* Index 0 code */ |
2139 | error = T1_Add_Table( swap_table, 1, |
2140 | code_table->elements[0], |
2141 | code_table->lengths [0] ); |
2142 | if ( error ) |
2143 | goto Fail; |
2144 | |
2145 | /* Index notdef_index name */ |
2146 | error = T1_Add_Table( swap_table, 2, |
2147 | name_table->elements[notdef_index], |
2148 | name_table->lengths [notdef_index] ); |
2149 | if ( error ) |
2150 | goto Fail; |
2151 | |
2152 | /* Index notdef_index code */ |
2153 | error = T1_Add_Table( swap_table, 3, |
2154 | code_table->elements[notdef_index], |
2155 | code_table->lengths [notdef_index] ); |
2156 | if ( error ) |
2157 | goto Fail; |
2158 | |
2159 | error = T1_Add_Table( name_table, notdef_index, |
2160 | swap_table->elements[0], |
2161 | swap_table->lengths [0] ); |
2162 | if ( error ) |
2163 | goto Fail; |
2164 | |
2165 | error = T1_Add_Table( code_table, notdef_index, |
2166 | swap_table->elements[1], |
2167 | swap_table->lengths [1] ); |
2168 | if ( error ) |
2169 | goto Fail; |
2170 | |
2171 | error = T1_Add_Table( name_table, 0, |
2172 | swap_table->elements[2], |
2173 | swap_table->lengths [2] ); |
2174 | if ( error ) |
2175 | goto Fail; |
2176 | |
2177 | error = T1_Add_Table( code_table, 0, |
2178 | swap_table->elements[3], |
2179 | swap_table->lengths [3] ); |
2180 | if ( error ) |
2181 | goto Fail; |
2182 | |
2183 | } |
2184 | else if ( !notdef_found ) |
2185 | { |
2186 | /* notdef_index is already 0, or /.notdef is undefined in */ |
2187 | /* charstrings dictionary. Worry about /.notdef undefined. */ |
2188 | /* We take index 0 and add it to the end of the table(s) */ |
2189 | /* and add our own /.notdef glyph to index 0. */ |
2190 | |
2191 | /* 0 333 hsbw endchar */ |
2192 | FT_Byte notdef_glyph[] = { 0x8B, 0xF7, 0xE1, 0x0D, 0x0E }; |
2193 | |
2194 | |
2195 | error = T1_Add_Table( swap_table, 0, |
2196 | name_table->elements[0], |
2197 | name_table->lengths [0] ); |
2198 | if ( error ) |
2199 | goto Fail; |
2200 | |
2201 | error = T1_Add_Table( swap_table, 1, |
2202 | code_table->elements[0], |
2203 | code_table->lengths [0] ); |
2204 | if ( error ) |
2205 | goto Fail; |
2206 | |
2207 | error = T1_Add_Table( name_table, 0, ".notdef" , 8 ); |
2208 | if ( error ) |
2209 | goto Fail; |
2210 | |
2211 | error = T1_Add_Table( code_table, 0, notdef_glyph, 5 ); |
2212 | |
2213 | if ( error ) |
2214 | goto Fail; |
2215 | |
2216 | error = T1_Add_Table( name_table, n, |
2217 | swap_table->elements[0], |
2218 | swap_table->lengths [0] ); |
2219 | if ( error ) |
2220 | goto Fail; |
2221 | |
2222 | error = T1_Add_Table( code_table, n, |
2223 | swap_table->elements[1], |
2224 | swap_table->lengths [1] ); |
2225 | if ( error ) |
2226 | goto Fail; |
2227 | |
2228 | /* we added a glyph. */ |
2229 | loader->num_glyphs += 1; |
2230 | } |
2231 | |
2232 | #ifdef FT_DEBUG_LEVEL_TRACE |
2233 | FT_TRACE4(( " <" )); |
2234 | |
2235 | /* XXX show charstrings? */ |
2236 | FT_TRACE4(( "%d elements" , loader->num_glyphs )); |
2237 | |
2238 | FT_TRACE4(( ">\n" )); |
2239 | #endif |
2240 | |
2241 | return; |
2242 | |
2243 | Fail: |
2244 | parser->root.error = error; |
2245 | } |
2246 | |
2247 | |
2248 | /************************************************************************** |
2249 | * |
2250 | * Define the token field static variables. This is a set of |
2251 | * T1_FieldRec variables. |
2252 | * |
2253 | */ |
2254 | |
2255 | |
2256 | static |
2257 | const T1_FieldRec t1_keywords[] = |
2258 | { |
2259 | |
2260 | #include "t1tokens.h" |
2261 | |
2262 | /* now add the special functions... */ |
2263 | T1_FIELD_CALLBACK( "FontMatrix" , t1_parse_font_matrix, |
2264 | T1_FIELD_DICT_FONTDICT ) |
2265 | T1_FIELD_CALLBACK( "Encoding" , parse_encoding, |
2266 | T1_FIELD_DICT_FONTDICT ) |
2267 | T1_FIELD_CALLBACK( "Subrs" , parse_subrs, |
2268 | T1_FIELD_DICT_PRIVATE ) |
2269 | T1_FIELD_CALLBACK( "CharStrings" , parse_charstrings, |
2270 | T1_FIELD_DICT_PRIVATE ) |
2271 | T1_FIELD_CALLBACK( "Private" , parse_private, |
2272 | T1_FIELD_DICT_FONTDICT ) |
2273 | |
2274 | #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT |
2275 | T1_FIELD_CALLBACK( "BlendDesignPositions" , parse_blend_design_positions, |
2276 | T1_FIELD_DICT_FONTDICT ) |
2277 | T1_FIELD_CALLBACK( "BlendDesignMap" , parse_blend_design_map, |
2278 | T1_FIELD_DICT_FONTDICT ) |
2279 | T1_FIELD_CALLBACK( "BlendAxisTypes" , parse_blend_axis_types, |
2280 | T1_FIELD_DICT_FONTDICT ) |
2281 | T1_FIELD_CALLBACK( "WeightVector" , parse_weight_vector, |
2282 | T1_FIELD_DICT_FONTDICT ) |
2283 | T1_FIELD_CALLBACK( "BuildCharArray" , parse_buildchar, |
2284 | T1_FIELD_DICT_PRIVATE ) |
2285 | #endif |
2286 | |
2287 | { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0, 0 } |
2288 | }; |
2289 | |
2290 | |
2291 | static FT_Error |
2292 | parse_dict( T1_Face face, |
2293 | T1_Loader loader, |
2294 | FT_Byte* base, |
2295 | FT_ULong size ) |
2296 | { |
2297 | T1_Parser parser = &loader->parser; |
2298 | FT_Byte *limit, *start_binary = NULL; |
2299 | FT_Bool have_integer = 0; |
2300 | |
2301 | |
2302 | parser->root.cursor = base; |
2303 | parser->root.limit = base + size; |
2304 | parser->root.error = FT_Err_Ok; |
2305 | |
2306 | limit = parser->root.limit; |
2307 | |
2308 | T1_Skip_Spaces( parser ); |
2309 | |
2310 | while ( parser->root.cursor < limit ) |
2311 | { |
2312 | FT_Byte* cur; |
2313 | |
2314 | |
2315 | cur = parser->root.cursor; |
2316 | |
2317 | /* look for `eexec' */ |
2318 | if ( IS_PS_TOKEN( cur, limit, "eexec" ) ) |
2319 | break; |
2320 | |
2321 | /* look for `closefile' which ends the eexec section */ |
2322 | else if ( IS_PS_TOKEN( cur, limit, "closefile" ) ) |
2323 | break; |
2324 | |
2325 | /* in a synthetic font the base font starts after a */ |
2326 | /* `FontDictionary' token that is placed after a Private dict */ |
2327 | else if ( IS_PS_TOKEN( cur, limit, "FontDirectory" ) ) |
2328 | { |
2329 | if ( loader->keywords_encountered & T1_PRIVATE ) |
2330 | loader->keywords_encountered |= |
2331 | T1_FONTDIR_AFTER_PRIVATE; |
2332 | parser->root.cursor += 13; |
2333 | } |
2334 | |
2335 | /* check whether we have an integer */ |
2336 | else if ( ft_isdigit( *cur ) ) |
2337 | { |
2338 | start_binary = cur; |
2339 | T1_Skip_PS_Token( parser ); |
2340 | if ( parser->root.error ) |
2341 | goto Exit; |
2342 | have_integer = 1; |
2343 | } |
2344 | |
2345 | /* in valid Type 1 fonts we don't see `RD' or `-|' directly */ |
2346 | /* since those tokens are handled by parse_subrs and */ |
2347 | /* parse_charstrings */ |
2348 | else if ( *cur == 'R' && cur + 6 < limit && *( cur + 1 ) == 'D' && |
2349 | have_integer ) |
2350 | { |
2351 | FT_ULong s; |
2352 | FT_Byte* b; |
2353 | |
2354 | |
2355 | parser->root.cursor = start_binary; |
2356 | if ( !read_binary_data( parser, &s, &b, IS_INCREMENTAL ) ) |
2357 | return FT_THROW( Invalid_File_Format ); |
2358 | have_integer = 0; |
2359 | } |
2360 | |
2361 | else if ( *cur == '-' && cur + 6 < limit && *( cur + 1 ) == '|' && |
2362 | have_integer ) |
2363 | { |
2364 | FT_ULong s; |
2365 | FT_Byte* b; |
2366 | |
2367 | |
2368 | parser->root.cursor = start_binary; |
2369 | if ( !read_binary_data( parser, &s, &b, IS_INCREMENTAL ) ) |
2370 | return FT_THROW( Invalid_File_Format ); |
2371 | have_integer = 0; |
2372 | } |
2373 | |
2374 | /* look for immediates */ |
2375 | else if ( *cur == '/' && cur + 2 < limit ) |
2376 | { |
2377 | FT_UInt len; |
2378 | |
2379 | |
2380 | cur++; |
2381 | |
2382 | parser->root.cursor = cur; |
2383 | T1_Skip_PS_Token( parser ); |
2384 | if ( parser->root.error ) |
2385 | goto Exit; |
2386 | |
2387 | len = (FT_UInt)( parser->root.cursor - cur ); |
2388 | |
2389 | if ( len > 0 && len < 22 && parser->root.cursor < limit ) |
2390 | { |
2391 | /* now compare the immediate name to the keyword table */ |
2392 | T1_Field keyword = (T1_Field)t1_keywords; |
2393 | |
2394 | |
2395 | for (;;) |
2396 | { |
2397 | FT_Byte* name; |
2398 | |
2399 | |
2400 | name = (FT_Byte*)keyword->ident; |
2401 | if ( !name ) |
2402 | break; |
2403 | |
2404 | if ( cur[0] == name[0] && |
2405 | len == ft_strlen( (const char *)name ) && |
2406 | ft_memcmp( cur, name, len ) == 0 ) |
2407 | { |
2408 | /* We found it -- run the parsing callback! */ |
2409 | /* We record every instance of every field */ |
2410 | /* (until we reach the base font of a */ |
2411 | /* synthetic font) to deal adequately with */ |
2412 | /* multiple master fonts; this is also */ |
2413 | /* necessary because later PostScript */ |
2414 | /* definitions override earlier ones. */ |
2415 | |
2416 | /* Once we encounter `FontDirectory' after */ |
2417 | /* `/Private', we know that this is a synthetic */ |
2418 | /* font; except for `/CharStrings' we are not */ |
2419 | /* interested in anything that follows this */ |
2420 | /* `FontDirectory'. */ |
2421 | |
2422 | /* MM fonts have more than one /Private token at */ |
2423 | /* the top level; let's hope that all the junk */ |
2424 | /* that follows the first /Private token is not */ |
2425 | /* interesting to us. */ |
2426 | |
2427 | /* According to Adobe Tech Note #5175 (CID-Keyed */ |
2428 | /* Font Installation for ATM Software) a `begin' */ |
2429 | /* must be followed by exactly one `end', and */ |
2430 | /* `begin' -- `end' pairs must be accurately */ |
2431 | /* paired. We could use this to distinguish */ |
2432 | /* between the global Private and the Private */ |
2433 | /* dict that is a member of the Blend dict. */ |
2434 | |
2435 | const FT_UInt dict = |
2436 | ( loader->keywords_encountered & T1_PRIVATE ) |
2437 | ? T1_FIELD_DICT_PRIVATE |
2438 | : T1_FIELD_DICT_FONTDICT; |
2439 | |
2440 | |
2441 | if ( !( dict & keyword->dict ) ) |
2442 | { |
2443 | FT_TRACE1(( "parse_dict: found `%s' but ignoring it" |
2444 | " since it is in the wrong dictionary\n" , |
2445 | keyword->ident )); |
2446 | break; |
2447 | } |
2448 | |
2449 | if ( !( loader->keywords_encountered & |
2450 | T1_FONTDIR_AFTER_PRIVATE ) || |
2451 | ft_strcmp( (const char*)name, "CharStrings" ) == 0 ) |
2452 | { |
2453 | parser->root.error = t1_load_keyword( face, |
2454 | loader, |
2455 | keyword ); |
2456 | if ( parser->root.error ) |
2457 | { |
2458 | if ( FT_ERR_EQ( parser->root.error, Ignore ) ) |
2459 | parser->root.error = FT_Err_Ok; |
2460 | else |
2461 | return parser->root.error; |
2462 | } |
2463 | } |
2464 | break; |
2465 | } |
2466 | |
2467 | keyword++; |
2468 | } |
2469 | } |
2470 | |
2471 | have_integer = 0; |
2472 | } |
2473 | else |
2474 | { |
2475 | T1_Skip_PS_Token( parser ); |
2476 | if ( parser->root.error ) |
2477 | goto Exit; |
2478 | have_integer = 0; |
2479 | } |
2480 | |
2481 | T1_Skip_Spaces( parser ); |
2482 | } |
2483 | |
2484 | Exit: |
2485 | return parser->root.error; |
2486 | } |
2487 | |
2488 | |
2489 | static void |
2490 | t1_init_loader( T1_Loader loader, |
2491 | T1_Face face ) |
2492 | { |
2493 | FT_UNUSED( face ); |
2494 | |
2495 | FT_ZERO( loader ); |
2496 | } |
2497 | |
2498 | |
2499 | static void |
2500 | t1_done_loader( T1_Loader loader ) |
2501 | { |
2502 | T1_Parser parser = &loader->parser; |
2503 | FT_Memory memory = parser->root.memory; |
2504 | |
2505 | |
2506 | /* finalize tables */ |
2507 | T1_Release_Table( &loader->encoding_table ); |
2508 | T1_Release_Table( &loader->charstrings ); |
2509 | T1_Release_Table( &loader->glyph_names ); |
2510 | T1_Release_Table( &loader->swap_table ); |
2511 | T1_Release_Table( &loader->subrs ); |
2512 | |
2513 | /* finalize hash */ |
2514 | ft_hash_num_free( loader->subrs_hash, memory ); |
2515 | FT_FREE( loader->subrs_hash ); |
2516 | |
2517 | /* finalize parser */ |
2518 | T1_Finalize_Parser( parser ); |
2519 | } |
2520 | |
2521 | |
2522 | FT_LOCAL_DEF( FT_Error ) |
2523 | T1_Open_Face( T1_Face face ) |
2524 | { |
2525 | T1_LoaderRec loader; |
2526 | T1_Parser parser; |
2527 | T1_Font type1 = &face->type1; |
2528 | PS_Private priv = &type1->private_dict; |
2529 | FT_Error error; |
2530 | |
2531 | PSAux_Service psaux = (PSAux_Service)face->psaux; |
2532 | |
2533 | |
2534 | t1_init_loader( &loader, face ); |
2535 | |
2536 | /* default values */ |
2537 | face->ndv_idx = -1; |
2538 | face->cdv_idx = -1; |
2539 | face->len_buildchar = 0; |
2540 | |
2541 | priv->blue_shift = 7; |
2542 | priv->blue_fuzz = 1; |
2543 | priv->lenIV = 4; |
2544 | priv->expansion_factor = (FT_Fixed)( 0.06 * 0x10000L ); |
2545 | priv->blue_scale = (FT_Fixed)( 0.039625 * 0x10000L * 1000 ); |
2546 | |
2547 | parser = &loader.parser; |
2548 | error = T1_New_Parser( parser, |
2549 | face->root.stream, |
2550 | face->root.memory, |
2551 | psaux ); |
2552 | if ( error ) |
2553 | goto Exit; |
2554 | |
2555 | FT_TRACE4(( " top dictionary:\n" )); |
2556 | error = parse_dict( face, &loader, |
2557 | parser->base_dict, parser->base_len ); |
2558 | if ( error ) |
2559 | goto Exit; |
2560 | |
2561 | error = T1_Get_Private_Dict( parser, psaux ); |
2562 | if ( error ) |
2563 | goto Exit; |
2564 | |
2565 | FT_TRACE4(( " private dictionary:\n" )); |
2566 | error = parse_dict( face, &loader, |
2567 | parser->private_dict, parser->private_len ); |
2568 | if ( error ) |
2569 | goto Exit; |
2570 | |
2571 | /* ensure even-ness of `num_blue_values' */ |
2572 | priv->num_blue_values &= ~1; |
2573 | |
2574 | #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT |
2575 | |
2576 | /* we don't support Multiple Master fonts with intermediate designs; */ |
2577 | /* this implies that `num_designs' must be equal to `2^^num_axis' */ |
2578 | if ( face->blend && |
2579 | face->blend->num_designs != ( 1U << face->blend->num_axis ) ) |
2580 | { |
2581 | FT_ERROR(( "T1_Open_Face:" |
2582 | " number-of-designs != 2 ^^ number-of-axes\n" )); |
2583 | T1_Done_Blend( FT_FACE( face ) ); |
2584 | } |
2585 | |
2586 | if ( face->blend && |
2587 | face->blend->num_default_design_vector != 0 && |
2588 | face->blend->num_default_design_vector != face->blend->num_axis ) |
2589 | { |
2590 | /* we don't use it currently so just warn, reset, and ignore */ |
2591 | FT_ERROR(( "T1_Open_Face(): /DesignVector contains %u entries " |
2592 | "while there are %u axes.\n" , |
2593 | face->blend->num_default_design_vector, |
2594 | face->blend->num_axis )); |
2595 | |
2596 | face->blend->num_default_design_vector = 0; |
2597 | } |
2598 | |
2599 | /* the following can happen for MM instances; we then treat the */ |
2600 | /* font as a normal PS font */ |
2601 | if ( face->blend && |
2602 | ( !face->blend->num_designs || !face->blend->num_axis ) ) |
2603 | T1_Done_Blend( FT_FACE( face ) ); |
2604 | |
2605 | /* the font may have no valid WeightVector */ |
2606 | if ( face->blend && !face->blend->weight_vector ) |
2607 | T1_Done_Blend( FT_FACE( face ) ); |
2608 | |
2609 | /* the font may have no valid BlendDesignPositions */ |
2610 | if ( face->blend && !face->blend->design_pos[0] ) |
2611 | T1_Done_Blend( FT_FACE( face ) ); |
2612 | |
2613 | /* the font may have no valid BlendDesignMap */ |
2614 | if ( face->blend ) |
2615 | { |
2616 | FT_UInt i; |
2617 | |
2618 | |
2619 | for ( i = 0; i < face->blend->num_axis; i++ ) |
2620 | if ( !face->blend->design_map[i].num_points ) |
2621 | { |
2622 | T1_Done_Blend( FT_FACE( face ) ); |
2623 | break; |
2624 | } |
2625 | } |
2626 | |
2627 | if ( face->blend ) |
2628 | { |
2629 | if ( face->len_buildchar > 0 ) |
2630 | { |
2631 | FT_Memory memory = face->root.memory; |
2632 | |
2633 | |
2634 | if ( FT_NEW_ARRAY( face->buildchar, face->len_buildchar ) ) |
2635 | { |
2636 | FT_ERROR(( "T1_Open_Face: cannot allocate BuildCharArray\n" )); |
2637 | face->len_buildchar = 0; |
2638 | goto Exit; |
2639 | } |
2640 | } |
2641 | } |
2642 | else |
2643 | face->len_buildchar = 0; |
2644 | |
2645 | #endif /* !T1_CONFIG_OPTION_NO_MM_SUPPORT */ |
2646 | |
2647 | /* now, propagate the subrs, charstrings, and glyphnames tables */ |
2648 | /* to the Type1 data */ |
2649 | type1->num_glyphs = loader.num_glyphs; |
2650 | |
2651 | if ( loader.subrs.init ) |
2652 | { |
2653 | type1->num_subrs = loader.num_subrs; |
2654 | type1->subrs_block = loader.subrs.block; |
2655 | type1->subrs = loader.subrs.elements; |
2656 | type1->subrs_len = loader.subrs.lengths; |
2657 | type1->subrs_hash = loader.subrs_hash; |
2658 | |
2659 | /* prevent `t1_done_loader' from freeing the propagated data */ |
2660 | loader.subrs.init = 0; |
2661 | loader.subrs_hash = NULL; |
2662 | } |
2663 | |
2664 | if ( !IS_INCREMENTAL ) |
2665 | if ( !loader.charstrings.init ) |
2666 | { |
2667 | FT_ERROR(( "T1_Open_Face: no `/CharStrings' array in face\n" )); |
2668 | error = FT_THROW( Invalid_File_Format ); |
2669 | } |
2670 | |
2671 | loader.charstrings.init = 0; |
2672 | type1->charstrings_block = loader.charstrings.block; |
2673 | type1->charstrings = loader.charstrings.elements; |
2674 | type1->charstrings_len = loader.charstrings.lengths; |
2675 | |
2676 | /* we copy the glyph names `block' and `elements' fields; */ |
2677 | /* the `lengths' field must be released later */ |
2678 | type1->glyph_names_block = loader.glyph_names.block; |
2679 | type1->glyph_names = (FT_String**)loader.glyph_names.elements; |
2680 | loader.glyph_names.block = NULL; |
2681 | loader.glyph_names.elements = NULL; |
2682 | |
2683 | /* we must now build type1.encoding when we have a custom array */ |
2684 | if ( type1->encoding_type == T1_ENCODING_TYPE_ARRAY ) |
2685 | { |
2686 | FT_Int charcode, idx, min_char, max_char; |
2687 | |
2688 | |
2689 | /* OK, we do the following: for each element in the encoding */ |
2690 | /* table, look up the index of the glyph having the same name */ |
2691 | /* the index is then stored in type1.encoding.char_index, and */ |
2692 | /* the name to type1.encoding.char_name */ |
2693 | |
2694 | min_char = 0; |
2695 | max_char = 0; |
2696 | |
2697 | charcode = 0; |
2698 | for ( ; charcode < loader.encoding_table.max_elems; charcode++ ) |
2699 | { |
2700 | const FT_String* char_name = |
2701 | (const FT_String*)loader.encoding_table.elements[charcode]; |
2702 | |
2703 | |
2704 | type1->encoding.char_index[charcode] = 0; |
2705 | type1->encoding.char_name [charcode] = ".notdef" ; |
2706 | |
2707 | if ( char_name ) |
2708 | for ( idx = 0; idx < type1->num_glyphs; idx++ ) |
2709 | { |
2710 | const FT_String* glyph_name = type1->glyph_names[idx]; |
2711 | |
2712 | |
2713 | if ( ft_strcmp( char_name, glyph_name ) == 0 ) |
2714 | { |
2715 | type1->encoding.char_index[charcode] = (FT_UShort)idx; |
2716 | type1->encoding.char_name [charcode] = glyph_name; |
2717 | |
2718 | /* Change min/max encoded char only if glyph name is */ |
2719 | /* not /.notdef */ |
2720 | if ( ft_strcmp( ".notdef" , glyph_name ) != 0 ) |
2721 | { |
2722 | if ( charcode < min_char ) |
2723 | min_char = charcode; |
2724 | if ( charcode >= max_char ) |
2725 | max_char = charcode + 1; |
2726 | } |
2727 | break; |
2728 | } |
2729 | } |
2730 | } |
2731 | |
2732 | type1->encoding.code_first = min_char; |
2733 | type1->encoding.code_last = max_char; |
2734 | type1->encoding.num_chars = loader.num_chars; |
2735 | } |
2736 | |
2737 | /* some sanitizing to avoid overflows later on; */ |
2738 | /* the upper limits are ad-hoc values */ |
2739 | if ( priv->blue_shift > 1000 || priv->blue_shift < 0 ) |
2740 | { |
2741 | FT_TRACE2(( "T1_Open_Face:" |
2742 | " setting unlikely BlueShift value %d to default (7)\n" , |
2743 | priv->blue_shift )); |
2744 | priv->blue_shift = 7; |
2745 | } |
2746 | |
2747 | if ( priv->blue_fuzz > 1000 || priv->blue_fuzz < 0 ) |
2748 | { |
2749 | FT_TRACE2(( "T1_Open_Face:" |
2750 | " setting unlikely BlueFuzz value %d to default (1)\n" , |
2751 | priv->blue_fuzz )); |
2752 | priv->blue_fuzz = 1; |
2753 | } |
2754 | |
2755 | Exit: |
2756 | t1_done_loader( &loader ); |
2757 | return error; |
2758 | } |
2759 | |
2760 | |
2761 | /* END */ |
2762 | |