ref: 7c388ba4911d76856d85bc1b9e0059414c1b05c9
parent: 4e183694917419772396a7d55f39d72a335eb933
author: David Turner <[email protected]>
date: Thu May 25 22:07:40 EDT 2000
added support for multiple master fonts in "type1z". It is now working, but there is no way currently to change the default weight vector (tested with custom vectors though). Note that you should remove the "type1" driver from the module list to be able to test it..
--- a/include/freetype/freetype.h
+++ b/include/freetype/freetype.h
@@ -645,7 +645,7 @@
/* */
/* <Description> */
/* A bit-field constant, used to indicate that a given face contains */
- /* fixed-width characters (like Courier, MonoType, etc). */
+ /* fixed-width characters (like Courier, Lucida, MonoType, etc..) */
/* */
#define FT_FACE_FLAG_FIXED_WIDTH 4
--- a/include/freetype/internal/ftdebug.h
+++ b/include/freetype/internal/ftdebug.h
@@ -170,7 +170,7 @@
/* print a message and exit */
FT_EXPORT_DEF(void) FT_Panic ( const char* fmt, ... );
-#define FT_ERROR(varformat) do { FT_XCAT( FT_Message, varformat ) } while(0)
+#define FT_ERROR(varformat) do { FT_XCAT( FT_Message, varformat ); } while(0)
#endif /* FT_DEBUG_LEVEL_TRACE || FT_DEBUG_LEVEL_ERROR */
--- a/include/freetype/t1tables.h
+++ b/include/freetype/t1tables.h
@@ -140,9 +140,14 @@
} 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
+ #define T1_MAX_MM_DESIGNS 16
+
+ /* maximum number of multiple-masters axis, per-se the spec */
+ #define T1_MAX_MM_AXIS 4
+ /* maximum number of elements in a design map */
+ #define T1_MAX_MM_MAP_POINTS 20
+
/* this structure is used to store the BlendDesignMap entry for an axis */
typedef struct T1_DesignMap_
{
@@ -152,6 +157,7 @@
} T1_DesignMap;
+
typedef struct T1_Blend_
{
FT_UInt num_designs;
@@ -161,6 +167,9 @@
FT_Fixed* design_pos[ T1_MAX_MM_DESIGNS ];
T1_DesignMap design_map[ T1_MAX_MM_AXIS ];
+ FT_Fixed* weight_vector;
+ FT_Fixed* default_weight_vector;
+
T1_FontInfo* font_infos[ T1_MAX_MM_DESIGNS+1 ];
T1_Private* privates [ T1_MAX_MM_DESIGNS+1 ];
@@ -173,7 +182,7 @@
typedef struct CID_FontDict_
{
T1_FontInfo font_info;
- T1_Private private;
+ T1_Private private_dict;
FT_UInt num_subrs;
FT_ULong subrmap_offset;
--- a/src/type1z/t1gload.c
+++ b/src/type1z/t1gload.c
@@ -205,6 +205,7 @@
decoder->zone = 0;
decoder->flex_state = 0;
decoder->num_flex_vectors = 0;
+ decoder->blend = 0;
/* Clear loader */
MEM_Set( &decoder->builder, 0, sizeof(decoder->builder) );
@@ -830,6 +831,72 @@
break;;
}
+ case 12:
+ case 13:
+ {
+ /* counter control hints, clear stack */
+ top = decoder->stack;
+ break;
+ }
+
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ case 18: /* multiple masters */
+ {
+ T1_Blend* blend = decoder->blend;
+ T1_UInt num_points, nn, mm;
+ T1_Int* delta;
+ T1_Int* values;
+
+ if (!blend)
+ {
+ FT_ERROR(( "T1.Parse_CharStrings: unexpected multiple masters operator !!\n" ));
+ goto Syntax_Error;
+ }
+
+ num_points = top[1] - 13 + (top[1] == 18);
+ if (top[0] != num_points*blend->num_designs)
+ {
+ FT_ERROR(( "T1.Parse_CharStrings: incorrect number of mm arguments\n" ));
+ goto Syntax_Error;
+ }
+
+ top -= blend->num_designs*num_points;
+ if (top < decoder->stack)
+ goto Stack_Underflow;
+
+ /* we want to compute: */
+ /* */
+ /* a0*w0 + a1*w1 + ... + ak*wk */
+ /* */
+ /* but we only have the a0, a1-a0, a2-a0, .. ak-a0 */
+ /* however, given that w0 + w1 + ... + wk == 1, we can */
+ /* rewrite it easily as: */
+ /* */
+ /* a0 + (a1-a0)*w1 + (a2-a0)*w2 + .. + (ak-a0)*wk */
+ /* */
+ /* where k == num_designs-1 */
+ /* */
+ /* I guess that's why it's written in this "compact" */
+ /* form.. */
+ /* */
+ /* */
+ delta = top + num_points;
+ values = top;
+ for ( nn = 0; nn < num_points; nn++ )
+ {
+ T1_Int x = values[0];
+ for ( mm = 1; mm < blend->num_designs; mm++ )
+ x += FT_MulFix( *delta++, blend->weight_vector[mm] );
+
+ *values++ = x;
+ }
+ /* note that "top" will be incremented later by calls to "pop" */
+ break;
+ }
+
default:
Unexpected_OtherSubr:
FT_ERROR(( "T1.Parse_CharStrings: invalid othersubr [%d %d]!!\n",
@@ -1086,8 +1153,9 @@
case op_pop: /****************************************************/
{
FT_TRACE4(( " pop" ));
- FT_ERROR(( "T1.Parse_CharStrings : unexpected POP\n" ));
- goto Syntax_Error;
+ /* theorically, the arguments are already on the stack */
+ top++;
+ break;
}
@@ -1202,6 +1270,7 @@
T1_Init_Decoder( &decoder );
T1_Init_Builder( &decoder.builder, face, 0, 0 );
+ decoder.blend = face->blend;
decoder.builder.metrics_only = 1;
decoder.builder.load_points = 0;
@@ -1270,6 +1339,7 @@
T1_Init_Decoder( &decoder );
T1_Init_Builder( &decoder.builder, face, size, glyph );
+ decoder.blend = ((T1_Face)glyph->root.face)->blend;
decoder.builder.no_recurse = (FT_Bool)!!(load_flags & FT_LOAD_NO_RECURSE);
/* now load the unscaled outline */
--- a/src/type1z/t1gload.h
+++ b/src/type1z/t1gload.h
@@ -139,6 +139,8 @@
T1_Int num_flex_vectors;
T1_Vector flex_vectors[7];
+ T1_Blend* blend; /* for multiple masters */
+
} T1_Decoder;
--- a/src/type1z/t1load.c
+++ b/src/type1z/t1load.c
@@ -102,9 +102,12 @@
{
/* 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 ) )
+ ALLOC_ARRAY( blend->privates[1], num_designs, T1_Private ) ||
+ ALLOC_ARRAY( blend->weight_vector, num_designs*2, FT_Fixed ) )
goto Exit;
+ blend->default_weight_vector = blend->weight_vector + num_designs;
+
blend->font_infos[0] = &face->type1.font_info;
blend->privates [0] = &face->type1.private_dict;
blend->num_designs = num_designs;
@@ -144,7 +147,7 @@
}
- static void t1_done_blend( T1_Face face )
+ LOCAL_FUNC void T1_Done_Blend( T1_Face face )
{
FT_Memory memory = face->root.memory;
T1_Blend* blend = face->blend;
@@ -169,6 +172,10 @@
blend->font_infos[n] = 0;
}
+ /* release weight vectors */
+ FREE( blend->weight_vector );
+ blend->default_weight_vector = 0;
+
/* release axis names */
for ( n = 0; n < num_axis; n++ )
FREE( blend->axis_names[n] );
@@ -178,7 +185,6 @@
{
T1_DesignMap* dmap = blend->design_map + n;
FREE( dmap->design_points );
- FREE( dmap->blend_points );
dmap->num_points = 0;
}
@@ -186,6 +192,261 @@
}
}
+
+ static void parse_blend_axis_types( T1_Face face, T1_Loader* loader )
+ {
+ T1_Token_Rec axis_tokens[ T1_MAX_MM_AXIS ];
+ T1_Int n, num_axis;
+ FT_Error error = 0;
+ T1_Blend* blend;
+ FT_Memory memory;
+
+ /* take an array of objects */
+ T1_ToTokenArray( &loader->parser, axis_tokens, T1_MAX_MM_AXIS, &num_axis );
+ if (num_axis <= 0 || num_axis > T1_MAX_MM_AXIS)
+ {
+ FT_ERROR(( "T1.parse_blend_axis_types: incorrect number of axis: %d\n",
+ num_axis ));
+ error = FT_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ /* allocate blend if necessary */
+ error = t1_allocate_blend( face, 0, (T1_UInt)num_axis );
+ if (error) goto Exit;
+
+ blend = face->blend;
+ memory = face->root.memory;
+
+ /* each token is an immediate containing the name of the axis */
+ for ( n = 0; n < num_axis; n++ )
+ {
+ T1_Token_Rec* token = axis_tokens + n;
+ T1_Byte* name;
+ T1_Int len;
+
+ /* skip first slash, if any */
+ if (token->start[0] == '/')
+ token->start++;
+
+ len = token->limit - token->start;
+ if (len <= 0)
+ {
+ error = FT_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ if ( ALLOC( blend->axis_names[n], len+1 ) )
+ goto Exit;
+
+ name = (T1_Byte*)blend->axis_names[n];
+ MEM_Copy( name, token->start, len );
+ name[len] = 0;
+ }
+
+ Exit:
+ loader->parser.error = error;
+ }
+
+
+ static void parse_blend_design_positions( T1_Face face, T1_Loader* loader )
+ {
+ T1_Token_Rec design_tokens[ T1_MAX_MM_DESIGNS ];
+ T1_Int num_designs;
+ T1_Int num_axis;
+ T1_Parser* parser = &loader->parser;
+
+ FT_Error error = 0;
+ T1_Blend* blend;
+
+ /* get the array of design tokens - compute number of designs */
+ T1_ToTokenArray( parser, design_tokens, T1_MAX_MM_DESIGNS, &num_designs );
+ if (num_designs <= 0 || num_designs > T1_MAX_MM_DESIGNS)
+ {
+ FT_ERROR(( "T1.design positions: incorrect number of designs: %d\n",
+ num_designs ));
+ error = FT_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ {
+ T1_Byte* old_cursor = parser->cursor;
+ T1_Byte* old_limit = parser->limit;
+ T1_UInt n;
+
+ blend = face->blend;
+ for ( n = 0; n < (T1_UInt)num_designs; n++ )
+ {
+ T1_Token_Rec axis_tokens[ T1_MAX_MM_DESIGNS ];
+ T1_Token_Rec* token;
+ T1_Int axis, n_axis;
+
+ /* read axis/coordinates tokens */
+ token = design_tokens + n;
+ parser->cursor = token->start - 1;
+ parser->limit = token->limit + 1;
+ T1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &n_axis );
+
+ if (n == 0)
+ {
+ num_axis = n_axis;
+ error = t1_allocate_blend( face, num_designs, num_axis );
+ if (error) goto Exit;
+ blend = face->blend;
+ }
+ else if (n_axis != num_axis)
+ {
+ FT_ERROR(( "T1.design_positions: incorrect table\n" ));
+ error = FT_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ /* now, read each axis token into the design position */
+ for (axis = 0; axis < n_axis; axis++ )
+ {
+ T1_Token_Rec* token2 = axis_tokens + axis;
+ parser->cursor = token2->start;
+ parser->limit = token2->limit;
+ blend->design_pos[n][axis] = T1_ToFixed( parser, 0 );
+ }
+ }
+
+ loader->parser.cursor = old_cursor;
+ loader->parser.limit = old_limit;
+ }
+
+ Exit:
+ loader->parser.error = error;
+ }
+
+ static void parse_blend_design_map( T1_Face face, T1_Loader* loader )
+ {
+ FT_Error error = 0;
+ T1_Parser* parser = &loader->parser;
+ T1_Blend* blend;
+ T1_Token_Rec axis_tokens[ T1_MAX_MM_AXIS ];
+ T1_Int n, num_axis;
+ T1_Byte* old_cursor;
+ T1_Byte* old_limit;
+ FT_Memory memory = face->root.memory;
+
+ T1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &num_axis );
+ if (num_axis <= 0 || num_axis > T1_MAX_MM_AXIS)
+ {
+ FT_ERROR(( "T1.design map: incorrect number of axis: %d\n",
+ num_axis ));
+ error = FT_Err_Invalid_File_Format;
+ goto Exit;
+ }
+ old_cursor = parser->cursor;
+ old_limit = parser->limit;
+
+ error = t1_allocate_blend( face, 0, num_axis );
+ if (error) goto Exit;
+ blend = face->blend;
+
+ /* now, read each axis design map */
+ for ( n = 0; n < num_axis; n++ )
+ {
+ T1_DesignMap* map = blend->design_map + n;
+ T1_Token_Rec* token;
+ T1_Int p, num_points;
+
+ token = axis_tokens + n;
+ parser->cursor = token->start;
+ parser->limit = token->limit;
+
+ /* count the number of map points */
+ {
+ T1_Byte* p = token->start;
+ T1_Byte* limit = token->limit;
+
+ num_points = 0;
+ for ( ; p < limit; p++ )
+ if (p[0] == '[')
+ num_points++;
+ }
+ if (num_points <= 0 || num_points > T1_MAX_MM_MAP_POINTS)
+ {
+ FT_ERROR(( "T1.design map: incorrect table\n" ));
+ error = FT_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ /* allocate design map data */
+ if ( ALLOC_ARRAY( map->design_points, num_points*2, FT_Fixed ) )
+ goto Exit;
+ map->blend_points = map->design_points + num_points;
+ map->num_points = (FT_Byte)num_points;
+
+ for ( p = 0; p < num_points; p++ )
+ {
+ map->design_points[p] = T1_ToInt( parser );
+ map->blend_points [p] = T1_ToFixed( parser, 0 );
+ }
+ }
+
+ parser->cursor = old_cursor;
+ parser->limit = old_limit;
+ Exit:
+ parser->error = error;
+ }
+
+ static void parse_weight_vector( T1_Face face, T1_Loader* loader )
+ {
+ FT_Error error = 0;
+ T1_Parser* parser = &loader->parser;
+ T1_Blend* blend = face->blend;
+ T1_Token_Rec master;
+ T1_UInt n;
+ T1_Byte* old_cursor;
+ T1_Byte* old_limit;
+
+ if (!blend || blend->num_designs == 0)
+ {
+ FT_ERROR(( "t1.weight_vector: too early !!\n" ));
+ error = FT_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ T1_ToToken( parser, &master );
+ if (master.type != t1_token_array)
+ {
+ FT_ERROR(( "t1.weight_vector: incorrect format !!\n" ));
+ error = FT_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ old_cursor = parser->cursor;
+ old_limit = parser->limit;
+
+ parser->cursor = master.start;
+ parser->limit = master.limit;
+ for ( n = 0; n < blend->num_designs; n++ )
+ {
+ blend->default_weight_vector[n] =
+ blend->weight_vector[n] = T1_ToFixed( parser, 0 );
+ }
+
+ parser->cursor = old_cursor;
+ parser->limit = old_limit;
+ Exit:
+ parser->error = error;
+ }
+
+ /* the keyword /shareddict appears in some multiple master fonts with a lot */
+ /* of Postscript garbage behind it (that's completely out of spec !!), we */
+ /* detect it and terminate the parsing */
+ static void parse_shared_dict( T1_Face face, T1_Loader* loader )
+ {
+ T1_Parser* parser = &loader->parser;
+
+ UNUSED(face);
+
+ parser->cursor = parser->limit;
+ parser->error = 0;
+ }
+
/***************************************************************************/
/***************************************************************************/
/***** *****/
@@ -802,6 +1063,13 @@
T1_KEYWORD_CALLBACK( "Encoding", parse_encoding ),
T1_KEYWORD_CALLBACK( "Subrs", parse_subrs ),
T1_KEYWORD_CALLBACK( "CharStrings", parse_charstrings ),
+#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
+ T1_KEYWORD_CALLBACK( "BlendDesignPositions", parse_blend_design_positions ),
+ T1_KEYWORD_CALLBACK( "BlendDesignMap", parse_blend_design_map ),
+ T1_KEYWORD_CALLBACK( "BlendAxisTypes", parse_blend_axis_types ),
+ T1_KEYWORD_CALLBACK( "WeightVector", parse_weight_vector ),
+ T1_KEYWORD_CALLBACK( "shareddict", parse_shared_dict ),
+#endif
T1_KEYWORD_CALLBACK( 0, 0 )
};
@@ -864,7 +1132,7 @@
while (cur2 < limit && is_alpha(*cur2)) cur2++;
len = cur2-cur;
- if (len > 0 && len < 20)
+ if (len > 0 && len < 22)
{
if (!loader->fontdata)
{
--- a/src/type1z/t1load.h
+++ b/src/type1z/t1load.h
@@ -46,6 +46,10 @@
LOCAL_DEF
T1_Error T1_Open_Face( T1_Face face );
+#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
+ LOCAL_DEF
+ void T1_Done_Blend( T1_Face face );
+#endif
#ifdef __cplusplus
}
--- a/src/type1z/t1objs.c
+++ b/src/type1z/t1objs.c
@@ -138,6 +138,12 @@
{
memory = face->root.memory;
+#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
+ /* release multiple masters information */
+ T1_Done_Blend( face );
+ face->blend = 0;
+#endif
+
/* release font info strings */
{
T1_FontInfo* info = &type1->font_info;
--- a/src/type1z/t1parse.c
+++ b/src/type1z/t1parse.c
@@ -621,6 +621,7 @@
}
+#if 0
static
T1_String* t1_tostring( T1_Byte* *cursor, T1_Byte* limit, FT_Memory memory )
{
@@ -670,6 +671,7 @@
*cursor = cur;
return result;
}
+#endif
static
int t1_tobool( T1_Byte* *cursor, T1_Byte* limit )
@@ -732,7 +734,7 @@
/* if this is an array, and we have no blend, an error occurs */
if (max_objects == 0)
goto Fail;
-
+
count = max_objects;
index = 1;
}
@@ -894,6 +896,7 @@
}
+#if 0
LOCAL_FUNC
T1_String* T1_ToString( T1_Parser* parser )
{
@@ -906,7 +909,7 @@
{
return t1_tobool( &parser->cursor, parser->limit );
}
-
+#endif
static
--- a/src/type1z/t1parse.h
+++ b/src/type1z/t1parse.h
@@ -280,25 +280,14 @@
T1_Fixed* values,
T1_Int power_ten );
+#if 0
LOCAL_DEF
T1_String* T1_ToString( T1_Parser* parser );
-
LOCAL_DEF
T1_Bool T1_ToBool( T1_Parser* parser );
-
-#if 0
- LOCAL_DEF
- T1_Int T1_ToImmediate( T1_Parser* parser );
#endif
-#if 0
- /* load a single field in an object */
- LOCAL_DEF
- T1_Error T1_Load_Field( T1_Parser* parser,
- void* object,
- T1_Field_Rec* field );
-#endif