1 /***************************************************************************/
5 /* Auxiliary functions for PostScript fonts (body). */
7 /* Copyright 1996-2012 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 PSaux_Err_Invalid_Argument;
181 FT_ERROR(( "ps_table_add: invalid length\n" ));
182 return PSaux_Err_Invalid_Argument;
185 /* grow the base block if needed */
186 if ( table->cursor + length > table->capacity )
189 FT_Offset new_size = table->capacity;
190 FT_PtrDist in_offset;
193 in_offset = (FT_Byte*)object - table->block;
194 if ( in_offset < 0 || (FT_Offset)in_offset >= table->capacity )
197 while ( new_size < table->cursor + length )
199 /* increase size by 25% and round up to the nearest multiple
201 new_size += ( new_size >> 2 ) + 1;
202 new_size = FT_PAD_CEIL( new_size, 1024 );
205 error = reallocate_t1_table( table, new_size );
209 if ( in_offset >= 0 )
210 object = table->block + in_offset;
213 /* add the object to the base block and adjust offset */
214 table->elements[idx] = table->block + table->cursor;
215 table->lengths [idx] = length;
216 FT_MEM_COPY( table->block + table->cursor, object, length );
218 table->cursor += length;
223 /*************************************************************************/
229 /* Finalizes a PS_TableRec (i.e., reallocate it to its current */
233 /* table :: The target table. */
236 /* This function does NOT release the heap's memory block. It is up */
237 /* to the caller to clean it, or reference it in its own structures. */
240 ps_table_done( PS_Table table )
242 FT_Memory memory = table->memory;
244 FT_Byte* old_base = table->block;
247 /* should never fail, because rec.cursor <= rec.size */
251 if ( FT_ALLOC( table->block, table->cursor ) )
253 FT_MEM_COPY( table->block, old_base, table->cursor );
254 shift_elements( table, old_base );
256 table->capacity = table->cursor;
264 ps_table_release( PS_Table table )
266 FT_Memory memory = table->memory;
269 if ( (FT_ULong)table->init == 0xDEADBEEFUL )
271 FT_FREE( table->block );
272 FT_FREE( table->elements );
273 FT_FREE( table->lengths );
279 /*************************************************************************/
280 /*************************************************************************/
282 /***** T1 PARSER *****/
284 /*************************************************************************/
285 /*************************************************************************/
288 /* first character must be already part of the comment */
291 skip_comment( FT_Byte* *acur,
294 FT_Byte* cur = *acur;
297 while ( cur < limit )
299 if ( IS_PS_NEWLINE( *cur ) )
309 skip_spaces( FT_Byte* *acur,
312 FT_Byte* cur = *acur;
315 while ( cur < limit )
317 if ( !IS_PS_SPACE( *cur ) )
320 /* According to the PLRM, a comment is equal to a space. */
321 skip_comment( &cur, limit );
332 #define IS_OCTAL_DIGIT( c ) ( '0' <= (c) && (c) <= '7' )
335 /* first character must be `('; */
336 /* *acur is positioned at the character after the closing `)' */
339 skip_literal_string( FT_Byte* *acur,
342 FT_Byte* cur = *acur;
344 FT_Error error = PSaux_Err_Invalid_File_Format;
348 while ( cur < limit )
357 /* Red Book 3rd ed., section `Literal Text Strings', p. 29: */
358 /* A backslash can introduce three different types */
359 /* of escape sequences: */
360 /* - a special escaped char like \r, \n, etc. */
361 /* - a one-, two-, or three-digit octal number */
362 /* - none of the above in which case the backslash is ignored */
365 /* error (or to be ignored?) */
370 /* skip `special' escape */
383 /* skip octal escape or ignore backslash */
384 for ( i = 0; i < 3 && cur < limit; ++i )
386 if ( !IS_OCTAL_DIGIT( *cur ) )
400 error = PSaux_Err_Ok;
412 /* first character must be `<' */
415 skip_string( FT_Byte* *acur,
418 FT_Byte* cur = *acur;
419 FT_Error err = PSaux_Err_Ok;
422 while ( ++cur < limit )
424 /* All whitespace characters are ignored. */
425 skip_spaces( &cur, limit );
429 if ( !IS_PS_XDIGIT( *cur ) )
433 if ( cur < limit && *cur != '>' )
435 FT_ERROR(( "skip_string: missing closing delimiter `>'\n" ));
436 err = PSaux_Err_Invalid_File_Format;
446 /* first character must be the opening brace that */
447 /* starts the procedure */
449 /* NB: [ and ] need not match: */
450 /* `/foo {[} def' is a valid PostScript fragment, */
451 /* even within a Type1 font */
454 skip_procedure( FT_Byte* *acur,
459 FT_Error error = PSaux_Err_Ok;
462 FT_ASSERT( **acur == '{' );
464 for ( cur = *acur; cur < limit && error == PSaux_Err_Ok; ++cur )
482 error = skip_literal_string( &cur, limit );
486 error = skip_string( &cur, limit );
490 skip_comment( &cur, limit );
497 error = PSaux_Err_Invalid_File_Format;
505 /***********************************************************************/
507 /* All exported parsing routines handle leading whitespace and stop at */
508 /* the first character which isn't part of the just handled token. */
510 /***********************************************************************/
514 ps_parser_skip_PS_token( PS_Parser parser )
516 /* Note: PostScript allows any non-delimiting, non-whitespace */
517 /* character in a name (PS Ref Manual, 3rd ed, p31). */
518 /* PostScript delimiters are (, ), <, >, [, ], {, }, /, and %. */
520 FT_Byte* cur = parser->cursor;
521 FT_Byte* limit = parser->limit;
522 FT_Error error = PSaux_Err_Ok;
525 skip_spaces( &cur, limit ); /* this also skips comments */
529 /* self-delimiting, single-character tokens */
530 if ( *cur == '[' || *cur == ']' )
536 /* skip balanced expressions (procedures and strings) */
538 if ( *cur == '{' ) /* {...} */
540 error = skip_procedure( &cur, limit );
544 if ( *cur == '(' ) /* (...) */
546 error = skip_literal_string( &cur, limit );
550 if ( *cur == '<' ) /* <...> */
552 if ( cur + 1 < limit && *(cur + 1) == '<' ) /* << */
558 error = skip_string( &cur, limit );
566 if ( cur >= limit || *cur != '>' ) /* >> */
568 FT_ERROR(( "ps_parser_skip_PS_token:"
569 " unexpected closing delimiter `>'\n" ));
570 error = PSaux_Err_Invalid_File_Format;
581 while ( cur < limit )
583 /* *cur might be invalid (e.g., ')' or '}'), but this */
584 /* is handled by the test `cur == parser->cursor' below */
585 if ( IS_PS_DELIM( *cur ) )
592 if ( cur < limit && cur == parser->cursor )
594 FT_ERROR(( "ps_parser_skip_PS_token:"
595 " current token is `%c' which is self-delimiting\n"
597 " but invalid at this point\n",
600 error = PSaux_Err_Invalid_File_Format;
603 parser->error = error;
604 parser->cursor = cur;
609 ps_parser_skip_spaces( PS_Parser parser )
611 skip_spaces( &parser->cursor, parser->limit );
615 /* `token' here means either something between balanced delimiters */
616 /* or the next token; the delimiters are not removed. */
619 ps_parser_to_token( PS_Parser parser,
627 token->type = T1_TOKEN_TYPE_NONE;
631 /* first of all, skip leading whitespace */
632 ps_parser_skip_spaces( parser );
634 cur = parser->cursor;
635 limit = parser->limit;
642 /************* check for literal string *****************/
644 token->type = T1_TOKEN_TYPE_STRING;
647 if ( skip_literal_string( &cur, limit ) == PSaux_Err_Ok )
651 /************* check for programs/array *****************/
653 token->type = T1_TOKEN_TYPE_ARRAY;
656 if ( skip_procedure( &cur, limit ) == PSaux_Err_Ok )
660 /************* check for table/array ********************/
661 /* XXX: in theory we should also look for "<<" */
662 /* since this is semantically equivalent to "["; */
663 /* in practice it doesn't matter (?) */
665 token->type = T1_TOKEN_TYPE_ARRAY;
667 token->start = cur++;
669 /* we need this to catch `[ ]' */
670 parser->cursor = cur;
671 ps_parser_skip_spaces( parser );
672 cur = parser->cursor;
674 while ( cur < limit && !parser->error )
676 /* XXX: this is wrong because it does not */
677 /* skip comments, procedures, and strings */
680 else if ( *cur == ']' )
685 token->limit = ++cur;
690 parser->cursor = cur;
691 ps_parser_skip_PS_token( parser );
692 /* we need this to catch `[XXX ]' */
693 ps_parser_skip_spaces ( parser );
694 cur = parser->cursor;
698 /* ************ otherwise, it is any token **************/
701 token->type = ( *cur == '/' ? T1_TOKEN_TYPE_KEY : T1_TOKEN_TYPE_ANY );
702 ps_parser_skip_PS_token( parser );
703 cur = parser->cursor;
704 if ( !parser->error )
711 token->type = T1_TOKEN_TYPE_NONE;
714 parser->cursor = cur;
718 /* NB: `tokens' can be NULL if we only want to count */
719 /* the number of array elements */
722 ps_parser_to_token_array( PS_Parser parser,
725 FT_Int* pnum_tokens )
732 /* this also handles leading whitespace */
733 ps_parser_to_token( parser, &master );
735 if ( master.type == T1_TOKEN_TYPE_ARRAY )
737 FT_Byte* old_cursor = parser->cursor;
738 FT_Byte* old_limit = parser->limit;
739 T1_Token cur = tokens;
740 T1_Token limit = cur + max_tokens;
743 /* don't include outermost delimiters */
744 parser->cursor = master.start + 1;
745 parser->limit = master.limit - 1;
747 while ( parser->cursor < parser->limit )
752 ps_parser_to_token( parser, &token );
756 if ( tokens != NULL && cur < limit )
762 *pnum_tokens = (FT_Int)( cur - tokens );
764 parser->cursor = old_cursor;
765 parser->limit = old_limit;
770 /* first character must be a delimiter or a part of a number */
771 /* NB: `coords' can be NULL if we just want to skip the */
772 /* array; in this case we ignore `max_coords' */
775 ps_tocoordarray( FT_Byte* *acur,
780 FT_Byte* cur = *acur;
788 /* check for the beginning of an array; otherwise, only one number */
801 /* now, read the coordinates */
802 while ( cur < limit )
808 /* skip whitespace in front of data */
809 skip_spaces( &cur, limit );
821 if ( coords != NULL && count >= max_coords )
824 /* call PS_Conv_ToFixed() even if coords == NULL */
825 /* to properly parse number at `cur' */
826 *( coords != NULL ? &coords[count] : &dummy ) =
827 (FT_Short)( PS_Conv_ToFixed( &cur, limit, 0 ) >> 16 );
829 if ( old_cur == cur )
847 /* first character must be a delimiter or a part of a number */
848 /* NB: `values' can be NULL if we just want to skip the */
849 /* array; in this case we ignore `max_values' */
852 ps_tofixedarray( FT_Byte* *acur,
858 FT_Byte* cur = *acur;
866 /* Check for the beginning of an array. Otherwise, only one number */
879 /* now, read the values */
880 while ( cur < limit )
886 /* skip whitespace in front of data */
887 skip_spaces( &cur, limit );
899 if ( values != NULL && count >= max_values )
902 /* call PS_Conv_ToFixed() even if coords == NULL */
903 /* to properly parse number at `cur' */
904 *( values != NULL ? &values[count] : &dummy ) =
905 PS_Conv_ToFixed( &cur, limit, power_ten );
907 if ( old_cur == cur )
928 ps_tostring( FT_Byte** cursor,
932 FT_Byte* cur = *cursor;
939 /* XXX: some stupid fonts have a `Notice' or `Copyright' string */
940 /* that simply doesn't begin with an opening parenthesis, even */
941 /* though they have a closing one! E.g. "amuncial.pfb" */
943 /* We must deal with these ill-fated cases there. Note that */
944 /* these fonts didn't work with the old Type 1 driver as the */
945 /* notice/copyright was not recognized as a valid string token */
946 /* and made the old token parser commit errors. */
948 while ( cur < limit && ( *cur == ' ' || *cur == '\t' ) )
950 if ( cur + 1 >= limit )
954 cur++; /* skip the opening parenthesis, if there is one */
959 /* then, count its length */
960 for ( ; cur < limit; cur++ )
965 else if ( *cur == ')' )
974 if ( cur >= limit || FT_ALLOC( result, len + 1 ) )
977 /* now copy the string */
978 FT_MEM_COPY( result, *cursor, len );
988 ps_tobool( FT_Byte* *acur,
991 FT_Byte* cur = *acur;
995 /* return 1 if we find `true', 0 otherwise */
996 if ( cur + 3 < limit &&
1005 else if ( cur + 4 < limit &&
1021 /* load a simple field (i.e. non-table) into the current list of objects */
1023 FT_LOCAL_DEF( FT_Error )
1024 ps_parser_load_field( PS_Parser parser,
1025 const T1_Field field,
1027 FT_UInt max_objects,
1038 /* this also skips leading whitespace */
1039 ps_parser_to_token( parser, &token );
1046 limit = token.limit;
1048 /* we must detect arrays in /FontBBox */
1049 if ( field->type == T1_FIELD_TYPE_BBOX )
1052 FT_Byte* old_cur = parser->cursor;
1053 FT_Byte* old_limit = parser->limit;
1056 /* don't include delimiters */
1057 parser->cursor = token.start + 1;
1058 parser->limit = token.limit - 1;
1060 ps_parser_to_token( parser, &token2 );
1061 parser->cursor = old_cur;
1062 parser->limit = old_limit;
1064 if ( token2.type == T1_TOKEN_TYPE_ARRAY )
1067 else if ( token.type == T1_TOKEN_TYPE_ARRAY )
1070 /* if this is an array and we have no blend, an error occurs */
1071 if ( max_objects == 0 )
1074 count = max_objects;
1077 /* don't include delimiters */
1082 for ( ; count > 0; count--, idx++ )
1084 FT_Byte* q = (FT_Byte*)objects[idx] + field->offset;
1089 skip_spaces( &cur, limit );
1091 switch ( field->type )
1093 case T1_FIELD_TYPE_BOOL:
1094 val = ps_tobool( &cur, limit );
1097 case T1_FIELD_TYPE_FIXED:
1098 val = PS_Conv_ToFixed( &cur, limit, 0 );
1101 case T1_FIELD_TYPE_FIXED_1000:
1102 val = PS_Conv_ToFixed( &cur, limit, 3 );
1105 case T1_FIELD_TYPE_INTEGER:
1106 val = PS_Conv_ToInt( &cur, limit );
1110 switch ( field->size )
1112 case (8 / FT_CHAR_BIT):
1113 *(FT_Byte*)q = (FT_Byte)val;
1116 case (16 / FT_CHAR_BIT):
1117 *(FT_UShort*)q = (FT_UShort)val;
1120 case (32 / FT_CHAR_BIT):
1121 *(FT_UInt32*)q = (FT_UInt32)val;
1124 default: /* for 64-bit systems */
1129 case T1_FIELD_TYPE_STRING:
1130 case T1_FIELD_TYPE_KEY:
1132 FT_Memory memory = parser->memory;
1133 FT_UInt len = (FT_UInt)( limit - cur );
1139 /* we allow both a string or a name */
1140 /* for cases like /FontName (foo) def */
1141 if ( token.type == T1_TOKEN_TYPE_KEY )
1143 /* don't include leading `/' */
1147 else if ( token.type == T1_TOKEN_TYPE_STRING )
1149 /* don't include delimiting parentheses */
1150 /* XXX we don't handle <<...>> here */
1151 /* XXX should we convert octal escapes? */
1152 /* if so, what encoding should we use? */
1158 FT_ERROR(( "ps_parser_load_field:"
1159 " expected a name or string\n"
1161 " but found token of type %d instead\n",
1163 error = PSaux_Err_Invalid_File_Format;
1167 /* for this to work (FT_String**)q must have been */
1168 /* initialized to NULL */
1169 if ( *(FT_String**)q != NULL )
1171 FT_TRACE0(( "ps_parser_load_field: overwriting field %s\n",
1173 FT_FREE( *(FT_String**)q );
1174 *(FT_String**)q = NULL;
1177 if ( FT_ALLOC( string, len + 1 ) )
1180 FT_MEM_COPY( string, cur, len );
1183 *(FT_String**)q = string;
1187 case T1_FIELD_TYPE_BBOX:
1190 FT_BBox* bbox = (FT_BBox*)q;
1194 result = ps_tofixedarray( &cur, limit, 4, temp, 0 );
1198 FT_ERROR(( "ps_parser_load_field:"
1199 " expected four integers in bounding box\n" ));
1200 error = PSaux_Err_Invalid_File_Format;
1204 bbox->xMin = FT_RoundFix( temp[0] );
1205 bbox->yMin = FT_RoundFix( temp[1] );
1206 bbox->xMax = FT_RoundFix( temp[2] );
1207 bbox->yMax = FT_RoundFix( temp[3] );
1212 /* an error occurred */
1217 #if 0 /* obsolete -- keep for reference */
1219 *pflags |= 1L << field->flag_bit;
1221 FT_UNUSED( pflags );
1224 error = PSaux_Err_Ok;
1230 error = PSaux_Err_Invalid_File_Format;
1235 #define T1_MAX_TABLE_ELEMENTS 32
1238 FT_LOCAL_DEF( FT_Error )
1239 ps_parser_load_field_table( PS_Parser parser,
1240 const T1_Field field,
1242 FT_UInt max_objects,
1245 T1_TokenRec elements[T1_MAX_TABLE_ELEMENTS];
1247 FT_Int num_elements;
1248 FT_Error error = PSaux_Err_Ok;
1249 FT_Byte* old_cursor;
1251 T1_FieldRec fieldrec = *(T1_Field)field;
1254 fieldrec.type = T1_FIELD_TYPE_INTEGER;
1255 if ( field->type == T1_FIELD_TYPE_FIXED_ARRAY ||
1256 field->type == T1_FIELD_TYPE_BBOX )
1257 fieldrec.type = T1_FIELD_TYPE_FIXED;
1259 ps_parser_to_token_array( parser, elements,
1260 T1_MAX_TABLE_ELEMENTS, &num_elements );
1261 if ( num_elements < 0 )
1263 error = PSaux_Err_Ignore;
1266 if ( (FT_UInt)num_elements > field->array_max )
1267 num_elements = field->array_max;
1269 old_cursor = parser->cursor;
1270 old_limit = parser->limit;
1272 /* we store the elements count if necessary; */
1273 /* we further assume that `count_offset' can't be zero */
1274 if ( field->type != T1_FIELD_TYPE_BBOX && field->count_offset != 0 )
1275 *(FT_Byte*)( (FT_Byte*)objects[0] + field->count_offset ) =
1276 (FT_Byte)num_elements;
1278 /* we now load each element, adjusting the field.offset on each one */
1280 for ( ; num_elements > 0; num_elements--, token++ )
1282 parser->cursor = token->start;
1283 parser->limit = token->limit;
1284 ps_parser_load_field( parser, &fieldrec, objects, max_objects, 0 );
1285 fieldrec.offset += fieldrec.size;
1288 #if 0 /* obsolete -- keep for reference */
1290 *pflags |= 1L << field->flag_bit;
1292 FT_UNUSED( pflags );
1295 parser->cursor = old_cursor;
1296 parser->limit = old_limit;
1303 FT_LOCAL_DEF( FT_Long )
1304 ps_parser_to_int( PS_Parser parser )
1306 ps_parser_skip_spaces( parser );
1307 return PS_Conv_ToInt( &parser->cursor, parser->limit );
1311 /* first character must be `<' if `delimiters' is non-zero */
1313 FT_LOCAL_DEF( FT_Error )
1314 ps_parser_to_bytes( PS_Parser parser,
1316 FT_Offset max_bytes,
1317 FT_Long* pnum_bytes,
1318 FT_Bool delimiters )
1320 FT_Error error = PSaux_Err_Ok;
1324 ps_parser_skip_spaces( parser );
1325 cur = parser->cursor;
1327 if ( cur >= parser->limit )
1334 FT_ERROR(( "ps_parser_to_bytes: Missing starting delimiter `<'\n" ));
1335 error = PSaux_Err_Invalid_File_Format;
1342 *pnum_bytes = PS_Conv_ASCIIHexDecode( &cur,
1349 if ( cur < parser->limit && *cur != '>' )
1351 FT_ERROR(( "ps_parser_to_bytes: Missing closing delimiter `>'\n" ));
1352 error = PSaux_Err_Invalid_File_Format;
1359 parser->cursor = cur;
1366 FT_LOCAL_DEF( FT_Fixed )
1367 ps_parser_to_fixed( PS_Parser parser,
1370 ps_parser_skip_spaces( parser );
1371 return PS_Conv_ToFixed( &parser->cursor, parser->limit, power_ten );
1375 FT_LOCAL_DEF( FT_Int )
1376 ps_parser_to_coord_array( PS_Parser parser,
1380 ps_parser_skip_spaces( parser );
1381 return ps_tocoordarray( &parser->cursor, parser->limit,
1382 max_coords, coords );
1386 FT_LOCAL_DEF( FT_Int )
1387 ps_parser_to_fixed_array( PS_Parser parser,
1392 ps_parser_skip_spaces( parser );
1393 return ps_tofixedarray( &parser->cursor, parser->limit,
1394 max_values, values, power_ten );
1400 FT_LOCAL_DEF( FT_String* )
1401 T1_ToString( PS_Parser parser )
1403 return ps_tostring( &parser->cursor, parser->limit, parser->memory );
1407 FT_LOCAL_DEF( FT_Bool )
1408 T1_ToBool( PS_Parser parser )
1410 return ps_tobool( &parser->cursor, parser->limit );
1416 FT_LOCAL_DEF( void )
1417 ps_parser_init( PS_Parser parser,
1422 parser->error = PSaux_Err_Ok;
1423 parser->base = base;
1424 parser->limit = limit;
1425 parser->cursor = base;
1426 parser->memory = memory;
1427 parser->funcs = ps_parser_funcs;
1431 FT_LOCAL_DEF( void )
1432 ps_parser_done( PS_Parser parser )
1434 FT_UNUSED( parser );
1438 /*************************************************************************/
1439 /*************************************************************************/
1441 /***** T1 BUILDER *****/
1443 /*************************************************************************/
1444 /*************************************************************************/
1446 /*************************************************************************/
1449 /* t1_builder_init */
1452 /* Initializes a given glyph builder. */
1455 /* builder :: A pointer to the glyph builder to initialize. */
1458 /* face :: The current face object. */
1460 /* size :: The current size object. */
1462 /* glyph :: The current glyph object. */
1464 /* hinting :: Whether hinting should be applied. */
1466 FT_LOCAL_DEF( void )
1467 t1_builder_init( T1_Builder builder,
1473 builder->parse_state = T1_Parse_Start;
1474 builder->load_points = 1;
1476 builder->face = face;
1477 builder->glyph = glyph;
1478 builder->memory = face->memory;
1482 FT_GlyphLoader loader = glyph->internal->loader;
1485 builder->loader = loader;
1486 builder->base = &loader->base.outline;
1487 builder->current = &loader->current.outline;
1488 FT_GlyphLoader_Rewind( loader );
1490 builder->hints_globals = size->internal;
1491 builder->hints_funcs = 0;
1494 builder->hints_funcs = glyph->internal->glyph_hints;
1500 builder->left_bearing.x = 0;
1501 builder->left_bearing.y = 0;
1502 builder->advance.x = 0;
1503 builder->advance.y = 0;
1505 builder->funcs = t1_builder_funcs;
1509 /*************************************************************************/
1512 /* t1_builder_done */
1515 /* Finalizes a given glyph builder. Its contents can still be used */
1516 /* after the call, but the function saves important information */
1517 /* within the corresponding glyph slot. */
1520 /* builder :: A pointer to the glyph builder to finalize. */
1522 FT_LOCAL_DEF( void )
1523 t1_builder_done( T1_Builder builder )
1525 FT_GlyphSlot glyph = builder->glyph;
1529 glyph->outline = *builder->base;
1533 /* check that there is enough space for `count' more points */
1534 FT_LOCAL_DEF( FT_Error )
1535 t1_builder_check_points( T1_Builder builder,
1538 return FT_GLYPHLOADER_CHECK_POINTS( builder->loader, count, 0 );
1542 /* add a new point, do not check space */
1543 FT_LOCAL_DEF( void )
1544 t1_builder_add_point( T1_Builder builder,
1549 FT_Outline* outline = builder->current;
1552 if ( builder->load_points )
1554 FT_Vector* point = outline->points + outline->n_points;
1555 FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points;
1558 point->x = FIXED_TO_INT( x );
1559 point->y = FIXED_TO_INT( y );
1560 *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC );
1562 outline->n_points++;
1566 /* check space for a new on-curve point, then add it */
1567 FT_LOCAL_DEF( FT_Error )
1568 t1_builder_add_point1( T1_Builder builder,
1575 error = t1_builder_check_points( builder, 1 );
1577 t1_builder_add_point( builder, x, y, 1 );
1583 /* check space for a new contour, then add it */
1584 FT_LOCAL_DEF( FT_Error )
1585 t1_builder_add_contour( T1_Builder builder )
1587 FT_Outline* outline = builder->current;
1591 /* this might happen in invalid fonts */
1594 FT_ERROR(( "t1_builder_add_contour: no outline to add points to\n" ));
1595 return PSaux_Err_Invalid_File_Format;
1598 if ( !builder->load_points )
1600 outline->n_contours++;
1601 return PSaux_Err_Ok;
1604 error = FT_GLYPHLOADER_CHECK_POINTS( builder->loader, 0, 1 );
1607 if ( outline->n_contours > 0 )
1608 outline->contours[outline->n_contours - 1] =
1609 (short)( outline->n_points - 1 );
1611 outline->n_contours++;
1618 /* if a path was begun, add its first on-curve point */
1619 FT_LOCAL_DEF( FT_Error )
1620 t1_builder_start_point( T1_Builder builder,
1624 FT_Error error = PSaux_Err_Invalid_File_Format;
1627 /* test whether we are building a new contour */
1629 if ( builder->parse_state == T1_Parse_Have_Path )
1630 error = PSaux_Err_Ok;
1633 builder->parse_state = T1_Parse_Have_Path;
1634 error = t1_builder_add_contour( builder );
1636 error = t1_builder_add_point1( builder, x, y );
1643 /* close the current contour */
1644 FT_LOCAL_DEF( void )
1645 t1_builder_close_contour( T1_Builder builder )
1647 FT_Outline* outline = builder->current;
1654 first = outline->n_contours <= 1
1655 ? 0 : outline->contours[outline->n_contours - 2] + 1;
1657 /* We must not include the last point in the path if it */
1658 /* is located on the first point. */
1659 if ( outline->n_points > 1 )
1661 FT_Vector* p1 = outline->points + first;
1662 FT_Vector* p2 = outline->points + outline->n_points - 1;
1663 FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points - 1;
1666 /* `delete' last point only if it coincides with the first */
1667 /* point and it is not a control point (which can happen). */
1668 if ( p1->x == p2->x && p1->y == p2->y )
1669 if ( *control == FT_CURVE_TAG_ON )
1670 outline->n_points--;
1673 if ( outline->n_contours > 0 )
1675 /* Don't add contours only consisting of one point, i.e., */
1676 /* check whether the first and the last point is the same. */
1677 if ( first == outline->n_points - 1 )
1679 outline->n_contours--;
1680 outline->n_points--;
1683 outline->contours[outline->n_contours - 1] =
1684 (short)( outline->n_points - 1 );
1689 /*************************************************************************/
1690 /*************************************************************************/
1694 /*************************************************************************/
1695 /*************************************************************************/
1697 FT_LOCAL_DEF( void )
1698 t1_decrypt( FT_Byte* buffer,
1702 PS_Conv_EexecDecode( &buffer,