#include "freetype.h"
#include "tttypes.h"
#include "ttdebug.h"
#include "ttcalc.h"
#include "ttmemory.h"
#include "ttinterp.h"
#ifdef TT_CONFIG_OPTION_NO_INTERPRETER
LOCAL_FUNC
TT_Error RunIns( PExecution_Context exc )
{
(void)exc;
return TT_Err_Ok;
}
#else
#ifdef DEBUG_INTERPRETER
#include <memory.h>
#include "ttdebug.h"
#ifdef OS2
#include <conio.h>
#else
#define getch getchar
#endif
#endif
#undef TT_COMPONENT
#define TT_COMPONENT trace_interp
#define MAX_RUNNABLE_OPCODES 1000000
#ifndef TT_CONFIG_OPTION_STATIC_INTERPRETER
#define CUR (*exc)
#else
#define CUR cur
static TExecution_Context cur;
#endif
#define INS_ARG EXEC_OPS PStorage args
#define SKIP_Code() SkipCode( EXEC_ARG )
#define GET_ShortIns() GetShortIns( EXEC_ARG )
#define COMPUTE_Funcs() Compute_Funcs( EXEC_ARG )
#define NORMalize( x, y, v ) Normalize( EXEC_ARGS x, y, v )
#define SET_SuperRound( scale, flags ) \
SetSuperRound( EXEC_ARGS scale, flags )
#define INS_Goto_CodeRange( range, ip ) \
Ins_Goto_CodeRange( EXEC_ARGS range, ip )
#define CUR_Func_project( x, y ) CUR.func_project( EXEC_ARGS x, y )
#define CUR_Func_move( z, p, d ) CUR.func_move( EXEC_ARGS z, p, d )
#define CUR_Func_dualproj( x, y ) CUR.func_dualproj( EXEC_ARGS x, y )
#define CUR_Func_freeProj( x, y ) CUR.func_freeProj( EXEC_ARGS x, y )
#define CUR_Func_round( d, c ) CUR.func_round( EXEC_ARGS d, c )
#define CUR_Func_read_cvt( index ) \
CUR.func_read_cvt( EXEC_ARGS index )
#define CUR_Func_write_cvt( index, val ) \
CUR.func_write_cvt( EXEC_ARGS index, val )
#define CUR_Func_move_cvt( index, val ) \
CUR.func_move_cvt( EXEC_ARGS index, val )
#define CURRENT_Ratio() Current_Ratio( EXEC_ARG )
#define CURRENT_Ppem() Current_Ppem( EXEC_ARG )
#define CALC_Length() Calc_Length( EXEC_ARG )
#define INS_SxVTL( a, b, c, d ) Ins_SxVTL( EXEC_ARGS a, b, c, d )
#define COMPUTE_Point_Displacement( a, b, c, d ) \
Compute_Point_Displacement( EXEC_ARGS a, b, c, d )
#define MOVE_Zp2_Point( a, b, c, t ) Move_Zp2_Point( EXEC_ARGS a, b, c, t )
#define CUR_Ppem() Cur_PPEM( EXEC_ARG )
typedef void (*TInstruction_Function)( INS_ARG );
#define BOUNDS( x, n ) ( (x) >= (n) )
#undef PACK
#define PACK( x, y ) ((x << 4) | y)
static const Byte Pop_Push_Count[256] =
{
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 0, 2 ),
PACK( 0, 2 ),
PACK( 0, 0 ),
PACK( 5, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 1, 0 ),
PACK( 0, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 2 ),
PACK( 1, 0 ),
PACK( 0, 0 ),
PACK( 2, 2 ),
PACK( 0, 1 ),
PACK( 1, 1 ),
PACK( 1, 0 ),
PACK( 2, 0 ),
PACK( 0, 0 ),
PACK( 1, 0 ),
PACK( 2, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 0, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 0, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 2, 0 ),
PACK( 1, 1 ),
PACK( 2, 0 ),
PACK( 1, 1 ),
PACK( 1, 1 ),
PACK( 1, 1 ),
PACK( 2, 0 ),
PACK( 2, 1 ),
PACK( 2, 1 ),
PACK( 0, 1 ),
PACK( 0, 1 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 1, 0 ),
PACK( 2, 1 ),
PACK( 2, 1 ),
PACK( 2, 1 ),
PACK( 2, 1 ),
PACK( 2, 1 ),
PACK( 2, 1 ),
PACK( 1, 1 ),
PACK( 1, 1 ),
PACK( 1, 0 ),
PACK( 0, 0 ),
PACK( 2, 1 ),
PACK( 2, 1 ),
PACK( 1, 1 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 2, 1 ),
PACK( 2, 1 ),
PACK( 2, 1 ),
PACK( 2, 1 ),
PACK( 1, 1 ),
PACK( 1, 1 ),
PACK( 1, 1 ),
PACK( 1, 1 ),
PACK( 1, 1 ),
PACK( 1, 1 ),
PACK( 1, 1 ),
PACK( 1, 1 ),
PACK( 1, 1 ),
PACK( 1, 1 ),
PACK( 1, 1 ),
PACK( 1, 1 ),
PACK( 2, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 0, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 1, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 1, 1 ),
PACK( 1, 0 ),
PACK( 3, 3 ),
PACK( 2, 1 ),
PACK( 2, 1 ),
PACK( 1, 0 ),
PACK( 2, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 0 ),
PACK( 0, 1 ),
PACK( 0, 2 ),
PACK( 0, 3 ),
PACK( 0, 4 ),
PACK( 0, 5 ),
PACK( 0, 6 ),
PACK( 0, 7 ),
PACK( 0, 8 ),
PACK( 0, 1 ),
PACK( 0, 2 ),
PACK( 0, 3 ),
PACK( 0, 4 ),
PACK( 0, 5 ),
PACK( 0, 6 ),
PACK( 0, 7 ),
PACK( 0, 8 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 1, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 ),
PACK( 2, 0 )
};
static const TT_Vector Null_Vector = {0,0};
#undef NULL_Vector
#define NULL_Vector (TT_Vector*)&Null_Vector
static TT_F26Dot6 Norm( TT_F26Dot6 X, TT_F26Dot6 Y )
{
TT_Int64 T1, T2;
MUL_64( X, X, T1 );
MUL_64( Y, Y, T2 );
ADD_64( T1, T2, T1 );
return (TT_F26Dot6)SQRT_64( T1 );
}
static TT_F26Dot6 FUnits_To_Pixels( EXEC_OPS Short distance )
{
return TT_MulDiv( distance,
CUR.metrics.scale1,
CUR.metrics.scale2 );
}
static Long Current_Ratio( EXEC_OP )
{
if ( CUR.metrics.ratio )
return CUR.metrics.ratio;
if ( CUR.GS.projVector.y == 0 )
CUR.metrics.ratio = CUR.metrics.x_ratio;
else if ( CUR.GS.projVector.x == 0 )
CUR.metrics.ratio = CUR.metrics.y_ratio;
else
{
Long x, y;
x = TT_MulDiv( CUR.GS.projVector.x, CUR.metrics.x_ratio, 0x4000 );
y = TT_MulDiv( CUR.GS.projVector.y, CUR.metrics.y_ratio, 0x4000 );
CUR.metrics.ratio = Norm( x, y );
}
return CUR.metrics.ratio;
}
static Long Current_Ppem( EXEC_OP )
{
return TT_MulFix( CUR.metrics.ppem, CURRENT_Ratio() );
}
static TT_F26Dot6 Read_CVT( EXEC_OPS ULong index )
{
return CUR.cvt[index];
}
static TT_F26Dot6 Read_CVT_Stretched( EXEC_OPS ULong index )
{
return TT_MulFix( CUR.cvt[index], CURRENT_Ratio() );
}
static void Write_CVT( EXEC_OPS ULong index, TT_F26Dot6 value )
{
CUR.cvt[index] = value;
}
static void Write_CVT_Stretched( EXEC_OPS ULong index, TT_F26Dot6 value )
{
CUR.cvt[index] = TT_MulDiv( value, 0x10000, CURRENT_Ratio() );
}
static void Move_CVT( EXEC_OPS ULong index, TT_F26Dot6 value )
{
CUR.cvt[index] += value;
}
static void Move_CVT_Stretched( EXEC_OPS ULong index, TT_F26Dot6 value )
{
CUR.cvt[index] += TT_MulDiv( value, 0x10000, CURRENT_Ratio() );
}
static Bool Calc_Length( EXEC_OP )
{
CUR.opcode = CUR.code[CUR.IP];
switch ( CUR.opcode )
{
case 0x40:
if ( CUR.IP + 1 >= CUR.codeSize )
return FAILURE;
CUR.length = CUR.code[CUR.IP + 1] + 2;
break;
case 0x41:
if ( CUR.IP + 1 >= CUR.codeSize )
return FAILURE;
CUR.length = CUR.code[CUR.IP + 1] * 2 + 2;
break;
case 0xB0:
case 0xB1:
case 0xB2:
case 0xB3:
case 0xB4:
case 0xB5:
case 0xB6:
case 0xB7:
CUR.length = CUR.opcode - 0xB0 + 2;
break;
case 0xB8:
case 0xB9:
case 0xBA:
case 0xBB:
case 0xBC:
case 0xBD:
case 0xBE:
case 0xBF:
CUR.length = (CUR.opcode - 0xB8) * 2 + 3;
break;
default:
CUR.length = 1;
break;
}
if ( CUR.IP + CUR.length > CUR.codeSize )
return FAILURE;
return SUCCESS;
}
static Short GetShortIns( EXEC_OP )
{
CUR.IP += 2;
return (Short)((CUR.code[CUR.IP - 2] << 8) + CUR.code[CUR.IP - 1]);
}
static Bool Ins_Goto_CodeRange( EXEC_OPS Int aRange, ULong aIP )
{
TCodeRange* WITH;
if ( aRange < 1 || aRange > 3 )
{
CUR.error = TT_Err_Bad_Argument;
return FAILURE;
}
WITH = &CUR.codeRangeTable[aRange - 1];
if ( WITH->Base == NULL )
{
CUR.error = TT_Err_Invalid_CodeRange;
return FAILURE;
}
if ( aIP > WITH->Size )
{
CUR.error = TT_Err_Code_Overflow;
return FAILURE;
}
CUR.code = WITH->Base;
CUR.codeSize = WITH->Size;
CUR.IP = aIP;
CUR.curRange = aRange;
return SUCCESS;
}
static void Direct_Move( EXEC_OPS PGlyph_Zone zone,
UShort point,
TT_F26Dot6 distance )
{
TT_F26Dot6 v;
v = CUR.GS.freeVector.x;
if ( v != 0 )
{
zone->cur[point].x += TT_MulDiv( distance,
v * 0x10000L,
CUR.F_dot_P );
zone->touch[point] |= TT_Flag_Touched_X;
}
v = CUR.GS.freeVector.y;
if ( v != 0 )
{
zone->cur[point].y += TT_MulDiv( distance,
v * 0x10000L,
CUR.F_dot_P );
zone->touch[point] |= TT_Flag_Touched_Y;
}
}
static void Direct_Move_X( EXEC_OPS PGlyph_Zone zone,
UShort point,
TT_F26Dot6 distance )
{
zone->cur[point].x += distance;
zone->touch[point] |= TT_Flag_Touched_X;
}
static void Direct_Move_Y( EXEC_OPS PGlyph_Zone zone,
UShort point,
TT_F26Dot6 distance )
{
zone->cur[point].y += distance;
zone->touch[point] |= TT_Flag_Touched_Y;
}
static TT_F26Dot6 Round_None( EXEC_OPS TT_F26Dot6 distance,
TT_F26Dot6 compensation )
{
TT_F26Dot6 val;
if ( distance >= 0 )
{
val = distance + compensation;
if ( val < 0 )
val = 0;
}
else {
val = distance - compensation;
if ( val > 0 )
val = 0;
}
return val;
}
static TT_F26Dot6 Round_To_Grid( EXEC_OPS TT_F26Dot6 distance,
TT_F26Dot6 compensation )
{
TT_F26Dot6 val;
if ( distance >= 0 )
{
val = distance + compensation + 32;
if ( val > 0 )
val &= ~63;
else
val = 0;
}
else
{
val = -( (compensation - distance + 32) & (-64) );
if ( val > 0 )
val = 0;
}
return val;
}
static TT_F26Dot6 Round_To_Half_Grid( EXEC_OPS TT_F26Dot6 distance,
TT_F26Dot6 compensation )
{
TT_F26Dot6 val;
if ( distance >= 0 )
{
val = ((distance + compensation) & (-64)) + 32;
if ( val < 0 )
val = 0;
}
else
{
val = -( ((compensation - distance) & (-64)) + 32 );
if ( val > 0 )
val = 0;
}
return val;
}
static TT_F26Dot6 Round_Down_To_Grid( EXEC_OPS TT_F26Dot6 distance,
TT_F26Dot6 compensation )
{
TT_F26Dot6 val;
if ( distance >= 0 )
{
val = distance + compensation;
if ( val > 0 )
val &= ~63;
else
val = 0;
}
else
{
val = -( (compensation - distance) & (-64) );
if ( val > 0 )
val = 0;
}
return val;
}
static TT_F26Dot6 Round_Up_To_Grid( EXEC_OPS TT_F26Dot6 distance,
TT_F26Dot6 compensation )
{
TT_F26Dot6 val;
if ( distance >= 0 )
{
val = distance + compensation + 63;
if ( val > 0 )
val &= ~63;
else
val = 0;
}
else
{
val = -( (compensation - distance + 63) & (-64) );
if ( val > 0 )
val = 0;
}
return val;
}
static TT_F26Dot6 Round_To_Double_Grid( EXEC_OPS TT_F26Dot6 distance,
TT_F26Dot6 compensation )
{
TT_F26Dot6 val;
if ( distance >= 0 )
{
val = distance + compensation + 16;
if ( val > 0 )
val &= ~31;
else
val = 0;
}
else
{
val = -( (compensation - distance + 16) & (-32) );
if ( val > 0 )
val = 0;
}
return val;
}
static TT_F26Dot6 Round_Super( EXEC_OPS TT_F26Dot6 distance,
TT_F26Dot6 compensation )
{
TT_F26Dot6 val;
if ( distance >= 0 )
{
val = (distance - CUR.phase + CUR.threshold + compensation) &
(-CUR.period);
if ( val < 0 )
val = 0;
val += CUR.phase;
}
else
{
val = -( (CUR.threshold - CUR.phase - distance + compensation) &
(-CUR.period) );
if ( val > 0 )
val = 0;
val -= CUR.phase;
}
return val;
}
static TT_F26Dot6 Round_Super_45( EXEC_OPS TT_F26Dot6 distance,
TT_F26Dot6 compensation )
{
TT_F26Dot6 val;
if ( distance >= 0 )
{
val = ( (distance - CUR.phase + CUR.threshold + compensation) /
CUR.period ) * CUR.period;
if ( val < 0 )
val = 0;
val += CUR.phase;
}
else
{
val = -( ( (CUR.threshold - CUR.phase - distance + compensation) /
CUR.period ) * CUR.period );
if ( val > 0 )
val = 0;
val -= CUR.phase;
}
return val;
}
static void Compute_Round( EXEC_OPS Byte round_mode )
{
switch ( round_mode )
{
case TT_Round_Off:
CUR.func_round = (TRound_Function)Round_None;
break;
case TT_Round_To_Grid:
CUR.func_round = (TRound_Function)Round_To_Grid;
break;
case TT_Round_Up_To_Grid:
CUR.func_round = (TRound_Function)Round_Up_To_Grid;
break;
case TT_Round_Down_To_Grid:
CUR.func_round = (TRound_Function)Round_Down_To_Grid;
break;
case TT_Round_To_Half_Grid:
CUR.func_round = (TRound_Function)Round_To_Half_Grid;
break;
case TT_Round_To_Double_Grid:
CUR.func_round = (TRound_Function)Round_To_Double_Grid;
break;
case TT_Round_Super:
CUR.func_round = (TRound_Function)Round_Super;
break;
case TT_Round_Super_45:
CUR.func_round = (TRound_Function)Round_Super_45;
break;
}
}
static void SetSuperRound( EXEC_OPS TT_F26Dot6 GridPeriod,
Long selector )
{
switch ( (Int)(selector & 0xC0) )
{
case 0:
CUR.period = GridPeriod / 2;
break;
case 0x40:
CUR.period = GridPeriod;
break;
case 0x80:
CUR.period = GridPeriod * 2;
break;
case 0xC0:
CUR.period = GridPeriod;
break;
}
switch ( (Int)(selector & 0x30) )
{
case 0:
CUR.phase = 0;
break;
case 0x10:
CUR.phase = CUR.period / 4;
break;
case 0x20:
CUR.phase = CUR.period / 2;
break;
case 0x30:
CUR.phase = GridPeriod * 3 / 4;
break;
}
if ( (selector & 0x0F) == 0 )
CUR.threshold = CUR.period - 1;
else
CUR.threshold = ( (Int)(selector & 0x0F) - 4 ) * CUR.period / 8;
CUR.period /= 256;
CUR.phase /= 256;
CUR.threshold /= 256;
}
static TT_F26Dot6 Project( EXEC_OPS TT_Vector* v1,
TT_Vector* v2 )
{
TT_Int64 T1, T2;
MUL_64( v1->x - v2->x, CUR.GS.projVector.x, T1 );
MUL_64( v1->y - v2->y, CUR.GS.projVector.y, T2 );
ADD_64( T1, T2, T1 );
return (TT_F26Dot6)DIV_64( T1, 0x4000L );
}
static TT_F26Dot6 Dual_Project( EXEC_OPS TT_Vector* v1,
TT_Vector* v2 )
{
TT_Int64 T1, T2;
MUL_64( v1->x - v2->x, CUR.GS.dualVector.x, T1 );
MUL_64( v1->y - v2->y, CUR.GS.dualVector.y, T2 );
ADD_64( T1, T2, T1 );
return (TT_F26Dot6)DIV_64( T1, 0x4000L );
}
static TT_F26Dot6 Free_Project( EXEC_OPS TT_Vector* v1,
TT_Vector* v2 )
{
TT_Int64 T1, T2;
MUL_64( v1->x - v2->x, CUR.GS.freeVector.x, T1 );
MUL_64( v1->y - v2->y, CUR.GS.freeVector.y, T2 );
ADD_64( T1, T2, T1 );
return (TT_F26Dot6)DIV_64( T1, 0x4000L );
}
static TT_F26Dot6 Project_x( EXEC_OPS TT_Vector* v1,
TT_Vector* v2 )
{
return (v1->x - v2->x);
}
static TT_F26Dot6 Project_y( EXEC_OPS TT_Vector* v1,
TT_Vector* v2 )
{
return (v1->y - v2->y);
}
static void Compute_Funcs( EXEC_OP )
{
if ( CUR.GS.freeVector.x == 0x4000 )
{
CUR.func_freeProj = (TProject_Function)Project_x;
CUR.F_dot_P = CUR.GS.projVector.x * 0x10000L;
}
else
{
if ( CUR.GS.freeVector.y == 0x4000 )
{
CUR.func_freeProj = (TProject_Function)Project_y;
CUR.F_dot_P = CUR.GS.projVector.y * 0x10000L;
}
else
{
CUR.func_freeProj = (TProject_Function)Free_Project;
CUR.F_dot_P = (Long)CUR.GS.projVector.x * CUR.GS.freeVector.x * 4 +
(Long)CUR.GS.projVector.y * CUR.GS.freeVector.y * 4;
}
}
CUR.cached_metrics = FALSE;
if ( CUR.GS.projVector.x == 0x4000 )
CUR.func_project = (TProject_Function)Project_x;
else
{
if ( CUR.GS.projVector.y == 0x4000 )
CUR.func_project = (TProject_Function)Project_y;
else
CUR.func_project = (TProject_Function)Project;
}
if ( CUR.GS.dualVector.x == 0x4000 )
CUR.func_dualproj = (TProject_Function)Project_x;
else
{
if ( CUR.GS.dualVector.y == 0x4000 )
CUR.func_dualproj = (TProject_Function)Project_y;
else
CUR.func_dualproj = (TProject_Function)Dual_Project;
}
CUR.func_move = (TMove_Function)Direct_Move;
if ( CUR.F_dot_P == 0x40000000L )
{
if ( CUR.GS.freeVector.x == 0x4000 )
CUR.func_move = (TMove_Function)Direct_Move_X;
else
{
if ( CUR.GS.freeVector.y == 0x4000 )
CUR.func_move = (TMove_Function)Direct_Move_Y;
}
}
if ( ABS( CUR.F_dot_P ) < 0x4000000L )
CUR.F_dot_P = 0x40000000L;
CUR.metrics.ratio = 0;
}
static Bool Normalize( EXEC_OPS TT_F26Dot6 Vx,
TT_F26Dot6 Vy,
TT_UnitVector* R )
{
TT_F26Dot6 W;
Bool S1, S2;
if ( ABS( Vx ) < 0x10000L && ABS( Vy ) < 0x10000L )
{
Vx *= 0x100;
Vy *= 0x100;
W = Norm( Vx, Vy );
if ( W == 0 )
{
return SUCCESS;
}
R->x = (TT_F2Dot14)TT_MulDiv( Vx, 0x4000L, W );
R->y = (TT_F2Dot14)TT_MulDiv( Vy, 0x4000L, W );
return SUCCESS;
}
W = Norm( Vx, Vy );
Vx = TT_MulDiv( Vx, 0x4000L, W );
Vy = TT_MulDiv( Vy, 0x4000L, W );
W = Vx * Vx + Vy * Vy;
if ( Vx < 0 )
{
Vx = -Vx;
S1 = TRUE;
}
else
S1 = FALSE;
if ( Vy < 0 )
{
Vy = -Vy;
S2 = TRUE;
}
else
S2 = FALSE;
while ( W < 0x1000000L )
{
if ( Vx < Vy )
Vx++;
else
Vy++;
W = Vx * Vx + Vy * Vy;
}
while ( W >= 0x1004000L )
{
if ( Vx < Vy )
Vx--;
else
Vy--;
W = Vx * Vx + Vy * Vy;
}
if ( S1 )
Vx = -Vx;
if ( S2 )
Vy = -Vy;
R->x = (TT_F2Dot14)Vx;
R->y = (TT_F2Dot14)Vy;
return SUCCESS;
}
static Bool Ins_SxVTL( EXEC_OPS UShort aIdx1,
UShort aIdx2,
Int aOpc,
TT_UnitVector* Vec )
{
Long A, B, C;
TT_Vector* p1;
TT_Vector* p2;
if ( BOUNDS( aIdx1, CUR.zp2.n_points ) ||
BOUNDS( aIdx2, CUR.zp1.n_points ) )
{
if ( CUR.pedantic_hinting )
CUR.error = TT_Err_Invalid_Reference;
return FAILURE;
}
p1 = CUR.zp1.cur + aIdx2;
p2 = CUR.zp2.cur + aIdx1;
A = p1->x - p2->x;
B = p1->y - p2->y;
if ( (aOpc & 1) != 0 )
{
C = B;
B = A;
A = -C;
}
NORMalize( A, B, Vec );
return SUCCESS;
}
#define DO_SVTCA \
{ \
Short A, B; \
\
\
A = (Short)(CUR.opcode & 1) << 14; \
B = A ^ (Short)0x4000; \
\
CUR.GS.freeVector.x = A; \
CUR.GS.projVector.x = A; \
CUR.GS.dualVector.x = A; \
\
CUR.GS.freeVector.y = B; \
CUR.GS.projVector.y = B; \
CUR.GS.dualVector.y = B; \
\
COMPUTE_Funcs(); \
}
#define DO_SPVTCA \
{ \
Short A, B; \
\
\
A = (Short)(CUR.opcode & 1) << 14; \
B = A ^ (Short)0x4000; \
\
CUR.GS.projVector.x = A; \
CUR.GS.dualVector.x = A; \
\
CUR.GS.projVector.y = B; \
CUR.GS.dualVector.y = B; \
\
COMPUTE_Funcs(); \
}
#define DO_SFVTCA \
{ \
Short A, B; \
\
\
A = (Short)(CUR.opcode & 1) << 14; \
B = A ^ (Short)0x4000; \
\
CUR.GS.freeVector.x = A; \
CUR.GS.freeVector.y = B; \
\
COMPUTE_Funcs(); \
}
#define DO_SPVTL \
if ( INS_SxVTL( (UShort)args[1], \
(UShort)args[0], \
CUR.opcode, \
&CUR.GS.projVector) == SUCCESS ) \
{ \
CUR.GS.dualVector = CUR.GS.projVector; \
COMPUTE_Funcs(); \
}
#define DO_SFVTL \
if ( INS_SxVTL( (UShort)args[1], \
(UShort)args[0], \
CUR.opcode, \
&CUR.GS.freeVector) == SUCCESS ) \
COMPUTE_Funcs();
#define DO_SFVTPV \
CUR.GS.freeVector = CUR.GS.projVector; \
COMPUTE_Funcs();
#define DO_SPVFS \
{ \
Short S; \
Long X, Y; \
\
\
\
S = (Short)args[1]; \
Y = (Long)S; \
S = (Short)args[0]; \
X = (Long)S; \
\
NORMalize( X, Y, &CUR.GS.projVector ); \
\
CUR.GS.dualVector = CUR.GS.projVector; \
COMPUTE_Funcs(); \
}
#define DO_SFVFS \
{ \
Short S; \
Long X, Y; \
\
\
\
S = (Short)args[1]; \
Y = (Long)S; \
S = (Short)args[0]; \
X = S; \
\
NORMalize( X, Y, &CUR.GS.freeVector ); \
COMPUTE_Funcs(); \
}
#define DO_GPV \
args[0] = CUR.GS.projVector.x; \
args[1] = CUR.GS.projVector.y;
#define DO_GFV \
args[0] = CUR.GS.freeVector.x; \
args[1] = CUR.GS.freeVector.y;
#define DO_SRP0 \
CUR.GS.rp0 = (UShort)args[0];
#define DO_SRP1 \
CUR.GS.rp1 = (UShort)args[0];
#define DO_SRP2 \
CUR.GS.rp2 = (UShort)args[0];
#define DO_RTHG \
CUR.GS.round_state = TT_Round_To_Half_Grid; \
CUR.func_round = (TRound_Function)Round_To_Half_Grid;
#define DO_RTG \
CUR.GS.round_state = TT_Round_To_Grid; \
CUR.func_round = (TRound_Function)Round_To_Grid;
#define DO_RTDG \
CUR.GS.round_state = TT_Round_To_Double_Grid; \
CUR.func_round = (TRound_Function)Round_To_Double_Grid;
#define DO_RUTG \
CUR.GS.round_state = TT_Round_Up_To_Grid; \
CUR.func_round = (TRound_Function)Round_Up_To_Grid;
#define DO_RDTG \
CUR.GS.round_state = TT_Round_Down_To_Grid; \
CUR.func_round = (TRound_Function)Round_Down_To_Grid;
#define DO_ROFF \
CUR.GS.round_state = TT_Round_Off; \
CUR.func_round = (TRound_Function)Round_None;
#define DO_SROUND \
SET_SuperRound( 0x4000L, args[0] ); \
CUR.GS.round_state = TT_Round_Super; \
CUR.func_round = (TRound_Function)Round_Super;
#define DO_S45ROUND \
SET_SuperRound( 0x2D41L, args[0] ); \
CUR.GS.round_state = TT_Round_Super_45; \
CUR.func_round = (TRound_Function)Round_Super_45;
#define DO_SLOOP \
if ( args[0] < 0 ) \
CUR.error = TT_Err_Bad_Argument; \
else \
CUR.GS.loop = args[0];
#define DO_SMD \
CUR.GS.minimum_distance = (TT_F26Dot6)args[0];
#define DO_SCVTCI \
CUR.GS.control_value_cutin = (TT_F26Dot6)args[0];
#define DO_SSWCI \
CUR.GS.single_width_cutin = (TT_F26Dot6)args[0];
#define DO_SSW \
CUR.GS.single_width_value = (TT_F26Dot6)(args[0] >> 10);
#define DO_FLIPON \
CUR.GS.auto_flip = TRUE;
#define DO_FLIPOFF \
CUR.GS.auto_flip = FALSE;
#define DO_SDB \
CUR.GS.delta_base = (Short)args[0];
#define DO_SDS \
CUR.GS.delta_shift = (Short)args[0];
#define DO_MD
#define DO_MPPEM \
args[0] = CURRENT_Ppem();
#define DO_MPS \
args[0] = CUR.metrics.pointSize;
#define DO_DUP \
args[1] = args[0];
#define DO_CLEAR \
CUR.new_top = 0;
#define DO_SWAP \
{ \
Long L; \
\
L = args[0]; \
args[0] = args[1]; \
args[1] = L; \
}
#define DO_DEPTH \
args[0] = CUR.top;
#define DO_CINDEX \
{ \
Long L; \
\
\
L = args[0]; \
\
if ( L <= 0 || L > CUR.args ) \
CUR.error = TT_Err_Invalid_Reference; \
else \
args[0] = CUR.stack[CUR.args - L]; \
}
#define DO_JROT \
if ( args[1] != 0 ) \
{ \
CUR.IP += args[0]; \
CUR.step_ins = FALSE; \
}
#define DO_JMPR \
CUR.IP += args[0]; \
CUR.step_ins = FALSE;
#define DO_JROF \
if ( args[1] == 0 ) \
{ \
CUR.IP += args[0]; \
CUR.step_ins = FALSE; \
}
#define DO_LT \
args[0] = (args[0] < args[1]);
#define DO_LTEQ \
args[0] = (args[0] <= args[1]);
#define DO_GT \
args[0] = (args[0] > args[1]);
#define DO_GTEQ \
args[0] = (args[0] >= args[1]);
#define DO_EQ \
args[0] = (args[0] == args[1]);
#define DO_NEQ \
args[0] = (args[0] != args[1]);
#define DO_ODD \
args[0] = ( (CUR_Func_round( args[0], 0 ) & 127) == 64 );
#define DO_EVEN \
args[0] = ( (CUR_Func_round( args[0], 0 ) & 127) == 0 );
#define DO_AND \
args[0] = ( args[0] && args[1] );
#define DO_OR \
args[0] = ( args[0] || args[1] );
#define DO_NOT \
args[0] = !args[0];
#define DO_ADD \
args[0] += args[1];
#define DO_SUB \
args[0] -= args[1];
#define DO_DIV \
if ( args[1] == 0 ) \
CUR.error = TT_Err_Divide_By_Zero; \
else \
args[0] = TT_MulDiv( args[0], 64L, args[1] );
#define DO_MUL \
args[0] = TT_MulDiv( args[0], args[1], 64L );
#define DO_ABS \
args[0] = ABS( args[0] );
#define DO_NEG \
args[0] = -args[0];
#define DO_FLOOR \
args[0] &= -64;
#define DO_CEILING \
args[0] = (args[0] + 63) & (-64);
#define DO_RS \
{ \
ULong I = (ULong)args[0]; \
if ( BOUNDS( I, CUR.storeSize ) ) \
{ \
if ( CUR.pedantic_hinting ) \
{ \
ARRAY_BOUND_ERROR; \
} \
else \
args[0] = 0; \
} \
else \
args[0] = CUR.storage[I]; \
}
#define DO_WS \
{ \
ULong I = (ULong)args[0]; \
if ( BOUNDS( I, CUR.storeSize ) ) \
{ \
if ( CUR.pedantic_hinting ) \
{ \
ARRAY_BOUND_ERROR; \
} \
} \
else \
CUR.storage[I] = args[1]; \
}
#define DO_RCVT \
{ \
ULong I = (ULong)args[0]; \
if ( BOUNDS( I, CUR.cvtSize ) ) \
{ \
if ( CUR.pedantic_hinting ) \
{ \
ARRAY_BOUND_ERROR; \
} \
else \
args[0] = 0; \
} \
else \
args[0] = CUR_Func_read_cvt(I); \
}
#define DO_WCVTP \
{ \
ULong I = (ULong)args[0]; \
if ( BOUNDS( I, CUR.cvtSize ) ) \
{ \
if ( CUR.pedantic_hinting ) \
{ \
ARRAY_BOUND_ERROR; \
} \
} \
else \
CUR_Func_write_cvt( I, args[1] ); \
}
#define DO_WCVTF \
{ \
ULong I = (ULong)args[0]; \
if ( BOUNDS( I, CUR.cvtSize ) ) \
{ \
if ( CUR.pedantic_hinting ) \
{ \
ARRAY_BOUND_ERROR; \
} \
} \
else \
CUR.cvt[I] = FUnits_To_Pixels( EXEC_ARGS (Short)args[1] ); \
}
#define DO_DEBUG \
CUR.error = TT_Err_Debug_OpCode;
#define DO_ROUND \
args[0] = CUR_Func_round( args[0], \
CUR.metrics.compensations[CUR.opcode-0x68] );
#define DO_NROUND \
args[0] = Round_None( EXEC_ARGS \
args[0], \
CUR.metrics.compensations[CUR.opcode - 0x6C] );
#define DO_MAX \
if ( args[1] > args[0] ) \
args[0] = args[1];
#define DO_MIN \
if ( args[1] < args[0] ) \
args[0] = args[1];
#ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
#undef ARRAY_BOUND_ERROR
#define ARRAY_BOUND_ERROR \
{ \
CUR.error = TT_Err_Invalid_Reference; \
return; \
}
static void Ins_SVTCA( INS_ARG )
{
DO_SVTCA
}
static void Ins_SPVTCA( INS_ARG )
{
DO_SPVTCA
}
static void Ins_SFVTCA( INS_ARG )
{
DO_SFVTCA
}
static void Ins_SPVTL( INS_ARG )
{
DO_SPVTL
}
static void Ins_SFVTL( INS_ARG )
{
DO_SFVTL
}
static void Ins_SFVTPV( INS_ARG )
{
DO_SFVTPV
}
static void Ins_SPVFS( INS_ARG )
{
DO_SPVFS
}
static void Ins_SFVFS( INS_ARG )
{
DO_SFVFS
}
static void Ins_GPV( INS_ARG )
{
DO_GPV
}
static void Ins_GFV( INS_ARG )
{
DO_GFV
}
static void Ins_SRP0( INS_ARG )
{
DO_SRP0
}
static void Ins_SRP1( INS_ARG )
{
DO_SRP1
}
static void Ins_SRP2( INS_ARG )
{
DO_SRP2
}
static void Ins_RTHG( INS_ARG )
{
DO_RTHG
}
static void Ins_RTG( INS_ARG )
{
DO_RTG
}
static void Ins_RTDG( INS_ARG )
{
DO_RTDG
}
static void Ins_RUTG( INS_ARG )
{
DO_RUTG
}
static void Ins_RDTG( INS_ARG )
{
DO_RDTG
}
static void Ins_ROFF( INS_ARG )
{
DO_ROFF
}
static void Ins_SROUND( INS_ARG )
{
DO_SROUND
}
static void Ins_S45ROUND( INS_ARG )
{
DO_S45ROUND
}
static void Ins_SLOOP( INS_ARG )
{
DO_SLOOP
}
static void Ins_SMD( INS_ARG )
{
DO_SMD
}
static void Ins_SCVTCI( INS_ARG )
{
DO_SCVTCI
}
static void Ins_SSWCI( INS_ARG )
{
DO_SSWCI
}
static void Ins_SSW( INS_ARG )
{
DO_SSW
}
static void Ins_FLIPON( INS_ARG )
{
DO_FLIPON
}
static void Ins_FLIPOFF( INS_ARG )
{
DO_FLIPOFF
}
static void Ins_SANGW( INS_ARG )
{
}
static void Ins_SDB( INS_ARG )
{
DO_SDB
}
static void Ins_SDS( INS_ARG )
{
DO_SDS
}
static void Ins_MPPEM( INS_ARG )
{
DO_MPPEM
}
static void Ins_MPS( INS_ARG )
{
DO_MPS
}
static void Ins_DUP( INS_ARG )
{
DO_DUP
}
static void Ins_POP( INS_ARG )
{
}
static void Ins_CLEAR( INS_ARG )
{
DO_CLEAR
}
static void Ins_SWAP( INS_ARG )
{
DO_SWAP
}
static void Ins_DEPTH( INS_ARG )
{
DO_DEPTH
}
static void Ins_CINDEX( INS_ARG )
{
DO_CINDEX
}
static void Ins_EIF( INS_ARG )
{
}
static void Ins_JROT( INS_ARG )
{
DO_JROT
}
static void Ins_JMPR( INS_ARG )
{
DO_JMPR
}
static void Ins_JROF( INS_ARG )
{
DO_JROF
}
static void Ins_LT( INS_ARG )
{
DO_LT
}
static void Ins_LTEQ( INS_ARG )
{
DO_LTEQ
}
static void Ins_GT( INS_ARG )
{
DO_GT
}
static void Ins_GTEQ( INS_ARG )
{
DO_GTEQ
}
static void Ins_EQ( INS_ARG )
{
DO_EQ
}
static void Ins_NEQ( INS_ARG )
{
DO_NEQ
}
static void Ins_ODD( INS_ARG )
{
DO_ODD
}
static void Ins_EVEN( INS_ARG )
{
DO_EVEN
}
static void Ins_AND( INS_ARG )
{
DO_AND
}
static void Ins_OR( INS_ARG )
{
DO_OR
}
static void Ins_NOT( INS_ARG )
{
DO_NOT
}
static void Ins_ADD( INS_ARG )
{
DO_ADD
}
static void Ins_SUB( INS_ARG )
{
DO_SUB
}
static void Ins_DIV( INS_ARG )
{
DO_DIV
}
static void Ins_MUL( INS_ARG )
{
DO_MUL
}
static void Ins_ABS( INS_ARG )
{
DO_ABS
}
static void Ins_NEG( INS_ARG )
{
DO_NEG
}
static void Ins_FLOOR( INS_ARG )
{
DO_FLOOR
}
static void Ins_CEILING( INS_ARG )
{
DO_CEILING
}
static void Ins_RS( INS_ARG )
{
DO_RS
}
static void Ins_WS( INS_ARG )
{
DO_WS
}
static void Ins_WCVTP( INS_ARG )
{
DO_WCVTP
}
static void Ins_WCVTF( INS_ARG )
{
DO_WCVTF
}
static void Ins_RCVT( INS_ARG )
{
DO_RCVT
}
static void Ins_AA( INS_ARG )
{
}
static void Ins_DEBUG( INS_ARG )
{
DO_DEBUG
}
static void Ins_ROUND( INS_ARG )
{
DO_ROUND
}
static void Ins_NROUND( INS_ARG )
{
DO_NROUND
}
static void Ins_MAX( INS_ARG )
{
DO_MAX
}
static void Ins_MIN( INS_ARG )
{
DO_MIN
}
#endif
static void Ins_MINDEX( INS_ARG )
{
Long L, K;
L = args[0];
if ( L <= 0 || L > CUR.args )
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
K = CUR.stack[CUR.args - L];
MEM_Move( (&CUR.stack[CUR.args - L ]),
(&CUR.stack[CUR.args - L + 1]),
(L - 1) * sizeof ( Long ) );
CUR.stack[CUR.args - 1] = K;
}
static void Ins_ROLL( INS_ARG )
{
Long A, B, C;
A = args[2];
B = args[1];
C = args[0];
args[2] = C;
args[1] = A;
args[0] = B;
}
static Bool SkipCode( EXEC_OP )
{
CUR.IP += CUR.length;
if ( CUR.IP < CUR.codeSize )
if ( CALC_Length() == SUCCESS )
return SUCCESS;
CUR.error = TT_Err_Code_Overflow;
return FAILURE;
}
static void Ins_IF( INS_ARG )
{
Int nIfs;
Bool Out;
if ( args[0] != 0 )
return;
nIfs = 1;
Out = 0;
do
{
if ( SKIP_Code() == FAILURE )
return;
switch ( CUR.opcode )
{
case 0x58:
nIfs++;
break;
case 0x1b:
Out = (nIfs == 1);
break;
case 0x59:
nIfs--;
Out = (nIfs == 0);
break;
}
} while ( Out == 0 );
}
static void Ins_ELSE( INS_ARG )
{
Int nIfs;
nIfs = 1;
do
{
if ( SKIP_Code() == FAILURE )
return;
switch ( CUR.opcode )
{
case 0x58:
nIfs++;
break;
case 0x59:
nIfs--;
break;
}
} while ( nIfs != 0 );
}
static PDefRecord Locate_FDef( EXEC_OPS Int n, Bool new_def )
{
PDefRecord def;
UShort hash;
UShort cnt;
if ( !new_def && ( n < 0 || n > CUR.maxFunc ) )
return NULL;
for ( cnt = 0; cnt < CUR.maxFDefs; ++cnt )
{
hash = ( (UShort)n + cnt ) % CUR.maxFDefs;
def = &CUR.FDefs[ hash ];
if ( !def->Active )
return new_def ? def : NULL;
if ( def->Opc == n )
return def;
}
return NULL;
}
static void Ins_FDEF( INS_ARG )
{
Int n;
PDefRecord def;
if ( CUR.numFDefs >= CUR.maxFDefs )
{
CUR.error = TT_Err_Too_Many_Ins;
return;
}
n = (Int)args[0];
if ( n < 0 || (ULong)n != args[0] )
{
CUR.error = TT_Err_Bad_Argument;
return;
}
def = Locate_FDef( EXEC_ARGS n, TRUE );
if ( !def )
{
CUR.error = TT_Err_Too_Many_Ins;
return;
}
if ( !def->Active )
CUR.numFDefs++;
def->Range = CUR.curRange;
def->Opc = n;
def->Start = CUR.IP + 1;
def->Active = TRUE;
if ( n > CUR.maxFunc )
CUR.maxFunc = n;
while ( SKIP_Code() == SUCCESS )
{
switch ( CUR.opcode )
{
case 0x89:
case 0x2c:
CUR.error = TT_Err_Nested_DEFS;
return;
case 0x2d:
return;
}
}
}
static void Ins_ENDF( INS_ARG )
{
PCallRecord pRec;
if ( CUR.callTop <= 0 )
{
CUR.error = TT_Err_ENDF_In_Exec_Stream;
return;
}
CUR.callTop--;
pRec = &CUR.callStack[CUR.callTop];
pRec->Cur_Count--;
CUR.step_ins = FALSE;
if ( pRec->Cur_Count > 0 )
{
CUR.callTop++;
CUR.IP = pRec->Cur_Restart;
}
else
INS_Goto_CodeRange( pRec->Caller_Range,
pRec->Caller_IP );
}
static void Ins_CALL( INS_ARG )
{
Int n;
PDefRecord def;
PCallRecord pCrec;
n = (Int)args[0];
def = Locate_FDef( EXEC_ARGS n, FALSE );
if ( !def )
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
if ( CUR.callTop >= CUR.callSize )
{
CUR.error = TT_Err_Stack_Overflow;
return;
}
pCrec = CUR.callStack + CUR.callTop;
pCrec->Caller_Range = CUR.curRange;
pCrec->Caller_IP = CUR.IP + 1;
pCrec->Cur_Count = 1;
pCrec->Cur_Restart = def->Start;
CUR.callTop++;
INS_Goto_CodeRange( def->Range,
def->Start );
CUR.step_ins = FALSE;
}
static void Ins_LOOPCALL( INS_ARG )
{
Int n;
Long count;
PDefRecord def;
PCallRecord pTCR;
n = (Int)args[1];
def = Locate_FDef( EXEC_ARGS n, FALSE );
if ( !def )
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
if ( CUR.callTop >= CUR.callSize )
{
CUR.error = TT_Err_Stack_Overflow;
return;
}
count = (Long)args[0];
if ( count <= 0 )
return;
pTCR = &CUR.callStack[CUR.callTop];
pTCR->Caller_Range = CUR.curRange;
pTCR->Caller_IP = CUR.IP + 1;
pTCR->Cur_Count = count;
pTCR->Cur_Restart = def->Start;
CUR.callTop++;
INS_Goto_CodeRange( def->Range,
def->Start );
CUR.step_ins = FALSE;
}
static void Ins_IDEF( INS_ARG )
{
Byte opcode;
PDefRecord def;
PDefRecord limit;
opcode = (Byte)args[0];
def = CUR.IDefs;
limit = def + CUR.numIDefs;
for ( ; def < limit; def++ )
if ( def->Opc == opcode )
break;
if ( def == limit )
{
if ( CUR.numIDefs >= CUR.maxIDefs )
{
CUR.error = TT_Err_Too_Many_Ins;
return;
}
CUR.numIDefs++;
}
def->Opc = opcode;
def->Start = CUR.IP + 1;
def->Range = CUR.curRange;
def->Active = TRUE;
if ( opcode > CUR.maxIns )
CUR.maxIns = opcode;
while ( SKIP_Code() == SUCCESS )
{
switch ( CUR.opcode )
{
case 0x89:
case 0x2c:
CUR.error = TT_Err_Nested_DEFS;
return;
case 0x2d:
return;
}
}
}
static void Ins_NPUSHB( INS_ARG )
{
UShort L, K;
L = (UShort)CUR.code[CUR.IP + 1];
if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
{
CUR.error = TT_Err_Stack_Overflow;
return;
}
for ( K = 1; K <= L; K++ )
args[K - 1] = CUR.code[CUR.IP + K + 1];
CUR.new_top += L;
}
static void Ins_NPUSHW( INS_ARG )
{
UShort L, K;
L = (UShort)CUR.code[CUR.IP + 1];
if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
{
CUR.error = TT_Err_Stack_Overflow;
return;
}
CUR.IP += 2;
for ( K = 0; K < L; K++ )
args[K] = GET_ShortIns();
CUR.step_ins = FALSE;
CUR.new_top += L;
}
static void Ins_PUSHB( INS_ARG )
{
UShort L, K;
L = (UShort)CUR.opcode - 0xB0 + 1;
if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
{
CUR.error = TT_Err_Stack_Overflow;
return;
}
for ( K = 1; K <= L; K++ )
args[K - 1] = CUR.code[CUR.IP + K];
}
static void Ins_PUSHW( INS_ARG )
{
UShort L, K;
L = (UShort)CUR.opcode - 0xB8 + 1;
if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
{
CUR.error = TT_Err_Stack_Overflow;
return;
}
CUR.IP++;
for ( K = 0; K < L; K++ )
args[K] = GET_ShortIns();
CUR.step_ins = FALSE;
}
static void Ins_GC( INS_ARG )
{
ULong L;
TT_F26Dot6 R;
L = (ULong)args[0];
if ( BOUNDS( L, CUR.zp2.n_points ) )
{
if ( CUR.pedantic_hinting )
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
else
R = 0;
}
else
{
if ( CUR.opcode & 1 )
R = CUR_Func_dualproj( CUR.zp2.org + L, NULL_Vector );
else
R = CUR_Func_project( CUR.zp2.cur + L, NULL_Vector );
}
args[0] = R;
}
static void Ins_SCFS( INS_ARG )
{
Long K;
UShort L;
L = (UShort)args[0];
if ( BOUNDS( L, CUR.zp2.n_points ) )
{
if ( CUR.pedantic_hinting )
CUR.error = TT_Err_Invalid_Reference;
return;
}
K = CUR_Func_project( CUR.zp2.cur + L, NULL_Vector );
CUR_Func_move( &CUR.zp2, L, args[1] - K );
if ( CUR.GS.gep2 == 0 )
CUR.zp2.org[L] = CUR.zp2.cur[L];
}
static void Ins_MD( INS_ARG )
{
UShort K, L;
TT_F26Dot6 D;
K = (UShort)args[1];
L = (UShort)args[0];
if( BOUNDS( L, CUR.zp0.n_points ) ||
BOUNDS( K, CUR.zp1.n_points ) )
{
if ( CUR.pedantic_hinting )
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
else
D = 0;
}
else
{
if ( CUR.opcode & 1 )
D = CUR_Func_project( CUR.zp0.cur + L, CUR.zp1.cur + K );
else
D = CUR_Func_dualproj( CUR.zp0.org + L, CUR.zp1.org + K );
}
args[0] = D;
}
static void Ins_SDPVTL( INS_ARG )
{
Long A, B, C;
UShort p1, p2;
p1 = (UShort)args[1];
p2 = (UShort)args[0];
if ( BOUNDS( p2, CUR.zp1.n_points ) ||
BOUNDS( p1, CUR.zp2.n_points ) )
{
if ( CUR.pedantic_hinting )
CUR.error = TT_Err_Invalid_Reference;
return;
}
{
TT_Vector* v1 = CUR.zp1.org + p2;
TT_Vector* v2 = CUR.zp2.org + p1;
A = v1->x - v2->x;
B = v1->y - v2->y;
}
if ( (CUR.opcode & 1) != 0 )
{
C = B;
B = A;
A = -C;
}
NORMalize( A, B, &CUR.GS.dualVector );
{
TT_Vector* v1 = CUR.zp1.cur + p2;
TT_Vector* v2 = CUR.zp2.cur + p1;
A = v1->x - v2->x;
B = v1->y - v2->y;
}
if ( (CUR.opcode & 1) != 0 )
{
C = B;
B = A;
A = -C;
}
NORMalize( A, B, &CUR.GS.projVector );
COMPUTE_Funcs();
}
static void Ins_SZP0( INS_ARG )
{
switch ( (Int)args[0] )
{
case 0:
CUR.zp0 = CUR.twilight;
break;
case 1:
CUR.zp0 = CUR.pts;
break;
default:
if ( CUR.pedantic_hinting )
CUR.error = TT_Err_Invalid_Reference;
return;
}
CUR.GS.gep0 = (UShort)args[0];
}
static void Ins_SZP1( INS_ARG )
{
switch ( (Int)args[0] )
{
case 0:
CUR.zp1 = CUR.twilight;
break;
case 1:
CUR.zp1 = CUR.pts;
break;
default:
if ( CUR.pedantic_hinting )
CUR.error = TT_Err_Invalid_Reference;
return;
}
CUR.GS.gep1 = (UShort)args[0];
}
static void Ins_SZP2( INS_ARG )
{
switch ( (Int)args[0] )
{
case 0:
CUR.zp2 = CUR.twilight;
break;
case 1:
CUR.zp2 = CUR.pts;
break;
default:
if ( CUR.pedantic_hinting )
CUR.error = TT_Err_Invalid_Reference;
return;
}
CUR.GS.gep2 = (UShort)args[0];
}
static void Ins_SZPS( INS_ARG )
{
switch ( (Int)args[0] )
{
case 0:
CUR.zp0 = CUR.twilight;
break;
case 1:
CUR.zp0 = CUR.pts;
break;
default:
if ( CUR.pedantic_hinting )
CUR.error = TT_Err_Invalid_Reference;
return;
}
CUR.zp1 = CUR.zp0;
CUR.zp2 = CUR.zp0;
CUR.GS.gep0 = (UShort)args[0];
CUR.GS.gep1 = (UShort)args[0];
CUR.GS.gep2 = (UShort)args[0];
}
static void Ins_INSTCTRL( INS_ARG )
{
Long K, L;
K = args[1];
L = args[0];
if ( K < 1 || K > 2 )
{
if ( CUR.pedantic_hinting )
CUR.error = TT_Err_Invalid_Reference;
return;
}
if ( L != 0 )
L = K;
CUR.GS.instruct_control =
(Byte)( CUR.GS.instruct_control & ~(Byte)K ) | (Byte)L;
}
static void Ins_SCANCTRL( INS_ARG )
{
Int A;
A = (Int)(args[0] & 0xFF);
if ( A == 0xFF )
{
CUR.GS.scan_control = TRUE;
return;
}
else if ( A == 0 )
{
CUR.GS.scan_control = FALSE;
return;
}
A *= 64;
if ( (args[0] & 0x100) != 0 && CUR.metrics.pointSize <= A )
CUR.GS.scan_control = TRUE;
if ( (args[0] & 0x200) != 0 && CUR.metrics.rotated )
CUR.GS.scan_control = TRUE;
if ( (args[0] & 0x400) != 0 && CUR.metrics.stretched )
CUR.GS.scan_control = TRUE;
if ( (args[0] & 0x800) != 0 && CUR.metrics.pointSize > A )
CUR.GS.scan_control = FALSE;
if ( (args[0] & 0x1000) != 0 && CUR.metrics.rotated )
CUR.GS.scan_control = FALSE;
if ( (args[0] & 0x2000) != 0 && CUR.metrics.stretched )
CUR.GS.scan_control = FALSE;
}
static void Ins_SCANTYPE( INS_ARG )
{
if ( args[0] >= 0 && args[0] <= 5 )
{
if ( args[0] == 3 )
args[0] = 2;
CUR.GS.scan_type = (Int)args[0];
}
}
static void Ins_FLIPPT( INS_ARG )
{
UShort point;
if ( CUR.top < CUR.GS.loop )
{
CUR.error = TT_Err_Too_Few_Arguments;
return;
}
while ( CUR.GS.loop > 0 )
{
CUR.args--;
point = (UShort)CUR.stack[CUR.args];
if ( BOUNDS( point, CUR.pts.n_points ) )
{
if ( CUR.pedantic_hinting )
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
}
else
CUR.pts.touch[point] ^= TT_Flag_On_Curve;
CUR.GS.loop--;
}
CUR.GS.loop = 1;
CUR.new_top = CUR.args;
}
static void Ins_FLIPRGON( INS_ARG )
{
UShort I, K, L;
K = (UShort)args[1];
L = (UShort)args[0];
if ( BOUNDS( K, CUR.pts.n_points ) ||
BOUNDS( L, CUR.pts.n_points ) )
{
if ( CUR.pedantic_hinting )
CUR.error = TT_Err_Invalid_Reference;
return;
}
for ( I = L; I <= K; I++ )
CUR.pts.touch[I] |= TT_Flag_On_Curve;
}
static void Ins_FLIPRGOFF( INS_ARG )
{
UShort I, K, L;
K = (UShort)args[1];
L = (UShort)args[0];
if ( BOUNDS( K, CUR.pts.n_points ) ||
BOUNDS( L, CUR.pts.n_points ) )
{
if ( CUR.pedantic_hinting )
CUR.error = TT_Err_Invalid_Reference;
return;
}
for ( I = L; I <= K; I++ )
CUR.pts.touch[I] &= ~TT_Flag_On_Curve;
}
static Bool Compute_Point_Displacement( EXEC_OPS
PCoordinates x,
PCoordinates y,
PGlyph_Zone zone,
UShort* refp )
{
TGlyph_Zone zp;
UShort p;
TT_F26Dot6 d;
if ( CUR.opcode & 1 )
{
zp = CUR.zp0;
p = CUR.GS.rp1;
}
else
{
zp = CUR.zp1;
p = CUR.GS.rp2;
}
if ( BOUNDS( p, zp.n_points ) )
{
if ( CUR.pedantic_hinting )
CUR.error = TT_Err_Invalid_Displacement;
return FAILURE;
}
*zone = zp;
*refp = p;
d = CUR_Func_project( zp.cur + p, zp.org + p );
*x = TT_MulDiv(d, (Long)CUR.GS.freeVector.x * 0x10000L, CUR.F_dot_P );
*y = TT_MulDiv(d, (Long)CUR.GS.freeVector.y * 0x10000L, CUR.F_dot_P );
return SUCCESS;
}
static void Move_Zp2_Point( EXEC_OPS
UShort point,
TT_F26Dot6 dx,
TT_F26Dot6 dy,
Bool touch )
{
if ( CUR.GS.freeVector.x != 0 )
{
CUR.zp2.cur[point].x += dx;
if ( touch )
CUR.zp2.touch[point] |= TT_Flag_Touched_X;
}
if ( CUR.GS.freeVector.y != 0 )
{
CUR.zp2.cur[point].y += dy;
if ( touch )
CUR.zp2.touch[point] |= TT_Flag_Touched_Y;
}
}
static void Ins_SHP( INS_ARG )
{
TGlyph_Zone zp;
UShort refp;
TT_F26Dot6 dx,
dy;
UShort point;
if ( CUR.top < CUR.GS.loop )
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
return;
while ( CUR.GS.loop > 0 )
{
CUR.args--;
point = (UShort)CUR.stack[CUR.args];
if ( BOUNDS( point, CUR.zp2.n_points ) )
{
if ( CUR.pedantic_hinting )
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
}
else
MOVE_Zp2_Point( point, dx, dy, TRUE );
CUR.GS.loop--;
}
CUR.GS.loop = 1;
CUR.new_top = CUR.args;
}
static void Ins_SHC( INS_ARG )
{
TGlyph_Zone zp;
UShort refp;
TT_F26Dot6 dx,
dy;
Short contour;
UShort first_point, last_point, i;
contour = (UShort)args[0];
if ( BOUNDS( contour, CUR.pts.n_contours ) )
{
if ( CUR.pedantic_hinting )
CUR.error = TT_Err_Invalid_Reference;
return;
}
if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
return;
if ( contour == 0 )
first_point = 0;
else
first_point = CUR.pts.contours[contour - 1] + 1;
last_point = CUR.pts.contours[contour];
if ( last_point > CUR.zp2.n_points )
{
if ( CUR.zp2.n_points > 0 )
last_point = CUR.zp2.n_points - 1;
else
last_point = 0;
}
for ( i = first_point; i <= last_point; i++ )
{
if ( zp.cur != CUR.zp2.cur || refp != i )
MOVE_Zp2_Point( i, dx, dy, FALSE );
}
}
static void Ins_SHZ( INS_ARG )
{
TGlyph_Zone zp;
UShort refp;
TT_F26Dot6 dx,
dy;
UShort last_point, i;
if ( BOUNDS( args[0], 2 ) )
{
if ( CUR.pedantic_hinting )
CUR.error = TT_Err_Invalid_Reference;
return;
}
if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
return;
if ( CUR.zp2.n_points > 0 )
last_point = CUR.zp2.n_points - 1;
else
last_point = 0;
for ( i = 0; i <= last_point; i++ )
{
if ( zp.cur != CUR.zp2.cur || refp != i )
MOVE_Zp2_Point( i, dx, dy, FALSE );
}
}
static void Ins_SHPIX( INS_ARG )
{
TT_F26Dot6 dx, dy;
UShort point;
if ( CUR.top < CUR.GS.loop + 1 )
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
dx = TT_MulDiv( args[0],
(Long)CUR.GS.freeVector.x,
0x4000 );
dy = TT_MulDiv( args[0],
(Long)CUR.GS.freeVector.y,
0x4000 );
while ( CUR.GS.loop > 0 )
{
CUR.args--;
point = (UShort)CUR.stack[CUR.args];
if ( BOUNDS( point, CUR.zp2.n_points ) )
{
if ( CUR.pedantic_hinting )
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
}
else
MOVE_Zp2_Point( point, dx, dy, TRUE );
CUR.GS.loop--;
}
CUR.GS.loop = 1;
CUR.new_top = CUR.args;
}
static void Ins_MSIRP( INS_ARG )
{
UShort point;
TT_F26Dot6 distance;
point = (UShort)args[0];
if ( BOUNDS( point, CUR.zp1.n_points ) ||
BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
{
if ( CUR.pedantic_hinting )
CUR.error = TT_Err_Invalid_Reference;
return;
}
if ( CUR.GS.gep0 == 0 )
{
CUR.zp1.org[point] = CUR.zp0.org[CUR.GS.rp0];
CUR.zp1.cur[point] = CUR.zp1.org[point];
}
distance = CUR_Func_project( CUR.zp1.cur + point,
CUR.zp0.cur + CUR.GS.rp0 );
CUR_Func_move( &CUR.zp1, point, args[1] - distance );
CUR.GS.rp1 = CUR.GS.rp0;
CUR.GS.rp2 = point;
if ( (CUR.opcode & 1) != 0 )
CUR.GS.rp0 = point;
}
static void Ins_MDAP( INS_ARG )
{
UShort point;
TT_F26Dot6 cur_dist,
distance;
point = (UShort)args[0];
if ( BOUNDS( point, CUR.zp0.n_points ) )
{
if ( CUR.pedantic_hinting )
CUR.error = TT_Err_Invalid_Reference;
return;
}
if ( (CUR.opcode & 1) != 0 )
{
cur_dist = CUR_Func_project( CUR.zp0.cur + point, NULL_Vector );
distance = CUR_Func_round( cur_dist,
CUR.metrics.compensations[0] ) - cur_dist;
}
else
distance = 0;
CUR_Func_move( &CUR.zp0, point, distance );
CUR.GS.rp0 = point;
CUR.GS.rp1 = point;
}
static void Ins_MIAP( INS_ARG )
{
ULong cvtEntry;
UShort point;
TT_F26Dot6 distance,
org_dist;
cvtEntry = (ULong)args[1];
point = (UShort)args[0];
if ( BOUNDS( point, CUR.zp0.n_points ) ||
BOUNDS( cvtEntry, CUR.cvtSize ) )
{
if ( CUR.pedantic_hinting )
CUR.error = TT_Err_Invalid_Reference;
return;
}
distance = CUR_Func_read_cvt( cvtEntry );
if ( CUR.GS.gep0 == 0 )
{
CUR.zp0.org[point].x = TT_MulDiv( CUR.GS.freeVector.x,
distance, 0x4000L );
CUR.zp0.org[point].y = TT_MulDiv( CUR.GS.freeVector.y,
distance, 0x4000L );
CUR.zp0.cur[point] = CUR.zp0.org[point];
}
org_dist = CUR_Func_project( CUR.zp0.cur + point, NULL_Vector );
if ( (CUR.opcode & 1) != 0 )
{
if ( ABS( distance - org_dist ) > CUR.GS.control_value_cutin )
distance = org_dist;
distance = CUR_Func_round( distance, CUR.metrics.compensations[0] );
}
CUR_Func_move( &CUR.zp0, point, distance - org_dist );
CUR.GS.rp0 = point;
CUR.GS.rp1 = point;
}
static void Ins_MDRP( INS_ARG )
{
UShort point;
TT_F26Dot6 org_dist, distance;
point = (UShort)args[0];
if ( BOUNDS( point, CUR.zp1.n_points ) ||
BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
{
if ( CUR.pedantic_hinting )
CUR.error = TT_Err_Invalid_Reference;
return;
}
org_dist = CUR_Func_dualproj( CUR.zp1.org + point,
CUR.zp0.org + CUR.GS.rp0 );
if ( ABS( org_dist ) < CUR.GS.single_width_cutin )
{
if ( org_dist >= 0 )
org_dist = CUR.GS.single_width_value;
else
org_dist = -CUR.GS.single_width_value;
}
if ( (CUR.opcode & 4) != 0 )
distance = CUR_Func_round( org_dist,
CUR.metrics.compensations[CUR.opcode & 3] );
else
distance = Round_None( EXEC_ARGS
org_dist,
CUR.metrics.compensations[CUR.opcode & 3] );
if ( (CUR.opcode & 8) != 0 )
{
if ( org_dist >= 0 )
{
if ( distance < CUR.GS.minimum_distance )
distance = CUR.GS.minimum_distance;
}
else
{
if ( distance > -CUR.GS.minimum_distance )
distance = -CUR.GS.minimum_distance;
}
}
org_dist = CUR_Func_project( CUR.zp1.cur + point,
CUR.zp0.cur + CUR.GS.rp0 );
CUR_Func_move( &CUR.zp1, point, distance - org_dist );
CUR.GS.rp1 = CUR.GS.rp0;
CUR.GS.rp2 = point;
if ( (CUR.opcode & 16) != 0 )
CUR.GS.rp0 = point;
}
static void Ins_MIRP( INS_ARG )
{
UShort point;
ULong cvtEntry;
TT_F26Dot6 cvt_dist,
distance,
cur_dist,
org_dist;
point = (UShort)args[0];
cvtEntry = (ULong)(args[1] + 1);
if ( BOUNDS( point, CUR.zp1.n_points ) ||
BOUNDS( cvtEntry, CUR.cvtSize + 1 ) ||
BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
{
if ( CUR.pedantic_hinting )
CUR.error = TT_Err_Invalid_Reference;
return;
}
if ( !cvtEntry )
cvt_dist = 0;
else
cvt_dist = CUR_Func_read_cvt( cvtEntry - 1 );
if ( ABS( cvt_dist ) < CUR.GS.single_width_cutin )
{
if ( cvt_dist >= 0 )
cvt_dist = CUR.GS.single_width_value;
else
cvt_dist = -CUR.GS.single_width_value;
}
if ( CUR.GS.gep1 == 0 )
{
CUR.zp1.org[point].x = CUR.zp0.org[CUR.GS.rp0].x +
TT_MulDiv( cvt_dist,
CUR.GS.freeVector.x,
0x4000 );
CUR.zp1.org[point].y = CUR.zp0.org[CUR.GS.rp0].y +
TT_MulDiv( cvt_dist,
CUR.GS.freeVector.y,
0x4000 );
CUR.zp1.cur[point] = CUR.zp1.org[point];
}
org_dist = CUR_Func_dualproj( CUR.zp1.org + point,
CUR.zp0.org + CUR.GS.rp0 );
cur_dist = CUR_Func_project( CUR.zp1.cur + point,
CUR.zp0.cur + CUR.GS.rp0 );
if ( CUR.GS.auto_flip )
{
if ( (org_dist ^ cvt_dist) < 0 )
cvt_dist = -cvt_dist;
}
if ( (CUR.opcode & 4) != 0 )
{
if ( CUR.GS.gep0 == CUR.GS.gep1 )
if ( ABS( cvt_dist - org_dist ) >= CUR.GS.control_value_cutin )
cvt_dist = org_dist;
distance = CUR_Func_round( cvt_dist,
CUR.metrics.compensations[CUR.opcode & 3] );
}
else
distance = Round_None( EXEC_ARGS
cvt_dist,
CUR.metrics.compensations[CUR.opcode & 3] );
if ( (CUR.opcode & 8) != 0 )
{
if ( org_dist >= 0 )
{
if ( distance < CUR.GS.minimum_distance )
distance = CUR.GS.minimum_distance;
}
else
{
if ( distance > -CUR.GS.minimum_distance )
distance = -CUR.GS.minimum_distance;
}
}
CUR_Func_move( &CUR.zp1, point, distance - cur_dist );
CUR.GS.rp1 = CUR.GS.rp0;
if ( (CUR.opcode & 16) != 0 )
CUR.GS.rp0 = point;
CUR.GS.rp2 = point;
}
static void Ins_ALIGNRP( INS_ARG )
{
UShort point;
TT_F26Dot6 distance;
if ( CUR.top < CUR.GS.loop ||
BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
{
if ( CUR.pedantic_hinting )
CUR.error = TT_Err_Invalid_Reference;
return;
}
while ( CUR.GS.loop > 0 )
{
CUR.args--;
point = (UShort)CUR.stack[CUR.args];
if ( BOUNDS( point, CUR.zp1.n_points ) )
{
if ( CUR.pedantic_hinting )
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
}
else
{
distance = CUR_Func_project( CUR.zp1.cur + point,
CUR.zp0.cur + CUR.GS.rp0 );
CUR_Func_move( &CUR.zp1, point, -distance );
}
CUR.GS.loop--;
}
CUR.GS.loop = 1;
CUR.new_top = CUR.args;
}
static void Ins_ISECT( INS_ARG )
{
UShort point,
a0, a1,
b0, b1;
TT_F26Dot6 discriminant;
TT_F26Dot6 dx, dy,
dax, day,
dbx, dby;
TT_F26Dot6 val;
TT_Vector R;
point = (UShort)args[0];
a0 = (UShort)args[1];
a1 = (UShort)args[2];
b0 = (UShort)args[3];
b1 = (UShort)args[4];
if ( BOUNDS( b0, CUR.zp0.n_points ) ||
BOUNDS( b1, CUR.zp0.n_points ) ||
BOUNDS( a0, CUR.zp1.n_points ) ||
BOUNDS( a1, CUR.zp1.n_points ) ||
BOUNDS( point, CUR.zp2.n_points ) )
{
if ( CUR.pedantic_hinting )
CUR.error = TT_Err_Invalid_Reference;
return;
}
dbx = CUR.zp0.cur[b1].x - CUR.zp0.cur[b0].x;
dby = CUR.zp0.cur[b1].y - CUR.zp0.cur[b0].y;
dax = CUR.zp1.cur[a1].x - CUR.zp1.cur[a0].x;
day = CUR.zp1.cur[a1].y - CUR.zp1.cur[a0].y;
dx = CUR.zp0.cur[b0].x - CUR.zp1.cur[a0].x;
dy = CUR.zp0.cur[b0].y - CUR.zp1.cur[a0].y;
CUR.zp2.touch[point] |= TT_Flag_Touched_Both;
discriminant = TT_MulDiv( dax, -dby, 0x40L ) +
TT_MulDiv( day, dbx, 0x40L );
if ( ABS( discriminant ) >= 0x40 )
{
val = TT_MulDiv( dx, -dby, 0x40L ) + TT_MulDiv( dy, dbx, 0x40L );
R.x = TT_MulDiv( val, dax, discriminant );
R.y = TT_MulDiv( val, day, discriminant );
CUR.zp2.cur[point].x = CUR.zp1.cur[a0].x + R.x;
CUR.zp2.cur[point].y = CUR.zp1.cur[a0].y + R.y;
}
else
{
CUR.zp2.cur[point].x = ( CUR.zp1.cur[a0].x +
CUR.zp1.cur[a1].x +
CUR.zp0.cur[b0].x +
CUR.zp0.cur[b1].x ) / 4;
CUR.zp2.cur[point].y = ( CUR.zp1.cur[a0].y +
CUR.zp1.cur[a1].y +
CUR.zp0.cur[b0].y +
CUR.zp0.cur[b1].y ) / 4;
}
}
static void Ins_ALIGNPTS( INS_ARG )
{
UShort p1, p2;
TT_F26Dot6 distance;
p1 = (UShort)args[0];
p2 = (UShort)args[1];
if ( BOUNDS( args[0], CUR.zp1.n_points ) ||
BOUNDS( args[1], CUR.zp0.n_points ) )
{
if ( CUR.pedantic_hinting )
CUR.error = TT_Err_Invalid_Reference;
return;
}
distance = CUR_Func_project( CUR.zp0.cur + p2,
CUR.zp1.cur + p1 ) / 2;
CUR_Func_move( &CUR.zp1, p1, distance );
CUR_Func_move( &CUR.zp0, p2, -distance );
}
static void Ins_IP( INS_ARG )
{
TT_F26Dot6 org_a, org_b, org_x,
cur_a, cur_b, cur_x,
distance;
UShort point;
if ( CUR.top < CUR.GS.loop )
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) ||
BOUNDS( CUR.GS.rp2, CUR.zp1.n_points ) )
{
org_a = cur_a = 0;
org_b = cur_b = 0;
}
else
{
org_a = CUR_Func_dualproj( CUR.zp0.org + CUR.GS.rp1, NULL_Vector );
org_b = CUR_Func_dualproj( CUR.zp1.org + CUR.GS.rp2, NULL_Vector );
cur_a = CUR_Func_project( CUR.zp0.cur + CUR.GS.rp1, NULL_Vector );
cur_b = CUR_Func_project( CUR.zp1.cur + CUR.GS.rp2, NULL_Vector );
}
while ( CUR.GS.loop > 0 )
{
CUR.args--;
point = (UShort)CUR.stack[CUR.args];
if ( BOUNDS( point, CUR.zp2.n_points ) )
{
if ( CUR.pedantic_hinting )
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
}
else
{
org_x = CUR_Func_dualproj( CUR.zp2.org + point, NULL_Vector );
cur_x = CUR_Func_project ( CUR.zp2.cur + point, NULL_Vector );
if ( ( org_a <= org_b && org_x <= org_a ) ||
( org_a > org_b && org_x >= org_a ) )
distance = ( cur_a - org_a ) + ( org_x - cur_x );
else if ( ( org_a <= org_b && org_x >= org_b ) ||
( org_a > org_b && org_x < org_b ) )
distance = ( cur_b - org_b ) + ( org_x - cur_x );
else
distance = TT_MulDiv( cur_b - cur_a,
org_x - org_a,
org_b - org_a ) + ( cur_a - cur_x );
CUR_Func_move( &CUR.zp2, point, distance );
}
CUR.GS.loop--;
}
CUR.GS.loop = 1;
CUR.new_top = CUR.args;
}
static void Ins_UTP( INS_ARG )
{
UShort point;
Byte mask;
point = (UShort)args[0];
if ( BOUNDS( point, CUR.zp0.n_points ) )
{
if ( CUR.pedantic_hinting )
CUR.error = TT_Err_Invalid_Reference;
return;
}
mask = 0xFF;
if ( CUR.GS.freeVector.x != 0 )
mask &= ~TT_Flag_Touched_X;
if ( CUR.GS.freeVector.y != 0 )
mask &= ~TT_Flag_Touched_Y;
CUR.zp0.touch[point] &= mask;
}
struct LOC_Ins_IUP
{
TT_Vector* orgs;
TT_Vector* curs;
};
static void Shift( UShort p1,
UShort p2,
UShort p,
struct LOC_Ins_IUP* LINK )
{
UShort i;
TT_F26Dot6 x;
x = LINK->curs[p].x - LINK->orgs[p].x;
for ( i = p1; i < p; i++ )
LINK->curs[i].x += x;
for ( i = p + 1; i <= p2; i++ )
LINK->curs[i].x += x;
}
static void Interp( UShort p1,
UShort p2,
UShort ref1,
UShort ref2,
struct LOC_Ins_IUP* LINK )
{
UShort i;
TT_F26Dot6 x, x1, x2, d1, d2;
if ( p1 > p2 )
return;
x1 = LINK->orgs[ref1].x;
d1 = LINK->curs[ref1].x - LINK->orgs[ref1].x;
x2 = LINK->orgs[ref2].x;
d2 = LINK->curs[ref2].x - LINK->orgs[ref2].x;
if ( x1 == x2 )
{
for ( i = p1; i <= p2; i++ )
{
x = LINK->orgs[i].x;
if ( x <= x1 )
x += d1;
else
x += d2;
LINK->curs[i].x = x;
}
return;
}
if ( x1 < x2 )
{
for ( i = p1; i <= p2; i++ )
{
x = LINK->orgs[i].x;
if ( x <= x1 )
x += d1;
else
{
if ( x >= x2 )
x += d2;
else
x = LINK->curs[ref1].x +
TT_MulDiv( x - x1,
LINK->curs[ref2].x - LINK->curs[ref1].x,
x2 - x1 );
}
LINK->curs[i].x = x;
}
return;
}
for ( i = p1; i <= p2; i++ )
{
x = LINK->orgs[i].x;
if ( x <= x2 )
x += d2;
else
{
if ( x >= x1 )
x += d1;
else
x = LINK->curs[ref1].x +
TT_MulDiv( x - x1,
LINK->curs[ref2].x - LINK->curs[ref1].x,
x2 - x1 );
}
LINK->curs[i].x = x;
}
}
static void Ins_IUP( INS_ARG )
{
struct LOC_Ins_IUP V;
Byte mask;
UShort first_point;
UShort end_point;
UShort first_touched;
UShort cur_touched;
UShort point;
Short contour;
if ( CUR.opcode & 1 )
{
mask = TT_Flag_Touched_X;
V.orgs = CUR.pts.org;
V.curs = CUR.pts.cur;
}
else
{
mask = TT_Flag_Touched_Y;
V.orgs = (TT_Vector*)( ((TT_F26Dot6*)CUR.pts.org) + 1 );
V.curs = (TT_Vector*)( ((TT_F26Dot6*)CUR.pts.cur) + 1 );
}
contour = 0;
point = 0;
do
{
end_point = CUR.pts.contours[contour];
first_point = point;
while ( point <= end_point && (CUR.pts.touch[point] & mask) == 0 )
point++;
if ( point <= end_point )
{
first_touched = point;
cur_touched = point;
point++;
while ( point <= end_point )
{
if ( (CUR.pts.touch[point] & mask) != 0 )
{
if ( point > 0 )
Interp( cur_touched + 1,
point - 1,
cur_touched,
point,
&V );
cur_touched = point;
}
point++;
}
if ( cur_touched == first_touched )
Shift( first_point, end_point, cur_touched, &V );
else
{
Interp( cur_touched + 1,
end_point,
cur_touched,
first_touched,
&V );
if ( first_touched > 0 )
Interp( first_point,
first_touched - 1,
cur_touched,
first_touched,
&V );
}
}
contour++;
} while ( contour < CUR.pts.n_contours );
}
static void Ins_DELTAP( INS_ARG )
{
ULong nump, k;
UShort A;
ULong C;
Long B;
nump = (ULong)args[0];
for ( k = 1; k <= nump; k++ )
{
if ( CUR.args < 2 )
{
CUR.error = TT_Err_Too_Few_Arguments;
return;
}
CUR.args -= 2;
A = (UShort)CUR.stack[CUR.args + 1];
B = CUR.stack[CUR.args];
if ( !BOUNDS( A, CUR.zp0.n_points ) )
{
C = ((ULong)B & 0xF0) >> 4;
switch ( CUR.opcode )
{
case 0x5d:
break;
case 0x71:
C += 16;
break;
case 0x72:
C += 32;
break;
}
C += CUR.GS.delta_base;
if ( CURRENT_Ppem() == (Long)C )
{
B = ((ULong)B & 0xF) - 8;
if ( B >= 0 )
B++;
B = B * 64L / (1L << CUR.GS.delta_shift);
CUR_Func_move( &CUR.zp0, A, B );
}
}
else
if ( CUR.pedantic_hinting )
CUR.error = TT_Err_Invalid_Reference;
}
CUR.new_top = CUR.args;
}
static void Ins_DELTAC( INS_ARG )
{
ULong nump, k;
ULong A, C;
Long B;
nump = (ULong)args[0];
for ( k = 1; k <= nump; k++ )
{
if ( CUR.args < 2 )
{
CUR.error = TT_Err_Too_Few_Arguments;
return;
}
CUR.args -= 2;
A = (ULong)CUR.stack[CUR.args + 1];
B = CUR.stack[CUR.args];
if ( BOUNDS( A, CUR.cvtSize ) )
{
if ( CUR.pedantic_hinting )
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
}
else
{
C = ((ULong)B & 0xF0) >> 4;
switch ( CUR.opcode )
{
case 0x73:
break;
case 0x74:
C += 16;
break;
case 0x75:
C += 32;
break;
}
C += CUR.GS.delta_base;
if ( CURRENT_Ppem() == (Long)C )
{
B = ((ULong)B & 0xF) - 8;
if ( B >= 0 )
B++;
B = B * 64L / (1L << CUR.GS.delta_shift);
CUR_Func_move_cvt( A, B );
}
}
}
CUR.new_top = CUR.args;
}
static void Ins_GETINFO( INS_ARG )
{
Long K;
K = 0;
if ( (args[0] & 1) != 0 )
K = 3;
if ( CUR.metrics.rotated )
K |= 0x80;
if ( CUR.metrics.stretched )
K |= 0x100;
args[0] = K;
}
static void Ins_UNKNOWN( INS_ARG )
{
PDefRecord def, limit;
def = CUR.IDefs;
limit = def + CUR.numIDefs;
for ( ; def < limit; def++ )
{
if ( def->Opc == CUR.opcode && def->Active )
{
PCallRecord pCrec;
if ( CUR.callTop >= CUR.callSize )
{
CUR.error = TT_Err_Stack_Overflow;
return;
}
pCrec = CUR.callStack + CUR.callTop;
pCrec->Caller_Range = CUR.curRange;
pCrec->Caller_IP = CUR.IP + 1;
pCrec->Cur_Count = 1;
pCrec->Cur_Restart = def->Start;
CUR.callTop++;
INS_Goto_CodeRange( def->Range,
def->Start );
CUR.step_ins = FALSE;
return;
}
}
CUR.error = TT_Err_Invalid_Opcode;
}
#ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
static TInstruction_Function Instruct_Dispatch[256] =
{
Ins_SVTCA,
Ins_SVTCA,
Ins_SPVTCA,
Ins_SPVTCA,
Ins_SFVTCA,
Ins_SFVTCA,
Ins_SPVTL,
Ins_SPVTL,
Ins_SFVTL,
Ins_SFVTL,
Ins_SPVFS,
Ins_SFVFS,
Ins_GPV,
Ins_GFV,
Ins_SFVTPV,
Ins_ISECT,
Ins_SRP0,
Ins_SRP1,
Ins_SRP2,
Ins_SZP0,
Ins_SZP1,
Ins_SZP2,
Ins_SZPS,
Ins_SLOOP,
Ins_RTG,
Ins_RTHG,
Ins_SMD,
Ins_ELSE,
Ins_JMPR,
Ins_SCVTCI,
Ins_SSWCI,
Ins_SSW,
Ins_DUP,
Ins_POP,
Ins_CLEAR,
Ins_SWAP,
Ins_DEPTH,
Ins_CINDEX,
Ins_MINDEX,
Ins_ALIGNPTS,
Ins_UNKNOWN,
Ins_UTP,
Ins_LOOPCALL,
Ins_CALL,
Ins_FDEF,
Ins_ENDF,
Ins_MDAP,
Ins_MDAP,
Ins_IUP,
Ins_IUP,
Ins_SHP,
Ins_SHP,
Ins_SHC,
Ins_SHC,
Ins_SHZ,
Ins_SHZ,
Ins_SHPIX,
Ins_IP,
Ins_MSIRP,
Ins_MSIRP,
Ins_ALIGNRP,
Ins_RTDG,
Ins_MIAP,
Ins_MIAP,
Ins_NPUSHB,
Ins_NPUSHW,
Ins_WS,
Ins_RS,
Ins_WCVTP,
Ins_RCVT,
Ins_GC,
Ins_GC,
Ins_SCFS,
Ins_MD,
Ins_MD,
Ins_MPPEM,
Ins_MPS,
Ins_FLIPON,
Ins_FLIPOFF,
Ins_DEBUG,
Ins_LT,
Ins_LTEQ,
Ins_GT,
Ins_GTEQ,
Ins_EQ,
Ins_NEQ,
Ins_ODD,
Ins_EVEN,
Ins_IF,
Ins_EIF,
Ins_AND,
Ins_OR,
Ins_NOT,
Ins_DELTAP,
Ins_SDB,
Ins_SDS,
Ins_ADD,
Ins_SUB,
Ins_DIV,
Ins_MUL,
Ins_ABS,
Ins_NEG,
Ins_FLOOR,
Ins_CEILING,
Ins_ROUND,
Ins_ROUND,
Ins_ROUND,
Ins_ROUND,
Ins_NROUND,
Ins_NROUND,
Ins_NROUND,
Ins_NROUND,
Ins_WCVTF,
Ins_DELTAP,
Ins_DELTAP,
Ins_DELTAC,
Ins_DELTAC,
Ins_DELTAC,
Ins_SROUND,
Ins_S45ROUND,
Ins_JROT,
Ins_JROF,
Ins_ROFF,
Ins_UNKNOWN,
Ins_RUTG,
Ins_RDTG,
Ins_SANGW,
Ins_AA,
Ins_FLIPPT,
Ins_FLIPRGON,
Ins_FLIPRGOFF,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_SCANCTRL,
Ins_SDPVTL,
Ins_SDPVTL,
Ins_GETINFO,
Ins_IDEF,
Ins_ROLL,
Ins_MAX,
Ins_MIN,
Ins_SCANTYPE,
Ins_INSTCTRL,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_UNKNOWN,
Ins_PUSHB,
Ins_PUSHB,
Ins_PUSHB,
Ins_PUSHB,
Ins_PUSHB,
Ins_PUSHB,
Ins_PUSHB,
Ins_PUSHB,
Ins_PUSHW,
Ins_PUSHW,
Ins_PUSHW,
Ins_PUSHW,
Ins_PUSHW,
Ins_PUSHW,
Ins_PUSHW,
Ins_PUSHW,
Ins_MDRP,
Ins_MDRP,
Ins_MDRP,
Ins_MDRP,
Ins_MDRP,
Ins_MDRP,
Ins_MDRP,
Ins_MDRP,
Ins_MDRP,
Ins_MDRP,
Ins_MDRP,
Ins_MDRP,
Ins_MDRP,
Ins_MDRP,
Ins_MDRP,
Ins_MDRP,
Ins_MDRP,
Ins_MDRP,
Ins_MDRP,
Ins_MDRP,
Ins_MDRP,
Ins_MDRP,
Ins_MDRP,
Ins_MDRP,
Ins_MDRP,
Ins_MDRP,
Ins_MDRP,
Ins_MDRP,
Ins_MDRP,
Ins_MDRP,
Ins_MDRP,
Ins_MDRP,
Ins_MIRP,
Ins_MIRP,
Ins_MIRP,
Ins_MIRP,
Ins_MIRP,
Ins_MIRP,
Ins_MIRP,
Ins_MIRP,
Ins_MIRP,
Ins_MIRP,
Ins_MIRP,
Ins_MIRP,
Ins_MIRP,
Ins_MIRP,
Ins_MIRP,
Ins_MIRP,
Ins_MIRP,
Ins_MIRP,
Ins_MIRP,
Ins_MIRP,
Ins_MIRP,
Ins_MIRP,
Ins_MIRP,
Ins_MIRP,
Ins_MIRP,
Ins_MIRP,
Ins_MIRP,
Ins_MIRP,
Ins_MIRP,
Ins_MIRP,
Ins_MIRP,
Ins_MIRP
};
#endif
LOCAL_FUNC
#ifndef DEBUG_INTERPRETER
TT_Error RunIns( PExecution_Context exc )
#else
TT_Error RunIns2( PExecution_Context exc )
#endif
{
UShort A;
PDefRecord WITH;
PCallRecord WITH1;
Long ins_counter = 0;
#ifdef TT_CONFIG_OPTION_STATIC_INTERPRETER
cur = *exc;
#endif
CUR.metrics.ratio = 0;
if ( CUR.metrics.x_ppem != CUR.metrics.y_ppem )
{
CUR.func_read_cvt = Read_CVT_Stretched;
CUR.func_write_cvt = Write_CVT_Stretched;
CUR.func_move_cvt = Move_CVT_Stretched;
}
else
{
CUR.func_read_cvt = Read_CVT;
CUR.func_write_cvt = Write_CVT;
CUR.func_move_cvt = Move_CVT;
}
COMPUTE_Funcs();
Compute_Round( EXEC_ARGS (Byte)exc->GS.round_state );
do
{
if ( CALC_Length() != SUCCESS )
{
CUR.error = TT_Err_Code_Overflow;
goto LErrorLabel_;
}
CUR.args = CUR.top - (Pop_Push_Count[CUR.opcode] >> 4);
if ( CUR.args < 0 )
{
CUR.error = TT_Err_Too_Few_Arguments;
goto LErrorLabel_;
}
CUR.new_top = CUR.args + (Pop_Push_Count[CUR.opcode] & 15);
if ( CUR.new_top > CUR.stackSize )
{
CUR.error = TT_Err_Stack_Overflow;
goto LErrorLabel_;
}
CUR.step_ins = TRUE;
CUR.error = TT_Err_Ok;
#ifdef TT_CONFIG_OPTION_INTERPRETER_SWITCH
{
PStorage args = CUR.stack + CUR.args;
Byte opcode = CUR.opcode;
#undef ARRAY_BOUND_ERROR
#define ARRAY_BOUND_ERROR goto Set_Invalid_Ref
switch ( opcode )
{
case 0x00:
case 0x01:
case 0x02:
case 0x03:
case 0x04:
case 0x05:
{
Short AA, BB;
AA = (Short)(opcode & 1) << 14;
BB = AA ^ (Short)0x4000;
if ( opcode < 4 )
{
CUR.GS.projVector.x = AA;
CUR.GS.projVector.y = BB;
CUR.GS.dualVector.x = AA;
CUR.GS.dualVector.y = BB;
}
if ( (opcode & 2) == 0 )
{
CUR.GS.freeVector.x = AA;
CUR.GS.freeVector.y = BB;
}
COMPUTE_Funcs();
}
break;
case 0x06:
case 0x07:
DO_SPVTL
break;
case 0x08:
case 0x09:
DO_SFVTL
break;
case 0x0A:
DO_SPVFS
break;
case 0x0B:
DO_SFVFS
break;
case 0x0C:
DO_GPV
break;
case 0x0D:
DO_GFV
break;
case 0x0E:
DO_SFVTPV
break;
case 0x0F:
Ins_ISECT( EXEC_ARGS args );
break;
case 0x10:
DO_SRP0
break;
case 0x11:
DO_SRP1
break;
case 0x12:
DO_SRP2
break;
case 0x13:
Ins_SZP0( EXEC_ARGS args );
break;
case 0x14:
Ins_SZP1( EXEC_ARGS args );
break;
case 0x15:
Ins_SZP2( EXEC_ARGS args );
break;
case 0x16:
Ins_SZPS( EXEC_ARGS args );
break;
case 0x17:
DO_SLOOP
break;
case 0x18:
DO_RTG
break;
case 0x19:
DO_RTHG
break;
case 0x1A:
DO_SMD
break;
case 0x1B:
Ins_ELSE( EXEC_ARGS args );
break;
case 0x1C:
DO_JMPR
break;
case 0x1D:
DO_SCVTCI
break;
case 0x1E:
DO_SSWCI
break;
case 0x1F:
DO_SSW
break;
case 0x20:
DO_DUP
break;
case 0x21:
break;
case 0x22:
DO_CLEAR
break;
case 0x23:
DO_SWAP
break;
case 0x24:
DO_DEPTH
break;
case 0x25:
DO_CINDEX
break;
case 0x26:
Ins_MINDEX( EXEC_ARGS args );
break;
case 0x27:
Ins_ALIGNPTS( EXEC_ARGS args );
break;
case 0x28:
Ins_UNKNOWN( EXEC_ARGS args );
break;
case 0x29:
Ins_UTP( EXEC_ARGS args );
break;
case 0x2A:
Ins_LOOPCALL( EXEC_ARGS args );
break;
case 0x2B:
Ins_CALL( EXEC_ARGS args );
break;
case 0x2C:
Ins_FDEF( EXEC_ARGS args );
break;
case 0x2D:
Ins_ENDF( EXEC_ARGS args );
break;
case 0x2E:
case 0x2F:
Ins_MDAP( EXEC_ARGS args );
break;
case 0x30:
case 0x31:
Ins_IUP( EXEC_ARGS args );
break;
case 0x32:
case 0x33:
Ins_SHP( EXEC_ARGS args );
break;
case 0x34:
case 0x35:
Ins_SHC( EXEC_ARGS args );
break;
case 0x36:
case 0x37:
Ins_SHZ( EXEC_ARGS args );
break;
case 0x38:
Ins_SHPIX( EXEC_ARGS args );
break;
case 0x39:
Ins_IP( EXEC_ARGS args );
break;
case 0x3A:
case 0x3B:
Ins_MSIRP( EXEC_ARGS args );
break;
case 0x3C:
Ins_ALIGNRP( EXEC_ARGS args );
break;
case 0x3D:
DO_RTDG
break;
case 0x3E:
case 0x3F:
Ins_MIAP( EXEC_ARGS args );
break;
case 0x40:
Ins_NPUSHB( EXEC_ARGS args );
break;
case 0x41:
Ins_NPUSHW( EXEC_ARGS args );
break;
case 0x42:
DO_WS
break;
Set_Invalid_Ref:
CUR.error = TT_Err_Invalid_Reference;
break;
case 0x43:
DO_RS
break;
case 0x44:
DO_WCVTP
break;
case 0x45:
DO_RCVT
break;
case 0x46:
case 0x47:
Ins_GC( EXEC_ARGS args );
break;
case 0x48:
Ins_SCFS( EXEC_ARGS args );
break;
case 0x49:
case 0x4A:
Ins_MD( EXEC_ARGS args );
break;
case 0x4B:
DO_MPPEM
break;
case 0x4C:
DO_MPS
break;
case 0x4D:
DO_FLIPON
break;
case 0x4E:
DO_FLIPOFF
break;
case 0x4F:
DO_DEBUG
break;
case 0x50:
DO_LT
break;
case 0x51:
DO_LTEQ
break;
case 0x52:
DO_GT
break;
case 0x53:
DO_GTEQ
break;
case 0x54:
DO_EQ
break;
case 0x55:
DO_NEQ
break;
case 0x56:
DO_ODD
break;
case 0x57:
DO_EVEN
break;
case 0x58:
Ins_IF( EXEC_ARGS args );
break;
case 0x59:
break;
case 0x5A:
DO_AND
break;
case 0x5B:
DO_OR
break;
case 0x5C:
DO_NOT
break;
case 0x5D:
Ins_DELTAP( EXEC_ARGS args );
break;
case 0x5E:
DO_SDB
break;
case 0x5F:
DO_SDS
break;
case 0x60:
DO_ADD
break;
case 0x61:
DO_SUB
break;
case 0x62:
DO_DIV
break;
case 0x63:
DO_MUL
break;
case 0x64:
DO_ABS
break;
case 0x65:
DO_NEG
break;
case 0x66:
DO_FLOOR
break;
case 0x67:
DO_CEILING
break;
case 0x68:
case 0x69:
case 0x6A:
case 0x6B:
DO_ROUND
break;
case 0x6C:
case 0x6D:
case 0x6E:
case 0x6F:
DO_NROUND
break;
case 0x70:
DO_WCVTF
break;
case 0x71:
case 0x72:
Ins_DELTAP( EXEC_ARGS args );
break;
case 0x73:
case 0x74:
case 0x75:
Ins_DELTAC( EXEC_ARGS args );
break;
case 0x76:
DO_SROUND
break;
case 0x77:
DO_S45ROUND
break;
case 0x78:
DO_JROT
break;
case 0x79:
DO_JROF
break;
case 0x7A:
DO_ROFF
break;
case 0x7B:
Ins_UNKNOWN( EXEC_ARGS args );
break;
case 0x7C:
DO_RUTG
break;
case 0x7D:
DO_RDTG
break;
case 0x7E:
case 0x7F:
break;
case 0x80:
Ins_FLIPPT( EXEC_ARGS args );
break;
case 0x81:
Ins_FLIPRGON( EXEC_ARGS args );
break;
case 0x82:
Ins_FLIPRGOFF( EXEC_ARGS args );
break;
case 0x83:
case 0x84:
Ins_UNKNOWN( EXEC_ARGS args );
break;
case 0x85:
Ins_SCANCTRL( EXEC_ARGS args );
break;
case 0x86:
case 0x87:
Ins_SDPVTL( EXEC_ARGS args );
break;
case 0x88:
Ins_GETINFO( EXEC_ARGS args );
break;
case 0x89:
Ins_IDEF( EXEC_ARGS args );
break;
case 0x8A:
Ins_ROLL( EXEC_ARGS args );
break;
case 0x8B:
DO_MAX
break;
case 0x8C:
DO_MIN
break;
case 0x8D:
Ins_SCANTYPE( EXEC_ARGS args );
break;
case 0x8E:
Ins_INSTCTRL( EXEC_ARGS args );
break;
case 0x8F:
Ins_UNKNOWN( EXEC_ARGS args );
break;
default:
if ( opcode >= 0xE0 )
Ins_MIRP( EXEC_ARGS args );
else if ( opcode >= 0xC0 )
Ins_MDRP( EXEC_ARGS args );
else if ( opcode >= 0xB8 )
Ins_PUSHW( EXEC_ARGS args );
else if ( opcode >= 0xB0 )
Ins_PUSHB( EXEC_ARGS args );
else
Ins_UNKNOWN( EXEC_ARGS args );
}
}
#else
Instruct_Dispatch[CUR.opcode]( EXEC_ARGS &CUR.stack[CUR.args] );
#endif
if ( CUR.error != TT_Err_Ok )
{
switch ( (Int)(CUR.error) )
{
case TT_Err_Invalid_Opcode:
A = 0;
while ( A < CUR.numIDefs )
{
WITH = &CUR.IDefs[A];
if ( WITH->Active && CUR.opcode == WITH->Opc )
{
if ( CUR.callTop >= CUR.callSize )
{
CUR.error = TT_Err_Invalid_Reference;
goto LErrorLabel_;
}
WITH1 = &CUR.callStack[CUR.callTop];
WITH1->Caller_Range = CUR.curRange;
WITH1->Caller_IP = CUR.IP + 1;
WITH1->Cur_Count = 1;
WITH1->Cur_Restart = WITH->Start;
if ( INS_Goto_CodeRange( WITH->Range, WITH->Start ) == FAILURE )
goto LErrorLabel_;
goto LSuiteLabel_;
}
else
{
A++;
continue;
}
}
CUR.error = TT_Err_Invalid_Opcode;
goto LErrorLabel_;
default:
goto LErrorLabel_;
}
}
CUR.top = CUR.new_top;
if ( CUR.step_ins )
CUR.IP += CUR.length;
if ( ++ins_counter > MAX_RUNNABLE_OPCODES )
{
CUR.error = TT_Err_Execution_Too_Long;
goto LErrorLabel_;
}
LSuiteLabel_:
if ( CUR.IP >= CUR.codeSize )
{
if ( CUR.callTop > 0 )
{
CUR.error = TT_Err_Code_Overflow;
goto LErrorLabel_;
}
else
goto LNo_Error_;
}
} while ( !CUR.instruction_trap );
LNo_Error_:
CUR.error = TT_Err_Ok;
LErrorLabel_:
#ifdef TT_CONFIG_OPTION_STATIC_INTERPRETER
*exc = cur;
#endif
return CUR.error;
}
#ifdef DEBUG_INTERPRETER
int debug_coderange = TT_CodeRange_Glyph;
LOCAL_FUNC
TT_Error RunIns( PExecution_Context exc )
{
Int A, diff;
ULong next_IP;
Char ch, oldch;
char *temp;
int key;
TT_Error error = 0;
TGlyph_Zone save;
TGlyph_Zone pts;
#define TT_Round_Off 5
#define TT_Round_To_Half_Grid 0
#define TT_Round_To_Grid 1
#define TT_Round_To_Double_Grid 2
#define TT_Round_Up_To_Grid 4
#define TT_Round_Down_To_Grid 3
#define TT_Round_Super 6
#define TT_Round_Super_45 7
const String* round_str[8] =
{
"to half-grid",
"to grid",
"to double grid",
"down to grid",
"up to grid",
"off",
"super",
"super 45"
};
if ( exc->curRange != debug_coderange )
return RunIns2( exc );
pts = exc->pts;
save.n_points = pts.n_points;
save.n_contours = pts.n_contours;
MEM_Alloc( save.org, sizeof ( TT_Vector ) * save.n_points );
MEM_Alloc( save.cur, sizeof ( TT_Vector ) * save.n_points );
MEM_Alloc( save.touch, sizeof ( Byte ) * save.n_points );
exc->instruction_trap = 1;
oldch = '\0';
do
{
if ( exc->IP < exc->codeSize )
{
#ifdef TT_CONFIG_OPTION_STATIC_INTERPRETER
cur = *exc;
#endif
CALC_Length();
exc->args = exc->top - (Pop_Push_Count[exc->opcode] >> 4);
{
char temp[80];
int n, col, pop;
int args = CUR.args;
sprintf( temp, "%78c\n", ' ' );
switch ( CUR.curRange )
{
case TT_CodeRange_Glyph:
temp[0] = 'g';
break;
case TT_CodeRange_Cvt:
temp[0] = 'c';
break;
default:
temp[0] = 'f';
}
sprintf( temp+1, "%04lx: %02x %-36.36s",
CUR.IP,
CUR.opcode,
Cur_U_Line(&CUR) );
strncpy( temp+46, " (", 2 );
args = CUR.top - 1;
pop = Pop_Push_Count[CUR.opcode] >> 4;
col = 48;
for ( n = 6; n > 0; n-- )
{
if ( pop == 0 )
temp[col-1] = (temp[col-1] == '(' ? ' ' : ')' );
if ( args < CUR.top && args >= 0 )
sprintf( temp+col, "%04lx", CUR.stack[args] );
else
sprintf( temp+col, " " );
temp[col+4] = ' ';
col += 5;
pop--;
args--;
}
temp[78] = '\n';
temp[79] = '\0';
PTRACE0(( temp ));
}
if ( CUR.args < 0 )
{
PTRACE0(( "ERROR : Too few arguments\n" ));
exc->error = TT_Err_Too_Few_Arguments;
goto LErrorLabel_;
}
CUR.new_top = CUR.args + (Pop_Push_Count[CUR.opcode] & 15);
if ( CUR.new_top > CUR.stackSize )
{
PTRACE0(( "ERROR : Stack overflow\n" ));
exc->error = TT_Err_Stack_Overflow;
goto LErrorLabel_;
}
}
else
PTRACE0(( "End of program reached.\n" ));
key = 0;
do
{
ch = getch();
switch ( ch )
{
case '?':
PTRACE0(( "FDebug Help\n\n" ));
PTRACE0(( "? Show this page\n" ));
PTRACE0(( "q Quit debugger\n" ));
PTRACE0(( "n Skip to next instruction\n" ));
PTRACE0(( "s Step into\n" ));
PTRACE0(( "v Show vector info\n" ));
PTRACE0(( "g Show graphics state\n" ));
PTRACE0(( "p Show points zone\n\n" ));
break;
case 'v':
PTRACE0(( "freedom (%04hx,%04hx)\n", exc->GS.freeVector.x,
exc->GS.freeVector.y ));
PTRACE0(( "projection (%04hx,%04hx)\n", exc->GS.projVector.x,
exc->GS.projVector.y ));
PTRACE0(( "dual (%04hx,%04hx)\n\n", exc->GS.dualVector.x,
exc->GS.dualVector.y ));
break;
case 'g':
PTRACE0(( "rounding %s\n", round_str[exc->GS.round_state] ));
PTRACE0(( "min dist %04lx\n", exc->GS.minimum_distance ));
PTRACE0(( "cvt_cutin %04lx\n", exc->GS.control_value_cutin ));
break;
case 'p':
for ( A = 0; A < exc->pts.n_points; A++ )
{
PTRACE0(( "%02hx ", A ));
PTRACE0(( "%08lx,%08lx - ", pts.org[A].x, pts.org[A].y ));
PTRACE0(( "%08lx,%08lx\n", pts.cur[A].x, pts.cur[A].y ));
}
PTRACE0(( "\n" ));
break;
default:
key = 1;
}
} while ( !key );
MEM_Copy( save.org, pts.org, pts.n_points * sizeof ( TT_Vector ) );
MEM_Copy( save.cur, pts.cur, pts.n_points * sizeof ( TT_Vector ) );
MEM_Copy( save.touch, pts.touch, pts.n_points );
if (ch == '\r')
ch = oldch;
switch ( ch )
{
case 'q':
goto LErrorLabel_;
case 'n':
if ( exc->IP < exc->codeSize )
{
if ( CUR.opcode != 0x2a && CUR.opcode != 0x2b )
goto Step_into;
next_IP = CUR.IP + CUR.length;
while ( exc->IP != next_IP )
{
if ( ( error = RunIns2( exc ) ) )
goto LErrorLabel_;
}
}
oldch = ch;
break;
case 's':
if ( exc->IP < exc->codeSize )
Step_into:
if ( ( error = RunIns2( exc ) ) )
goto LErrorLabel_;
oldch = ch;
break;
default:
PTRACE0(( "unknown command. Press ? for help\n" ));
oldch = '\0';
}
for ( A = 0; A < pts.n_points; A++ )
{
diff = 0;
if ( save.org[A].x != pts.org[A].x ) diff |= 1;
if ( save.org[A].y != pts.org[A].y ) diff |= 2;
if ( save.cur[A].x != pts.cur[A].x ) diff |= 4;
if ( save.cur[A].y != pts.cur[A].y ) diff |= 8;
if ( save.touch[A] != pts.touch[A] ) diff |= 16;
if ( diff )
{
PTRACE0(( "%02hx ", A ));
if ( diff & 16 ) temp = "(%01hx)"; else temp = " %01hx ";
PTRACE0(( temp, save.touch[A] & 7 ));
if ( diff & 1 ) temp = "(%08lx)"; else temp = " %08lx ";
PTRACE0(( temp, save.org[A].x ));
if ( diff & 2 ) temp = "(%08lx)"; else temp = " %08lx ";
PTRACE0(( temp, save.org[A].y ));
if ( diff & 4 ) temp = "(%08lx)"; else temp = " %08lx ";
PTRACE0(( temp, save.cur[A].x ));
if ( diff & 8 ) temp = "(%08lx)"; else temp = " %08lx ";
PTRACE0(( temp, save.cur[A].y ));
PTRACE0(( "\n" ));
PTRACE0(( "%02hx ", A ));
if ( diff & 16 ) temp = "[%01hx]"; else temp = " %01hx ";
PTRACE0(( temp, pts.touch[A] & 7 ));
if ( diff & 1 ) temp = "[%08lx]"; else temp = " %08lx ";
PTRACE0(( temp, pts.org[A].x ));
if ( diff & 2 ) temp = "[%08lx]"; else temp = " %08lx ";
PTRACE0(( temp, pts.org[A].y ));
if ( diff & 4 ) temp = "[%08lx]"; else temp = " %08lx ";
PTRACE0(( temp, pts.cur[A].x ));
if ( diff & 8 ) temp = "[%08lx]"; else temp = " %08lx ";
PTRACE0(( temp, pts.cur[A].y ));
PTRACE0(( "\n\n" ));
}
}
} while ( TRUE );
LErrorLabel_:
return error;
}
#endif
#endif