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