From 1c9a1cab3f6f5d3387094726e5958a29afd2e2c2 Mon Sep 17 00:00:00 2001 From: David Turner Date: Wed, 24 May 2000 21:12:02 +0000 Subject: [PATCH] important modifications to the Type1z driver these are used to prepare for multiple master fonts --- include/freetype/internal/t1types.h | 4 +- include/freetype/t1tables.h | 57 ++-- src/type1/t1hinter.c | 4 +- src/type1/t1objs.c | 2 +- src/type1z/t1load.c | 507 +++++++++++++++++++++------- src/type1z/t1load.h | 1 + src/type1z/t1objs.c | 2 +- src/type1z/t1parse.c | 363 ++++++++++++++++++-- src/type1z/t1parse.h | 131 ++++++- src/type1z/t1tokens.h | 48 ++- 10 files changed, 916 insertions(+), 203 deletions(-) diff --git a/include/freetype/internal/t1types.h b/include/freetype/internal/t1types.h index e4eaa354e..c1cf24135 100644 --- a/include/freetype/internal/t1types.h +++ b/include/freetype/internal/t1types.h @@ -29,7 +29,6 @@ #endif - /*************************************************************************/ /*************************************************************************/ /*************************************************************************/ @@ -392,6 +391,9 @@ FT_CharMap charmaps[2]; PS_Unicodes unicode_map; + /* support for multiple masters */ + T1_Blend* blend; + } T1_FaceRec; diff --git a/include/freetype/t1tables.h b/include/freetype/t1tables.h index a25d7f25a..ef688ef77 100644 --- a/include/freetype/t1tables.h +++ b/include/freetype/t1tables.h @@ -84,8 +84,8 @@ FT_Int blue_shift; FT_Int blue_fuzz; - FT_UShort standard_width; - FT_UShort standard_height; + FT_UShort standard_width[1]; + FT_UShort standard_height[1]; FT_Byte num_snap_widths; FT_Byte num_snap_heights; @@ -116,10 +116,8 @@ */ typedef enum { - t1_blend_none = 0, - /* required fields in a FontInfo blend dictionary */ - t1_blend_underline_position, + t1_blend_underline_position = 0, t1_blend_underline_thickness, t1_blend_italic_angle, @@ -139,38 +137,35 @@ /* never remove */ t1_blend_max - } T1_Flags; + } T1_Blend_Flags; + /* maximum number of multiple-masters designs, per-se the spec */ + #define T1_MAX_MM_DESIGNS 16 + #define T1_MAX_MM_AXIS 4 - typedef struct T1_Blend_Pos + /* this structure is used to store the BlendDesignMap entry for an axis */ + typedef struct T1_DesignMap_ { - FT_Fixed min; - FT_Fixed max; + FT_Byte num_points; + FT_Fixed* design_points; + FT_Fixed* blend_points; + + } T1_DesignMap; - } T1_Blend_Pos; - - /************************************************************************* - * - * - * T1_Blend - * - * - * A structure used to describe the multiple-master fonts information - * of a given Type 1 font. - * - */ typedef struct T1_Blend_ { - FT_Int num_axis; - FT_String* axis_types[4]; - - /* XXXX : add /BlendDesignMap entries */ - - FT_Int num_blends; - T1_Flags* flags [17]; - T1_Private* privates [17]; - T1_FontInfo* fontinfos[17]; - + FT_UInt num_designs; + FT_UInt num_axis; + + FT_String* axis_names[ T1_MAX_MM_AXIS ]; + FT_Fixed* design_pos[ T1_MAX_MM_DESIGNS ]; + T1_DesignMap design_map[ T1_MAX_MM_AXIS ]; + + T1_FontInfo* font_infos[ T1_MAX_MM_DESIGNS+1 ]; + T1_Private* privates [ T1_MAX_MM_DESIGNS+1 ]; + + FT_ULong blend_bitflags; + } T1_Blend; diff --git a/src/type1/t1hinter.c b/src/type1/t1hinter.c index d7dd8945b..970a07cda 100644 --- a/src/type1/t1hinter.c +++ b/src/type1/t1hinter.c @@ -291,7 +291,7 @@ /* start with horizontal snap zones */ direction = 0; - standard_width = priv->standard_width; + standard_width = priv->standard_width[0]; n_zones = priv->num_snap_widths; base_zone = hints->snap_widths; orgs = priv->stem_snap_widths; @@ -458,7 +458,7 @@ /* continue with vertical snap zone */ direction++; - standard_width = priv->standard_height; + standard_width = priv->standard_height[0]; n_zones = priv->num_snap_heights; base_zone = hints->snap_heights; orgs = priv->stem_snap_heights; diff --git a/src/type1/t1objs.c b/src/type1/t1objs.c index b272a9787..289277452 100644 --- a/src/type1/t1objs.c +++ b/src/type1/t1objs.c @@ -330,7 +330,7 @@ /* now compute the maximum advance width */ - root->max_advance_width = type1->private_dict.standard_width; + root->max_advance_width = type1->private_dict.standard_width[0]; /* compute max advance width for proportional fonts */ if (!type1->font_info.is_fixed_pitch) diff --git a/src/type1z/t1load.c b/src/type1z/t1load.c index e53e9149a..86c40e965 100644 --- a/src/type1z/t1load.c +++ b/src/type1z/t1load.c @@ -70,82 +70,312 @@ #undef FT_COMPONENT #define FT_COMPONENT trace_t1load + /***************************************************************************/ + /***************************************************************************/ + /***** *****/ + /***** MULTIPLE MASTERS SUPPORT *****/ + /***** *****/ + /***************************************************************************/ + /***************************************************************************/ + + static T1_Error t1_allocate_blend( T1_Face face, + T1_UInt num_designs, + T1_UInt num_axis ) + { + T1_Blend* blend; + FT_Memory memory = face->root.memory; + T1_Error error = 0; + + blend = face->blend; + if (!blend) + { + if ( ALLOC( blend, sizeof(*blend) ) ) + goto Exit; + + face->blend = blend; + } + + /* allocate design data if needed */ + if (num_designs > 0) + { + if (blend->num_designs == 0) + { + /* allocate the blend "private" and "font_info" dictionaries */ + if ( ALLOC_ARRAY( blend->font_infos[1], num_designs, T1_FontInfo ) || + ALLOC_ARRAY( blend->privates[1], num_designs, T1_Private ) ) + goto Exit; + + blend->font_infos[0] = &face->type1.font_info; + blend->privates [0] = &face->type1.private_dict; + blend->num_designs = num_designs; + } + else if (blend->num_designs != num_designs) + goto Fail; + } + + /* allocate axis data if needed */ + if (num_axis > 0) + { + if (blend->num_axis != 0 && blend->num_axis != num_axis) + goto Fail; + + blend->num_axis = num_axis; + } + + /* allocate the blend design pos table if needed */ + num_designs = blend->num_designs; + num_axis = blend->num_axis; + if ( num_designs && num_axis && blend->design_pos[0] == 0) + { + FT_UInt n; + + if ( ALLOC_ARRAY( blend->design_pos[0], num_designs*num_axis, FT_Fixed ) ) + goto Exit; + + for ( n = 1; n < num_designs; n++ ) + blend->design_pos[n] = blend->design_pos[0] + num_axis*n; + } + + Exit: + return error; + Fail: + error = -1; + goto Exit; + } + + + static void t1_done_blend( T1_Face face ) + { + FT_Memory memory = face->root.memory; + T1_Blend* blend = face->blend; + + if (blend) + { + T1_UInt num_designs = blend->num_designs; + T1_UInt num_axis = blend->num_axis; + T1_UInt n; + + /* release design pos table */ + FREE( blend->design_pos[0] ); + for ( n = 1; n < num_designs; n++ ) + blend->design_pos[n] = 0; + + /* release blend "private" and "font info" dictionaries */ + FREE( blend->privates[1] ); + FREE( blend->font_infos[1] ); + for ( n = 0; n < num_designs; n++ ) + { + blend->privates [n] = 0; + blend->font_infos[n] = 0; + } + + /* release axis names */ + for ( n = 0; n < num_axis; n++ ) + FREE( blend->axis_names[n] ); + + /* release design map */ + for ( n = 0; n < num_axis; n++ ) + { + T1_DesignMap* dmap = blend->design_map + n; + FREE( dmap->design_points ); + FREE( dmap->blend_points ); + dmap->num_points = 0; + } + + FREE( face->blend ); + } + } + + /***************************************************************************/ + /***************************************************************************/ + /***** *****/ + /***** TYPE 1 SYMBOL PARSING *****/ + /***** *****/ + /***************************************************************************/ + /***************************************************************************/ + + /********************************************************************* + * + * First of all, define the token field static variables. This is + * a set of T1_Field_Rec variables used later.. + * + *********************************************************************/ + +#define T1_NEW_STRING( _name, _field ) \ + static const T1_Field_Rec t1_field_ ## _field = T1_FIELD_STRING( T1TYPE, _field ); + +#define T1_NEW_BOOL( _name, _field ) \ + static const T1_Field_Rec t1_field_ ## _field = T1_FIELD_BOOL( T1TYPE, _field ); + +#define T1_NEW_NUM( _name, _field ) \ + static const T1_Field_Rec t1_field_ ## _field = T1_FIELD_NUM( T1TYPE, _field ); + +#define T1_NEW_FIXED( _name, _field ) \ + static const T1_Field_Rec t1_field_ ## _field = T1_FIELD_FIXED( T1TYPE, _field, _power ); + +#define T1_NEW_NUM_TABLE( _name, _field, _max, _count ) \ + static const T1_Field_Rec t1_field_ ## _field = T1_FIELD_NUM_ARRAY( T1TYPE, _field, _count, _max ); + +#define T1_NEW_FIXED_TABLE( _name, _field, _max, _count ) \ + static const T1_Field_Rec t1_field_ ## _field = T1_FIELD_FIXED_ARRAY( T1TYPE, _field, _count, _max ); + +#define T1_NEW_NUM_TABLE2( _name, _field, _max ) \ + static const T1_Field_Rec t1_field_ ## _field = T1_FIELD_NUM_ARRAY2( T1TYPE, _field, _max ); + +#define T1_NEW_FIXED_TABLE2( _name, _field, _max ) \ + static const T1_Field_Rec t1_field_ ## _field = T1_FIELD_FIXED_ARRAY2( T1TYPE, _field, _max ); + + +#define T1_FONTINFO_STRING(n,f) T1_NEW_STRING(n,f) +#define T1_FONTINFO_NUM(n,f) T1_NEW_NUM(n,f) +#define T1_FONTINFO_BOOL(n,f) T1_NEW_BOOL(n,f) +#define T1_PRIVATE_NUM(n,f) T1_NEW_NUM(n,f) +#define T1_PRIVATE_FIXED(n,f) T1_NEW_FIXED(n,f) +#define T1_PRIVATE_NUM_TABLE(n,f,m,c) T1_NEW_NUM_TABLE(n,f,m,c) +#define T1_PRIVATE_NUM_TABLE2(n,f,m) T1_NEW_NUM_TABLE2(n,f,m) +#define T1_TOPDICT_NUM(n,f) T1_NEW_NUM(n,f) +#define T1_TOPDICT_NUM_FIXED2(n,f,m) T1_NEW_FIXED_TABLE2(n,f,m) + +/* including this file defines all field variables */ +#include + + /********************************************************************* + * + * Second, define the keyword variables. This is a set of T1_KeyWord + * structures used to model the way each keyword is "loaded".. + * + *********************************************************************/ + typedef void (*T1_Parse_Func)( T1_Face face, T1_Loader* loader ); + typedef enum T1_KeyWord_Type_ + { + t1_keyword_callback = 0, + t1_keyword_field, + t1_keyword_field_table + + } T1_KeyWord_Type; + + typedef enum T1_KeyWord_Location_ + { + t1_keyword_type1 = 0, + t1_keyword_font_info, + t1_keyword_private + + } T1_KeyWord_Location; + typedef struct T1_KeyWord_ { - const char* name; - T1_Parse_Func parsing; + const char* name; + T1_KeyWord_Type type; + T1_KeyWord_Location location; + T1_Parse_Func parsing; + const T1_Field_Rec* field; } T1_KeyWord; - /* some handy macros used to easily define parsing callback functions */ - /* each callback is in charge of loading a value and storing it in a */ - /* given field of the Type 1 face.. */ -#define PARSE_(x) static void FT_XCAT(parse_,x) ( T1_Face face, T1_Loader* loader ) +#define T1_KEYWORD_CALLBACK( name, callback ) \ + { name, t1_keyword_callback, t1_keyword_type1, callback, 0 } -#define FIELD FACE.x +#define T1_KEYWORD_TYPE1( name, f ) \ + { name, t1_keyword_field, t1_keyword_type1, 0, &t1_field_ ## f } + +#define T1_KEYWORD_FONTINFO( name, f ) \ + { name, t1_keyword_field, t1_keyword_font_info, 0, &t1_field_ ## f } -#define PARSE_STRING(s,x) PARSE_(x) \ - { \ - FACE.x = T1_ToString(&loader->parser); \ - FT_TRACE2(( "type1.parse_%s: \"%s\"\n", #x, FACE.x )); \ +#define T1_KEYWORD_PRIVATE( name, f ) \ + { name, t1_keyword_field, t1_keyword_private, 0, &t1_field_ ## f } + +#define T1_KEYWORD_FONTINFO_TABLE( name, f ) \ + { name, t1_keyword_field_table, t1_keyword_font_info, 0, &t1_field_ ## f } + +#define T1_KEYWORD_PRIVATE_TABLE( name, f ) \ + { name, t1_keyword_field_table, t1_keyword_private, 0, &t1_field_ ## f } + +#undef T1_FONTINFO_STRING +#undef T1_FONTINFO_NUM +#undef T1_FONTINFO_BOOL +#undef T1_PRIVATE_NUM +#undef T1_PRIVATE_FIXED +#undef T1_PRIVATE_NUM_TABLE +#undef T1_PRIVATE_NUM_TABLE2 +#undef T1_TOPDICT_NUM +#undef T1_TOPDICT_NUM_FIXED2 + +#define T1_FONTINFO_STRING(n,f) T1_KEYWORD_FONTINFO(n,f), +#define T1_FONTINFO_NUM(n,f) T1_KEYWORD_FONTINFO(n,f), +#define T1_FONTINFO_BOOL(n,f) T1_KEYWORD_FONTINFO(n,f), +#define T1_PRIVATE_NUM(n,f) T1_KEYWORD_PRIVATE(n,f), +#define T1_PRIVATE_FIXED(n,f) T1_KEYWORD_PRIVATE(n,f), +#define T1_PRIVATE_NUM_TABLE(n,f,m,c) T1_KEYWORD_PRIVATE_TABLE(n,f), +#define T1_PRIVATE_NUM_TABLE2(n,f,m) T1_KEYWORD_PRIVATE_TABLE(n,f), +#define T1_TOPDICT_NUM(n,f) T1_KEYWORD_TYPE1(n,f), +#define T1_TOPDICT_NUM_FIXED2(n,f,m) T1_KEYWORD_TYPE1(n,f), + + + static T1_Error t1_load_keyword( T1_Face face, + T1_Loader* loader, + T1_KeyWord* keyword ) + { + T1_Error error; + void* dummy_object; + void** objects; + T1_UInt max_objects; + T1_Blend* blend = face->blend; + + /* if the keyword has a dedicated callback, call it */ + if (keyword->type == t1_keyword_callback) + { + keyword->parsing( face, loader ); + error = loader->parser.error; + goto Exit; + } + + /* now, the keyword is either a simple field, or a table of fields */ + /* we are now going to take care of it.. */ + switch (keyword->location) + { + case t1_keyword_font_info: + { + dummy_object = &face->type1.font_info; + objects = &dummy_object; + max_objects = 0; + if (blend) + { + objects = (void**)blend->font_infos; + max_objects = blend->num_designs; + } } - -#define PARSE_NUM(s,x,t) PARSE_(x) \ - { \ - FACE.x = (t)T1_ToInt(&loader->parser); \ - FT_TRACE2(( "type1.parse_%s: \"%d\"\n", #x, FACE.x )); \ + break; + + case t1_keyword_private: + { + dummy_object = &face->type1.private_dict; + objects = &dummy_object; + max_objects = 0; + if (blend) + { + objects = (void**)blend->privates; + max_objects = blend->num_designs; + } } - -#define PARSE_INT(s,x) PARSE_(x) \ - { \ - FACE.x = T1_ToInt(&loader->parser); \ - FT_TRACE2(( "type1.parse_%s: \"%d\"\n", #x, FACE.x )); \ - } - -#define PARSE_BOOL(s,x) PARSE_(x) \ - { \ - FACE.x = T1_ToBool(&loader->parser); \ - FT_TRACE2(( "type1.parse_%s : \"%s\"\n", \ - #x, FACE.x ? "true" : "false" )); \ - } - -#define PARSE_FIXED(s,x) PARSE_(x) \ - { \ - FACE.x = T1_ToFixed(&loader->parser,3); \ - FT_TRACE2(( "type1.parse_%s: \"%f\"\n", #x, FACE.x/65536.0 )); \ - } - -#define PARSE_COORDS(s,c,m,x) PARSE_(x) \ - { \ - FACE.c = T1_ToCoordArray(&loader->parser, m, (T1_Short*)FACE.x ); \ - FT_TRACE2(( "type1.parse_%s\n", #x )); \ - } - -#define PARSE_FIXEDS(s,c,m,x) PARSE_(x) \ - { \ - FACE.c = T1_ToFixedArray(&loader->parser, m, (T1_Fixed*)FACE.x, 3 ); \ - FT_TRACE2(( "type1.parse_%s\n", #x )); \ - } - - -#define PARSE_COORDS2(s,m,x) PARSE_(x) \ - { \ - (void)T1_ToCoordArray( &loader->parser, m, (T1_Short*)&FACE.x ); \ - FT_TRACE2(( "type1.parse_%s\n", #x )); \ - } - -#define PARSE_FIXEDS2(s,m,x) PARSE_(x) \ - { \ - (void)T1_ToFixedArray(&loader->parser, m, (T1_Fixed*)&FACE.x, 3 ); \ - FT_TRACE2(( "type1.parse_%s\n", #x )); \ - } - - -/* define all parsing callbacks */ -#include + break; + + default: + dummy_object = &face->type1; + objects = &dummy_object; + max_objects = 0; + } + + if (keyword->type == t1_keyword_field_table) + error = T1_Load_Field_Table( &loader->parser, keyword->field, objects, max_objects, 0 ); + else + error = T1_Load_Field( &loader->parser, keyword->field, objects, max_objects, 0 ); + + Exit: + return error; + } static @@ -273,6 +503,22 @@ bbox->yMax = temp[3]; } + static + void parse_font_matrix( T1_Face face, T1_Loader* loader ) + { + T1_Parser* parser = &loader->parser; + FT_Matrix* matrix = &face->type1.font_matrix; + T1_Fixed temp[4]; + + (void)T1_ToFixedArray( parser, 4, temp, 3 ); + matrix->xx = temp[0]; + matrix->yx = temp[1]; + matrix->xy = temp[2]; + matrix->yy = temp[3]; + } + + + static void parse_encoding( T1_Face face, T1_Loader* loader ) { @@ -542,40 +788,21 @@ } -#undef PARSE_STRING -#undef PARSE_INT -#undef PARSE_NUM -#undef PARSE_BOOL -#undef PARSE_FIXED -#undef PARSE_COORDS -#undef PARSE_FIXEDS -#undef PARSE_COORDS2 -#undef PARSE_FIXEDS2 -#undef PARSE_ -#define PARSE_(s,x) { s, parse_##x }, - -#define PARSE_STRING(s,x) PARSE_(s,x) -#define PARSE_INT(s,x) PARSE_(s,x) -#define PARSE_NUM(s,x,t) PARSE_(s,x) -#define PARSE_BOOL(s,x) PARSE_(s,x) -#define PARSE_FIXED(s,x) PARSE_(s,x) -#define PARSE_COORDS(s,c,m,x) PARSE_(s,x) -#define PARSE_FIXEDS(s,c,m,x) PARSE_(s,x) -#define PARSE_COORDS2(s,m,x) PARSE_(s,x) -#define PARSE_FIXEDS2(s,m,x) PARSE_(s,x) static const T1_KeyWord t1_keywords[] = { -#include +#include + /* now add the special functions... */ - { "FontName", parse_font_name }, - { "FontBBox", parse_font_bbox }, - { "Encoding", parse_encoding }, - { "Subrs", parse_subrs }, - { "CharStrings", parse_charstrings }, - { 0, 0 } + T1_KEYWORD_CALLBACK( "FontName", parse_font_name ), + T1_KEYWORD_CALLBACK( "FontBBox", parse_font_bbox ), + T1_KEYWORD_CALLBACK( "FontMatrix", parse_font_matrix ), + T1_KEYWORD_CALLBACK( "Encoding", parse_encoding ), + T1_KEYWORD_CALLBACK( "Subrs", parse_subrs ), + T1_KEYWORD_CALLBACK( "CharStrings", parse_charstrings ), + T1_KEYWORD_CALLBACK( 0, 0 ) }; @@ -585,7 +812,7 @@ T1_Byte* base, T1_Long size ) { - T1_Parser* parser = &loader->parser; + T1_Parser* parser = &loader->parser; parser->cursor = base; parser->limit = base + size; @@ -597,8 +824,37 @@ for ( ;cur < limit; cur++ ) { + /* look for "FontDirectory", which causes problems on some fonts */ + if ( *cur == 'F' && cur+25 < limit && + strncmp( (char*)cur, "FontDirectory", 13 ) == 0 ) + { + T1_Byte* cur2; + + /* skip the "FontDirectory" keyword */ + cur += 13; + cur2 = cur; + + /* lookup the 'known' keyword */ + while (cur < limit && *cur != 'k' && strncmp( (char*)cur, "known", 5 ) ) + cur++; + + if (cur < limit) + { + T1_Token_Rec token; + + /* skip the "known" keyword and the token following it */ + cur += 5; + loader->parser.cursor = cur; + T1_ToToken( &loader->parser, &token ); + + /* if the last token was an array, skip it !! */ + if (token.type == t1_token_array) + cur2 = parser->cursor; + } + cur = cur2; + } /* look for immediates */ - if (*cur == '/' && cur+2 < limit) + else if (*cur == '/' && cur+2 < limit) { T1_Byte* cur2; T1_Int len; @@ -610,38 +866,46 @@ if (len > 0 && len < 20) { - /* now, compare the immediate name to the keyword table */ - T1_KeyWord* keyword = (T1_KeyWord*)t1_keywords; - - for (;;) + if (!loader->fontdata) { - T1_Byte* name; - - name = (T1_Byte*)keyword->name; - if (!name) break; - - if ( cur[0] == name[0] && - len == (T1_Int)strlen((const char*)name) ) + if ( strncmp( (char*)cur, "FontInfo", 8 ) == 0 ) + loader->fontdata = 1; + } + else + { + /* now, compare the immediate name to the keyword table */ + T1_KeyWord* keyword = (T1_KeyWord*)t1_keywords; + + for (;;) { - T1_Int n; - for ( n = 1; n < len; n++ ) - if (cur[n] != name[n]) - break; - - if (n >= len) + T1_Byte* name; + + name = (T1_Byte*)keyword->name; + if (!name) break; + + if ( cur[0] == name[0] && + len == (T1_Int)strlen((const char*)name) ) { - /* we found it - run the parsing callback !! */ - parser->cursor = cur2; - skip_whitespace( parser ); - keyword->parsing( face, loader ); - if (parser->error) - return parser->error; - - cur = parser->cursor; - break; + T1_Int n; + for ( n = 1; n < len; n++ ) + if (cur[n] != name[n]) + break; + + if (n >= len) + { + /* we found it - run the parsing callback !! */ + parser->cursor = cur2; + skip_whitespace( parser ); + parser->error = t1_load_keyword( face, loader, keyword ); + if (parser->error) + return parser->error; + + cur = parser->cursor; + break; + } } + keyword++; } - keyword++; } } } @@ -664,6 +928,7 @@ loader->charstrings.init = 0; loader->glyph_names.init = 0; loader->subrs.init = 0; + loader->fontdata = 0; } static diff --git a/src/type1z/t1load.h b/src/type1z/t1load.h index 629e94356..811dfa526 100644 --- a/src/type1z/t1load.h +++ b/src/type1z/t1load.h @@ -39,6 +39,7 @@ T1_Int num_subrs; T1_Table subrs; + T1_Bool fontdata; } T1_Loader; diff --git a/src/type1z/t1objs.c b/src/type1z/t1objs.c index 3a5c053bb..87b94d2c8 100644 --- a/src/type1z/t1objs.c +++ b/src/type1z/t1objs.c @@ -298,7 +298,7 @@ /* now compute the maximum advance width */ - root->max_advance_width = face->type1.private_dict.standard_width; + root->max_advance_width = face->type1.private_dict.standard_width[0]; /* compute max advance width for proportional fonts */ if (!face->type1.font_info.is_fixed_pitch) diff --git a/src/type1z/t1parse.c b/src/type1z/t1parse.c index 3ce808640..69035b3f6 100644 --- a/src/type1z/t1parse.c +++ b/src/type1z/t1parse.c @@ -38,6 +38,18 @@ #undef FT_COMPONENT #define FT_COMPONENT trace_t1load +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** IMPLEMENTATION OF T1_TABLE OBJECT *****/ +/***** *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ + + /*************************************************************************/ /* */ /* T1_New_Table */ @@ -221,6 +233,163 @@ } } +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ +/***** *****/ +/***** INPUT STREAM PARSER *****/ +/***** *****/ +/***** *****/ +/*************************************************************************/ +/*************************************************************************/ +/*************************************************************************/ + + #define IS_T1_WHITESPACE(c) ( (c) == ' ' || (c) == '\t' ) + #define IS_T1_LINESPACE(c) ( (c) == '\r' || (c) == '\n' ) + + #define IS_T1_SPACE(c) ( IS_T1_WHITESPACE(c) || IS_T1_LINESPACE(c) ) + + LOCAL_FUNC + void T1_Skip_Spaces( T1_Parser* parser ) + { + T1_Byte* cur = parser->cursor; + T1_Byte* limit = parser->limit; + + while (cur < limit) + { + T1_Byte c = *cur; + if (!IS_T1_SPACE(c)) + break; + cur++; + } + parser->cursor = cur; + } + + LOCAL_FUNC + void T1_ToToken( T1_Parser* parser, + T1_Token_Rec* token ) + { + T1_Byte* cur; + T1_Byte* limit; + T1_Byte starter, ender; + T1_Int embed; + + token->type = t1_token_none; + token->start = 0; + token->limit = 0; + + /* first of all, skip space */ + T1_Skip_Spaces(parser); + + cur = parser->cursor; + limit = parser->limit; + + if ( cur < limit ) + { + switch (*cur) + { + /************* check for strings ***********************/ + case '(': + token->type = t1_token_string; + ender = ')'; + goto Lookup_Ender; + + /************* check for programs/array ****************/ + case '{': + token->type = t1_token_array; + ender = '}'; + goto Lookup_Ender; + + /************* check for table/array ******************/ + case '[': + token->type = t1_token_array; + ender = ']'; + + Lookup_Ender: + embed = 1; + starter = *cur++; + token->start = cur; + while (cur < limit) + { + if (*cur == starter) + embed++; + else if (*cur == ender) + { + embed--; + if (embed <= 0) + { + token->limit = cur++; + break; + } + } + cur++; + } + break; + + /* **************** otherwise, it's any token **********/ + default: + token->start = cur++; + token->type = t1_token_any; + while (cur < limit && !IS_T1_SPACE(*cur)) + cur++; + + token->limit = cur; + } + + if (!token->limit) + { + token->start = 0; + token->type = t1_token_none; + } + + parser->cursor = cur; + } + } + + + LOCAL_FUNC + void T1_ToTokenArray( T1_Parser* parser, + T1_Token_Rec* tokens, + T1_UInt max_tokens, + T1_Int *pnum_tokens ) + { + T1_Token_Rec master; + + *pnum_tokens = -1; + + T1_ToToken( parser, &master ); + if (master.type == t1_token_array) + { + T1_Byte* old_cursor = parser->cursor; + T1_Byte* old_limit = parser->limit; + T1_Token_Rec* cur = tokens; + T1_Token_Rec* limit = cur + max_tokens; + + parser->cursor = master.start; + parser->limit = master.limit; + + while (parser->cursor < parser->limit) + { + T1_Token_Rec token; + + T1_ToToken( parser, &token ); + if (!token.type) + break; + + if (cur < limit) + *cur = token; + + cur++; + } + + *pnum_tokens = cur - tokens; + + parser->cursor = old_cursor; + parser->limit = old_limit; + } + } + + static T1_Long t1_toint( T1_Byte* *cursor, T1_Byte* limit ) @@ -533,6 +702,165 @@ } + + /* Loads a simple field (i.e. non-table) into the current list of objects */ + LOCAL_FUNC + T1_Error T1_Load_Field( T1_Parser* parser, + const T1_Field_Rec* field, + void** objects, + T1_UInt max_objects, + T1_ULong* pflags ) + { + T1_Token_Rec token; + T1_Byte* cur; + T1_Byte* limit; + T1_UInt count; + T1_UInt index; + T1_Error error; + + T1_ToToken( parser, &token ); + if (!token.type) + goto Fail; + + count = 1; + index = 0; + cur = token.start; + limit = token.limit; + + if (token.type == t1_token_array) + { + /* if this is an array, and we have no blend, an error occurs */ + if (max_objects == 0) + goto Fail; + + count = max_objects; + index = 1; + } + + for ( ; count > 0; count--, index++ ) + { + T1_Byte* q = (T1_Byte*)objects[index] + field->offset; + T1_Long val; + T1_String* string; + + switch (field->type) + { + case t1_field_bool: + { + val = t1_tobool( &cur, limit ); + goto Store_Integer; + } + + case t1_field_fixed: + { + val = t1_tofixed( &cur, limit, 3 ); + goto Store_Integer; + } + + case t1_field_integer: + { + val = t1_toint( &cur, limit ); + Store_Integer: + switch (field->size) + { + case 1: *(T1_Byte*)q = (T1_Byte)val; break; + case 2: *(T1_UShort*)q = (T1_UShort)val; break; + default: *(T1_Long*)q = val; + } + } + break; + + case t1_field_string: + { + FT_Memory memory = parser->memory; + FT_UInt len = limit-cur; + + if ( ALLOC( string, len+1 ) ) + goto Exit; + + MEM_Copy( string, cur, len ); + string[len] = 0; + + *(T1_String**)q = string; + } + break; + + default: + /* an error occured */ + goto Fail; + } + } + if (pflags) + *pflags |= 1L << field->flag_bit; + error = 0; + + Exit: + return error; + Fail: + error = T1_Err_Invalid_File_Format; + goto Exit; + } + + +#define T1_MAX_TABLE_ELEMENTS 32 + + LOCAL_FUNC + T1_Error T1_Load_Field_Table( T1_Parser* parser, + const T1_Field_Rec* field, + void** objects, + T1_UInt max_objects, + T1_ULong* pflags ) + { + T1_Token_Rec elements[T1_MAX_TABLE_ELEMENTS]; + T1_Token_Rec* token; + T1_Int num_elements; + T1_Error error = 0; + T1_Byte* old_cursor; + T1_Byte* old_limit; + T1_Field_Rec fieldrec = *(T1_Field_Rec*)field; + + T1_ToTokenArray( parser, elements, 32, &num_elements ); + if (num_elements < 0) + goto Fail; + + if (num_elements > T1_MAX_TABLE_ELEMENTS) + num_elements = T1_MAX_TABLE_ELEMENTS; + + old_cursor = parser->cursor; + old_limit = parser->limit; + + /* we store the elements count */ + *(T1_Byte*)((T1_Byte*)objects[0] + field->count_offset) = num_elements; + + /* we now load each element, adjusting the field.offset on each one */ + token = elements; + for ( ; num_elements > 0; num_elements--, token++ ) + { + parser->cursor = token->start; + parser->limit = token->limit; + T1_Load_Field( parser, &fieldrec, objects, max_objects, 0 ); + fieldrec.offset += fieldrec.size; + } + + if (pflags) + *pflags |= 1L << field->flag_bit; + + parser->cursor = old_cursor; + parser->limit = old_limit; + + Exit: + return error; + Fail: + error = T1_Err_Invalid_File_Format; + goto Exit; + } + + + + + + + LOCAL_FUNC T1_Long T1_ToInt ( T1_Parser* parser ) { @@ -580,41 +908,6 @@ } -#if 0 - /* load a single field in an object */ - LOCAL_FUNC - T1_Error T1_Load_Field( T1_Parser* parser, - void* object, - T1_Field_Rec* field ) - { - FT_Byte* p = (FT_Byte*)object + field->offset; - FT_Byte** pcursor = &parser->cursor; - FT_Byte* limit = parser->limit; - - switch (field->type) - { - case t1_field_boolean: - *(T1_Bool*)p = t1_tobool( pcursor, limit ); - break; - - case t1_field_string: - *(T1_String**)p = t1_tostring( pcursor, limit, parser->memory ); - break; - - case t1_field_int: - *(T1_Long*)p = t1_toint( pcursor, limit ); - break; - - case t1_field_fixed: - *(T1_Fixed*)p = t1_tofixed( pcursor, limit, field->power_ten ); - break; - - default: - return T1_Err_Invalid_Argument; - } - return 0; - } -#endif static FT_Error read_pfb_tag( FT_Stream stream, T1_UShort *tag, T1_Long* size ) diff --git a/src/type1z/t1parse.h b/src/type1z/t1parse.h index 0dd7a897a..fb25883e6 100644 --- a/src/type1z/t1parse.h +++ b/src/type1z/t1parse.h @@ -38,6 +38,29 @@ #endif + /* simple enumeration type used to identify token types */ + typedef enum T1_Token_Type_ + { + t1_token_none = 0, + t1_token_any, + t1_token_string, + t1_token_array, + + /* do not remove */ + t1_token_max + + } T1_Token_Type; + + /* a simple structure used to identify tokens */ + typedef struct T1_Token_Rec_ + { + T1_Byte* start; /* first character of token in input stream */ + T1_Byte* limit; /* first character after the token */ + T1_Token_Type type; /* type of token.. */ + + } T1_Token_Rec; + + /* enumeration type used to identify object fields */ typedef enum T1_Field_Type_ { t1_field_none = 0, @@ -45,22 +68,84 @@ t1_field_integer, t1_field_fixed, t1_field_string, + t1_field_integer_array, t1_field_fixed_array, - t1_field_coord_array + + /* do not remove */ + t1_field_max } T1_Field_Type; - - + + /* structure type used to model object fields */ typedef struct T1_Field_Rec_ { - T1_Field_Type type; /* type of field */ - FT_UInt offset; /* offset of field in object */ - FT_UInt size; /* size of field in bytes */ - T1_Int array_max; /* maximum number of elements for array */ - T1_Int power_ten; /* power of ten for "fixed" fields */ - + T1_Field_Type type; /* type of field */ + T1_UInt offset; /* offset of field in object */ + T1_UInt size; /* size of field in bytes */ + T1_UInt array_max; /* maximum number of elements for array */ + T1_UInt count_offset; /* offset of element count for arrays */ + T1_Int flag_bit; /* bit number for field flag */ + } T1_Field_Rec; - + +#define T1_FIELD_REF(s,f) (((s*)0)->f) + +#define T1_FIELD_BOOL( _ftype, _fname ) \ + { t1_field_bool, \ + (T1_UInt)(char*)&T1_FIELD_REF(_ftype,_fname), \ + sizeof(T1_FIELD_REF(_ftype,_fname)), \ + 0, 0, 0 } + +#define T1_FIELD_NUM( _ftype, _fname ) \ + { t1_field_integer, \ + (T1_UInt)(char*)&T1_FIELD_REF(_ftype,_fname), \ + sizeof(T1_FIELD_REF(_ftype,_fname)), \ + 0, 0, 0 } + +#define T1_FIELD_FIXED( _ftype, _fname, _power ) \ + { t1_field_fixed, \ + (T1_UInt)(char*)&T1_FIELD_REF(_ftype,_fname), \ + sizeof(T1_FIELD_REF(_ftype,_fname)), \ + 0, 0, 0 } + +#define T1_FIELD_STRING( _ftype, _fname ) \ + { t1_field_string, \ + (T1_UInt)(char*)&T1_FIELD_REF(_ftype,_fname), \ + sizeof(T1_FIELD_REF(_ftype,_fname)), \ + 0, 0, 0 } + +#define T1_FIELD_NUM_ARRAY( _ftype, _fname, _fcount, _fmax ) \ + { t1_field_integer, \ + (T1_UInt)(char*)&T1_FIELD_REF(_ftype,_fname), \ + sizeof(T1_FIELD_REF(_ftype,_fname)[0]), \ + _fmax, \ + (T1_UInt)(char*)&T1_FIELD_REF(_ftype,_fcount), \ + 0 } + +#define T1_FIELD_FIXED_ARRAY( _ftype, _fname, _fcount, _fmax ) \ + { t1_field_fixed, \ + (T1_UInt)(char*)&T1_FIELD_REF(_ftype,_fname), \ + sizeof(T1_FIELD_REF(_ftype,_fname)[0]), \ + _fmax, \ + (T1_UInt)(char*)&T1_FIELD_REF(_ftype,_fcount), \ + 0 } + +#define T1_FIELD_NUM_ARRAY2( _ftype, _fname, _fmax ) \ + { t1_field_integer, \ + (T1_UInt)(char*)&T1_FIELD_REF(_ftype,_fname), \ + sizeof(T1_FIELD_REF(_ftype,_fname)[0]), \ + _fmax, \ + 0, 0 } + +#define T1_FIELD_FIXED_ARRAY2( _ftype, _fname, _fmax ) \ + { t1_field_fixed, \ + (T1_UInt)(char*)&T1_FIELD_REF(_ftype,_fname), \ + sizeof(T1_FIELD_REF(_ftype,_fname)[0]), \ + _fmax, \ + 0, 0 } + + + /************************************************************************* * * T1_Table @@ -215,6 +300,32 @@ T1_Field_Rec* field ); #endif + + + + + LOCAL_DEF + void T1_Skip_Spaces( T1_Parser* parser ); + + LOCAL_DEF + void T1_ToToken( T1_Parser* parser, + T1_Token_Rec* token ); + + LOCAL_DEF + T1_Error T1_Load_Field( T1_Parser* parser, + const T1_Field_Rec* field, + void** objects, + T1_UInt max_objects, + T1_ULong* pflags ); + + LOCAL_DEF + T1_Error T1_Load_Field_Table( T1_Parser* parser, + const T1_Field_Rec* field, + void** objects, + T1_UInt max_objects, + T1_ULong* pflags ); + + LOCAL_DEF T1_Error T1_New_Parser( T1_Parser* parser, FT_Stream stream, diff --git a/src/type1z/t1tokens.h b/src/type1z/t1tokens.h index 2ef03b41f..ceff4e14e 100644 --- a/src/type1z/t1tokens.h +++ b/src/type1z/t1tokens.h @@ -17,6 +17,52 @@ * ******************************************************************/ +#undef T1TYPE +#define T1TYPE T1_FontInfo + + T1_FONTINFO_STRING( "version", version ) + T1_FONTINFO_STRING( "Notice", notice ) + T1_FONTINFO_STRING( "FullName", full_name ) + T1_FONTINFO_STRING( "FamilyName", family_name ) + T1_FONTINFO_STRING( "Weight", weight ) + + T1_FONTINFO_NUM( "ItalicAngle", italic_angle ) + T1_FONTINFO_BOOL( "isFixedPitch", is_fixed_pitch ) + T1_FONTINFO_NUM( "UnderlinePosition", underline_position ) + T1_FONTINFO_NUM( "UnderlineThickness", underline_thickness ) + +#undef T1TYPE +#define T1TYPE T1_Private + + T1_PRIVATE_NUM ( "UniqueID", unique_id ) + T1_PRIVATE_NUM ( "lenIV", lenIV ) + T1_PRIVATE_NUM ( "LanguageGroup", language_group ) + T1_PRIVATE_NUM ( "password", password ) + + T1_PRIVATE_FIXED( "BlueScale", blue_scale ) + T1_PRIVATE_NUM ( "BlueShift", blue_shift ) + T1_PRIVATE_NUM ( "BlueFuzz", blue_fuzz ) + + T1_PRIVATE_NUM_TABLE( "BlueValues", blue_values, 14, num_blues ) + T1_PRIVATE_NUM_TABLE( "OtherBlues", other_blues, 10, num_other_blues ) + T1_PRIVATE_NUM_TABLE( "FamilyBlues", family_blues, 14, num_family_blues ) + T1_PRIVATE_NUM_TABLE( "FamilyOtherBlues", family_other_blues, 10, num_family_other_blues ) + + T1_PRIVATE_NUM_TABLE2( "StdHW", standard_width, 1 ) + T1_PRIVATE_NUM_TABLE2( "StdVW", standard_height, 1 ) + T1_PRIVATE_NUM_TABLE2( "MinFeature", min_feature, 2 ) + + T1_PRIVATE_NUM_TABLE ( "StemSnapH", stem_snap_widths, 12, num_snap_widths ) + T1_PRIVATE_NUM_TABLE ( "StemSnapV", stem_snap_heights, 12, num_snap_heights ) + +#undef T1TYPE +#define T1TYPE T1_Font + + T1_TOPDICT_NUM( "PaintType", paint_type ) + T1_TOPDICT_NUM( "FontType", font_type ) + T1_TOPDICT_NUM( "StrokeWidth", stroke_width ) + +#if 0 /* define the font info dictionary parsing callbacks */ #undef FACE #define FACE (face->type1.font_info) @@ -75,5 +121,5 @@ PARSE_INT( "StrokeWidth", stroke_width ) #undef FACE - +#endif