diff --git a/include/freetype/config/ftoption.h b/include/freetype/config/ftoption.h index b973e837b..fd31befcb 100644 --- a/include/freetype/config/ftoption.h +++ b/include/freetype/config/ftoption.h @@ -335,14 +335,6 @@ /*************************************************************************/ - /*************************************************************************/ - /* */ - /* T1_MAX_STACK_DEPTH is the maximal depth of the token stack used by */ - /* the Type 1 parser (see t1load.c). A minimum of 16 is required. */ - /* */ -#define T1_MAX_STACK_DEPTH 16 - - /*************************************************************************/ /* */ /* T1_MAX_DICT_DEPTH is the maximal depth of nest dictionaries and */ @@ -363,10 +355,10 @@ /*************************************************************************/ /* */ /* T1_MAX_CHARSTRING_OPERANDS is the charstring stack's capacity. */ + /* A minimum of 16 is required.. */ /* */ #define T1_MAX_CHARSTRINGS_OPERANDS 32 - /*************************************************************************/ /* */ /* Define T1_CONFIG_OPTION_DISABLE_HINTER if you want to generate a */ diff --git a/include/freetype/internal/ftdebug.h b/include/freetype/internal/ftdebug.h index 8b1e4dd5a..ae36bcadb 100644 --- a/include/freetype/internal/ftdebug.h +++ b/include/freetype/internal/ftdebug.h @@ -84,6 +84,10 @@ trace_t1load, trace_t1objs, + /* Postcript helper module 'psaux' */ + trace_t1decode, + trace_psobjs, + /* experimental Type 1 driver components */ trace_z1driver, trace_z1gload, diff --git a/include/freetype/internal/psaux.h b/include/freetype/internal/psaux.h index 1e70f0fa6..459c4feb0 100644 --- a/include/freetype/internal/psaux.h +++ b/include/freetype/internal/psaux.h @@ -22,7 +22,7 @@ #include - +#include #ifdef __cplusplus extern "C" { @@ -419,6 +419,7 @@ FT_Bool path_begun; FT_Bool load_points; FT_Bool no_recurse; + FT_Bool shift; FT_Error error; /* only used for memory errors */ FT_Bool metrics_only; @@ -427,14 +428,14 @@ typedef FT_Error (*T1_Builder_Check_Points_Func) ( T1_Builder* builder, - FT_Int count ); + FT_Int count ); typedef void (*T1_Builder_Add_Point_Func) ( T1_Builder* builder, FT_Pos x, FT_Pos y, FT_Byte flag ); - typedef void (*T1_Builder_Add_Point1_Func) ( T1_Builder* builder, + typedef FT_Error (*T1_Builder_Add_Point1_Func) ( T1_Builder* builder, FT_Pos x, FT_Pos y ); @@ -465,6 +466,103 @@ } T1_Builder_Funcs; + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** T1 DECODER *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#if 0 +#define T1_MAX_CHARSTRINGS_OPERANDS 64 +#define T1_MAX_SUBRS_CALLS 16 + + /*************************************************************************/ + /* */ + /* T1_MAX_SUBRS_CALLS details the maximum number of nested sub-routine */ + /* calls during glyph loading. */ + /* */ +#define T1_MAX_SUBRS_CALLS 8 + + + /*************************************************************************/ + /* */ + /* T1_MAX_CHARSTRING_OPERANDS is the charstring stack's capacity. */ + /* A minimum of 16 is required.. */ + /* */ +#define T1_MAX_CHARSTRINGS_OPERANDS 32 +#endif + + + + typedef struct T1_Decoder_Zone_ + { + FT_Byte* cursor; + FT_Byte* base; + FT_Byte* limit; + + } T1_Decoder_Zone; + + + typedef struct T1_Decoder_ T1_Decoder; + typedef struct T1_Decoder_Funcs_ T1_Decoder_Funcs; + + typedef FT_Error (*T1_Decoder_Parse_Func)( T1_Decoder* decoder, + FT_UInt glyph_index ); + + struct T1_Decoder_ + { + T1_Builder builder; + + FT_Long stack[T1_MAX_CHARSTRINGS_OPERANDS]; + FT_Long* top; + + T1_Decoder_Zone zones[T1_MAX_SUBRS_CALLS + 1]; + T1_Decoder_Zone* zone; + + PSNames_Interface* psnames; /* for seac */ + FT_UInt num_glyphs; + FT_Byte** glyph_names; + + FT_UInt lenIV; /* internal for sub routine calls */ + FT_UInt num_subrs; + FT_Byte** subrs; + FT_Int* subrs_len; /* array of subrs length (optional) */ + + FT_Matrix font_matrix; + + FT_Int flex_state; + FT_Int num_flex_vectors; + FT_Vector flex_vectors[7]; + + T1_Blend* blend; /* for multiple master support */ + + const T1_Decoder_Funcs* funcs; + T1_Decoder_Parse_Func parse_glyph; + }; + + + struct T1_Decoder_Funcs_ + { + FT_Error (*init) ( T1_Decoder* decoder, + FT_Face face, + FT_Size size, + FT_GlyphSlot slot, + FT_Byte** glyph_names, + T1_Blend* blend, + T1_Decoder_Parse_Func parse ); + + void (*done) ( T1_Decoder* decoder ); + + FT_Error (*parse_charstrings)( T1_Decoder* decoder, + FT_Byte* base, + FT_UInt len ); + + + }; + /*************************************************************************/ /*************************************************************************/ /***** *****/ @@ -478,6 +576,7 @@ const PS_Table_Funcs* t1_table_funcs; const T1_Parser_Funcs* t1_parser_funcs; const T1_Builder_Funcs* t1_builder_funcs; + const T1_Decoder_Funcs* t1_decoder_funcs; void (*t1_decrypt)( FT_Byte* buffer, FT_Int length, diff --git a/include/freetype/internal/t1types.h b/include/freetype/internal/t1types.h index a84ad838a..8db60b05e 100644 --- a/include/freetype/internal/t1types.h +++ b/include/freetype/internal/t1types.h @@ -165,6 +165,7 @@ FT_FaceRec root; T1_Font type1; void* psnames; + void* psaux; void* afm_data; FT_CharMapRec charmaprecs[2]; FT_CharMap charmaps[2]; diff --git a/src/base/ftglyph.c b/src/base/ftglyph.c index 99cd7b83f..5f9f1bce2 100644 --- a/src/base/ftglyph.c +++ b/src/base/ftglyph.c @@ -859,335 +859,7 @@ } -#if 0 - - /*************************************************************************/ - /*************************************************************************/ - /**** ****/ - /**** EXPERIMENTAL EMBOLDENING/OUTLINING SUPPORT ****/ - /**** ****/ - /*************************************************************************/ - /*************************************************************************/ - - /* Compute the norm of a vector */ - -#ifdef FT_CONFIG_OPTION_OLD_CALCS - - static - FT_Pos ft_norm( FT_Vector* vec ) - { - FT_Int64 t1, t2; - - - MUL_64( vec->x, vec->x, t1 ); - MUL_64( vec->y, vec->y, t2 ); - ADD_64( t1, t2, t1 ); - - return (FT_Pos)SQRT_64( t1 ); - } - -#else /* FT_CONFIG_OPTION_OLD_CALCS */ - - static - FT_Pos ft_norm( FT_Vector* vec ) - { - FT_F26Dot6 u, v, d; - FT_Int shift; - FT_ULong H, L, L2, hi, lo, med; - - - u = vec->x; if ( u < 0 ) u = -u; - v = vec->y; if ( v < 0 ) v = -v; - - if ( u < v ) - { - d = u; - u = v; - v = d; - } - - /* check that we are not trying to normalize zero! */ - if ( u == 0 ) - return 0; - - /* compute (u*u + v*v) on 64 bits with two 32-bit registers [H:L] */ - hi = (FT_ULong)u >> 16; - lo = (FT_ULong)u & 0xFFFF; - med = hi * lo; - - H = hi * hi + ( med >> 15 ); - med <<= 17; - L = lo * lo + med; - if ( L < med ) - H++; - - hi = (FT_ULong)v >> 16; - lo = (FT_ULong)v & 0xFFFF; - med = hi * lo; - - H += hi * hi + ( med >> 15 ); - med <<= 17; - L2 = lo * lo + med; - if ( L2 < med ) - H++; - - L += L2; - if ( L < L2 ) - H++; - - /* if the value is smaller than 32 bits */ - shift = 0; - if ( H == 0 ) - { - while ( ( L & 0xC0000000UL ) == 0 ) - { - L <<= 2; - shift++; - } - return ( FT_Sqrt32( L ) >> shift ); - } - else - { - while ( H ) - { - L = ( L >> 2 ) | ( H << 30 ); - H >>= 2; - shift++; - } - return ( FT_Sqrt32( L ) << shift ); - } - } - -#endif /* FT_CONFIG_OPTION_OLD_CALCS */ - - - static - int ft_test_extrema( FT_Outline* outline, - int n ) - { - FT_Vector *prev, *cur, *next; - FT_Pos product; - FT_Int first, last; - - - /* we need to compute the `previous' and `next' point */ - /* for these extrema. */ - cur = outline->points + n; - prev = cur - 1; - next = cur + 1; - - first = 0; - for ( c = 0; c < outline->n_contours; c++ ) - { - last = outline->contours[c]; - - if ( n == first ) - prev = outline->points + last; - - if ( n == last ) - next = outline->points + first; - - first = last + 1; - } - - product = FT_MulDiv( cur->x - prev->x, /* in.x */ - next->y - cur->y, /* out.y */ - 0x40 ) - - - FT_MulDiv( cur->y - prev->y, /* in.y */ - next->x - cur->x, /* out.x */ - 0x40 ); - - if ( product ) - product = product > 0 ? 1 : -1; - - return product; - } - - - /* Compute the orientation of path filling. It differs between TrueType */ - /* and Type1 formats. We could use the `ft_outline_reverse_fill' flag, */ - /* but it is better to re-compute it directly (it seems that this flag */ - /* isn't correctly set for some weird composite glyphs currently). */ - /* */ - /* We do this by computing bounding box points, and computing their */ - /* curvature. */ - /* */ - /* The function returns either 1 or -1. */ - /* */ - static - int ft_get_orientation( FT_Outline* outline ) - { - FT_BBox box; - FT_BBox indices; - int n, last; - - - indices.xMin = -1; - indices.yMin = -1; - indices.xMax = -1; - indices.yMax = -1; - - box.xMin = box.yMin = 32767; - box.xMax = box.yMax = -32768; - - /* is it empty ? */ - if ( outline->n_contours < 1 ) - return 1; - - last = outline->contours[outline->n_contours - 1]; - - for ( n = 0; n <= last; n++ ) - { - FT_Pos x, y; - - - x = outline->points[n].x; - if ( x < box.xMin ) - { - box.xMin = x; - indices.xMin = n; - } - if ( x > box.xMax ) - { - box.xMax = x; - indices.xMax = n; - } - - y = outline->points[n].y; - if ( y < box.yMin ) - { - box.yMin = y; - indices.yMin = n; - } - if ( y > box.yMax ) - { - box.yMax = y; - indices.yMax = n; - } - } - - /* test orientation of the xmin */ - n = ft_test_extrema( outline, indices.xMin ); - if (n) goto Exit; - - n = ft_test_extrema( outline, indices.yMin ); - if (n) goto Exit; - - n = ft_test_extrema( outline, indices.xMax ); - if (n) goto Exit; - - n = ft_test_extrema( outline, indices.yMax ); - if (!n) - n = 1; - - Exit: - return n; - } - - - static - FT_Error ft_embolden( FT_Face original, - FT_Outline* outline, - FT_Pos* advance ) - { - FT_Vector u, v; - FT_Vector* points; - FT_Vector cur, prev, next; - FT_Pos distance; - int c, n, first, orientation; - - FT_UNUSED( advance ); - - - /* compute control distance */ - distance = FT_MulFix( original->em_size / 60, - original->size->metrics.y_scale ); - - orientation = ft_get_orientation( &original->glyph->outline ); - - points = original->glyph->outline.points; - - first = 0; - for ( c = 0; c < outline->n_contours; c++ ) - { - int last = outline->contours[c]; - - - prev = points[last]; - - for ( n = first; n <= last; n++ ) - { - FT_Pos norm, delta, d; - FT_Vector in, out; - - - cur = points[n]; - if ( n < last ) next = points[n + 1]; - else next = points[first]; - - /* compute the in and out vectors */ - in.x = cur.x - prev.x; - in.y = cur.y - prev.y; - - out.x = next.x - cur.x; - out.y = next.y - cur.y; - - /* compute U and V */ - norm = ft_norm( &in ); - u.x = orientation * FT_DivFix( in.y, norm ); - u.y = orientation * -FT_DivFix( in.x, norm ); - - norm = ft_norm( &out ); - v.x = orientation * FT_DivFix( out.y, norm ); - v.y = orientation * -FT_DivFix( out.x, norm ); - - d = distance; - - if ( ( outline->flags[n] & FT_Curve_Tag_On ) == 0 ) - d *= 2; - - /* Check discriminant for parallel vectors */ - delta = FT_MulFix( u.x, v.y ) - FT_MulFix( u.y, v.x ); - if ( delta > FT_BOLD_THRESHOLD || delta < -FT_BOLD_THRESHOLD ) - { - /* Move point -- compute A and B */ - FT_Pos x, y, A, B; - - - A = d + FT_MulFix( cur.x, u.x ) + FT_MulFix( cur.y, u.y ); - B = d + FT_MulFix( cur.x, v.x ) + FT_MulFix( cur.y, v.y ); - - x = FT_MulFix( A, v.y ) - FT_MulFix( B, u.y ); - y = FT_MulFix( B, u.x ) - FT_MulFix( A, v.x ); - - outline->points[n].x = distance + FT_DivFix( x, delta ); - outline->points[n].y = distance + FT_DivFix( y, delta ); - } - else - { - /* Vectors are nearly parallel */ - FT_Pos x, y; - - - x = distance + cur.x + FT_MulFix( d, u.x + v.x ) / 2; - y = distance + cur.y + FT_MulFix( d, u.y + v.y ) / 2; - - outline->points[n].x = x; - outline->points[n].y = y; - } - - prev = cur; - } - - first = last + 1; - } - - if ( advance ) - *advance = ( *advance + distance * 4 ) & -64; - - return 0; - } +#if 1 #endif /* 0 -- EXPERIMENTAL STUFF! */ diff --git a/src/cid/cidgload.c b/src/cid/cidgload.c index 97c9252be..f8519d091 100644 --- a/src/cid/cidgload.c +++ b/src/cid/cidgload.c @@ -33,7 +33,6 @@ #include #include - /*************************************************************************/ /* */ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ diff --git a/src/psaux/module.mk b/src/psaux/module.mk new file mode 100644 index 000000000..cbc52c29a --- /dev/null +++ b/src/psaux/module.mk @@ -0,0 +1,7 @@ +make_module_list: add_psaux_module + +add_psaux_module: + $(OPEN_DRIVER)psaux_module_class$(CLOSE_DRIVER) + $(ECHO_DRIVER)psaux $(ECHO_DRIVER_DESC)Postscript Type 1 & Type 2 helper module$(ECHO_DRIVER_DONE) + +# EOF diff --git a/src/psaux/psaux.c b/src/psaux/psaux.c new file mode 100644 index 000000000..60af03a46 --- /dev/null +++ b/src/psaux/psaux.c @@ -0,0 +1,16 @@ +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#ifdef FT_FLAT_COMPILE + +#include "psobjs.c" +#include "psmodule.c" +#include "t1decode.c" + +#else + +#include +#include +#include + +#endif + diff --git a/src/psaux/psmodule.c b/src/psaux/psmodule.c new file mode 100644 index 000000000..9f3c85fb4 --- /dev/null +++ b/src/psaux/psmodule.c @@ -0,0 +1,82 @@ +#include +#include +#include + + static + const PS_Table_Funcs ps_table_funcs = + { + PS_Table_New, + PS_Table_Done, + PS_Table_Add, + PS_Table_Release + }; + + + static + const T1_Parser_Funcs t1_parser_funcs = + { + T1_Init_Parser, + T1_Done_Parser, + T1_Skip_Spaces, + T1_Skip_Alpha, + T1_ToInt, + T1_ToFixed, + T1_ToCoordArray, + T1_ToFixedArray, + T1_ToToken, + T1_ToTokenArray, + T1_Load_Field, + T1_Load_Field_Table + }; + + + static + const T1_Builder_Funcs t1_builder_funcs = + { + T1_Builder_Init, + T1_Builder_Done, + T1_Builder_Check_Points, + T1_Builder_Add_Point, + T1_Builder_Add_Point1, + T1_Builder_Add_Contour, + T1_Builder_Start_Point, + T1_Builder_Close_Contour + }; + + + static + const T1_Decoder_Funcs t1_decoder_funcs = + { + T1_Decoder_Init, + T1_Decoder_Done, + T1_Decoder_Parse_Charstrings + }; + + + static + const PSAux_Interface psaux_interface = + { + &ps_table_funcs, + &t1_parser_funcs, + &t1_builder_funcs, + &t1_decoder_funcs, + + T1_Decrypt + }; + + + FT_CPLUSPLUS(const FT_Module_Class) psaux_module_class = + { + 0, + sizeof( FT_ModuleRec ), + "psaux", + 0x10000L, + 0x20000L, + + &psaux_interface, /* module-specific interface */ + + (FT_Module_Constructor) 0, + (FT_Module_Destructor) 0, + (FT_Module_Requester) 0 + }; + diff --git a/src/psaux/psmodule.h b/src/psaux/psmodule.h new file mode 100644 index 000000000..41e3159df --- /dev/null +++ b/src/psaux/psmodule.h @@ -0,0 +1,16 @@ +#ifndef PSMODULE_H +#define PSMODULE_H + +#include + +#ifdef __cplusplus + extern "C" { +#endif + + FT_EXPORT_VAR( const FT_Module_Class ) psaux_driver_class; + +#ifdef __cplusplus + } +#endif + +#endif /* PSMODULE_H */ diff --git a/src/psaux/psobjs.c b/src/psaux/psobjs.c index c0b7cd9c6..92688a665 100644 --- a/src/psaux/psobjs.c +++ b/src/psaux/psobjs.c @@ -229,7 +229,7 @@ FT_Memory memory = table->memory; - if ( table->init == 0xDEADBEEFL ) + if ( (FT_ULong)table->init == 0xDEADBEEFUL ) { FREE( table->block ); FREE( table->elements ); @@ -1133,9 +1133,13 @@ FT_Vector* point = outline->points + outline->n_points; FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points; - - point->x = x >> 16; - point->y = y >> 16; + if (builder->shift) + { + x >>= 16; + y >>= 16; + } + point->x = x; + point->y = y; *control = flag ? FT_Curve_Tag_On : FT_Curve_Tag_Cubic; builder->last = *point; diff --git a/src/psaux/rules.mk b/src/psaux/rules.mk new file mode 100644 index 000000000..896013af0 --- /dev/null +++ b/src/psaux/rules.mk @@ -0,0 +1,70 @@ +# +# FreeType 2 PSAUX driver configuration rules +# + + +# Copyright 1996-2000 by +# David Turner, Robert Wilhelm, and Werner Lemberg. +# +# This file is part of the FreeType project, and may only be used, modified, +# and distributed under the terms of the FreeType project license, +# LICENSE.TXT. By continuing to use, modify, or distribute this file you +# indicate that you have read the license and understand and accept it +# fully. + + +# PSAUX driver directory +# +PSAUX_DIR := $(SRC_)psaux +PSAUX_DIR_ := $(PSAUX_DIR)$(SEP) + + +# compilation flags for the driver +# +PSAUX_COMPILE := $(FT_COMPILE) + + +# PSAUX driver sources (i.e., C files) +# +PSAUX_DRV_SRC := $(PSAUX_DIR_)psobjs.c \ + $(PSAUX_DIR_)t1decode.c \ + $(PSAUX_DIR_)psmodule.c + +# PSAUX driver headers +# +PSAUX_DRV_H := $(PSAUX_DRV_SRC:%c=%h) + + +# PSAUX driver object(s) +# +# PSAUX_DRV_OBJ_M is used during `multi' builds. +# PSAUX_DRV_OBJ_S is used during `single' builds. +# +PSAUX_DRV_OBJ_M := $(PSAUX_DRV_SRC:$(PSAUX_DIR_)%.c=$(OBJ_)%.$O) +PSAUX_DRV_OBJ_S := $(OBJ_)psaux.$O + +# PSAUX driver source file for single build +# +PSAUX_DRV_SRC_S := $(PSAUX_DIR_)psaux.c + + +# PSAUX driver - single object +# +$(PSAUX_DRV_OBJ_S): $(PSAUX_DRV_SRC_S) $(PSAUX_DRV_SRC) \ + $(FREETYPE_H) $(PSAUX_DRV_H) + $(PSAUX_COMPILE) $T$@ $(PSAUX_DRV_SRC_S) + + +# PSAUX driver - multiple objects +# +$(OBJ_)%.$O: $(PSAUX_DIR_)%.c $(FREETYPE_H) $(PSAUX_DRV_H) + $(PSAUX_COMPILE) $T$@ $< + + +# update main driver object lists +# +DRV_OBJS_S += $(PSAUX_DRV_OBJ_S) +DRV_OBJS_M += $(PSAUX_DRV_OBJ_M) + + +# EOF diff --git a/src/psaux/t1decode.c b/src/psaux/t1decode.c new file mode 100644 index 000000000..9f129c3e7 --- /dev/null +++ b/src/psaux/t1decode.c @@ -0,0 +1,1026 @@ +#include +#include +#include +#include + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_t1decode + + + typedef enum T1_Operator_ + { + op_none = 0, + op_endchar, + op_hsbw, + op_seac, + op_sbw, + op_closepath, + op_hlineto, + op_hmoveto, + op_hvcurveto, + op_rlineto, + op_rmoveto, + op_rrcurveto, + op_vhcurveto, + op_vlineto, + op_vmoveto, + op_dotsection, + op_hstem, + op_hstem3, + op_vstem, + op_vstem3, + op_div, + op_callothersubr, + op_callsubr, + op_pop, + op_return, + op_setcurrentpoint, + + op_max /* never remove this one */ + + } T1_Operator; + + static + const FT_Int t1_args_count[op_max] = + { + 0, /* none */ + 0, /* endchar */ + 2, /* hsbw */ + 5, /* seac */ + 4, /* sbw */ + 0, /* closepath */ + 1, /* hlineto */ + 1, /* hmoveto */ + 4, /* hvcurveto */ + 2, /* rlineto */ + 2, /* rmoveto */ + 6, /* rrcurveto */ + 4, /* vhcurveto */ + 1, /* vlineto */ + 1, /* vmoveto */ + 0, /* dotsection */ + 2, /* hstem */ + 6, /* hstem3 */ + 2, /* vstem */ + 6, /* vstem3 */ + 2, /* div */ + -1, /* callothersubr */ + 1, /* callsubr */ + 0, /* pop */ + 0, /* return */ + 2 /* setcurrentpoint */ + }; + + + /*************************************************************************/ + /* */ + /* */ + /* lookup_glyph_by_stdcharcode */ + /* */ + /* */ + /* Looks up a given glyph by its StandardEncoding charcode. Used */ + /* to implement the SEAC Type 1 operator. */ + /* */ + /* */ + /* face :: The current face object. */ + /* */ + /* charcode :: The character code to look for. */ + /* */ + /* */ + /* A glyph index in the font face. Returns -1 if the corresponding */ + /* glyph wasn't found. */ + /* */ + static + FT_Int t1_lookup_glyph_by_stdcharcode( T1_Decoder* decoder, + FT_Int charcode ) + { + FT_UInt n; + const FT_String* glyph_name; + PSNames_Interface* psnames = decoder->psnames; + + + /* check range of standard char code */ + if ( charcode < 0 || charcode > 255 ) + return -1; + + glyph_name = psnames->adobe_std_strings( + psnames->adobe_std_encoding[charcode]); + + for ( n = 0; n < decoder->num_glyphs; n++ ) + { + FT_String* name = (FT_String*)decoder->glyph_names[n]; + + + if ( name && strcmp( name,glyph_name ) == 0 ) + return n; + } + + return -1; + } + + + /*************************************************************************/ + /* */ + /* */ + /* t1operator_seac */ + /* */ + /* */ + /* Implements the `seac' Type 1 operator for a Type 1 decoder. */ + /* */ + /* */ + /* decoder :: The current CID decoder. */ + /* */ + /* asb :: The accent's side bearing. */ + /* */ + /* adx :: The horizontal offset of the accent. */ + /* */ + /* ady :: The vertical offset of the accent. */ + /* */ + /* bchar :: The base character's StandardEncoding charcode. */ + /* */ + /* achar :: The accent character's StandardEncoding charcode. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + static + FT_Error t1operator_seac( T1_Decoder* decoder, + FT_Pos asb, + FT_Pos adx, + FT_Pos ady, + FT_Int bchar, + FT_Int achar ) + { + FT_Error error; + FT_Int bchar_index, achar_index, n_base_points; + FT_Outline* base = decoder->builder.base; + FT_Vector left_bearing, advance; + + + /* seac weirdness */ + adx += decoder->builder.left_bearing.x; + + bchar_index = t1_lookup_glyph_by_stdcharcode( decoder, bchar ); + achar_index = t1_lookup_glyph_by_stdcharcode( decoder, achar ); + + if ( bchar_index < 0 || achar_index < 0 ) + { + FT_ERROR(( "t1operator_seac:" )); + FT_ERROR(( " invalid seac character code arguments\n" )); + return T1_Err_Syntax_Error; + } + + /* if we are trying to load a composite glyph, do not load the */ + /* accent character and return the array of subglyphs. */ + if ( decoder->builder.no_recurse ) + { + FT_GlyphSlot glyph = (FT_GlyphSlot)decoder->builder.glyph; + FT_GlyphLoader* loader = glyph->loader; + FT_SubGlyph* subg; + + + /* reallocate subglyph array if necessary */ + error = FT_GlyphLoader_Check_Subglyphs( loader, 2 ); + if ( error ) + goto Exit; + + subg = loader->current.subglyphs; + + /* subglyph 0 = base character */ + subg->index = bchar_index; + subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES | + FT_SUBGLYPH_FLAG_USE_MY_METRICS; + subg->arg1 = 0; + subg->arg2 = 0; + subg++; + + /* subglyph 1 = accent character */ + subg->index = achar_index; + subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES; + subg->arg1 = adx - asb; + subg->arg2 = ady; + + /* set up remaining glyph fields */ + glyph->num_subglyphs = 2; + glyph->subglyphs = loader->base.subglyphs; + glyph->format = ft_glyph_format_composite; + + loader->current.num_subglyphs = 2; + } + + /* First load `bchar' in builder */ + /* now load the unscaled outline */ + + FT_GlyphLoader_Prepare( decoder->builder.loader ); /* prepare loader */ + + error = T1_Decoder_Parse_Glyph( decoder, bchar_index ); + if ( error ) + goto Exit; + + n_base_points = base->n_points; + + /* save the left bearing and width of the base character */ + /* as they will be erased by the next load. */ + + left_bearing = decoder->builder.left_bearing; + advance = decoder->builder.advance; + + decoder->builder.left_bearing.x = 0; + decoder->builder.left_bearing.y = 0; + + /* Now load `achar' on top of */ + /* the base outline */ + error = T1_Decoder_Parse_Glyph( decoder, achar_index ); + if ( error ) + goto Exit; + + /* restore the left side bearing and */ + /* advance width of the base character */ + + decoder->builder.left_bearing = left_bearing; + decoder->builder.advance = advance; + + /* Finally, move the accent */ + if ( decoder->builder.load_points ) + { + FT_Outline dummy; + + + dummy.n_points = base->n_points - n_base_points; + dummy.points = base->points + n_base_points; + FT_Outline_Translate( &dummy, adx - asb, ady ); + } + + Exit: + return error; + } + + + + /*************************************************************************/ + /* */ + /* */ + /* T1_Decoder_Parse_Charstrings */ + /* */ + /* */ + /* Parses a given Type 1 charstrings program. */ + /* */ + /* */ + /* decoder :: The current Type 1 decoder. */ + /* */ + /* charstring_base :: The base address of the charstring stream. */ + /* */ + /* charstring_len :: The length in bytes of the charstring stream. */ + /* */ + /* */ + /* Free error code. 0 means success. */ + /* */ + LOCAL_FUNC + FT_Error T1_Decoder_Parse_Charstrings( T1_Decoder* decoder, + FT_Byte* charstring_base, + FT_UInt charstring_len ) + { + FT_Error error; + T1_Decoder_Zone* zone; + FT_Byte* ip; + FT_Byte* limit; + T1_Builder* builder = &decoder->builder; + FT_Outline* outline; + FT_Pos x, y; + + /* we don't want to touch the source code -- use macro trick */ +#define start_point T1_Builder_Start_Point +#define check_points T1_Builder_Check_Points +#define add_point T1_Builder_Add_Point +#define add_point1 T1_Builder_Add_Point1 +#define add_contour T1_Builder_Add_Contour +#define close_contour T1_Builder_Close_Contour + + /* First of all, initialize the decoder */ + decoder->top = decoder->stack; + decoder->zone = decoder->zones; + zone = decoder->zones; + + builder->path_begun = 0; + + zone->base = charstring_base; + limit = zone->limit = charstring_base + charstring_len; + ip = zone->cursor = zone->base; + + error = FT_Err_Ok; + outline = builder->current; + + x = builder->pos_x; + y = builder->pos_y; + + /* now, execute loop */ + while ( ip < limit ) + { + FT_Long* top = decoder->top; + T1_Operator op = op_none; + FT_Long value = 0; + + + /*********************************************************************/ + /* */ + /* Decode operator or operand */ + /* */ + /* */ + + /* first of all, decompress operator or value */ + switch ( *ip++ ) + { + case 1: + op = op_hstem; + break; + + case 3: + op = op_vstem; + break; + case 4: + op = op_vmoveto; + break; + case 5: + op = op_rlineto; + break; + case 6: + op = op_hlineto; + break; + case 7: + op = op_vlineto; + break; + case 8: + op = op_rrcurveto; + break; + case 9: + op = op_closepath; + break; + case 10: + op = op_callsubr; + break; + case 11: + op = op_return; + break; + + case 13: + op = op_hsbw; + break; + case 14: + op = op_endchar; + break; + + case 21: + op = op_rmoveto; + break; + case 22: + op = op_hmoveto; + break; + + case 30: + op = op_vhcurveto; + break; + case 31: + op = op_hvcurveto; + break; + + case 12: + if ( ip > limit ) + { + FT_ERROR(( "T1_Parse_CharStrings: invalid escape (12+EOF)\n" )); + goto Syntax_Error; + } + + switch ( *ip++ ) + { + case 0: + op = op_dotsection; + break; + case 1: + op = op_vstem3; + break; + case 2: + op = op_hstem3; + break; + case 6: + op = op_seac; + break; + case 7: + op = op_sbw; + break; + case 12: + op = op_div; + break; + case 16: + op = op_callothersubr; + break; + case 17: + op = op_pop; + break; + case 33: + op = op_setcurrentpoint; + break; + + default: + FT_ERROR(( "T1_Parse_CharStrings: invalid escape (12+%d)\n", + ip[-1] )); + goto Syntax_Error; + } + break; + + case 255: /* four bytes integer */ + if ( ip + 4 > limit ) + { + FT_ERROR(( "T1_Parse_CharStrings: unexpected EOF in integer\n" )); + goto Syntax_Error; + } + + value = ( (FT_Long)ip[0] << 24 ) | + ( (FT_Long)ip[1] << 16 ) | + ( (FT_Long)ip[2] << 8 ) | + ip[3]; + ip += 4; + break; + + default: + if ( ip[-1] >= 32 ) + { + if ( ip[-1] < 247 ) + value = (FT_Long)ip[-1] - 139; + else + { + if ( ++ip > limit ) + { + FT_ERROR(( "T1_Parse_CharStrings:" )); + FT_ERROR(( " unexpected EOF in integer\n" )); + goto Syntax_Error; + } + + if ( ip[-2] < 251 ) + value = ( ( (FT_Long)ip[-2] - 247 ) << 8 ) + ip[-1] + 108; + else + value = -( ( ( (FT_Long)ip[-2] - 251 ) << 8 ) + ip[-1] + 108 ); + } + } + else + { + FT_ERROR(( "T1_Parse_CharStrings: invalid byte (%d)\n", + ip[-1] )); + goto Syntax_Error; + } + } + + /*********************************************************************/ + /* */ + /* Push value on stack, or process operator */ + /* */ + /* */ + if ( op == op_none ) + { + if ( top - decoder->stack >= T1_MAX_CHARSTRINGS_OPERANDS ) + { + FT_ERROR(( "T1_Parse_CharStrings: stack overflow!\n" )); + goto Syntax_Error; + } + + FT_TRACE4(( " %ld", value )); + + *top++ = value; + decoder->top = top; + } + else if ( op == op_callothersubr ) /* callothersubr */ + { + FT_TRACE4(( " callothersubr" )); + + if ( top - decoder->stack < 2 ) + goto Stack_Underflow; + + top -= 2; + switch ( top[1] ) + { + case 1: /* start flex feature */ + if ( top[0] != 0 ) + goto Unexpected_OtherSubr; + + decoder->flex_state = 1; + decoder->num_flex_vectors = 0; + if ( start_point( builder, x, y ) || + check_points( builder, 6 ) ) + goto Memory_Error; + break; + + case 2: /* add flex vectors */ + { + FT_Int index; + + if ( top[0] != 0 ) + goto Unexpected_OtherSubr; + + /* note that we should not add a point for index 0; */ + /* this will move our current position to the flex */ + /* point without adding any point to the outline */ + index = decoder->num_flex_vectors++; + if ( index > 0 && index < 7 ) + add_point( builder, + x, + y, + (FT_Byte)( index == 3 || index == 6 ) ); + } + break; + + case 0: /* end flex feature */ + if ( top[0] != 3 ) + goto Unexpected_OtherSubr; + + if ( decoder->flex_state == 0 || + decoder->num_flex_vectors != 7 ) + { + FT_ERROR(( "T1_Parse_CharStrings: unexpected flex end\n" )); + goto Syntax_Error; + } + + /* now consume the remaining `pop pop setcurpoint' */ + if ( ip + 6 > limit || + ip[0] != 12 || ip[1] != 17 || /* pop */ + ip[2] != 12 || ip[3] != 17 || /* pop */ + ip[4] != 12 || ip[5] != 33 ) /* setcurpoint */ + { + FT_ERROR(( "T1_Parse_CharStrings: invalid flex charstring\n" )); + goto Syntax_Error; + } + + ip += 6; + decoder->flex_state = 0; + break; + + case 3: /* change hints */ + if ( top[0] != 1 ) + goto Unexpected_OtherSubr; + + /* eat the following `pop' */ + if ( ip + 2 > limit ) + { + FT_ERROR(( "T1_Parse_CharStrings: invalid escape (12+%d)\n", + ip[-1] )); + goto Syntax_Error; + } + + if ( ip[0] != 12 || ip[1] != 17 ) + { + FT_ERROR(( "T1_Parse_CharStrings:" )); + FT_ERROR(( " `pop' expected, found (%d %d)\n", + ip[0], ip[1] )); + goto Syntax_Error; + } + ip += 2; + 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; + FT_UInt num_points, nn, mm; + FT_Long* delta; + FT_Long* values; + + + if ( !blend ) + { + FT_ERROR(( "T1_Parse_CharStrings:" )); + FT_ERROR(( " unexpected multiple masters operator!\n" )); + goto Syntax_Error; + } + + num_points = top[1] - 13 + ( top[1] == 18 ); + if ( top[0] != (FT_Int)( num_points * blend->num_designs ) ) + { + FT_ERROR(( "T1_Parse_CharStrings:" )); + FT_ERROR(( " 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++ ) + { + FT_Int tmp = values[0]; + + + for ( mm = 1; mm < blend->num_designs; mm++ ) + tmp += FT_MulFix( *delta++, blend->weight_vector[mm] ); + + *values++ = tmp; + } + /* 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", + top[0], top[1] )); + goto Syntax_Error; + } + decoder->top = top; + } + else /* general operator */ + { + FT_Int num_args = t1_args_count[op]; + + + if ( top - decoder->stack < num_args ) + goto Stack_Underflow; + + top -= num_args; + + switch ( op ) + { + case op_endchar: + FT_TRACE4(( " endchar" )); + + close_contour( builder ); + + /* add current outline to the glyph slot */ + FT_GlyphLoader_Add( builder->loader ); + + /* return now! */ + FT_TRACE4(( "\n\n" )); + return FT_Err_Ok; + + case op_hsbw: + FT_TRACE4(( " hsbw" )); + + builder->left_bearing.x += top[0]; + builder->advance.x = top[1]; + builder->advance.y = 0; + + builder->last.x = x = top[0]; + builder->last.y = y = 0; + + /* the `metrics_only' indicates that we only want to compute */ + /* the glyph's metrics (lsb + advance width), not load the */ + /* rest of it; so exit immediately */ + if ( builder->metrics_only ) + return FT_Err_Ok; + + break; + + case op_seac: + /* return immediately after the processing */ + return t1operator_seac( decoder, top[0], top[1], + top[2], top[3], top[4] ); + + case op_sbw: + FT_TRACE4(( " sbw" )); + + builder->left_bearing.x += top[0]; + builder->left_bearing.y += top[1]; + builder->advance.x = top[2]; + builder->advance.y = top[3]; + + builder->last.x = x = top[0]; + builder->last.y = y = top[1]; + + /* the `metrics_only' indicates that we only want to compute */ + /* the glyph's metrics (lsb + advance width), not load the */ + /* rest of it; so exit immediately */ + if ( builder->metrics_only ) + return FT_Err_Ok; + + break; + + case op_closepath: + FT_TRACE4(( " closepath" )); + + close_contour( builder ); + builder->path_begun = 0; + break; + + case op_hlineto: + FT_TRACE4(( " hlineto" )); + + if ( start_point( builder, x, y ) ) + goto Memory_Error; + + x += top[0]; + goto Add_Line; + + case op_hmoveto: + FT_TRACE4(( " hmoveto" )); + + x += top[0]; + builder->path_begun = 0; + break; + + case op_hvcurveto: + FT_TRACE4(( " hvcurveto" )); + + if ( start_point( builder, x, y ) || + check_points( builder, 3 ) ) + goto Memory_Error; + + x += top[0]; + add_point( builder, x, y, 0 ); + x += top[1]; + y += top[2]; + add_point( builder, x, y, 0 ); + y += top[3]; + add_point( builder, x, y, 1 ); + break; + + case op_rlineto: + FT_TRACE4(( " rlineto" )); + + if ( start_point( builder, x, y ) ) + goto Memory_Error; + + x += top[0]; + y += top[1]; + + Add_Line: + if ( add_point1( builder, x, y ) ) + goto Memory_Error; + break; + + case op_rmoveto: + FT_TRACE4(( " rmoveto" )); + + x += top[0]; + y += top[1]; + builder->path_begun = 0; + break; + + case op_rrcurveto: + FT_TRACE4(( " rcurveto" )); + + if ( start_point( builder, x, y ) || + check_points( builder, 3 ) ) + goto Memory_Error; + + x += top[0]; + y += top[1]; + add_point( builder, x, y, 0 ); + + x += top[2]; + y += top[3]; + add_point( builder, x, y, 0 ); + + x += top[4]; + y += top[5]; + add_point( builder, x, y, 1 ); + break; + + case op_vhcurveto: + FT_TRACE4(( " vhcurveto" )); + + if ( start_point( builder, x, y ) || + check_points( builder, 3 ) ) + goto Memory_Error; + + y += top[0]; + add_point( builder, x, y, 0 ); + x += top[1]; + y += top[2]; + add_point( builder, x, y, 0 ); + x += top[3]; + add_point( builder, x, y, 1 ); + break; + + case op_vlineto: + FT_TRACE4(( " vlineto" )); + + if ( start_point( builder, x, y ) ) + goto Memory_Error; + + y += top[0]; + goto Add_Line; + + case op_vmoveto: + FT_TRACE4(( " vmoveto" )); + + y += top[0]; + builder->path_begun = 0; + break; + + case op_div: + FT_TRACE4(( " div" )); + + if ( top[1] ) + { + *top = top[0] / top[1]; + ++top; + } + else + { + FT_ERROR(( "T1_Parse_CharStrings: division by 0\n" )); + goto Syntax_Error; + } + break; + + case op_callsubr: + { + FT_Int index; + + + FT_TRACE4(( " callsubr" )); + + index = top[0]; + if ( index < 0 || index >= (FT_Int)decoder->num_subrs ) + { + FT_ERROR(( "T1_Parse_CharStrings: invalid subrs index\n" )); + goto Syntax_Error; + } + + if ( zone - decoder->zones >= T1_MAX_SUBRS_CALLS ) + { + FT_ERROR(( "T1_Parse_CharStrings: too many nested subrs\n" )); + goto Syntax_Error; + } + + zone->cursor = ip; /* save current instruction pointer */ + + zone++; + zone->base = decoder->subrs[index] + decoder->lenIV; + + if (decoder->subrs_len) + zone->limit = zone->base + decoder->subrs_len[index]; + else + zone->limit = decoder->subrs[index+1]; + + zone->cursor = zone->base; + + if ( !zone->base ) + { + FT_ERROR(( "T1_Parse_CharStrings: invoking empty subrs!\n" )); + goto Syntax_Error; + } + + decoder->zone = zone; + ip = zone->base; + limit = zone->limit; + break; + } + + case op_pop: + FT_TRACE4(( " pop" )); + + /* theorically, the arguments are already on the stack */ + top++; + break; + + case op_return: + FT_TRACE4(( " return" )); + + if ( zone <= decoder->zones ) + { + FT_ERROR(( "T1_Parse_CharStrings: unexpected return\n" )); + goto Syntax_Error; + } + + zone--; + ip = zone->cursor; + limit = zone->limit; + decoder->zone = zone; + break; + + case op_dotsection: + FT_TRACE4(( " dotsection" )); + + break; + + case op_hstem: + FT_TRACE4(( " hstem" )); + + break; + + case op_hstem3: + FT_TRACE4(( " hstem3" )); + + break; + + case op_vstem: + FT_TRACE4(( " vstem" )); + + break; + + case op_vstem3: + FT_TRACE4(( " vstem3" )); + + break; + + case op_setcurrentpoint: + FT_TRACE4(( " setcurrentpoint" )); + + FT_ERROR(( "T1_Parse_CharStrings:" )); + FT_ERROR(( " unexpected `setcurrentpoint'\n" )); + goto Syntax_Error; + + default: + FT_ERROR(( "T1_Parse_CharStrings: unhandled opcode %d\n", op )); + goto Syntax_Error; + } + + decoder->top = top; + + } /* general operator processing */ + + } /* while ip < limit */ + + FT_TRACE4(( "..end..\n\n" )); + return error; + + Syntax_Error: + return T1_Err_Syntax_Error; + + Stack_Underflow: + return T1_Err_Stack_Underflow; + + Memory_Error: + return builder->error; + } + + + LOCAL_FUNC + FT_Error T1_Decoder_Parse_Glyph( T1_Decoder* decoder, + FT_UInt glyph ) + { + return decoder->parse_glyph( decoder, glyph ); + } + + + LOCAL_FUNC + FT_Error T1_Decoder_Init( T1_Decoder* decoder, + FT_Face face, + FT_Size size, + FT_GlyphSlot slot, + FT_Byte** glyph_names, + T1_Blend* blend, + T1_Decoder_Parse_Func parse_glyph ) + { + MEM_Set( decoder, 0, sizeof(*decoder) ); + + /* retrieve PSNames interface from list of current modules */ + { + PSNames_Interface* psnames = 0; + + psnames = (PSNames_Interface*)FT_Get_Module_Interface( + FT_FACE_LIBRARY(face), "psnames" ); + if (!psnames) + { + FT_ERROR(( "T1_Decoder_Init: the 'psnames' module is not available\n" )); + return FT_Err_Unimplemented_Feature; + } + + decoder->psnames = psnames; + } + T1_Builder_Init( &decoder->builder, face, size, slot ); + + decoder->num_glyphs = face->num_glyphs; + decoder->glyph_names = glyph_names; + decoder->blend = blend; + decoder->parse_glyph = parse_glyph; + + decoder->funcs = &t1_decoder_funcs; + return 0; + } + + + LOCAL_FUNC + void T1_Decoder_Done( T1_Decoder* decoder ) + { + T1_Builder_Done( &decoder->builder ); + } + diff --git a/src/psaux/t1decode.h b/src/psaux/t1decode.h new file mode 100644 index 000000000..b85575006 --- /dev/null +++ b/src/psaux/t1decode.h @@ -0,0 +1,32 @@ +#ifndef T1DECODE_H +#define T1DECODE_H + +#include +#include +#include + + LOCAL_DEF + const T1_Decoder_Funcs t1_decoder_funcs; + + LOCAL_DEF + FT_Error T1_Decoder_Parse_Glyph( T1_Decoder* decoder, + FT_UInt glyph_index ); + + LOCAL_DEF + FT_Error T1_Decoder_Parse_Charstrings( T1_Decoder* decoder, + FT_Byte* base, + FT_UInt len ); + + LOCAL_DEF + FT_Error T1_Decoder_Init( T1_Decoder* decoder, + FT_Face face, + FT_Size size, + FT_GlyphSlot slot, + FT_Byte** glyph_names, + T1_Blend* blend, + T1_Decoder_Parse_Func parse_glyph ); + + LOCAL_DEF + void T1_Decoder_Done( T1_Decoder* decoder ); + +#endif /* T1DECODE_H */ diff --git a/src/type1z/z1gload.c b/src/type1z/z1gload.c index 15999cb9c..9eaa101e3 100644 --- a/src/type1z/z1gload.c +++ b/src/type1z/z1gload.c @@ -30,6 +30,8 @@ #include #include #include +#include + #include /* for strcmp() */ @@ -44,1235 +46,6 @@ #define FT_COMPONENT trace_z1gload - typedef enum Z1_Operator_ - { - op_none = 0, - op_endchar, - op_hsbw, - op_seac, - op_sbw, - op_closepath, - op_hlineto, - op_hmoveto, - op_hvcurveto, - op_rlineto, - op_rmoveto, - op_rrcurveto, - op_vhcurveto, - op_vlineto, - op_vmoveto, - op_dotsection, - op_hstem, - op_hstem3, - op_vstem, - op_vstem3, - op_div, - op_callothersubr, - op_callsubr, - op_pop, - op_return, - op_setcurrentpoint, - - op_max /* never remove this one */ - - } Z1_Operator; - - static - const FT_Int t1_args_count[op_max] = - { - 0, /* none */ - 0, /* endchar */ - 2, /* hsbw */ - 5, /* seac */ - 4, /* sbw */ - 0, /* closepath */ - 1, /* hlineto */ - 1, /* hmoveto */ - 4, /* hvcurveto */ - 2, /* rlineto */ - 2, /* rmoveto */ - 6, /* rrcurveto */ - 4, /* vhcurveto */ - 1, /* vlineto */ - 1, /* vmoveto */ - 0, /* dotsection */ - 2, /* hstem */ - 6, /* hstem3 */ - 2, /* vstem */ - 6, /* vstem3 */ - 2, /* div */ - -1, /* callothersubr */ - 1, /* callsubr */ - 0, /* pop */ - 0, /* return */ - 2 /* setcurrentpoint */ - }; - - - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - /********** *********/ - /********** *********/ - /********** GENERIC CHARSTRING PARSING *********/ - /********** *********/ - /********** *********/ - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - - - /*************************************************************************/ - /* */ - /* */ - /* Z1_Init_Builder */ - /* */ - /* */ - /* Initializes a given glyph builder. */ - /* */ - /* */ - /* builder :: A pointer to the glyph builder to initialize. */ - /* */ - /* */ - /* face :: The current face object. */ - /* */ - /* size :: The current size object. */ - /* */ - /* glyph :: The current glyph object. */ - /* */ - LOCAL_FUNC - void Z1_Init_Builder( Z1_Builder* builder, - T1_Face face, - Z1_Size size, - Z1_GlyphSlot glyph ) - { - builder->path_begun = 0; - builder->load_points = 1; - - builder->face = face; - builder->glyph = glyph; - builder->memory = face->root.memory; - - if ( glyph ) - { - FT_GlyphLoader* loader = glyph->root.loader; - - - builder->loader = loader; - builder->current = &loader->current.outline; - builder->base = &loader->base.outline; - - FT_GlyphLoader_Rewind( loader ); - } - - if ( size ) - { - builder->scale_x = size->root.metrics.x_scale; - builder->scale_y = size->root.metrics.y_scale; - } - - builder->pos_x = 0; - builder->pos_y = 0; - - builder->left_bearing.x = 0; - builder->left_bearing.y = 0; - builder->advance.x = 0; - builder->advance.y = 0; - } - - - /*************************************************************************/ - /* */ - /* */ - /* Z1_Done_Builder */ - /* */ - /* */ - /* Finalizes a given glyph builder. Its contents can still be used */ - /* after the call, but the function saves important information */ - /* within the corresponding glyph slot. */ - /* */ - /* */ - /* builder :: A pointer to the glyph builder to finalize. */ - /* */ - LOCAL_FUNC - void Z1_Done_Builder( Z1_Builder* builder ) - { - Z1_GlyphSlot glyph = builder->glyph; - - - if ( glyph ) - glyph->root.outline = *builder->base; - } - - - /*************************************************************************/ - /* */ - /* */ - /* Z1_Init_Decoder */ - /* */ - /* */ - /* Initializes a given glyph decoder. */ - /* */ - /* */ - /* decoder :: A pointer to the glyph builder to initialize. */ - /* */ - LOCAL_FUNC - void Z1_Init_Decoder( Z1_Decoder* decoder ) - { - decoder->top = 0; - 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 ) ); - } - - - /* check that there is enough space for `count' more points */ - static - FT_Error check_points( Z1_Builder* builder, - FT_Int count ) - { - return FT_GlyphLoader_Check_Points( builder->loader, count, 0 ); - } - - - /* add a new point; do not check space */ - static - void add_point( Z1_Builder* builder, - FT_Pos x, - FT_Pos y, - FT_Byte flag ) - { - FT_Outline* outline = builder->current; - - - if ( builder->load_points ) - { - FT_Vector* point = outline->points + outline->n_points; - FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points; - - - point->x = x; - point->y = y; - *control = flag ? FT_Curve_Tag_On : FT_Curve_Tag_Cubic; - - builder->last = *point; - } - - outline->n_points++; - } - - - /* check space for a new on-curve point, then add it */ - static - FT_Error add_point1( Z1_Builder* builder, - FT_Pos x, - FT_Pos y ) - { - FT_Error error; - - - error = check_points( builder, 1 ); - if ( !error ) - add_point( builder, x, y, 1 ); - - return error; - } - - - /* check space for a new contour, then add it */ - static - FT_Error add_contour( Z1_Builder* builder ) - { - FT_Outline* outline = builder->current; - FT_Error error; - - - if ( !builder->load_points ) - { - outline->n_contours++; - return FT_Err_Ok; - } - - /* reallocate contours array if necessary */ - error = FT_GlyphLoader_Check_Points( builder->loader, 0, 1 ); - if ( !error ) - { - if ( outline->n_contours > 0 ) - outline->contours[outline->n_contours - 1] = outline->n_points - 1; - - outline->n_contours++; - } - - return error; - } - - - /* if a path was begun, add its first on-curve point */ - static - FT_Error start_point( Z1_Builder* builder, - FT_Pos x, - FT_Pos y ) - { - /* test whether we are building a new contour */ - if ( !builder->path_begun ) - { - FT_Error error; - - - builder->path_begun = 1; - error = add_contour( builder ); - if ( error ) - return error; - } - return add_point1( builder, x, y ); - } - - - /* close the current contour */ - static - void close_contour( Z1_Builder* builder ) - { - FT_Outline* outline = builder->current; - - - /* XXX: we must not include the last point in the path if it */ - /* is located on the first point */ - if ( outline->n_points > 1 ) - { - FT_Int first = 0; - FT_Vector* p1 = outline->points + first; - FT_Vector* p2 = outline->points + outline->n_points-1; - - - if ( outline->n_contours > 1 ) - { - first = outline->contours[outline->n_contours - 2] + 1; - p1 = outline->points + first; - } - - if ( p1->x == p2->x && p1->y == p2->y ) - outline->n_points--; - } - - if ( outline->n_contours > 0 ) - outline->contours[outline->n_contours - 1] = outline->n_points - 1; - } - - - /*************************************************************************/ - /* */ - /* */ - /* lookup_glyph_by_stdcharcode */ - /* */ - /* */ - /* Looks up a given glyph by its StandardEncoding charcode. Used */ - /* to implement the SEAC Type 1 operator. */ - /* */ - /* */ - /* face :: The current face object. */ - /* */ - /* charcode :: The character code to look for. */ - /* */ - /* */ - /* A glyph index in the font face. Returns -1 if the corresponding */ - /* glyph wasn't found. */ - /* */ - static - FT_Int lookup_glyph_by_stdcharcode( T1_Face face, - FT_Int charcode ) - { - FT_Int n; - const FT_String* glyph_name; - PSNames_Interface* psnames = (PSNames_Interface*)face->psnames; - - - /* check range of standard char code */ - if ( charcode < 0 || charcode > 255 ) - return -1; - - glyph_name = psnames->adobe_std_strings( - psnames->adobe_std_encoding[charcode]); - - for ( n = 0; n < face->type1.num_glyphs; n++ ) - { - FT_String* name = (FT_String*)face->type1.glyph_names[n]; - - - if ( name && strcmp( name,glyph_name ) == 0 ) - return n; - } - - return -1; - } - - - /*************************************************************************/ - /* */ - /* */ - /* t1operator_seac */ - /* */ - /* */ - /* Implements the `seac' Type 1 operator for a Type 1 decoder. */ - /* */ - /* */ - /* decoder :: The current CID decoder. */ - /* */ - /* asb :: The accent's side bearing. */ - /* */ - /* adx :: The horizontal offset of the accent. */ - /* */ - /* ady :: The vertical offset of the accent. */ - /* */ - /* bchar :: The base character's StandardEncoding charcode. */ - /* */ - /* achar :: The accent character's StandardEncoding charcode. */ - /* */ - /* */ - /* FreeType error code. 0 means success. */ - /* */ - static - FT_Error t1operator_seac( Z1_Decoder* decoder, - FT_Pos asb, - FT_Pos adx, - FT_Pos ady, - FT_Int bchar, - FT_Int achar ) - { - FT_Error error; - FT_Int bchar_index, achar_index, n_base_points; - FT_Outline* base = decoder->builder.base; - FT_Vector left_bearing, advance; - T1_Face face = decoder->builder.face; - T1_Font* type1 = &face->type1; - - - /* seac weirdness */ - adx += decoder->builder.left_bearing.x; - - bchar_index = lookup_glyph_by_stdcharcode( face, bchar ); - achar_index = lookup_glyph_by_stdcharcode( face, achar ); - - if ( bchar_index < 0 || achar_index < 0 ) - { - FT_ERROR(( "t1operator_seac:" )); - FT_ERROR(( " invalid seac character code arguments\n" )); - return T1_Err_Syntax_Error; - } - - /* if we are trying to load a composite glyph, do not load the */ - /* accent character and return the array of subglyphs. */ - if ( decoder->builder.no_recurse ) - { - FT_GlyphSlot glyph = (FT_GlyphSlot)decoder->builder.glyph; - FT_GlyphLoader* loader = glyph->loader; - FT_SubGlyph* subg; - - - /* reallocate subglyph array if necessary */ - error = FT_GlyphLoader_Check_Subglyphs( loader, 2 ); - if ( error ) - goto Exit; - - subg = loader->current.subglyphs; - - /* subglyph 0 = base character */ - subg->index = bchar_index; - subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES | - FT_SUBGLYPH_FLAG_USE_MY_METRICS; - subg->arg1 = 0; - subg->arg2 = 0; - subg++; - - /* subglyph 1 = accent character */ - subg->index = achar_index; - subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES; - subg->arg1 = adx - asb; - subg->arg2 = ady; - - /* set up remaining glyph fields */ - glyph->num_subglyphs = 2; - glyph->subglyphs = loader->base.subglyphs; - glyph->format = ft_glyph_format_composite; - - loader->current.num_subglyphs = 2; - } - - /* First load `bchar' in builder */ - /* now load the unscaled outline */ - - FT_GlyphLoader_Prepare( decoder->builder.loader ); /* prepare loader */ - - error = Z1_Parse_CharStrings( decoder, - type1->charstrings [bchar_index], - type1->charstrings_len[bchar_index], - type1->num_subrs, - type1->subrs, - type1->subrs_len ); - if ( error ) - goto Exit; - - n_base_points = base->n_points; - - /* save the left bearing and width of the base character */ - /* as they will be erased by the next load. */ - - left_bearing = decoder->builder.left_bearing; - advance = decoder->builder.advance; - - decoder->builder.left_bearing.x = 0; - decoder->builder.left_bearing.y = 0; - - /* Now load `achar' on top of */ - /* the base outline */ - error = Z1_Parse_CharStrings( decoder, - type1->charstrings [achar_index], - type1->charstrings_len[achar_index], - type1->num_subrs, - type1->subrs, - type1->subrs_len ); - if ( error ) - return error; - - /* restore the left side bearing and */ - /* advance width of the base character */ - - decoder->builder.left_bearing = left_bearing; - decoder->builder.advance = advance; - - /* Finally, move the accent */ - if ( decoder->builder.load_points ) - { - FT_Outline dummy; - - - dummy.n_points = base->n_points - n_base_points; - dummy.points = base->points + n_base_points; - FT_Outline_Translate( &dummy, adx - asb, ady ); - } - - Exit: - return error; - } - - -#define USE_ARGS( n ) do \ - { \ - top -= n; \ - if ( top < decoder->stack ) \ - goto Stack_Underflow; \ - } while ( 0 ) - - - /*************************************************************************/ - /* */ - /* */ - /* Z1_Parse_CharStrings */ - /* */ - /* */ - /* Parses a given Type 1 charstrings program. */ - /* */ - /* */ - /* decoder :: The current Type 1 decoder. */ - /* */ - /* charstring_base :: The base address of the charstring stream. */ - /* */ - /* charstring_len :: The length in bytes of the charstring stream. */ - /* */ - /* num_subrs :: The number of sub-routines. */ - /* */ - /* subrs_base :: An array of sub-routines addresses. */ - /* */ - /* subrs_len :: An array of sub-routines lengths. */ - /* */ - /* */ - /* Free error code. 0 means success. */ - /* */ - LOCAL_FUNC - FT_Error Z1_Parse_CharStrings( Z1_Decoder* decoder, - FT_Byte* charstring_base, - FT_Int charstring_len, - FT_Int num_subrs, - FT_Byte** subrs_base, - FT_Int* subrs_len ) - { - FT_Error error; - Z1_Decoder_Zone* zone; - FT_Byte* ip; - FT_Byte* limit; - Z1_Builder* builder = &decoder->builder; - FT_Outline* outline; - FT_Pos x, y; - - - /* First of all, initialize the decoder */ - decoder->top = decoder->stack; - decoder->zone = decoder->zones; - zone = decoder->zones; - - builder->path_begun = 0; - - zone->base = charstring_base; - limit = zone->limit = charstring_base + charstring_len; - ip = zone->cursor = zone->base; - - error = T1_Err_Ok; - outline = builder->current; - - x = builder->pos_x; - y = builder->pos_y; - - /* now, execute loop */ - while ( ip < limit ) - { - FT_Int* top = decoder->top; - Z1_Operator op = op_none; - FT_Long value = 0; - - - /*********************************************************************/ - /* */ - /* Decode operator or operand */ - /* */ - /* */ - - /* first of all, decompress operator or value */ - switch ( *ip++ ) - { - case 1: - op = op_hstem; - break; - - case 3: - op = op_vstem; - break; - case 4: - op = op_vmoveto; - break; - case 5: - op = op_rlineto; - break; - case 6: - op = op_hlineto; - break; - case 7: - op = op_vlineto; - break; - case 8: - op = op_rrcurveto; - break; - case 9: - op = op_closepath; - break; - case 10: - op = op_callsubr; - break; - case 11: - op = op_return; - break; - - case 13: - op = op_hsbw; - break; - case 14: - op = op_endchar; - break; - - case 21: - op = op_rmoveto; - break; - case 22: - op = op_hmoveto; - break; - - case 30: - op = op_vhcurveto; - break; - case 31: - op = op_hvcurveto; - break; - - case 12: - if ( ip > limit ) - { - FT_ERROR(( "Z1_Parse_CharStrings: invalid escape (12+EOF)\n" )); - goto Syntax_Error; - } - - switch ( *ip++ ) - { - case 0: - op = op_dotsection; - break; - case 1: - op = op_vstem3; - break; - case 2: - op = op_hstem3; - break; - case 6: - op = op_seac; - break; - case 7: - op = op_sbw; - break; - case 12: - op = op_div; - break; - case 16: - op = op_callothersubr; - break; - case 17: - op = op_pop; - break; - case 33: - op = op_setcurrentpoint; - break; - - default: - FT_ERROR(( "Z1_Parse_CharStrings: invalid escape (12+%d)\n", - ip[-1] )); - goto Syntax_Error; - } - break; - - case 255: /* four bytes integer */ - if ( ip + 4 > limit ) - { - FT_ERROR(( "Z1_Parse_CharStrings: unexpected EOF in integer\n" )); - goto Syntax_Error; - } - - value = ( (FT_Long)ip[0] << 24 ) | - ( (FT_Long)ip[1] << 16 ) | - ( (FT_Long)ip[2] << 8 ) | - ip[3]; - ip += 4; - break; - - default: - if ( ip[-1] >= 32 ) - { - if ( ip[-1] < 247 ) - value = (FT_Long)ip[-1] - 139; - else - { - if ( ++ip > limit ) - { - FT_ERROR(( "Z1_Parse_CharStrings:" )); - FT_ERROR(( " unexpected EOF in integer\n" )); - goto Syntax_Error; - } - - if ( ip[-2] < 251 ) - value = ( (FT_Long)( ip[-2] - 247 ) << 8 ) + ip[-1] + 108; - else - value = -( ( ( (FT_Long)ip[-2] - 251 ) << 8 ) + ip[-1] + 108 ); - } - } - else - { - FT_ERROR(( "Z1_Parse_CharStrings: invalid byte (%d)\n", - ip[-1] )); - goto Syntax_Error; - } - } - - /*********************************************************************/ - /* */ - /* Push value on stack, or process operator */ - /* */ - /* */ - if ( op == op_none ) - { - if ( top - decoder->stack >= T1_MAX_CHARSTRINGS_OPERANDS ) - { - FT_ERROR(( "Z1_Parse_CharStrings: stack overflow!\n" )); - goto Syntax_Error; - } - - FT_TRACE4(( " %ld", value )); - - *top++ = value; - decoder->top = top; - } - else if ( op == op_callothersubr ) /* callothersubr */ - { - FT_TRACE4(( " callothersubr" )); - - if ( top - decoder->stack < 2 ) - goto Stack_Underflow; - - top -= 2; - switch ( top[1] ) - { - case 1: /* start flex feature */ - if ( top[0] != 0 ) - goto Unexpected_OtherSubr; - - decoder->flex_state = 1; - decoder->num_flex_vectors = 0; - if ( start_point( builder, x, y ) || - check_points( builder, 6 ) ) - goto Memory_Error; - break; - - case 2: /* add flex vectors */ - { - FT_Int index; - - if ( top[0] != 0 ) - goto Unexpected_OtherSubr; - - /* note that we should not add a point for index 0; */ - /* this will move our current position to the flex */ - /* point without adding any point to the outline */ - index = decoder->num_flex_vectors++; - if ( index > 0 && index < 7 ) - add_point( builder, - x, - y, - (FT_Byte)( index == 3 || index == 6 ) ); - } - break; - - case 0: /* end flex feature */ - if ( top[0] != 3 ) - goto Unexpected_OtherSubr; - - if ( decoder->flex_state == 0 || - decoder->num_flex_vectors != 7 ) - { - FT_ERROR(( "Z1_Parse_CharStrings: unexpected flex end\n" )); - goto Syntax_Error; - } - - /* now consume the remaining `pop pop setcurpoint' */ - if ( ip + 6 > limit || - ip[0] != 12 || ip[1] != 17 || /* pop */ - ip[2] != 12 || ip[3] != 17 || /* pop */ - ip[4] != 12 || ip[5] != 33 ) /* setcurpoint */ - { - FT_ERROR(( "Z1_Parse_CharStrings: invalid flex charstring\n" )); - goto Syntax_Error; - } - - ip += 6; - decoder->flex_state = 0; - break; - - case 3: /* change hints */ - if ( top[0] != 1 ) - goto Unexpected_OtherSubr; - - /* eat the following `pop' */ - if ( ip + 2 > limit ) - { - FT_ERROR(( "Z1_Parse_CharStrings: invalid escape (12+%d)\n", - ip[-1] )); - goto Syntax_Error; - } - - if ( ip[0] != 12 || ip[1] != 17 ) - { - FT_ERROR(( "Z1_Parse_CharStrings:" )); - FT_ERROR(( " `pop' expected, found (%d %d)\n", - ip[0], ip[1] )); - goto Syntax_Error; - } - ip += 2; - 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; - FT_UInt num_points, nn, mm; - FT_Int* delta; - FT_Int* values; - - - if ( !blend ) - { - FT_ERROR(( "Z1_Parse_CharStrings:" )); - FT_ERROR(( " unexpected multiple masters operator!\n" )); - goto Syntax_Error; - } - - num_points = top[1] - 13 + ( top[1] == 18 ); - if ( top[0] != (FT_Int)( num_points * blend->num_designs ) ) - { - FT_ERROR(( "Z1_Parse_CharStrings:" )); - FT_ERROR(( " 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++ ) - { - FT_Int tmp = values[0]; - - - for ( mm = 1; mm < blend->num_designs; mm++ ) - tmp += FT_MulFix( *delta++, blend->weight_vector[mm] ); - - *values++ = tmp; - } - /* note that `top' will be incremented later by calls to `pop' */ - break; - } - - default: - Unexpected_OtherSubr: - FT_ERROR(( "Z1_Parse_CharStrings: invalid othersubr [%d %d]!\n", - top[0], top[1] )); - goto Syntax_Error; - } - decoder->top = top; - } - else /* general operator */ - { - FT_Int num_args = t1_args_count[op]; - - - if ( top - decoder->stack < num_args ) - goto Stack_Underflow; - - top -= num_args; - - switch ( op ) - { - case op_endchar: - FT_TRACE4(( " endchar" )); - - close_contour( builder ); - - /* add current outline to the glyph slot */ - FT_GlyphLoader_Add( builder->loader ); - - /* return now! */ - FT_TRACE4(( "\n\n" )); - return T1_Err_Ok; - - case op_hsbw: - FT_TRACE4(( " hsbw" )); - - builder->left_bearing.x += top[0]; - builder->advance.x = top[1]; - builder->advance.y = 0; - - builder->last.x = x = top[0]; - builder->last.y = y = 0; - - /* the `metrics_only' indicates that we only want to compute */ - /* the glyph's metrics (lsb + advance width), not load the */ - /* rest of it; so exit immediately */ - if ( builder->metrics_only ) - return T1_Err_Ok; - - break; - - case op_seac: - /* return immediately after the processing */ - return t1operator_seac( decoder, top[0], top[1], - top[2], top[3], top[4] ); - - case op_sbw: - FT_TRACE4(( " sbw" )); - - builder->left_bearing.x += top[0]; - builder->left_bearing.y += top[1]; - builder->advance.x = top[2]; - builder->advance.y = top[3]; - - builder->last.x = x = top[0]; - builder->last.y = y = top[1]; - - /* the `metrics_only' indicates that we only want to compute */ - /* the glyph's metrics (lsb + advance width), not load the */ - /* rest of it; so exit immediately */ - if ( builder->metrics_only ) - return T1_Err_Ok; - - break; - - case op_closepath: - FT_TRACE4(( " closepath" )); - - close_contour( builder ); - builder->path_begun = 0; - break; - - case op_hlineto: - FT_TRACE4(( " hlineto" )); - - if ( start_point( builder, x, y ) ) - goto Memory_Error; - - x += top[0]; - goto Add_Line; - - case op_hmoveto: - FT_TRACE4(( " hmoveto" )); - - x += top[0]; - builder->path_begun = 0; - break; - - case op_hvcurveto: - FT_TRACE4(( " hvcurveto" )); - - if ( start_point( builder, x, y ) || - check_points( builder, 3 ) ) - goto Memory_Error; - - x += top[0]; - add_point( builder, x, y, 0 ); - x += top[1]; - y += top[2]; - add_point( builder, x, y, 0 ); - y += top[3]; - add_point( builder, x, y, 1 ); - break; - - case op_rlineto: - FT_TRACE4(( " rlineto" )); - - if ( start_point( builder, x, y ) ) - goto Memory_Error; - - x += top[0]; - y += top[1]; - - Add_Line: - if ( add_point1( builder, x, y ) ) - goto Memory_Error; - break; - - case op_rmoveto: - FT_TRACE4(( " rmoveto" )); - - x += top[0]; - y += top[1]; - builder->path_begun = 0; - break; - - case op_rrcurveto: - FT_TRACE4(( " rcurveto" )); - - if ( start_point( builder, x, y ) || - check_points( builder, 3 ) ) - goto Memory_Error; - - x += top[0]; - y += top[1]; - add_point( builder, x, y, 0 ); - - x += top[2]; - y += top[3]; - add_point( builder, x, y, 0 ); - - x += top[4]; - y += top[5]; - add_point( builder, x, y, 1 ); - break; - - case op_vhcurveto: - FT_TRACE4(( " vhcurveto" )); - - if ( start_point( builder, x, y ) || - check_points( builder, 3 ) ) - goto Memory_Error; - - y += top[0]; - add_point( builder, x, y, 0 ); - x += top[1]; - y += top[2]; - add_point( builder, x, y, 0 ); - x += top[3]; - add_point( builder, x, y, 1 ); - break; - - case op_vlineto: - FT_TRACE4(( " vlineto" )); - - if ( start_point( builder, x, y ) ) - goto Memory_Error; - - y += top[0]; - goto Add_Line; - - case op_vmoveto: - FT_TRACE4(( " vmoveto" )); - - y += top[0]; - builder->path_begun = 0; - break; - - case op_div: - FT_TRACE4(( " div" )); - - if ( top[1] ) - { - *top = top[0] / top[1]; - ++top; - } - else - { - FT_ERROR(( "Z1_Parse_CharStrings: division by 0\n" )); - goto Syntax_Error; - } - break; - - case op_callsubr: - { - FT_Int index; - - - FT_TRACE4(( " callsubr" )); - - index = top[0]; - if ( index < 0 || index >= num_subrs ) - { - FT_ERROR(( "Z1_Parse_CharStrings: invalid subrs index\n" )); - goto Syntax_Error; - } - - if ( zone - decoder->zones >= T1_MAX_SUBRS_CALLS ) - { - FT_ERROR(( "Z1_Parse_CharStrings: too many nested subrs\n" )); - goto Syntax_Error; - } - - zone->cursor = ip; /* save current instruction pointer */ - - zone++; - zone->base = subrs_base[index]; - zone->limit = zone->base + subrs_len[index]; - zone->cursor = zone->base; - - if ( !zone->base ) - { - FT_ERROR(( "Z1_Parse_CharStrings: invoking empty subrs!\n" )); - goto Syntax_Error; - } - - decoder->zone = zone; - ip = zone->base; - limit = zone->limit; - break; - } - - case op_pop: - FT_TRACE4(( " pop" )); - - /* theorically, the arguments are already on the stack */ - top++; - break; - - case op_return: - FT_TRACE4(( " return" )); - - if ( zone <= decoder->zones ) - { - FT_ERROR(( "Z1_Parse_CharStrings: unexpected return\n" )); - goto Syntax_Error; - } - - zone--; - ip = zone->cursor; - limit = zone->limit; - decoder->zone = zone; - break; - - case op_dotsection: - FT_TRACE4(( " dotsection" )); - - break; - - case op_hstem: - FT_TRACE4(( " hstem" )); - - break; - - case op_hstem3: - FT_TRACE4(( " hstem3" )); - - break; - - case op_vstem: - FT_TRACE4(( " vstem" )); - - break; - - case op_vstem3: - FT_TRACE4(( " vstem3" )); - - break; - - case op_setcurrentpoint: - FT_TRACE4(( " setcurrentpoint" )); - - FT_ERROR(( "Z1_Parse_CharStrings:" )); - FT_ERROR(( " unexpected `setcurrentpoint'\n" )); - goto Syntax_Error; - - default: - FT_ERROR(( "Z1_Parse_CharStrings: unhandled opcode %d\n", op )); - goto Syntax_Error; - } - - decoder->top = top; - - } /* general operator processing */ - - } /* while ip < limit */ - - FT_TRACE4(( "..end..\n\n" )); - return error; - - Syntax_Error: - return T1_Err_Syntax_Error; - - Stack_Underflow: - return T1_Err_Stack_Underflow; - - Memory_Error: - return builder->error; - } - /*************************************************************************/ /*************************************************************************/ @@ -1291,37 +64,53 @@ /*************************************************************************/ + static + FT_Error Z1_Parse_Glyph( T1_Decoder* decoder, + FT_UInt glyph_index ) + { + T1_Face face = (T1_Face)decoder->builder.face; + T1_Font* type1 = &face->type1; + + return decoder->funcs->parse_charstrings( decoder, + type1->charstrings [glyph_index], + type1->charstrings_len[glyph_index] ); + } + LOCAL_FUNC FT_Error Z1_Compute_Max_Advance( T1_Face face, FT_Int* max_advance ) { - FT_Error error; - Z1_Decoder decoder; - FT_Int glyph_index; - T1_Font* type1 = &face->type1; + FT_Error error; + T1_Decoder decoder; + FT_Int glyph_index; + T1_Font* type1 = &face->type1; + PSAux_Interface* psaux = (PSAux_Interface*)face->psaux; *max_advance = 0; /* Initialize load decoder */ - Z1_Init_Decoder( &decoder ); - Z1_Init_Builder( &decoder.builder, face, 0, 0 ); + error = psaux->t1_decoder_funcs->init( &decoder, + (FT_Face)face, + 0, /* size */ + 0, /* glyph slot */ + (FT_Byte**)type1->glyph_names, + face->blend, + Z1_Parse_Glyph ); - decoder.blend = face->blend; decoder.builder.metrics_only = 1; decoder.builder.load_points = 0; + decoder.num_subrs = type1->num_subrs; + decoder.subrs = type1->subrs; + decoder.subrs_len = type1->subrs_len; + /* for each glyph, parse the glyph charstring and extract */ /* the advance width */ for ( glyph_index = 0; glyph_index < type1->num_glyphs; glyph_index++ ) { /* now get load the unscaled outline */ - error = Z1_Parse_CharStrings( &decoder, - type1->charstrings [glyph_index], - type1->charstrings_len[glyph_index], - type1->num_subrs, - type1->subrs, - type1->subrs_len ); + error = Z1_Parse_Glyph( &decoder, glyph_index ); /* ignore the error if one occured - skip to next glyph */ } @@ -1353,11 +142,13 @@ FT_Int glyph_index, FT_Int load_flags ) { - FT_Error error; - Z1_Decoder decoder; - T1_Face face = (T1_Face)glyph->root.face; - FT_Bool hinting; - T1_Font* type1 = &face->type1; + FT_Error error; + T1_Decoder decoder; + T1_Face face = (T1_Face)glyph->root.face; + FT_Bool hinting; + T1_Font* type1 = &face->type1; + PSAux_Interface* psaux = (PSAux_Interface*)face->psaux; + const T1_Decoder_Funcs* decoder_funcs = psaux->t1_decoder_funcs; if ( load_flags & FT_LOAD_NO_RECURSE ) @@ -1374,22 +165,30 @@ glyph->root.format = ft_glyph_format_outline; - Z1_Init_Decoder( &decoder ); - Z1_Init_Builder( &decoder.builder, face, size, glyph ); - - decoder.blend = ((T1_Face)glyph->root.face)->blend; + error = decoder_funcs->init( &decoder, + (FT_Face)face, + (FT_Size)size, + (FT_GlyphSlot)glyph, + (FT_Byte**)type1->glyph_names, + face->blend, + Z1_Parse_Glyph ); + if (error) + goto Exit; + decoder.builder.no_recurse = ( load_flags & FT_LOAD_NO_RECURSE ) != 0; + decoder.num_subrs = type1->num_subrs; + decoder.subrs = type1->subrs; + decoder.subrs_len = type1->subrs_len; + + /* now load the unscaled outline */ - error = Z1_Parse_CharStrings( &decoder, - type1->charstrings [glyph_index], - type1->charstrings_len[glyph_index], - type1->num_subrs, - type1->subrs, - type1->subrs_len ); + error = Z1_Parse_Glyph( &decoder, glyph_index ); + if (error) + goto Exit; /* save new glyph tables */ - Z1_Done_Builder( &decoder.builder ); + decoder_funcs->done( &decoder ); /* now, set the metrics -- this is rather simple, as */ /* the left side bearing is the xMin, and the top side */ @@ -1485,6 +284,7 @@ metrics->horiBearingY = cbox.yMax; } } + Exit: return error; } diff --git a/src/type1z/z1gload.h b/src/type1z/z1gload.h index 5bb6dc0a2..de7b8dca0 100644 --- a/src/type1z/z1gload.h +++ b/src/type1z/z1gload.h @@ -36,139 +36,11 @@ #endif - /*************************************************************************/ - /* */ - /* */ - /* Z1_Builder */ - /* */ - /* */ - /* A structure used during glyph loading to store its outline. */ - /* */ - /* */ - /* memory :: The current memory object. */ - /* */ - /* face :: The current face object. */ - /* */ - /* glyph :: The current glyph slot. */ - /* */ - /* loader :: The current glyph loader. */ - /* */ - /* current :: The current glyph outline. */ - /* */ - /* base :: The base glyph outline. */ - /* */ - /* last :: The last point position. */ - /* */ - /* scale_x :: The horizontal scale (FUnits to sub-pixels). */ - /* */ - /* scale_y :: The vertical scale (FUnits to sub-pixels). */ - /* */ - /* pos_x :: The horizontal translation (for composite glyphs). */ - /* */ - /* pos_y :: The vertical translation (for composite glyphs). */ - /* */ - /* left_bearing :: The left side bearing point. */ - /* */ - /* advance :: The horizontal advance vector. */ - /* */ - /* no_recurse :: */ - /* */ - /* bbox :: The glyph's bounding box. */ - /* */ - /* path_begun :: A flag which indicates that a new path has begun. */ - /* */ - /* load_points :: A flag which indicates, if not set, that no points */ - /* are loaded. */ - /* */ - /* error :: The current error code. */ - /* */ - /* metrics_only :: A flag whether to compute metrics only. */ - /* */ - typedef struct Z1_Builder_ - { - FT_Memory memory; - T1_Face face; - Z1_GlyphSlot glyph; - FT_GlyphLoader* loader; - - FT_Outline* current; /* the current glyph outline */ - FT_Outline* base; /* the composite glyph outline */ - - FT_Vector last; - - FT_Fixed scale_x; - FT_Fixed scale_y; - - FT_Pos pos_x; - FT_Pos pos_y; - - FT_Vector left_bearing; - FT_Vector advance; - - FT_BBox bbox; /* bounding box */ - FT_Bool path_begun; - FT_Bool load_points; - FT_Bool no_recurse; - - FT_Error error; /* only used for memory errors */ - FT_Bool metrics_only; - - } Z1_Builder; - - - /* execution context charstring zone */ - typedef struct Z1_Decoder_Zone_ - { - FT_Byte* base; - FT_Byte* limit; - FT_Byte* cursor; - - } Z1_Decoder_Zone; - - - typedef struct Z1_Decoder_ - { - Z1_Builder builder; - - FT_Int stack[T1_MAX_CHARSTRINGS_OPERANDS]; - FT_Int* top; - - Z1_Decoder_Zone zones[T1_MAX_SUBRS_CALLS + 1]; - Z1_Decoder_Zone* zone; - - FT_Int flex_state; - FT_Int num_flex_vectors; - FT_Vector flex_vectors[7]; - - T1_Blend* blend; /* for multiple masters */ - - } Z1_Decoder; - - - LOCAL_DEF - void Z1_Init_Builder( Z1_Builder* builder, - T1_Face face, - Z1_Size size, - Z1_GlyphSlot glyph ); - - LOCAL_DEF - void Z1_Done_Builder( Z1_Builder* builder ); - - LOCAL_DEF - void Z1_Init_Decoder( Z1_Decoder* decoder ); LOCAL_DEF FT_Error Z1_Compute_Max_Advance( T1_Face face, FT_Int* max_advance ); - LOCAL_DEF - FT_Error Z1_Parse_CharStrings( Z1_Decoder* decoder, - FT_Byte* charstring_base, - FT_Int charstring_len, - FT_Int num_subrs, - FT_Byte** subrs_base, - FT_Int* subrs_len ); - LOCAL_DEF FT_Error Z1_Load_Glyph( Z1_GlyphSlot glyph, Z1_Size size, diff --git a/src/type1z/z1load.c b/src/type1z/z1load.c index dd70892f0..5cb1f8e30 100644 --- a/src/type1z/z1load.c +++ b/src/type1z/z1load.c @@ -634,7 +634,7 @@ } Z1_ToToken( parser, &master ); - if ( master.type != t1_token_array ) + if ( master.type != z1_token_array ) { FT_ERROR(( "parse_weight_vector: incorrect format!\n" )); error = T1_Err_Invalid_File_Format; @@ -699,42 +699,42 @@ #define Z1_NEW_STRING( _name, _field ) \ static \ - const Z1_Field_Rec t1_field_ ## _field = \ + const Z1_Field_Rec z1_field_ ## _field = \ Z1_FIELD_STRING( _field ); #define Z1_NEW_BOOL( _name, _field ) \ static \ - const Z1_Field_Rec t1_field_ ## _field = \ + const Z1_Field_Rec z1_field_ ## _field = \ Z1_FIELD_BOOL( _field ); #define Z1_NEW_NUM( _name, _field ) \ static \ - const Z1_Field_Rec t1_field_ ## _field = \ + const Z1_Field_Rec z1_field_ ## _field = \ Z1_FIELD_NUM( _field ); #define Z1_NEW_FIXED( _name, _field ) \ static \ - const Z1_Field_Rec t1_field_ ## _field = \ + const Z1_Field_Rec z1_field_ ## _field = \ Z1_FIELD_FIXED( _field, _power ); #define Z1_NEW_NUM_TABLE( _name, _field, _max, _count ) \ static \ - const Z1_Field_Rec t1_field_ ## _field = \ + const Z1_Field_Rec z1_field_ ## _field = \ Z1_FIELD_NUM_ARRAY( _field, _count, _max ); #define Z1_NEW_FIXED_TABLE( _name, _field, _max, _count ) \ static \ - const Z1_Field_Rec t1_field_ ## _field = \ + const Z1_Field_Rec z1_field_ ## _field = \ Z1_FIELD_FIXED_ARRAY( _field, _count, _max ); #define Z1_NEW_NUM_TABLE2( _name, _field, _max ) \ static \ - const Z1_Field_Rec t1_field_ ## _field = \ + const Z1_Field_Rec z1_field_ ## _field = \ Z1_FIELD_NUM_ARRAY2( _field, _max ); #define Z1_NEW_FIXED_TABLE2( _name, _field, _max ) \ static \ - const Z1_Field_Rec t1_field_ ## _field = \ + const Z1_Field_Rec z1_field_ ## _field = \ Z1_FIELD_FIXED_ARRAY2( _field, _max ); @@ -808,29 +808,29 @@ #define Z1_KEYWORD_TYPE1( name, f ) \ { \ - name, t1_keyword_field, t1_keyword_type1, 0, &t1_field_ ## f \ + name, t1_keyword_field, t1_keyword_type1, 0, &z1_field_ ## f \ } #define Z1_KEYWORD_FONTINFO( name, f ) \ { \ - name, t1_keyword_field, t1_keyword_font_info, 0, &t1_field_ ## f \ + name, t1_keyword_field, t1_keyword_font_info, 0, &z1_field_ ## f \ } #define Z1_KEYWORD_PRIVATE( name, f ) \ { \ - name, t1_keyword_field, t1_keyword_private, 0, &t1_field_ ## f \ + name, t1_keyword_field, t1_keyword_private, 0, &z1_field_ ## f \ } #define Z1_KEYWORD_FONTINFO_TABLE( name, f ) \ { \ name, t1_keyword_field_table, t1_keyword_font_info, 0, \ - &t1_field_ ## f \ + &z1_field_ ## f \ } #define Z1_KEYWORD_PRIVATE_TABLE( name, f ) \ { \ name, t1_keyword_field_table, t1_keyword_private, 0, \ - &t1_field_ ## f \ + &z1_field_ ## f \ } @@ -1518,7 +1518,7 @@ Z1_ToToken( &loader->parser, &token ); /* if the last token was an array, skip it! */ - if ( token.type == t1_token_array ) + if ( token.type == z1_token_array ) cur2 = parser->cursor; } cur = cur2; diff --git a/src/type1z/z1load.h b/src/type1z/z1load.h index 672b5531b..9f7685a5a 100644 --- a/src/type1z/z1load.h +++ b/src/type1z/z1load.h @@ -20,7 +20,7 @@ #define Z1LOAD_H #include -#include +#include #include diff --git a/src/type1z/z1objs.c b/src/type1z/z1objs.c index b5079746c..ec8509f2b 100644 --- a/src/type1z/z1objs.c +++ b/src/type1z/z1objs.c @@ -36,6 +36,7 @@ #include +#include /*************************************************************************/ @@ -158,6 +159,7 @@ { FT_Error error; PSNames_Interface* psnames; + PSAux_Interface* psaux; FT_UNUSED( num_params ); FT_UNUSED( params ); @@ -176,6 +178,15 @@ face->psnames = psnames; } + psaux = (PSAux_Interface*)face->psaux; + if (!psaux) + { + psaux = (PSAux_Interface*) + FT_Get_Module_Interface( FT_FACE_LIBRARY( face ), "psaux" ); + + face->psaux = psaux; + } + /* open the tokenizer, this will also check the font format */ error = Z1_Open_Face( face ); if ( error ) diff --git a/src/type1z/z1parse.c b/src/type1z/z1parse.c index 794339dd2..f433f55da 100644 --- a/src/type1z/z1parse.c +++ b/src/type1z/z1parse.c @@ -326,7 +326,7 @@ FT_Int embed; - token->type = t1_token_none; + token->type = z1_token_none; token->start = 0; token->limit = 0; @@ -342,19 +342,19 @@ { /************* check for strings ***********************/ case '(': - token->type = t1_token_string; + token->type = z1_token_string; ender = ')'; goto Lookup_Ender; /************* check for programs/array ****************/ case '{': - token->type = t1_token_array; + token->type = z1_token_array; ender = '}'; goto Lookup_Ender; /************* check for table/array ******************/ case '[': - token->type = t1_token_array; + token->type = z1_token_array; ender = ']'; Lookup_Ender: @@ -381,7 +381,7 @@ /* **************** otherwise, it's any token **********/ default: token->start = cur++; - token->type = t1_token_any; + token->type = z1_token_any; while ( cur < limit && !IS_Z1_SPACE( *cur ) ) cur++; @@ -391,7 +391,7 @@ if ( !token->limit ) { token->start = 0; - token->type = t1_token_none; + token->type = z1_token_none; } parser->cursor = cur; @@ -411,7 +411,7 @@ *pnum_tokens = -1; Z1_ToToken( parser, &master ); - if ( master.type == t1_token_array ) + if ( master.type == z1_token_array ) { FT_Byte* old_cursor = parser->cursor; FT_Byte* old_limit = parser->limit; @@ -819,7 +819,7 @@ cur = token.start; limit = token.limit; - if ( token.type == t1_token_array ) + if ( token.type == z1_token_array ) { /* if this is an array, and we have no blend, an error occurs */ if ( max_objects == 0 ) @@ -837,15 +837,15 @@ switch ( field->type ) { - case t1_field_bool: + case z1_field_bool: val = t1_tobool( &cur, limit ); goto Store_Integer; - case t1_field_fixed: + case z1_field_fixed: val = t1_tofixed( &cur, limit, 3 ); goto Store_Integer; - case t1_field_integer: + case z1_field_integer: val = t1_toint( &cur, limit ); Store_Integer: @@ -868,7 +868,7 @@ } break; - case t1_field_string: + case z1_field_string: { FT_Memory memory = parser->memory; FT_UInt len = limit-cur; diff --git a/src/type1z/z1parse.h b/src/type1z/z1parse.h index ffa8c08dd..39841baf0 100644 --- a/src/type1z/z1parse.h +++ b/src/type1z/z1parse.h @@ -30,13 +30,13 @@ /* simple enumeration type used to identify token types */ typedef enum Z1_Token_Type_ { - t1_token_none = 0, - t1_token_any, - t1_token_string, - t1_token_array, + z1_token_none = 0, + z1_token_any, + z1_token_string, + z1_token_array, /* do not remove */ - t1_token_max + z1_token_max } Z1_Token_Type; @@ -54,16 +54,16 @@ /* enumeration type used to identify object fields */ typedef enum Z1_Field_Type_ { - t1_field_none = 0, - t1_field_bool, - t1_field_integer, - t1_field_fixed, - t1_field_string, - t1_field_integer_array, - t1_field_fixed_array, + z1_field_none = 0, + z1_field_bool, + z1_field_integer, + z1_field_fixed, + z1_field_string, + z1_field_integer_array, + z1_field_fixed_array, /* do not remove */ - t1_field_max + z1_field_max } Z1_Field_Type; @@ -83,7 +83,7 @@ #define Z1_FIELD_BOOL( _fname ) \ { \ - t1_field_bool, \ + z1_field_bool, \ FT_FIELD_OFFSET( _fname ), \ FT_FIELD_SIZE( _fname ), \ 0, 0, 0 \ @@ -91,7 +91,7 @@ #define Z1_FIELD_NUM( _fname ) \ { \ - t1_field_integer, \ + z1_field_integer, \ FT_FIELD_OFFSET( _fname ), \ FT_FIELD_SIZE( _fname ), \ 0, 0, 0 \ @@ -99,7 +99,7 @@ #define Z1_FIELD_FIXED( _fname, _power ) \ { \ - t1_field_fixed, \ + z1_field_fixed, \ FT_FIELD_OFFSET( _fname ), \ FT_FIELD_SIZE( _fname ), \ 0, 0, 0 \ @@ -107,7 +107,7 @@ #define Z1_FIELD_STRING( _fname ) \ { \ - t1_field_string, \ + z1_field_string, \ FT_FIELD_OFFSET( _fname ), \ FT_FIELD_SIZE( _fname ), \ 0, 0, 0 \ @@ -115,7 +115,7 @@ #define Z1_FIELD_NUM_ARRAY( _fname, _fcount, _fmax ) \ { \ - t1_field_integer, \ + z1_field_integer, \ FT_FIELD_OFFSET( _fname ), \ FT_FIELD_SIZE_DELTA( _fname ), \ _fmax, \ @@ -125,7 +125,7 @@ #define Z1_FIELD_FIXED_ARRAY( _fname, _fcount, _fmax ) \ { \ - t1_field_fixed, \ + z1_field_fixed, \ FT_FIELD_OFFSET( _fname ), \ FT_FIELD_SIZE_DELTA( _fname ), \ _fmax, \ @@ -135,7 +135,7 @@ #define Z1_FIELD_NUM_ARRAY2( _fname, _fmax ) \ { \ - t1_field_integer, \ + z1_field_integer, \ FT_FIELD_OFFSET( _fname ), \ FT_FIELD_SIZE_DELTA( _fname ), \ _fmax, \ @@ -144,7 +144,7 @@ #define Z1_FIELD_FIXED_ARRAY2( _fname, _fmax ) \ { \ - t1_field_fixed, \ + z1_field_fixed, \ FT_FIELD_OFFSTE( _fname ), \ FT_FIELD_SIZE_DELTA( _fname ), \ _fmax, \