sdk-world v2026.11.05
PS2 SDK - world tier (copyleft-allowed, non-essential packages)
Loading...
Searching...
No Matches
t1load.c
1/****************************************************************************
2 *
3 * t1load.c
4 *
5 * Type 1 font loader (body).
6 *
7 * Copyright (C) 1996-2025 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>
65#include FT_CONFIG_CONFIG_H
66#include <freetype/ftmm.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 %u of %u 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_WeightVector( 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 %u of %u 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->blend_points );
755 FT_FREE( dmap->design_points );
756 dmap->num_points = 0;
757 }
758
759 FT_FREE( t1face->blend );
760 }
761 }
762
763
764 static void
765 parse_blend_axis_types( FT_Face face, /* T1_Face */
766 void* loader_ )
767 {
768 T1_Face t1face = (T1_Face)face;
769 T1_Loader loader = (T1_Loader)loader_;
770 T1_TokenRec axis_tokens[T1_MAX_MM_AXIS];
771 FT_Int n, num_axis;
772 FT_Error error = FT_Err_Ok;
773 PS_Blend blend;
774 FT_Memory memory = FT_FACE_MEMORY( face );
775
776
777 /* take an array of objects */
778 T1_ToTokenArray( &loader->parser, axis_tokens,
779 T1_MAX_MM_AXIS, &num_axis );
780 if ( num_axis < 0 )
781 {
782 error = FT_ERR( Ignore );
783 goto Exit;
784 }
785 if ( num_axis == 0 || num_axis > T1_MAX_MM_AXIS )
786 {
787 FT_ERROR(( "parse_blend_axis_types: incorrect number of axes: %d\n",
788 num_axis ));
789 error = FT_THROW( Invalid_File_Format );
790 goto Exit;
791 }
792
793 /* allocate blend if necessary */
794 error = t1_allocate_blend( t1face, 0, (FT_UInt)num_axis );
795 if ( error )
796 goto Exit;
797
798 FT_TRACE4(( " [" ));
799
800 blend = t1face->blend;
801
802 /* each token is an immediate containing the name of the axis */
803 for ( n = 0; n < num_axis; n++ )
804 {
805 T1_Token token = axis_tokens + n;
806 FT_Byte* name;
807 FT_UInt len;
808
809
810 /* skip first slash, if any */
811 if ( token->start[0] == '/' )
812 token->start++;
813
814 len = (FT_UInt)( token->limit - token->start );
815 if ( len == 0 )
816 {
817 error = FT_THROW( Invalid_File_Format );
818 goto Exit;
819 }
820
821 FT_TRACE4(( " /%.*s", len, token->start ));
822
823 name = (FT_Byte*)blend->axis_names[n];
824 if ( name )
825 {
826 FT_TRACE0(( "parse_blend_axis_types:"
827 " overwriting axis name `%s' with `%.*s'\n",
828 name, len, token->start ));
829 FT_FREE( name );
830 }
831
832 if ( FT_QALLOC( blend->axis_names[n], len + 1 ) )
833 goto Exit;
834
835 name = (FT_Byte*)blend->axis_names[n];
836 FT_MEM_COPY( name, token->start, len );
837 name[len] = '\0';
838 }
839
840 FT_TRACE4(( "]\n" ));
841
842 Exit:
843 loader->parser.root.error = error;
844 }
845
846
847 static void
848 parse_blend_design_positions( FT_Face face, /* T1_Face */
849 void* loader_ )
850 {
851 T1_Face t1face = (T1_Face)face;
852 T1_Loader loader = (T1_Loader)loader_;
853 T1_TokenRec design_tokens[T1_MAX_MM_DESIGNS];
854 FT_Int num_designs;
855 FT_Int num_axis = 0; /* make compiler happy */
856 T1_Parser parser = &loader->parser;
857 FT_Memory memory = FT_FACE_MEMORY( face );
858 FT_Error error = FT_Err_Ok;
859 FT_Fixed* design_pos[T1_MAX_MM_DESIGNS];
860
861
862 design_pos[0] = NULL;
863
864 /* get the array of design tokens -- compute number of designs */
865 T1_ToTokenArray( parser, design_tokens,
866 T1_MAX_MM_DESIGNS, &num_designs );
867 if ( num_designs < 0 )
868 {
869 error = FT_ERR( Ignore );
870 goto Exit;
871 }
872 if ( num_designs == 0 || num_designs > T1_MAX_MM_DESIGNS )
873 {
874 FT_ERROR(( "parse_blend_design_positions:"
875 " incorrect number of designs: %d\n",
876 num_designs ));
877 error = FT_THROW( Invalid_File_Format );
878 goto Exit;
879 }
880
881 {
882 FT_Byte* old_cursor = parser->root.cursor;
883 FT_Byte* old_limit = parser->root.limit;
884 FT_Int n, nn;
885 PS_Blend blend;
886
887
888 FT_TRACE4(( " [" ));
889
890 for ( n = 0; n < num_designs; n++ )
891 {
892 T1_TokenRec axis_tokens[T1_MAX_MM_AXIS];
893 T1_Token token;
894 FT_Int axis, n_axis;
895
896
897 /* read axis/coordinates tokens */
898 token = design_tokens + n;
899 parser->root.cursor = token->start;
900 parser->root.limit = token->limit;
901 T1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &n_axis );
902
903 if ( n == 0 )
904 {
905 if ( n_axis <= 0 || n_axis > T1_MAX_MM_AXIS )
906 {
907 FT_ERROR(( "parse_blend_design_positions:"
908 " invalid number of axes: %d\n",
909 n_axis ));
910 error = FT_THROW( Invalid_File_Format );
911 goto Exit;
912 }
913
914 num_axis = n_axis;
915 error = t1_allocate_blend( t1face,
916 (FT_UInt)num_designs,
917 (FT_UInt)num_axis );
918 if ( error )
919 goto Exit;
920
921 /* allocate a blend design pos table */
922 if ( FT_QNEW_ARRAY( design_pos[0], num_designs * num_axis ) )
923 goto Exit;
924
925 for ( nn = 1; nn < num_designs; nn++ )
926 design_pos[nn] = design_pos[0] + num_axis * nn;
927 }
928 else if ( n_axis != num_axis )
929 {
930 FT_ERROR(( "parse_blend_design_positions: incorrect table\n" ));
931 error = FT_THROW( Invalid_File_Format );
932 goto Exit;
933 }
934
935 /* now read each axis token into the design position */
936 FT_TRACE4(( " [" )) ;
937 for ( axis = 0; axis < n_axis; axis++ )
938 {
939 T1_Token token2 = axis_tokens + axis;
940
941
942 parser->root.cursor = token2->start;
943 parser->root.limit = token2->limit;
944 design_pos[n][axis] = T1_ToFixed( parser, 0 );
945 FT_TRACE4(( " %f", (double)design_pos[n][axis] / 65536 ));
946 }
947 FT_TRACE4(( "]" )) ;
948 }
949
950 FT_TRACE4(( "]\n" ));
951
952 loader->parser.root.cursor = old_cursor;
953 loader->parser.root.limit = old_limit;
954
955 /* a valid BlendDesignPosition has been parsed */
956 blend = t1face->blend;
957 if ( blend->design_pos[0] )
958 FT_FREE( blend->design_pos[0] );
959
960 for ( n = 0; n < num_designs; n++ )
961 {
962 blend->design_pos[n] = design_pos[n];
963 design_pos[n] = NULL;
964 }
965 }
966
967 Exit:
968 FT_FREE( design_pos[0] );
969 loader->parser.root.error = error;
970 }
971
972
973 static void
974 parse_blend_design_map( FT_Face face, /* T1_Face */
975 void* loader_ )
976 {
977 T1_Face t1face = (T1_Face)face;
978 T1_Loader loader = (T1_Loader)loader_;
979 FT_Error error = FT_Err_Ok;
980 T1_Parser parser = &loader->parser;
981 PS_Blend blend;
982 T1_TokenRec axis_tokens[T1_MAX_MM_AXIS];
983 FT_Int n, num_axis;
984 FT_Byte* old_cursor;
985 FT_Byte* old_limit;
986 FT_Memory memory = FT_FACE_MEMORY( face );
987
988
989 T1_ToTokenArray( parser, axis_tokens,
990 T1_MAX_MM_AXIS, &num_axis );
991 if ( num_axis < 0 )
992 {
993 error = FT_ERR( Ignore );
994 goto Exit;
995 }
996 if ( num_axis == 0 || num_axis > T1_MAX_MM_AXIS )
997 {
998 FT_ERROR(( "parse_blend_design_map: incorrect number of axes: %d\n",
999 num_axis ));
1000 error = FT_THROW( Invalid_File_Format );
1001 goto Exit;
1002 }
1003
1004 old_cursor = parser->root.cursor;
1005 old_limit = parser->root.limit;
1006
1007 error = t1_allocate_blend( t1face, 0, (FT_UInt)num_axis );
1008 if ( error )
1009 goto Exit;
1010 blend = t1face->blend;
1011
1012 FT_TRACE4(( " [" ));
1013
1014 /* now read each axis design map */
1015 for ( n = 0; n < num_axis; n++ )
1016 {
1017 PS_DesignMap map = blend->design_map + n;
1018 T1_Token axis_token;
1019 T1_TokenRec point_tokens[T1_MAX_MM_MAP_POINTS];
1020 FT_Int p, num_points;
1021
1022
1023 axis_token = axis_tokens + n;
1024
1025 parser->root.cursor = axis_token->start;
1026 parser->root.limit = axis_token->limit;
1027 T1_ToTokenArray( parser, point_tokens,
1028 T1_MAX_MM_MAP_POINTS, &num_points );
1029
1030 FT_TRACE4(( " [" ));
1031
1032 if ( num_points <= 0 || num_points > T1_MAX_MM_MAP_POINTS )
1033 {
1034 FT_ERROR(( "parse_blend_design_map: incorrect table\n" ));
1035 error = FT_THROW( Invalid_File_Format );
1036 goto Exit;
1037 }
1038
1039 if ( map->design_points )
1040 {
1041 FT_ERROR(( "parse_blend_design_map: duplicate table\n" ));
1042 error = FT_THROW( Invalid_File_Format );
1043 goto Exit;
1044 }
1045
1046 /* allocate design map data */
1047 if ( FT_QNEW_ARRAY( map->design_points, num_points ) ||
1048 FT_QNEW_ARRAY( map->blend_points, num_points ) )
1049 goto Exit;
1050 map->num_points = (FT_Byte)num_points;
1051
1052 for ( p = 0; p < num_points; p++ )
1053 {
1054 T1_Token point_token;
1055
1056
1057 point_token = point_tokens + p;
1058
1059 /* don't include delimiting brackets */
1060 parser->root.cursor = point_token->start + 1;
1061 parser->root.limit = point_token->limit - 1;
1062
1063 map->design_points[p] = T1_ToInt( parser );
1064 map->blend_points [p] = T1_ToFixed( parser, 0 );
1065
1066 FT_TRACE4(( " [%ld %f]",
1067 map->design_points[p],
1068 (double)map->blend_points[p] / 65536 ));
1069 }
1070
1071 FT_TRACE4(( "]" ));
1072 }
1073
1074 FT_TRACE4(( "]\n" ));
1075
1076 parser->root.cursor = old_cursor;
1077 parser->root.limit = old_limit;
1078
1079 Exit:
1080 parser->root.error = error;
1081 }
1082
1083
1084 static void
1085 parse_weight_vector( FT_Face face, /* T1_Face */
1086 void* loader_ )
1087 {
1088 T1_Face t1face = (T1_Face)face;
1089 T1_Loader loader = (T1_Loader)loader_;
1090 T1_TokenRec design_tokens[T1_MAX_MM_DESIGNS];
1091 FT_Int num_designs;
1092 FT_Error error = FT_Err_Ok;
1093 FT_Memory memory = FT_FACE_MEMORY( face );
1094 T1_Parser parser = &loader->parser;
1095 PS_Blend blend = t1face->blend;
1096 T1_Token token;
1097 FT_Int n;
1098 FT_Byte* old_cursor;
1099 FT_Byte* old_limit;
1100
1101
1102 T1_ToTokenArray( parser, design_tokens,
1103 T1_MAX_MM_DESIGNS, &num_designs );
1104 if ( num_designs < 0 )
1105 {
1106 error = FT_ERR( Ignore );
1107 goto Exit;
1108 }
1109 if ( num_designs == 0 || num_designs > T1_MAX_MM_DESIGNS )
1110 {
1111 FT_ERROR(( "parse_weight_vector:"
1112 " incorrect number of designs: %d\n",
1113 num_designs ));
1114 error = FT_THROW( Invalid_File_Format );
1115 goto Exit;
1116 }
1117
1118 if ( !blend || !blend->num_designs )
1119 {
1120 error = t1_allocate_blend( t1face, (FT_UInt)num_designs, 0 );
1121 if ( error )
1122 goto Exit;
1123 blend = t1face->blend;
1124 }
1125 else if ( blend->num_designs != (FT_UInt)num_designs )
1126 {
1127 FT_ERROR(( "parse_weight_vector:"
1128 " /BlendDesignPosition and /WeightVector have\n" ));
1129 FT_ERROR(( " "
1130 " different number of elements\n" ));
1131 error = FT_THROW( Invalid_File_Format );
1132 goto Exit;
1133 }
1134
1135 if ( !blend->weight_vector )
1136 if ( FT_QNEW_ARRAY( blend->weight_vector, num_designs * 2 ) )
1137 goto Exit;
1138
1139 blend->default_weight_vector = blend->weight_vector + num_designs;
1140
1141 old_cursor = parser->root.cursor;
1142 old_limit = parser->root.limit;
1143
1144 FT_TRACE4(( "[" ));
1145
1146 for ( n = 0; n < num_designs; n++ )
1147 {
1148 token = design_tokens + n;
1149 parser->root.cursor = token->start;
1150 parser->root.limit = token->limit;
1151
1152 blend->default_weight_vector[n] =
1153 blend->weight_vector[n] = T1_ToFixed( parser, 0 );
1154
1155 FT_TRACE4(( " %f", (double)blend->weight_vector[n] / 65536 ));
1156 }
1157
1158 FT_TRACE4(( "]\n" ));
1159
1160 parser->root.cursor = old_cursor;
1161 parser->root.limit = old_limit;
1162
1163 Exit:
1164 parser->root.error = error;
1165 }
1166
1167
1168 /* e.g., /BuildCharArray [0 0 0 0 0 0 0 0] def */
1169 /* we're only interested in the number of array elements */
1170 static void
1171 parse_buildchar( FT_Face face, /* T1_Face */
1172 void* loader_ )
1173 {
1174 T1_Face t1face = (T1_Face)face;
1175 T1_Loader loader = (T1_Loader)loader_;
1176
1177
1178 t1face->len_buildchar = (FT_UInt)T1_ToFixedArray( &loader->parser,
1179 0, NULL, 0 );
1180
1181#ifdef FT_DEBUG_LEVEL_TRACE
1182 {
1183 FT_UInt i;
1184
1185
1186 FT_TRACE4(( " [" ));
1187 for ( i = 0; i < t1face->len_buildchar; i++ )
1188 FT_TRACE4(( " 0" ));
1189
1190 FT_TRACE4(( "]\n" ));
1191 }
1192#endif
1193
1194 return;
1195 }
1196
1197
1198#endif /* !T1_CONFIG_OPTION_NO_MM_SUPPORT */
1199
1200
1201
1202
1203 /*************************************************************************/
1204 /*************************************************************************/
1205 /***** *****/
1206 /***** TYPE 1 SYMBOL PARSING *****/
1207 /***** *****/
1208 /*************************************************************************/
1209 /*************************************************************************/
1210
1211 static FT_Error
1212 t1_load_keyword( T1_Face face,
1213 T1_Loader loader,
1214 const T1_Field field )
1215 {
1216 FT_Error error;
1217 void* dummy_object;
1218 void** objects;
1219 FT_UInt max_objects;
1220 PS_Blend blend = face->blend;
1221
1222
1223 if ( blend && blend->num_designs == 0 )
1224 blend = NULL;
1225
1226 /* if the keyword has a dedicated callback, call it */
1227 if ( field->type == T1_FIELD_TYPE_CALLBACK )
1228 {
1229 FT_TRACE4(( " %s", field->ident ));
1230
1231 field->reader( (FT_Face)face, loader );
1232 error = loader->parser.root.error;
1233 goto Exit;
1234 }
1235
1236 /* now, the keyword is either a simple field, or a table of fields; */
1237 /* we are now going to take care of it */
1238 switch ( field->location )
1239 {
1240 case T1_FIELD_LOCATION_FONT_INFO:
1241 dummy_object = &face->type1.font_info;
1242 objects = &dummy_object;
1243 max_objects = 0;
1244
1245 if ( blend )
1246 {
1247 objects = (void**)blend->font_infos;
1248 max_objects = blend->num_designs;
1249 }
1250 break;
1251
1252 case T1_FIELD_LOCATION_FONT_EXTRA:
1253 dummy_object = &face->type1.font_extra;
1254 objects = &dummy_object;
1255 max_objects = 0;
1256 break;
1257
1258 case T1_FIELD_LOCATION_PRIVATE:
1259 dummy_object = &face->type1.private_dict;
1260 objects = &dummy_object;
1261 max_objects = 0;
1262
1263 if ( blend )
1264 {
1265 objects = (void**)blend->privates;
1266 max_objects = blend->num_designs;
1267 }
1268 break;
1269
1270 case T1_FIELD_LOCATION_BBOX:
1271 dummy_object = &face->type1.font_bbox;
1272 objects = &dummy_object;
1273 max_objects = 0;
1274
1275 if ( blend )
1276 {
1277 objects = (void**)blend->bboxes;
1278 max_objects = blend->num_designs;
1279 }
1280 break;
1281
1282 case T1_FIELD_LOCATION_LOADER:
1283 dummy_object = loader;
1284 objects = &dummy_object;
1285 max_objects = 0;
1286 break;
1287
1288 case T1_FIELD_LOCATION_FACE:
1289 dummy_object = face;
1290 objects = &dummy_object;
1291 max_objects = 0;
1292 break;
1293
1294#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
1295 case T1_FIELD_LOCATION_BLEND:
1296 dummy_object = face->blend;
1297 objects = &dummy_object;
1298 max_objects = 0;
1299 break;
1300#endif
1301
1302 default:
1303 dummy_object = &face->type1;
1304 objects = &dummy_object;
1305 max_objects = 0;
1306 }
1307
1308 FT_TRACE4(( " %s", field->ident ));
1309
1310 if ( *objects )
1311 {
1312 if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY ||
1313 field->type == T1_FIELD_TYPE_FIXED_ARRAY )
1314 error = T1_Load_Field_Table( &loader->parser, field,
1315 objects, max_objects, 0 );
1316 else
1317 error = T1_Load_Field( &loader->parser, field,
1318 objects, max_objects, 0 );
1319 }
1320 else
1321 {
1322 FT_TRACE1(( "t1_load_keyword: ignoring keyword `%s'"
1323 " which is not valid at this point\n",
1324 field->ident ));
1325 FT_TRACE1(( " (probably due to missing keywords)\n" ));
1326 error = FT_Err_Ok;
1327 }
1328
1329 FT_TRACE4(( "\n" ));
1330
1331 Exit:
1332 return error;
1333 }
1334
1335
1336 static void
1337 parse_private( FT_Face face,
1338 void* loader_ )
1339 {
1340 T1_Loader loader = (T1_Loader)loader_;
1341 FT_UNUSED( face );
1342
1343 loader->keywords_encountered |= T1_PRIVATE;
1344
1345 FT_TRACE4(( "\n" ));
1346 }
1347
1348
1349 /* return 1 in case of success */
1350
1351 static int
1352 read_binary_data( T1_Parser parser,
1353 FT_ULong* size,
1354 FT_Byte** base,
1355 FT_Bool incremental )
1356 {
1357 FT_Byte* cur;
1358 FT_Byte* limit = parser->root.limit;
1359
1360
1361 /* the binary data has one of the following formats */
1362 /* */
1363 /* `size' [white*] RD white ....... ND */
1364 /* `size' [white*] -| white ....... |- */
1365 /* */
1366
1367 T1_Skip_Spaces( parser );
1368
1369 cur = parser->root.cursor;
1370
1371 if ( cur < limit && ft_isdigit( *cur ) )
1372 {
1373 FT_Long s = T1_ToInt( parser );
1374
1375
1376 T1_Skip_PS_Token( parser ); /* `RD' or `-|' or something else */
1377
1378 /* there is only one whitespace char after the */
1379 /* `RD' or `-|' token */
1380 *base = parser->root.cursor + 1;
1381
1382 if ( s >= 0 && s < limit - *base )
1383 {
1384 parser->root.cursor += s + 1;
1385 *size = (FT_ULong)s;
1386 return !parser->root.error;
1387 }
1388 }
1389
1390 if( !incremental )
1391 {
1392 FT_ERROR(( "read_binary_data: invalid size field\n" ));
1393 parser->root.error = FT_THROW( Invalid_File_Format );
1394 }
1395
1396 return 0;
1397 }
1398
1399
1400 /* We now define the routines to handle the `/Encoding', `/Subrs', */
1401 /* and `/CharStrings' dictionaries. */
1402
1403 static void
1404 t1_parse_font_matrix( FT_Face face, /* T1_Face */
1405 void* loader_ )
1406 {
1407 T1_Face t1face = (T1_Face)face;
1408 T1_Loader loader = (T1_Loader)loader_;
1409 T1_Parser parser = &loader->parser;
1410 FT_Matrix* matrix = &t1face->type1.font_matrix;
1411 FT_Vector* offset = &t1face->type1.font_offset;
1412 FT_Fixed temp[6];
1413 FT_Fixed temp_scale;
1414 FT_Int result;
1415
1416
1417 /* input is scaled by 1000 to accommodate default FontMatrix */
1418 result = T1_ToFixedArray( parser, 6, temp, 3 );
1419
1420 if ( result < 6 )
1421 {
1422 parser->root.error = FT_THROW( Invalid_File_Format );
1423 return;
1424 }
1425
1426 FT_TRACE4(( " [%f %f %f %f %f %f]\n",
1427 (double)temp[0] / 65536 / 1000,
1428 (double)temp[1] / 65536 / 1000,
1429 (double)temp[2] / 65536 / 1000,
1430 (double)temp[3] / 65536 / 1000,
1431 (double)temp[4] / 65536 / 1000,
1432 (double)temp[5] / 65536 / 1000 ));
1433
1434 temp_scale = FT_ABS( temp[3] );
1435
1436 if ( temp_scale == 0 )
1437 {
1438 FT_ERROR(( "t1_parse_font_matrix: invalid font matrix\n" ));
1439 parser->root.error = FT_THROW( Invalid_File_Format );
1440 return;
1441 }
1442
1443 /* atypical case */
1444 if ( temp_scale != 0x10000L )
1445 {
1446 /* set units per EM based on FontMatrix values */
1447 face->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale );
1448
1449 temp[0] = FT_DivFix( temp[0], temp_scale );
1450 temp[1] = FT_DivFix( temp[1], temp_scale );
1451 temp[2] = FT_DivFix( temp[2], temp_scale );
1452 temp[4] = FT_DivFix( temp[4], temp_scale );
1453 temp[5] = FT_DivFix( temp[5], temp_scale );
1454 temp[3] = temp[3] < 0 ? -0x10000L : 0x10000L;
1455 }
1456 matrix->xx = temp[0];
1457 matrix->yx = temp[1];
1458 matrix->xy = temp[2];
1459 matrix->yy = temp[3];
1460
1461 if ( !FT_Matrix_Check( matrix ) )
1462 {
1463 FT_ERROR(( "t1_parse_font_matrix: invalid font matrix\n" ));
1464 parser->root.error = FT_THROW( Invalid_File_Format );
1465 return;
1466 }
1467
1468 /* note that the offsets must be expressed in integer font units */
1469 offset->x = temp[4] >> 16;
1470 offset->y = temp[5] >> 16;
1471 }
1472
1473
1474 static void
1475 parse_encoding( FT_Face face, /* T1_Face */
1476 void* loader_ )
1477 {
1478 T1_Face t1face = (T1_Face)face;
1479 T1_Loader loader = (T1_Loader)loader_;
1480 T1_Parser parser = &loader->parser;
1481 FT_Byte* cur;
1482 FT_Byte* limit = parser->root.limit;
1483
1484 PSAux_Service psaux = (PSAux_Service)t1face->psaux;
1485
1486
1487 T1_Skip_Spaces( parser );
1488 cur = parser->root.cursor;
1489 if ( cur >= limit )
1490 {
1491 FT_ERROR(( "parse_encoding: out of bounds\n" ));
1492 parser->root.error = FT_THROW( Invalid_File_Format );
1493 return;
1494 }
1495
1496 /* if we have a number or `[', the encoding is an array, */
1497 /* and we must load it now */
1498 if ( ft_isdigit( *cur ) || *cur == '[' )
1499 {
1500 T1_Encoding encode = &t1face->type1.encoding;
1501 FT_Int count, array_size, n;
1502 PS_Table char_table = &loader->encoding_table;
1503 FT_Memory memory = parser->root.memory;
1504 FT_Error error;
1505 FT_Bool only_immediates = 0;
1506
1507
1508 /* read the number of entries in the encoding; should be 256 */
1509 if ( *cur == '[' )
1510 {
1511 count = 256;
1512 only_immediates = 1;
1513 parser->root.cursor++;
1514 }
1515 else
1516 count = (FT_Int)T1_ToInt( parser );
1517
1518 array_size = count;
1519 if ( count > 256 )
1520 {
1521 FT_TRACE2(( "parse_encoding:"
1522 " only using first 256 encoding array entries\n" ));
1523 array_size = 256;
1524 }
1525
1526 T1_Skip_Spaces( parser );
1527 if ( parser->root.cursor >= limit )
1528 return;
1529
1530 /* PostScript happily allows overwriting of encoding arrays */
1531 if ( encode->char_index )
1532 {
1533 FT_FREE( encode->char_index );
1534 FT_FREE( encode->char_name );
1535 T1_Release_Table( char_table );
1536 }
1537
1538 /* we use a T1_Table to store our charnames */
1539 loader->num_chars = encode->num_chars = array_size;
1540 if ( FT_QNEW_ARRAY( encode->char_index, array_size ) ||
1541 FT_QNEW_ARRAY( encode->char_name, array_size ) ||
1542 FT_SET_ERROR( psaux->ps_table_funcs->init(
1543 char_table, array_size, memory ) ) )
1544 {
1545 parser->root.error = error;
1546 return;
1547 }
1548
1549 /* We need to `zero' out encoding_table.elements */
1550 for ( n = 0; n < array_size; n++ )
1551 (void)T1_Add_Table( char_table, n, ".notdef", 8 );
1552
1553 /* Now we need to read records of the form */
1554 /* */
1555 /* ... charcode /charname ... */
1556 /* */
1557 /* for each entry in our table. */
1558 /* */
1559 /* We simply look for a number followed by an immediate */
1560 /* name. Note that this ignores correctly the sequence */
1561 /* that is often seen in type1 fonts: */
1562 /* */
1563 /* 0 1 255 { 1 index exch /.notdef put } for dup */
1564 /* */
1565 /* used to clean the encoding array before anything else. */
1566 /* */
1567 /* Alternatively, if the array is directly given as */
1568 /* */
1569 /* /Encoding [ ... ] */
1570 /* */
1571 /* we only read immediates. */
1572
1573 n = 0;
1574 T1_Skip_Spaces( parser );
1575
1576 while ( parser->root.cursor < limit )
1577 {
1578 cur = parser->root.cursor;
1579
1580 /* we stop when we encounter a `def' or `]' */
1581 if ( *cur == 'd' && cur + 3 < limit )
1582 {
1583 if ( cur[1] == 'e' &&
1584 cur[2] == 'f' &&
1585 IS_PS_DELIM( cur[3] ) )
1586 {
1587 FT_TRACE6(( "encoding end\n" ));
1588 cur += 3;
1589 break;
1590 }
1591 }
1592 if ( *cur == ']' )
1593 {
1594 FT_TRACE6(( "encoding end\n" ));
1595 cur++;
1596 break;
1597 }
1598
1599 /* check whether we've found an entry */
1600 if ( ft_isdigit( *cur ) || only_immediates )
1601 {
1602 FT_Int charcode;
1603
1604
1605 if ( only_immediates )
1606 charcode = n;
1607 else
1608 {
1609 charcode = (FT_Int)T1_ToInt( parser );
1610 T1_Skip_Spaces( parser );
1611
1612 /* protect against invalid charcode */
1613 if ( cur == parser->root.cursor )
1614 {
1615 parser->root.error = FT_THROW( Unknown_File_Format );
1616 return;
1617 }
1618 }
1619
1620 cur = parser->root.cursor;
1621
1622 if ( cur + 2 < limit && *cur == '/' && n < count )
1623 {
1624 FT_UInt len;
1625
1626
1627 cur++;
1628
1629 parser->root.cursor = cur;
1630 T1_Skip_PS_Token( parser );
1631 if ( parser->root.cursor >= limit )
1632 return;
1633 if ( parser->root.error )
1634 return;
1635
1636 len = (FT_UInt)( parser->root.cursor - cur );
1637
1638 if ( n < array_size )
1639 {
1640 parser->root.error = T1_Add_Table( char_table, charcode,
1641 cur, len + 1 );
1642 if ( parser->root.error )
1643 return;
1644 char_table->elements[charcode][len] = '\0';
1645 }
1646
1647 n++;
1648 }
1649 else if ( only_immediates )
1650 {
1651 /* Since the current position is not updated for */
1652 /* immediates-only mode we would get an infinite loop if */
1653 /* we don't do anything here. */
1654 /* */
1655 /* This encoding array is not valid according to the type1 */
1656 /* specification (it might be an encoding for a CID type1 */
1657 /* font, however), so we conclude that this font is NOT a */
1658 /* type1 font. */
1659 parser->root.error = FT_THROW( Unknown_File_Format );
1660 return;
1661 }
1662 }
1663 else
1664 {
1665 T1_Skip_PS_Token( parser );
1666 if ( parser->root.error )
1667 return;
1668 }
1669
1670 T1_Skip_Spaces( parser );
1671 }
1672
1673#ifdef FT_DEBUG_LEVEL_TRACE
1674 FT_TRACE4(( " [" ));
1675
1676 /* XXX show encoding vector */
1677 FT_TRACE4(( "..." ));
1678
1679 FT_TRACE4(( "]\n" ));
1680#endif
1681
1682 t1face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY;
1683 parser->root.cursor = cur;
1684 }
1685
1686 /* Otherwise, we should have either `StandardEncoding', */
1687 /* `ExpertEncoding', or `ISOLatin1Encoding' */
1688 else
1689 {
1690 if ( cur + 17 < limit &&
1691 ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 )
1692 {
1693 t1face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD;
1694 FT_TRACE4(( " StandardEncoding\n" ));
1695 }
1696
1697 else if ( cur + 15 < limit &&
1698 ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 )
1699 {
1700 t1face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT;
1701 FT_TRACE4(( " ExpertEncoding\n" ));
1702 }
1703
1704 else if ( cur + 18 < limit &&
1705 ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 )
1706 {
1707 t1face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1;
1708 FT_TRACE4(( " ISOLatin1Encoding\n" ));
1709 }
1710
1711 else
1712 {
1713 parser->root.error = FT_ERR( Ignore );
1714 FT_TRACE4(( "<unknown>\n" ));
1715 }
1716 }
1717 }
1718
1719
1720 static void
1721 parse_subrs( FT_Face face, /* T1_Face */
1722 void* loader_ )
1723 {
1724 T1_Face t1face = (T1_Face)face;
1725 T1_Loader loader = (T1_Loader)loader_;
1726 T1_Parser parser = &loader->parser;
1727 PS_Table table = &loader->subrs;
1728 FT_Memory memory = parser->root.memory;
1729 FT_Error error;
1730 FT_Int num_subrs;
1731 FT_UInt count;
1732
1733 PSAux_Service psaux = (PSAux_Service)t1face->psaux;
1734
1735
1736 T1_Skip_Spaces( parser );
1737
1738 /* test for empty array */
1739 if ( parser->root.cursor < parser->root.limit &&
1740 *parser->root.cursor == '[' )
1741 {
1742 T1_Skip_PS_Token( parser );
1743 T1_Skip_Spaces ( parser );
1744 if ( parser->root.cursor >= parser->root.limit ||
1745 *parser->root.cursor != ']' )
1746 parser->root.error = FT_THROW( Invalid_File_Format );
1747 return;
1748 }
1749
1750 num_subrs = (FT_Int)T1_ToInt( parser );
1751 if ( num_subrs < 0 )
1752 {
1753 parser->root.error = FT_THROW( Invalid_File_Format );
1754 return;
1755 }
1756
1757 /* we certainly need more than 8 bytes per subroutine */
1758 if ( parser->root.limit >= parser->root.cursor &&
1759 num_subrs > ( parser->root.limit - parser->root.cursor ) >> 3 )
1760 {
1761 /*
1762 * There are two possibilities. Either the font contains an invalid
1763 * value for `num_subrs', or we have a subsetted font where the
1764 * subroutine indices are not adjusted, e.g.
1765 *
1766 * /Subrs 812 array
1767 * dup 0 { ... } NP
1768 * dup 51 { ... } NP
1769 * dup 681 { ... } NP
1770 * ND
1771 *
1772 * In both cases, we use a number hash that maps from subr indices to
1773 * actual array elements.
1774 */
1775
1776 FT_TRACE0(( "parse_subrs: adjusting number of subroutines"
1777 " (from %d to %zu)\n",
1778 num_subrs,
1779 ( parser->root.limit - parser->root.cursor ) >> 3 ));
1780 num_subrs = ( parser->root.limit - parser->root.cursor ) >> 3;
1781
1782 if ( !loader->subrs_hash )
1783 {
1784 if ( FT_QNEW( loader->subrs_hash ) )
1785 goto Fail;
1786
1787 error = ft_hash_num_init( loader->subrs_hash, memory );
1788 if ( error )
1789 goto Fail;
1790 }
1791 }
1792
1793 /* position the parser right before the `dup' of the first subr */
1794 T1_Skip_PS_Token( parser ); /* `array' */
1795 if ( parser->root.error )
1796 return;
1797 T1_Skip_Spaces( parser );
1798
1799 /* initialize subrs array -- with synthetic fonts it is possible */
1800 /* we get here twice */
1801 if ( !loader->num_subrs )
1802 {
1803 error = psaux->ps_table_funcs->init( table, num_subrs, memory );
1804 if ( error )
1805 goto Fail;
1806 }
1807
1808 /* the format is simple: */
1809 /* */
1810 /* `index' + binary data */
1811 /* */
1812 for ( count = 0; ; count++ )
1813 {
1814 FT_Long idx;
1815 FT_ULong size;
1816 FT_Byte* base;
1817
1818
1819 /* If we are out of data, or if the next token isn't `dup', */
1820 /* we are done. */
1821 if ( parser->root.cursor + 4 >= parser->root.limit ||
1822 ft_strncmp( (char*)parser->root.cursor, "dup", 3 ) != 0 )
1823 break;
1824
1825 T1_Skip_PS_Token( parser ); /* `dup' */
1826
1827 idx = T1_ToInt( parser );
1828
1829 if ( !read_binary_data( parser, &size, &base, IS_INCREMENTAL ) )
1830 return;
1831
1832 /* The binary string is followed by one token, e.g. `NP' */
1833 /* (bound to `noaccess put') or by two separate tokens: */
1834 /* `noaccess' & `put'. We position the parser right */
1835 /* before the next `dup', if any. */
1836 T1_Skip_PS_Token( parser ); /* `NP' or `|' or `noaccess' */
1837 if ( parser->root.error )
1838 return;
1839 T1_Skip_Spaces ( parser );
1840
1841 if ( parser->root.cursor + 4 < parser->root.limit &&
1842 ft_strncmp( (char*)parser->root.cursor, "put", 3 ) == 0 )
1843 {
1844 T1_Skip_PS_Token( parser ); /* skip `put' */
1845 T1_Skip_Spaces ( parser );
1846 }
1847
1848 /* if we use a hash, the subrs index is the key, and a running */
1849 /* counter specified for `T1_Add_Table' acts as the value */
1850 if ( loader->subrs_hash )
1851 {
1852 ft_hash_num_insert( idx, count, loader->subrs_hash, memory );
1853 idx = count;
1854 }
1855
1856 /* with synthetic fonts it is possible we get here twice */
1857 if ( loader->num_subrs )
1858 continue;
1859
1860 /* some fonts use a value of -1 for lenIV to indicate that */
1861 /* the charstrings are unencoded */
1862 /* */
1863 /* thanks to Tom Kacvinsky for pointing this out */
1864 /* */
1865 if ( t1face->type1.private_dict.lenIV >= 0 )
1866 {
1867 FT_Byte* temp = NULL;
1868
1869
1870 /* some fonts define empty subr records -- this is not totally */
1871 /* compliant to the specification (which says they should at */
1872 /* least contain a `return'), but we support them anyway */
1873 if ( size < (FT_ULong)t1face->type1.private_dict.lenIV )
1874 {
1875 error = FT_THROW( Invalid_File_Format );
1876 goto Fail;
1877 }
1878
1879 /* t1_decrypt() shouldn't write to base -- make temporary copy */
1880 if ( FT_DUP( temp, base, size ) )
1881 goto Fail;
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_DUP( temp, base, size ) )
2094 goto Fail;
2095 psaux->t1_decrypt( temp, size, 4330 );
2096 size -= (FT_ULong)t1face->type1.private_dict.lenIV;
2097 error = T1_Add_Table( code_table,
2098 n,
2099 temp + t1face->type1.private_dict.lenIV,
2100 size );
2101 FT_FREE( temp );
2102 }
2103 else
2104 error = T1_Add_Table( code_table, n, base, size );
2105 if ( error )
2106 goto Fail;
2107
2108 n++;
2109 }
2110 }
2111
2112 if ( !n )
2113 {
2114 error = FT_THROW( Invalid_File_Format );
2115 goto Fail;
2116 }
2117
2118 loader->num_glyphs = n;
2119
2120 /* if /.notdef is found but does not occupy index 0, do our magic. */
2121 if ( notdef_found &&
2122 ft_strcmp( ".notdef", (const char*)name_table->elements[0] ) )
2123 {
2124 /* Swap glyph in index 0 with /.notdef glyph. First, add index 0 */
2125 /* name and code entries to swap_table. Then place notdef_index */
2126 /* name and code entries into swap_table. Then swap name and code */
2127 /* entries at indices notdef_index and 0 using values stored in */
2128 /* swap_table. */
2129
2130 /* Index 0 name */
2131 error = T1_Add_Table( swap_table, 0,
2132 name_table->elements[0],
2133 name_table->lengths [0] );
2134 if ( error )
2135 goto Fail;
2136
2137 /* Index 0 code */
2138 error = T1_Add_Table( swap_table, 1,
2139 code_table->elements[0],
2140 code_table->lengths [0] );
2141 if ( error )
2142 goto Fail;
2143
2144 /* Index notdef_index name */
2145 error = T1_Add_Table( swap_table, 2,
2146 name_table->elements[notdef_index],
2147 name_table->lengths [notdef_index] );
2148 if ( error )
2149 goto Fail;
2150
2151 /* Index notdef_index code */
2152 error = T1_Add_Table( swap_table, 3,
2153 code_table->elements[notdef_index],
2154 code_table->lengths [notdef_index] );
2155 if ( error )
2156 goto Fail;
2157
2158 error = T1_Add_Table( name_table, notdef_index,
2159 swap_table->elements[0],
2160 swap_table->lengths [0] );
2161 if ( error )
2162 goto Fail;
2163
2164 error = T1_Add_Table( code_table, notdef_index,
2165 swap_table->elements[1],
2166 swap_table->lengths [1] );
2167 if ( error )
2168 goto Fail;
2169
2170 error = T1_Add_Table( name_table, 0,
2171 swap_table->elements[2],
2172 swap_table->lengths [2] );
2173 if ( error )
2174 goto Fail;
2175
2176 error = T1_Add_Table( code_table, 0,
2177 swap_table->elements[3],
2178 swap_table->lengths [3] );
2179 if ( error )
2180 goto Fail;
2181
2182 }
2183 else if ( !notdef_found )
2184 {
2185 /* notdef_index is already 0, or /.notdef is undefined in */
2186 /* charstrings dictionary. Worry about /.notdef undefined. */
2187 /* We take index 0 and add it to the end of the table(s) */
2188 /* and add our own /.notdef glyph to index 0. */
2189
2190 /* 0 333 hsbw endchar */
2191 FT_Byte notdef_glyph[] = { 0x8B, 0xF7, 0xE1, 0x0D, 0x0E };
2192
2193
2194 error = T1_Add_Table( swap_table, 0,
2195 name_table->elements[0],
2196 name_table->lengths [0] );
2197 if ( error )
2198 goto Fail;
2199
2200 error = T1_Add_Table( swap_table, 1,
2201 code_table->elements[0],
2202 code_table->lengths [0] );
2203 if ( error )
2204 goto Fail;
2205
2206 error = T1_Add_Table( name_table, 0, ".notdef", 8 );
2207 if ( error )
2208 goto Fail;
2209
2210 error = T1_Add_Table( code_table, 0, notdef_glyph, 5 );
2211
2212 if ( error )
2213 goto Fail;
2214
2215 error = T1_Add_Table( name_table, n,
2216 swap_table->elements[0],
2217 swap_table->lengths [0] );
2218 if ( error )
2219 goto Fail;
2220
2221 error = T1_Add_Table( code_table, n,
2222 swap_table->elements[1],
2223 swap_table->lengths [1] );
2224 if ( error )
2225 goto Fail;
2226
2227 /* we added a glyph. */
2228 loader->num_glyphs += 1;
2229 }
2230
2231#ifdef FT_DEBUG_LEVEL_TRACE
2232 FT_TRACE4(( " <" ));
2233
2234 /* XXX show charstrings? */
2235 FT_TRACE4(( "%d elements", loader->num_glyphs ));
2236
2237 FT_TRACE4(( ">\n" ));
2238#endif
2239
2240 return;
2241
2242 Fail:
2243 parser->root.error = error;
2244 }
2245
2246
2247 /**************************************************************************
2248 *
2249 * Define the token field static variables. This is a set of
2250 * T1_FieldRec variables.
2251 *
2252 */
2253
2254
2255 static
2256 const T1_FieldRec t1_keywords[] =
2257 {
2258
2259#include "t1tokens.h"
2260
2261 /* now add the special functions... */
2262 T1_FIELD_CALLBACK( "FontMatrix", t1_parse_font_matrix,
2263 T1_FIELD_DICT_FONTDICT )
2264 T1_FIELD_CALLBACK( "Encoding", parse_encoding,
2265 T1_FIELD_DICT_FONTDICT )
2266 T1_FIELD_CALLBACK( "Subrs", parse_subrs,
2267 T1_FIELD_DICT_PRIVATE )
2268 T1_FIELD_CALLBACK( "CharStrings", parse_charstrings,
2269 T1_FIELD_DICT_PRIVATE )
2270 T1_FIELD_CALLBACK( "Private", parse_private,
2271 T1_FIELD_DICT_FONTDICT )
2272
2273#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
2274 T1_FIELD_CALLBACK( "BlendDesignPositions", parse_blend_design_positions,
2275 T1_FIELD_DICT_FONTDICT )
2276 T1_FIELD_CALLBACK( "BlendDesignMap", parse_blend_design_map,
2277 T1_FIELD_DICT_FONTDICT )
2278 T1_FIELD_CALLBACK( "BlendAxisTypes", parse_blend_axis_types,
2279 T1_FIELD_DICT_FONTDICT )
2280 T1_FIELD_CALLBACK( "WeightVector", parse_weight_vector,
2281 T1_FIELD_DICT_FONTDICT )
2282 T1_FIELD_CALLBACK( "BuildCharArray", parse_buildchar,
2283 T1_FIELD_DICT_PRIVATE )
2284#endif
2285
2286 T1_FIELD_ZERO
2287 };
2288
2289
2290 static FT_Error
2291 parse_dict( T1_Face face,
2292 T1_Loader loader,
2293 FT_Byte* base,
2294 FT_ULong size )
2295 {
2296 T1_Parser parser = &loader->parser;
2297 FT_Byte *limit, *start_binary = NULL;
2298 FT_Bool have_integer = 0;
2299
2300
2301 parser->root.cursor = base;
2302 parser->root.limit = base + size;
2303 parser->root.error = FT_Err_Ok;
2304
2305 limit = parser->root.limit;
2306
2307 T1_Skip_Spaces( parser );
2308
2309 while ( parser->root.cursor < limit )
2310 {
2311 FT_Byte* cur;
2312
2313
2314 cur = parser->root.cursor;
2315
2316 /* look for `eexec' */
2317 if ( IS_PS_TOKEN( cur, limit, "eexec" ) )
2318 break;
2319
2320 /* look for `closefile' which ends the eexec section */
2321 else if ( IS_PS_TOKEN( cur, limit, "closefile" ) )
2322 break;
2323
2324 /* in a synthetic font the base font starts after a */
2325 /* `FontDictionary' token that is placed after a Private dict */
2326 else if ( IS_PS_TOKEN( cur, limit, "FontDirectory" ) )
2327 {
2328 if ( loader->keywords_encountered & T1_PRIVATE )
2329 loader->keywords_encountered |=
2330 T1_FONTDIR_AFTER_PRIVATE;
2331 parser->root.cursor += 13;
2332 }
2333
2334 /* check whether we have an integer */
2335 else if ( ft_isdigit( *cur ) )
2336 {
2337 start_binary = cur;
2338 T1_Skip_PS_Token( parser );
2339 if ( parser->root.error )
2340 goto Exit;
2341 have_integer = 1;
2342 }
2343
2344 /* in valid Type 1 fonts we don't see `RD' or `-|' directly */
2345 /* since those tokens are handled by parse_subrs and */
2346 /* parse_charstrings */
2347 else if ( *cur == 'R' && cur + 6 < limit && *( cur + 1 ) == 'D' &&
2348 have_integer )
2349 {
2350 FT_ULong s;
2351 FT_Byte* b;
2352
2353
2354 parser->root.cursor = start_binary;
2355 if ( !read_binary_data( parser, &s, &b, IS_INCREMENTAL ) )
2356 return FT_THROW( Invalid_File_Format );
2357 have_integer = 0;
2358 }
2359
2360 else if ( *cur == '-' && cur + 6 < limit && *( cur + 1 ) == '|' &&
2361 have_integer )
2362 {
2363 FT_ULong s;
2364 FT_Byte* b;
2365
2366
2367 parser->root.cursor = start_binary;
2368 if ( !read_binary_data( parser, &s, &b, IS_INCREMENTAL ) )
2369 return FT_THROW( Invalid_File_Format );
2370 have_integer = 0;
2371 }
2372
2373 /* look for immediates */
2374 else if ( *cur == '/' && cur + 2 < limit )
2375 {
2376 FT_UInt len;
2377
2378
2379 cur++;
2380
2381 parser->root.cursor = cur;
2382 T1_Skip_PS_Token( parser );
2383 if ( parser->root.error )
2384 goto Exit;
2385
2386 len = (FT_UInt)( parser->root.cursor - cur );
2387
2388 if ( len > 0 && len < 22 && parser->root.cursor < limit )
2389 {
2390 /* now compare the immediate name to the keyword table */
2391 T1_Field keyword = (T1_Field)t1_keywords;
2392
2393
2394 while ( keyword->len )
2395 {
2396 FT_Byte* name = (FT_Byte*)keyword->ident;
2397
2398
2399 if ( keyword->len == len &&
2400 ft_memcmp( cur, name, len ) == 0 )
2401 {
2402 /* We found it -- run the parsing callback! */
2403 /* We record every instance of every field */
2404 /* (until we reach the base font of a */
2405 /* synthetic font) to deal adequately with */
2406 /* multiple master fonts; this is also */
2407 /* necessary because later PostScript */
2408 /* definitions override earlier ones. */
2409
2410 /* Once we encounter `FontDirectory' after */
2411 /* `/Private', we know that this is a synthetic */
2412 /* font; except for `/CharStrings' we are not */
2413 /* interested in anything that follows this */
2414 /* `FontDirectory'. */
2415
2416 /* MM fonts have more than one /Private token at */
2417 /* the top level; let's hope that all the junk */
2418 /* that follows the first /Private token is not */
2419 /* interesting to us. */
2420
2421 /* According to Adobe Tech Note #5175 (CID-Keyed */
2422 /* Font Installation for ATM Software) a `begin' */
2423 /* must be followed by exactly one `end', and */
2424 /* `begin' -- `end' pairs must be accurately */
2425 /* paired. We could use this to distinguish */
2426 /* between the global Private and the Private */
2427 /* dict that is a member of the Blend dict. */
2428
2429 const FT_UInt dict =
2430 ( loader->keywords_encountered & T1_PRIVATE )
2431 ? T1_FIELD_DICT_PRIVATE
2432 : T1_FIELD_DICT_FONTDICT;
2433
2434
2435 if ( !( dict & keyword->dict ) )
2436 {
2437 FT_TRACE1(( "parse_dict: found `%s' but ignoring it"
2438 " since it is in the wrong dictionary\n",
2439 keyword->ident ));
2440 break;
2441 }
2442
2443 if ( !( loader->keywords_encountered &
2444 T1_FONTDIR_AFTER_PRIVATE ) ||
2445 ft_strcmp( (const char*)name, "CharStrings" ) == 0 )
2446 {
2447 parser->root.error = t1_load_keyword( face,
2448 loader,
2449 keyword );
2450 if ( parser->root.error )
2451 {
2452 if ( FT_ERR_EQ( parser->root.error, Ignore ) )
2453 parser->root.error = FT_Err_Ok;
2454 else
2455 return parser->root.error;
2456 }
2457 }
2458 break;
2459 }
2460
2461 keyword++;
2462 }
2463 }
2464
2465 have_integer = 0;
2466 }
2467 else
2468 {
2469 T1_Skip_PS_Token( parser );
2470 if ( parser->root.error )
2471 goto Exit;
2472 have_integer = 0;
2473 }
2474
2475 T1_Skip_Spaces( parser );
2476 }
2477
2478 Exit:
2479 return parser->root.error;
2480 }
2481
2482
2483 static void
2484 t1_init_loader( T1_Loader loader,
2485 T1_Face face )
2486 {
2487 FT_UNUSED( face );
2488
2489 FT_ZERO( loader );
2490 }
2491
2492
2493 static void
2494 t1_done_loader( T1_Loader loader )
2495 {
2496 T1_Parser parser = &loader->parser;
2497 FT_Memory memory = parser->root.memory;
2498
2499
2500 /* finalize tables */
2501 T1_Release_Table( &loader->encoding_table );
2502 T1_Release_Table( &loader->charstrings );
2503 T1_Release_Table( &loader->glyph_names );
2504 T1_Release_Table( &loader->swap_table );
2505 T1_Release_Table( &loader->subrs );
2506
2507 /* finalize hash */
2508 ft_hash_num_free( loader->subrs_hash, memory );
2509 FT_FREE( loader->subrs_hash );
2510
2511 /* finalize parser */
2512 T1_Finalize_Parser( parser );
2513 }
2514
2515
2516 FT_LOCAL_DEF( FT_Error )
2517 T1_Open_Face( T1_Face face )
2518 {
2519 T1_LoaderRec loader;
2520 T1_Parser parser;
2521 T1_Font type1 = &face->type1;
2522 PS_Private priv = &type1->private_dict;
2523 FT_Error error;
2524
2525 PSAux_Service psaux = (PSAux_Service)face->psaux;
2526
2527
2528 t1_init_loader( &loader, face );
2529
2530 /* default values */
2531 face->ndv_idx = -1;
2532 face->cdv_idx = -1;
2533 face->len_buildchar = 0;
2534
2535 priv->blue_shift = 7;
2536 priv->blue_fuzz = 1;
2537 priv->lenIV = 4;
2538 priv->expansion_factor = (FT_Fixed)( 0.06 * 0x10000L );
2539 priv->blue_scale = (FT_Fixed)( 0.039625 * 0x10000L * 1000 );
2540
2541 parser = &loader.parser;
2542 error = T1_New_Parser( parser,
2543 face->root.stream,
2544 face->root.memory,
2545 psaux );
2546 if ( error )
2547 goto Exit;
2548
2549 FT_TRACE4(( " top dictionary:\n" ));
2550 error = parse_dict( face, &loader,
2551 parser->base_dict, parser->base_len );
2552 if ( error )
2553 goto Exit;
2554
2555 error = T1_Get_Private_Dict( parser, psaux );
2556 if ( error )
2557 goto Exit;
2558
2559 FT_TRACE4(( " private dictionary:\n" ));
2560 error = parse_dict( face, &loader,
2561 parser->private_dict, parser->private_len );
2562 if ( error )
2563 goto Exit;
2564
2565 /* ensure even-ness of `num_blue_values' */
2566 priv->num_blue_values &= ~1;
2567
2568#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
2569
2570 /* we don't support Multiple Master fonts with intermediate designs; */
2571 /* this implies that `num_designs' must be equal to `2^^num_axis' */
2572 if ( face->blend &&
2573 face->blend->num_designs != ( 1U << face->blend->num_axis ) )
2574 {
2575 FT_ERROR(( "T1_Open_Face:"
2576 " number-of-designs != 2 ^^ number-of-axes\n" ));
2577 T1_Done_Blend( FT_FACE( face ) );
2578 }
2579
2580 if ( face->blend &&
2581 face->blend->num_default_design_vector != 0 &&
2582 face->blend->num_default_design_vector != face->blend->num_axis )
2583 {
2584 /* we don't use it currently so just warn, reset, and ignore */
2585 FT_ERROR(( "T1_Open_Face(): /DesignVector contains %u entries "
2586 "while there are %u axes.\n",
2587 face->blend->num_default_design_vector,
2588 face->blend->num_axis ));
2589
2590 face->blend->num_default_design_vector = 0;
2591 }
2592
2593 /* the following can happen for MM instances; we then treat the */
2594 /* font as a normal PS font */
2595 if ( face->blend &&
2596 ( !face->blend->num_designs || !face->blend->num_axis ) )
2597 T1_Done_Blend( FT_FACE( face ) );
2598
2599 /* the font may have no valid WeightVector */
2600 if ( face->blend && !face->blend->weight_vector )
2601 T1_Done_Blend( FT_FACE( face ) );
2602
2603 /* the font may have no valid BlendDesignPositions */
2604 if ( face->blend && !face->blend->design_pos[0] )
2605 T1_Done_Blend( FT_FACE( face ) );
2606
2607 /* the font may have no valid BlendDesignMap */
2608 if ( face->blend )
2609 {
2610 FT_UInt i;
2611
2612
2613 for ( i = 0; i < face->blend->num_axis; i++ )
2614 if ( !face->blend->design_map[i].num_points )
2615 {
2616 T1_Done_Blend( FT_FACE( face ) );
2617 break;
2618 }
2619 }
2620
2621 if ( face->blend )
2622 {
2623 if ( face->len_buildchar > 0 )
2624 {
2625 FT_Memory memory = face->root.memory;
2626
2627
2628 if ( FT_NEW_ARRAY( face->buildchar, face->len_buildchar ) )
2629 {
2630 FT_ERROR(( "T1_Open_Face: cannot allocate BuildCharArray\n" ));
2631 face->len_buildchar = 0;
2632 goto Exit;
2633 }
2634 }
2635 }
2636 else
2637 face->len_buildchar = 0;
2638
2639#endif /* !T1_CONFIG_OPTION_NO_MM_SUPPORT */
2640
2641 /* now, propagate the subrs, charstrings, and glyphnames tables */
2642 /* to the Type1 data */
2643 type1->num_glyphs = loader.num_glyphs;
2644
2645 if ( loader.subrs.init )
2646 {
2647 type1->num_subrs = loader.num_subrs;
2648 type1->subrs_block = loader.subrs.block;
2649 type1->subrs = loader.subrs.elements;
2650 type1->subrs_len = loader.subrs.lengths;
2651 type1->subrs_hash = loader.subrs_hash;
2652
2653 /* prevent `t1_done_loader' from freeing the propagated data */
2654 loader.subrs.init = 0;
2655 loader.subrs_hash = NULL;
2656 }
2657
2658 if ( !IS_INCREMENTAL )
2659 if ( !loader.charstrings.init )
2660 {
2661 FT_ERROR(( "T1_Open_Face: no `/CharStrings' array in face\n" ));
2662 error = FT_THROW( Invalid_File_Format );
2663 }
2664
2665 loader.charstrings.init = 0;
2666 type1->charstrings_block = loader.charstrings.block;
2667 type1->charstrings = loader.charstrings.elements;
2668 type1->charstrings_len = loader.charstrings.lengths;
2669
2670 /* we copy the glyph names `block' and `elements' fields; */
2671 /* the `lengths' field must be released later */
2672 type1->glyph_names_block = loader.glyph_names.block;
2673 type1->glyph_names = (FT_String**)loader.glyph_names.elements;
2674 loader.glyph_names.block = NULL;
2675 loader.glyph_names.elements = NULL;
2676
2677 /* we must now build type1.encoding when we have a custom array */
2678 if ( type1->encoding_type == T1_ENCODING_TYPE_ARRAY )
2679 {
2680 FT_Int charcode, idx, min_char, max_char;
2681
2682
2683 /* OK, we do the following: for each element in the encoding */
2684 /* table, look up the index of the glyph having the same name */
2685 /* the index is then stored in type1.encoding.char_index, and */
2686 /* the name to type1.encoding.char_name */
2687
2688 min_char = 0;
2689 max_char = 0;
2690
2691 charcode = 0;
2692 for ( ; charcode < loader.encoding_table.max_elems; charcode++ )
2693 {
2694 const FT_String* char_name =
2695 (const FT_String*)loader.encoding_table.elements[charcode];
2696
2697
2698 type1->encoding.char_index[charcode] = 0;
2699 type1->encoding.char_name [charcode] = ".notdef";
2700
2701 if ( char_name )
2702 for ( idx = 0; idx < type1->num_glyphs; idx++ )
2703 {
2704 const FT_String* glyph_name = type1->glyph_names[idx];
2705
2706
2707 if ( ft_strcmp( char_name, glyph_name ) == 0 )
2708 {
2709 type1->encoding.char_index[charcode] = (FT_UShort)idx;
2710 type1->encoding.char_name [charcode] = glyph_name;
2711
2712 /* Change min/max encoded char only if glyph name is */
2713 /* not /.notdef */
2714 if ( ft_strcmp( ".notdef", glyph_name ) != 0 )
2715 {
2716 if ( charcode < min_char )
2717 min_char = charcode;
2718 if ( charcode >= max_char )
2719 max_char = charcode + 1;
2720 }
2721 break;
2722 }
2723 }
2724 }
2725
2726 type1->encoding.code_first = min_char;
2727 type1->encoding.code_last = max_char;
2728 type1->encoding.num_chars = loader.num_chars;
2729 }
2730
2731 /* some sanitizing to avoid overflows later on; */
2732 /* the upper limits are ad-hoc values */
2733 if ( priv->blue_shift > 1000 || priv->blue_shift < 0 )
2734 {
2735 FT_TRACE2(( "T1_Open_Face:"
2736 " setting unlikely BlueShift value %d to default (7)\n",
2737 priv->blue_shift ));
2738 priv->blue_shift = 7;
2739 }
2740
2741 if ( priv->blue_fuzz > 1000 || priv->blue_fuzz < 0 )
2742 {
2743 FT_TRACE2(( "T1_Open_Face:"
2744 " setting unlikely BlueFuzz value %d to default (1)\n",
2745 priv->blue_fuzz ));
2746 priv->blue_fuzz = 1;
2747 }
2748
2749 Exit:
2750 t1_done_loader( &loader );
2751 return error;
2752 }
2753
2754
2755/* END */