1 /***************************************************************************/
5 /* Auxiliary functions for PostScript fonts (body). */
7 /* Copyright 1996-2001 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
28 /*************************************************************************/
29 /*************************************************************************/
31 /***** PS_TABLE *****/
33 /*************************************************************************/
34 /*************************************************************************/
36 /*************************************************************************/
42 /* Initializes a PS_Table. */
45 /* table :: The address of the target table. */
48 /* count :: The table size = the maximum number of elements. */
50 /* memory :: The memory object to use for all subsequent */
54 /* FreeType error code. 0 means success. */
57 PS_Table_New( PS_Table* table,
64 table->memory = memory;
65 if ( ALLOC_ARRAY( table->elements, count, FT_Byte* ) ||
66 ALLOC_ARRAY( table->lengths, count, FT_Byte* ) )
69 table->max_elems = count;
70 table->init = 0xDEADBEEFUL;
75 table->funcs = ps_table_funcs;
79 FREE( table->elements );
86 shift_elements( PS_Table* table,
89 FT_Long delta = (FT_Long)( table->block - old_base );
90 FT_Byte** offset = table->elements;
91 FT_Byte** limit = offset + table->max_elems;
94 for ( ; offset < limit; offset++ )
103 reallocate_t1_table( PS_Table* table,
106 FT_Memory memory = table->memory;
107 FT_Byte* old_base = table->block;
111 /* allocate new base block */
112 if ( ALLOC( table->block, new_size ) )
115 /* copy elements and shift offsets */
118 MEM_Copy( table->block, old_base, table->capacity );
119 shift_elements( table, old_base );
123 table->capacity = new_size;
129 /*************************************************************************/
135 /* Adds an object to a PS_Table, possibly growing its memory block. */
138 /* table :: The target table. */
141 /* index :: The index of the object in the table. */
143 /* object :: The address of the object to copy in memory. */
145 /* length :: The length in bytes of the source object. */
148 /* FreeType error code. 0 means success. An error is returned if a */
149 /* reallocation fails. */
151 FT_LOCAL_DEF FT_Error
152 PS_Table_Add( PS_Table* table,
157 if ( index < 0 || index > table->max_elems )
159 FT_ERROR(( "PS_Table_Add: invalid index\n" ));
160 return PSaux_Err_Invalid_Argument;
163 /* grow the base block if needed */
164 if ( table->cursor + length > table->capacity )
167 FT_Offset new_size = table->capacity;
171 in_offset = (FT_Long)((FT_Byte*)object - table->block);
172 if ( (FT_ULong)in_offset >= table->capacity )
175 while ( new_size < table->cursor + length )
178 error = reallocate_t1_table( table, new_size );
182 if ( in_offset >= 0 )
183 object = table->block + in_offset;
186 /* add the object to the base block and adjust offset */
187 table->elements[index] = table->block + table->cursor;
188 table->lengths [index] = length;
189 MEM_Copy( table->block + table->cursor, object, length );
191 table->cursor += length;
196 /*************************************************************************/
202 /* Finalizes a PS_Table (i.e., reallocate it to its current cursor). */
205 /* table :: The target table. */
208 /* This function does NOT release the heap's memory block. It is up */
209 /* to the caller to clean it, or reference it in its own structures. */
212 PS_Table_Done( PS_Table* table )
214 FT_Memory memory = table->memory;
216 FT_Byte* old_base = table->block;
219 /* should never fail, because rec.cursor <= rec.size */
223 if ( ALLOC( table->block, table->cursor ) )
225 MEM_Copy( table->block, old_base, table->cursor );
226 shift_elements( table, old_base );
228 table->capacity = table->cursor;
234 PS_Table_Release( PS_Table* table )
236 FT_Memory memory = table->memory;
239 if ( (FT_ULong)table->init == 0xDEADBEEFUL )
241 FREE( table->block );
242 FREE( table->elements );
243 FREE( table->lengths );
249 /*************************************************************************/
250 /*************************************************************************/
252 /***** T1 PARSER *****/
254 /*************************************************************************/
255 /*************************************************************************/
258 #define IS_T1_WHITESPACE( c ) ( (c) == ' ' || (c) == '\t' )
259 #define IS_T1_LINESPACE( c ) ( (c) == '\r' || (c) == '\n' )
261 #define IS_T1_SPACE( c ) ( IS_T1_WHITESPACE( c ) || IS_T1_LINESPACE( c ) )
265 T1_Skip_Spaces( T1_Parser* parser )
267 FT_Byte* cur = parser->cursor;
268 FT_Byte* limit = parser->limit;
271 while ( cur < limit )
276 if ( !IS_T1_SPACE( c ) )
280 parser->cursor = cur;
285 T1_Skip_Alpha( T1_Parser* parser )
287 FT_Byte* cur = parser->cursor;
288 FT_Byte* limit = parser->limit;
291 while ( cur < limit )
296 if ( IS_T1_SPACE( c ) )
300 parser->cursor = cur;
305 T1_ToToken( T1_Parser* parser,
310 FT_Byte starter, ender;
314 token->type = t1_token_none;
318 /* first of all, skip space */
319 T1_Skip_Spaces( parser );
321 cur = parser->cursor;
322 limit = parser->limit;
328 /************* check for strings ***********************/
330 token->type = t1_token_string;
334 /************* check for programs/array ****************/
336 token->type = t1_token_array;
340 /************* check for table/array ******************/
342 token->type = t1_token_array;
349 while ( cur < limit )
351 if ( *cur == starter )
353 else if ( *cur == ender )
358 token->limit = cur++;
366 /* **************** otherwise, it's any token **********/
368 token->start = cur++;
369 token->type = t1_token_any;
370 while ( cur < limit && !IS_T1_SPACE( *cur ) )
379 token->type = t1_token_none;
382 parser->cursor = cur;
388 T1_ToTokenArray( T1_Parser* parser,
391 FT_Int* pnum_tokens )
398 T1_ToToken( parser, &master );
399 if ( master.type == t1_token_array )
401 FT_Byte* old_cursor = parser->cursor;
402 FT_Byte* old_limit = parser->limit;
403 T1_Token* cur = tokens;
404 T1_Token* limit = cur + max_tokens;
407 parser->cursor = master.start;
408 parser->limit = master.limit;
410 while ( parser->cursor < parser->limit )
415 T1_ToToken( parser, &token );
425 *pnum_tokens = (FT_Int)( cur - tokens );
427 parser->cursor = old_cursor;
428 parser->limit = old_limit;
434 t1_toint( FT_Byte** cursor,
438 FT_Byte* cur = *cursor;
442 for ( ; cur < limit; cur++ )
445 d = (FT_Byte)( c - '0' );
460 d = (FT_Byte)( cur[0] - '0' );
464 result = result * 10 + d;
467 } while ( cur < limit );
479 t1_tofixed( FT_Byte** cursor,
483 FT_Byte* cur = *cursor;
484 FT_Long num, divider, result;
492 /* first of all, check the sign */
499 /* then, read the integer part, if any */
501 result = t1_toint( &cur, limit ) << 16;
511 /* read decimal part, if any */
512 if ( *cur == '.' && cur + 1 < limit )
518 d = (FT_Byte)( *cur - '0' );
522 if ( divider < 10000000L )
534 /* read exponent, if any */
535 if ( cur + 1 < limit && ( *cur == 'e' || *cur == 'E' ) )
538 power_ten += t1_toint( &cur, limit );
542 /* raise to power of ten if needed */
543 while ( power_ten > 0 )
545 result = result * 10;
550 while ( power_ten < 0 )
552 result = result / 10;
553 divider = divider * 10;
558 result += FT_DivFix( num, divider );
569 t1_tocoordarray( FT_Byte** cursor,
574 FT_Byte* cur = *cursor;
582 /* check for the beginning of an array; if not, only one number will */
596 /* now, read the coordinates */
597 for ( ; cur < limit; )
599 /* skip whitespace in front of data */
603 if ( c != ' ' && c != '\t' )
611 if ( count >= max_coords || c == ender )
614 coords[count] = (FT_Short)( t1_tofixed( &cur, limit, 0 ) >> 16 );
628 t1_tofixedarray( FT_Byte** cursor,
634 FT_Byte* cur = *cursor;
639 if ( cur >= limit ) goto Exit;
641 /* check for the beginning of an array. If not, only one number will */
655 /* now, read the values */
656 for ( ; cur < limit; )
658 /* skip whitespace in front of data */
662 if ( c != ' ' && c != '\t' )
670 if ( count >= max_values || c == ender )
673 values[count] = t1_tofixed( &cur, limit, power_ten );
689 t1_tostring( FT_Byte** cursor,
693 FT_Byte* cur = *cursor;
700 /* XXX: some stupid fonts have a `Notice' or `Copyright' string */
701 /* that simply doesn't begin with an opening parenthesis, even */
702 /* though they have a closing one! E.g. "amuncial.pfb" */
704 /* We must deal with these ill-fated cases there. Note that */
705 /* these fonts didn't work with the old Type 1 driver as the */
706 /* notice/copyright was not recognized as a valid string token */
707 /* and made the old token parser commit errors. */
709 while ( cur < limit && ( *cur == ' ' || *cur == '\t' ) )
711 if ( cur + 1 >= limit )
715 cur++; /* skip the opening parenthesis, if there is one */
720 /* then, count its length */
721 for ( ; cur < limit; cur++ )
726 else if ( *cur == ')' )
735 if ( cur >= limit || ALLOC( result, len + 1 ) )
738 /* now copy the string */
739 MEM_Copy( result, *cursor, len );
749 t1_tobool( FT_Byte** cursor,
752 FT_Byte* cur = *cursor;
756 /* return 1 if we find `true', 0 otherwise */
757 if ( cur + 3 < limit &&
766 else if ( cur + 4 < limit &&
782 /* Load a simple field (i.e. non-table) into the current list of objects */
783 FT_LOCAL_DEF FT_Error
784 T1_Load_Field( T1_Parser* parser,
785 const T1_Field* field,
798 T1_ToToken( parser, &token );
807 if ( token.type == t1_token_array )
809 /* if this is an array, and we have no blend, an error occurs */
810 if ( max_objects == 0 )
817 for ( ; count > 0; count--, index++ )
819 FT_Byte* q = (FT_Byte*)objects[index] + field->offset;
824 switch ( field->type )
827 val = t1_tobool( &cur, limit );
831 val = t1_tofixed( &cur, limit, 3 );
834 case t1_field_integer:
835 val = t1_toint( &cur, limit );
838 switch ( field->size )
841 *(FT_Byte*)q = (FT_Byte)val;
845 *(FT_UShort*)q = (FT_UShort)val;
849 *(FT_UInt32*)q = (FT_UInt32)val;
852 default: /* for 64-bit systems */
857 case t1_field_string:
859 FT_Memory memory = parser->memory;
860 FT_UInt len = (FT_UInt)( limit - cur );
863 if ( *(FT_String**)q )
864 /* with synthetic fonts, it's possible to find a field twice */
867 if ( ALLOC( string, len + 1 ) )
870 MEM_Copy( string, cur, len );
873 *(FT_String**)q = string;
878 /* an error occured */
883 #if 0 /* obsolete - keep for reference */
885 *pflags |= 1L << field->flag_bit;
890 error = PSaux_Err_Ok;
896 error = PSaux_Err_Invalid_File_Format;
901 #define T1_MAX_TABLE_ELEMENTS 32
904 FT_LOCAL_DEF FT_Error
905 T1_Load_Field_Table( T1_Parser* parser,
906 const T1_Field* field,
911 T1_Token elements[T1_MAX_TABLE_ELEMENTS];
917 T1_Field fieldrec = *(T1_Field*)field;
920 fieldrec.type = t1_field_integer;
921 if ( field->type == t1_field_fixed_array )
922 fieldrec.type = t1_field_fixed;
925 T1_ToTokenArray( parser, elements, 32, &num_elements );
926 if ( num_elements < 0 )
929 if ( num_elements > T1_MAX_TABLE_ELEMENTS )
930 num_elements = T1_MAX_TABLE_ELEMENTS;
932 old_cursor = parser->cursor;
933 old_limit = parser->limit;
935 /* we store the elements count */
936 *(FT_Byte*)( (FT_Byte*)objects[0] + field->count_offset ) =
937 (FT_Byte)num_elements;
939 /* we now load each element, adjusting the field.offset on each one */
941 for ( ; num_elements > 0; num_elements--, token++ )
943 parser->cursor = token->start;
944 parser->limit = token->limit;
945 T1_Load_Field( parser, &fieldrec, objects, max_objects, 0 );
946 fieldrec.offset += fieldrec.size;
949 #if 0 /* obsolete -- keep for reference */
951 *pflags |= 1L << field->flag_bit;
956 parser->cursor = old_cursor;
957 parser->limit = old_limit;
963 error = PSaux_Err_Invalid_File_Format;
969 T1_ToInt( T1_Parser* parser )
971 return t1_toint( &parser->cursor, parser->limit );
975 FT_LOCAL_DEF FT_Fixed
976 T1_ToFixed( T1_Parser* parser,
979 return t1_tofixed( &parser->cursor, parser->limit, power_ten );
984 T1_ToCoordArray( T1_Parser* parser,
988 return t1_tocoordarray( &parser->cursor, parser->limit,
989 max_coords, coords );
994 T1_ToFixedArray( T1_Parser* parser,
999 return t1_tofixedarray( &parser->cursor, parser->limit,
1000 max_values, values, power_ten );
1006 FT_LOCAL_DEF FT_String*
1007 T1_ToString( T1_Parser* parser )
1009 return t1_tostring( &parser->cursor, parser->limit, parser->memory );
1013 FT_LOCAL_DEF FT_Bool
1014 T1_ToBool( T1_Parser* parser )
1016 return t1_tobool( &parser->cursor, parser->limit );
1023 T1_Init_Parser( T1_Parser* parser,
1029 parser->base = base;
1030 parser->limit = limit;
1031 parser->cursor = base;
1032 parser->memory = memory;
1033 parser->funcs = t1_parser_funcs;
1038 T1_Done_Parser( T1_Parser* parser )
1040 FT_UNUSED( parser );
1044 /*************************************************************************/
1045 /*************************************************************************/
1047 /***** T1 BUILDER *****/
1049 /*************************************************************************/
1050 /*************************************************************************/
1052 /*************************************************************************/
1055 /* T1_Builder_Init */
1058 /* Initializes a given glyph builder. */
1061 /* builder :: A pointer to the glyph builder to initialize. */
1064 /* face :: The current face object. */
1066 /* size :: The current size object. */
1068 /* glyph :: The current glyph object. */
1071 T1_Builder_Init( T1_Builder* builder,
1074 FT_GlyphSlot glyph )
1076 builder->path_begun = 0;
1077 builder->load_points = 1;
1079 builder->face = face;
1080 builder->glyph = glyph;
1081 builder->memory = face->memory;
1085 FT_GlyphLoader* loader = glyph->internal->loader;
1088 builder->loader = loader;
1089 builder->base = &loader->base.outline;
1090 builder->current = &loader->current.outline;
1091 FT_GlyphLoader_Rewind( loader );
1096 builder->scale_x = size->metrics.x_scale;
1097 builder->scale_y = size->metrics.y_scale;
1103 builder->left_bearing.x = 0;
1104 builder->left_bearing.y = 0;
1105 builder->advance.x = 0;
1106 builder->advance.y = 0;
1108 builder->funcs = t1_builder_funcs;
1112 /*************************************************************************/
1115 /* T1_Builder_Done */
1118 /* Finalizes a given glyph builder. Its contents can still be used */
1119 /* after the call, but the function saves important information */
1120 /* within the corresponding glyph slot. */
1123 /* builder :: A pointer to the glyph builder to finalize. */
1126 T1_Builder_Done( T1_Builder* builder )
1128 FT_GlyphSlot glyph = builder->glyph;
1132 glyph->outline = *builder->base;
1136 /* check that there is enough room for `count' more points */
1137 FT_LOCAL_DEF FT_Error
1138 T1_Builder_Check_Points( T1_Builder* builder,
1141 return FT_GlyphLoader_Check_Points( builder->loader, count, 0 );
1145 /* add a new point, do not check space */
1147 T1_Builder_Add_Point( T1_Builder* builder,
1152 FT_Outline* outline = builder->current;
1155 if ( builder->load_points )
1157 FT_Vector* point = outline->points + outline->n_points;
1158 FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points;
1161 if ( builder->shift )
1168 *control = (FT_Byte)( flag ? FT_Curve_Tag_On : FT_Curve_Tag_Cubic );
1170 builder->last = *point;
1172 outline->n_points++;
1176 /* check space for a new on-curve point, then add it */
1177 FT_LOCAL_DEF FT_Error
1178 T1_Builder_Add_Point1( T1_Builder* builder,
1185 error = T1_Builder_Check_Points( builder, 1 );
1187 T1_Builder_Add_Point( builder, x, y, 1 );
1193 /* check room for a new contour, then add it */
1194 FT_LOCAL_DEF FT_Error
1195 T1_Builder_Add_Contour( T1_Builder* builder )
1197 FT_Outline* outline = builder->current;
1201 if ( !builder->load_points )
1203 outline->n_contours++;
1204 return PSaux_Err_Ok;
1207 error = FT_GlyphLoader_Check_Points( builder->loader, 0, 1 );
1210 if ( outline->n_contours > 0 )
1211 outline->contours[outline->n_contours - 1] =
1212 (short)( outline->n_points - 1 );
1214 outline->n_contours++;
1221 /* if a path was begun, add its first on-curve point */
1222 FT_LOCAL_DEF FT_Error
1223 T1_Builder_Start_Point( T1_Builder* builder,
1230 /* test whether we are building a new contour */
1231 if ( !builder->path_begun )
1233 builder->path_begun = 1;
1234 error = T1_Builder_Add_Contour( builder );
1236 error = T1_Builder_Add_Point1( builder, x, y );
1242 /* close the current contour */
1244 T1_Builder_Close_Contour( T1_Builder* builder )
1246 FT_Outline* outline = builder->current;
1249 /* XXXX: We must not include the last point in the path if it */
1250 /* is located on the first point. */
1251 if ( outline->n_points > 1 )
1254 FT_Vector* p1 = outline->points + first;
1255 FT_Vector* p2 = outline->points + outline->n_points - 1;
1256 FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points - 1;
1259 if ( outline->n_contours > 1 )
1261 first = outline->contours[outline->n_contours - 2] + 1;
1262 p1 = outline->points + first;
1265 /* `delete' last point only if it coincides with the first */
1266 /* point and it is not a control point (which can happen). */
1267 if ( p1->x == p2->x && p1->y == p2->y )
1268 if ( *control == FT_Curve_Tag_On )
1269 outline->n_points--;
1272 if ( outline->n_contours > 0 )
1273 outline->contours[outline->n_contours - 1] =
1274 (short)( outline->n_points - 1 );
1278 /*************************************************************************/
1279 /*************************************************************************/
1283 /*************************************************************************/
1284 /*************************************************************************/
1287 T1_Decrypt( FT_Byte* buffer,
1291 while ( length > 0 )
1296 plain = (FT_Byte)( *buffer ^ ( seed >> 8 ) );
1297 seed = (FT_UShort)( ( *buffer + seed ) * 52845U + 22719 );