1
/***************************************************************************/
5
/* Auxiliary functions for PostScript fonts (body). */
7
/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 by */
8
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
10
/* This file is part of the FreeType project, and may only be used, */
11
/* modified, and distributed under the terms of the FreeType project */
12
/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
13
/* this file you indicate that you have read the license and */
14
/* understand and accept it fully. */
16
/***************************************************************************/
20
#include FT_INTERNAL_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;
180
FT_ERROR(( "ps_table_add: invalid length\n" ));
181
return PSaux_Err_Invalid_Argument;
184
/* grow the base block if needed */
185
if ( table->cursor + length > table->capacity )
188
FT_Offset new_size = table->capacity;
192
in_offset = (FT_Long)((FT_Byte*)object - table->block);
193
if ( (FT_ULong)in_offset >= table->capacity )
196
while ( new_size < table->cursor + length )
198
/* increase size by 25% and round up to the nearest multiple
200
new_size += ( new_size >> 2 ) + 1;
201
new_size = FT_PAD_CEIL( new_size, 1024 );
204
error = reallocate_t1_table( table, new_size );
208
if ( in_offset >= 0 )
209
object = table->block + in_offset;
212
/* add the object to the base block and adjust offset */
213
table->elements[idx] = table->block + table->cursor;
214
table->lengths [idx] = length;
215
FT_MEM_COPY( table->block + table->cursor, object, length );
217
table->cursor += length;
222
/*************************************************************************/
228
/* Finalizes a PS_TableRec (i.e., reallocate it to its current */
232
/* table :: The target table. */
235
/* This function does NOT release the heap's memory block. It is up */
236
/* to the caller to clean it, or reference it in its own structures. */
239
ps_table_done( PS_Table table )
241
FT_Memory memory = table->memory;
243
FT_Byte* old_base = table->block;
246
/* should never fail, because rec.cursor <= rec.size */
250
if ( FT_ALLOC( table->block, table->cursor ) )
252
FT_MEM_COPY( table->block, old_base, table->cursor );
253
shift_elements( table, old_base );
255
table->capacity = table->cursor;
263
ps_table_release( PS_Table table )
265
FT_Memory memory = table->memory;
268
if ( (FT_ULong)table->init == 0xDEADBEEFUL )
270
FT_FREE( table->block );
271
FT_FREE( table->elements );
272
FT_FREE( table->lengths );
278
/*************************************************************************/
279
/*************************************************************************/
281
/***** T1 PARSER *****/
283
/*************************************************************************/
284
/*************************************************************************/
287
/* first character must be already part of the comment */
290
skip_comment( FT_Byte* *acur,
293
FT_Byte* cur = *acur;
296
while ( cur < limit )
298
if ( IS_PS_NEWLINE( *cur ) )
308
skip_spaces( FT_Byte* *acur,
311
FT_Byte* cur = *acur;
314
while ( cur < limit )
316
if ( !IS_PS_SPACE( *cur ) )
319
/* According to the PLRM, a comment is equal to a space. */
320
skip_comment( &cur, limit );
331
#define IS_OCTAL_DIGIT( c ) ( '0' <= (c) && (c) <= '7' )
334
/* first character must be `('; */
335
/* *acur is positioned at the character after the closing `)' */
338
skip_literal_string( FT_Byte* *acur,
341
FT_Byte* cur = *acur;
343
FT_Error error = PSaux_Err_Invalid_File_Format;
347
while ( cur < limit )
356
/* Red Book 3rd ed., section `Literal Text Strings', p. 29: */
357
/* A backslash can introduce three different types */
358
/* of escape sequences: */
359
/* - a special escaped char like \r, \n, etc. */
360
/* - a one-, two-, or three-digit octal number */
361
/* - none of the above in which case the backslash is ignored */
364
/* error (or to be ignored?) */
369
/* skip `special' escape */
382
/* skip octal escape or ignore backslash */
383
for ( i = 0; i < 3 && cur < limit; ++i )
385
if ( !IS_OCTAL_DIGIT( *cur ) )
399
error = PSaux_Err_Ok;
411
/* first character must be `<' */
414
skip_string( FT_Byte* *acur,
417
FT_Byte* cur = *acur;
418
FT_Error err = PSaux_Err_Ok;
421
while ( ++cur < limit )
423
/* All whitespace characters are ignored. */
424
skip_spaces( &cur, limit );
428
if ( !IS_PS_XDIGIT( *cur ) )
432
if ( cur < limit && *cur != '>' )
434
FT_ERROR(( "skip_string: missing closing delimiter `>'\n" ));
435
err = PSaux_Err_Invalid_File_Format;
445
/* first character must be the opening brace that */
446
/* starts the procedure */
448
/* NB: [ and ] need not match: */
449
/* `/foo {[} def' is a valid PostScript fragment, */
450
/* even within a Type1 font */
453
skip_procedure( FT_Byte* *acur,
458
FT_Error error = PSaux_Err_Ok;
461
FT_ASSERT( **acur == '{' );
463
for ( cur = *acur; cur < limit && error == PSaux_Err_Ok; ++cur )
481
error = skip_literal_string( &cur, limit );
485
error = skip_string( &cur, limit );
489
skip_comment( &cur, limit );
496
error = PSaux_Err_Invalid_File_Format;
504
/***********************************************************************/
506
/* All exported parsing routines handle leading whitespace and stop at */
507
/* the first character which isn't part of the just handled token. */
509
/***********************************************************************/
513
ps_parser_skip_PS_token( PS_Parser parser )
515
/* Note: PostScript allows any non-delimiting, non-whitespace */
516
/* character in a name (PS Ref Manual, 3rd ed, p31). */
517
/* PostScript delimiters are (, ), <, >, [, ], {, }, /, and %. */
519
FT_Byte* cur = parser->cursor;
520
FT_Byte* limit = parser->limit;
521
FT_Error error = PSaux_Err_Ok;
524
skip_spaces( &cur, limit ); /* this also skips comments */
528
/* self-delimiting, single-character tokens */
529
if ( *cur == '[' || *cur == ']' )
535
/* skip balanced expressions (procedures and strings) */
537
if ( *cur == '{' ) /* {...} */
539
error = skip_procedure( &cur, limit );
543
if ( *cur == '(' ) /* (...) */
545
error = skip_literal_string( &cur, limit );
549
if ( *cur == '<' ) /* <...> */
551
if ( cur + 1 < limit && *(cur + 1) == '<' ) /* << */
557
error = skip_string( &cur, limit );
565
if ( cur >= limit || *cur != '>' ) /* >> */
567
FT_ERROR(( "ps_parser_skip_PS_token: "
568
"unexpected closing delimiter `>'\n" ));
569
error = PSaux_Err_Invalid_File_Format;
580
while ( cur < limit )
582
/* *cur might be invalid (e.g., ')' or '}'), but this */
583
/* is handled by the test `cur == parser->cursor' below */
584
if ( IS_PS_DELIM( *cur ) )
591
if ( cur == parser->cursor )
593
FT_ERROR(( "ps_parser_skip_PS_token: "
594
"current token is `%c', which is self-delimiting "
595
"but invalid at this point\n",
598
error = PSaux_Err_Invalid_File_Format;
601
parser->error = error;
602
parser->cursor = cur;
607
ps_parser_skip_spaces( PS_Parser parser )
609
skip_spaces( &parser->cursor, parser->limit );
613
/* `token' here means either something between balanced delimiters */
614
/* or the next token; the delimiters are not removed. */
617
ps_parser_to_token( PS_Parser parser,
625
token->type = T1_TOKEN_TYPE_NONE;
629
/* first of all, skip leading whitespace */
630
ps_parser_skip_spaces( parser );
632
cur = parser->cursor;
633
limit = parser->limit;
640
/************* check for literal string *****************/
642
token->type = T1_TOKEN_TYPE_STRING;
645
if ( skip_literal_string( &cur, limit ) == PSaux_Err_Ok )
649
/************* check for programs/array *****************/
651
token->type = T1_TOKEN_TYPE_ARRAY;
654
if ( skip_procedure( &cur, limit ) == PSaux_Err_Ok )
658
/************* check for table/array ********************/
659
/* XXX: in theory we should also look for "<<" */
660
/* since this is semantically equivalent to "["; */
661
/* in practice it doesn't matter (?) */
663
token->type = T1_TOKEN_TYPE_ARRAY;
665
token->start = cur++;
667
/* we need this to catch `[ ]' */
668
parser->cursor = cur;
669
ps_parser_skip_spaces( parser );
670
cur = parser->cursor;
672
while ( cur < limit && !parser->error )
674
/* XXX: this is wrong because it does not */
675
/* skip comments, procedures, and strings */
678
else if ( *cur == ']' )
683
token->limit = ++cur;
688
parser->cursor = cur;
689
ps_parser_skip_PS_token( parser );
690
/* we need this to catch `[XXX ]' */
691
ps_parser_skip_spaces ( parser );
692
cur = parser->cursor;
696
/* ************ otherwise, it is any token **************/
699
token->type = ( *cur == '/' ? T1_TOKEN_TYPE_KEY : T1_TOKEN_TYPE_ANY );
700
ps_parser_skip_PS_token( parser );
701
cur = parser->cursor;
702
if ( !parser->error )
709
token->type = T1_TOKEN_TYPE_NONE;
712
parser->cursor = cur;
716
/* NB: `tokens' can be NULL if we only want to count */
717
/* the number of array elements */
720
ps_parser_to_token_array( PS_Parser parser,
723
FT_Int* pnum_tokens )
730
/* this also handles leading whitespace */
731
ps_parser_to_token( parser, &master );
733
if ( master.type == T1_TOKEN_TYPE_ARRAY )
735
FT_Byte* old_cursor = parser->cursor;
736
FT_Byte* old_limit = parser->limit;
737
T1_Token cur = tokens;
738
T1_Token limit = cur + max_tokens;
741
/* don't include outermost delimiters */
742
parser->cursor = master.start + 1;
743
parser->limit = master.limit - 1;
745
while ( parser->cursor < parser->limit )
750
ps_parser_to_token( parser, &token );
754
if ( tokens != NULL && cur < limit )
760
*pnum_tokens = (FT_Int)( cur - tokens );
762
parser->cursor = old_cursor;
763
parser->limit = old_limit;
768
/* first character must be a delimiter or a part of a number */
769
/* NB: `coords' can be NULL if we just want to skip the */
770
/* array; in this case we ignore `max_coords' */
773
ps_tocoordarray( FT_Byte* *acur,
778
FT_Byte* cur = *acur;
786
/* check for the beginning of an array; otherwise, only one number */
799
/* now, read the coordinates */
800
while ( cur < limit )
806
/* skip whitespace in front of data */
807
skip_spaces( &cur, limit );
819
if ( coords != NULL && count >= max_coords )
822
/* call PS_Conv_ToFixed() even if coords == NULL */
823
/* to properly parse number at `cur' */
824
*( coords != NULL ? &coords[count] : &dummy ) =
825
(FT_Short)( PS_Conv_ToFixed( &cur, limit, 0 ) >> 16 );
827
if ( old_cur == cur )
845
/* first character must be a delimiter or a part of a number */
846
/* NB: `values' can be NULL if we just want to skip the */
847
/* array; in this case we ignore `max_values' */
850
ps_tofixedarray( FT_Byte* *acur,
856
FT_Byte* cur = *acur;
864
/* Check for the beginning of an array. Otherwise, only one number */
877
/* now, read the values */
878
while ( cur < limit )
884
/* skip whitespace in front of data */
885
skip_spaces( &cur, limit );
897
if ( values != NULL && count >= max_values )
900
/* call PS_Conv_ToFixed() even if coords == NULL */
901
/* to properly parse number at `cur' */
902
*( values != NULL ? &values[count] : &dummy ) =
903
PS_Conv_ToFixed( &cur, limit, power_ten );
905
if ( old_cur == cur )
926
ps_tostring( FT_Byte** cursor,
930
FT_Byte* cur = *cursor;
937
/* XXX: some stupid fonts have a `Notice' or `Copyright' string */
938
/* that simply doesn't begin with an opening parenthesis, even */
939
/* though they have a closing one! E.g. "amuncial.pfb" */
941
/* We must deal with these ill-fated cases there. Note that */
942
/* these fonts didn't work with the old Type 1 driver as the */
943
/* notice/copyright was not recognized as a valid string token */
944
/* and made the old token parser commit errors. */
946
while ( cur < limit && ( *cur == ' ' || *cur == '\t' ) )
948
if ( cur + 1 >= limit )
952
cur++; /* skip the opening parenthesis, if there is one */
957
/* then, count its length */
958
for ( ; cur < limit; cur++ )
963
else if ( *cur == ')' )
972
if ( cur >= limit || FT_ALLOC( result, len + 1 ) )
975
/* now copy the string */
976
FT_MEM_COPY( result, *cursor, len );
986
ps_tobool( FT_Byte* *acur,
989
FT_Byte* cur = *acur;
993
/* return 1 if we find `true', 0 otherwise */
994
if ( cur + 3 < limit &&
1003
else if ( cur + 4 < limit &&
1019
/* load a simple field (i.e. non-table) into the current list of objects */
1021
FT_LOCAL_DEF( FT_Error )
1022
ps_parser_load_field( PS_Parser parser,
1023
const T1_Field field,
1025
FT_UInt max_objects,
1036
/* this also skips leading whitespace */
1037
ps_parser_to_token( parser, &token );
1044
limit = token.limit;
1046
/* we must detect arrays in /FontBBox */
1047
if ( field->type == T1_FIELD_TYPE_BBOX )
1050
FT_Byte* old_cur = parser->cursor;
1051
FT_Byte* old_limit = parser->limit;
1054
/* don't include delimiters */
1055
parser->cursor = token.start + 1;
1056
parser->limit = token.limit - 1;
1058
ps_parser_to_token( parser, &token2 );
1059
parser->cursor = old_cur;
1060
parser->limit = old_limit;
1062
if ( token2.type == T1_TOKEN_TYPE_ARRAY )
1065
else if ( token.type == T1_TOKEN_TYPE_ARRAY )
1068
/* if this is an array and we have no blend, an error occurs */
1069
if ( max_objects == 0 )
1072
count = max_objects;
1075
/* don't include delimiters */
1080
for ( ; count > 0; count--, idx++ )
1082
FT_Byte* q = (FT_Byte*)objects[idx] + field->offset;
1087
skip_spaces( &cur, limit );
1089
switch ( field->type )
1091
case T1_FIELD_TYPE_BOOL:
1092
val = ps_tobool( &cur, limit );
1095
case T1_FIELD_TYPE_FIXED:
1096
val = PS_Conv_ToFixed( &cur, limit, 0 );
1099
case T1_FIELD_TYPE_FIXED_1000:
1100
val = PS_Conv_ToFixed( &cur, limit, 3 );
1103
case T1_FIELD_TYPE_INTEGER:
1104
val = PS_Conv_ToInt( &cur, limit );
1108
switch ( field->size )
1110
case (8 / FT_CHAR_BIT):
1111
*(FT_Byte*)q = (FT_Byte)val;
1114
case (16 / FT_CHAR_BIT):
1115
*(FT_UShort*)q = (FT_UShort)val;
1118
case (32 / FT_CHAR_BIT):
1119
*(FT_UInt32*)q = (FT_UInt32)val;
1122
default: /* for 64-bit systems */
1127
case T1_FIELD_TYPE_STRING:
1128
case T1_FIELD_TYPE_KEY:
1130
FT_Memory memory = parser->memory;
1131
FT_UInt len = (FT_UInt)( limit - cur );
1137
/* we allow both a string or a name */
1138
/* for cases like /FontName (foo) def */
1139
if ( token.type == T1_TOKEN_TYPE_KEY )
1141
/* don't include leading `/' */
1145
else if ( token.type == T1_TOKEN_TYPE_STRING )
1147
/* don't include delimiting parentheses */
1148
/* XXX we don't handle <<...>> here */
1149
/* XXX should we convert octal escapes? */
1150
/* if so, what encoding should we use? */
1156
FT_ERROR(( "ps_parser_load_field: expected a name or string "
1157
"but found token of type %d instead\n",
1159
error = PSaux_Err_Invalid_File_Format;
1163
/* for this to work (FT_String**)q must have been */
1164
/* initialized to NULL */
1165
if ( *(FT_String**)q != NULL )
1167
FT_TRACE0(( "ps_parser_load_field: overwriting field %s\n",
1169
FT_FREE( *(FT_String**)q );
1170
*(FT_String**)q = NULL;
1173
if ( FT_ALLOC( string, len + 1 ) )
1176
FT_MEM_COPY( string, cur, len );
1179
*(FT_String**)q = string;
1183
case T1_FIELD_TYPE_BBOX:
1186
FT_BBox* bbox = (FT_BBox*)q;
1190
result = ps_tofixedarray( &cur, limit, 4, temp, 0 );
1194
FT_ERROR(( "ps_parser_load_field: "
1195
"expected four integers in bounding box\n" ));
1196
error = PSaux_Err_Invalid_File_Format;
1200
bbox->xMin = FT_RoundFix( temp[0] );
1201
bbox->yMin = FT_RoundFix( temp[1] );
1202
bbox->xMax = FT_RoundFix( temp[2] );
1203
bbox->yMax = FT_RoundFix( temp[3] );
1208
/* an error occurred */
1213
#if 0 /* obsolete -- keep for reference */
1215
*pflags |= 1L << field->flag_bit;
1217
FT_UNUSED( pflags );
1220
error = PSaux_Err_Ok;
1226
error = PSaux_Err_Invalid_File_Format;
1231
#define T1_MAX_TABLE_ELEMENTS 32
1234
FT_LOCAL_DEF( FT_Error )
1235
ps_parser_load_field_table( PS_Parser parser,
1236
const T1_Field field,
1238
FT_UInt max_objects,
1241
T1_TokenRec elements[T1_MAX_TABLE_ELEMENTS];
1243
FT_Int num_elements;
1244
FT_Error error = PSaux_Err_Ok;
1245
FT_Byte* old_cursor;
1247
T1_FieldRec fieldrec = *(T1_Field)field;
1250
fieldrec.type = T1_FIELD_TYPE_INTEGER;
1251
if ( field->type == T1_FIELD_TYPE_FIXED_ARRAY ||
1252
field->type == T1_FIELD_TYPE_BBOX )
1253
fieldrec.type = T1_FIELD_TYPE_FIXED;
1255
ps_parser_to_token_array( parser, elements,
1256
T1_MAX_TABLE_ELEMENTS, &num_elements );
1257
if ( num_elements < 0 )
1259
error = PSaux_Err_Ignore;
1262
if ( (FT_UInt)num_elements > field->array_max )
1263
num_elements = field->array_max;
1265
old_cursor = parser->cursor;
1266
old_limit = parser->limit;
1268
/* we store the elements count if necessary; */
1269
/* we further assume that `count_offset' can't be zero */
1270
if ( field->type != T1_FIELD_TYPE_BBOX && field->count_offset != 0 )
1271
*(FT_Byte*)( (FT_Byte*)objects[0] + field->count_offset ) =
1272
(FT_Byte)num_elements;
1274
/* we now load each element, adjusting the field.offset on each one */
1276
for ( ; num_elements > 0; num_elements--, token++ )
1278
parser->cursor = token->start;
1279
parser->limit = token->limit;
1280
ps_parser_load_field( parser, &fieldrec, objects, max_objects, 0 );
1281
fieldrec.offset += fieldrec.size;
1284
#if 0 /* obsolete -- keep for reference */
1286
*pflags |= 1L << field->flag_bit;
1288
FT_UNUSED( pflags );
1291
parser->cursor = old_cursor;
1292
parser->limit = old_limit;
1299
FT_LOCAL_DEF( FT_Long )
1300
ps_parser_to_int( PS_Parser parser )
1302
ps_parser_skip_spaces( parser );
1303
return PS_Conv_ToInt( &parser->cursor, parser->limit );
1307
/* first character must be `<' if `delimiters' is non-zero */
1309
FT_LOCAL_DEF( FT_Error )
1310
ps_parser_to_bytes( PS_Parser parser,
1313
FT_Long* pnum_bytes,
1314
FT_Bool delimiters )
1316
FT_Error error = PSaux_Err_Ok;
1320
ps_parser_skip_spaces( parser );
1321
cur = parser->cursor;
1323
if ( cur >= parser->limit )
1330
FT_ERROR(( "ps_parser_to_bytes: Missing starting delimiter `<'\n" ));
1331
error = PSaux_Err_Invalid_File_Format;
1338
*pnum_bytes = PS_Conv_ASCIIHexDecode( &cur,
1345
if ( cur < parser->limit && *cur != '>' )
1347
FT_ERROR(( "ps_parser_to_bytes: Missing closing delimiter `>'\n" ));
1348
error = PSaux_Err_Invalid_File_Format;
1355
parser->cursor = cur;
1362
FT_LOCAL_DEF( FT_Fixed )
1363
ps_parser_to_fixed( PS_Parser parser,
1366
ps_parser_skip_spaces( parser );
1367
return PS_Conv_ToFixed( &parser->cursor, parser->limit, power_ten );
1371
FT_LOCAL_DEF( FT_Int )
1372
ps_parser_to_coord_array( PS_Parser parser,
1376
ps_parser_skip_spaces( parser );
1377
return ps_tocoordarray( &parser->cursor, parser->limit,
1378
max_coords, coords );
1382
FT_LOCAL_DEF( FT_Int )
1383
ps_parser_to_fixed_array( PS_Parser parser,
1388
ps_parser_skip_spaces( parser );
1389
return ps_tofixedarray( &parser->cursor, parser->limit,
1390
max_values, values, power_ten );
1396
FT_LOCAL_DEF( FT_String* )
1397
T1_ToString( PS_Parser parser )
1399
return ps_tostring( &parser->cursor, parser->limit, parser->memory );
1403
FT_LOCAL_DEF( FT_Bool )
1404
T1_ToBool( PS_Parser parser )
1406
return ps_tobool( &parser->cursor, parser->limit );
1412
FT_LOCAL_DEF( void )
1413
ps_parser_init( PS_Parser parser,
1418
parser->error = PSaux_Err_Ok;
1419
parser->base = base;
1420
parser->limit = limit;
1421
parser->cursor = base;
1422
parser->memory = memory;
1423
parser->funcs = ps_parser_funcs;
1427
FT_LOCAL_DEF( void )
1428
ps_parser_done( PS_Parser parser )
1430
FT_UNUSED( parser );
1434
/*************************************************************************/
1435
/*************************************************************************/
1437
/***** T1 BUILDER *****/
1439
/*************************************************************************/
1440
/*************************************************************************/
1442
/*************************************************************************/
1445
/* t1_builder_init */
1448
/* Initializes a given glyph builder. */
1451
/* builder :: A pointer to the glyph builder to initialize. */
1454
/* face :: The current face object. */
1456
/* size :: The current size object. */
1458
/* glyph :: The current glyph object. */
1460
/* hinting :: Whether hinting should be applied. */
1462
FT_LOCAL_DEF( void )
1463
t1_builder_init( T1_Builder builder,
1469
builder->parse_state = T1_Parse_Start;
1470
builder->load_points = 1;
1472
builder->face = face;
1473
builder->glyph = glyph;
1474
builder->memory = face->memory;
1478
FT_GlyphLoader loader = glyph->internal->loader;
1481
builder->loader = loader;
1482
builder->base = &loader->base.outline;
1483
builder->current = &loader->current.outline;
1484
FT_GlyphLoader_Rewind( loader );
1486
builder->hints_globals = size->internal;
1487
builder->hints_funcs = 0;
1490
builder->hints_funcs = glyph->internal->glyph_hints;
1496
builder->left_bearing.x = 0;
1497
builder->left_bearing.y = 0;
1498
builder->advance.x = 0;
1499
builder->advance.y = 0;
1501
builder->funcs = t1_builder_funcs;
1505
/*************************************************************************/
1508
/* t1_builder_done */
1511
/* Finalizes a given glyph builder. Its contents can still be used */
1512
/* after the call, but the function saves important information */
1513
/* within the corresponding glyph slot. */
1516
/* builder :: A pointer to the glyph builder to finalize. */
1518
FT_LOCAL_DEF( void )
1519
t1_builder_done( T1_Builder builder )
1521
FT_GlyphSlot glyph = builder->glyph;
1525
glyph->outline = *builder->base;
1529
/* check that there is enough space for `count' more points */
1530
FT_LOCAL_DEF( FT_Error )
1531
t1_builder_check_points( T1_Builder builder,
1534
return FT_GLYPHLOADER_CHECK_POINTS( builder->loader, count, 0 );
1538
/* add a new point, do not check space */
1539
FT_LOCAL_DEF( void )
1540
t1_builder_add_point( T1_Builder builder,
1545
FT_Outline* outline = builder->current;
1548
if ( builder->load_points )
1550
FT_Vector* point = outline->points + outline->n_points;
1551
FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points;
1554
if ( builder->shift )
1561
*control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC );
1563
builder->last = *point;
1565
outline->n_points++;
1569
/* check space for a new on-curve point, then add it */
1570
FT_LOCAL_DEF( FT_Error )
1571
t1_builder_add_point1( T1_Builder builder,
1578
error = t1_builder_check_points( builder, 1 );
1580
t1_builder_add_point( builder, x, y, 1 );
1586
/* check space for a new contour, then add it */
1587
FT_LOCAL_DEF( FT_Error )
1588
t1_builder_add_contour( T1_Builder builder )
1590
FT_Outline* outline = builder->current;
1594
if ( !builder->load_points )
1596
outline->n_contours++;
1597
return PSaux_Err_Ok;
1600
error = FT_GLYPHLOADER_CHECK_POINTS( builder->loader, 0, 1 );
1603
if ( outline->n_contours > 0 )
1604
outline->contours[outline->n_contours - 1] =
1605
(short)( outline->n_points - 1 );
1607
outline->n_contours++;
1614
/* if a path was begun, add its first on-curve point */
1615
FT_LOCAL_DEF( FT_Error )
1616
t1_builder_start_point( T1_Builder builder,
1620
FT_Error error = PSaux_Err_Invalid_File_Format;
1623
/* test whether we are building a new contour */
1625
if ( builder->parse_state == T1_Parse_Have_Path )
1626
error = PSaux_Err_Ok;
1627
else if ( builder->parse_state == T1_Parse_Have_Moveto )
1629
builder->parse_state = T1_Parse_Have_Path;
1630
error = t1_builder_add_contour( builder );
1632
error = t1_builder_add_point1( builder, x, y );
1639
/* close the current contour */
1640
FT_LOCAL_DEF( void )
1641
t1_builder_close_contour( T1_Builder builder )
1643
FT_Outline* outline = builder->current;
1650
first = outline->n_contours <= 1
1651
? 0 : outline->contours[outline->n_contours - 2] + 1;
1653
/* We must not include the last point in the path if it */
1654
/* is located on the first point. */
1655
if ( outline->n_points > 1 )
1657
FT_Vector* p1 = outline->points + first;
1658
FT_Vector* p2 = outline->points + outline->n_points - 1;
1659
FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points - 1;
1662
/* `delete' last point only if it coincides with the first */
1663
/* point and it is not a control point (which can happen). */
1664
if ( p1->x == p2->x && p1->y == p2->y )
1665
if ( *control == FT_CURVE_TAG_ON )
1666
outline->n_points--;
1669
if ( outline->n_contours > 0 )
1671
/* Don't add contours only consisting of one point, i.e., */
1672
/* check whether begin point and last point are the same. */
1673
if ( first == outline->n_points - 1 )
1675
outline->n_contours--;
1676
outline->n_points--;
1679
outline->contours[outline->n_contours - 1] =
1680
(short)( outline->n_points - 1 );
1685
/*************************************************************************/
1686
/*************************************************************************/
1690
/*************************************************************************/
1691
/*************************************************************************/
1693
FT_LOCAL_DEF( void )
1694
t1_decrypt( FT_Byte* buffer,
1698
PS_Conv_EexecDecode( &buffer,