1 /***************************************************************************/
5 /* CID-keyed Type1 font loader (body). */
7 /* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006 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_BBOX
:
101 object
= (FT_Byte
*)&cid
->font_bbox
;
109 if ( parser
->num_dict
< 0 )
111 FT_ERROR(( "cid_load_keyword: invalid use of `%s'!\n",
113 error
= CID_Err_Syntax_Error
;
117 dict
= cid
->font_dicts
+ parser
->num_dict
;
118 switch ( keyword
->location
)
120 case T1_FIELD_LOCATION_PRIVATE
:
121 object
= (FT_Byte
*)&dict
->private_dict
;
125 object
= (FT_Byte
*)dict
;
130 dummy_object
= object
;
132 /* now, load the keyword data in the object's field(s) */
133 if ( keyword
->type
== T1_FIELD_TYPE_INTEGER_ARRAY
||
134 keyword
->type
== T1_FIELD_TYPE_FIXED_ARRAY
)
135 error
= cid_parser_load_field_table( &loader
->parser
, keyword
,
138 error
= cid_parser_load_field( &loader
->parser
,
139 keyword
, &dummy_object
);
145 FT_CALLBACK_DEF( FT_Error
)
146 parse_font_matrix( CID_Face face
,
152 FT_Face root
= (FT_Face
)&face
->root
;
157 if ( parser
->num_dict
>= 0 )
159 dict
= face
->cid
.font_dicts
+ parser
->num_dict
;
160 matrix
= &dict
->font_matrix
;
161 offset
= &dict
->font_offset
;
163 (void)cid_parser_to_fixed_array( parser
, 6, temp
, 3 );
165 temp_scale
= FT_ABS( temp
[3] );
167 /* Set units per EM based on FontMatrix values. We set the value to */
168 /* `1000/temp_scale', because temp_scale was already multiplied by */
169 /* 1000 (in `t1_tofixed', from psobjs.c). */
170 root
->units_per_EM
= (FT_UShort
)( FT_DivFix( 0x10000L
,
171 FT_DivFix( temp_scale
, 1000 ) ) );
173 /* we need to scale the values by 1.0/temp[3] */
174 if ( temp_scale
!= 0x10000L
)
176 temp
[0] = FT_DivFix( temp
[0], temp_scale
);
177 temp
[1] = FT_DivFix( temp
[1], temp_scale
);
178 temp
[2] = FT_DivFix( temp
[2], temp_scale
);
179 temp
[4] = FT_DivFix( temp
[4], temp_scale
);
180 temp
[5] = FT_DivFix( temp
[5], temp_scale
);
184 matrix
->xx
= temp
[0];
185 matrix
->yx
= temp
[1];
186 matrix
->xy
= temp
[2];
187 matrix
->yy
= temp
[3];
189 /* note that the font offsets are expressed in integer font units */
190 offset
->x
= temp
[4] >> 16;
191 offset
->y
= temp
[5] >> 16;
194 return CID_Err_Ok
; /* this is a callback function; */
195 /* we must return an error code */
199 FT_CALLBACK_DEF( FT_Error
)
200 parse_fd_array( CID_Face face
,
203 CID_FaceInfo cid
= &face
->cid
;
204 FT_Memory memory
= face
->root
.memory
;
205 FT_Error error
= CID_Err_Ok
;
209 num_dicts
= cid_parser_to_int( parser
);
211 if ( !cid
->font_dicts
)
216 if ( FT_NEW_ARRAY( cid
->font_dicts
, num_dicts
) )
219 cid
->num_dicts
= (FT_UInt
)num_dicts
;
221 /* don't forget to set a few defaults */
222 for ( n
= 0; n
< cid
->num_dicts
; n
++ )
224 CID_FaceDict dict
= cid
->font_dicts
+ n
;
227 /* default value for lenIV */
228 dict
->private_dict
.lenIV
= 4;
238 const T1_FieldRec cid_field_records
[] =
241 #include "cidtoken.h"
243 T1_FIELD_CALLBACK( "FDArray", parse_fd_array
, 0 )
244 T1_FIELD_CALLBACK( "FontMatrix", parse_font_matrix
, 0 )
246 { 0, T1_FIELD_LOCATION_CID_INFO
, T1_FIELD_TYPE_NONE
, 0, 0, 0, 0, 0, 0 }
251 cid_parse_dict( CID_Face face
,
256 CID_Parser
* parser
= &loader
->parser
;
259 parser
->root
.cursor
= base
;
260 parser
->root
.limit
= base
+ size
;
261 parser
->root
.error
= CID_Err_Ok
;
265 FT_Byte
* limit
= cur
+ size
;
273 parser
->root
.cursor
= cur
;
274 cid_parser_skip_spaces( parser
);
276 if ( parser
->root
.cursor
>= limit
)
277 newlimit
= limit
- 1 - 17;
279 newlimit
= parser
->root
.cursor
- 17;
281 /* look for `%ADOBeginFontDict' */
282 for ( ; cur
< newlimit
; cur
++ )
285 ft_strncmp( (char*)cur
, "%ADOBeginFontDict", 17 ) == 0 )
287 /* if /FDArray was found, then cid->num_dicts is > 0, and */
288 /* we can start increasing parser->num_dict */
289 if ( face
->cid
.num_dicts
> 0 )
294 cur
= parser
->root
.cursor
;
295 /* no error can occur in cid_parser_skip_spaces */
299 cid_parser_skip_PS_token( parser
);
300 if ( parser
->root
.cursor
>= limit
|| parser
->root
.error
)
303 /* look for immediates */
304 if ( *cur
== '/' && cur
+ 2 < limit
)
310 len
= parser
->root
.cursor
- cur
;
312 if ( len
> 0 && len
< 22 )
314 /* now compare the immediate name to the keyword table */
315 T1_Field keyword
= (T1_Field
)cid_field_records
;
323 name
= (FT_Byte
*)keyword
->ident
;
327 if ( cur
[0] == name
[0] &&
328 len
== (FT_PtrDist
)ft_strlen( (const char*)name
) )
333 for ( n
= 1; n
< len
; n
++ )
334 if ( cur
[n
] != name
[n
] )
339 /* we found it - run the parsing callback */
340 parser
->root
.error
= cid_load_keyword( face
,
343 if ( parser
->root
.error
)
344 return parser
->root
.error
;
353 cur
= parser
->root
.cursor
;
356 return parser
->root
.error
;
360 /* read the subrmap and the subrs of each font dict */
362 cid_read_subrs( CID_Face face
)
364 CID_FaceInfo cid
= &face
->cid
;
365 FT_Memory memory
= face
->root
.memory
;
366 FT_Stream stream
= face
->cid_stream
;
370 FT_UInt max_offsets
= 0;
371 FT_ULong
* offsets
= 0;
372 PSAux_Service psaux
= (PSAux_Service
)face
->psaux
;
375 if ( FT_NEW_ARRAY( face
->subrs
, cid
->num_dicts
) )
379 for ( n
= 0; n
< cid
->num_dicts
; n
++, subr
++ )
381 CID_FaceDict dict
= cid
->font_dicts
+ n
;
382 FT_Int lenIV
= dict
->private_dict
.lenIV
;
383 FT_UInt count
, num_subrs
= dict
->num_subrs
;
388 /* reallocate offsets array if needed */
389 if ( num_subrs
+ 1 > max_offsets
)
391 FT_UInt new_max
= FT_PAD_CEIL( num_subrs
+ 1, 4 );
394 if ( FT_RENEW_ARRAY( offsets
, max_offsets
, new_max
) )
397 max_offsets
= new_max
;
400 /* read the subrmap's offsets */
401 if ( FT_STREAM_SEEK( cid
->data_offset
+ dict
->subrmap_offset
) ||
402 FT_FRAME_ENTER( ( num_subrs
+ 1 ) * dict
->sd_bytes
) )
405 p
= (FT_Byte
*)stream
->cursor
;
406 for ( count
= 0; count
<= num_subrs
; count
++ )
407 offsets
[count
] = cid_get_offset( &p
, (FT_Byte
)dict
->sd_bytes
);
411 /* now, compute the size of subrs charstrings, */
412 /* allocate, and read them */
413 data_len
= offsets
[num_subrs
] - offsets
[0];
415 if ( FT_NEW_ARRAY( subr
->code
, num_subrs
+ 1 ) ||
416 FT_ALLOC( subr
->code
[0], data_len
) )
419 if ( FT_STREAM_SEEK( cid
->data_offset
+ offsets
[0] ) ||
420 FT_STREAM_READ( subr
->code
[0], data_len
) )
423 /* set up pointers */
424 for ( count
= 1; count
<= num_subrs
; count
++ )
429 len
= offsets
[count
] - offsets
[count
- 1];
430 subr
->code
[count
] = subr
->code
[count
- 1] + len
;
433 /* decrypt subroutines, but only if lenIV >= 0 */
436 for ( count
= 0; count
< num_subrs
; count
++ )
441 len
= offsets
[count
+ 1] - offsets
[count
];
442 psaux
->t1_decrypt( subr
->code
[count
], len
, 4330 );
446 subr
->num_subrs
= num_subrs
;
456 for ( n
= 0; n
< cid
->num_dicts
; n
++ )
458 if ( face
->subrs
[n
].code
)
459 FT_FREE( face
->subrs
[n
].code
[0] );
461 FT_FREE( face
->subrs
[n
].code
);
463 FT_FREE( face
->subrs
);
470 t1_init_loader( CID_Loader
* loader
,
475 FT_MEM_ZERO( loader
, sizeof ( *loader
) );
480 t1_done_loader( CID_Loader
* loader
)
482 CID_Parser
* parser
= &loader
->parser
;
485 /* finalize parser */
486 cid_parser_done( parser
);
491 cid_hex_to_binary( FT_Byte
* data
,
496 FT_Stream stream
= face
->root
.stream
;
504 FT_Bool upper_nibble
, done
;
507 if ( FT_STREAM_SEEK( offset
) )
511 dlimit
= d
+ data_len
;
522 FT_ULong oldpos
= FT_STREAM_POS();
523 FT_ULong size
= stream
->size
- oldpos
;
528 error
= CID_Err_Syntax_Error
;
532 if ( FT_STREAM_READ( buffer
, 256 > size
? size
: 256 ) )
535 plimit
= p
+ FT_STREAM_POS() - oldpos
;
538 if ( ft_isdigit( *p
) )
539 val
= (FT_Byte
)( *p
- '0' );
540 else if ( *p
>= 'a' && *p
<= 'f' )
541 val
= (FT_Byte
)( *p
- 'a' );
542 else if ( *p
>= 'A' && *p
<= 'F' )
543 val
= (FT_Byte
)( *p
- 'A' + 10 );
544 else if ( *p
== ' ' ||
554 else if ( *p
== '>' )
561 error
= CID_Err_Syntax_Error
;
566 *d
= (FT_Byte
)( val
<< 4 );
569 *d
= (FT_Byte
)( *d
+ val
);
573 upper_nibble
= (FT_Byte
)( 1 - upper_nibble
);
588 FT_LOCAL_DEF( FT_Error
)
589 cid_face_open( CID_Face face
,
594 FT_Memory memory
= face
->root
.memory
;
598 t1_init_loader( &loader
, face
);
600 parser
= &loader
.parser
;
601 error
= cid_parser_new( parser
, face
->root
.stream
, face
->root
.memory
,
602 (PSAux_Service
)face
->psaux
);
606 error
= cid_parse_dict( face
, &loader
,
608 parser
->postscript_len
);
612 if ( face_index
< 0 )
615 if ( FT_NEW( face
->cid_stream
) )
618 if ( parser
->binary_length
)
620 /* we must convert the data section from hexadecimal to binary */
621 if ( FT_ALLOC( face
->binary_data
, parser
->binary_length
) ||
622 cid_hex_to_binary( face
->binary_data
, parser
->binary_length
,
623 parser
->data_offset
, face
) )
626 FT_Stream_OpenMemory( face
->cid_stream
,
627 face
->binary_data
, parser
->binary_length
);
628 face
->cid
.data_offset
= 0;
632 *face
->cid_stream
= *face
->root
.stream
;
633 face
->cid
.data_offset
= loader
.parser
.data_offset
;
636 error
= cid_read_subrs( face
);
639 t1_done_loader( &loader
);