diff --git a/src/truetype/ttinterp.c b/src/truetype/ttinterp.c index 7bcf089d2..293af9d5d 100644 --- a/src/truetype/ttinterp.c +++ b/src/truetype/ttinterp.c @@ -2628,57 +2628,6 @@ /*************************************************************************/ - static FT_Bool - Ins_SxVTL( TT_ExecContext exc, - FT_UShort aIdx1, - FT_UShort aIdx2, - FT_UnitVector* Vec ) - { - FT_Long A, B, C; - FT_Vector* p1; - FT_Vector* p2; - - FT_Byte opcode = exc->opcode; - - - if ( BOUNDS( aIdx1, exc->zp2.n_points ) || - BOUNDS( aIdx2, exc->zp1.n_points ) ) - { - if ( exc->pedantic_hinting ) - exc->error = FT_THROW( Invalid_Reference ); - return FAILURE; - } - - p1 = exc->zp1.cur + aIdx2; - p2 = exc->zp2.cur + aIdx1; - - A = p1->x - p2->x; - B = p1->y - p2->y; - - /* If p1 == p2, SPvTL and SFvTL behave the same as */ - /* SPvTCA[X] and SFvTCA[X], respectively. */ - /* */ - /* Confirmed by Greg Hitchcock. */ - - if ( A == 0 && B == 0 ) - { - A = 0x4000; - opcode = 0; - } - - if ( ( opcode & 1 ) != 0 ) - { - C = B; /* counter clockwise rotation */ - B = A; - A = -C; - } - - Normalize( A, B, Vec ); - - return SUCCESS; - } - - #define ARRAY_BOUND_ERROR \ do \ { \ @@ -2689,2115 +2638,2158 @@ /*************************************************************************/ /* */ - /* SVTCA[a]: Set (F and P) Vectors to Coordinate Axis */ - /* Opcode range: 0x00-0x01 */ - /* Stack: --> */ - /* */ - /* SPvTCA[a]: Set PVector to Coordinate Axis */ - /* Opcode range: 0x02-0x03 */ - /* Stack: --> */ - /* */ - /* SFvTCA[a]: Set FVector to Coordinate Axis */ - /* Opcode range: 0x04-0x05 */ - /* Stack: --> */ + /* MPPEM[]: Measure Pixel Per EM */ + /* Opcode range: 0x4B */ + /* Stack: --> Euint16 */ /* */ static void - Ins_SxyTCA( TT_ExecContext exc ) + Ins_MPPEM( TT_ExecContext exc, + FT_Long* args ) { - FT_Short AA, BB; - - FT_Byte opcode = exc->opcode; - - - AA = (FT_Short)( ( opcode & 1 ) << 14 ); - BB = (FT_Short)( AA ^ 0x4000 ); - - if ( opcode < 4 ) - { - exc->GS.projVector.x = AA; - exc->GS.projVector.y = BB; - - exc->GS.dualVector.x = AA; - exc->GS.dualVector.y = BB; - } - else - GUESS_VECTOR( projVector ); - - if ( ( opcode & 2 ) == 0 ) - { - exc->GS.freeVector.x = AA; - exc->GS.freeVector.y = BB; - } - else - GUESS_VECTOR( freeVector ); - - Compute_Funcs( exc ); + args[0] = exc->func_cur_ppem( exc ); } /*************************************************************************/ /* */ - /* SPvTL[a]: Set PVector To Line */ - /* Opcode range: 0x06-0x07 */ - /* Stack: uint32 uint32 --> */ + /* MPS[]: Measure Point Size */ + /* Opcode range: 0x4C */ + /* Stack: --> Euint16 */ /* */ static void - Ins_SPVTL( TT_ExecContext exc, - FT_Long* args ) + Ins_MPS( TT_ExecContext exc, + FT_Long* args ) { - if ( Ins_SxVTL( exc, - (FT_UShort)args[1], - (FT_UShort)args[0], - &exc->GS.projVector ) == SUCCESS ) - { - exc->GS.dualVector = exc->GS.projVector; - GUESS_VECTOR( freeVector ); - Compute_Funcs( exc ); - } + /* Note: The point size should be irrelevant in a given font program; */ + /* we thus decide to return only the PPEM value. */ +#if 0 + args[0] = exc->metrics.pointSize; +#else + args[0] = exc->func_cur_ppem( exc ); +#endif } /*************************************************************************/ /* */ - /* SFvTL[a]: Set FVector To Line */ - /* Opcode range: 0x08-0x09 */ - /* Stack: uint32 uint32 --> */ + /* DUP[]: DUPlicate the stack's top element */ + /* Opcode range: 0x20 */ + /* Stack: StkElt --> StkElt StkElt */ /* */ static void - Ins_SFVTL( TT_ExecContext exc, - FT_Long* args ) + Ins_DUP( FT_Long* args ) { - if ( Ins_SxVTL( exc, - (FT_UShort)args[1], - (FT_UShort)args[0], - &exc->GS.freeVector ) == SUCCESS ) - { - GUESS_VECTOR( projVector ); - Compute_Funcs( exc ); - } + args[1] = args[0]; } /*************************************************************************/ /* */ - /* SFvTPv[]: Set FVector To PVector */ - /* Opcode range: 0x0E */ - /* Stack: --> */ + /* POP[]: POP the stack's top element */ + /* Opcode range: 0x21 */ + /* Stack: StkElt --> */ /* */ static void - Ins_SFVTPV( TT_ExecContext exc ) + Ins_POP( void ) { - GUESS_VECTOR( projVector ); - exc->GS.freeVector = exc->GS.projVector; - Compute_Funcs( exc ); + /* nothing to do */ } /*************************************************************************/ /* */ - /* SPvFS[]: Set PVector From Stack */ - /* Opcode range: 0x0A */ - /* Stack: f2.14 f2.14 --> */ + /* CLEAR[]: CLEAR the entire stack */ + /* Opcode range: 0x22 */ + /* Stack: StkElt... --> */ /* */ static void - Ins_SPVFS( TT_ExecContext exc, - FT_Long* args ) + Ins_CLEAR( TT_ExecContext exc ) { - FT_Short S; - FT_Long X, Y; - - - /* Only use low 16bits, then sign extend */ - S = (FT_Short)args[1]; - Y = (FT_Long)S; - S = (FT_Short)args[0]; - X = (FT_Long)S; - - Normalize( X, Y, &exc->GS.projVector ); - - exc->GS.dualVector = exc->GS.projVector; - GUESS_VECTOR( freeVector ); - Compute_Funcs( exc ); + exc->new_top = 0; } /*************************************************************************/ /* */ - /* SFvFS[]: Set FVector From Stack */ - /* Opcode range: 0x0B */ - /* Stack: f2.14 f2.14 --> */ + /* SWAP[]: SWAP the stack's top two elements */ + /* Opcode range: 0x23 */ + /* Stack: 2 * StkElt --> 2 * StkElt */ /* */ static void - Ins_SFVFS( TT_ExecContext exc, - FT_Long* args ) + Ins_SWAP( FT_Long* args ) { - FT_Short S; - FT_Long X, Y; - + FT_Long L; - /* Only use low 16bits, then sign extend */ - S = (FT_Short)args[1]; - Y = (FT_Long)S; - S = (FT_Short)args[0]; - X = S; - Normalize( X, Y, &exc->GS.freeVector ); - GUESS_VECTOR( projVector ); - Compute_Funcs( exc ); + L = args[0]; + args[0] = args[1]; + args[1] = L; } /*************************************************************************/ /* */ - /* GPv[]: Get Projection Vector */ - /* Opcode range: 0x0C */ - /* Stack: ef2.14 --> ef2.14 */ + /* DEPTH[]: return the stack DEPTH */ + /* Opcode range: 0x24 */ + /* Stack: --> uint32 */ /* */ static void - Ins_GPV( TT_ExecContext exc, - FT_Long* args ) + Ins_DEPTH( TT_ExecContext exc, + FT_Long* args ) { -#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING - if ( exc->face->unpatented_hinting ) - { - args[0] = exc->GS.both_x_axis ? 0x4000 : 0; - args[1] = exc->GS.both_x_axis ? 0 : 0x4000; - } - else - { - args[0] = exc->GS.projVector.x; - args[1] = exc->GS.projVector.y; - } -#else - args[0] = exc->GS.projVector.x; - args[1] = exc->GS.projVector.y; -#endif + args[0] = exc->top; } /*************************************************************************/ /* */ - /* GFv[]: Get Freedom Vector */ - /* Opcode range: 0x0D */ - /* Stack: ef2.14 --> ef2.14 */ + /* LT[]: Less Than */ + /* Opcode range: 0x50 */ + /* Stack: int32? int32? --> bool */ /* */ static void - Ins_GFV( TT_ExecContext exc, - FT_Long* args ) + Ins_LT( FT_Long* args ) { -#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING - if ( exc->face->unpatented_hinting ) - { - args[0] = exc->GS.both_x_axis ? 0x4000 : 0; - args[1] = exc->GS.both_x_axis ? 0 : 0x4000; - } - else - { - args[0] = exc->GS.freeVector.x; - args[1] = exc->GS.freeVector.y; - } -#else - args[0] = exc->GS.freeVector.x; - args[1] = exc->GS.freeVector.y; -#endif + args[0] = ( args[0] < args[1] ); } /*************************************************************************/ /* */ - /* SRP0[]: Set Reference Point 0 */ - /* Opcode range: 0x10 */ - /* Stack: uint32 --> */ + /* LTEQ[]: Less Than or EQual */ + /* Opcode range: 0x51 */ + /* Stack: int32? int32? --> bool */ /* */ static void - Ins_SRP0( TT_ExecContext exc, - FT_Long* args ) + Ins_LTEQ( FT_Long* args ) { - exc->GS.rp0 = (FT_UShort)args[0]; + args[0] = ( args[0] <= args[1] ); } /*************************************************************************/ /* */ - /* SRP1[]: Set Reference Point 1 */ - /* Opcode range: 0x11 */ - /* Stack: uint32 --> */ + /* GT[]: Greater Than */ + /* Opcode range: 0x52 */ + /* Stack: int32? int32? --> bool */ /* */ static void - Ins_SRP1( TT_ExecContext exc, - FT_Long* args ) + Ins_GT( FT_Long* args ) { - exc->GS.rp1 = (FT_UShort)args[0]; + args[0] = ( args[0] > args[1] ); } /*************************************************************************/ /* */ - /* SRP2[]: Set Reference Point 2 */ - /* Opcode range: 0x12 */ - /* Stack: uint32 --> */ + /* GTEQ[]: Greater Than or EQual */ + /* Opcode range: 0x53 */ + /* Stack: int32? int32? --> bool */ /* */ static void - Ins_SRP2( TT_ExecContext exc, - FT_Long* args ) + Ins_GTEQ( FT_Long* args ) { - exc->GS.rp2 = (FT_UShort)args[0]; + args[0] = ( args[0] >= args[1] ); } /*************************************************************************/ /* */ - /* RTHG[]: Round To Half Grid */ - /* Opcode range: 0x19 */ - /* Stack: --> */ + /* EQ[]: EQual */ + /* Opcode range: 0x54 */ + /* Stack: StkElt StkElt --> bool */ /* */ static void - Ins_RTHG( TT_ExecContext exc ) + Ins_EQ( FT_Long* args ) { - exc->GS.round_state = TT_Round_To_Half_Grid; - exc->func_round = (TT_Round_Func)Round_To_Half_Grid; + args[0] = ( args[0] == args[1] ); } /*************************************************************************/ /* */ - /* RTG[]: Round To Grid */ - /* Opcode range: 0x18 */ - /* Stack: --> */ + /* NEQ[]: Not EQual */ + /* Opcode range: 0x55 */ + /* Stack: StkElt StkElt --> bool */ /* */ static void - Ins_RTG( TT_ExecContext exc ) + Ins_NEQ( FT_Long* args ) { - exc->GS.round_state = TT_Round_To_Grid; - exc->func_round = (TT_Round_Func)Round_To_Grid; + args[0] = ( args[0] != args[1] ); } /*************************************************************************/ - /* RTDG[]: Round To Double Grid */ - /* Opcode range: 0x3D */ - /* Stack: --> */ /* */ - static void - Ins_RTDG( TT_ExecContext exc ) - { - exc->GS.round_state = TT_Round_To_Double_Grid; - exc->func_round = (TT_Round_Func)Round_To_Double_Grid; - } - - - /*************************************************************************/ - /* RUTG[]: Round Up To Grid */ - /* Opcode range: 0x7C */ - /* Stack: --> */ + /* ODD[]: Is ODD */ + /* Opcode range: 0x56 */ + /* Stack: f26.6 --> bool */ /* */ static void - Ins_RUTG( TT_ExecContext exc ) + Ins_ODD( TT_ExecContext exc, + FT_Long* args ) { - exc->GS.round_state = TT_Round_Up_To_Grid; - exc->func_round = (TT_Round_Func)Round_Up_To_Grid; + args[0] = ( ( exc->func_round( exc, args[0], 0 ) & 127 ) == 64 ); } /*************************************************************************/ /* */ - /* RDTG[]: Round Down To Grid */ - /* Opcode range: 0x7D */ - /* Stack: --> */ + /* EVEN[]: Is EVEN */ + /* Opcode range: 0x57 */ + /* Stack: f26.6 --> bool */ /* */ static void - Ins_RDTG( TT_ExecContext exc ) + Ins_EVEN( TT_ExecContext exc, + FT_Long* args ) { - exc->GS.round_state = TT_Round_Down_To_Grid; - exc->func_round = (TT_Round_Func)Round_Down_To_Grid; + args[0] = ( ( exc->func_round( exc, args[0], 0 ) & 127 ) == 0 ); } /*************************************************************************/ /* */ - /* ROFF[]: Round OFF */ - /* Opcode range: 0x7A */ - /* Stack: --> */ + /* AND[]: logical AND */ + /* Opcode range: 0x5A */ + /* Stack: uint32 uint32 --> uint32 */ /* */ static void - Ins_ROFF( TT_ExecContext exc ) + Ins_AND( FT_Long* args ) { - exc->GS.round_state = TT_Round_Off; - exc->func_round = (TT_Round_Func)Round_None; + args[0] = ( args[0] && args[1] ); } /*************************************************************************/ /* */ - /* SROUND[]: Super ROUND */ - /* Opcode range: 0x76 */ - /* Stack: Eint8 --> */ + /* OR[]: logical OR */ + /* Opcode range: 0x5B */ + /* Stack: uint32 uint32 --> uint32 */ /* */ static void - Ins_SROUND( TT_ExecContext exc, - FT_Long* args ) + Ins_OR( FT_Long* args ) { - SetSuperRound( exc, 0x4000, args[0] ); - - exc->GS.round_state = TT_Round_Super; - exc->func_round = (TT_Round_Func)Round_Super; + args[0] = ( args[0] || args[1] ); } /*************************************************************************/ /* */ - /* S45ROUND[]: Super ROUND 45 degrees */ - /* Opcode range: 0x77 */ - /* Stack: uint32 --> */ + /* NOT[]: logical NOT */ + /* Opcode range: 0x5C */ + /* Stack: StkElt --> uint32 */ /* */ static void - Ins_S45ROUND( TT_ExecContext exc, - FT_Long* args ) + Ins_NOT( FT_Long* args ) { - SetSuperRound( exc, 0x2D41, args[0] ); - - exc->GS.round_state = TT_Round_Super_45; - exc->func_round = (TT_Round_Func)Round_Super_45; + args[0] = !args[0]; } /*************************************************************************/ /* */ - /* SLOOP[]: Set LOOP variable */ - /* Opcode range: 0x17 */ - /* Stack: int32? --> */ + /* ADD[]: ADD */ + /* Opcode range: 0x60 */ + /* Stack: f26.6 f26.6 --> f26.6 */ /* */ static void - Ins_SLOOP( TT_ExecContext exc, - FT_Long* args ) + Ins_ADD( FT_Long* args ) { - if ( args[0] < 0 ) - exc->error = FT_THROW( Bad_Argument ); - else - exc->GS.loop = args[0]; + args[0] += args[1]; } /*************************************************************************/ /* */ - /* SMD[]: Set Minimum Distance */ - /* Opcode range: 0x1A */ - /* Stack: f26.6 --> */ + /* SUB[]: SUBtract */ + /* Opcode range: 0x61 */ + /* Stack: f26.6 f26.6 --> f26.6 */ /* */ static void - Ins_SMD( TT_ExecContext exc, - FT_Long* args ) + Ins_SUB( FT_Long* args ) { - exc->GS.minimum_distance = args[0]; + args[0] -= args[1]; } /*************************************************************************/ /* */ - /* SCVTCI[]: Set Control Value Table Cut In */ - /* Opcode range: 0x1D */ - /* Stack: f26.6 --> */ + /* DIV[]: DIVide */ + /* Opcode range: 0x62 */ + /* Stack: f26.6 f26.6 --> f26.6 */ /* */ static void - Ins_SCVTCI( TT_ExecContext exc, - FT_Long* args ) + Ins_DIV( TT_ExecContext exc, + FT_Long* args ) { - exc->GS.control_value_cutin = (FT_F26Dot6)args[0]; + if ( args[1] == 0 ) + exc->error = FT_THROW( Divide_By_Zero ); + else + args[0] = FT_MulDiv_No_Round( args[0], 64L, args[1] ); } /*************************************************************************/ /* */ - /* SSWCI[]: Set Single Width Cut In */ - /* Opcode range: 0x1E */ - /* Stack: f26.6 --> */ + /* MUL[]: MULtiply */ + /* Opcode range: 0x63 */ + /* Stack: f26.6 f26.6 --> f26.6 */ /* */ static void - Ins_SSWCI( TT_ExecContext exc, - FT_Long* args ) + Ins_MUL( FT_Long* args ) { - exc->GS.single_width_cutin = (FT_F26Dot6)args[0]; + args[0] = FT_MulDiv( args[0], args[1], 64L ); } /*************************************************************************/ /* */ - /* SSW[]: Set Single Width */ - /* Opcode range: 0x1F */ - /* Stack: int32? --> */ + /* ABS[]: ABSolute value */ + /* Opcode range: 0x64 */ + /* Stack: f26.6 --> f26.6 */ /* */ static void - Ins_SSW( TT_ExecContext exc, - FT_Long* args ) + Ins_ABS( FT_Long* args ) { - exc->GS.single_width_value = FT_MulFix( args[0], - exc->tt_metrics.scale ); + args[0] = FT_ABS( args[0] ); } /*************************************************************************/ /* */ - /* FLIPON[]: Set auto-FLIP to ON */ - /* Opcode range: 0x4D */ - /* Stack: --> */ + /* NEG[]: NEGate */ + /* Opcode range: 0x65 */ + /* Stack: f26.6 --> f26.6 */ /* */ static void - Ins_FLIPON( TT_ExecContext exc ) + Ins_NEG( FT_Long* args ) { - exc->GS.auto_flip = TRUE; + args[0] = -args[0]; } /*************************************************************************/ /* */ - /* FLIPOFF[]: Set auto-FLIP to OFF */ - /* Opcode range: 0x4E */ - /* Stack: --> */ + /* FLOOR[]: FLOOR */ + /* Opcode range: 0x66 */ + /* Stack: f26.6 --> f26.6 */ /* */ static void - Ins_FLIPOFF( TT_ExecContext exc ) + Ins_FLOOR( FT_Long* args ) { - exc->GS.auto_flip = FALSE; + args[0] = FT_PIX_FLOOR( args[0] ); } /*************************************************************************/ /* */ - /* SANGW[]: Set ANGle Weight */ - /* Opcode range: 0x7E */ - /* Stack: uint32 --> */ + /* CEILING[]: CEILING */ + /* Opcode range: 0x67 */ + /* Stack: f26.6 --> f26.6 */ /* */ static void - Ins_SANGW( void ) + Ins_CEILING( FT_Long* args ) { - /* instruction not supported anymore */ + args[0] = FT_PIX_CEIL( args[0] ); } /*************************************************************************/ /* */ - /* SDB[]: Set Delta Base */ - /* Opcode range: 0x5E */ - /* Stack: uint32 --> */ + /* RS[]: Read Store */ + /* Opcode range: 0x43 */ + /* Stack: uint32 --> uint32 */ /* */ static void - Ins_SDB( TT_ExecContext exc, - FT_Long* args ) + Ins_RS( TT_ExecContext exc, + FT_Long* args ) { - exc->GS.delta_base = (FT_UShort)args[0]; - } - +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - /*************************************************************************/ - /* */ - /* SDS[]: Set Delta Shift */ - /* Opcode range: 0x5F */ - /* Stack: uint32 --> */ - /* */ - static void - Ins_SDS( TT_ExecContext exc, - FT_Long* args ) - { - if ( (FT_ULong)args[0] > 6UL ) - exc->error = FT_THROW( Bad_Argument ); - else - exc->GS.delta_shift = (FT_UShort)args[0]; - } + FT_ULong I = (FT_ULong)args[0]; - /*************************************************************************/ - /* */ - /* MPPEM[]: Measure Pixel Per EM */ - /* Opcode range: 0x4B */ - /* Stack: --> Euint16 */ - /* */ - static void - Ins_MPPEM( TT_ExecContext exc, - FT_Long* args ) - { - args[0] = exc->func_cur_ppem( exc ); - } + if ( BOUNDSL( I, exc->storeSize ) ) + { + if ( exc->pedantic_hinting ) + ARRAY_BOUND_ERROR; + else + args[0] = 0; + } + else + { + /* subpixel hinting - avoid Typeman Dstroke and */ + /* IStroke and Vacuform rounds */ + if ( SUBPIXEL_HINTING && + exc->ignore_x_mode && + ( ( I == 24 && + ( exc->face->sph_found_func_flags & + ( SPH_FDEF_SPACING_1 | + SPH_FDEF_SPACING_2 ) ) ) || + ( I == 22 && + ( exc->sph_in_func_flags & + SPH_FDEF_TYPEMAN_STROKES ) ) || + ( I == 8 && + ( exc->face->sph_found_func_flags & + SPH_FDEF_VACUFORM_ROUND_1 ) && + exc->iup_called ) ) ) + args[0] = 0; + else + args[0] = exc->storage[I]; + } +#else /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */ - /*************************************************************************/ - /* */ - /* MPS[]: Measure Point Size */ - /* Opcode range: 0x4C */ - /* Stack: --> Euint16 */ - /* */ - static void - Ins_MPS( TT_ExecContext exc, - FT_Long* args ) - { - /* Note: The point size should be irrelevant in a given font program; */ - /* we thus decide to return only the PPEM value. */ -#if 0 - args[0] = exc->metrics.pointSize; -#else - args[0] = exc->func_cur_ppem( exc ); -#endif - } + FT_ULong I = (FT_ULong)args[0]; - /*************************************************************************/ - /* */ - /* DUP[]: DUPlicate the stack's top element */ - /* Opcode range: 0x20 */ - /* Stack: StkElt --> StkElt StkElt */ - /* */ - static void - Ins_DUP( FT_Long* args ) - { - args[1] = args[0]; + if ( BOUNDSL( I, exc->storeSize ) ) + { + if ( exc->pedantic_hinting ) + ARRAY_BOUND_ERROR; + else + args[0] = 0; + } + else + args[0] = exc->storage[I]; + +#endif /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */ } /*************************************************************************/ /* */ - /* POP[]: POP the stack's top element */ - /* Opcode range: 0x21 */ - /* Stack: StkElt --> */ + /* WS[]: Write Store */ + /* Opcode range: 0x42 */ + /* Stack: uint32 uint32 --> */ /* */ static void - Ins_POP( void ) + Ins_WS( TT_ExecContext exc, + FT_Long* args ) { - /* nothing to do */ - } + FT_ULong I = (FT_ULong)args[0]; - /*************************************************************************/ - /* */ - /* CLEAR[]: CLEAR the entire stack */ - /* Opcode range: 0x22 */ - /* Stack: StkElt... --> */ - /* */ - static void - Ins_CLEAR( TT_ExecContext exc ) - { - exc->new_top = 0; + if ( BOUNDSL( I, exc->storeSize ) ) + { + if ( exc->pedantic_hinting ) + ARRAY_BOUND_ERROR; + } + else + exc->storage[I] = args[1]; } /*************************************************************************/ /* */ - /* SWAP[]: SWAP the stack's top two elements */ - /* Opcode range: 0x23 */ - /* Stack: 2 * StkElt --> 2 * StkElt */ + /* WCVTP[]: Write CVT in Pixel units */ + /* Opcode range: 0x44 */ + /* Stack: f26.6 uint32 --> */ /* */ static void - Ins_SWAP( FT_Long* args ) + Ins_WCVTP( TT_ExecContext exc, + FT_Long* args ) { - FT_Long L; + FT_ULong I = (FT_ULong)args[0]; - L = args[0]; - args[0] = args[1]; - args[1] = L; + if ( BOUNDSL( I, exc->cvtSize ) ) + { + if ( exc->pedantic_hinting ) + ARRAY_BOUND_ERROR; + } + else + exc->func_write_cvt( exc, I, args[1] ); } /*************************************************************************/ /* */ - /* DEPTH[]: return the stack DEPTH */ - /* Opcode range: 0x24 */ - /* Stack: --> uint32 */ + /* WCVTF[]: Write CVT in Funits */ + /* Opcode range: 0x70 */ + /* Stack: uint32 uint32 --> */ /* */ static void - Ins_DEPTH( TT_ExecContext exc, + Ins_WCVTF( TT_ExecContext exc, FT_Long* args ) { - args[0] = exc->top; + FT_ULong I = (FT_ULong)args[0]; + + + if ( BOUNDSL( I, exc->cvtSize ) ) + { + if ( exc->pedantic_hinting ) + ARRAY_BOUND_ERROR; + } + else + exc->cvt[I] = FT_MulFix( args[1], exc->tt_metrics.scale ); } /*************************************************************************/ /* */ - /* CINDEX[]: Copy INDEXed element */ - /* Opcode range: 0x25 */ - /* Stack: int32 --> StkElt */ + /* RCVT[]: Read CVT */ + /* Opcode range: 0x45 */ + /* Stack: uint32 --> f26.6 */ /* */ static void - Ins_CINDEX( TT_ExecContext exc, - FT_Long* args ) + Ins_RCVT( TT_ExecContext exc, + FT_Long* args ) { - FT_Long L; - + FT_ULong I = (FT_ULong)args[0]; - L = args[0]; - if ( L <= 0 || L > exc->args ) + if ( BOUNDSL( I, exc->cvtSize ) ) { if ( exc->pedantic_hinting ) - exc->error = FT_THROW( Invalid_Reference ); - args[0] = 0; + ARRAY_BOUND_ERROR; + else + args[0] = 0; } else - args[0] = exc->stack[exc->args - L]; + args[0] = exc->func_read_cvt( exc, I ); } /*************************************************************************/ /* */ - /* EIF[]: End IF */ - /* Opcode range: 0x59 */ - /* Stack: --> */ + /* AA[]: Adjust Angle */ + /* Opcode range: 0x7F */ + /* Stack: uint32 --> */ /* */ static void - Ins_EIF( void ) + Ins_AA( void ) { - /* nothing to do */ + /* intentionally no longer supported */ } /*************************************************************************/ /* */ - /* JMPR[]: JuMP Relative */ - /* Opcode range: 0x1C */ - /* Stack: int32 --> */ + /* DEBUG[]: DEBUG. Unsupported. */ + /* Opcode range: 0x4F */ + /* Stack: uint32 --> */ + /* */ + /* Note: The original instruction pops a value from the stack. */ /* */ static void - Ins_JMPR( TT_ExecContext exc, - FT_Long* args ) + Ins_DEBUG( TT_ExecContext exc ) { - if ( args[0] == 0 && exc->args == 0 ) - exc->error = FT_THROW( Bad_Argument ); - exc->IP += args[0]; - if ( exc->IP < 0 || - ( exc->callTop > 0 && - exc->IP > exc->callStack[exc->callTop - 1].Def->end ) ) - exc->error = FT_THROW( Bad_Argument ); - exc->step_ins = FALSE; + exc->error = FT_THROW( Debug_OpCode ); } /*************************************************************************/ /* */ - /* JROT[]: Jump Relative On True */ - /* Opcode range: 0x78 */ - /* Stack: StkElt int32 --> */ + /* ROUND[ab]: ROUND value */ + /* Opcode range: 0x68-0x6B */ + /* Stack: f26.6 --> f26.6 */ /* */ static void - Ins_JROT( TT_ExecContext exc, - FT_Long* args ) + Ins_ROUND( TT_ExecContext exc, + FT_Long* args ) { - if ( args[1] != 0 ) - Ins_JMPR( exc, args ); + args[0] = exc->func_round( + exc, + args[0], + exc->tt_metrics.compensations[exc->opcode - 0x68] ); } /*************************************************************************/ /* */ - /* JROF[]: Jump Relative On False */ - /* Opcode range: 0x79 */ - /* Stack: StkElt int32 --> */ + /* NROUND[ab]: No ROUNDing of value */ + /* Opcode range: 0x6C-0x6F */ + /* Stack: f26.6 --> f26.6 */ /* */ static void - Ins_JROF( TT_ExecContext exc, - FT_Long* args ) + Ins_NROUND( TT_ExecContext exc, + FT_Long* args ) { - if ( args[1] == 0 ) - Ins_JMPR( exc, args ); + args[0] = Round_None( + exc, + args[0], + exc->tt_metrics.compensations[exc->opcode - 0x6C] ); } /*************************************************************************/ /* */ - /* LT[]: Less Than */ - /* Opcode range: 0x50 */ - /* Stack: int32? int32? --> bool */ + /* MAX[]: MAXimum */ + /* Opcode range: 0x68 */ + /* Stack: int32? int32? --> int32 */ /* */ static void - Ins_LT( FT_Long* args ) + Ins_MAX( FT_Long* args ) { - args[0] = ( args[0] < args[1] ); + if ( args[1] > args[0] ) + args[0] = args[1]; } /*************************************************************************/ /* */ - /* LTEQ[]: Less Than or EQual */ - /* Opcode range: 0x51 */ - /* Stack: int32? int32? --> bool */ + /* MIN[]: MINimum */ + /* Opcode range: 0x69 */ + /* Stack: int32? int32? --> int32 */ /* */ static void - Ins_LTEQ( FT_Long* args ) + Ins_MIN( FT_Long* args ) { - args[0] = ( args[0] <= args[1] ); + if ( args[1] < args[0] ) + args[0] = args[1]; } /*************************************************************************/ /* */ - /* GT[]: Greater Than */ - /* Opcode range: 0x52 */ - /* Stack: int32? int32? --> bool */ - /* */ - static void - Ins_GT( FT_Long* args ) + /* MINDEX[]: Move INDEXed element */ + /* Opcode range: 0x26 */ + /* Stack: int32? --> StkElt */ + /* */ + static void + Ins_MINDEX( TT_ExecContext exc, + FT_Long* args ) { - args[0] = ( args[0] > args[1] ); + FT_Long L, K; + + + L = args[0]; + + if ( L <= 0 || L > exc->args ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + } + else + { + K = exc->stack[exc->args - L]; + + FT_ARRAY_MOVE( &exc->stack[exc->args - L ], + &exc->stack[exc->args - L + 1], + ( L - 1 ) ); + + exc->stack[exc->args - 1] = K; + } } /*************************************************************************/ /* */ - /* GTEQ[]: Greater Than or EQual */ - /* Opcode range: 0x53 */ - /* Stack: int32? int32? --> bool */ + /* CINDEX[]: Copy INDEXed element */ + /* Opcode range: 0x25 */ + /* Stack: int32 --> StkElt */ /* */ static void - Ins_GTEQ( FT_Long* args ) + Ins_CINDEX( TT_ExecContext exc, + FT_Long* args ) { - args[0] = ( args[0] >= args[1] ); + FT_Long L; + + + L = args[0]; + + if ( L <= 0 || L > exc->args ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + args[0] = 0; + } + else + args[0] = exc->stack[exc->args - L]; } /*************************************************************************/ /* */ - /* EQ[]: EQual */ - /* Opcode range: 0x54 */ - /* Stack: StkElt StkElt --> bool */ + /* ROLL[]: ROLL top three elements */ + /* Opcode range: 0x8A */ + /* Stack: 3 * StkElt --> 3 * StkElt */ /* */ static void - Ins_EQ( FT_Long* args ) + Ins_ROLL( FT_Long* args ) { - args[0] = ( args[0] == args[1] ); + FT_Long A, B, C; + + + A = args[2]; + B = args[1]; + C = args[0]; + + args[2] = C; + args[1] = A; + args[0] = B; } /*************************************************************************/ /* */ - /* NEQ[]: Not EQual */ - /* Opcode range: 0x55 */ - /* Stack: StkElt StkElt --> bool */ + /* MANAGING THE FLOW OF CONTROL */ /* */ - static void - Ins_NEQ( FT_Long* args ) - { - args[0] = ( args[0] != args[1] ); - } + /*************************************************************************/ /*************************************************************************/ /* */ - /* ODD[]: Is ODD */ - /* Opcode range: 0x56 */ - /* Stack: f26.6 --> bool */ + /* SLOOP[]: Set LOOP variable */ + /* Opcode range: 0x17 */ + /* Stack: int32? --> */ /* */ static void - Ins_ODD( TT_ExecContext exc, - FT_Long* args ) + Ins_SLOOP( TT_ExecContext exc, + FT_Long* args ) { - args[0] = ( ( exc->func_round( exc, args[0], 0 ) & 127 ) == 64 ); + if ( args[0] < 0 ) + exc->error = FT_THROW( Bad_Argument ); + else + exc->GS.loop = args[0]; } - /*************************************************************************/ - /* */ - /* EVEN[]: Is EVEN */ - /* Opcode range: 0x57 */ - /* Stack: f26.6 --> bool */ - /* */ - static void - Ins_EVEN( TT_ExecContext exc, - FT_Long* args ) + static FT_Bool + SkipCode( TT_ExecContext exc ) { - args[0] = ( ( exc->func_round( exc, args[0], 0 ) & 127 ) == 0 ); + exc->IP += exc->length; + + if ( exc->IP < exc->codeSize ) + { + exc->opcode = exc->code[exc->IP]; + + exc->length = opcode_length[exc->opcode]; + if ( exc->length < 0 ) + { + if ( exc->IP + 1 >= exc->codeSize ) + goto Fail_Overflow; + exc->length = 2 - exc->length * exc->code[exc->IP + 1]; + } + + if ( exc->IP + exc->length <= exc->codeSize ) + return SUCCESS; + } + + Fail_Overflow: + exc->error = FT_THROW( Code_Overflow ); + return FAILURE; } /*************************************************************************/ /* */ - /* AND[]: logical AND */ - /* Opcode range: 0x5A */ - /* Stack: uint32 uint32 --> uint32 */ + /* IF[]: IF test */ + /* Opcode range: 0x58 */ + /* Stack: StkElt --> */ /* */ static void - Ins_AND( FT_Long* args ) + Ins_IF( TT_ExecContext exc, + FT_Long* args ) { - args[0] = ( args[0] && args[1] ); + FT_Int nIfs; + FT_Bool Out; + + + if ( args[0] != 0 ) + return; + + nIfs = 1; + Out = 0; + + do + { + if ( SkipCode( exc ) == FAILURE ) + return; + + switch ( exc->opcode ) + { + case 0x58: /* IF */ + nIfs++; + break; + + case 0x1B: /* ELSE */ + Out = FT_BOOL( nIfs == 1 ); + break; + + case 0x59: /* EIF */ + nIfs--; + Out = FT_BOOL( nIfs == 0 ); + break; + } + } while ( Out == 0 ); } /*************************************************************************/ /* */ - /* OR[]: logical OR */ - /* Opcode range: 0x5B */ - /* Stack: uint32 uint32 --> uint32 */ + /* ELSE[]: ELSE */ + /* Opcode range: 0x1B */ + /* Stack: --> */ /* */ static void - Ins_OR( FT_Long* args ) + Ins_ELSE( TT_ExecContext exc ) { - args[0] = ( args[0] || args[1] ); + FT_Int nIfs; + + + nIfs = 1; + + do + { + if ( SkipCode( exc ) == FAILURE ) + return; + + switch ( exc->opcode ) + { + case 0x58: /* IF */ + nIfs++; + break; + + case 0x59: /* EIF */ + nIfs--; + break; + } + } while ( nIfs != 0 ); } /*************************************************************************/ /* */ - /* NOT[]: logical NOT */ - /* Opcode range: 0x5C */ - /* Stack: StkElt --> uint32 */ + /* EIF[]: End IF */ + /* Opcode range: 0x59 */ + /* Stack: --> */ /* */ static void - Ins_NOT( FT_Long* args ) + Ins_EIF( void ) { - args[0] = !args[0]; + /* nothing to do */ } /*************************************************************************/ /* */ - /* ADD[]: ADD */ - /* Opcode range: 0x60 */ - /* Stack: f26.6 f26.6 --> f26.6 */ + /* JMPR[]: JuMP Relative */ + /* Opcode range: 0x1C */ + /* Stack: int32 --> */ /* */ static void - Ins_ADD( FT_Long* args ) + Ins_JMPR( TT_ExecContext exc, + FT_Long* args ) { - args[0] += args[1]; + if ( args[0] == 0 && exc->args == 0 ) + exc->error = FT_THROW( Bad_Argument ); + exc->IP += args[0]; + if ( exc->IP < 0 || + ( exc->callTop > 0 && + exc->IP > exc->callStack[exc->callTop - 1].Def->end ) ) + exc->error = FT_THROW( Bad_Argument ); + exc->step_ins = FALSE; } /*************************************************************************/ /* */ - /* SUB[]: SUBtract */ - /* Opcode range: 0x61 */ - /* Stack: f26.6 f26.6 --> f26.6 */ + /* JROT[]: Jump Relative On True */ + /* Opcode range: 0x78 */ + /* Stack: StkElt int32 --> */ /* */ static void - Ins_SUB( FT_Long* args ) + Ins_JROT( TT_ExecContext exc, + FT_Long* args ) { - args[0] -= args[1]; + if ( args[1] != 0 ) + Ins_JMPR( exc, args ); } /*************************************************************************/ /* */ - /* DIV[]: DIVide */ - /* Opcode range: 0x62 */ - /* Stack: f26.6 f26.6 --> f26.6 */ + /* JROF[]: Jump Relative On False */ + /* Opcode range: 0x79 */ + /* Stack: StkElt int32 --> */ /* */ static void - Ins_DIV( TT_ExecContext exc, - FT_Long* args ) + Ins_JROF( TT_ExecContext exc, + FT_Long* args ) { if ( args[1] == 0 ) - exc->error = FT_THROW( Divide_By_Zero ); - else - args[0] = FT_MulDiv_No_Round( args[0], 64L, args[1] ); + Ins_JMPR( exc, args ); } /*************************************************************************/ /* */ - /* MUL[]: MULtiply */ - /* Opcode range: 0x63 */ - /* Stack: f26.6 f26.6 --> f26.6 */ - /* */ - static void - Ins_MUL( FT_Long* args ) - { - args[0] = FT_MulDiv( args[0], args[1], 64L ); - } - - - /*************************************************************************/ - /* */ - /* ABS[]: ABSolute value */ - /* Opcode range: 0x64 */ - /* Stack: f26.6 --> f26.6 */ - /* */ - static void - Ins_ABS( FT_Long* args ) - { - args[0] = FT_ABS( args[0] ); - } - - - /*************************************************************************/ - /* */ - /* NEG[]: NEGate */ - /* Opcode range: 0x65 */ - /* Stack: f26.6 --> f26.6 */ + /* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS */ /* */ - static void - Ins_NEG( FT_Long* args ) - { - args[0] = -args[0]; - } - - /*************************************************************************/ - /* */ - /* FLOOR[]: FLOOR */ - /* Opcode range: 0x66 */ - /* Stack: f26.6 --> f26.6 */ - /* */ - static void - Ins_FLOOR( FT_Long* args ) - { - args[0] = FT_PIX_FLOOR( args[0] ); - } /*************************************************************************/ /* */ - /* CEILING[]: CEILING */ - /* Opcode range: 0x67 */ - /* Stack: f26.6 --> f26.6 */ + /* FDEF[]: Function DEFinition */ + /* Opcode range: 0x2C */ + /* Stack: uint32 --> */ /* */ static void - Ins_CEILING( FT_Long* args ) + Ins_FDEF( TT_ExecContext exc, + FT_Long* args ) { - args[0] = FT_PIX_CEIL( args[0] ); - } - + FT_ULong n; + TT_DefRecord* rec; + TT_DefRecord* limit; - /*************************************************************************/ - /* */ - /* RS[]: Read Store */ - /* Opcode range: 0x43 */ - /* Stack: uint32 --> uint32 */ - /* */ - static void - Ins_RS( TT_ExecContext exc, - FT_Long* args ) - { #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + /* arguments to opcodes are skipped by `SKIP_Code' */ + FT_Byte opcode_pattern[9][12] = { + /* #0 inline delta function 1 */ + { + 0x4B, /* PPEM */ + 0x53, /* GTEQ */ + 0x23, /* SWAP */ + 0x4B, /* PPEM */ + 0x51, /* LTEQ */ + 0x5A, /* AND */ + 0x58, /* IF */ + 0x38, /* SHPIX */ + 0x1B, /* ELSE */ + 0x21, /* POP */ + 0x21, /* POP */ + 0x59 /* EIF */ + }, + /* #1 inline delta function 2 */ + { + 0x4B, /* PPEM */ + 0x54, /* EQ */ + 0x58, /* IF */ + 0x38, /* SHPIX */ + 0x1B, /* ELSE */ + 0x21, /* POP */ + 0x21, /* POP */ + 0x59 /* EIF */ + }, + /* #2 diagonal stroke function */ + { + 0x20, /* DUP */ + 0x20, /* DUP */ + 0xB0, /* PUSHB_1 */ + /* 1 */ + 0x60, /* ADD */ + 0x46, /* GC_cur */ + 0xB0, /* PUSHB_1 */ + /* 64 */ + 0x23, /* SWAP */ + 0x42 /* WS */ + }, + /* #3 VacuFormRound function */ + { + 0x45, /* RCVT */ + 0x23, /* SWAP */ + 0x46, /* GC_cur */ + 0x60, /* ADD */ + 0x20, /* DUP */ + 0xB0 /* PUSHB_1 */ + /* 38 */ + }, + /* #4 TTFautohint bytecode (old) */ + { + 0x20, /* DUP */ + 0x64, /* ABS */ + 0xB0, /* PUSHB_1 */ + /* 32 */ + 0x60, /* ADD */ + 0x66, /* FLOOR */ + 0x23, /* SWAP */ + 0xB0 /* PUSHB_1 */ + }, + /* #5 spacing function 1 */ + { + 0x01, /* SVTCA_x */ + 0xB0, /* PUSHB_1 */ + /* 24 */ + 0x43, /* RS */ + 0x58 /* IF */ + }, + /* #6 spacing function 2 */ + { + 0x01, /* SVTCA_x */ + 0x18, /* RTG */ + 0xB0, /* PUSHB_1 */ + /* 24 */ + 0x43, /* RS */ + 0x58 /* IF */ + }, + /* #7 TypeMan Talk DiagEndCtrl function */ + { + 0x01, /* SVTCA_x */ + 0x20, /* DUP */ + 0xB0, /* PUSHB_1 */ + /* 3 */ + 0x25, /* CINDEX */ + }, + /* #8 TypeMan Talk Align */ + { + 0x06, /* SPVTL */ + 0x7D, /* RDTG */ + }, + }; + FT_UShort opcode_patterns = 9; + FT_UShort opcode_pointer[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + FT_UShort opcode_size[9] = { 12, 8, 8, 6, 7, 4, 5, 4, 2 }; + FT_UShort i; +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ - FT_ULong I = (FT_ULong)args[0]; + /* some font programs are broken enough to redefine functions! */ + /* We will then parse the current table. */ - if ( BOUNDSL( I, exc->storeSize ) ) - { - if ( exc->pedantic_hinting ) - ARRAY_BOUND_ERROR; - else - args[0] = 0; - } - else + rec = exc->FDefs; + limit = rec + exc->numFDefs; + n = args[0]; + + for ( ; rec < limit; rec++ ) { - /* subpixel hinting - avoid Typeman Dstroke and */ - /* IStroke and Vacuform rounds */ - if ( SUBPIXEL_HINTING && - exc->ignore_x_mode && - ( ( I == 24 && - ( exc->face->sph_found_func_flags & - ( SPH_FDEF_SPACING_1 | - SPH_FDEF_SPACING_2 ) ) ) || - ( I == 22 && - ( exc->sph_in_func_flags & - SPH_FDEF_TYPEMAN_STROKES ) ) || - ( I == 8 && - ( exc->face->sph_found_func_flags & - SPH_FDEF_VACUFORM_ROUND_1 ) && - exc->iup_called ) ) ) - args[0] = 0; - else - args[0] = exc->storage[I]; + if ( rec->opc == n ) + break; } -#else /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */ - - FT_ULong I = (FT_ULong)args[0]; - - - if ( BOUNDSL( I, exc->storeSize ) ) + if ( rec == limit ) { - if ( exc->pedantic_hinting ) - ARRAY_BOUND_ERROR; - else - args[0] = 0; + /* check that there is enough room for new functions */ + if ( exc->numFDefs >= exc->maxFDefs ) + { + exc->error = FT_THROW( Too_Many_Function_Defs ); + return; + } + exc->numFDefs++; } - else - args[0] = exc->storage[I]; - -#endif /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */ - } - - - /*************************************************************************/ - /* */ - /* WS[]: Write Store */ - /* Opcode range: 0x42 */ - /* Stack: uint32 uint32 --> */ - /* */ - static void - Ins_WS( TT_ExecContext exc, - FT_Long* args ) - { - FT_ULong I = (FT_ULong)args[0]; - - if ( BOUNDSL( I, exc->storeSize ) ) + /* Although FDEF takes unsigned 32-bit integer, */ + /* func # must be within unsigned 16-bit integer */ + if ( n > 0xFFFFU ) { - if ( exc->pedantic_hinting ) - ARRAY_BOUND_ERROR; + exc->error = FT_THROW( Too_Many_Function_Defs ); + return; } - else - exc->storage[I] = args[1]; - } + rec->range = exc->curRange; + rec->opc = (FT_UInt16)n; + rec->start = exc->IP + 1; + rec->active = TRUE; + rec->inline_delta = FALSE; + rec->sph_fdef_flags = 0x0000; - /*************************************************************************/ - /* */ - /* WCVTP[]: Write CVT in Pixel units */ - /* Opcode range: 0x44 */ - /* Stack: f26.6 uint32 --> */ - /* */ - static void - Ins_WCVTP( TT_ExecContext exc, - FT_Long* args ) - { - FT_ULong I = (FT_ULong)args[0]; + if ( n > exc->maxFunc ) + exc->maxFunc = (FT_UInt16)n; + +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + /* We don't know for sure these are typeman functions, */ + /* however they are only active when RS 22 is called */ + if ( n >= 64 && n <= 66 ) + rec->sph_fdef_flags |= SPH_FDEF_TYPEMAN_STROKES; +#endif + /* Now skip the whole function definition. */ + /* We don't allow nested IDEFS & FDEFs. */ - if ( BOUNDSL( I, exc->cvtSize ) ) + while ( SkipCode( exc ) == SUCCESS ) { - if ( exc->pedantic_hinting ) - ARRAY_BOUND_ERROR; - } - else - exc->func_write_cvt( exc, I, args[1] ); - } +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - /*************************************************************************/ - /* */ - /* WCVTF[]: Write CVT in Funits */ - /* Opcode range: 0x70 */ - /* Stack: uint32 uint32 --> */ - /* */ - static void - Ins_WCVTF( TT_ExecContext exc, - FT_Long* args ) - { - FT_ULong I = (FT_ULong)args[0]; + if ( SUBPIXEL_HINTING ) + { + for ( i = 0; i < opcode_patterns; i++ ) + { + if ( opcode_pointer[i] < opcode_size[i] && + exc->opcode == opcode_pattern[i][opcode_pointer[i]] ) + { + opcode_pointer[i] += 1; + if ( opcode_pointer[i] == opcode_size[i] ) + { + FT_TRACE7(( "sph: Function %d, opcode ptrn: %d, %s %s\n", + i, n, + exc->face->root.family_name, + exc->face->root.style_name )); - if ( BOUNDSL( I, exc->cvtSize ) ) - { - if ( exc->pedantic_hinting ) - ARRAY_BOUND_ERROR; - } - else - exc->cvt[I] = FT_MulFix( args[1], exc->tt_metrics.scale ); - } + switch ( i ) + { + case 0: + rec->sph_fdef_flags |= SPH_FDEF_INLINE_DELTA_1; + exc->face->sph_found_func_flags |= SPH_FDEF_INLINE_DELTA_1; + break; + case 1: + rec->sph_fdef_flags |= SPH_FDEF_INLINE_DELTA_2; + exc->face->sph_found_func_flags |= SPH_FDEF_INLINE_DELTA_2; + break; - /*************************************************************************/ - /* */ - /* RCVT[]: Read CVT */ - /* Opcode range: 0x45 */ - /* Stack: uint32 --> f26.6 */ - /* */ - static void - Ins_RCVT( TT_ExecContext exc, - FT_Long* args ) - { - FT_ULong I = (FT_ULong)args[0]; + case 2: + switch ( n ) + { + /* needs to be implemented still */ + case 58: + rec->sph_fdef_flags |= SPH_FDEF_DIAGONAL_STROKE; + exc->face->sph_found_func_flags |= SPH_FDEF_DIAGONAL_STROKE; + } + break; + case 3: + switch ( n ) + { + case 0: + rec->sph_fdef_flags |= SPH_FDEF_VACUFORM_ROUND_1; + exc->face->sph_found_func_flags |= SPH_FDEF_VACUFORM_ROUND_1; + } + break; - if ( BOUNDSL( I, exc->cvtSize ) ) - { - if ( exc->pedantic_hinting ) - ARRAY_BOUND_ERROR; - else - args[0] = 0; - } - else - args[0] = exc->func_read_cvt( exc, I ); - } + case 4: + /* probably not necessary to detect anymore */ + rec->sph_fdef_flags |= SPH_FDEF_TTFAUTOHINT_1; + exc->face->sph_found_func_flags |= SPH_FDEF_TTFAUTOHINT_1; + break; + case 5: + switch ( n ) + { + case 0: + case 1: + case 2: + case 4: + case 7: + case 8: + rec->sph_fdef_flags |= SPH_FDEF_SPACING_1; + exc->face->sph_found_func_flags |= SPH_FDEF_SPACING_1; + } + break; - /*************************************************************************/ - /* */ - /* AA[]: Adjust Angle */ - /* Opcode range: 0x7F */ - /* Stack: uint32 --> */ - /* */ - static void - Ins_AA( void ) - { - /* intentionally no longer supported */ - } + case 6: + switch ( n ) + { + case 0: + case 1: + case 2: + case 4: + case 7: + case 8: + rec->sph_fdef_flags |= SPH_FDEF_SPACING_2; + exc->face->sph_found_func_flags |= SPH_FDEF_SPACING_2; + } + break; + case 7: + rec->sph_fdef_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL; + exc->face->sph_found_func_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL; + break; - /*************************************************************************/ - /* */ - /* DEBUG[]: DEBUG. Unsupported. */ - /* Opcode range: 0x4F */ - /* Stack: uint32 --> */ - /* */ - /* Note: The original instruction pops a value from the stack. */ - /* */ - static void - Ins_DEBUG( TT_ExecContext exc ) - { - exc->error = FT_THROW( Debug_OpCode ); - } + case 8: +#if 0 + rec->sph_fdef_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL; + exc->face->sph_found_func_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL; +#endif + break; + } + opcode_pointer[i] = 0; + } + } + else + opcode_pointer[i] = 0; + } - /*************************************************************************/ - /* */ - /* ROUND[ab]: ROUND value */ - /* Opcode range: 0x68-0x6B */ - /* Stack: f26.6 --> f26.6 */ - /* */ - static void - Ins_ROUND( TT_ExecContext exc, - FT_Long* args ) - { - args[0] = exc->func_round( - exc, - args[0], - exc->tt_metrics.compensations[exc->opcode - 0x68] ); - } + /* Set sph_compatibility_mode only when deltas are detected */ + exc->face->sph_compatibility_mode = + ( ( exc->face->sph_found_func_flags & SPH_FDEF_INLINE_DELTA_1 ) | + ( exc->face->sph_found_func_flags & SPH_FDEF_INLINE_DELTA_2 ) ); + } +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ - /*************************************************************************/ - /* */ - /* NROUND[ab]: No ROUNDing of value */ - /* Opcode range: 0x6C-0x6F */ - /* Stack: f26.6 --> f26.6 */ - /* */ - static void - Ins_NROUND( TT_ExecContext exc, - FT_Long* args ) - { - args[0] = Round_None( - exc, - args[0], - exc->tt_metrics.compensations[exc->opcode - 0x6C] ); + switch ( exc->opcode ) + { + case 0x89: /* IDEF */ + case 0x2C: /* FDEF */ + exc->error = FT_THROW( Nested_DEFS ); + return; + + case 0x2D: /* ENDF */ + rec->end = exc->IP; + return; + } + } } /*************************************************************************/ /* */ - /* MAX[]: MAXimum */ - /* Opcode range: 0x68 */ - /* Stack: int32? int32? --> int32 */ + /* ENDF[]: END Function definition */ + /* Opcode range: 0x2D */ + /* Stack: --> */ /* */ static void - Ins_MAX( FT_Long* args ) + Ins_ENDF( TT_ExecContext exc ) { - if ( args[1] > args[0] ) - args[0] = args[1]; - } + TT_CallRec* pRec; - /*************************************************************************/ - /* */ - /* MIN[]: MINimum */ - /* Opcode range: 0x69 */ - /* Stack: int32? int32? --> int32 */ - /* */ - static void - Ins_MIN( FT_Long* args ) - { - if ( args[1] < args[0] ) - args[0] = args[1]; - } +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + exc->sph_in_func_flags = 0x0000; +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + if ( exc->callTop <= 0 ) /* We encountered an ENDF without a call */ + { + exc->error = FT_THROW( ENDF_In_Exec_Stream ); + return; + } - /*************************************************************************/ - /* */ - /* MINDEX[]: Move INDEXed element */ - /* Opcode range: 0x26 */ - /* Stack: int32? --> StkElt */ - /* */ - static void - Ins_MINDEX( TT_ExecContext exc, - FT_Long* args ) - { - FT_Long L, K; + exc->callTop--; + pRec = &exc->callStack[exc->callTop]; - L = args[0]; + pRec->Cur_Count--; - if ( L <= 0 || L > exc->args ) + exc->step_ins = FALSE; + + if ( pRec->Cur_Count > 0 ) { - if ( exc->pedantic_hinting ) - exc->error = FT_THROW( Invalid_Reference ); + exc->callTop++; + exc->IP = pRec->Def->start; } else - { - K = exc->stack[exc->args - L]; + /* Loop through the current function */ + Ins_Goto_CodeRange( exc, pRec->Caller_Range, pRec->Caller_IP ); - FT_ARRAY_MOVE( &exc->stack[exc->args - L ], - &exc->stack[exc->args - L + 1], - ( L - 1 ) ); + /* Exit the current call frame. */ - exc->stack[exc->args - 1] = K; - } + /* NOTE: If the last instruction of a program is a */ + /* CALL or LOOPCALL, the return address is */ + /* always out of the code range. This is a */ + /* valid address, and it is why we do not test */ + /* the result of Ins_Goto_CodeRange() here! */ } /*************************************************************************/ /* */ - /* ROLL[]: ROLL top three elements */ - /* Opcode range: 0x8A */ - /* Stack: 3 * StkElt --> 3 * StkElt */ + /* CALL[]: CALL function */ + /* Opcode range: 0x2B */ + /* Stack: uint32? --> */ /* */ static void - Ins_ROLL( FT_Long* args ) + Ins_CALL( TT_ExecContext exc, + FT_Long* args ) { - FT_Long A, B, C; - - - A = args[2]; - B = args[1]; - C = args[0]; + FT_ULong F; + TT_CallRec* pCrec; + TT_DefRecord* def; - args[2] = C; - args[1] = A; - args[0] = B; - } + /* first of all, check the index */ - /*************************************************************************/ - /* */ - /* MANAGING THE FLOW OF CONTROL */ - /* */ - /* Instructions appear in the specification's order. */ - /* */ - /*************************************************************************/ + F = args[0]; + if ( BOUNDSL( F, exc->maxFunc + 1 ) ) + goto Fail; + /* Except for some old Apple fonts, all functions in a TrueType */ + /* font are defined in increasing order, starting from 0. This */ + /* means that we normally have */ + /* */ + /* exc->maxFunc+1 == exc->numFDefs */ + /* exc->FDefs[n].opc == n for n in 0..exc->maxFunc */ + /* */ + /* If this isn't true, we need to look up the function table. */ - static FT_Bool - SkipCode( TT_ExecContext exc ) - { - exc->IP += exc->length; + def = exc->FDefs + F; + if ( exc->maxFunc + 1 != exc->numFDefs || def->opc != F ) + { + /* look up the FDefs table */ + TT_DefRecord* limit; - if ( exc->IP < exc->codeSize ) - { - exc->opcode = exc->code[exc->IP]; - exc->length = opcode_length[exc->opcode]; - if ( exc->length < 0 ) - { - if ( exc->IP + 1 >= exc->codeSize ) - goto Fail_Overflow; - exc->length = 2 - exc->length * exc->code[exc->IP + 1]; - } + def = exc->FDefs; + limit = def + exc->numFDefs; - if ( exc->IP + exc->length <= exc->codeSize ) - return SUCCESS; + while ( def < limit && def->opc != F ) + def++; + + if ( def == limit ) + goto Fail; } - Fail_Overflow: - exc->error = FT_THROW( Code_Overflow ); - return FAILURE; - } + /* check that the function is active */ + if ( !def->active ) + goto Fail; +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + if ( SUBPIXEL_HINTING && + exc->ignore_x_mode && + ( ( exc->iup_called && + ( exc->sph_tweak_flags & SPH_TWEAK_NO_CALL_AFTER_IUP ) ) || + ( def->sph_fdef_flags & SPH_FDEF_VACUFORM_ROUND_1 ) ) ) + goto Fail; + else + exc->sph_in_func_flags = def->sph_fdef_flags; +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ - /*************************************************************************/ - /* */ - /* IF[]: IF test */ - /* Opcode range: 0x58 */ - /* Stack: StkElt --> */ - /* */ - static void - Ins_IF( TT_ExecContext exc, - FT_Long* args ) - { - FT_Int nIfs; - FT_Bool Out; + /* check the call stack */ + if ( exc->callTop >= exc->callSize ) + { + exc->error = FT_THROW( Stack_Overflow ); + return; + } + pCrec = exc->callStack + exc->callTop; - if ( args[0] != 0 ) - return; + pCrec->Caller_Range = exc->curRange; + pCrec->Caller_IP = exc->IP + 1; + pCrec->Cur_Count = 1; + pCrec->Def = def; - nIfs = 1; - Out = 0; + exc->callTop++; - do - { - if ( SkipCode( exc ) == FAILURE ) - return; + Ins_Goto_CodeRange( exc, def->range, def->start ); - switch ( exc->opcode ) - { - case 0x58: /* IF */ - nIfs++; - break; + exc->step_ins = FALSE; - case 0x1B: /* ELSE */ - Out = FT_BOOL( nIfs == 1 ); - break; + return; - case 0x59: /* EIF */ - nIfs--; - Out = FT_BOOL( nIfs == 0 ); - break; - } - } while ( Out == 0 ); + Fail: + exc->error = FT_THROW( Invalid_Reference ); } /*************************************************************************/ /* */ - /* ELSE[]: ELSE */ - /* Opcode range: 0x1B */ - /* Stack: --> */ + /* LOOPCALL[]: LOOP and CALL function */ + /* Opcode range: 0x2A */ + /* Stack: uint32? Eint16? --> */ /* */ static void - Ins_ELSE( TT_ExecContext exc ) + Ins_LOOPCALL( TT_ExecContext exc, + FT_Long* args ) { - FT_Int nIfs; - - - nIfs = 1; - - do - { - if ( SkipCode( exc ) == FAILURE ) - return; + FT_ULong F; + TT_CallRec* pCrec; + TT_DefRecord* def; - switch ( exc->opcode ) - { - case 0x58: /* IF */ - nIfs++; - break; - case 0x59: /* EIF */ - nIfs--; - break; - } - } while ( nIfs != 0 ); - } + /* first of all, check the index */ + F = args[1]; + if ( BOUNDSL( F, exc->maxFunc + 1 ) ) + goto Fail; + /* Except for some old Apple fonts, all functions in a TrueType */ + /* font are defined in increasing order, starting from 0. This */ + /* means that we normally have */ + /* */ + /* exc->maxFunc+1 == exc->numFDefs */ + /* exc->FDefs[n].opc == n for n in 0..exc->maxFunc */ + /* */ + /* If this isn't true, we need to look up the function table. */ - /*************************************************************************/ - /* */ - /* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS */ - /* */ - /* Instructions appear in the specification's order. */ - /* */ - /*************************************************************************/ + def = exc->FDefs + F; + if ( exc->maxFunc + 1 != exc->numFDefs || def->opc != F ) + { + /* look up the FDefs table */ + TT_DefRecord* limit; - /*************************************************************************/ - /* */ - /* FDEF[]: Function DEFinition */ - /* Opcode range: 0x2C */ - /* Stack: uint32 --> */ - /* */ - static void - Ins_FDEF( TT_ExecContext exc, - FT_Long* args ) - { - FT_ULong n; - TT_DefRecord* rec; - TT_DefRecord* limit; + def = exc->FDefs; + limit = def + exc->numFDefs; -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - /* arguments to opcodes are skipped by `SKIP_Code' */ - FT_Byte opcode_pattern[9][12] = { - /* #0 inline delta function 1 */ - { - 0x4B, /* PPEM */ - 0x53, /* GTEQ */ - 0x23, /* SWAP */ - 0x4B, /* PPEM */ - 0x51, /* LTEQ */ - 0x5A, /* AND */ - 0x58, /* IF */ - 0x38, /* SHPIX */ - 0x1B, /* ELSE */ - 0x21, /* POP */ - 0x21, /* POP */ - 0x59 /* EIF */ - }, - /* #1 inline delta function 2 */ - { - 0x4B, /* PPEM */ - 0x54, /* EQ */ - 0x58, /* IF */ - 0x38, /* SHPIX */ - 0x1B, /* ELSE */ - 0x21, /* POP */ - 0x21, /* POP */ - 0x59 /* EIF */ - }, - /* #2 diagonal stroke function */ - { - 0x20, /* DUP */ - 0x20, /* DUP */ - 0xB0, /* PUSHB_1 */ - /* 1 */ - 0x60, /* ADD */ - 0x46, /* GC_cur */ - 0xB0, /* PUSHB_1 */ - /* 64 */ - 0x23, /* SWAP */ - 0x42 /* WS */ - }, - /* #3 VacuFormRound function */ - { - 0x45, /* RCVT */ - 0x23, /* SWAP */ - 0x46, /* GC_cur */ - 0x60, /* ADD */ - 0x20, /* DUP */ - 0xB0 /* PUSHB_1 */ - /* 38 */ - }, - /* #4 TTFautohint bytecode (old) */ - { - 0x20, /* DUP */ - 0x64, /* ABS */ - 0xB0, /* PUSHB_1 */ - /* 32 */ - 0x60, /* ADD */ - 0x66, /* FLOOR */ - 0x23, /* SWAP */ - 0xB0 /* PUSHB_1 */ - }, - /* #5 spacing function 1 */ - { - 0x01, /* SVTCA_x */ - 0xB0, /* PUSHB_1 */ - /* 24 */ - 0x43, /* RS */ - 0x58 /* IF */ - }, - /* #6 spacing function 2 */ - { - 0x01, /* SVTCA_x */ - 0x18, /* RTG */ - 0xB0, /* PUSHB_1 */ - /* 24 */ - 0x43, /* RS */ - 0x58 /* IF */ - }, - /* #7 TypeMan Talk DiagEndCtrl function */ - { - 0x01, /* SVTCA_x */ - 0x20, /* DUP */ - 0xB0, /* PUSHB_1 */ - /* 3 */ - 0x25, /* CINDEX */ - }, - /* #8 TypeMan Talk Align */ - { - 0x06, /* SPVTL */ - 0x7D, /* RDTG */ - }, - }; - FT_UShort opcode_patterns = 9; - FT_UShort opcode_pointer[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - FT_UShort opcode_size[9] = { 12, 8, 8, 6, 7, 4, 5, 4, 2 }; - FT_UShort i; -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + while ( def < limit && def->opc != F ) + def++; + if ( def == limit ) + goto Fail; + } - /* some font programs are broken enough to redefine functions! */ - /* We will then parse the current table. */ + /* check that the function is active */ + if ( !def->active ) + goto Fail; - rec = exc->FDefs; - limit = rec + exc->numFDefs; - n = args[0]; +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + if ( SUBPIXEL_HINTING && + exc->ignore_x_mode && + ( def->sph_fdef_flags & SPH_FDEF_VACUFORM_ROUND_1 ) ) + goto Fail; + else + exc->sph_in_func_flags = def->sph_fdef_flags; +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ - for ( ; rec < limit; rec++ ) + /* check stack */ + if ( exc->callTop >= exc->callSize ) { - if ( rec->opc == n ) - break; + exc->error = FT_THROW( Stack_Overflow ); + return; } - if ( rec == limit ) + if ( args[0] > 0 ) { - /* check that there is enough room for new functions */ - if ( exc->numFDefs >= exc->maxFDefs ) + pCrec = exc->callStack + exc->callTop; + + pCrec->Caller_Range = exc->curRange; + pCrec->Caller_IP = exc->IP + 1; + pCrec->Cur_Count = (FT_Int)args[0]; + pCrec->Def = def; + + exc->callTop++; + + Ins_Goto_CodeRange( exc, def->range, def->start ); + + exc->step_ins = FALSE; + } + + return; + + Fail: + exc->error = FT_THROW( Invalid_Reference ); + } + + + /*************************************************************************/ + /* */ + /* IDEF[]: Instruction DEFinition */ + /* Opcode range: 0x89 */ + /* Stack: Eint8 --> */ + /* */ + static void + Ins_IDEF( TT_ExecContext exc, + FT_Long* args ) + { + TT_DefRecord* def; + TT_DefRecord* limit; + + + /* First of all, look for the same function in our table */ + + def = exc->IDefs; + limit = def + exc->numIDefs; + + for ( ; def < limit; def++ ) + if ( def->opc == (FT_ULong)args[0] ) + break; + + if ( def == limit ) + { + /* check that there is enough room for a new instruction */ + if ( exc->numIDefs >= exc->maxIDefs ) { - exc->error = FT_THROW( Too_Many_Function_Defs ); + exc->error = FT_THROW( Too_Many_Instruction_Defs ); return; } - exc->numFDefs++; + exc->numIDefs++; } - /* Although FDEF takes unsigned 32-bit integer, */ - /* func # must be within unsigned 16-bit integer */ - if ( n > 0xFFFFU ) + /* opcode must be unsigned 8-bit integer */ + if ( 0 > args[0] || args[0] > 0x00FF ) { - exc->error = FT_THROW( Too_Many_Function_Defs ); + exc->error = FT_THROW( Too_Many_Instruction_Defs ); return; } - rec->range = exc->curRange; - rec->opc = (FT_UInt16)n; - rec->start = exc->IP + 1; - rec->active = TRUE; - rec->inline_delta = FALSE; - rec->sph_fdef_flags = 0x0000; - - if ( n > exc->maxFunc ) - exc->maxFunc = (FT_UInt16)n; + def->opc = (FT_Byte)args[0]; + def->start = exc->IP + 1; + def->range = exc->curRange; + def->active = TRUE; -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - /* We don't know for sure these are typeman functions, */ - /* however they are only active when RS 22 is called */ - if ( n >= 64 && n <= 66 ) - rec->sph_fdef_flags |= SPH_FDEF_TYPEMAN_STROKES; -#endif + if ( (FT_ULong)args[0] > exc->maxIns ) + exc->maxIns = (FT_Byte)args[0]; /* Now skip the whole function definition. */ - /* We don't allow nested IDEFS & FDEFs. */ + /* We don't allow nested IDEFs & FDEFs. */ while ( SkipCode( exc ) == SUCCESS ) { - -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - - if ( SUBPIXEL_HINTING ) + switch ( exc->opcode ) { - for ( i = 0; i < opcode_patterns; i++ ) - { - if ( opcode_pointer[i] < opcode_size[i] && - exc->opcode == opcode_pattern[i][opcode_pointer[i]] ) - { - opcode_pointer[i] += 1; - - if ( opcode_pointer[i] == opcode_size[i] ) - { - FT_TRACE7(( "sph: Function %d, opcode ptrn: %d, %s %s\n", - i, n, - exc->face->root.family_name, - exc->face->root.style_name )); + case 0x89: /* IDEF */ + case 0x2C: /* FDEF */ + exc->error = FT_THROW( Nested_DEFS ); + return; + case 0x2D: /* ENDF */ + return; + } + } + } - switch ( i ) - { - case 0: - rec->sph_fdef_flags |= SPH_FDEF_INLINE_DELTA_1; - exc->face->sph_found_func_flags |= SPH_FDEF_INLINE_DELTA_1; - break; - case 1: - rec->sph_fdef_flags |= SPH_FDEF_INLINE_DELTA_2; - exc->face->sph_found_func_flags |= SPH_FDEF_INLINE_DELTA_2; - break; + /*************************************************************************/ + /* */ + /* PUSHING DATA ONTO THE INTERPRETER STACK */ + /* */ + /*************************************************************************/ - case 2: - switch ( n ) - { - /* needs to be implemented still */ - case 58: - rec->sph_fdef_flags |= SPH_FDEF_DIAGONAL_STROKE; - exc->face->sph_found_func_flags |= SPH_FDEF_DIAGONAL_STROKE; - } - break; - case 3: - switch ( n ) - { - case 0: - rec->sph_fdef_flags |= SPH_FDEF_VACUFORM_ROUND_1; - exc->face->sph_found_func_flags |= SPH_FDEF_VACUFORM_ROUND_1; - } - break; + /*************************************************************************/ + /* */ + /* NPUSHB[]: PUSH N Bytes */ + /* Opcode range: 0x40 */ + /* Stack: --> uint32... */ + /* */ + static void + Ins_NPUSHB( TT_ExecContext exc, + FT_Long* args ) + { + FT_UShort L, K; - case 4: - /* probably not necessary to detect anymore */ - rec->sph_fdef_flags |= SPH_FDEF_TTFAUTOHINT_1; - exc->face->sph_found_func_flags |= SPH_FDEF_TTFAUTOHINT_1; - break; - case 5: - switch ( n ) - { - case 0: - case 1: - case 2: - case 4: - case 7: - case 8: - rec->sph_fdef_flags |= SPH_FDEF_SPACING_1; - exc->face->sph_found_func_flags |= SPH_FDEF_SPACING_1; - } - break; + L = (FT_UShort)exc->code[exc->IP + 1]; - case 6: - switch ( n ) - { - case 0: - case 1: - case 2: - case 4: - case 7: - case 8: - rec->sph_fdef_flags |= SPH_FDEF_SPACING_2; - exc->face->sph_found_func_flags |= SPH_FDEF_SPACING_2; - } - break; + if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) ) + { + exc->error = FT_THROW( Stack_Overflow ); + return; + } - case 7: - rec->sph_fdef_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL; - exc->face->sph_found_func_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL; - break; + for ( K = 1; K <= L; K++ ) + args[K - 1] = exc->code[exc->IP + K + 1]; - case 8: -#if 0 - rec->sph_fdef_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL; - exc->face->sph_found_func_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL; -#endif - break; - } - opcode_pointer[i] = 0; - } - } + exc->new_top += L; + } - else - opcode_pointer[i] = 0; - } - /* Set sph_compatibility_mode only when deltas are detected */ - exc->face->sph_compatibility_mode = - ( ( exc->face->sph_found_func_flags & SPH_FDEF_INLINE_DELTA_1 ) | - ( exc->face->sph_found_func_flags & SPH_FDEF_INLINE_DELTA_2 ) ); - } + /*************************************************************************/ + /* */ + /* NPUSHW[]: PUSH N Words */ + /* Opcode range: 0x41 */ + /* Stack: --> int32... */ + /* */ + static void + Ins_NPUSHW( TT_ExecContext exc, + FT_Long* args ) + { + FT_UShort L, K; -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ - switch ( exc->opcode ) - { - case 0x89: /* IDEF */ - case 0x2C: /* FDEF */ - exc->error = FT_THROW( Nested_DEFS ); - return; + L = (FT_UShort)exc->code[exc->IP + 1]; - case 0x2D: /* ENDF */ - rec->end = exc->IP; - return; - } + if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) ) + { + exc->error = FT_THROW( Stack_Overflow ); + return; } + + exc->IP += 2; + + for ( K = 0; K < L; K++ ) + args[K] = GetShortIns( exc ); + + exc->step_ins = FALSE; + exc->new_top += L; } /*************************************************************************/ /* */ - /* ENDF[]: END Function definition */ - /* Opcode range: 0x2D */ - /* Stack: --> */ + /* PUSHB[abc]: PUSH Bytes */ + /* Opcode range: 0xB0-0xB7 */ + /* Stack: --> uint32... */ /* */ static void - Ins_ENDF( TT_ExecContext exc ) + Ins_PUSHB( TT_ExecContext exc, + FT_Long* args ) { - TT_CallRec* pRec; + FT_UShort L, K; -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - exc->sph_in_func_flags = 0x0000; -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + L = (FT_UShort)( exc->opcode - 0xB0 + 1 ); - if ( exc->callTop <= 0 ) /* We encountered an ENDF without a call */ + if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) ) { - exc->error = FT_THROW( ENDF_In_Exec_Stream ); + exc->error = FT_THROW( Stack_Overflow ); return; } - exc->callTop--; + for ( K = 1; K <= L; K++ ) + args[K - 1] = exc->code[exc->IP + K]; + } - pRec = &exc->callStack[exc->callTop]; - pRec->Cur_Count--; + /*************************************************************************/ + /* */ + /* PUSHW[abc]: PUSH Words */ + /* Opcode range: 0xB8-0xBF */ + /* Stack: --> int32... */ + /* */ + static void + Ins_PUSHW( TT_ExecContext exc, + FT_Long* args ) + { + FT_UShort L, K; - exc->step_ins = FALSE; - if ( pRec->Cur_Count > 0 ) + L = (FT_UShort)( exc->opcode - 0xB8 + 1 ); + + if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) ) { - exc->callTop++; - exc->IP = pRec->Def->start; + exc->error = FT_THROW( Stack_Overflow ); + return; } - else - /* Loop through the current function */ - Ins_Goto_CodeRange( exc, pRec->Caller_Range, pRec->Caller_IP ); - /* Exit the current call frame. */ + exc->IP++; - /* NOTE: If the last instruction of a program is a */ - /* CALL or LOOPCALL, the return address is */ - /* always out of the code range. This is a */ - /* valid address, and it is why we do not test */ - /* the result of Ins_Goto_CodeRange() here! */ + for ( K = 0; K < L; K++ ) + args[K] = GetShortIns( exc ); + + exc->step_ins = FALSE; } /*************************************************************************/ /* */ - /* CALL[]: CALL function */ - /* Opcode range: 0x2B */ - /* Stack: uint32? --> */ + /* MANAGING THE GRAPHICS STATE */ /* */ - static void - Ins_CALL( TT_ExecContext exc, - FT_Long* args ) - { - FT_ULong F; - TT_CallRec* pCrec; - TT_DefRecord* def; + /*************************************************************************/ - /* first of all, check the index */ + static FT_Bool + Ins_SxVTL( TT_ExecContext exc, + FT_UShort aIdx1, + FT_UShort aIdx2, + FT_UnitVector* Vec ) + { + FT_Long A, B, C; + FT_Vector* p1; + FT_Vector* p2; - F = args[0]; - if ( BOUNDSL( F, exc->maxFunc + 1 ) ) - goto Fail; + FT_Byte opcode = exc->opcode; - /* Except for some old Apple fonts, all functions in a TrueType */ - /* font are defined in increasing order, starting from 0. This */ - /* means that we normally have */ - /* */ - /* exc->maxFunc+1 == exc->numFDefs */ - /* exc->FDefs[n].opc == n for n in 0..exc->maxFunc */ - /* */ - /* If this isn't true, we need to look up the function table. */ - def = exc->FDefs + F; - if ( exc->maxFunc + 1 != exc->numFDefs || def->opc != F ) + if ( BOUNDS( aIdx1, exc->zp2.n_points ) || + BOUNDS( aIdx2, exc->zp1.n_points ) ) { - /* look up the FDefs table */ - TT_DefRecord* limit; + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); + return FAILURE; + } + p1 = exc->zp1.cur + aIdx2; + p2 = exc->zp2.cur + aIdx1; - def = exc->FDefs; - limit = def + exc->numFDefs; + A = p1->x - p2->x; + B = p1->y - p2->y; - while ( def < limit && def->opc != F ) - def++; + /* If p1 == p2, SPvTL and SFvTL behave the same as */ + /* SPvTCA[X] and SFvTCA[X], respectively. */ + /* */ + /* Confirmed by Greg Hitchcock. */ - if ( def == limit ) - goto Fail; + if ( A == 0 && B == 0 ) + { + A = 0x4000; + opcode = 0; } - /* check that the function is active */ - if ( !def->active ) - goto Fail; + if ( ( opcode & 1 ) != 0 ) + { + C = B; /* counter clockwise rotation */ + B = A; + A = -C; + } -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - if ( SUBPIXEL_HINTING && - exc->ignore_x_mode && - ( ( exc->iup_called && - ( exc->sph_tweak_flags & SPH_TWEAK_NO_CALL_AFTER_IUP ) ) || - ( def->sph_fdef_flags & SPH_FDEF_VACUFORM_ROUND_1 ) ) ) - goto Fail; + Normalize( A, B, Vec ); + + return SUCCESS; + } + + + /*************************************************************************/ + /* */ + /* SVTCA[a]: Set (F and P) Vectors to Coordinate Axis */ + /* Opcode range: 0x00-0x01 */ + /* Stack: --> */ + /* */ + /* SPvTCA[a]: Set PVector to Coordinate Axis */ + /* Opcode range: 0x02-0x03 */ + /* Stack: --> */ + /* */ + /* SFvTCA[a]: Set FVector to Coordinate Axis */ + /* Opcode range: 0x04-0x05 */ + /* Stack: --> */ + /* */ + static void + Ins_SxyTCA( TT_ExecContext exc ) + { + FT_Short AA, BB; + + FT_Byte opcode = exc->opcode; + + + AA = (FT_Short)( ( opcode & 1 ) << 14 ); + BB = (FT_Short)( AA ^ 0x4000 ); + + if ( opcode < 4 ) + { + exc->GS.projVector.x = AA; + exc->GS.projVector.y = BB; + + exc->GS.dualVector.x = AA; + exc->GS.dualVector.y = BB; + } else - exc->sph_in_func_flags = def->sph_fdef_flags; -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + GUESS_VECTOR( projVector ); - /* check the call stack */ - if ( exc->callTop >= exc->callSize ) + if ( ( opcode & 2 ) == 0 ) { - exc->error = FT_THROW( Stack_Overflow ); - return; + exc->GS.freeVector.x = AA; + exc->GS.freeVector.y = BB; + } + else + GUESS_VECTOR( freeVector ); + + Compute_Funcs( exc ); + } + + + /*************************************************************************/ + /* */ + /* SPvTL[a]: Set PVector To Line */ + /* Opcode range: 0x06-0x07 */ + /* Stack: uint32 uint32 --> */ + /* */ + static void + Ins_SPVTL( TT_ExecContext exc, + FT_Long* args ) + { + if ( Ins_SxVTL( exc, + (FT_UShort)args[1], + (FT_UShort)args[0], + &exc->GS.projVector ) == SUCCESS ) + { + exc->GS.dualVector = exc->GS.projVector; + GUESS_VECTOR( freeVector ); + Compute_Funcs( exc ); + } + } + + + /*************************************************************************/ + /* */ + /* SFvTL[a]: Set FVector To Line */ + /* Opcode range: 0x08-0x09 */ + /* Stack: uint32 uint32 --> */ + /* */ + static void + Ins_SFVTL( TT_ExecContext exc, + FT_Long* args ) + { + if ( Ins_SxVTL( exc, + (FT_UShort)args[1], + (FT_UShort)args[0], + &exc->GS.freeVector ) == SUCCESS ) + { + GUESS_VECTOR( projVector ); + Compute_Funcs( exc ); } + } - pCrec = exc->callStack + exc->callTop; - - pCrec->Caller_Range = exc->curRange; - pCrec->Caller_IP = exc->IP + 1; - pCrec->Cur_Count = 1; - pCrec->Def = def; - - exc->callTop++; - - Ins_Goto_CodeRange( exc, def->range, def->start ); - - exc->step_ins = FALSE; - - return; - Fail: - exc->error = FT_THROW( Invalid_Reference ); + /*************************************************************************/ + /* */ + /* SFvTPv[]: Set FVector To PVector */ + /* Opcode range: 0x0E */ + /* Stack: --> */ + /* */ + static void + Ins_SFVTPV( TT_ExecContext exc ) + { + GUESS_VECTOR( projVector ); + exc->GS.freeVector = exc->GS.projVector; + Compute_Funcs( exc ); } /*************************************************************************/ /* */ - /* LOOPCALL[]: LOOP and CALL function */ - /* Opcode range: 0x2A */ - /* Stack: uint32? Eint16? --> */ + /* SPvFS[]: Set PVector From Stack */ + /* Opcode range: 0x0A */ + /* Stack: f2.14 f2.14 --> */ /* */ static void - Ins_LOOPCALL( TT_ExecContext exc, - FT_Long* args ) + Ins_SPVFS( TT_ExecContext exc, + FT_Long* args ) { - FT_ULong F; - TT_CallRec* pCrec; - TT_DefRecord* def; + FT_Short S; + FT_Long X, Y; - /* first of all, check the index */ - F = args[1]; - if ( BOUNDSL( F, exc->maxFunc + 1 ) ) - goto Fail; + /* Only use low 16bits, then sign extend */ + S = (FT_Short)args[1]; + Y = (FT_Long)S; + S = (FT_Short)args[0]; + X = (FT_Long)S; - /* Except for some old Apple fonts, all functions in a TrueType */ - /* font are defined in increasing order, starting from 0. This */ - /* means that we normally have */ - /* */ - /* exc->maxFunc+1 == exc->numFDefs */ - /* exc->FDefs[n].opc == n for n in 0..exc->maxFunc */ - /* */ - /* If this isn't true, we need to look up the function table. */ + Normalize( X, Y, &exc->GS.projVector ); - def = exc->FDefs + F; - if ( exc->maxFunc + 1 != exc->numFDefs || def->opc != F ) - { - /* look up the FDefs table */ - TT_DefRecord* limit; + exc->GS.dualVector = exc->GS.projVector; + GUESS_VECTOR( freeVector ); + Compute_Funcs( exc ); + } - def = exc->FDefs; - limit = def + exc->numFDefs; + /*************************************************************************/ + /* */ + /* SFvFS[]: Set FVector From Stack */ + /* Opcode range: 0x0B */ + /* Stack: f2.14 f2.14 --> */ + /* */ + static void + Ins_SFVFS( TT_ExecContext exc, + FT_Long* args ) + { + FT_Short S; + FT_Long X, Y; - while ( def < limit && def->opc != F ) - def++; - if ( def == limit ) - goto Fail; - } + /* Only use low 16bits, then sign extend */ + S = (FT_Short)args[1]; + Y = (FT_Long)S; + S = (FT_Short)args[0]; + X = S; - /* check that the function is active */ - if ( !def->active ) - goto Fail; + Normalize( X, Y, &exc->GS.freeVector ); + GUESS_VECTOR( projVector ); + Compute_Funcs( exc ); + } -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - if ( SUBPIXEL_HINTING && - exc->ignore_x_mode && - ( def->sph_fdef_flags & SPH_FDEF_VACUFORM_ROUND_1 ) ) - goto Fail; - else - exc->sph_in_func_flags = def->sph_fdef_flags; -#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ - /* check stack */ - if ( exc->callTop >= exc->callSize ) + /*************************************************************************/ + /* */ + /* GPv[]: Get Projection Vector */ + /* Opcode range: 0x0C */ + /* Stack: ef2.14 --> ef2.14 */ + /* */ + static void + Ins_GPV( TT_ExecContext exc, + FT_Long* args ) + { +#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING + if ( exc->face->unpatented_hinting ) { - exc->error = FT_THROW( Stack_Overflow ); - return; + args[0] = exc->GS.both_x_axis ? 0x4000 : 0; + args[1] = exc->GS.both_x_axis ? 0 : 0x4000; } - - if ( args[0] > 0 ) + else { - pCrec = exc->callStack + exc->callTop; - - pCrec->Caller_Range = exc->curRange; - pCrec->Caller_IP = exc->IP + 1; - pCrec->Cur_Count = (FT_Int)args[0]; - pCrec->Def = def; - - exc->callTop++; - - Ins_Goto_CodeRange( exc, def->range, def->start ); - - exc->step_ins = FALSE; + args[0] = exc->GS.projVector.x; + args[1] = exc->GS.projVector.y; } - - return; - - Fail: - exc->error = FT_THROW( Invalid_Reference ); +#else + args[0] = exc->GS.projVector.x; + args[1] = exc->GS.projVector.y; +#endif } /*************************************************************************/ /* */ - /* IDEF[]: Instruction DEFinition */ - /* Opcode range: 0x89 */ - /* Stack: Eint8 --> */ + /* GFv[]: Get Freedom Vector */ + /* Opcode range: 0x0D */ + /* Stack: ef2.14 --> ef2.14 */ /* */ static void - Ins_IDEF( TT_ExecContext exc, - FT_Long* args ) + Ins_GFV( TT_ExecContext exc, + FT_Long* args ) { - TT_DefRecord* def; - TT_DefRecord* limit; - - - /* First of all, look for the same function in our table */ - - def = exc->IDefs; - limit = def + exc->numIDefs; - - for ( ; def < limit; def++ ) - if ( def->opc == (FT_ULong)args[0] ) - break; - - if ( def == limit ) +#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING + if ( exc->face->unpatented_hinting ) { - /* check that there is enough room for a new instruction */ - if ( exc->numIDefs >= exc->maxIDefs ) - { - exc->error = FT_THROW( Too_Many_Instruction_Defs ); - return; - } - exc->numIDefs++; + args[0] = exc->GS.both_x_axis ? 0x4000 : 0; + args[1] = exc->GS.both_x_axis ? 0 : 0x4000; } - - /* opcode must be unsigned 8-bit integer */ - if ( 0 > args[0] || args[0] > 0x00FF ) + else { - exc->error = FT_THROW( Too_Many_Instruction_Defs ); - return; + args[0] = exc->GS.freeVector.x; + args[1] = exc->GS.freeVector.y; } +#else + args[0] = exc->GS.freeVector.x; + args[1] = exc->GS.freeVector.y; +#endif + } - def->opc = (FT_Byte)args[0]; - def->start = exc->IP + 1; - def->range = exc->curRange; - def->active = TRUE; - if ( (FT_ULong)args[0] > exc->maxIns ) - exc->maxIns = (FT_Byte)args[0]; + /*************************************************************************/ + /* */ + /* SRP0[]: Set Reference Point 0 */ + /* Opcode range: 0x10 */ + /* Stack: uint32 --> */ + /* */ + static void + Ins_SRP0( TT_ExecContext exc, + FT_Long* args ) + { + exc->GS.rp0 = (FT_UShort)args[0]; + } - /* Now skip the whole function definition. */ - /* We don't allow nested IDEFs & FDEFs. */ - while ( SkipCode( exc ) == SUCCESS ) - { - switch ( exc->opcode ) - { - case 0x89: /* IDEF */ - case 0x2C: /* FDEF */ - exc->error = FT_THROW( Nested_DEFS ); - return; - case 0x2D: /* ENDF */ - return; - } - } + /*************************************************************************/ + /* */ + /* SRP1[]: Set Reference Point 1 */ + /* Opcode range: 0x11 */ + /* Stack: uint32 --> */ + /* */ + static void + Ins_SRP1( TT_ExecContext exc, + FT_Long* args ) + { + exc->GS.rp1 = (FT_UShort)args[0]; + } + + + /*************************************************************************/ + /* */ + /* SRP2[]: Set Reference Point 2 */ + /* Opcode range: 0x12 */ + /* Stack: uint32 --> */ + /* */ + static void + Ins_SRP2( TT_ExecContext exc, + FT_Long* args ) + { + exc->GS.rp2 = (FT_UShort)args[0]; } /*************************************************************************/ /* */ - /* PUSHING DATA ONTO THE INTERPRETER STACK */ - /* */ - /* Instructions appear in the specification's order. */ + /* SMD[]: Set Minimum Distance */ + /* Opcode range: 0x1A */ + /* Stack: f26.6 --> */ /* */ - /*************************************************************************/ + static void + Ins_SMD( TT_ExecContext exc, + FT_Long* args ) + { + exc->GS.minimum_distance = args[0]; + } /*************************************************************************/ /* */ - /* NPUSHB[]: PUSH N Bytes */ - /* Opcode range: 0x40 */ - /* Stack: --> uint32... */ + /* SCVTCI[]: Set Control Value Table Cut In */ + /* Opcode range: 0x1D */ + /* Stack: f26.6 --> */ /* */ static void - Ins_NPUSHB( TT_ExecContext exc, + Ins_SCVTCI( TT_ExecContext exc, FT_Long* args ) { - FT_UShort L, K; - - - L = (FT_UShort)exc->code[exc->IP + 1]; - - if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) ) - { - exc->error = FT_THROW( Stack_Overflow ); - return; - } + exc->GS.control_value_cutin = (FT_F26Dot6)args[0]; + } - for ( K = 1; K <= L; K++ ) - args[K - 1] = exc->code[exc->IP + K + 1]; - exc->new_top += L; + /*************************************************************************/ + /* */ + /* SSWCI[]: Set Single Width Cut In */ + /* Opcode range: 0x1E */ + /* Stack: f26.6 --> */ + /* */ + static void + Ins_SSWCI( TT_ExecContext exc, + FT_Long* args ) + { + exc->GS.single_width_cutin = (FT_F26Dot6)args[0]; } /*************************************************************************/ /* */ - /* NPUSHW[]: PUSH N Words */ - /* Opcode range: 0x41 */ - /* Stack: --> int32... */ + /* SSW[]: Set Single Width */ + /* Opcode range: 0x1F */ + /* Stack: int32? --> */ /* */ static void - Ins_NPUSHW( TT_ExecContext exc, - FT_Long* args ) + Ins_SSW( TT_ExecContext exc, + FT_Long* args ) { - FT_UShort L, K; + exc->GS.single_width_value = FT_MulFix( args[0], + exc->tt_metrics.scale ); + } - L = (FT_UShort)exc->code[exc->IP + 1]; + /*************************************************************************/ + /* */ + /* FLIPON[]: Set auto-FLIP to ON */ + /* Opcode range: 0x4D */ + /* Stack: --> */ + /* */ + static void + Ins_FLIPON( TT_ExecContext exc ) + { + exc->GS.auto_flip = TRUE; + } - if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) ) - { - exc->error = FT_THROW( Stack_Overflow ); - return; - } - exc->IP += 2; + /*************************************************************************/ + /* */ + /* FLIPOFF[]: Set auto-FLIP to OFF */ + /* Opcode range: 0x4E */ + /* Stack: --> */ + /* */ + static void + Ins_FLIPOFF( TT_ExecContext exc ) + { + exc->GS.auto_flip = FALSE; + } - for ( K = 0; K < L; K++ ) - args[K] = GetShortIns( exc ); - exc->step_ins = FALSE; - exc->new_top += L; + /*************************************************************************/ + /* */ + /* SANGW[]: Set ANGle Weight */ + /* Opcode range: 0x7E */ + /* Stack: uint32 --> */ + /* */ + static void + Ins_SANGW( void ) + { + /* instruction not supported anymore */ } /*************************************************************************/ /* */ - /* PUSHB[abc]: PUSH Bytes */ - /* Opcode range: 0xB0-0xB7 */ - /* Stack: --> uint32... */ + /* SDB[]: Set Delta Base */ + /* Opcode range: 0x5E */ + /* Stack: uint32 --> */ /* */ static void - Ins_PUSHB( TT_ExecContext exc, - FT_Long* args ) + Ins_SDB( TT_ExecContext exc, + FT_Long* args ) { - FT_UShort L, K; + exc->GS.delta_base = (FT_UShort)args[0]; + } - L = (FT_UShort)( exc->opcode - 0xB0 + 1 ); + /*************************************************************************/ + /* */ + /* SDS[]: Set Delta Shift */ + /* Opcode range: 0x5F */ + /* Stack: uint32 --> */ + /* */ + static void + Ins_SDS( TT_ExecContext exc, + FT_Long* args ) + { + if ( (FT_ULong)args[0] > 6UL ) + exc->error = FT_THROW( Bad_Argument ); + else + exc->GS.delta_shift = (FT_UShort)args[0]; + } - if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) ) - { - exc->error = FT_THROW( Stack_Overflow ); - return; - } - for ( K = 1; K <= L; K++ ) - args[K - 1] = exc->code[exc->IP + K]; + /*************************************************************************/ + /* */ + /* RTHG[]: Round To Half Grid */ + /* Opcode range: 0x19 */ + /* Stack: --> */ + /* */ + static void + Ins_RTHG( TT_ExecContext exc ) + { + exc->GS.round_state = TT_Round_To_Half_Grid; + exc->func_round = (TT_Round_Func)Round_To_Half_Grid; } /*************************************************************************/ /* */ - /* PUSHW[abc]: PUSH Words */ - /* Opcode range: 0xB8-0xBF */ - /* Stack: --> int32... */ + /* RTG[]: Round To Grid */ + /* Opcode range: 0x18 */ + /* Stack: --> */ /* */ static void - Ins_PUSHW( TT_ExecContext exc, - FT_Long* args ) + Ins_RTG( TT_ExecContext exc ) { - FT_UShort L, K; + exc->GS.round_state = TT_Round_To_Grid; + exc->func_round = (TT_Round_Func)Round_To_Grid; + } - L = (FT_UShort)( exc->opcode - 0xB8 + 1 ); + /*************************************************************************/ + /* RTDG[]: Round To Double Grid */ + /* Opcode range: 0x3D */ + /* Stack: --> */ + /* */ + static void + Ins_RTDG( TT_ExecContext exc ) + { + exc->GS.round_state = TT_Round_To_Double_Grid; + exc->func_round = (TT_Round_Func)Round_To_Double_Grid; + } - if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) ) - { - exc->error = FT_THROW( Stack_Overflow ); - return; - } - exc->IP++; + /*************************************************************************/ + /* RUTG[]: Round Up To Grid */ + /* Opcode range: 0x7C */ + /* Stack: --> */ + /* */ + static void + Ins_RUTG( TT_ExecContext exc ) + { + exc->GS.round_state = TT_Round_Up_To_Grid; + exc->func_round = (TT_Round_Func)Round_Up_To_Grid; + } - for ( K = 0; K < L; K++ ) - args[K] = GetShortIns( exc ); - exc->step_ins = FALSE; + /*************************************************************************/ + /* */ + /* RDTG[]: Round Down To Grid */ + /* Opcode range: 0x7D */ + /* Stack: --> */ + /* */ + static void + Ins_RDTG( TT_ExecContext exc ) + { + exc->GS.round_state = TT_Round_Down_To_Grid; + exc->func_round = (TT_Round_Func)Round_Down_To_Grid; } /*************************************************************************/ /* */ - /* MANAGING THE GRAPHICS STATE */ + /* ROFF[]: Round OFF */ + /* Opcode range: 0x7A */ + /* Stack: --> */ + /* */ + static void + Ins_ROFF( TT_ExecContext exc ) + { + exc->GS.round_state = TT_Round_Off; + exc->func_round = (TT_Round_Func)Round_None; + } + + + /*************************************************************************/ /* */ - /* Instructions appear in the specs' order. */ + /* SROUND[]: Super ROUND */ + /* Opcode range: 0x76 */ + /* Stack: Eint8 --> */ /* */ + static void + Ins_SROUND( TT_ExecContext exc, + FT_Long* args ) + { + SetSuperRound( exc, 0x4000, args[0] ); + + exc->GS.round_state = TT_Round_Super; + exc->func_round = (TT_Round_Func)Round_Super; + } + + /*************************************************************************/ + /* */ + /* S45ROUND[]: Super ROUND 45 degrees */ + /* Opcode range: 0x77 */ + /* Stack: uint32 --> */ + /* */ + static void + Ins_S45ROUND( TT_ExecContext exc, + FT_Long* args ) + { + SetSuperRound( exc, 0x2D41, args[0] ); + + exc->GS.round_state = TT_Round_Super_45; + exc->func_round = (TT_Round_Func)Round_Super_45; + } /*************************************************************************/ @@ -5267,8 +5259,6 @@ /* */ /* MANAGING OUTLINES */ /* */ - /* Instructions appear in the specification's order. */ - /* */ /*************************************************************************/ @@ -7473,8 +7463,6 @@ /* */ /* THIS IS THE INTERPRETER'S MAIN LOOP. */ /* */ - /* Instructions appear in the specification's order. */ - /* */ /*************************************************************************/