1 /***************************************************************************/
5 /* Auxiliary functions for PostScript fonts (body). */
7 /* Copyright 1996-2016 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
22 #include FT_INTERNAL_CALC_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_psobjs
40 /*************************************************************************/
41 /*************************************************************************/
43 /***** PS_TABLE *****/
45 /*************************************************************************/
46 /*************************************************************************/
48 /*************************************************************************/
54 /* Initializes a PS_Table. */
57 /* table :: The address of the target table. */
60 /* count :: The table size = the maximum number of elements. */
62 /* memory :: The memory object to use for all subsequent */
66 /* FreeType error code. 0 means success. */
68 FT_LOCAL_DEF( FT_Error
)
69 ps_table_new( PS_Table table
,
76 table
->memory
= memory
;
77 if ( FT_NEW_ARRAY( table
->elements
, count
) ||
78 FT_NEW_ARRAY( table
->lengths
, count
) )
81 table
->max_elems
= count
;
82 table
->init
= 0xDEADBEEFUL
;
88 *(PS_Table_FuncsRec
*)&table
->funcs
= ps_table_funcs
;
92 FT_FREE( table
->elements
);
99 shift_elements( PS_Table table
,
102 FT_PtrDist delta
= table
->block
- old_base
;
103 FT_Byte
** offset
= table
->elements
;
104 FT_Byte
** limit
= offset
+ table
->max_elems
;
107 for ( ; offset
< limit
; offset
++ )
116 reallocate_t1_table( PS_Table table
,
119 FT_Memory memory
= table
->memory
;
120 FT_Byte
* old_base
= table
->block
;
124 /* allocate new base block */
125 if ( FT_ALLOC( table
->block
, new_size
) )
127 table
->block
= old_base
;
131 /* copy elements and shift offsets */
134 FT_MEM_COPY( table
->block
, old_base
, table
->capacity
);
135 shift_elements( table
, old_base
);
139 table
->capacity
= new_size
;
145 /*************************************************************************/
151 /* Adds an object to a PS_Table, possibly growing its memory block. */
154 /* table :: The target table. */
157 /* idx :: The index of the object in the table. */
159 /* object :: The address of the object to copy in memory. */
161 /* length :: The length in bytes of the source object. */
164 /* FreeType error code. 0 means success. An error is returned if a */
165 /* reallocation fails. */
167 FT_LOCAL_DEF( FT_Error
)
168 ps_table_add( PS_Table table
,
173 if ( idx
< 0 || idx
>= table
->max_elems
)
175 FT_ERROR(( "ps_table_add: invalid index\n" ));
176 return FT_THROW( Invalid_Argument
);
179 /* grow the base block if needed */
180 if ( table
->cursor
+ length
> table
->capacity
)
183 FT_Offset new_size
= table
->capacity
;
184 FT_PtrDist in_offset
;
187 in_offset
= (FT_Byte
*)object
- table
->block
;
188 if ( in_offset
< 0 || (FT_Offset
)in_offset
>= table
->capacity
)
191 while ( new_size
< table
->cursor
+ length
)
193 /* increase size by 25% and round up to the nearest multiple
195 new_size
+= ( new_size
>> 2 ) + 1;
196 new_size
= FT_PAD_CEIL( new_size
, 1024 );
199 error
= reallocate_t1_table( table
, new_size
);
203 if ( in_offset
>= 0 )
204 object
= table
->block
+ in_offset
;
207 /* add the object to the base block and adjust offset */
208 table
->elements
[idx
] = table
->block
+ table
->cursor
;
209 table
->lengths
[idx
] = length
;
210 FT_MEM_COPY( table
->block
+ table
->cursor
, object
, length
);
212 table
->cursor
+= length
;
217 /*************************************************************************/
223 /* Finalizes a PS_TableRec (i.e., reallocate it to its current */
227 /* table :: The target table. */
230 /* This function does NOT release the heap's memory block. It is up */
231 /* to the caller to clean it, or reference it in its own structures. */
234 ps_table_done( PS_Table table
)
236 FT_Memory memory
= table
->memory
;
238 FT_Byte
* old_base
= table
->block
;
241 /* should never fail, because rec.cursor <= rec.size */
245 if ( FT_ALLOC( table
->block
, table
->cursor
) )
247 FT_MEM_COPY( table
->block
, old_base
, table
->cursor
);
248 shift_elements( table
, old_base
);
250 table
->capacity
= table
->cursor
;
258 ps_table_release( PS_Table table
)
260 FT_Memory memory
= table
->memory
;
263 if ( (FT_ULong
)table
->init
== 0xDEADBEEFUL
)
265 FT_FREE( table
->block
);
266 FT_FREE( table
->elements
);
267 FT_FREE( table
->lengths
);
273 /*************************************************************************/
274 /*************************************************************************/
276 /***** T1 PARSER *****/
278 /*************************************************************************/
279 /*************************************************************************/
282 /* first character must be already part of the comment */
285 skip_comment( FT_Byte
* *acur
,
288 FT_Byte
* cur
= *acur
;
291 while ( cur
< limit
)
293 if ( IS_PS_NEWLINE( *cur
) )
303 skip_spaces( FT_Byte
* *acur
,
306 FT_Byte
* cur
= *acur
;
309 while ( cur
< limit
)
311 if ( !IS_PS_SPACE( *cur
) )
314 /* According to the PLRM, a comment is equal to a space. */
315 skip_comment( &cur
, limit
);
326 #define IS_OCTAL_DIGIT( c ) ( '0' <= (c) && (c) <= '7' )
329 /* first character must be `('; */
330 /* *acur is positioned at the character after the closing `)' */
333 skip_literal_string( FT_Byte
* *acur
,
336 FT_Byte
* cur
= *acur
;
338 FT_Error error
= FT_ERR( Invalid_File_Format
);
342 while ( cur
< limit
)
351 /* Red Book 3rd ed., section `Literal Text Strings', p. 29: */
352 /* A backslash can introduce three different types */
353 /* of escape sequences: */
354 /* - a special escaped char like \r, \n, etc. */
355 /* - a one-, two-, or three-digit octal number */
356 /* - none of the above in which case the backslash is ignored */
359 /* error (or to be ignored?) */
364 /* skip `special' escape */
377 /* skip octal escape or ignore backslash */
378 for ( i
= 0; i
< 3 && cur
< limit
; ++i
)
380 if ( !IS_OCTAL_DIGIT( *cur
) )
406 /* first character must be `<' */
409 skip_string( FT_Byte
* *acur
,
412 FT_Byte
* cur
= *acur
;
413 FT_Error err
= FT_Err_Ok
;
416 while ( ++cur
< limit
)
418 /* All whitespace characters are ignored. */
419 skip_spaces( &cur
, limit
);
423 if ( !IS_PS_XDIGIT( *cur
) )
427 if ( cur
< limit
&& *cur
!= '>' )
429 FT_ERROR(( "skip_string: missing closing delimiter `>'\n" ));
430 err
= FT_THROW( Invalid_File_Format
);
440 /* first character must be the opening brace that */
441 /* starts the procedure */
443 /* NB: [ and ] need not match: */
444 /* `/foo {[} def' is a valid PostScript fragment, */
445 /* even within a Type1 font */
448 skip_procedure( FT_Byte
* *acur
,
453 FT_Error error
= FT_Err_Ok
;
456 FT_ASSERT( **acur
== '{' );
458 for ( cur
= *acur
; cur
< limit
&& error
== FT_Err_Ok
; ++cur
)
476 error
= skip_literal_string( &cur
, limit
);
480 error
= skip_string( &cur
, limit
);
484 skip_comment( &cur
, limit
);
491 error
= FT_THROW( Invalid_File_Format
);
499 /***********************************************************************/
501 /* All exported parsing routines handle leading whitespace and stop at */
502 /* the first character which isn't part of the just handled token. */
504 /***********************************************************************/
508 ps_parser_skip_PS_token( PS_Parser parser
)
510 /* Note: PostScript allows any non-delimiting, non-whitespace */
511 /* character in a name (PS Ref Manual, 3rd ed, p31). */
512 /* PostScript delimiters are (, ), <, >, [, ], {, }, /, and %. */
514 FT_Byte
* cur
= parser
->cursor
;
515 FT_Byte
* limit
= parser
->limit
;
516 FT_Error error
= FT_Err_Ok
;
519 skip_spaces( &cur
, limit
); /* this also skips comments */
523 /* self-delimiting, single-character tokens */
524 if ( *cur
== '[' || *cur
== ']' )
530 /* skip balanced expressions (procedures and strings) */
532 if ( *cur
== '{' ) /* {...} */
534 error
= skip_procedure( &cur
, limit
);
538 if ( *cur
== '(' ) /* (...) */
540 error
= skip_literal_string( &cur
, limit
);
544 if ( *cur
== '<' ) /* <...> */
546 if ( cur
+ 1 < limit
&& *(cur
+ 1) == '<' ) /* << */
552 error
= skip_string( &cur
, limit
);
560 if ( cur
>= limit
|| *cur
!= '>' ) /* >> */
562 FT_ERROR(( "ps_parser_skip_PS_token:"
563 " unexpected closing delimiter `>'\n" ));
564 error
= FT_THROW( Invalid_File_Format
);
575 while ( cur
< limit
)
577 /* *cur might be invalid (e.g., ')' or '}'), but this */
578 /* is handled by the test `cur == parser->cursor' below */
579 if ( IS_PS_DELIM( *cur
) )
586 if ( cur
< limit
&& cur
== parser
->cursor
)
588 FT_ERROR(( "ps_parser_skip_PS_token:"
589 " current token is `%c' which is self-delimiting\n"
591 " but invalid at this point\n",
594 error
= FT_THROW( Invalid_File_Format
);
600 parser
->error
= error
;
601 parser
->cursor
= cur
;
606 ps_parser_skip_spaces( PS_Parser parser
)
608 skip_spaces( &parser
->cursor
, parser
->limit
);
612 /* `token' here means either something between balanced delimiters */
613 /* or the next token; the delimiters are not removed. */
616 ps_parser_to_token( PS_Parser parser
,
624 token
->type
= T1_TOKEN_TYPE_NONE
;
628 /* first of all, skip leading whitespace */
629 ps_parser_skip_spaces( parser
);
631 cur
= parser
->cursor
;
632 limit
= parser
->limit
;
639 /************* check for literal string *****************/
641 token
->type
= T1_TOKEN_TYPE_STRING
;
644 if ( skip_literal_string( &cur
, limit
) == FT_Err_Ok
)
648 /************* check for programs/array *****************/
650 token
->type
= T1_TOKEN_TYPE_ARRAY
;
653 if ( skip_procedure( &cur
, limit
) == FT_Err_Ok
)
657 /************* check for table/array ********************/
658 /* XXX: in theory we should also look for "<<" */
659 /* since this is semantically equivalent to "["; */
660 /* in practice it doesn't matter (?) */
662 token
->type
= T1_TOKEN_TYPE_ARRAY
;
664 token
->start
= cur
++;
666 /* we need this to catch `[ ]' */
667 parser
->cursor
= cur
;
668 ps_parser_skip_spaces( parser
);
669 cur
= parser
->cursor
;
671 while ( cur
< limit
&& !parser
->error
)
673 /* XXX: this is wrong because it does not */
674 /* skip comments, procedures, and strings */
677 else if ( *cur
== ']' )
682 token
->limit
= ++cur
;
687 parser
->cursor
= cur
;
688 ps_parser_skip_PS_token( parser
);
689 /* we need this to catch `[XXX ]' */
690 ps_parser_skip_spaces ( parser
);
691 cur
= parser
->cursor
;
695 /* ************ otherwise, it is any token **************/
698 token
->type
= ( *cur
== '/' ? T1_TOKEN_TYPE_KEY
: T1_TOKEN_TYPE_ANY
);
699 ps_parser_skip_PS_token( parser
);
700 cur
= parser
->cursor
;
701 if ( !parser
->error
)
708 token
->type
= T1_TOKEN_TYPE_NONE
;
711 parser
->cursor
= cur
;
715 /* NB: `tokens' can be NULL if we only want to count */
716 /* the number of array elements */
719 ps_parser_to_token_array( PS_Parser parser
,
722 FT_Int
* pnum_tokens
)
729 /* this also handles leading whitespace */
730 ps_parser_to_token( parser
, &master
);
732 if ( master
.type
== T1_TOKEN_TYPE_ARRAY
)
734 FT_Byte
* old_cursor
= parser
->cursor
;
735 FT_Byte
* old_limit
= parser
->limit
;
736 T1_Token cur
= tokens
;
737 T1_Token limit
= cur
+ max_tokens
;
740 /* don't include outermost delimiters */
741 parser
->cursor
= master
.start
+ 1;
742 parser
->limit
= master
.limit
- 1;
744 while ( parser
->cursor
< parser
->limit
)
749 ps_parser_to_token( parser
, &token
);
753 if ( tokens
!= NULL
&& cur
< limit
)
759 *pnum_tokens
= (FT_Int
)( cur
- tokens
);
761 parser
->cursor
= old_cursor
;
762 parser
->limit
= old_limit
;
767 /* first character must be a delimiter or a part of a number */
768 /* NB: `coords' can be NULL if we just want to skip the */
769 /* array; in this case we ignore `max_coords' */
772 ps_tocoordarray( FT_Byte
* *acur
,
777 FT_Byte
* cur
= *acur
;
785 /* check for the beginning of an array; otherwise, only one number */
798 /* now, read the coordinates */
799 while ( cur
< limit
)
805 /* skip whitespace in front of data */
806 skip_spaces( &cur
, limit
);
818 if ( coords
!= NULL
&& count
>= max_coords
)
821 /* call PS_Conv_ToFixed() even if coords == NULL */
822 /* to properly parse number at `cur' */
823 *( coords
!= NULL
? &coords
[count
] : &dummy
) =
824 (FT_Short
)( PS_Conv_ToFixed( &cur
, limit
, 0 ) >> 16 );
826 if ( old_cur
== cur
)
844 /* first character must be a delimiter or a part of a number */
845 /* NB: `values' can be NULL if we just want to skip the */
846 /* array; in this case we ignore `max_values' */
848 /* return number of successfully parsed values */
851 ps_tofixedarray( FT_Byte
* *acur
,
857 FT_Byte
* cur
= *acur
;
865 /* Check for the beginning of an array. Otherwise, only one number */
878 /* now, read the values */
879 while ( cur
< limit
)
885 /* skip whitespace in front of data */
886 skip_spaces( &cur
, limit
);
898 if ( values
!= NULL
&& count
>= max_values
)
901 /* call PS_Conv_ToFixed() even if coords == NULL */
902 /* to properly parse number at `cur' */
903 *( values
!= NULL
? &values
[count
] : &dummy
) =
904 PS_Conv_ToFixed( &cur
, limit
, power_ten
);
906 if ( old_cur
== cur
)
927 ps_tostring( FT_Byte
** cursor
,
931 FT_Byte
* cur
= *cursor
;
938 /* XXX: some stupid fonts have a `Notice' or `Copyright' string */
939 /* that simply doesn't begin with an opening parenthesis, even */
940 /* though they have a closing one! E.g. "amuncial.pfb" */
942 /* We must deal with these ill-fated cases there. Note that */
943 /* these fonts didn't work with the old Type 1 driver as the */
944 /* notice/copyright was not recognized as a valid string token */
945 /* and made the old token parser commit errors. */
947 while ( cur
< limit
&& ( *cur
== ' ' || *cur
== '\t' ) )
949 if ( cur
+ 1 >= limit
)
953 cur
++; /* skip the opening parenthesis, if there is one */
958 /* then, count its length */
959 for ( ; cur
< limit
; cur
++ )
964 else if ( *cur
== ')' )
972 len
= (FT_UInt
)( cur
- *cursor
);
973 if ( cur
>= limit
|| FT_ALLOC( result
, len
+ 1 ) )
976 /* now copy the string */
977 FT_MEM_COPY( result
, *cursor
, len
);
987 ps_tobool( FT_Byte
* *acur
,
990 FT_Byte
* cur
= *acur
;
994 /* return 1 if we find `true', 0 otherwise */
995 if ( cur
+ 3 < limit
&&
1004 else if ( cur
+ 4 < limit
&&
1020 /* load a simple field (i.e. non-table) into the current list of objects */
1022 FT_LOCAL_DEF( FT_Error
)
1023 ps_parser_load_field( PS_Parser parser
,
1024 const T1_Field field
,
1026 FT_UInt max_objects
,
1038 /* this also skips leading whitespace */
1039 ps_parser_to_token( parser
, &token
);
1046 limit
= token
.limit
;
1050 /* we must detect arrays in /FontBBox */
1051 if ( type
== T1_FIELD_TYPE_BBOX
)
1054 FT_Byte
* old_cur
= parser
->cursor
;
1055 FT_Byte
* old_limit
= parser
->limit
;
1058 /* don't include delimiters */
1059 parser
->cursor
= token
.start
+ 1;
1060 parser
->limit
= token
.limit
- 1;
1062 ps_parser_to_token( parser
, &token2
);
1063 parser
->cursor
= old_cur
;
1064 parser
->limit
= old_limit
;
1066 if ( token2
.type
== T1_TOKEN_TYPE_ARRAY
)
1068 type
= T1_FIELD_TYPE_MM_BBOX
;
1072 else if ( token
.type
== T1_TOKEN_TYPE_ARRAY
)
1074 count
= max_objects
;
1077 /* if this is an array and we have no blend, an error occurs */
1078 if ( max_objects
== 0 )
1083 /* don't include delimiters */
1088 for ( ; count
> 0; count
--, idx
++ )
1090 FT_Byte
* q
= (FT_Byte
*)objects
[idx
] + field
->offset
;
1095 skip_spaces( &cur
, limit
);
1099 case T1_FIELD_TYPE_BOOL
:
1100 val
= ps_tobool( &cur
, limit
);
1103 case T1_FIELD_TYPE_FIXED
:
1104 val
= PS_Conv_ToFixed( &cur
, limit
, 0 );
1107 case T1_FIELD_TYPE_FIXED_1000
:
1108 val
= PS_Conv_ToFixed( &cur
, limit
, 3 );
1111 case T1_FIELD_TYPE_INTEGER
:
1112 val
= PS_Conv_ToInt( &cur
, limit
);
1116 switch ( field
->size
)
1118 case (8 / FT_CHAR_BIT
):
1119 *(FT_Byte
*)q
= (FT_Byte
)val
;
1122 case (16 / FT_CHAR_BIT
):
1123 *(FT_UShort
*)q
= (FT_UShort
)val
;
1126 case (32 / FT_CHAR_BIT
):
1127 *(FT_UInt32
*)q
= (FT_UInt32
)val
;
1130 default: /* for 64-bit systems */
1135 case T1_FIELD_TYPE_STRING
:
1136 case T1_FIELD_TYPE_KEY
:
1138 FT_Memory memory
= parser
->memory
;
1139 FT_UInt len
= (FT_UInt
)( limit
- cur
);
1145 /* we allow both a string or a name */
1146 /* for cases like /FontName (foo) def */
1147 if ( token
.type
== T1_TOKEN_TYPE_KEY
)
1149 /* don't include leading `/' */
1153 else if ( token
.type
== T1_TOKEN_TYPE_STRING
)
1155 /* don't include delimiting parentheses */
1156 /* XXX we don't handle <<...>> here */
1157 /* XXX should we convert octal escapes? */
1158 /* if so, what encoding should we use? */
1164 FT_ERROR(( "ps_parser_load_field:"
1165 " expected a name or string\n"
1167 " but found token of type %d instead\n",
1169 error
= FT_THROW( Invalid_File_Format
);
1173 /* for this to work (FT_String**)q must have been */
1174 /* initialized to NULL */
1175 if ( *(FT_String
**)q
!= NULL
)
1177 FT_TRACE0(( "ps_parser_load_field: overwriting field %s\n",
1179 FT_FREE( *(FT_String
**)q
);
1180 *(FT_String
**)q
= NULL
;
1183 if ( FT_ALLOC( string
, len
+ 1 ) )
1186 FT_MEM_COPY( string
, cur
, len
);
1189 *(FT_String
**)q
= string
;
1193 case T1_FIELD_TYPE_BBOX
:
1196 FT_BBox
* bbox
= (FT_BBox
*)q
;
1200 result
= ps_tofixedarray( &cur
, limit
, 4, temp
, 0 );
1204 FT_ERROR(( "ps_parser_load_field:"
1205 " expected four integers in bounding box\n" ));
1206 error
= FT_THROW( Invalid_File_Format
);
1210 bbox
->xMin
= FT_RoundFix( temp
[0] );
1211 bbox
->yMin
= FT_RoundFix( temp
[1] );
1212 bbox
->xMax
= FT_RoundFix( temp
[2] );
1213 bbox
->yMax
= FT_RoundFix( temp
[3] );
1217 case T1_FIELD_TYPE_MM_BBOX
:
1219 FT_Memory memory
= parser
->memory
;
1225 if ( FT_NEW_ARRAY( temp
, max_objects
* 4 ) )
1228 for ( i
= 0; i
< 4; i
++ )
1230 result
= ps_tofixedarray( &cur
, limit
, (FT_Int
)max_objects
,
1231 temp
+ i
* max_objects
, 0 );
1232 if ( result
< 0 || (FT_UInt
)result
< max_objects
)
1234 FT_ERROR(( "ps_parser_load_field:"
1235 " expected %d integer%s in the %s subarray\n"
1237 " of /FontBBox in the /Blend dictionary\n",
1238 max_objects
, max_objects
> 1 ? "s" : "",
1240 : ( i
== 1 ? "second"
1241 : ( i
== 2 ? "third"
1243 error
= FT_THROW( Invalid_File_Format
);
1249 skip_spaces( &cur
, limit
);
1252 for ( i
= 0; i
< max_objects
; i
++ )
1254 FT_BBox
* bbox
= (FT_BBox
*)objects
[i
];
1257 bbox
->xMin
= FT_RoundFix( temp
[i
] );
1258 bbox
->yMin
= FT_RoundFix( temp
[i
+ max_objects
] );
1259 bbox
->xMax
= FT_RoundFix( temp
[i
+ 2 * max_objects
] );
1260 bbox
->yMax
= FT_RoundFix( temp
[i
+ 3 * max_objects
] );
1268 /* an error occurred */
1273 #if 0 /* obsolete -- keep for reference */
1275 *pflags
|= 1L << field
->flag_bit
;
1277 FT_UNUSED( pflags
);
1286 error
= FT_THROW( Invalid_File_Format
);
1291 #define T1_MAX_TABLE_ELEMENTS 32
1294 FT_LOCAL_DEF( FT_Error
)
1295 ps_parser_load_field_table( PS_Parser parser
,
1296 const T1_Field field
,
1298 FT_UInt max_objects
,
1301 T1_TokenRec elements
[T1_MAX_TABLE_ELEMENTS
];
1303 FT_Int num_elements
;
1304 FT_Error error
= FT_Err_Ok
;
1305 FT_Byte
* old_cursor
;
1307 T1_FieldRec fieldrec
= *(T1_Field
)field
;
1310 fieldrec
.type
= T1_FIELD_TYPE_INTEGER
;
1311 if ( field
->type
== T1_FIELD_TYPE_FIXED_ARRAY
||
1312 field
->type
== T1_FIELD_TYPE_BBOX
)
1313 fieldrec
.type
= T1_FIELD_TYPE_FIXED
;
1315 ps_parser_to_token_array( parser
, elements
,
1316 T1_MAX_TABLE_ELEMENTS
, &num_elements
);
1317 if ( num_elements
< 0 )
1319 error
= FT_ERR( Ignore
);
1322 if ( (FT_UInt
)num_elements
> field
->array_max
)
1323 num_elements
= (FT_Int
)field
->array_max
;
1325 old_cursor
= parser
->cursor
;
1326 old_limit
= parser
->limit
;
1328 /* we store the elements count if necessary; */
1329 /* we further assume that `count_offset' can't be zero */
1330 if ( field
->type
!= T1_FIELD_TYPE_BBOX
&& field
->count_offset
!= 0 )
1331 *(FT_Byte
*)( (FT_Byte
*)objects
[0] + field
->count_offset
) =
1332 (FT_Byte
)num_elements
;
1334 /* we now load each element, adjusting the field.offset on each one */
1336 for ( ; num_elements
> 0; num_elements
--, token
++ )
1338 parser
->cursor
= token
->start
;
1339 parser
->limit
= token
->limit
;
1341 error
= ps_parser_load_field( parser
,
1349 fieldrec
.offset
+= fieldrec
.size
;
1352 #if 0 /* obsolete -- keep for reference */
1354 *pflags
|= 1L << field
->flag_bit
;
1356 FT_UNUSED( pflags
);
1359 parser
->cursor
= old_cursor
;
1360 parser
->limit
= old_limit
;
1367 FT_LOCAL_DEF( FT_Long
)
1368 ps_parser_to_int( PS_Parser parser
)
1370 ps_parser_skip_spaces( parser
);
1371 return PS_Conv_ToInt( &parser
->cursor
, parser
->limit
);
1375 /* first character must be `<' if `delimiters' is non-zero */
1377 FT_LOCAL_DEF( FT_Error
)
1378 ps_parser_to_bytes( PS_Parser parser
,
1380 FT_Offset max_bytes
,
1381 FT_ULong
* pnum_bytes
,
1382 FT_Bool delimiters
)
1384 FT_Error error
= FT_Err_Ok
;
1388 ps_parser_skip_spaces( parser
);
1389 cur
= parser
->cursor
;
1391 if ( cur
>= parser
->limit
)
1398 FT_ERROR(( "ps_parser_to_bytes: Missing starting delimiter `<'\n" ));
1399 error
= FT_THROW( Invalid_File_Format
);
1406 *pnum_bytes
= PS_Conv_ASCIIHexDecode( &cur
,
1413 if ( cur
< parser
->limit
&& *cur
!= '>' )
1415 FT_ERROR(( "ps_parser_to_bytes: Missing closing delimiter `>'\n" ));
1416 error
= FT_THROW( Invalid_File_Format
);
1423 parser
->cursor
= cur
;
1430 FT_LOCAL_DEF( FT_Fixed
)
1431 ps_parser_to_fixed( PS_Parser parser
,
1434 ps_parser_skip_spaces( parser
);
1435 return PS_Conv_ToFixed( &parser
->cursor
, parser
->limit
, power_ten
);
1439 FT_LOCAL_DEF( FT_Int
)
1440 ps_parser_to_coord_array( PS_Parser parser
,
1444 ps_parser_skip_spaces( parser
);
1445 return ps_tocoordarray( &parser
->cursor
, parser
->limit
,
1446 max_coords
, coords
);
1450 FT_LOCAL_DEF( FT_Int
)
1451 ps_parser_to_fixed_array( PS_Parser parser
,
1456 ps_parser_skip_spaces( parser
);
1457 return ps_tofixedarray( &parser
->cursor
, parser
->limit
,
1458 max_values
, values
, power_ten
);
1464 FT_LOCAL_DEF( FT_String
* )
1465 T1_ToString( PS_Parser parser
)
1467 return ps_tostring( &parser
->cursor
, parser
->limit
, parser
->memory
);
1471 FT_LOCAL_DEF( FT_Bool
)
1472 T1_ToBool( PS_Parser parser
)
1474 return ps_tobool( &parser
->cursor
, parser
->limit
);
1480 FT_LOCAL_DEF( void )
1481 ps_parser_init( PS_Parser parser
,
1486 parser
->error
= FT_Err_Ok
;
1487 parser
->base
= base
;
1488 parser
->limit
= limit
;
1489 parser
->cursor
= base
;
1490 parser
->memory
= memory
;
1491 parser
->funcs
= ps_parser_funcs
;
1495 FT_LOCAL_DEF( void )
1496 ps_parser_done( PS_Parser parser
)
1498 FT_UNUSED( parser
);
1502 /*************************************************************************/
1503 /*************************************************************************/
1505 /***** T1 BUILDER *****/
1507 /*************************************************************************/
1508 /*************************************************************************/
1510 /*************************************************************************/
1513 /* t1_builder_init */
1516 /* Initializes a given glyph builder. */
1519 /* builder :: A pointer to the glyph builder to initialize. */
1522 /* face :: The current face object. */
1524 /* size :: The current size object. */
1526 /* glyph :: The current glyph object. */
1528 /* hinting :: Whether hinting should be applied. */
1530 FT_LOCAL_DEF( void )
1531 t1_builder_init( T1_Builder builder
,
1537 builder
->parse_state
= T1_Parse_Start
;
1538 builder
->load_points
= 1;
1540 builder
->face
= face
;
1541 builder
->glyph
= glyph
;
1542 builder
->memory
= face
->memory
;
1546 FT_GlyphLoader loader
= glyph
->internal
->loader
;
1549 builder
->loader
= loader
;
1550 builder
->base
= &loader
->base
.outline
;
1551 builder
->current
= &loader
->current
.outline
;
1552 FT_GlyphLoader_Rewind( loader
);
1554 builder
->hints_globals
= size
->internal
;
1555 builder
->hints_funcs
= NULL
;
1558 builder
->hints_funcs
= glyph
->internal
->glyph_hints
;
1564 builder
->left_bearing
.x
= 0;
1565 builder
->left_bearing
.y
= 0;
1566 builder
->advance
.x
= 0;
1567 builder
->advance
.y
= 0;
1569 builder
->funcs
= t1_builder_funcs
;
1573 /*************************************************************************/
1576 /* t1_builder_done */
1579 /* Finalizes a given glyph builder. Its contents can still be used */
1580 /* after the call, but the function saves important information */
1581 /* within the corresponding glyph slot. */
1584 /* builder :: A pointer to the glyph builder to finalize. */
1586 FT_LOCAL_DEF( void )
1587 t1_builder_done( T1_Builder builder
)
1589 FT_GlyphSlot glyph
= builder
->glyph
;
1593 glyph
->outline
= *builder
->base
;
1597 /* check that there is enough space for `count' more points */
1598 FT_LOCAL_DEF( FT_Error
)
1599 t1_builder_check_points( T1_Builder builder
,
1602 return FT_GLYPHLOADER_CHECK_POINTS( builder
->loader
, count
, 0 );
1606 /* add a new point, do not check space */
1607 FT_LOCAL_DEF( void )
1608 t1_builder_add_point( T1_Builder builder
,
1613 FT_Outline
* outline
= builder
->current
;
1616 if ( builder
->load_points
)
1618 FT_Vector
* point
= outline
->points
+ outline
->n_points
;
1619 FT_Byte
* control
= (FT_Byte
*)outline
->tags
+ outline
->n_points
;
1622 point
->x
= FIXED_TO_INT( x
);
1623 point
->y
= FIXED_TO_INT( y
);
1624 *control
= (FT_Byte
)( flag
? FT_CURVE_TAG_ON
: FT_CURVE_TAG_CUBIC
);
1626 outline
->n_points
++;
1630 /* check space for a new on-curve point, then add it */
1631 FT_LOCAL_DEF( FT_Error
)
1632 t1_builder_add_point1( T1_Builder builder
,
1639 error
= t1_builder_check_points( builder
, 1 );
1641 t1_builder_add_point( builder
, x
, y
, 1 );
1647 /* check space for a new contour, then add it */
1648 FT_LOCAL_DEF( FT_Error
)
1649 t1_builder_add_contour( T1_Builder builder
)
1651 FT_Outline
* outline
= builder
->current
;
1655 /* this might happen in invalid fonts */
1658 FT_ERROR(( "t1_builder_add_contour: no outline to add points to\n" ));
1659 return FT_THROW( Invalid_File_Format
);
1662 if ( !builder
->load_points
)
1664 outline
->n_contours
++;
1668 error
= FT_GLYPHLOADER_CHECK_POINTS( builder
->loader
, 0, 1 );
1671 if ( outline
->n_contours
> 0 )
1672 outline
->contours
[outline
->n_contours
- 1] =
1673 (short)( outline
->n_points
- 1 );
1675 outline
->n_contours
++;
1682 /* if a path was begun, add its first on-curve point */
1683 FT_LOCAL_DEF( FT_Error
)
1684 t1_builder_start_point( T1_Builder builder
,
1688 FT_Error error
= FT_ERR( Invalid_File_Format
);
1691 /* test whether we are building a new contour */
1693 if ( builder
->parse_state
== T1_Parse_Have_Path
)
1697 builder
->parse_state
= T1_Parse_Have_Path
;
1698 error
= t1_builder_add_contour( builder
);
1700 error
= t1_builder_add_point1( builder
, x
, y
);
1707 /* close the current contour */
1708 FT_LOCAL_DEF( void )
1709 t1_builder_close_contour( T1_Builder builder
)
1711 FT_Outline
* outline
= builder
->current
;
1718 first
= outline
->n_contours
<= 1
1719 ? 0 : outline
->contours
[outline
->n_contours
- 2] + 1;
1721 /* We must not include the last point in the path if it */
1722 /* is located on the first point. */
1723 if ( outline
->n_points
> 1 )
1725 FT_Vector
* p1
= outline
->points
+ first
;
1726 FT_Vector
* p2
= outline
->points
+ outline
->n_points
- 1;
1727 FT_Byte
* control
= (FT_Byte
*)outline
->tags
+ outline
->n_points
- 1;
1730 /* `delete' last point only if it coincides with the first */
1731 /* point and it is not a control point (which can happen). */
1732 if ( p1
->x
== p2
->x
&& p1
->y
== p2
->y
)
1733 if ( *control
== FT_CURVE_TAG_ON
)
1734 outline
->n_points
--;
1737 if ( outline
->n_contours
> 0 )
1739 /* Don't add contours only consisting of one point, i.e., */
1740 /* check whether the first and the last point is the same. */
1741 if ( first
== outline
->n_points
- 1 )
1743 outline
->n_contours
--;
1744 outline
->n_points
--;
1747 outline
->contours
[outline
->n_contours
- 1] =
1748 (short)( outline
->n_points
- 1 );
1753 /*************************************************************************/
1754 /*************************************************************************/
1758 /*************************************************************************/
1759 /*************************************************************************/
1761 FT_LOCAL_DEF( void )
1762 t1_decrypt( FT_Byte
* buffer
,
1766 PS_Conv_EexecDecode( &buffer
,