1 /***************************************************************************/
5 /* CID-keyed Type1 font loader (body). */
7 /* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2009 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
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. */
16 /***************************************************************************/
20 #include FT_INTERNAL_DEBUG_H
21 #include FT_CONFIG_CONFIG_H
22 #include FT_MULTIPLE_MASTERS_H
23 #include FT_INTERNAL_TYPE1_TYPES_H
30 /*************************************************************************/
32 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
33 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
34 /* messages during execution. */
37 #define FT_COMPONENT trace_cidload
40 /* read a single offset */
41 FT_LOCAL_DEF( FT_Long
)
42 cid_get_offset( FT_Byte
* *start
,
49 for ( result
= 0; offsize
> 0; offsize
-- )
60 /*************************************************************************/
61 /*************************************************************************/
63 /***** TYPE 1 SYMBOL PARSING *****/
65 /*************************************************************************/
66 /*************************************************************************/
70 cid_load_keyword( CID_Face face
,
72 const T1_Field keyword
)
75 CID_Parser
* parser
= &loader
->parser
;
78 CID_FaceInfo cid
= &face
->cid
;
81 /* if the keyword has a dedicated callback, call it */
82 if ( keyword
->type
== T1_FIELD_TYPE_CALLBACK
)
84 keyword
->reader( (FT_Face
)face
, parser
);
85 error
= parser
->root
.error
;
89 /* we must now compute the address of our target object */
90 switch ( keyword
->location
)
92 case T1_FIELD_LOCATION_CID_INFO
:
93 object
= (FT_Byte
*)cid
;
96 case T1_FIELD_LOCATION_FONT_INFO
:
97 object
= (FT_Byte
*)&cid
->font_info
;
100 case T1_FIELD_LOCATION_FONT_EXTRA
:
101 object
= (FT_Byte
*)&face
->font_extra
;
104 case T1_FIELD_LOCATION_BBOX
:
105 object
= (FT_Byte
*)&cid
->font_bbox
;
113 if ( parser
->num_dict
< 0 )
115 FT_ERROR(( "cid_load_keyword: invalid use of `%s'\n",
117 error
= CID_Err_Syntax_Error
;
121 dict
= cid
->font_dicts
+ parser
->num_dict
;
122 switch ( keyword
->location
)
124 case T1_FIELD_LOCATION_PRIVATE
:
125 object
= (FT_Byte
*)&dict
->private_dict
;
129 object
= (FT_Byte
*)dict
;
134 dummy_object
= object
;
136 /* now, load the keyword data in the object's field(s) */
137 if ( keyword
->type
== T1_FIELD_TYPE_INTEGER_ARRAY
||
138 keyword
->type
== T1_FIELD_TYPE_FIXED_ARRAY
)
139 error
= cid_parser_load_field_table( &loader
->parser
, keyword
,
142 error
= cid_parser_load_field( &loader
->parser
,
143 keyword
, &dummy_object
);
149 FT_CALLBACK_DEF( FT_Error
)
150 parse_font_matrix( CID_Face face
,
156 FT_Face root
= (FT_Face
)&face
->root
;
161 if ( parser
->num_dict
>= 0 )
163 dict
= face
->cid
.font_dicts
+ parser
->num_dict
;
164 matrix
= &dict
->font_matrix
;
165 offset
= &dict
->font_offset
;
167 (void)cid_parser_to_fixed_array( parser
, 6, temp
, 3 );
169 temp_scale
= FT_ABS( temp
[3] );
171 /* Set units per EM based on FontMatrix values. We set the value to */
172 /* `1000/temp_scale', because temp_scale was already multiplied by */
173 /* 1000 (in `t1_tofixed', from psobjs.c). */
174 root
->units_per_EM
= (FT_UShort
)( FT_DivFix( 0x10000L
,
175 FT_DivFix( temp_scale
, 1000 ) ) );
177 /* we need to scale the values by 1.0/temp[3] */
178 if ( temp_scale
!= 0x10000L
)
180 temp
[0] = FT_DivFix( temp
[0], temp_scale
);
181 temp
[1] = FT_DivFix( temp
[1], temp_scale
);
182 temp
[2] = FT_DivFix( temp
[2], temp_scale
);
183 temp
[4] = FT_DivFix( temp
[4], temp_scale
);
184 temp
[5] = FT_DivFix( temp
[5], temp_scale
);
188 matrix
->xx
= temp
[0];
189 matrix
->yx
= temp
[1];
190 matrix
->xy
= temp
[2];
191 matrix
->yy
= temp
[3];
193 /* note that the font offsets are expressed in integer font units */
194 offset
->x
= temp
[4] >> 16;
195 offset
->y
= temp
[5] >> 16;
198 return CID_Err_Ok
; /* this is a callback function; */
199 /* we must return an error code */
203 FT_CALLBACK_DEF( FT_Error
)
204 parse_fd_array( CID_Face face
,
207 CID_FaceInfo cid
= &face
->cid
;
208 FT_Memory memory
= face
->root
.memory
;
209 FT_Error error
= CID_Err_Ok
;
213 num_dicts
= cid_parser_to_int( parser
);
215 if ( !cid
->font_dicts
)
220 if ( FT_NEW_ARRAY( cid
->font_dicts
, num_dicts
) )
223 cid
->num_dicts
= (FT_UInt
)num_dicts
;
225 /* don't forget to set a few defaults */
226 for ( n
= 0; n
< cid
->num_dicts
; n
++ )
228 CID_FaceDict dict
= cid
->font_dicts
+ n
;
231 /* default value for lenIV */
232 dict
->private_dict
.lenIV
= 4;
241 /* by mistake, `expansion_factor' appears both in PS_PrivateRec */
242 /* and CID_FaceDictRec (both are public header files and can't */
243 /* changed); we simply copy the value */
245 FT_CALLBACK_DEF( FT_Error
)
246 parse_expansion_factor( CID_Face face
,
252 if ( parser
->num_dict
>= 0 )
254 dict
= face
->cid
.font_dicts
+ parser
->num_dict
;
256 dict
->expansion_factor
= cid_parser_to_fixed( parser
, 0 );
257 dict
->private_dict
.expansion_factor
= dict
->expansion_factor
;
265 const T1_FieldRec cid_field_records
[] =
268 #include "cidtoken.h"
270 T1_FIELD_CALLBACK( "FDArray", parse_fd_array
, 0 )
271 T1_FIELD_CALLBACK( "FontMatrix", parse_font_matrix
, 0 )
272 T1_FIELD_CALLBACK( "ExpansionFactor", parse_expansion_factor
, 0 )
274 { 0, T1_FIELD_LOCATION_CID_INFO
, T1_FIELD_TYPE_NONE
, 0, 0, 0, 0, 0, 0 }
279 cid_parse_dict( CID_Face face
,
284 CID_Parser
* parser
= &loader
->parser
;
287 parser
->root
.cursor
= base
;
288 parser
->root
.limit
= base
+ size
;
289 parser
->root
.error
= CID_Err_Ok
;
293 FT_Byte
* limit
= cur
+ size
;
301 parser
->root
.cursor
= cur
;
302 cid_parser_skip_spaces( parser
);
304 if ( parser
->root
.cursor
>= limit
)
305 newlimit
= limit
- 1 - 17;
307 newlimit
= parser
->root
.cursor
- 17;
309 /* look for `%ADOBeginFontDict' */
310 for ( ; cur
< newlimit
; cur
++ )
313 ft_strncmp( (char*)cur
, "%ADOBeginFontDict", 17 ) == 0 )
315 /* if /FDArray was found, then cid->num_dicts is > 0, and */
316 /* we can start increasing parser->num_dict */
317 if ( face
->cid
.num_dicts
> 0 )
322 cur
= parser
->root
.cursor
;
323 /* no error can occur in cid_parser_skip_spaces */
327 cid_parser_skip_PS_token( parser
);
328 if ( parser
->root
.cursor
>= limit
|| parser
->root
.error
)
331 /* look for immediates */
332 if ( *cur
== '/' && cur
+ 2 < limit
)
338 len
= parser
->root
.cursor
- cur
;
340 if ( len
> 0 && len
< 22 )
342 /* now compare the immediate name to the keyword table */
343 T1_Field keyword
= (T1_Field
)cid_field_records
;
351 name
= (FT_Byte
*)keyword
->ident
;
355 if ( cur
[0] == name
[0] &&
356 len
== (FT_PtrDist
)ft_strlen( (const char*)name
) )
361 for ( n
= 1; n
< len
; n
++ )
362 if ( cur
[n
] != name
[n
] )
367 /* we found it - run the parsing callback */
368 parser
->root
.error
= cid_load_keyword( face
,
371 if ( parser
->root
.error
)
372 return parser
->root
.error
;
381 cur
= parser
->root
.cursor
;
384 return parser
->root
.error
;
388 /* read the subrmap and the subrs of each font dict */
390 cid_read_subrs( CID_Face face
)
392 CID_FaceInfo cid
= &face
->cid
;
393 FT_Memory memory
= face
->root
.memory
;
394 FT_Stream stream
= face
->cid_stream
;
398 FT_UInt max_offsets
= 0;
399 FT_ULong
* offsets
= 0;
400 PSAux_Service psaux
= (PSAux_Service
)face
->psaux
;
403 if ( FT_NEW_ARRAY( face
->subrs
, cid
->num_dicts
) )
407 for ( n
= 0; n
< cid
->num_dicts
; n
++, subr
++ )
409 CID_FaceDict dict
= cid
->font_dicts
+ n
;
410 FT_Int lenIV
= dict
->private_dict
.lenIV
;
411 FT_UInt count
, num_subrs
= dict
->num_subrs
;
416 /* reallocate offsets array if needed */
417 if ( num_subrs
+ 1 > max_offsets
)
419 FT_UInt new_max
= FT_PAD_CEIL( num_subrs
+ 1, 4 );
422 if ( FT_RENEW_ARRAY( offsets
, max_offsets
, new_max
) )
425 max_offsets
= new_max
;
428 /* read the subrmap's offsets */
429 if ( FT_STREAM_SEEK( cid
->data_offset
+ dict
->subrmap_offset
) ||
430 FT_FRAME_ENTER( ( num_subrs
+ 1 ) * dict
->sd_bytes
) )
433 p
= (FT_Byte
*)stream
->cursor
;
434 for ( count
= 0; count
<= num_subrs
; count
++ )
435 offsets
[count
] = cid_get_offset( &p
, (FT_Byte
)dict
->sd_bytes
);
439 /* now, compute the size of subrs charstrings, */
440 /* allocate, and read them */
441 data_len
= offsets
[num_subrs
] - offsets
[0];
443 if ( FT_NEW_ARRAY( subr
->code
, num_subrs
+ 1 ) ||
444 FT_ALLOC( subr
->code
[0], data_len
) )
447 if ( FT_STREAM_SEEK( cid
->data_offset
+ offsets
[0] ) ||
448 FT_STREAM_READ( subr
->code
[0], data_len
) )
451 /* set up pointers */
452 for ( count
= 1; count
<= num_subrs
; count
++ )
457 len
= offsets
[count
] - offsets
[count
- 1];
458 subr
->code
[count
] = subr
->code
[count
- 1] + len
;
461 /* decrypt subroutines, but only if lenIV >= 0 */
464 for ( count
= 0; count
< num_subrs
; count
++ )
469 len
= offsets
[count
+ 1] - offsets
[count
];
470 psaux
->t1_decrypt( subr
->code
[count
], len
, 4330 );
474 subr
->num_subrs
= num_subrs
;
484 for ( n
= 0; n
< cid
->num_dicts
; n
++ )
486 if ( face
->subrs
[n
].code
)
487 FT_FREE( face
->subrs
[n
].code
[0] );
489 FT_FREE( face
->subrs
[n
].code
);
491 FT_FREE( face
->subrs
);
498 t1_init_loader( CID_Loader
* loader
,
503 FT_MEM_ZERO( loader
, sizeof ( *loader
) );
508 t1_done_loader( CID_Loader
* loader
)
510 CID_Parser
* parser
= &loader
->parser
;
513 /* finalize parser */
514 cid_parser_done( parser
);
519 cid_hex_to_binary( FT_Byte
* data
,
524 FT_Stream stream
= face
->root
.stream
;
532 FT_Bool upper_nibble
, done
;
535 if ( FT_STREAM_SEEK( offset
) )
539 dlimit
= d
+ data_len
;
550 FT_ULong oldpos
= FT_STREAM_POS();
551 FT_ULong size
= stream
->size
- oldpos
;
556 error
= CID_Err_Syntax_Error
;
560 if ( FT_STREAM_READ( buffer
, 256 > size
? size
: 256 ) )
563 plimit
= p
+ FT_STREAM_POS() - oldpos
;
566 if ( ft_isdigit( *p
) )
567 val
= (FT_Byte
)( *p
- '0' );
568 else if ( *p
>= 'a' && *p
<= 'f' )
569 val
= (FT_Byte
)( *p
- 'a' );
570 else if ( *p
>= 'A' && *p
<= 'F' )
571 val
= (FT_Byte
)( *p
- 'A' + 10 );
572 else if ( *p
== ' ' ||
582 else if ( *p
== '>' )
589 error
= CID_Err_Syntax_Error
;
594 *d
= (FT_Byte
)( val
<< 4 );
597 *d
= (FT_Byte
)( *d
+ val
);
601 upper_nibble
= (FT_Byte
)( 1 - upper_nibble
);
616 FT_LOCAL_DEF( FT_Error
)
617 cid_face_open( CID_Face face
,
622 FT_Memory memory
= face
->root
.memory
;
626 t1_init_loader( &loader
, face
);
628 parser
= &loader
.parser
;
629 error
= cid_parser_new( parser
, face
->root
.stream
, face
->root
.memory
,
630 (PSAux_Service
)face
->psaux
);
634 error
= cid_parse_dict( face
, &loader
,
636 parser
->postscript_len
);
640 if ( face_index
< 0 )
643 if ( FT_NEW( face
->cid_stream
) )
646 if ( parser
->binary_length
)
648 /* we must convert the data section from hexadecimal to binary */
649 if ( FT_ALLOC( face
->binary_data
, parser
->binary_length
) ||
650 cid_hex_to_binary( face
->binary_data
, parser
->binary_length
,
651 parser
->data_offset
, face
) )
654 FT_Stream_OpenMemory( face
->cid_stream
,
655 face
->binary_data
, parser
->binary_length
);
656 face
->cid
.data_offset
= 0;
660 *face
->cid_stream
= *face
->root
.stream
;
661 face
->cid
.data_offset
= loader
.parser
.data_offset
;
664 error
= cid_read_subrs( face
);
667 t1_done_loader( &loader
);