1 /***************************************************************************/
5 /* Auxiliary functions for PostScript fonts (body). */
7 /* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007 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_POSTSCRIPT_AUX_H
21 #include FT_INTERNAL_DEBUG_H
29 /*************************************************************************/
31 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
32 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
33 /* messages during execution. */
36 #define FT_COMPONENT trace_psobjs
39 /*************************************************************************/
40 /*************************************************************************/
42 /***** PS_TABLE *****/
44 /*************************************************************************/
45 /*************************************************************************/
47 /*************************************************************************/
53 /* Initializes a PS_Table. */
56 /* table :: The address of the target table. */
59 /* count :: The table size = the maximum number of elements. */
61 /* memory :: The memory object to use for all subsequent */
65 /* FreeType error code. 0 means success. */
67 FT_LOCAL_DEF( FT_Error
)
68 ps_table_new( PS_Table table
,
75 table
->memory
= memory
;
76 if ( FT_NEW_ARRAY( table
->elements
, count
) ||
77 FT_NEW_ARRAY( table
->lengths
, count
) )
80 table
->max_elems
= count
;
81 table
->init
= 0xDEADBEEFUL
;
87 *(PS_Table_FuncsRec
*)&table
->funcs
= ps_table_funcs
;
91 FT_FREE( table
->elements
);
98 shift_elements( PS_Table table
,
101 FT_PtrDist delta
= table
->block
- old_base
;
102 FT_Byte
** offset
= table
->elements
;
103 FT_Byte
** limit
= offset
+ table
->max_elems
;
106 for ( ; offset
< limit
; offset
++ )
115 reallocate_t1_table( PS_Table table
,
118 FT_Memory memory
= table
->memory
;
119 FT_Byte
* old_base
= table
->block
;
123 /* allocate new base block */
124 if ( FT_ALLOC( table
->block
, new_size
) )
126 table
->block
= old_base
;
130 /* copy elements and shift offsets */
133 FT_MEM_COPY( table
->block
, old_base
, table
->capacity
);
134 shift_elements( table
, old_base
);
138 table
->capacity
= new_size
;
144 /*************************************************************************/
150 /* Adds an object to a PS_Table, possibly growing its memory block. */
153 /* table :: The target table. */
156 /* idx :: The index of the object in the table. */
158 /* object :: The address of the object to copy in memory. */
160 /* length :: The length in bytes of the source object. */
163 /* FreeType error code. 0 means success. An error is returned if a */
164 /* reallocation fails. */
166 FT_LOCAL_DEF( FT_Error
)
167 ps_table_add( PS_Table table
,
172 if ( idx
< 0 || idx
> table
->max_elems
)
174 FT_ERROR(( "ps_table_add: invalid index\n" ));
175 return PSaux_Err_Invalid_Argument
;
178 /* grow the base block if needed */
179 if ( table
->cursor
+ length
> table
->capacity
)
182 FT_Offset new_size
= table
->capacity
;
186 in_offset
= (FT_Long
)((FT_Byte
*)object
- table
->block
);
187 if ( (FT_ULong
)in_offset
>= table
->capacity
)
190 while ( new_size
< table
->cursor
+ length
)
192 /* increase size by 25% and round up to the nearest multiple
194 new_size
+= ( new_size
>> 2 ) + 1;
195 new_size
= FT_PAD_CEIL( new_size
, 1024 );
198 error
= reallocate_t1_table( table
, new_size
);
202 if ( in_offset
>= 0 )
203 object
= table
->block
+ in_offset
;
206 /* add the object to the base block and adjust offset */
207 table
->elements
[idx
] = table
->block
+ table
->cursor
;
208 table
->lengths
[idx
] = length
;
209 FT_MEM_COPY( table
->block
+ table
->cursor
, object
, length
);
211 table
->cursor
+= length
;
216 /*************************************************************************/
222 /* Finalizes a PS_TableRec (i.e., reallocate it to its current */
226 /* table :: The target table. */
229 /* This function does NOT release the heap's memory block. It is up */
230 /* to the caller to clean it, or reference it in its own structures. */
233 ps_table_done( PS_Table table
)
235 FT_Memory memory
= table
->memory
;
237 FT_Byte
* old_base
= table
->block
;
240 /* should never fail, because rec.cursor <= rec.size */
244 if ( FT_ALLOC( table
->block
, table
->cursor
) )
246 FT_MEM_COPY( table
->block
, old_base
, table
->cursor
);
247 shift_elements( table
, old_base
);
249 table
->capacity
= table
->cursor
;
257 ps_table_release( PS_Table table
)
259 FT_Memory memory
= table
->memory
;
262 if ( (FT_ULong
)table
->init
== 0xDEADBEEFUL
)
264 FT_FREE( table
->block
);
265 FT_FREE( table
->elements
);
266 FT_FREE( table
->lengths
);
272 /*************************************************************************/
273 /*************************************************************************/
275 /***** T1 PARSER *****/
277 /*************************************************************************/
278 /*************************************************************************/
281 /* first character must be already part of the comment */
284 skip_comment( FT_Byte
* *acur
,
287 FT_Byte
* cur
= *acur
;
290 while ( cur
< limit
)
292 if ( IS_PS_NEWLINE( *cur
) )
302 skip_spaces( FT_Byte
* *acur
,
305 FT_Byte
* cur
= *acur
;
308 while ( cur
< limit
)
310 if ( !IS_PS_SPACE( *cur
) )
313 /* According to the PLRM, a comment is equal to a space. */
314 skip_comment( &cur
, limit
);
325 #define IS_OCTAL_DIGIT( c ) ( '0' <= (c) && (c) <= '7' )
328 /* first character must be `('; */
329 /* *acur is positioned at the character after the closing `)' */
332 skip_literal_string( FT_Byte
* *acur
,
335 FT_Byte
* cur
= *acur
;
337 FT_Error error
= PSaux_Err_Invalid_File_Format
;
341 while ( cur
< limit
)
350 /* Red Book 3rd ed., section `Literal Text Strings', p. 29: */
351 /* A backslash can introduce three different types */
352 /* of escape sequences: */
353 /* - a special escaped char like \r, \n, etc. */
354 /* - a one-, two-, or three-digit octal number */
355 /* - none of the above in which case the backslash is ignored */
358 /* error (or to be ignored?) */
363 /* skip `special' escape */
376 /* skip octal escape or ignore backslash */
377 for ( i
= 0; i
< 3 && cur
< limit
; ++i
)
379 if ( ! IS_OCTAL_DIGIT( *cur
) )
393 error
= PSaux_Err_Ok
;
405 /* first character must be `<' */
408 skip_string( FT_Byte
* *acur
,
411 FT_Byte
* cur
= *acur
;
412 FT_Error err
= PSaux_Err_Ok
;
415 while ( ++cur
< limit
)
417 /* All whitespace characters are ignored. */
418 skip_spaces( &cur
, limit
);
422 if ( !IS_PS_XDIGIT( *cur
) )
426 if ( cur
< limit
&& *cur
!= '>' )
428 FT_ERROR(( "skip_string: missing closing delimiter `>'\n" ));
429 err
= PSaux_Err_Invalid_File_Format
;
439 /* first character must be the opening brace that */
440 /* starts the procedure */
442 /* NB: [ and ] need not match: */
443 /* `/foo {[} def' is a valid PostScript fragment, */
444 /* even within a Type1 font */
447 skip_procedure( FT_Byte
* *acur
,
452 FT_Error error
= PSaux_Err_Ok
;
455 FT_ASSERT( **acur
== '{' );
457 for ( cur
= *acur
; cur
< limit
&& error
== PSaux_Err_Ok
; ++cur
)
475 error
= skip_literal_string( &cur
, limit
);
479 error
= skip_string( &cur
, limit
);
483 skip_comment( &cur
, limit
);
490 error
= PSaux_Err_Invalid_File_Format
;
498 /***********************************************************************/
500 /* All exported parsing routines handle leading whitespace and stop at */
501 /* the first character which isn't part of the just handled token. */
503 /***********************************************************************/
507 ps_parser_skip_PS_token( PS_Parser parser
)
509 /* Note: PostScript allows any non-delimiting, non-whitespace */
510 /* character in a name (PS Ref Manual, 3rd ed, p31). */
511 /* PostScript delimiters are (, ), <, >, [, ], {, }, /, and %. */
513 FT_Byte
* cur
= parser
->cursor
;
514 FT_Byte
* limit
= parser
->limit
;
515 FT_Error error
= PSaux_Err_Ok
;
518 skip_spaces( &cur
, limit
); /* this also skips comments */
522 /* self-delimiting, single-character tokens */
523 if ( *cur
== '[' || *cur
== ']' )
529 /* skip balanced expressions (procedures and strings) */
531 if ( *cur
== '{' ) /* {...} */
533 error
= skip_procedure( &cur
, limit
);
537 if ( *cur
== '(' ) /* (...) */
539 error
= skip_literal_string( &cur
, limit
);
543 if ( *cur
== '<' ) /* <...> */
545 if ( cur
+ 1 < limit
&& *(cur
+ 1) == '<' ) /* << */
551 error
= skip_string( &cur
, limit
);
559 if ( cur
>= limit
|| *cur
!= '>' ) /* >> */
561 FT_ERROR(( "ps_parser_skip_PS_token: "
562 "unexpected closing delimiter `>'\n" ));
563 error
= PSaux_Err_Invalid_File_Format
;
574 while ( cur
< limit
)
576 /* *cur might be invalid (e.g., ')' or '}'), but this */
577 /* is handled by the test `cur == parser->cursor' below */
578 if ( IS_PS_DELIM( *cur
) )
585 if ( cur
== parser
->cursor
)
587 FT_ERROR(( "ps_parser_skip_PS_token: "
588 "current token is `%c', which is self-delimiting "
589 "but invalid at this point\n",
592 error
= PSaux_Err_Invalid_File_Format
;
595 parser
->error
= error
;
596 parser
->cursor
= cur
;
601 ps_parser_skip_spaces( PS_Parser parser
)
603 skip_spaces( &parser
->cursor
, parser
->limit
);
607 /* `token' here means either something between balanced delimiters */
608 /* or the next token; the delimiters are not removed. */
611 ps_parser_to_token( PS_Parser parser
,
619 token
->type
= T1_TOKEN_TYPE_NONE
;
623 /* first of all, skip leading whitespace */
624 ps_parser_skip_spaces( parser
);
626 cur
= parser
->cursor
;
627 limit
= parser
->limit
;
634 /************* check for literal string *****************/
636 token
->type
= T1_TOKEN_TYPE_STRING
;
639 if ( skip_literal_string( &cur
, limit
) == PSaux_Err_Ok
)
643 /************* check for programs/array *****************/
645 token
->type
= T1_TOKEN_TYPE_ARRAY
;
648 if ( skip_procedure( &cur
, limit
) == PSaux_Err_Ok
)
652 /************* check for table/array ********************/
653 /* XXX: in theory we should also look for "<<" */
654 /* since this is semantically equivalent to "["; */
655 /* in practice it doesn't matter (?) */
657 token
->type
= T1_TOKEN_TYPE_ARRAY
;
659 token
->start
= cur
++;
661 /* we need this to catch `[ ]' */
662 parser
->cursor
= cur
;
663 ps_parser_skip_spaces( parser
);
664 cur
= parser
->cursor
;
666 while ( cur
< limit
&& !parser
->error
)
668 /* XXX: this is wrong because it does not */
669 /* skip comments, procedures, and strings */
672 else if ( *cur
== ']' )
677 token
->limit
= ++cur
;
682 parser
->cursor
= cur
;
683 ps_parser_skip_PS_token( parser
);
684 /* we need this to catch `[XXX ]' */
685 ps_parser_skip_spaces ( parser
);
686 cur
= parser
->cursor
;
690 /* ************ otherwise, it is any token **************/
693 token
->type
= ( *cur
== '/' ? T1_TOKEN_TYPE_KEY
: T1_TOKEN_TYPE_ANY
);
694 ps_parser_skip_PS_token( parser
);
695 cur
= parser
->cursor
;
696 if ( !parser
->error
)
703 token
->type
= T1_TOKEN_TYPE_NONE
;
706 parser
->cursor
= cur
;
710 /* NB: `tokens' can be NULL if we only want to count */
711 /* the number of array elements */
714 ps_parser_to_token_array( PS_Parser parser
,
717 FT_Int
* pnum_tokens
)
724 /* this also handles leading whitespace */
725 ps_parser_to_token( parser
, &master
);
727 if ( master
.type
== T1_TOKEN_TYPE_ARRAY
)
729 FT_Byte
* old_cursor
= parser
->cursor
;
730 FT_Byte
* old_limit
= parser
->limit
;
731 T1_Token cur
= tokens
;
732 T1_Token limit
= cur
+ max_tokens
;
735 /* don't include outermost delimiters */
736 parser
->cursor
= master
.start
+ 1;
737 parser
->limit
= master
.limit
- 1;
739 while ( parser
->cursor
< parser
->limit
)
744 ps_parser_to_token( parser
, &token
);
748 if ( tokens
!= NULL
&& cur
< limit
)
754 *pnum_tokens
= (FT_Int
)( cur
- tokens
);
756 parser
->cursor
= old_cursor
;
757 parser
->limit
= old_limit
;
762 /* first character must be a delimiter or a part of a number */
763 /* NB: `coords' can be NULL if we just want to skip the */
764 /* array; in this case we ignore `max_coords' */
767 ps_tocoordarray( FT_Byte
* *acur
,
772 FT_Byte
* cur
= *acur
;
780 /* check for the beginning of an array; otherwise, only one number */
793 /* now, read the coordinates */
794 while ( cur
< limit
)
800 /* skip whitespace in front of data */
801 skip_spaces( &cur
, limit
);
813 if ( coords
!= NULL
&& count
>= max_coords
)
816 /* call PS_Conv_ToFixed() even if coords == NULL */
817 /* to properly parse number at `cur' */
818 *( coords
!= NULL
? &coords
[count
] : &dummy
) =
819 (FT_Short
)( PS_Conv_ToFixed( &cur
, limit
, 0 ) >> 16 );
821 if ( old_cur
== cur
)
839 /* first character must be a delimiter or a part of a number */
840 /* NB: `values' can be NULL if we just want to skip the */
841 /* array; in this case we ignore `max_values' */
844 ps_tofixedarray( FT_Byte
* *acur
,
850 FT_Byte
* cur
= *acur
;
858 /* Check for the beginning of an array. Otherwise, only one number */
871 /* now, read the values */
872 while ( cur
< limit
)
878 /* skip whitespace in front of data */
879 skip_spaces( &cur
, limit
);
891 if ( values
!= NULL
&& count
>= max_values
)
894 /* call PS_Conv_ToFixed() even if coords == NULL */
895 /* to properly parse number at `cur' */
896 *( values
!= NULL
? &values
[count
] : &dummy
) =
897 PS_Conv_ToFixed( &cur
, limit
, power_ten
);
899 if ( old_cur
== cur
)
920 ps_tostring( FT_Byte
** cursor
,
924 FT_Byte
* cur
= *cursor
;
931 /* XXX: some stupid fonts have a `Notice' or `Copyright' string */
932 /* that simply doesn't begin with an opening parenthesis, even */
933 /* though they have a closing one! E.g. "amuncial.pfb" */
935 /* We must deal with these ill-fated cases there. Note that */
936 /* these fonts didn't work with the old Type 1 driver as the */
937 /* notice/copyright was not recognized as a valid string token */
938 /* and made the old token parser commit errors. */
940 while ( cur
< limit
&& ( *cur
== ' ' || *cur
== '\t' ) )
942 if ( cur
+ 1 >= limit
)
946 cur
++; /* skip the opening parenthesis, if there is one */
951 /* then, count its length */
952 for ( ; cur
< limit
; cur
++ )
957 else if ( *cur
== ')' )
966 if ( cur
>= limit
|| FT_ALLOC( result
, len
+ 1 ) )
969 /* now copy the string */
970 FT_MEM_COPY( result
, *cursor
, len
);
980 ps_tobool( FT_Byte
* *acur
,
983 FT_Byte
* cur
= *acur
;
987 /* return 1 if we find `true', 0 otherwise */
988 if ( cur
+ 3 < limit
&&
997 else if ( cur
+ 4 < limit
&&
1013 /* load a simple field (i.e. non-table) into the current list of objects */
1015 FT_LOCAL_DEF( FT_Error
)
1016 ps_parser_load_field( PS_Parser parser
,
1017 const T1_Field field
,
1019 FT_UInt max_objects
,
1030 /* this also skips leading whitespace */
1031 ps_parser_to_token( parser
, &token
);
1038 limit
= token
.limit
;
1040 /* we must detect arrays in /FontBBox */
1041 if ( field
->type
== T1_FIELD_TYPE_BBOX
)
1044 FT_Byte
* old_cur
= parser
->cursor
;
1045 FT_Byte
* old_limit
= parser
->limit
;
1048 /* don't include delimiters */
1049 parser
->cursor
= token
.start
+ 1;
1050 parser
->limit
= token
.limit
- 1;
1052 ps_parser_to_token( parser
, &token2
);
1053 parser
->cursor
= old_cur
;
1054 parser
->limit
= old_limit
;
1056 if ( token2
.type
== T1_TOKEN_TYPE_ARRAY
)
1059 else if ( token
.type
== T1_TOKEN_TYPE_ARRAY
)
1062 /* if this is an array and we have no blend, an error occurs */
1063 if ( max_objects
== 0 )
1066 count
= max_objects
;
1069 /* don't include delimiters */
1074 for ( ; count
> 0; count
--, idx
++ )
1076 FT_Byte
* q
= (FT_Byte
*)objects
[idx
] + field
->offset
;
1081 skip_spaces( &cur
, limit
);
1083 switch ( field
->type
)
1085 case T1_FIELD_TYPE_BOOL
:
1086 val
= ps_tobool( &cur
, limit
);
1089 case T1_FIELD_TYPE_FIXED
:
1090 val
= PS_Conv_ToFixed( &cur
, limit
, 0 );
1093 case T1_FIELD_TYPE_FIXED_1000
:
1094 val
= PS_Conv_ToFixed( &cur
, limit
, 3 );
1097 case T1_FIELD_TYPE_INTEGER
:
1098 val
= PS_Conv_ToInt( &cur
, limit
);
1102 switch ( field
->size
)
1104 case (8 / FT_CHAR_BIT
):
1105 *(FT_Byte
*)q
= (FT_Byte
)val
;
1108 case (16 / FT_CHAR_BIT
):
1109 *(FT_UShort
*)q
= (FT_UShort
)val
;
1112 case (32 / FT_CHAR_BIT
):
1113 *(FT_UInt32
*)q
= (FT_UInt32
)val
;
1116 default: /* for 64-bit systems */
1121 case T1_FIELD_TYPE_STRING
:
1122 case T1_FIELD_TYPE_KEY
:
1124 FT_Memory memory
= parser
->memory
;
1125 FT_UInt len
= (FT_UInt
)( limit
- cur
);
1131 /* we allow both a string or a name */
1132 /* for cases like /FontName (foo) def */
1133 if ( token
.type
== T1_TOKEN_TYPE_KEY
)
1135 /* don't include leading `/' */
1139 else if ( token
.type
== T1_TOKEN_TYPE_STRING
)
1141 /* don't include delimiting parentheses */
1142 /* XXX we don't handle <<...>> here */
1143 /* XXX should we convert octal escapes? */
1144 /* if so, what encoding should we use? */
1150 FT_ERROR(( "ps_parser_load_field: expected a name or string "
1151 "but found token of type %d instead\n",
1153 error
= PSaux_Err_Invalid_File_Format
;
1157 /* for this to work (FT_String**)q must have been */
1158 /* initialized to NULL */
1159 if ( *(FT_String
**)q
!= NULL
)
1161 FT_TRACE0(( "ps_parser_load_field: overwriting field %s\n",
1163 FT_FREE( *(FT_String
**)q
);
1164 *(FT_String
**)q
= NULL
;
1167 if ( FT_ALLOC( string
, len
+ 1 ) )
1170 FT_MEM_COPY( string
, cur
, len
);
1173 *(FT_String
**)q
= string
;
1177 case T1_FIELD_TYPE_BBOX
:
1180 FT_BBox
* bbox
= (FT_BBox
*)q
;
1184 result
= ps_tofixedarray( &cur
, limit
, 4, temp
, 0 );
1188 FT_ERROR(( "ps_parser_load_field: "
1189 "expected four integers in bounding box\n" ));
1190 error
= PSaux_Err_Invalid_File_Format
;
1194 bbox
->xMin
= FT_RoundFix( temp
[0] );
1195 bbox
->yMin
= FT_RoundFix( temp
[1] );
1196 bbox
->xMax
= FT_RoundFix( temp
[2] );
1197 bbox
->yMax
= FT_RoundFix( temp
[3] );
1202 /* an error occurred */
1207 #if 0 /* obsolete -- keep for reference */
1209 *pflags
|= 1L << field
->flag_bit
;
1211 FT_UNUSED( pflags
);
1214 error
= PSaux_Err_Ok
;
1220 error
= PSaux_Err_Invalid_File_Format
;
1225 #define T1_MAX_TABLE_ELEMENTS 32
1228 FT_LOCAL_DEF( FT_Error
)
1229 ps_parser_load_field_table( PS_Parser parser
,
1230 const T1_Field field
,
1232 FT_UInt max_objects
,
1235 T1_TokenRec elements
[T1_MAX_TABLE_ELEMENTS
];
1237 FT_Int num_elements
;
1238 FT_Error error
= PSaux_Err_Ok
;
1239 FT_Byte
* old_cursor
;
1241 T1_FieldRec fieldrec
= *(T1_Field
)field
;
1244 fieldrec
.type
= T1_FIELD_TYPE_INTEGER
;
1245 if ( field
->type
== T1_FIELD_TYPE_FIXED_ARRAY
||
1246 field
->type
== T1_FIELD_TYPE_BBOX
)
1247 fieldrec
.type
= T1_FIELD_TYPE_FIXED
;
1249 ps_parser_to_token_array( parser
, elements
,
1250 T1_MAX_TABLE_ELEMENTS
, &num_elements
);
1251 if ( num_elements
< 0 )
1253 error
= PSaux_Err_Ignore
;
1256 if ( (FT_UInt
)num_elements
> field
->array_max
)
1257 num_elements
= field
->array_max
;
1259 old_cursor
= parser
->cursor
;
1260 old_limit
= parser
->limit
;
1262 /* we store the elements count if necessary */
1263 if ( field
->type
!= T1_FIELD_TYPE_BBOX
)
1264 *(FT_Byte
*)( (FT_Byte
*)objects
[0] + field
->count_offset
) =
1265 (FT_Byte
)num_elements
;
1267 /* we now load each element, adjusting the field.offset on each one */
1269 for ( ; num_elements
> 0; num_elements
--, token
++ )
1271 parser
->cursor
= token
->start
;
1272 parser
->limit
= token
->limit
;
1273 ps_parser_load_field( parser
, &fieldrec
, objects
, max_objects
, 0 );
1274 fieldrec
.offset
+= fieldrec
.size
;
1277 #if 0 /* obsolete -- keep for reference */
1279 *pflags
|= 1L << field
->flag_bit
;
1281 FT_UNUSED( pflags
);
1284 parser
->cursor
= old_cursor
;
1285 parser
->limit
= old_limit
;
1292 FT_LOCAL_DEF( FT_Long
)
1293 ps_parser_to_int( PS_Parser parser
)
1295 ps_parser_skip_spaces( parser
);
1296 return PS_Conv_ToInt( &parser
->cursor
, parser
->limit
);
1300 /* first character must be `<' if `delimiters' is non-zero */
1302 FT_LOCAL_DEF( FT_Error
)
1303 ps_parser_to_bytes( PS_Parser parser
,
1306 FT_Long
* pnum_bytes
,
1307 FT_Bool delimiters
)
1309 FT_Error error
= PSaux_Err_Ok
;
1313 ps_parser_skip_spaces( parser
);
1314 cur
= parser
->cursor
;
1316 if ( cur
>= parser
->limit
)
1323 FT_ERROR(( "ps_parser_to_bytes: Missing starting delimiter `<'\n" ));
1324 error
= PSaux_Err_Invalid_File_Format
;
1331 *pnum_bytes
= PS_Conv_ASCIIHexDecode( &cur
,
1338 if ( cur
< parser
->limit
&& *cur
!= '>' )
1340 FT_ERROR(( "ps_parser_to_bytes: Missing closing delimiter `>'\n" ));
1341 error
= PSaux_Err_Invalid_File_Format
;
1348 parser
->cursor
= cur
;
1355 FT_LOCAL_DEF( FT_Fixed
)
1356 ps_parser_to_fixed( PS_Parser parser
,
1359 ps_parser_skip_spaces( parser
);
1360 return PS_Conv_ToFixed( &parser
->cursor
, parser
->limit
, power_ten
);
1364 FT_LOCAL_DEF( FT_Int
)
1365 ps_parser_to_coord_array( PS_Parser parser
,
1369 ps_parser_skip_spaces( parser
);
1370 return ps_tocoordarray( &parser
->cursor
, parser
->limit
,
1371 max_coords
, coords
);
1375 FT_LOCAL_DEF( FT_Int
)
1376 ps_parser_to_fixed_array( PS_Parser parser
,
1381 ps_parser_skip_spaces( parser
);
1382 return ps_tofixedarray( &parser
->cursor
, parser
->limit
,
1383 max_values
, values
, power_ten
);
1389 FT_LOCAL_DEF( FT_String
* )
1390 T1_ToString( PS_Parser parser
)
1392 return ps_tostring( &parser
->cursor
, parser
->limit
, parser
->memory
);
1396 FT_LOCAL_DEF( FT_Bool
)
1397 T1_ToBool( PS_Parser parser
)
1399 return ps_tobool( &parser
->cursor
, parser
->limit
);
1405 FT_LOCAL_DEF( void )
1406 ps_parser_init( PS_Parser parser
,
1411 parser
->error
= PSaux_Err_Ok
;
1412 parser
->base
= base
;
1413 parser
->limit
= limit
;
1414 parser
->cursor
= base
;
1415 parser
->memory
= memory
;
1416 parser
->funcs
= ps_parser_funcs
;
1420 FT_LOCAL_DEF( void )
1421 ps_parser_done( PS_Parser parser
)
1423 FT_UNUSED( parser
);
1427 /*************************************************************************/
1428 /*************************************************************************/
1430 /***** T1 BUILDER *****/
1432 /*************************************************************************/
1433 /*************************************************************************/
1435 /*************************************************************************/
1438 /* t1_builder_init */
1441 /* Initializes a given glyph builder. */
1444 /* builder :: A pointer to the glyph builder to initialize. */
1447 /* face :: The current face object. */
1449 /* size :: The current size object. */
1451 /* glyph :: The current glyph object. */
1453 /* hinting :: Whether hinting should be applied. */
1455 FT_LOCAL_DEF( void )
1456 t1_builder_init( T1_Builder builder
,
1462 builder
->parse_state
= T1_Parse_Start
;
1463 builder
->load_points
= 1;
1465 builder
->face
= face
;
1466 builder
->glyph
= glyph
;
1467 builder
->memory
= face
->memory
;
1471 FT_GlyphLoader loader
= glyph
->internal
->loader
;
1474 builder
->loader
= loader
;
1475 builder
->base
= &loader
->base
.outline
;
1476 builder
->current
= &loader
->current
.outline
;
1477 FT_GlyphLoader_Rewind( loader
);
1479 builder
->hints_globals
= size
->internal
;
1480 builder
->hints_funcs
= 0;
1483 builder
->hints_funcs
= glyph
->internal
->glyph_hints
;
1488 builder
->scale_x
= size
->metrics
.x_scale
;
1489 builder
->scale_y
= size
->metrics
.y_scale
;
1495 builder
->left_bearing
.x
= 0;
1496 builder
->left_bearing
.y
= 0;
1497 builder
->advance
.x
= 0;
1498 builder
->advance
.y
= 0;
1500 builder
->funcs
= t1_builder_funcs
;
1504 /*************************************************************************/
1507 /* t1_builder_done */
1510 /* Finalizes a given glyph builder. Its contents can still be used */
1511 /* after the call, but the function saves important information */
1512 /* within the corresponding glyph slot. */
1515 /* builder :: A pointer to the glyph builder to finalize. */
1517 FT_LOCAL_DEF( void )
1518 t1_builder_done( T1_Builder builder
)
1520 FT_GlyphSlot glyph
= builder
->glyph
;
1524 glyph
->outline
= *builder
->base
;
1528 /* check that there is enough space for `count' more points */
1529 FT_LOCAL_DEF( FT_Error
)
1530 t1_builder_check_points( T1_Builder builder
,
1533 return FT_GLYPHLOADER_CHECK_POINTS( builder
->loader
, count
, 0 );
1537 /* add a new point, do not check space */
1538 FT_LOCAL_DEF( void )
1539 t1_builder_add_point( T1_Builder builder
,
1544 FT_Outline
* outline
= builder
->current
;
1547 if ( builder
->load_points
)
1549 FT_Vector
* point
= outline
->points
+ outline
->n_points
;
1550 FT_Byte
* control
= (FT_Byte
*)outline
->tags
+ outline
->n_points
;
1553 if ( builder
->shift
)
1560 *control
= (FT_Byte
)( flag
? FT_CURVE_TAG_ON
: FT_CURVE_TAG_CUBIC
);
1562 builder
->last
= *point
;
1564 outline
->n_points
++;
1568 /* check space for a new on-curve point, then add it */
1569 FT_LOCAL_DEF( FT_Error
)
1570 t1_builder_add_point1( T1_Builder builder
,
1577 error
= t1_builder_check_points( builder
, 1 );
1579 t1_builder_add_point( builder
, x
, y
, 1 );
1585 /* check space for a new contour, then add it */
1586 FT_LOCAL_DEF( FT_Error
)
1587 t1_builder_add_contour( T1_Builder builder
)
1589 FT_Outline
* outline
= builder
->current
;
1593 if ( !builder
->load_points
)
1595 outline
->n_contours
++;
1596 return PSaux_Err_Ok
;
1599 error
= FT_GLYPHLOADER_CHECK_POINTS( builder
->loader
, 0, 1 );
1602 if ( outline
->n_contours
> 0 )
1603 outline
->contours
[outline
->n_contours
- 1] =
1604 (short)( outline
->n_points
- 1 );
1606 outline
->n_contours
++;
1613 /* if a path was begun, add its first on-curve point */
1614 FT_LOCAL_DEF( FT_Error
)
1615 t1_builder_start_point( T1_Builder builder
,
1619 FT_Error error
= PSaux_Err_Invalid_File_Format
;
1622 /* test whether we are building a new contour */
1624 if ( builder
->parse_state
== T1_Parse_Have_Path
)
1625 error
= PSaux_Err_Ok
;
1626 else if ( builder
->parse_state
== T1_Parse_Have_Moveto
)
1628 builder
->parse_state
= T1_Parse_Have_Path
;
1629 error
= t1_builder_add_contour( builder
);
1631 error
= t1_builder_add_point1( builder
, x
, y
);
1638 /* close the current contour */
1639 FT_LOCAL_DEF( void )
1640 t1_builder_close_contour( T1_Builder builder
)
1642 FT_Outline
* outline
= builder
->current
;
1648 /* XXXX: We must not include the last point in the path if it */
1649 /* is located on the first point. */
1650 if ( outline
->n_points
> 1 )
1653 FT_Vector
* p1
= outline
->points
+ first
;
1654 FT_Vector
* p2
= outline
->points
+ outline
->n_points
- 1;
1655 FT_Byte
* control
= (FT_Byte
*)outline
->tags
+ outline
->n_points
- 1;
1658 if ( outline
->n_contours
> 1 )
1660 first
= outline
->contours
[outline
->n_contours
- 2] + 1;
1661 p1
= outline
->points
+ first
;
1664 /* `delete' last point only if it coincides with the first */
1665 /* point and it is not a control point (which can happen). */
1666 if ( p1
->x
== p2
->x
&& p1
->y
== p2
->y
)
1667 if ( *control
== FT_CURVE_TAG_ON
)
1668 outline
->n_points
--;
1671 if ( outline
->n_contours
> 0 )
1672 outline
->contours
[outline
->n_contours
- 1] =
1673 (short)( outline
->n_points
- 1 );
1677 /*************************************************************************/
1678 /*************************************************************************/
1682 /*************************************************************************/
1683 /*************************************************************************/
1685 FT_LOCAL_DEF( void )
1686 t1_decrypt( FT_Byte
* buffer
,
1690 PS_Conv_EexecDecode( &buffer
,