1
/***************************************************************************/
5
/* Auxiliary functions for PostScript fonts (body). */
7
/* Copyright 1996-2011 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 == 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,