diff --git a/ChangeLog b/ChangeLog index 3e278f473..07a39f082 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,58 @@ +2006-07-14 Jens Claudius + + * freetype2/include/freetype/internal/psaux.h: New macros + IS_PS_NEWLINE, IS_PS_SPACE, IS_PS_SPECIAL, IS_PS_DELIM, IS_PS_DIGIT, + IS_PS_XDIGIT, and IS_PS_BASE85 (from freetype2/src/psaux/psconv.h). + (T1_FieldLocation): Add T1_FIELD_LOCATION_LOADER, + T1_FIELD_LOCATION_FACE, and T1_FIELD_LOCATION_BLEND. + (T1_DecoderRec): New fields `buildchar' and `face'. + (IS_PS_TOKEN): New macro. + + * freetype2/include/freetype/internal/t1types.h (T1_FaceRec): New + fields `ndv_idx', `cdv_idx', and `len_buildchar'. + + * freetype2/include/freetype/t1tables.h (PS_BlendRec): New fields + `default_design_vector' and `num_default_design_vector'. + + * freetype2/src/psaux/psconv.h: Move macros IS_PS_NEWLINE, + IS_PS_SPACE, IS_PS_SPECIAL, IS_PS_DELIM, IS_PS_DIGIT, IS_PS_XDIGIT, + and IS_PS_BASE85 to freetype2/include/freetype/internal/psaux.h. + + * freetype2/src/psaux/psobjs.c (ps_parser_to_token_array): Allow + `token' argument to be NULL if we want only to count the number of + tokens. + (ps_tocoordarray): Allow `coords' argument to be NULL if we just + want to skip the array. + (ps_tofixedarray): Allow `values' argument to be NULL if we just + want to skip the array. + + * freetype2/src/psaux/t1decode.c (t1_decoder_parse_charstrings): Add + support for (partially commented out) othersubrs 19-25, 27, and 28. + (t1_decoder_init): Initialize new fields `face' and `buildchar'. + (t1_decoder_done): Release new field `buildchar'. + + * freetype2/src/type1/t1load.c (parse_buildchar, parse_private): New + functions. + (t1_keywords): Register them. + (t1_allocate_blend): Updated. + (t1_load_keyword): Handle field types T1_FIELD_LOCATION_LOADER, + T1_FIELD_LOCATION_FACE and T1_FIELD_LOCATION_BLEND. + (parse_dict): Remove `keyword_flags' argument. + Use new macro IS_PS_TOKEN. + Changed function so that later PostScript definitions override + earlier ones. + (t1_init_loader): Initialize new field `keywords_encountered'. + (T1_Open_Face): Initialize new fields `ndv_idx', `cdv_idx', and + `len_buildchar'. + Remove `keywords_flags'. + + * freetype2/src/type1/t1load.h (T1_LoaderRect): New field + `keywords_encountered'. + (T1_PRIVATE, T1_FONTDIR_AFTER_PRIVATE): New macros. + + * freetype2/src/type1/t1tokens.h [!T1_CONFIG_OPTION_NO_MM_SUPPORT]: + New entries for parsing /NDV, /CDV, and /DesignVector. + 2006-07-07 Werner Lemberg Add many checks to protect against malformed PCF files. diff --git a/include/freetype/internal/psaux.h b/include/freetype/internal/psaux.h index d2e491000..4afd2b069 100644 --- a/include/freetype/internal/psaux.h +++ b/include/freetype/internal/psaux.h @@ -199,6 +199,9 @@ FT_BEGIN_HEADER T1_FIELD_LOCATION_FONT_INFO, T1_FIELD_LOCATION_PRIVATE, T1_FIELD_LOCATION_BBOX, + T1_FIELD_LOCATION_LOADER, + T1_FIELD_LOCATION_FACE, + T1_FIELD_LOCATION_BLEND, /* do not remove */ T1_FIELD_LOCATION_MAX @@ -683,6 +686,10 @@ FT_BEGIN_HEADER T1_Decoder_Callback parse_callback; T1_Decoder_FuncsRec funcs; + FT_Int* buildchar; + + T1_Face face; + } T1_DecoderRec; @@ -712,8 +719,10 @@ FT_BEGIN_HEADER } AFM_Parser_FuncsRec; + typedef struct AFM_StreamRec_* AFM_Stream; + /*************************************************************************/ /* */ /* */ @@ -801,6 +810,57 @@ FT_BEGIN_HEADER /* backwards-compatible type definition */ typedef PSAux_ServiceRec PSAux_Interface; + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** Some convenience functions *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define IS_PS_NEWLINE( ch ) \ + ( (ch) == '\r' || \ + (ch) == '\n' ) + +#define IS_PS_SPACE( ch ) \ + ( (ch) == ' ' || \ + IS_PS_NEWLINE( ch ) || \ + (ch) == '\t' || \ + (ch) == '\f' || \ + (ch) == '\0' ) + +#define IS_PS_SPECIAL( ch ) \ + ( (ch) == '/' || \ + (ch) == '(' || (ch) == ')' || \ + (ch) == '<' || (ch) == '>' || \ + (ch) == '[' || (ch) == ']' || \ + (ch) == '{' || (ch) == '}' || \ + (ch) == '%' ) + +#define IS_PS_DELIM( ch ) \ + ( IS_PS_SPACE( ch ) || \ + IS_PS_SPECIAL( ch ) ) + +#define IS_PS_DIGIT( ch ) \ + ( (ch) >= '0' && (ch) <= '9' ) + +#define IS_PS_XDIGIT( ch ) \ + ( IS_PS_DIGIT( ch ) || \ + ( (ch) >= 'A' && (ch) <= 'F' ) || \ + ( (ch) >= 'a' && (ch) <= 'f' ) ) + +#define IS_PS_BASE85( ch ) \ + ( (ch) >= '!' && (ch) <= 'u' ) + +#define IS_PS_TOKEN( cur, limit, token ) \ + ( (char)(cur)[0] == (token)[0] && \ + ( (cur) + sizeof ( (token) ) == (limit) || \ + ( (cur) + sizeof( (token) ) < (limit) && \ + IS_PS_DELIM( (cur)[sizeof ( (token) ) - 1] ) ) ) && \ + ft_strncmp( (char*)(cur), (token), sizeof ( (token) ) - 1 ) == 0 ) + + FT_END_HEADER #endif /* __PSAUX_H__ */ diff --git a/include/freetype/internal/t1types.h b/include/freetype/internal/t1types.h index 65d9ca92e..eca91a7fc 100644 --- a/include/freetype/internal/t1types.h +++ b/include/freetype/internal/t1types.h @@ -208,6 +208,16 @@ FT_BEGIN_HEADER /* support for Multiple Masters fonts */ PS_Blend blend; + /* undocumented, optional: indices of subroutines that express */ + /* the NormalizeDesignVector and the ConvertDesignVector procedure, */ + /* respectively, as Type 2 charstrings; -1 if keywords not present */ + FT_Int ndv_idx; + FT_Int cdv_idx; + + /* undocumented, optional: has the same meaning as len_buildchar */ + /* for Type 2 fonts; manipulated by othersubrs 19, 24, and 25 */ + FT_UInt len_buildchar; + /* since version 2.1 - interface to PostScript hinter */ const void* pshinter; diff --git a/include/freetype/t1tables.h b/include/freetype/t1tables.h index 1815250a4..7979ea531 100644 --- a/include/freetype/t1tables.h +++ b/include/freetype/t1tables.h @@ -5,7 +5,7 @@ /* Basic Type 1/Type 2 tables definitions and interface (specification */ /* only). */ /* */ -/* Copyright 1996-2001, 2002, 2003, 2004 by */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2006 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -256,6 +256,15 @@ FT_BEGIN_HEADER FT_BBox* bboxes [T1_MAX_MM_DESIGNS + 1]; + /* since 2.2.2 */ + + /* undocumented, optional: the default design instance; */ + /* corresponds to default_weight_vector -- */ + /* num_default_design_vector == 0 means it is not present */ + /* in the font and associated metrics files */ + FT_UInt default_design_vector[T1_MAX_MM_DESIGNS]; + FT_UInt num_default_design_vector; + } PS_BlendRec, *PS_Blend; diff --git a/src/psaux/psconv.h b/src/psaux/psconv.h index 82c370787..e51124185 100644 --- a/src/psaux/psconv.h +++ b/src/psaux/psconv.h @@ -63,42 +63,6 @@ FT_BEGIN_HEADER FT_UShort* seed ); -#define IS_PS_NEWLINE( ch ) \ - ( ( ch ) == '\r' || \ - ( ch ) == '\n' ) - -#define IS_PS_SPACE( ch ) \ - ( ( ch ) == ' ' || \ - IS_PS_NEWLINE( ch ) || \ - ( ch ) == '\t' || \ - ( ch ) == '\f' || \ - ( ch ) == '\0' ) - -#define IS_PS_SPECIAL( ch ) \ - ( ( ch ) == '/' || \ - ( ch ) == '(' || \ - ( ch ) == ')' || \ - ( ch ) == '<' || \ - ( ch ) == '>' || \ - ( ch ) == '[' || \ - ( ch ) == ']' || \ - ( ch ) == '{' || \ - ( ch ) == '}' || \ - ( ch ) == '%' ) - -#define IS_PS_DELIM( ch ) \ - ( IS_PS_SPACE( ch ) || \ - IS_PS_SPECIAL( ch ) ) - -#define IS_PS_DIGIT( ch ) ( ( ch ) >= '0' && ( ch ) <= '9' ) - -#define IS_PS_XDIGIT( ch ) \ - ( IS_PS_DIGIT( ( ch ) ) || \ - ( ( ch ) >= 'A' && ( ch ) <= 'F' ) || \ - ( ( ch ) >= 'a' && ( ch ) <= 'f' ) ) - -#define IS_PS_BASE85( ch ) ( ( ch ) >= '!' && ( ch ) <= 'u' ) - FT_END_HEADER #endif /* __PSCONV_H__ */ diff --git a/src/psaux/psobjs.c b/src/psaux/psobjs.c index 25b0bc632..5f7037f7e 100644 --- a/src/psaux/psobjs.c +++ b/src/psaux/psobjs.c @@ -698,6 +698,9 @@ } + /* NB: `tokens' can be NULL if we only want to count */ + /* the number of array elements */ + FT_LOCAL_DEF( void ) ps_parser_to_token_array( PS_Parser parser, T1_Token tokens, @@ -733,7 +736,7 @@ if ( !token.type ) break; - if ( cur < limit ) + if ( tokens != NULL && cur < limit ) *cur = token; cur++; @@ -748,6 +751,8 @@ /* first character must be a delimiter or a part of a number */ + /* NB: `coords' can be NULL if we just want to skip the */ + /* array; in this case we ignore `max_coords' */ static FT_Int ps_tocoordarray( FT_Byte* *acur, @@ -780,21 +785,26 @@ /* now, read the coordinates */ while ( cur < limit ) { + FT_Short dummy; + + /* skip whitespace in front of data */ skip_spaces( &cur, limit ); if ( cur >= limit ) goto Exit; - if ( count >= max_coords ) + if ( coords != NULL && count >= max_coords ) break; - if ( c == ender ) + if ( *cur == ender ) { cur++; break; } - coords[count] = + /* call PS_Conv_ToFixed() even if coords == NULL */ + /* to properly parse number at `cur' */ + *( coords != NULL ? &coords[count] : &dummy ) = (FT_Short)( PS_Conv_ToFixed( &cur, limit, 0 ) >> 16 ); count++; @@ -809,6 +819,8 @@ /* first character must be a delimiter or a part of a number */ + /* NB: `values' can be NULL if we just want to skip the */ + /* array in this case we ignore `max_values' */ static FT_Int ps_tofixedarray( FT_Byte* *acur, @@ -842,21 +854,27 @@ /* now, read the values */ while ( cur < limit ) { + FT_Fixed dummy; + + /* skip whitespace in front of data */ skip_spaces( &cur, limit ); if ( cur >= limit ) goto Exit; - if ( count >= max_values ) + if ( values != NULL && count >= max_values ) break; - if ( c == ender ) + if ( *cur == ender ) { cur++; break; } - values[count] = PS_Conv_ToFixed( &cur, limit, power_ten ); + /* call PS_Conv_ToFixed() even if coords == NULL */ + /* to properly parse number at `cur' */ + *( values != NULL ? &values[count] : &dummy ) = + PS_Conv_ToFixed( &cur, limit, power_ten ); count++; if ( !ender ) diff --git a/src/psaux/t1decode.c b/src/psaux/t1decode.c index 574527c57..bc799e489 100644 --- a/src/psaux/t1decode.c +++ b/src/psaux/t1decode.c @@ -348,6 +348,14 @@ hinter = (T1_Hints_Funcs)builder->hints_funcs; + /* a font that reads BuildCharArray without setting */ + /* its values first is buggy, but ... */ + if ( decoder->face->len_buildchar > 0 ) + memset( &decoder->buildchar[0], + 0, + sizeof( decoder->buildchar[0] ) * + decoder->face->len_buildchar ); + FT_TRACE4(( "\nStart charstring\n" )); zone->base = charstring_base; @@ -582,12 +590,9 @@ subr_no = (FT_Int)top[1]; arg_cnt = (FT_Int)top[0]; - if ( arg_cnt > top - decoder->stack ) - goto Stack_Underflow; - /***********************************************************/ /* */ - /* remove all operands to callsubr from the stack */ + /* remove all operands to callothersubr from the stack */ /* */ /* for handled othersubrs, where we know the number of */ /* arguments, we increase the stack by the value of */ @@ -596,11 +601,30 @@ /* for unhandled othersubrs the following pops adjust the */ /* stack pointer as necessary */ + if ( arg_cnt > top - decoder->stack ) + goto Stack_Underflow; + top -= arg_cnt; known_othersubr_result_cnt = 0; unknown_othersubr_result_cnt = 0; + /* XXX TODO: The checks to `arg_count == ' */ + /* might not be correct; an othersubr expects a certain */ + /* number of operands on the PostScript stack (as opposed */ + /* to the T1 stack) but it doesn't have to put them there */ + /* by itself; previous othersubrs might have left the */ + /* operands there if they were not followed by an */ + /* appropriate number of pops */ + /* */ + /* On the other hand, Adobe Reader 7.0.8 for Linux doesn't */ + /* accept a font that contains charstrings like */ + /* */ + /* 100 200 2 20 callothersubr */ + /* 300 1 20 callothersubr pop */ + /* */ + /* Perhaps this is the reason why BuildCharArray exists. */ + switch ( subr_no ) { case 1: /* start flex feature */ @@ -726,6 +750,158 @@ break; } +#ifdef CAN_HANDLE_NON_INTEGRAL_T1_OPERANDS + + /* We cannot yet enable these since currently */ + /* our T1 stack stores integers which lack the */ + /* precision to express the values */ + + case 19: + /* 1 19 callothersubr */ + /* => replace elements starting from index cvi( ) */ + /* of BuildCharArray with WeightVector */ + { + FT_Int idx; + PS_Blend blend = decoder->blend; + + + if ( arg_cnt != 1 || blend == NULL ) + goto Unexpected_OtherSubr; + + idx = top[0]; + + if ( idx < 0 || + idx + blend->num_designs > decoder->face->len_buildchar ) + goto Unexpected_OtherSubr; + + memcpy( &decoder->buildchar[idx], + blend->weight_vector, + blend->num_designs * + sizeof( blend->weight_vector[ 0 ] ) ); + } + break; + + case 20: + /* 2 20 callothersubr pop */ + /* ==> push + onto T1 stack */ + if ( arg_cnt != 2 ) + goto Unexpected_OtherSubr; + + top[0] += top[1]; /* XXX (over|under)flow */ + + known_othersubr_result_cnt = 1; + break; + + case 21: + /* 2 21 callothersubr pop */ + /* ==> push - onto T1 stack */ + if ( arg_cnt != 2 ) + goto Unexpected_OtherSubr; + + top[0] -= top[1]; /* XXX (over|under)flow */ + + known_othersubr_result_cnt = 1; + break; + + case 22: + /* 2 22 callothersubr pop */ + /* ==> push * onto T1 stack */ + if ( arg_cnt != 2 ) + goto Unexpected_OtherSubr; + + top[0] *= top[1]; /* XXX (over|under)flow */ + + known_othersubr_result_cnt = 1; + break; + + case 23: + /* 2 23 callothersubr pop */ + /* ==> push / onto T1 stack */ + if ( arg_cnt != 2 || top[1] == 0 ) + goto Unexpected_OtherSubr; + + top[0] /= top[1]; /* XXX (over|under)flow */ + + known_othersubr_result_cnt = 1; + break; + +#endif /* CAN_HANDLE_NON_INTEGRAL_T1_OPERANDS */ + + case 24: + /* 2 24 callothersubr */ + /* => set BuildCharArray[cvi( )] = */ + { + FT_Int idx; + PS_Blend blend = decoder->blend; + + if ( arg_cnt != 2 || blend == NULL ) + goto Unexpected_OtherSubr; + + idx = top[1]; + + if ( idx < 0 || (FT_UInt) idx >= decoder->face->len_buildchar ) + goto Unexpected_OtherSubr; + + decoder->buildchar[idx] = top[0]; + } + break; + + case 25: + /* 1 25 callothersubr pop */ + /* => push BuildCharArray[cvi( idx )] */ + /* onto T1 stack */ + { + FT_Int idx; + PS_Blend blend = decoder->blend; + + if ( arg_cnt != 1 || blend == NULL ) + goto Unexpected_OtherSubr; + + idx = top[0]; + + if ( idx < 0 || (FT_UInt) idx >= decoder->face->len_buildchar ) + goto Unexpected_OtherSubr; + + top[0] = decoder->buildchar[idx]; + } + + known_othersubr_result_cnt = 1; + break; + +#if 0 + case 26: + /* mark ==> set BuildCharArray[cvi( )] = , */ + /* leave mark on T1 stack */ + /* ==> set BuildCharArray[cvi( )] = */ + XXX who has left his mark on the (PostScript) stack ?; + break; +#endif + + case 27: + /* 4 27 callothersubr pop */ + /* ==> push onto T1 stack if <= , */ + /* otherwise push */ + if ( arg_cnt != 4 ) + goto Unexpected_OtherSubr; + + if ( top[2] > top[3] ) + top[0] = top[1]; + + known_othersubr_result_cnt = 1; + break; + +#ifdef CAN_HANDLE_NON_INTEGRAL_T1_OPERANDS + case 28: + /* 0 28 callothersubr pop */ + /* => push random value from interval [0, 1) onto stack */ + if ( arg_cnt != 0 ) + goto Unexpected_OtherSubr; + + top[0] = FT_rand(); + known_othersubr_result_cnt = 1; + break; +#endif + default: FT_ERROR(( "t1_decoder_parse_charstrings: " "unknown othersubr [%d %d], wish me luck!\n", @@ -805,8 +981,30 @@ /* add current outline to the glyph slot */ FT_GlyphLoader_Add( builder->loader ); + FT_TRACE4(( "\n" )); + + /* the compiler should optimize away this empty loop but ... */ + +#ifdef FT_DEBUG_LEVEL_TRACE + + if ( decoder->face->len_buildchar > 0 ) + { + FT_UInt i; + + + FT_TRACE4(( "BuildCharArray = [ " )); + + for ( i = 0; i < decoder->face->len_buildchar; ++i ) + FT_TRACE4(( "%d ", decoder->buildchar[ i ] )); + + FT_TRACE4(( "]\n" )); + } + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + FT_TRACE4(( "\n" )); + /* return now! */ - FT_TRACE4(( "\n\n" )); return PSaux_Err_Ok; case op_hsbw: @@ -1225,6 +1423,10 @@ FT_Render_Mode hint_mode, T1_Decoder_Callback parse_callback ) { + FT_Error error; + FT_Memory memory = face->memory; + + FT_MEM_ZERO( decoder, sizeof ( *decoder ) ); /* retrieve PSNames interface from list of current modules */ @@ -1243,6 +1445,18 @@ decoder->psnames = psnames; } + decoder->face = (T1_Face) face; + + if ( decoder->face->len_buildchar > 0 ) + { + if ( FT_NEW_ARRAY( decoder->buildchar, decoder->face->len_buildchar ) ) + { + FT_ERROR(( "t1_decoder_init: " )); + FT_ERROR(( "cannot allocate memory for BuildCharArray\n" )); + return error; + } + } + t1_builder_init( &decoder->builder, face, size, slot, hinting ); decoder->num_glyphs = (FT_UInt)face->num_glyphs; @@ -1261,7 +1475,12 @@ FT_LOCAL_DEF( void ) t1_decoder_done( T1_Decoder decoder ) { + FT_Memory memory = decoder->face->root.memory; + + t1_builder_done( &decoder->builder ); + + FT_FREE( decoder->buildchar ); } diff --git a/src/type1/t1load.c b/src/type1/t1load.c index 38d905500..635e16c5a 100644 --- a/src/type1/t1load.c +++ b/src/type1/t1load.c @@ -107,6 +107,8 @@ if ( FT_NEW( blend ) ) goto Exit; + blend->num_default_design_vector = 0; + face->blend = blend; } @@ -877,6 +879,18 @@ } + /* e.g., /BuildCharArray [0 0 0 0 0 0 0 0] def */ + /* we're only interested in the number of array elements */ + static void + parse_buildchar( T1_Face face, + T1_Loader loader ) + { + face->len_buildchar = T1_ToFixedArray( &loader->parser, 0, NULL, 0 ); + + return; + } + + #endif /* T1_CONFIG_OPTION_NO_MM_SUPPORT */ @@ -950,6 +964,26 @@ } break; + case T1_FIELD_LOCATION_LOADER: + dummy_object = loader; + objects = &dummy_object; + max_objects = 0; + break; + + case T1_FIELD_LOCATION_FACE: + dummy_object = face; + objects = &dummy_object; + max_objects = 0; + break; + +#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT + case T1_FIELD_LOCATION_BLEND: + dummy_object = face->blend; + objects = &dummy_object; + max_objects = 0; + break; +#endif + default: dummy_object = &face->type1; objects = &dummy_object; @@ -969,6 +1003,16 @@ } + static void + parse_private( T1_Face face, + T1_Loader loader ) + { + FT_UNUSED( face ); + + loader->keywords_encountered |= T1_PRIVATE; + } + + static int is_space( FT_Byte c ) { @@ -1681,12 +1725,14 @@ T1_FIELD_CALLBACK( "Encoding", parse_encoding ) T1_FIELD_CALLBACK( "Subrs", parse_subrs ) T1_FIELD_CALLBACK( "CharStrings", parse_charstrings ) + T1_FIELD_CALLBACK( "Private", parse_private ) #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT T1_FIELD_CALLBACK( "BlendDesignPositions", parse_blend_design_positions ) T1_FIELD_CALLBACK( "BlendDesignMap", parse_blend_design_map ) T1_FIELD_CALLBACK( "BlendAxisTypes", parse_blend_axis_types ) T1_FIELD_CALLBACK( "WeightVector", parse_weight_vector ) + T1_FIELD_CALLBACK( "BuildCharArray", parse_buildchar ) #endif { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0 } @@ -1701,8 +1747,7 @@ parse_dict( T1_Face face, T1_Loader loader, FT_Byte* base, - FT_Long size, - FT_Byte* keyword_flags ) + FT_Long size ) { T1_Parser parser = &loader->parser; FT_Byte *limit, *start_binary = NULL; @@ -1724,31 +1769,23 @@ cur = parser->root.cursor; - /* cur[5] must be a token delimiter; */ - /* eexec encryption is optional, so look for `eexec' */ - if ( *cur == 'e' && cur + 5 < limit && - ft_strncmp( (char*)cur, "eexec", 5 ) == 0 ) + /* look for `eexec' */ + if ( IS_PS_TOKEN( cur, limit, "eexec" ) ) break; - /* cur[9] must be a token delimiter; */ /* look for `closefile' which ends the eexec section */ - else if ( *cur == 'c' && cur + 9 < limit && - ft_strncmp( (char*)cur, "closefile", 9 ) == 0 ) + else if ( IS_PS_TOKEN( cur, limit, "closefile" ) ) break; -#ifdef TO_BE_DONE /* in a synthetic font the base font starts after a */ /* `FontDictionary' token that is placed after a Private dict */ - - /* cur[13] must be a token delimiter */ - else if ( *cur == 'F' && cur + 13 < limit && - ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 ) + else if ( IS_PS_TOKEN( cur, limit, "FontDirectory" ) ) { - if ( loader->private_encountered ) - loader->fontdir_after_private = 1; + if ( loader->keywords_encountered & T1_PRIVATE ) + loader->keywords_encountered |= + T1_FONTDIR_AFTER_PRIVATE; parser->root.cursor += 13; } -#endif /* check whether we have an integer */ else if ( ft_isdigit( *cur ) ) @@ -1807,8 +1844,7 @@ if ( len > 0 && len < 22 && parser->root.cursor < limit ) { /* now compare the immediate name to the keyword table */ - T1_Field keyword = (T1_Field)t1_keywords; - FT_Byte* keyword_flag = keyword_flags; + T1_Field keyword = (T1_Field)t1_keywords; for (;;) @@ -1824,21 +1860,28 @@ len == (FT_PtrDist)ft_strlen( (const char *)name ) && ft_memcmp( cur, name, len ) == 0 ) { - /* We found it -- run the parsing callback! */ - /* We only record the first instance of any */ - /* field to deal adequately with synthetic */ - /* fonts; /Subrs and /CharStrings are */ - /* handled specially. */ - if ( keyword_flag[0] == 0 || - ft_strcmp( (const char*)name, "Subrs" ) == 0 || - ft_strcmp( (const char*)name, "CharStrings" ) == 0 ) + /* We found it -- run the parsing callback! */ + /* We record every instance of every field */ + /* (until we reach the base font of a */ + /* synthetic font) to deal adequately with */ + /* multiple master fonts; this is also */ + /* necessary because later PostScript */ + /* definitions override earlier ones */ + + /* Once we encounter `FontDirectory' after */ + /* `/Private', we know that this is a synthetic */ + /* font; except for `/CharStrings' we are not */ + /* interested in anything that follows this */ + /* `FontDirectory' */ + + if ( !( loader->keywords_encountered & + T1_FONTDIR_AFTER_PRIVATE ) || + ft_strcmp((const char*)name, "CharStrings") == 0 ) { parser->root.error = t1_load_keyword( face, loader, keyword ); - if ( parser->root.error == T1_Err_Ok ) - keyword_flag[0] = 1; - else + if ( parser->root.error != T1_Err_Ok ) { if ( FT_ERROR_BASE( parser->root.error ) == FT_Err_Ignore ) parser->root.error = T1_Err_Ok; @@ -1850,7 +1893,6 @@ } keyword++; - keyword_flag++; } } @@ -1883,12 +1925,13 @@ loader->num_chars = 0; /* initialize the tables -- simply set their `init' field to 0 */ - loader->encoding_table.init = 0; - loader->charstrings.init = 0; - loader->glyph_names.init = 0; - loader->subrs.init = 0; - loader->swap_table.init = 0; - loader->fontdata = 0; + loader->encoding_table.init = 0; + loader->charstrings.init = 0; + loader->glyph_names.init = 0; + loader->subrs.init = 0; + loader->swap_table.init = 0; + loader->fontdata = 0; + loader->keywords_encountered = 0; } @@ -1918,7 +1961,6 @@ T1_Font type1 = &face->type1; PS_Private priv = &type1->private_dict; FT_Error error; - FT_Byte keyword_flags[T1_FIELD_COUNT]; PSAux_Service psaux = (PSAux_Service)face->psaux; @@ -1926,6 +1968,10 @@ t1_init_loader( &loader, face ); /* default values */ + face->ndv_idx = -1; + face->cdv_idx = -1; + face->len_buildchar = 0; + priv->blue_shift = 7; priv->blue_fuzz = 1; priv->lenIV = 4; @@ -1940,16 +1986,8 @@ if ( error ) goto Exit; - { - FT_UInt n; - - - for ( n = 0; n < T1_FIELD_COUNT; n++ ) - keyword_flags[n] = 0; - } - - error = parse_dict( face, &loader, parser->base_dict, parser->base_len, - keyword_flags ); + error = parse_dict( face, &loader, + parser->base_dict, parser->base_len ); if ( error ) goto Exit; @@ -1957,9 +1995,8 @@ if ( error ) goto Exit; - error = parse_dict( face, &loader, parser->private_dict, - parser->private_len, - keyword_flags ); + error = parse_dict( face, &loader, + parser->private_dict, parser->private_len ); if ( error ) goto Exit; @@ -1968,6 +2005,19 @@ #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT + if ( face->blend && + face->blend->num_default_design_vector != 0 && + face->blend->num_default_design_vector != face->blend->num_axis ) + { + /* we don't use it currently so just warn, reset, and ignore */ + FT_ERROR(( "T1_Open_Face(): /DesignVector contains %u entries " + "while there are %u axes.\n", + face->blend->num_default_design_vector, + face->blend->num_axis )); + + face->blend->num_default_design_vector = 0; + } + /* the following can happen for MM instances; we then treat the */ /* font as a normal PS font */ if ( face->blend && diff --git a/src/type1/t1load.h b/src/type1/t1load.h index 9823f53e0..717ae6138 100644 --- a/src/type1/t1load.h +++ b/src/type1/t1load.h @@ -4,7 +4,7 @@ /* */ /* Type 1 font loader (specification). */ /* */ -/* Copyright 1996-2001, 2002, 2004 by */ +/* Copyright 1996-2001, 2002, 2004, 2006 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -48,9 +48,18 @@ FT_BEGIN_HEADER PS_TableRec subrs; FT_Bool fontdata; + FT_UInt keywords_encountered; /* T1_LOADER_ENCOUNTERED_XXX */ + } T1_LoaderRec, *T1_Loader; + /* treatment of some keywords differs depending on whether */ + /* they preceed or follow certain other keywords */ + +#define T1_PRIVATE ( 1 << 0 ) +#define T1_FONTDIR_AFTER_PRIVATE ( 1 << 1 ) + + FT_LOCAL( FT_Error ) T1_Open_Face( T1_Face face ); diff --git a/src/type1/t1tokens.h b/src/type1/t1tokens.h index a3cc952e0..bd27361fb 100644 --- a/src/type1/t1tokens.h +++ b/src/type1/t1tokens.h @@ -4,7 +4,7 @@ /* */ /* Type 1 tokenizer (specification). */ /* */ -/* Copyright 1996-2001, 2002, 2003, 2004 by */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2006 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -73,6 +73,7 @@ T1_FIELD_NUM ( "FontType", font_type ) T1_FIELD_FIXED( "StrokeWidth", stroke_width ) + #undef FT_STRUCTURE #define FT_STRUCTURE FT_BBox #undef T1CODE @@ -81,4 +82,26 @@ T1_FIELD_BBOX("FontBBox", xMin ) +#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT + +#undef FT_STRUCTURE +#define FT_STRUCTURE T1_FaceRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_FACE + + T1_FIELD_NUM ( "NDV", ndv_idx ) + T1_FIELD_NUM ( "CDV", cdv_idx ) + + +#undef FT_STRUCTURE +#define FT_STRUCTURE PS_BlendRec +#undef T1CODE +#define T1CODE T1_FIELD_LOCATION_BLEND + + T1_FIELD_NUM_TABLE( "DesignVector", default_design_vector, T1_MAX_MM_DESIGNS ) + + +#endif /* T1_CONFIG_OPTION_NO_MM_SUPPORT */ + + /* END */