home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: SysTools
/
SysTools.zip
/
ft-beta.zip
/
freetype
/
lib
/
ttinterp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-10-06
|
137KB
|
5,248 lines
/*******************************************************************
*
* ttinterp.c 2.3
*
* TrueType bytecode intepreter.
*
* Copyright 1996 David Turner, Robert Wilhelm and Werner Lemberg
*
* This file is part of the FreeType project, and may only be used
* modified and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*
* TODO :
*
* - Fix the non-square pixel case (or how to manage the CVT to
* detect horizontal and vertical scaled FUnits ?)
*
*
* Changes between 2.3 and 2.2 :
*
* - added support for rotation, stretching, instruction control
*
* - added support for non-square pixels. However, this doesn't
* work perfectly yet..
*
* Changes between 2.2 and 2.1 :
*
* - a small bugfix in the Push opcodes
*
* Changes between 2.1 and 2.0 :
*
* - created the TTExec component to take care of all execution
* context management. The interpreter has now one single
* function.
*
* - made some changes to support re-entrancy. The re-entrant
* interpreter is smaller !
*
******************************************************************/
#include "freetype.h"
#include "tttypes.h"
#include "tterror.h"
#include "ttcalc.h"
#include "ttmemory.h"
#include "ttinterp.h"
#ifdef DEBUG
#include "ttdebug.h"
#ifdef HAVE_CONIO_H
#include "conio.h"
#endif
#endif /* DEBUG */
/* There are two kinds of implementations there : */
/* */
/* a. static implementation : */
/* */
/* the current execution context is a static variable, */
/* which fields are accessed directly by the interpreter */
/* during execution. the context is named 'cur'. */
/* */
/* this version is non-reentrant, of course.. */
/* */
/* */
/* b. indirect implementation : */
/* */
/* the current execution context is passed to _each_ */
/* function as its first argument, and each field is */
/* thus accessed indirectly. */
/* */
/* this version is however fully re-entrant.. */
/* */
/* */
/* The idea is that an indirect implementation may be */
/* slower to execute on the low-end processors that are */
/* used in some systems (like 386s or even 486s). */
/* */
/* When the interpreter started, we had no idea of the */
/* time that glyph hinting (i.e. executing instructions) */
/* could take in the whole process of rendering a glyph, */
/* and a 10 to 30% performance penalty on low-end systems */
/* didn't seem much of a good idea. This question led us */
/* to provide two distinct builds of the C version from */
/* a single source, with the use of macros (again !) */
/* */
/* Now that the engine is working (and working really */
/* well !), it seems that the greatest time-consuming */
/* factors are : file i/o, glyph loading, rasterizing and */
/* _then_ glyph hinting ! */
/* */
/* Tests performed with two versions of the 'timer' program */
/* seem to indicate that hinting takes less than 5% of the */
/* rendering process, which is dominated by glyph loading */
/* and scan-line conversion by an high order of magnitude. */
/* */
/* As a consequence, the indirect implementation is now the */
/* default, as its performance costs can be considered */
/* negligible in our context.. Note however that we */
/* kept the same source with macros because : */
/* */
/* - the code is kept very close in design to the */
/* Pascal one used for development. */
/* */
/* - it's much more readable that way ! */
/* */
/* - it's still open to later experimentation and tuning */
#ifndef TT_STATIC_INTERPRETER /* indirect implementation */
#define CUR (*exc) /* see ttobjs.h */
#else /* static implementation */
#define CUR cur
static TExecution_Context cur; /* static exec. context variable */
/* apparently, we have a _lot_ of direct indexing when accessing */
/* the static 'cur', which makes the code bigger ( due to all the */
/* four bytes addresses ). */
#endif
#define INS_ARG EXEC_OPS PStorage args /* see ttexec.h */
#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 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) Move_Zp2_Point( EXEC_ARGS a, b, c )
#define CUR_Ppem() Cur_PPEM( EXEC_ARG )
typedef void (*TInstruction_Function)( INS_ARG );
/* Instruction dispatch function, as used by the interpreter */
/* end local struct definitions */
#ifndef ABS
#define ABS(x) ( (x) < 0 ? -(x) : (x) )
#endif
/*********************************************************************/
/* */
/* Before an opcode is executed, the interpreter verifies that */
/* there are enough arguments on the stack, with the help of */
/* the Pop_Push_Count table. */
/* */
/* For each opcode, the first column gives the number of arguments */
/* that are popped from the stack; the second one gives the number */
/* of those that are pushed in result. */
/* */
/* Note that for opcodes with a varying number of parameters, */
/* either 0 or 1 arg is verified before execution, depending */
/* on the nature of the instruction : */
/* */
/* - if the number of arguments is given by the bytecode */
/* stream or the loop variable, 0 is chosen. */
/* */
/* - if the first argument is a count n that is followed */
/* by arguments a1..an, then 1 is chosen. */
/* */
/*********************************************************************/
static unsigned char Pop_Push_Count[512] =
/* opcodes are gathered in groups of 16 */
/* please keep the spaces as they are */
{
/* SVTCA y */ 0, 0,
/* SVTCA x */ 0, 0,
/* SPvTCA y */ 0, 0,
/* SPvTCA x */ 0, 0,
/* SFvTCA y */ 0, 0,
/* SFvTCA x */ 0, 0,
/* SPvTL // */ 2, 0,
/* SPvTL + */ 2, 0,
/* SFvTL // */ 2, 0,
/* SFvTL + */ 2, 0,
/* SPvFS */ 2, 0,
/* SFvFS */ 2, 0,
/* GPV */ 0, 2,
/* GFV */ 0, 2,
/* SFvTPv */ 0, 0,
/* ISECT */ 5, 0,
/* SRP0 */ 1, 0,
/* SRP1 */ 1, 0,
/* SRP2 */ 1, 0,
/* SZP0 */ 1, 0,
/* SZP1 */ 1, 0,
/* SZP2 */ 1, 0,
/* SZPS */ 1, 0,
/* SLOOP */ 1, 0,
/* RTG */ 0, 0,
/* RTHG */ 0, 0,
/* SMD */ 1, 0,
/* ELSE */ 0, 0,
/* JMPR */ 1, 0,
/* SCvTCi */ 1, 0,
/* SSwCi */ 1, 0,
/* SSW */ 1, 0,
/* DUP */ 1, 2,
/* POP */ 1, 0,
/* CLEAR */ 0, 0,
/* SWAP */ 2, 2,
/* DEPTH */ 0, 1,
/* CINDEX */ 1, 1,
/* MINDEX */ 1, 0,
/* AlignPTS */ 2, 0,
/* INS_$28 */ 0, 0,
/* UTP */ 1, 0,
/* LOOPCALL */ 2, 0,
/* CALL */ 1, 0,
/* FDEF */ 1, 0,
/* ENDF */ 0, 0,
/* MDAP[0] */ 1, 0,
/* MDAP[1] */ 1, 0,
/* IUP[0] */ 0, 0,
/* IUP[1] */ 0, 0,
/* SHP[0] */ 0, 0,
/* SHP[1] */ 0, 0,
/* SHC[0] */ 1, 0,
/* SHC[1] */ 1, 0,
/* SHZ[0] */ 1, 0,
/* SHZ[1] */ 1, 0,
/* SHPIX */ 1, 0,
/* IP */ 0, 0,
/* MSIRP[0] */ 2, 0,
/* MSIRP[1] */ 2, 0,
/* AlignRP */ 0, 0,
/* RTDG */ 0, 0,
/* MIAP[0] */ 2, 0,
/* MIAP[1] */ 2, 0,
/* NPushB */ 0, 0,
/* NPushW */ 0, 0,
/* WS */ 2, 0,
/* RS */ 1, 1,
/* WCvtP */ 2, 0,
/* RCvt */ 1, 1,
/* GC[0] */ 1, 1,
/* GC[1] */ 1, 1,
/* SCFS */ 2, 0,
/* MD[0] */ 2, 1,
/* MD[1] */ 2, 1,
/* MPPEM */ 0, 1,
/* MPS */ 0, 1,
/* FlipON */ 0, 0,
/* FlipOFF */ 0, 0,
/* DEBUG */ 1, 0,
/* LT */ 2, 1,
/* LTEQ */ 2, 1,
/* GT */ 2, 1,
/* GTEQ */ 2, 1,
/* EQ */ 2, 1,
/* NEQ */ 2, 1,
/* ODD */ 1, 1,
/* EVEN */ 1, 1,
/* IF */ 1, 0,
/* EIF */ 0, 0,
/* AND */ 2, 1,
/* OR */ 2, 1,
/* NOT */ 1, 1,
/* DeltaP1 */ 1, 0,
/* SDB */ 1, 0,
/* SDS */ 1, 0,
/* ADD */ 2, 1,
/* SUB */ 2, 1,
/* DIV */ 2, 1,
/* MUL */ 2, 1,
/* ABS */ 1, 1,
/* NEG */ 1, 1,
/* FLOOR */ 1, 1,
/* CEILING */ 1, 1,
/* ROUND[0] */ 1, 1,
/* ROUND[1] */ 1, 1,
/* ROUND[2] */ 1, 1,
/* ROUND[3] */ 1, 1,
/* NROUND[0] */ 1, 1,
/* NROUND[1] */ 1, 1,
/* NROUND[2] */ 1, 1,
/* NROUND[3] */ 1, 1,
/* WCvtF */ 2, 0,
/* DeltaP2 */ 1, 0,
/* DeltaP3 */ 1, 0,
/* DeltaCn[0] */ 1, 0,
/* DeltaCn[1] */ 1, 0,
/* DeltaCn[2] */ 1, 0,
/* SROUND */ 1, 0,
/* S45Round */ 1, 0,
/* JROT */ 2, 0,
/* JROF */ 2, 0,
/* ROFF */ 0, 0,
/* INS_$7B */ 0, 0,
/* RUTG */ 0, 0,
/* RDTG */ 0, 0,
/* SANGW */ 1, 0,
/* AA */ 1, 0,
/* FlipPT */ 0, 0,
/* FlipRgON */ 2, 0,
/* FlipRgOFF */ 2, 0,
/* INS_$83 */ 0, 0,
/* INS_$84 */ 0, 0,
/* ScanCTRL */ 1, 0,
/* SDVPTL[0] */ 2, 0,
/* SDVPTL[1] */ 2, 0,
/* GetINFO */ 1, 1,
/* IDEF */ 1, 0,
/* ROLL */ 3, 3,
/* MAX */ 2, 1,
/* MIN */ 2, 1,
/* ScanTYPE */ 1, 0,
/* InstCTRL */ 2, 0,
/* INS_$8F */ 0, 0,
/* INS_$90 */ 0, 0,
/* INS_$91 */ 0, 0,
/* INS_$92 */ 0, 0,
/* INS_$93 */ 0, 0,
/* INS_$94 */ 0, 0,
/* INS_$95 */ 0, 0,
/* INS_$96 */ 0, 0,
/* INS_$97 */ 0, 0,
/* INS_$98 */ 0, 0,
/* INS_$99 */ 0, 0,
/* INS_$9A */ 0, 0,
/* INS_$9B */ 0, 0,
/* INS_$9C */ 0, 0,
/* INS_$9D */ 0, 0,
/* INS_$9E */ 0, 0,
/* INS_$9F */ 0, 0,
/* INS_$A0 */ 0, 0,
/* INS_$A1 */ 0, 0,
/* INS_$A2 */ 0, 0,
/* INS_$A3 */ 0, 0,
/* INS_$A4 */ 0, 0,
/* INS_$A5 */ 0, 0,
/* INS_$A6 */ 0, 0,
/* INS_$A7 */ 0, 0,
/* INS_$A8 */ 0, 0,
/* INS_$A9 */ 0, 0,
/* INS_$AA */ 0, 0,
/* INS_$AB */ 0, 0,
/* INS_$AC */ 0, 0,
/* INS_$AD */ 0, 0,
/* INS_$AE */ 0, 0,
/* INS_$AF */ 0, 0,
/* PushB[0] */ 0, 1,
/* PushB[1] */ 0, 2,
/* PushB[2] */ 0, 3,
/* PushB[3] */ 0, 4,
/* PushB[4] */ 0, 5,
/* PushB[5] */ 0, 6,
/* PushB[6] */ 0, 7,
/* PushB[7] */ 0, 8,
/* PushW[0] */ 0, 1,
/* PushW[1] */ 0, 2,
/* PushW[2] */ 0, 3,
/* PushW[3] */ 0, 4,
/* PushW[4] */ 0, 5,
/* PushW[5] */ 0, 6,
/* PushW[6] */ 0, 7,
/* PushW[7] */ 0, 8,
/* MDRP[00] */ 1, 0,
/* MDRP[01] */ 1, 0,
/* MDRP[02] */ 1, 0,
/* MDRP[03] */ 1, 0,
/* MDRP[04] */ 1, 0,
/* MDRP[05] */ 1, 0,
/* MDRP[06] */ 1, 0,
/* MDRP[07] */ 1, 0,
/* MDRP[08] */ 1, 0,
/* MDRP[09] */ 1, 0,
/* MDRP[10] */ 1, 0,
/* MDRP[11] */ 1, 0,
/* MDRP[12] */ 1, 0,
/* MDRP[13] */ 1, 0,
/* MDRP[14] */ 1, 0,
/* MDRP[15] */ 1, 0,
/* MDRP[16] */ 1, 0,
/* MDRP[17] */ 1, 0,
/* MDRP[18] */ 1, 0,
/* MDRP[19] */ 1, 0,
/* MDRP[20] */ 1, 0,
/* MDRP[21] */ 1, 0,
/* MDRP[22] */ 1, 0,
/* MDRP[23] */ 1, 0,
/* MDRP[24] */ 1, 0,
/* MDRP[25] */ 1, 0,
/* MDRP[26] */ 1, 0,
/* MDRP[27] */ 1, 0,
/* MDRP[28] */ 1, 0,
/* MDRP[29] */ 1, 0,
/* MDRP[30] */ 1, 0,
/* MDRP[31] */ 1, 0,
/* MIRP[00] */ 2, 0,
/* MIRP[01] */ 2, 0,
/* MIRP[02] */ 2, 0,
/* MIRP[03] */ 2, 0,
/* MIRP[04] */ 2, 0,
/* MIRP[05] */ 2, 0,
/* MIRP[06] */ 2, 0,
/* MIRP[07] */ 2, 0,
/* MIRP[08] */ 2, 0,
/* MIRP[09] */ 2, 0,
/* MIRP[10] */ 2, 0,
/* MIRP[11] */ 2, 0,
/* MIRP[12] */ 2, 0,
/* MIRP[13] */ 2, 0,
/* MIRP[14] */ 2, 0,
/* MIRP[15] */ 2, 0,
/* MIRP[16] */ 2, 0,
/* MIRP[17] */ 2, 0,
/* MIRP[18] */ 2, 0,
/* MIRP[19] */ 2, 0,
/* MIRP[20] */ 2, 0,
/* MIRP[21] */ 2, 0,
/* MIRP[22] */ 2, 0,
/* MIRP[23] */ 2, 0,
/* MIRP[24] */ 2, 0,
/* MIRP[25] */ 2, 0,
/* MIRP[26] */ 2, 0,
/* MIRP[27] */ 2, 0,
/* MIRP[28] */ 2, 0,
/* MIRP[29] */ 2, 0,
/* MIRP[30] */ 2, 0,
/* MIRP[31] */ 2, 0
};
/******************************************************************
*
* Function : Cur_PPEM
*
* Description : Returns the current ppem along the projection
* vector.
*
*****************************************************************/
static TT_F26Dot6 Cur_PPEM( EXEC_OP )
{
Int64 Tx, Ty;
Int32 x, y;
if (CUR.cached_metrics)
return CUR.cur_ppem;
if (!CUR.GS.projVector.y)
{
CUR.cur_ppem = CUR.metrics.x_ppem;
CUR.scale1 = CUR.metrics.x_scale1;
CUR.scale2 = CUR.metrics.x_scale2;
}
else if ( !CUR.GS.projVector.x )
{
CUR.cur_ppem = CUR.metrics.y_ppem;
CUR.scale1 = CUR.metrics.y_scale1;
CUR.scale2 = CUR.metrics.y_scale2;
}
else
{
/* Rotation */
x = MulDiv_Round( CUR.metrics.x_ppem, CUR.GS.projVector.x, 0x40 );
/* x = x_ppem.proj_x * 256 */
y = MulDiv_Round( CUR.metrics.y_ppem, CUR.GS.projVector.y, 0x40 );
/* y = y_ppem.proj_y * 256 */
MUL_64( x, x, Tx );
MUL_64( y, y, Ty );
ADD_64( Tx, Ty, Tx );
CUR.cur_ppem = SQRT_64( Tx ) / 256;
/* XXX: Fix this.. for now we simply don't care */
CUR.scale1 = CUR.metrics.x_scale1;
CUR.scale2 = CUR.metrics.x_scale2;
}
CUR.cached_metrics = TRUE;
return CUR.cur_ppem;
}
/******************************************************************
*
* Function : Calc_Length
*
* Description : Computes the length in bytes of current opcode
*
*****************************************************************/
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;
}
/* make sure result is in range */
if ( CUR.IP + CUR.length > CUR.codeSize )
return FAILURE;
return SUCCESS;
}
/*******************************************************************
*
* Function : GetShortIns
*
* Description : Return a short integer taken from the instruction
* stream at address IP.
*
* Input : None
*
* Output : Short read at Code^[IP..IP+1]
*
* Notes : This one could become a Macro in the C version
*
*****************************************************************/
static Short GetShortIns( EXEC_OP )
{
/* Reading a byte stream so there is no endianess DaveP */
CUR.IP += 2;
return ( CUR.code[CUR.IP-2] << 8) +
CUR.code[CUR.IP-1];
}
/*******************************************************************
*
* Function : Ins_Goto_CodeRange
*
* Description :
*
*
* Input :
*
* Output :
*
* Notes :
*
*****************************************************************/
static Bool Ins_Goto_CodeRange( EXEC_OPS Int aRange, Int 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) /* invalid coderange */
{
CUR.error = TT_Err_Invalid_Coderange;
return FAILURE;
}
/* NOTE : Because the last instruction of a program may be a CALL */
/* which will return to the first byte *after* the code */
/* range, we test for AIP <= Size, instead of AIP < Size */
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;
}
/*******************************************************************
*
* Function : Direct_Move
*
* Description : Moves a point by a given distance along the
* freedom vector.
*
* Input : Vx, Vy point coordinates to move
* touch touch flag to modify
* distance
*
* Output : None
*
*****************************************************************/
static void Direct_Move( EXEC_OPS PVecRecord zone,
Int point,
TT_F26Dot6 distance)
{
TT_F26Dot6 v;
v = CUR.GS.freeVector.x;
if (v != 0)
{
zone->cur_x[point] += MulDiv_Round( distance,
v * 0x10000L,
CUR.F_dot_P);
zone->touch[point] |= TT_Flag_Touched_X;
}
v = CUR.GS.freeVector.y;
if (v != 0)
{
zone->cur_y[point] += MulDiv_Round( distance,
v * 0x10000L,
CUR.F_dot_P);
zone->touch[point] |= TT_Flag_Touched_Y;
}
}
/* The following versions are used whenever both vectors are both */
/* along one of the coordinate unit vectors, i.e. in 90% cases */
/*******************************************************************
* Direct_Move_X
*
*
*******************************************************************/
static void Direct_Move_X( EXEC_OPS PVecRecord zone,
Int point,
TT_F26Dot6 distance)
{
zone->cur_x[point] += distance;
zone->touch[point] |= TT_Flag_Touched_X;
}
/*******************************************************************
* Direct_Move_Y
*
*
*******************************************************************/
static void Direct_Move_Y( EXEC_OPS PVecRecord zone,
Int point,
TT_F26Dot6 distance)
{
zone->cur_y[point] += distance;
zone->touch[point] |= TT_Flag_Touched_Y;
}
/*******************************************************************
*
* Function : Round_None
*
* Description : Do not round, but add engine compensation
*
* Input : distance : distance to round
* compensation : engine compensation
*
* Output : rounded distance
*
* NOTE : The spec says very few about the relationship between
* rounding and engine compensation. However, it seems
* from the description of super round that we should
* should add the compensation before rounding
*
******************************************************************/
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;
}
/*******************************************************************
*
* Function : Round_To_Grid
*
* Description : round value to grid after adding engine
* compensation
*
* Input : distance : distance to round
* compensation : engine compensation
*
* Output : rounded distance
*
*****************************************************************/
static TT_F26Dot6 Round_To_Grid( EXEC_OPS TT_F26Dot6 distance,
TT_F26Dot6 compensation)
{
TT_F26Dot6 val;
if (distance >= 0)
{
val = (distance + compensation + 32) & (-64);
if (val < 0)
val = 0;
}
else
{
val = -((compensation - distance + 32) & (-64));
if (val > 0)
val = 0;
}
return val;
}
/*******************************************************************
*
* Function : Round_To_Half_Grid
*
* Description : round value to half grid after adding engine
* compensation
*
* Input : distance : distance to round
* compensation : engine compensation
*
* Output : rounded distance
*
*****************************************************************/
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;
}
/*******************************************************************
*
* Function : Round_Down_To_Grid
*
* Description : round value down to grid after adding engine
* compensation
*
* Input : distance : distance to round
* compensation : engine compensation
*
* Output : rounded distance
*
*****************************************************************/
static TT_F26Dot6 Round_Down_To_Grid( EXEC_OPS TT_F26Dot6 distance,
TT_F26Dot6 compensation )
{
TT_F26Dot6 val;
if (distance >= 0)
{
val = (distance + compensation) & (-64);
if (val < 0)
val = 0;
}
else
{
val = -((compensation - distance) & (-64));
if (val > 0)
val = 0;
}
return val;
}
/*******************************************************************
*
* Function : Round_Up_To_Grid
*
* Description : round value up to grid after adding engine
* compensation
*
* Input : distance : distance to round
* compensation : engine compensation
*
* Output : rounded distance
*
*****************************************************************/
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) & (-64);
if (val < 0)
val = 0;
}
else
{
val = -((compensation - distance + 63) & (-64));
if (val > 0)
val = 0;
}
return val;
}
/*******************************************************************
*
* Function : Round_To_Double_Grid
*
* Description : round value to double grid after adding engine
* compensation
*
* Input : distance : distance to round
* compensation : engine compensation
*
* Output : rounded distance
*
*****************************************************************/
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) & (-32);
if (val < 0)
val = 0;
}
else
{
val = -((compensation - distance + 16) & (-32));
if (val > 0)
val = 0;
}
return val;
}
/*******************************************************************
*
* Function : Round_Super
*
* Description : super round value to grid after adding engine
* compensation
*
* Input : distance : distance to round
* compensation : engine compensation
*
* Output : rounded distance
*
* NOTE : The spec says very few about the relationship between
* rounding and engine compensation. However, it seems
* from the description of super round that we should
* should add the compensation before rounding
*
*****************************************************************/
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;
}
/*******************************************************************
*
* Function : Round_Super_45
*
* Description : super round value to grid after adding engine
* compensation
*
* Input : distance : distance to round
* compensation : engine compensation
*
* Output : rounded distance
*
* NOTE : There is a separate function for Round_Super_45 as we
* may need a greater precision.
*
*****************************************************************/
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;
}
/******************************************************************************
* Compute_Round
*
*
******************************************************************************/
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;
}
}
/*******************************************************************
*
* Function : SetSuperRound
*
* Description : Set Super Round parameters
*
* Input : GridPeriod Grid period
* OpCode SROUND opcode
*
* Output : None
*
* Notes :
*
*****************************************************************/
static void SetSuperRound( EXEC_OPS TT_F26Dot6 GridPeriod, Long selector)
{
switch (selector & 0xC0)
{
case 0:
CUR.period = GridPeriod / 2;
break;
case 0x40:
CUR.period = GridPeriod;
break;
case 0x80:
CUR.period = GridPeriod * 2;
break;
/* This opcode is reserved, but ... */
case 0xC0:
CUR.period = GridPeriod;
break;
}
switch (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) - 4L) * CUR.period / 8;
CUR.period /= 256;
CUR.phase /= 256;
CUR.threshold /= 256;
}
/*******************************************************************
*
* Function : Norm
*
* Description : returns the norm (length) of a vector
*
* Input : X, Y vector
*
* Output : returns length in F26dot6
*
*****************************************************************/
static TT_F26Dot6 Norm( TT_F26Dot6 X, TT_F26Dot6 Y )
{
Int64 T1, T2;
MUL_64(X, X, T1);
MUL_64(Y, Y, T2);
ADD_64(T1, T2, T1);
return (TT_F26Dot6)SQRT_64(T1);
}
/*******************************************************************
*
* Function : Project
*
* Description : Computes the projection of (Vx,Vy) along the
* current projection vector
*
* Input : Vx, Vy input vector
*
* Output : return distance in F26dot6
*
*****************************************************************/
static TT_F26Dot6 Project( EXEC_OPS TT_F26Dot6 Vx, TT_F26Dot6 Vy)
{
Int64 T1, T2;
MUL_64( Vx, CUR.GS.projVector.x, T1);
MUL_64( Vy, CUR.GS.projVector.y, T2);
ADD_64( T1, T2, T1);
return (DIV_64( T1, 0x4000L));
}
/******************************************************************************
* #function#
*
*
******************************************************************************/
static TT_F26Dot6 Dual_Project( EXEC_OPS TT_F26Dot6 Vx, TT_F26Dot6 Vy)
{
Int64 T1, T2;
MUL_64( Vx, CUR.GS.dualVector.x, T1);
MUL_64( Vy, CUR.GS.dualVector.y, T2);
ADD_64( T1, T2, T1);
return ((TT_F26Dot6)DIV_64( T1, 0x4000L));
}
/******************************************************************************
* #function#
*
*
******************************************************************************/
static TT_F26Dot6 Free_Project( EXEC_OPS TT_F26Dot6 Vx, TT_F26Dot6 Vy)
{
Int64 T1, T2;
MUL_64( Vx, CUR.GS.freeVector.x, T1);
MUL_64( Vy, CUR.GS.freeVector.y, T2);
ADD_64( T1, T2, T1);
return ((TT_F26Dot6)DIV_64( T1, 0x4000L ));
}
/******************************************************************************
* #function#
*
*
******************************************************************************/
static TT_F26Dot6 Project_x( EXEC_OPS TT_F26Dot6 Vx, TT_F26Dot6 Vy)
{
return Vx;
}
/******************************************************************************
* #function#
*
*
******************************************************************************/
static TT_F26Dot6 Project_y( EXEC_OPS TT_F26Dot6 Vx, TT_F26Dot6 Vy)
{
return Vy;
}
/*******************************************************************
*
* Function : Compute_Funcs
*
* Description : Computes the projections and movement function
* pointers according to the current graphics state
*
* Input : None
*
*****************************************************************/
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_move = (TMove_Function)Direct_Move;
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;
CUR_Ppem(); /* Force computation */
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;
}
}
}
/* at small sizes, F_dot_P can become too small, resulting */
/* in overflows and 'spikes' in a number of glyfs like 'w' */
if (ABS(CUR.F_dot_P) < 0x4000000L)
CUR.F_dot_P = 0x40000000L;
}
/**************************************************/
/* */
/* Normalize : Normer un vecteur ( U, V ) */
/* rsultat dans ( X, Y ) */
/* False si vecteur paramtre nul */
/* */
/**************************************************/
static Bool Normalize( EXEC_OPS TT_F26Dot6 U, TT_F26Dot6 V, TT_UnitVector *R)
{
TT_F26Dot6 W;
Bool S1, S2;
if (ABS(U) < 0x10000L && ABS(V) < 0x10000L)
{
U *= 0x100; /* from DavidT 05n2.diff */
V *= 0x100;
W = Norm(U, V);
if (W == 0)
{
CUR.error = TT_Err_Divide_By_Zero;
return FAILURE;
}
R->x = (TT_F2Dot14)MulDiv(U, 0x4000L, W);
R->y = (TT_F2Dot14)MulDiv(V, 0x4000L, W);
return SUCCESS;
}
W = Norm(U, V);
if (W <= 0)
{
CUR.error = TT_Err_Divide_By_Zero;
return FAILURE;
}
U = MulDiv(U, 0x4000L, W);
V = MulDiv(V, 0x4000L, W);
W = U * U + V * V;
/* Now, we want that Sqrt( W ) = $4000 */
/* Or $1000000 <= W < $1004000 */
if (U < 0)
{
U = -U;
S1 = TRUE;
}
else
S1 = FALSE;
if (V < 0)
{
V = -V;
S2 = TRUE;
}
else
S2 = FALSE;
while (W < 0x1000000L)
{
/* We need to increase W, by a minimal amount */
if (U < V)
U++;
else
V++;
W = U * U + V * V;
}
while (W >= 0x1004000L)
{
/* We need to decrease W, by a minimal amount */
if (U < V)
U--;
else
V--;
W = U * U + V * V;
}
/* Note that in various cases, we can only */
/* compute a Sqrt(W) of $3FFF, eg. U=V */
if (S1)
U = -U;
if (S2)
V = -V;
R->x = (TT_F2Dot14)U; /* Type conversion */
R->y = (TT_F2Dot14)V; /* Type conversion */
return SUCCESS;
}
/****************************************************************/
/* */
/* MANAGING THE STACK */
/* */
/* Instructions appear in the specs' order */
/* */
/****************************************************************/
/*******************************************/
/* DUP[] : Duplicate top stack element */
/* CodeRange : $20 */
static void Ins_DUP( INS_ARG )
{
args[1] = args[0];
}
/*******************************************/
/* POP[] : POPs the stack's top elt. */
/* CodeRange : $21 */
static void Ins_POP( INS_ARG )
{
/* nothing to do */
}
/*******************************************/
/* CLEAR[] : Clear the entire stack */
/* CodeRange : $22 */
static void Ins_CLEAR( INS_ARG )
{
CUR.new_top = 0;
}
/*******************************************/
/* SWAP[] : Swap the top two elements */
/* CodeRange : $23 */
static void Ins_SWAP( INS_ARG )
{
Long L;
L = args[0];
args[0] = args[1];
args[1] = L;
}
/*******************************************/
/* DEPTH[] : return the stack depth */
/* CodeRange : $24 */
static void Ins_DEPTH( INS_ARG )
{
args[0] = CUR.top;
}
/*******************************************/
/* CINDEX[] : copy indexed element */
/* CodeRange : $25 */
static void Ins_CINDEX( INS_ARG )
{
Long L;
L = args[0];
if ( (unsigned)L > CUR.args )
CUR.error = TT_Err_Invalid_Reference;
else
args[0] = CUR.stack[CUR.args - L];
}
/*******************************************/
/* MINDEX[] : move indexed element */
/* CodeRange : $26 */
static void Ins_MINDEX( INS_ARG )
{
Long L, K;
L = args[0];
if ( (unsigned)L > CUR.args)
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
K = CUR.stack[CUR.args - L];
MEM_Copy( (&CUR.stack[ CUR.args-L ]),
(&CUR.stack[ CUR.args-L+1 ]),
( L-1 ) * sizeof(Long));
CUR.stack[ CUR.args-1 ] = K;
}
/*******************************************/
/* ROLL[] : roll top three elements */
/* CodeRange : $8A */
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;
}
/****************************************************************/
/* */
/* MANAGING THE FLOW OF CONTROL */
/* */
/* Instructions appear in the specs' order */
/* */
/****************************************************************/
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;
}
/*******************************************/
/* IF[] : IF test */
/* CodeRange : $58 */
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: /* IF */
nIfs++;
break;
case 0x1b: /* ELSE */
Out = (nIfs == 1);
break;
case 0x59: /* EIF */
nIfs--;
Out = (nIfs == 0);
break;
}
} while ( Out == 0 );
}
/*******************************************/
/* ELSE[] : ELSE */
/* CodeRange : $1B */
static void Ins_ELSE( INS_ARG )
{
Int nIfs;
nIfs = 1;
do
{
if ( SKIP_Code() == FAILURE )
return;
switch (CUR.opcode)
{
case 0x58: /* IF */
nIfs++;
break;
case 0x59: /* EIF */
nIfs--;
break;
}
} while ( nIfs != 0 );
}
/*******************************************/
/* EIF[] : End IF */
/* CodeRange : $59 */
static void Ins_EIF( INS_ARG )
{
/* nothing to do */
}
/*******************************************/
/* JROT[] : Jump Relative On True */
/* CodeRange : $78 */
static void Ins_JROT( INS_ARG )
{
if (args[1] != 0)
{
CUR.IP += (Int)(args[0]);
CUR.step_ins = FALSE;
}
}
/*******************************************/
/* JMPR[] : JuMP Relative */
/* CodeRange : $1C */
static void Ins_JMPR( INS_ARG )
{
CUR.IP += (Int)(args[0]);
CUR.step_ins = FALSE;
}
/*******************************************/
/* JROF[] : Jump Relative On False */
/* CodeRange : $79 */
static void Ins_JROF( INS_ARG )
{
if (args[1] == 0)
{
CUR.IP += (Int)(args[0]);
CUR.step_ins = FALSE;
}
}
/****************************************************************/
/* */
/* LOGICAL FUNCTIONS */
/* */
/* Instructions appear in the specs' order */
/* */
/****************************************************************/
/*******************************************/
/* LT[] : Less Than */
/* CodeRange : $50 */
static void Ins_LT( INS_ARG )
{
if (args[0] < args[1])
args[0] = 1;
else
args[0] = 0;
}
/*******************************************/
/* LTEQ[] : Less Than or EQual */
/* CodeRange : $51 */
static void Ins_LTEQ( INS_ARG )
{
if (args[0] <= args[1])
args[0] = 1;
else
args[0] = 0;
}
/*******************************************/
/* GT[] : Greater Than */
/* CodeRange : $52 */
static void Ins_GT( INS_ARG )
{
if (args[0] > args[1])
args[0] = 1;
else
args[0] = 0;
}
/*******************************************/
/* GTEQ[] : Greater Than or EQual */
/* CodeRange : $53 */
static void Ins_GTEQ( INS_ARG )
{
if (args[0] >= args[1])
args[0] = 1;
else
args[0] = 0;
}
/*******************************************/
/* EQ[] : EQual */
/* CodeRange : $54 */
static void Ins_EQ( INS_ARG )
{
if (args[0] == args[1])
args[0] = 1;
else
args[0] = 0;
}
/*******************************************/
/* NEQ[] : Not EQual */
/* CodeRange : $55 */
static void Ins_NEQ( INS_ARG )
{
if (args[0] != args[1])
args[0] = 1;
else
args[0] = 0;
}
/*******************************************/
/* ODD[] : Odd */
/* CodeRange : $56 */
static void Ins_ODD( INS_ARG )
{
if((CUR_Func_round( args[0], 0L) & 127) == 64)
args[0] = 1;
else
args[0] = 0;
}
/*******************************************/
/* EVEN[] : Even */
/* CodeRange : $57 */
static void Ins_EVEN( INS_ARG )
{
if((CUR_Func_round( args[0], 0L) & 127) == 0)
args[0] = 1;
else
args[0] = 0;
}
/*******************************************/
/* AND[] : logical AND */
/* CodeRange : $5A */
static void Ins_AND( INS_ARG )
{
if (args[0] != 0 && args[1] != 0)
args[0] = 1;
else
args[0] = 0;
}
/*******************************************/
/* OR[] : logical OR */
/* CodeRange : $5B */
static void Ins_OR( INS_ARG )
{
if (args[0] != 0 || args[1] != 0)
args[0] = 1;
else
args[0] = 0;
}
/*******************************************/
/* NOT[] : logical NOT */
/* CodeRange : $5C */
static void Ins_NOT( INS_ARG )
{
if (args[0] != 0)
args[0] = 0;
else
args[0] = 1;
}
/****************************************************************/
/* */
/* ARITHMETIC AND MATH INSTRUCTIONS */
/* */
/* Instructions appear in the specs' order */
/* */
/****************************************************************/
/*******************************************/
/* ADD[] : ADD */
/* CodeRange : $60 */
static void Ins_ADD( INS_ARG )
{
args[0] += args[1];
}
/*******************************************/
/* SUB[] : SUBstract */
/* CodeRange : $61 */
static void Ins_SUB( INS_ARG )
{
args[0] -= args[1];
}
/*******************************************/
/* DIV[] : DIVide */
/* CodeRange : $62 */
static void Ins_DIV( INS_ARG )
{
if (args[1] == 0)
{
CUR.error = TT_Err_Divide_By_Zero;
return;
}
args[0] = MulDiv_Round(args[0], 64L, args[1]);
}
/*******************************************/
/* MUL[] : MULtiply */
/* CodeRange : $63 */
static void Ins_MUL( INS_ARG )
{
args[0] = MulDiv_Round(args[0], args[1], 64L);
}
/*******************************************/
/* ABS[] : ABSolute value */
/* CodeRange : $64 */
static void Ins_ABS( INS_ARG )
{
args[0] = ABS(args[0]);
}
/*******************************************/
/* NEG[] : NEGate */
/* CodeRange : $65 */
static void Ins_NEG( INS_ARG )
{
args[0] = -args[0];
}
/*******************************************/
/* FLOOR[] : FLOOR */
/* CodeRange : $66 */
static void Ins_FLOOR( INS_ARG )
{
args[0] &= -64;
}
/*******************************************/
/* CEILING[] : CEILING */
/* CodeRange : $67 */
static void Ins_CEILING( INS_ARG )
{
args[0] = (args[0] + 63) & (-64);
}
/*******************************************/
/* MAX[] : MAXimum */
/* CodeRange : $68 */
static void Ins_MAX( INS_ARG )
{
if (args[1] > args[0])
args[0] = args[1];
}
/*******************************************/
/* MIN[] : MINimum */
/* CodeRange : $69 */
static void Ins_MIN( INS_ARG )
{
if (args[1] < args[0])
args[0] = args[1];
}
/****************************************************************/
/* */
/* COMPENSATING FOR THE ENGINE CHARACTERISTICS */
/* */
/* Instructions appear in the specs' order */
/* */
/****************************************************************/
/*******************************************/
/* ROUND[ab] : ROUND value */
/* CodeRange : $68-$6B */
static void Ins_ROUND( INS_ARG )
{
args[0] = CUR_Func_round( args[0],
CUR.metrics.compensations[ CUR.opcode-0x68 ]);
}
/*******************************************/
/* NROUND[ab]: No ROUNDing of value */
/* CodeRange : $6C-$6F */
static void Ins_NROUND( INS_ARG )
{
args[0] = Round_None( EXEC_ARGS
args[0],
CUR.metrics.compensations[ CUR.opcode-0x6C ]);
}
/****************************************************************/
/* */
/* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS */
/* */
/* Instructions appear in the specs' order */
/* */
/****************************************************************/
/*******************************************/
/* FDEF[] : Function DEFinition */
/* CodeRange : $2C */
static void Ins_FDEF( INS_ARG )
{
TDefRecord *pRec;
if ( args[0] < 0 || args[0] >= CUR.numFDefs)
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
pRec = &CUR.FDefs[args[0]];
pRec->Range = CUR.curRange;
pRec->Opc = (Byte)(args[0]);
pRec->Start = CUR.IP + 1;
pRec->Active = TRUE;
/* now skip the whole function definition */
/* we don't allow nested IDEFS & FDEFs */
while ( SKIP_Code() == SUCCESS )
{
switch (CUR.opcode)
{
case 0x89: /* IDEF */
case 0x2c: /* FDEF */
CUR.error = TT_Err_Nested_DEFS;
return;
case 0x2d: /* ENDF */
return;
}
}
}
/*******************************************/
/* ENDF[] : END Function definition */
/* CodeRange : $2D */
static void Ins_ENDF( INS_ARG )
{
TCallRecord *pRec;
if (CUR.callTop <= 0) { /* We encountered an ENDF without a call */
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 );
/* Loop the current function */
/* exit the current call frame */
/* NOTE : When the last intruction of a program */
/* is a CALL or LOOPCALL, the return address */
/* is always out of the code range. This is */
/* valid address, and is why we do not test */
/* the result of Ins_Goto_CodeRange here !! */
}
/*******************************************/
/* CALL[] : CALL function */
/* CodeRange : $2B */
static void Ins_CALL( INS_ARG )
{
TCallRecord *pCrec;
if ( args[0] < 0 || args[0] >= CUR.numFDefs ||
!CUR.FDefs[args[0]].Active)
{
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 = CUR.FDefs[args[0]].Start;
CUR.callTop++;
INS_Goto_CodeRange( CUR.FDefs[args[0]].Range,
CUR.FDefs[args[0]].Start);
CUR.step_ins = FALSE;
}
/*******************************************/
/* LOOPCALL[]: LOOP and CALL function */
/* CodeRange : $2A */
static void Ins_LOOPCALL( INS_ARG )
{
TCallRecord *pTCR;
if ( args[1] < 0 || args[1] >= CUR.numFDefs ||
!CUR.FDefs[args[1]].Active)
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
if (CUR.callTop >= CUR.callSize)
{
CUR.error = TT_Err_Stack_Overflow;
return;
}
if (args[0] > 0)
{
pTCR = &CUR.callStack[CUR.callTop];
pTCR->Caller_Range = CUR.curRange;
pTCR->Caller_IP = CUR.IP + 1;
pTCR->Cur_Count = (Int)(args[0]);
pTCR->Cur_Restart = CUR.FDefs[args[1]].Start;
CUR.callTop++;
INS_Goto_CodeRange( CUR.FDefs[args[1]].Range,
CUR.FDefs[args[1]].Start );
CUR.step_ins = FALSE;
}
}
/*******************************************/
/* IDEF[] : Instruction DEFinition */
/* CodeRange : $89 */
static void Ins_IDEF( INS_ARG )
{
Int A;
TDefRecord *pTDR;
A = 0;
while (A < CUR.numIDefs)
{
pTDR = &CUR.IDefs[A];
if ( pTDR->Active == 0 )
{
pTDR->Opc = (Byte)(args[0]);
pTDR->Start = CUR.IP + 1;
pTDR->Range = CUR.curRange;
pTDR->Active = TRUE;
A = CUR.numIDefs;
/* now skip the whole function definition */
/* we don't allow nested IDEFS & FDEFs */
while ( SKIP_Code() == SUCCESS )
{
switch (CUR.opcode)
{
case 0x89: /* IDEF */
case 0x2c: /* FDEF */
CUR.error = TT_Err_Nested_DEFS;
return;
case 0x2d: /* ENDF */
return;
}
}
}
else
A++;
}
}
/****************************************************************/
/* */
/* PUSHING DATA ONTO THE INTERPRETER STACK */
/* */
/* Instructions appear in the specs' order */
/* */
/****************************************************************/
/*******************************************/
/* NPUSHB[] : PUSH N Bytes */
/* CodeRange : $40 */
static void Ins_NPUSHB( INS_ARG )
{
Int L, K;
L = (Int)CUR.code[ CUR.IP+1 ];
if (CUR.top + L > CUR.stackSize)
{
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;
}
/*******************************************/
/* NPUSHW[] : PUSH N Words */
/* CodeRange : $41 */
static void Ins_NPUSHW( INS_ARG )
{
Int L, K;
L = (Int)CUR.code[ CUR.IP+1 ];
if ( CUR.top+L > CUR.stackSize )
{
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;
}
/*******************************************/
/* PUSHB[abc]: PUSH Bytes */
/* CodeRange : $B0-$B7 */
static void Ins_PUSHB( INS_ARG )
{
Int L, K;
L = ((Int)CUR.opcode - 0xB0 + 1);
if ( CUR.top+L > CUR.stackSize )
{
CUR.error = TT_Err_Stack_Overflow;
return;
}
for (K = 1; K <= L; K++)
args[ K-1 ] = CUR.code[ CUR.IP+K ];
}
/*******************************************/
/* PUSHW[abc]: PUSH Words */
/* CodeRange : $B8-$BF */
static void Ins_PUSHW( INS_ARG )
{
Int L, K;
L = CUR.opcode - 0xB8 + 1;
if ( CUR.top+L > CUR.stackSize )
{
CUR.error = TT_Err_Stack_Overflow;
return;
}
CUR.IP++;
for (K = 0; K < L; K++)
args[K] = GET_ShortIns();
CUR.step_ins = FALSE;
}
/****************************************************************/
/* */
/* MANAGING THE STORAGE AREA */
/* */
/* Instructions appear in the specs' order */
/* */
/****************************************************************/
/*******************************************/
/* RS[] : Read Store */
/* CodeRange : $43 */
static void Ins_RS( INS_ARG )
{
if ((unsigned)args[0] >= CUR.storeSize)
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
args[0] = CUR.storage[args[0]];
}
/*******************************************/
/* WS[] : Write Store */
/* CodeRange : $42 */
static void Ins_WS( INS_ARG )
{
if ( (unsigned)args[0] >= CUR.storeSize )
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
CUR.storage[args[0]] = args[1];
}
/*******************************************/
/* WCVTP[] : Write CVT in Pixel units */
/* CodeRange : $44 */
static void Ins_WCVTP( INS_ARG )
{
if ( (unsigned)args[0] >= CUR.cvtSize )
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
CUR.cvt[args[0]] = args[1];
}
/*******************************************/
/* WCVTF[] : Write CVT in FUnits */
/* CodeRange : $70 */
static void Ins_WCVTF( INS_ARG )
{
if ( (unsigned)args[0] >= CUR.cvtSize )
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
CUR.cvt[args[0]] = MulDiv_Round(args[1], CUR.scale1, CUR.scale2);
}
/*******************************************/
/* RCVT[] : Read CVT */
/* CodeRange : $45 */
static void Ins_RCVT( INS_ARG )
{
if ( (unsigned)args[0] >= CUR.cvtSize)
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
args[0] = CUR.cvt[args[0]];
}
/****************************************************************/
/* */
/* MANAGING THE GRAPHICS STATE */
/* */
/* Instructions appear in the specs' order */
/* */
/****************************************************************/
/*******************************************/
/* SVTCA[a] : Set F and P vectors to axis */
/* CodeRange : $00-$01 */
static void Ins_SVTCA( INS_ARG )
{
Short A, B;
if (CUR.opcode & 1)
A = 0x4000;
else
A = 0;
B = A ^ 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();
}
/*******************************************/
/* SPVTCA[a] : Set PVector to Axis */
/* CodeRange : $02-$03 */
static void Ins_SPVTCA( INS_ARG )
{
Short A, B;
if (CUR.opcode & 1)
A = 0x4000;
else
A = 0;
B = A ^ 0x4000;
CUR.GS.projVector.x = A;
CUR.GS.dualVector.x = A;
CUR.GS.projVector.y = B;
CUR.GS.dualVector.y = B;
COMPUTE_Funcs();
}
/*******************************************/
/* SFVTCA[a] : Set FVector to Axis */
/* CodeRange : $04-$05 */
static void Ins_SFVTCA( INS_ARG )
{
Short A, B;
if (CUR.opcode & 1)
A = 0x4000;
else
A = 0;
B = A ^ 0x4000;
CUR.GS.freeVector.x = A;
CUR.GS.freeVector.y = B;
COMPUTE_Funcs();
}
static Bool Ins_SxVTL( EXEC_OPS Int aIdx1,
Int aIdx2,
Int aOpc,
TT_UnitVector *Vec)
{
Long A, B, C;
if ( (unsigned)aIdx2 >= CUR.zp1.n ||
(unsigned)aIdx1 >= CUR.zp2.n )
{
CUR.error = TT_Err_Invalid_Reference;
return FAILURE;
}
A = CUR.zp1.cur_x[aIdx2] - CUR.zp2.cur_x[aIdx1];
B = CUR.zp1.cur_y[aIdx2] - CUR.zp2.cur_y[aIdx1];
if ((aOpc & 1) != 0)
{
C = B; /* CounterClockwise rotation */
B = A;
A = -C;
}
if ( NORMalize(A, B, Vec) == FAILURE )
{
/* When the vector is too small, or zero ! */
CUR.error = TT_Err_Ok;
Vec->x = 0x4000;
Vec->y = 0;
}
return SUCCESS;
}
/*******************************************/
/* SPVTL[a] : Set PVector to Line */
/* CodeRange : $06-$07 */
static void Ins_SPVTL( INS_ARG )
{
if ( INS_SxVTL( args[1],
args[0],
CUR.opcode,
&CUR.GS.projVector) == FAILURE )
return;
CUR.GS.dualVector = CUR.GS.projVector;
COMPUTE_Funcs();
}
/*******************************************/
/* SFVTL[a] : Set FVector to Line */
/* CodeRange : $08-$09 */
static void Ins_SFVTL( INS_ARG )
{
if ( INS_SxVTL( (Int)(args[1]),
(Int)(args[0]),
CUR.opcode,
&CUR.GS.freeVector) == FAILURE )
return;
COMPUTE_Funcs();
}
/*******************************************/
/* SFVTPV[] : Set FVector to PVector */
/* CodeRange : $0E */
static void Ins_SFVTPV( INS_ARG )
{
CUR.GS.freeVector = CUR.GS.projVector;
COMPUTE_Funcs();
}
/*******************************************/
/* SDPVTL[a] : Set Dual PVector to Line */
/* CodeRange : $86-$87 */
static void Ins_SDPVTL( INS_ARG )
{
Long A, B, C;
Long p1, p2; /* was Int in pas type ERROR */
p1 = args[1];
p2 = args[0];
if ( (unsigned)p2 >= CUR.zp1.n ||
(unsigned)p1 >= CUR.zp2.n )
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
A = CUR.zp1.org_x[p2] - CUR.zp2.org_x[p1];
B = CUR.zp1.org_y[p2] - CUR.zp2.org_y[p1];
if ((CUR.opcode & 1) != 0)
{
C = B; /* CounterClockwise rotation */
B = A;
A = -C;
}
if ( NORMalize( A, B, &CUR.GS.dualVector ) == FAILURE )
return;
A = CUR.zp1.cur_x[p2] - CUR.zp2.cur_x[p1];
B = CUR.zp1.cur_y[p2] - CUR.zp2.cur_y[p1];
if ( (CUR.opcode & 1) != 0 )
{
C = B; /* CounterClockwise rotation */
B = A;
A = -C;
}
if ( NORMalize(A, B, &CUR.GS.projVector) == FAILURE )
return;
COMPUTE_Funcs();
}
/*******************************************/
/* SPVFS[] : Set PVector From Stack */
/* CodeRange : $0A */
static void Ins_SPVFS( INS_ARG )
{
Short S;
Long X, Y;
/* Only use low 16bits, then sign extend */
S = (Short)args[1];
Y = (Long)S;
S = (Short)args[0];
X = (Long)S;
if ( NORMalize(X, Y, &CUR.GS.projVector) == FAILURE )
return;
CUR.GS.dualVector = CUR.GS.projVector;
COMPUTE_Funcs();
}
/*******************************************/
/* SFVFS[] : Set FVector From Stack */
/* CodeRange : $0B */
static void Ins_SFVFS( INS_ARG )
{
Short S;
Long X, Y;
/* Only use low 16bits, then sign extend */
S = (Short)args[1];
Y = (Long)S;
S = (Short)args[0];
X = S;
if ( NORMalize(X, Y, &CUR.GS.freeVector) == FAILURE )
return;
COMPUTE_Funcs();
}
/*******************************************/
/* GPV[] : Get Projection Vector */
/* CodeRange : $0C */
static void Ins_GPV( INS_ARG )
{
args[0] = CUR.GS.projVector.x;
args[1] = CUR.GS.projVector.y;
}
/*******************************************/
/* GFV[] : Get Freedom Vector */
/* CodeRange : $0D */
static void Ins_GFV( INS_ARG )
{
args[0] = CUR.GS.freeVector.x;
args[1] = CUR.GS.freeVector.y;
}
/*******************************************/
/* SRP0[] : Set Reference Point 0 */
/* CodeRange : $10 */
static void Ins_SRP0( INS_ARG )
{
CUR.GS.rp0 = (Int)(args[0]);
}
/*******************************************/
/* SRP1[] : Set Reference Point 1 */
/* CodeRange : $11 */
static void Ins_SRP1( INS_ARG )
{
CUR.GS.rp1 = (Int)(args[0]);
}
/*******************************************/
/* SRP2[] : Set Reference Point 2 */
/* CodeRange : $12 */
static void Ins_SRP2( INS_ARG )
{
CUR.GS.rp2 = (Int)(args[0]);
}
/*******************************************/
/* SZP0[] : Set Zone Pointer 0 */
/* CodeRange : $13 */
static void Ins_SZP0( INS_ARG )
{
switch (args[0])
{
case 0:
CUR.zp0 = CUR.twilight;
break;
case 1:
CUR.zp0 = CUR.pts;
break;
default:
CUR.error = TT_Err_Invalid_Reference;
return;
break;
}
CUR.GS.gep0 = (Int)(args[0]);
}
/*******************************************/
/* SZP1[] : Set Zone Pointer 1 */
/* CodeRange : $14 */
static void Ins_SZP1( INS_ARG )
{
switch (args[0])
{
case 0:
CUR.zp1 = CUR.twilight;
break;
case 1:
CUR.zp1 = CUR.pts;
break;
default:
CUR.error = TT_Err_Invalid_Reference;
return;
}
CUR.GS.gep1 = (Int)(args[0]);
}
/*******************************************/
/* SZP2[] : Set Zone Pointer 2 */
/* CodeRange : $15 */
static void Ins_SZP2( INS_ARG )
{
switch (args[0])
{
case 0:
CUR.zp2 = CUR.twilight;
break;
case 1:
CUR.zp2 = CUR.pts;
break;
default:
CUR.error = TT_Err_Invalid_Reference;
return;
}
CUR.GS.gep2 = (Int)(args[0]);
}
/*******************************************/
/* SZPS[] : Set Zone Pointers */
/* CodeRange : $16 */
static void Ins_SZPS( INS_ARG )
{
switch (args[0])
{
case 0:
CUR.zp0 = CUR.twilight;
break;
case 1:
CUR.zp0 = CUR.pts;
break;
default:
CUR.error = TT_Err_Invalid_Reference;
return;
}
CUR.zp1 = CUR.zp0;
CUR.zp2 = CUR.zp0;
CUR.GS.gep0 = (Int)(args[0]);
CUR.GS.gep1 = (Int)(args[0]);
CUR.GS.gep2 = (Int)(args[0]);
}
/*******************************************/
/* RTHG[] : Round To Half Grid */
/* CodeRange : $19 */
static void Ins_RTHG( INS_ARG )
{
CUR.GS.round_state = TT_Round_To_Half_Grid;
CUR.func_round = (TRound_Function)Round_To_Half_Grid;
}
/*******************************************/
/* RTG[] : Round To Grid */
/* CodeRange : $18 */
static void Ins_RTG( INS_ARG )
{
CUR.GS.round_state = TT_Round_To_Grid;
CUR.func_round = (TRound_Function)Round_To_Grid;
}
/*******************************************/
/* RTDG[] : Round To Double Grid */
/* CodeRange : $3D */
static void Ins_RTDG( INS_ARG )
{
CUR.GS.round_state = TT_Round_To_Double_Grid;
CUR.func_round = (TRound_Function)Round_To_Double_Grid;
}
/*******************************************/
/* RUTG[] : Round Up To Grid */
/* CodeRange : $7C */
static void Ins_RUTG( INS_ARG )
{
CUR.GS.round_state = TT_Round_Up_To_Grid;
CUR.func_round = (TRound_Function)Round_Up_To_Grid;
}
/*******************************************/
/* RDTG[] : Round Down To Grid */
/* CodeRange : $7D */
static void Ins_RDTG( INS_ARG )
{
CUR.GS.round_state = TT_Round_Down_To_Grid;
CUR.func_round = (TRound_Function)Round_Down_To_Grid;
}
/*******************************************/
/* ROFF[] : Round OFF */
/* CodeRange : $7A */
static void Ins_ROFF( INS_ARG )
{
CUR.GS.round_state = TT_Round_Off;
CUR.func_round = (TRound_Function)Round_None;
}
/*******************************************/
/* SROUND[] : Super ROUND */
/* CodeRange : $76 */
static void Ins_SROUND( INS_ARG )
{
SET_SuperRound( 0x4000L, args[0] );
CUR.GS.round_state = TT_Round_Super;
CUR.func_round = (TRound_Function)Round_Super;
}
/*******************************************/
/* S45ROUND[]: Super ROUND 45 degrees */
/* CodeRange : $77 */
static void Ins_S45ROUND( INS_ARG )
{
SET_SuperRound( 0x00002D41, args[0] );
CUR.GS.round_state = TT_Round_Super_45;
CUR.func_round = (TRound_Function)Round_Super_45;
}
/*******************************************/
/* SLOOP[] : Set LOOP variable */
/* CodeRange : $17 */
static void Ins_SLOOP( INS_ARG )
{
CUR.GS.loop = args[0];
}
/*******************************************/
/* SMD[] : Set Minimum Distance */
/* CodeRange : $1A */
static void Ins_SMD( INS_ARG )
{
CUR.GS.minimum_distance = args[0];
}
/*******************************************/
/* INSTCTRL[]: INSTruction ConTRol */
/* CodeRange : $8e */
static void Ins_INSTCTRL( INS_ARG )
{
Long K, L;
K = args[1];
L = args[0];
if (K < 1 || K > 2)
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
if( L != 0 )
L = K;
CUR.GS.instruct_control =
(Int)((CUR.GS.instruct_control & (~K)) | L);
}
/*******************************************/
/* SCANCTRL[]: SCAN ConTRol */
/* CodeRange : $85 */
static void Ins_SCANCTRL( INS_ARG )
{
Int A;
/* Get Threshold */
A = (Int)(args[0] & 0xFF);
if (A == 0xFF)
{
CUR.GS.scan_control = TRUE;
return;
}
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;
}
/*******************************************/
/* SCANTYPE[]: SCAN TYPE */
/* CodeRange : $8D */
static void Ins_SCANTYPE( INS_ARG )
{
/* For compatibility with future enhancements, */
/* we must ignore new modes */
if (args[0] >= 0 && args[0] <= 5)
{
if (args[0] == 3)
args[0] = 2;
CUR.GS.scan_type = (Int)args[0];
}
}
/**********************************************/
/* SCVTCI[] : Set Control Value Table Cut In */
/* CodeRange : $1D */
static void Ins_SCVTCI( INS_ARG )
{
CUR.GS.control_value_cutin = (TT_F26Dot6)args[0];
}
/**********************************************/
/* SSWCI[] : Set Single Width Cut In */
/* CodeRange : $1E */
static void Ins_SSWCI( INS_ARG )
{
CUR.GS.single_width_cutin = (TT_F26Dot6)args[0];
}
/**********************************************/
/* SSW[] : Set Single Width */
/* CodeRange : $1F */
static void Ins_SSW( INS_ARG )
{
CUR.GS.single_width_value = (TT_F26Dot6)args[0];
}
/**********************************************/
/* FLIPON[] : Set Auto_flip to On */
/* CodeRange : $4D */
static void Ins_FLIPON( INS_ARG )
{
CUR.GS.auto_flip = TRUE;
}
/**********************************************/
/* FLIPOFF[] : Set Auto_flip to Off */
/* CodeRange : $4E */
static void Ins_FLIPOFF( INS_ARG )
{
CUR.GS.auto_flip = FALSE;
}
/**********************************************/
/* SANGW[] : Set Angle Weigth */
/* CodeRange : $7E */
static void Ins_SANGW( INS_ARG )
{
/* instruction not supported anymore */
}
/**********************************************/
/* SDB[] : Set Delta Base */
/* CodeRange : $5E */
static void Ins_SDB( INS_ARG )
{
CUR.GS.delta_base = (Int)args[0];
}
/**********************************************/
/* SDS[] : Set Delta Shift */
/* CodeRange : $5F */
static void Ins_SDS( INS_ARG )
{
CUR.GS.delta_shift = (Int)args[0];
}
/**********************************************/
/* GC[a] : Get Coordinate projected onto */
/* CodeRange : $46-$47 */
/* BULLSHIT : Measures from the original glyph must to be taken */
/* along the dual projection vector !! */
static void Ins_GC( INS_ARG )
{
Long L;
L = args[0];
if ( (unsigned)L >= CUR.zp2.n)
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
switch (CUR.opcode & 1)
{
case 0:
L = CUR_Func_project( CUR.zp2.cur_x[L],
CUR.zp2.cur_y[L]);
break;
case 1:
L = CUR_Func_dualproj( CUR.zp2.org_x[L],
CUR.zp2.org_y[L]);
break;
}
args[0] = L;
}
/**********************************************/
/* SCFS[] : Set Coordinate From Stack */
/* CodeRange : $48 */
/* */
/* Formule : */
/* */
/* OA := OA + ( value - OA.p )/( f.p ) x f */
/* */
static void Ins_SCFS( INS_ARG )
{
Long K;
Int L;
L = (Int)args[0];
if ( args[0] < 0 || args[0] >= CUR.zp2.n)
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
K = CUR_Func_project( CUR.zp2.cur_x[L],
CUR.zp2.cur_y[L]);
CUR_Func_move(&CUR.zp2, L, args[1] - K);
/* not part of the specs, but here for safety */
if (CUR.GS.gep2 == 0)
{
CUR.zp2.org_x[L] = CUR.zp2.cur_x[L];
CUR.zp2.org_y[L] = CUR.zp2.cur_y[L];
}
}
/**********************************************/
/* MD[a] : Measure Distance */
/* CodeRange : $49-$4A */
/* BULLSHIT : Measure taken in the original glyph must be along */
/* the dual projection vector */
/* Second BULLSHIT : Flag attributions are inverted !! */
/* 0 => measure distance in original outline */
/* 1 => measure distance in grid-fitted outline */
static void Ins_MD( INS_ARG )
{
Long K, L;
TT_F26Dot6 D;
K = args[1];
L = args[0];
if( (unsigned)args[0] >= CUR.zp2.n ||
(unsigned)args[1] >= CUR.zp1.n )
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
if (CUR.opcode & 1)
D = CUR_Func_project( CUR.zp2.cur_x[L] - CUR.zp1.cur_x[K],
CUR.zp2.cur_y[L] - CUR.zp1.cur_y[K]);
else
D = CUR_Func_dualproj( CUR.zp2.org_x[L] - CUR.zp1.org_x[K],
CUR.zp2.org_y[L] - CUR.zp1.org_y[K]);
args[0] = D;
}
/**********************************************/
/* MPPEM[] : Measure Pixel Per EM */
/* CodeRange : $4B */
static void Ins_MPPEM( INS_ARG )
{
args[0] = CUR_Ppem();
}
/**********************************************/
/* MPS[] : Measure PointSize */
/* CodeRange : $4C */
static void Ins_MPS( INS_ARG )
{
args[0] = CUR.metrics.pointSize;
}
/****************************************************************/
/* */
/* MANAGING OUTLINES */
/* */
/* Instructions appear in the specs' order */
/* */
/****************************************************************/
/**********************************************/
/* FLIPPT[] : FLIP PoinT */
/* CodeRange : $80 */
static void Ins_FLIPPT( INS_ARG )
{
Long point;
if (CUR.top < CUR.GS.loop)
{
CUR.error = TT_Err_Too_Few_Arguments;
return;
}
while (CUR.GS.loop > 0)
{
CUR.args--;
point = CUR.stack[CUR.args];
if (point < 0 || point >= CUR.pts.n)
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
CUR.pts.touch[point] ^= TT_Flag_On_Curve;
CUR.GS.loop--;
}
CUR.GS.loop = 1;
CUR.new_top = CUR.args;
}
/**********************************************/
/* FLIPRGON[]: FLIP RanGe ON */
/* CodeRange : $81 */
static void Ins_FLIPRGON( INS_ARG )
{
Long I, K, L;
K = args[1];
L = args[0];
if ( (unsigned)K >= CUR.pts.n ||
(unsigned)L >= CUR.pts.n )
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
for (I = L; I <= K; I++)
CUR.pts.touch[I] |= TT_Flag_On_Curve;
}
/**********************************************/
/* FLIPRGOFF : FLIP RanGe OFF */
/* CodeRange : $82 */
static void Ins_FLIPRGOFF( INS_ARG )
{
Long I, K, L;
K = args[1];
L = args[0];
if ( (unsigned)K >= CUR.pts.n ||
(unsigned)L >= CUR.pts.n )
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
for (I = L; I <= K; I++)
CUR.pts.touch[I] &= ~TT_Flag_On_Curve;
}
static void Compute_Point_Displacement( EXEC_OPS
PCoordinates x,
PCoordinates y,
PVecRecord zone,
Int* refp)
{
TVecRecord zp;
Int p;
TT_F26Dot6 d;
if (CUR.opcode & 1)
{
zp = CUR.zp0;
p = CUR.GS.rp1;
}
else
{
zp = CUR.zp1;
p = CUR.GS.rp2;
}
*zone = zp;
*refp = p;
d = CUR_Func_project( zp.cur_x[p] - zp.org_x[p],
zp.cur_y[p] - zp.org_y[p]);
*x = MulDiv_Round(d, (Long)CUR.GS.freeVector.x * 0x10000L, CUR.F_dot_P);
*y = MulDiv_Round(d, (Long)CUR.GS.freeVector.y * 0x10000L, CUR.F_dot_P);
}
/****************************************************
* Move_Zp2_Point
*
*
****************************************************/
static void Move_Zp2_Point( EXEC_OPS
Long point,
TT_F26Dot6 dx,
TT_F26Dot6 dy)
{
if (CUR.GS.freeVector.x != 0)
{
CUR.zp2.cur_x[point] += dx;
CUR.zp2.touch[point] |= TT_Flag_Touched_X;
}
if (CUR.GS.freeVector.y != 0)
{
CUR.zp2.cur_y[point] += dy;
CUR.zp2.touch[point] |= TT_Flag_Touched_Y;
}
}
/**********************************************/
/* SHP[a] : SHift Point by the last point */
/* CodeRange : $32-33 */
static void Ins_SHP( INS_ARG )
{
TVecRecord zp;
Int refp;
TT_F26Dot6 dx,
dy;
Long point;
if (CUR.top < CUR.GS.loop)
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
COMPUTE_Point_Displacement(&dx, &dy, &zp, &refp);
while (CUR.GS.loop > 0)
{
CUR.args--;
point = CUR.stack[CUR.args];
if ( (unsigned)point >= CUR.zp2.n)
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
MOVE_Zp2_Point(point, dx, dy);
CUR.GS.loop--;
}
CUR.GS.loop = 1;
CUR.new_top = CUR.args;
}
/**********************************************/
/* SHC[a] : SHift Contour */
/* CodeRange : $34-35 */
static void Ins_SHC( INS_ARG )
{
TVecRecord zp;
Int refp;
TT_F26Dot6 dx,
dy;
Long contour, i;
Int first_point, last_point;
contour = args[0];
if ( (unsigned)args[0] >= CUR.numContours)
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
COMPUTE_Point_Displacement(&dx, &dy, &zp, &refp);
if (contour == 0)
first_point = 0;
else
first_point = CUR.endContours[contour - 1] + 1;
last_point = CUR.endContours[contour];
for (i = first_point; i <= last_point; i++)
{
if (zp.cur_x != CUR.zp2.cur_x || refp != i)
MOVE_Zp2_Point(i, dx, dy);
}
}
/**********************************************/
/* SHZ[a] : SHift Zone */
/* CodeRange : $36-37 */
static void Ins_SHZ( INS_ARG )
{
TVecRecord zp;
Int refp;
TT_F26Dot6 dx,
dy;
Int last_point;
Long i;
if ( (unsigned)args[0] > 1)
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
COMPUTE_Point_Displacement(&dx, &dy, &zp, &refp);
last_point = zp.n - 1;
for (i = 0; i <= last_point; i++)
{
if (zp.cur_x != CUR.zp2.cur_x || refp != i)
MOVE_Zp2_Point(i, dx, dy);
}
}
/**********************************************/
/* SHPIX[] : SHift points by a PIXel amount */
/* CodeRange : $38 */
static void Ins_SHPIX( INS_ARG )
{
TT_F26Dot6 dx, dy;
Long point;
if (CUR.top < CUR.GS.loop)
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
dx = MulDiv_Round( args[0],
(Long)CUR.GS.freeVector.x * 0x10000L,
CUR.F_dot_P);
dy = MulDiv_Round( args[0],
(Long)CUR.GS.freeVector.y * 0x10000L,
CUR.F_dot_P);
while (CUR.GS.loop > 0)
{
CUR.args--;
point = CUR.stack[CUR.args];
if ( (unsigned)point >= CUR.zp2.n)
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
MOVE_Zp2_Point(point, dx, dy);
CUR.GS.loop--;
}
CUR.GS.loop = 1;
CUR.new_top = CUR.args;
}
/**********************************************/
/* MSIRP[a] : Move Stack Indirect Relative */
/* CodeRange : $3A-$3B */
static void Ins_MSIRP( INS_ARG )
{
Int point;
TT_F26Dot6 distance;
point = (Int)args[0];
if ( (unsigned)args[0] >= CUR.zp1.n)
{
CUR.error = TT_Err_Invalid_Reference;
return;
/* XXXX Is there some undocumented feature while in the */
/* twilight zone ?? */
}
distance = CUR_Func_project( CUR.zp1.cur_x[point] -
CUR.zp0.cur_x[CUR.GS.rp0],
CUR.zp1.cur_y[point] -
CUR.zp0.cur_y[CUR.GS.rp0]);
/* Davep is point int or long in func call was set from PStorage */
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;
}
/**********************************************/
/* MDAP[a] : Move Direct Absolute Point */
/* CodeRange : $2E-$2F */
static void Ins_MDAP( INS_ARG )
{
Int point;
TT_F26Dot6 cur_dist,
distance;
point = (Int)args[0];
if ( (unsigned)args[0] >= CUR.zp0.n)
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
/* XXXX Is there some undocumented feature while in the */
/* twilight zone ?? */
if ((CUR.opcode & 1) != 0)
{
cur_dist = CUR_Func_project( CUR.zp0.cur_x[point],
CUR.zp0.cur_y[point]);
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;
}
/**********************************************/
/* MIAP[a] : Move Indirect Absolute Point */
/* CodeRange : $3E-$3F */
static void Ins_MIAP( INS_ARG )
{
Int cvtEntry, point;
TT_F26Dot6 distance,
org_dist;
cvtEntry = (Int)args[1];
point = (Int)args[0];
if ( (unsigned)args[0] >= CUR.zp0.n ||
(unsigned)args[1] >= CUR.cvtSize )
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
/* Undocumented : */
/* */
/* The behaviour of an MIAP instruction is quite */
/* different when used in the twilight zone. */
/* */
/* First, no control value cutin test is performed */
/* as it would fail anyway. Second, the original */
/* point, i.e. (org_x,org_y) of zp0.point, is set */
/* to the absolute, unrounded, distance found in */
/* the CVT. */
/* */
/* This is used in the CVT programs of the Microsoft */
/* fonts Arial, Times, etc.., in order to re-adjust */
/* some key font heights. It allows the use of the */
/* IP instruction in the twilight zone, which */
/* otherwise would be "illegal" per se the specs :) */
/* */
/* We implement it with a special sequence for the */
/* twilight zone. This is a bad hack, but it seems */
/* to work.. */
/* - David */
distance = CUR.cvt[cvtEntry];
if (CUR.GS.gep0 == 0) /* If in twilight zone */
{
CUR.zp0.org_x[point] = MulDiv_Round( CUR.GS.freeVector.x,
distance, 0x4000L);
CUR.zp0.cur_x[point] = CUR.zp0.org_x[point];
CUR.zp0.org_y[point] = MulDiv_Round( CUR.GS.freeVector.y,
distance,
0x4000L);
CUR.zp0.cur_y[point] = CUR.zp0.org_y[point];
}
org_dist = CUR_Func_project( CUR.zp0.cur_x[point],
CUR.zp0.cur_y[point]);
if ((CUR.opcode & 1) != 0) /* rounding and control cutin flag */
{
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;
}
/**********************************************/
/* MDRP[abcde] : Move Direct Relative Point */
/* CodeRange : $C0-$DF */
static void Ins_MDRP( INS_ARG )
{
Int point;
TT_F26Dot6 distance,
org_dist;
point = (Int)args[0];
if ( (unsigned)args[0] >= CUR.zp1.n)
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
/* XXXX Is there some undocumented feature while in the */
/* twilight zone ?? */
org_dist = CUR_Func_dualproj( CUR.zp1.org_x[point] -
CUR.zp0.org_x[CUR.GS.rp0],
CUR.zp1.org_y[point] -
CUR.zp0.org_y[CUR.GS.rp0] );
/* single width cutin test */
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;
}
/* round flag */
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]);
/* minimum distance flag */
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;
}
}
}
/* now move the point */
org_dist = CUR_Func_project( CUR.zp1.cur_x[point] -
CUR.zp0.cur_x[CUR.GS.rp0],
CUR.zp1.cur_y[point] -
CUR.zp0.cur_y[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;
}
/**********************************************/
/* MIRP[abcde] : Move Indirect Relative Point */
/* CodeRange : $E0-$FF */
static void Ins_MIRP( INS_ARG )
{
Int point,
cvtEntry;
TT_F26Dot6 cvt_dist,
distance,
cur_dist,
org_dist;
point = (Int)args[0];
cvtEntry = (Int)args[1];
if ( (unsigned)args[0] >= CUR.zp1.n ||
(unsigned)args[1] >= CUR.cvtSize )
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
cvt_dist = CUR.cvt[cvtEntry];
/* single width test */
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;
}
/* XXXX Is there some undocumented feature while in the */
/* twilight zone ?? */
org_dist = CUR_Func_dualproj( CUR.zp1.org_x[point] -
CUR.zp0.org_x[CUR.GS.rp0],
CUR.zp1.org_y[point] -
CUR.zp0.org_y[CUR.GS.rp0]);
cur_dist = CUR_Func_project( CUR.zp1.cur_x[point] -
CUR.zp0.cur_x[CUR.GS.rp0],
CUR.zp1.cur_y[point] -
CUR.zp0.cur_y[CUR.GS.rp0]);
/* auto-flip test */
if (CUR.GS.auto_flip)
{
if ((org_dist ^ cvt_dist) < 0)
cvt_dist = -cvt_dist;
}
/* control value cutin and round */
if ((CUR.opcode & 4) != 0)
{
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]);
/* minimum distance test */
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;
/* UNDOCUMENTED !! */
CUR.GS.rp2 = point;
}
/**********************************************/
/* ALIGNRP[] : ALIGN Relative Point */
/* CodeRange : $3C */
static void Ins_ALIGNRP( INS_ARG )
{
Int point;
TT_F26Dot6 distance;
if (CUR.top < CUR.GS.loop)
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
while (CUR.GS.loop > 0)
{
CUR.args--;
point = (Int)CUR.stack[CUR.args];
if ( (unsigned)point >= CUR.zp1.n)
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
distance = CUR_Func_project( CUR.zp1.cur_x[point] -
CUR.zp0.cur_x[CUR.GS.rp0],
CUR.zp1.cur_y[point] -
CUR.zp0.cur_y[CUR.GS.rp0]);
CUR_Func_move(&CUR.zp1, point, -distance);
CUR.GS.loop--;
}
CUR.GS.loop = 1;
CUR.new_top = CUR.args;
}
/**********************************************/
/* AA[] : Adjust Angle */
/* CodeRange : $7F */
static void Ins_AA( INS_ARG )
{
/* Intentional - no longer supported */
}
/**********************************************/
/* ISECT[] : moves point to InterSECTion */
/* CodeRange : $0F */
static void Ins_ISECT( INS_ARG )
{
Long point, /* are these Ints or Longs */
a0, a1,
b0, b1;
TT_F26Dot6 discriminant;
TT_F26Dot6 dx, dy,
dax, day,
dbx, dby;
TT_F26Dot6 val;
TT_Vector R;
point = args[0];
a0 = args[1];
a1 = args[2];
b0 = args[3];
b1 = args[4];
if ( (unsigned)b0 >= CUR.zp0.n ||
(unsigned)b1 >= CUR.zp0.n ||
(unsigned)a0 >= CUR.zp1.n ||
(unsigned)a1 >= CUR.zp1.n ||
(unsigned)point >= CUR.zp0.n)
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
dbx = CUR.zp0.cur_x[b1] - CUR.zp0.cur_x[b0];
dby = CUR.zp0.cur_y[b1] - CUR.zp0.cur_y[b0];
dax = CUR.zp1.cur_x[a1] - CUR.zp1.cur_x[a0];
day = CUR.zp1.cur_y[a1] - CUR.zp1.cur_y[a0];
dx = CUR.zp0.cur_x[b0] - CUR.zp1.cur_x[a0];
dy = CUR.zp0.cur_y[b0] - CUR.zp1.cur_y[a0];
CUR.zp2.touch[point] |= TT_Flag_Touched_Both;
discriminant = MulDiv( dax, -dby, 0x40L) +
MulDiv( day, dbx, 0x40L);
if (ABS(discriminant) >= 0x40)
{
val = MulDiv(dx, -dby, 0x40L) + MulDiv(dy, dbx, 0x40L);
R.x = MulDiv(val, dax, discriminant);
R.y = MulDiv(val, day, discriminant);
CUR.zp2.cur_x[point] = CUR.zp1.cur_x[a0] + R.x;
CUR.zp2.cur_y[point] = CUR.zp1.cur_y[a0] + R.y;
}
else
{
/* else, take the middle of the middles of A and B */
CUR.zp2.cur_x[point] = ( CUR.zp1.cur_x[a0] +
CUR.zp1.cur_x[a1] +
CUR.zp0.cur_x[b0] +
CUR.zp1.cur_x[b1]) / 4;
CUR.zp2.cur_y[point] = ( CUR.zp1.cur_y[a0] +
CUR.zp1.cur_y[a1] +
CUR.zp0.cur_y[b0] +
CUR.zp1.cur_y[b1]) / 4;
}
}
/**********************************************/
/* ALIGNPTS[] : ALIGN PoinTS */
/* CodeRange : $27 */
static void Ins_ALIGNPTS( INS_ARG )
{
Int p1, p2;
TT_F26Dot6 distance;
p1 = (Int)args[0];
p2 = (Int)args[1];
if ( (unsigned)args[0] >= CUR.zp1.n ||
(unsigned)args[1] >= CUR.zp0.n )
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
distance = CUR_Func_project( CUR.zp0.cur_x[p2] -
CUR.zp1.cur_x[p1],
CUR.zp0.cur_y[p2] -
CUR.zp1.cur_x[p1]) / 2;
CUR_Func_move(&CUR.zp1, p1, distance);
CUR_Func_move(&CUR.zp0, p2, -distance);
}
/**********************************************/
/* IP[] : Interpolate Point */
/* CodeRange : $39 */
static void Ins_IP( INS_ARG )
{
TT_F26Dot6 org_a,
org_b,
org_x,
cur_a,
cur_b,
cur_x,
distance;
Int point;
if (CUR.top < CUR.GS.loop)
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
org_a = CUR_Func_dualproj( CUR.zp0.org_x[CUR.GS.rp1],
CUR.zp0.org_y[CUR.GS.rp1] );
org_b = CUR_Func_dualproj( CUR.zp1.org_x[CUR.GS.rp2],
CUR.zp1.org_y[CUR.GS.rp2] );
cur_a = CUR_Func_project( CUR.zp0.cur_x[CUR.GS.rp1],
CUR.zp0.cur_y[CUR.GS.rp1] );
cur_b = CUR_Func_project( CUR.zp1.cur_x[CUR.GS.rp2],
CUR.zp1.cur_y[CUR.GS.rp2] );
while (CUR.GS.loop > 0)
{
CUR.args--;
point = (Int)CUR.stack[CUR.args];
org_x = CUR_Func_dualproj( CUR.zp2.org_x[point],
CUR.zp2.org_y[point] );
cur_x = CUR_Func_project( CUR.zp2.cur_x[point],
CUR.zp2.cur_y[point] );
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
{
/* note : it seems that rounding this value isn't a good */
/* idea ( width of capital 'S' in Times ) */
distance = 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;
}
/**********************************************/
/* UTP[a] : UnTouch Point */
/* CodeRange : $29 */
static void Ins_UTP( INS_ARG )
{
Byte mask;
if ( (unsigned)args[0] >= CUR.zp0.n)
{
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[args[0]] &= mask;
}
/* Local variables for Ins_IUP: */
struct LOC_Ins_IUP
{
PCoordinates orgs; /* original and current coordinate */
PCoordinates curs; /* arrays */
};
/******************************************************************************
* Local Procedure for Ins_IUP
*
*
******************************************************************************/
static void Shift( Int p1,
Int p2,
Int p,
struct LOC_Ins_IUP *LINK)
{
Int i;
TT_F26Dot6 x;
x = LINK->curs[p] - LINK->orgs[p];
for (i = p1; i < p; i++)
LINK->curs[i] += x;
for (i = p + 1; i <= p2; i++)
LINK->curs[i] += x;
}
/******************************************************************************
* Local Procedure for Ins_INP
*
*
******************************************************************************/
static void Interp(Int p1, Int p2, Int ref1, Int ref2,
struct LOC_Ins_IUP *LINK)
{
Long i;
TT_F26Dot6 x, x1, x2, d1, d2;
if (p1 > p2)
return;
x1 = LINK->orgs[ref1];
d1 = LINK->curs[ref1] - LINK->orgs[ref1];
x2 = LINK->orgs[ref2];
d2 = LINK->curs[ref2] - LINK->orgs[ref2];
if (x1 == x2)
{
for (i = p1; i <= p2; i++)
{
x = LINK->orgs[i];
if (x <= x1) x += d1;
else x += d2;
LINK->curs[i] = x;
}
return;
}
if (x1 < x2)
{
for (i = p1; i <= p2; i++)
{
x = LINK->orgs[i];
if (x <= x1)
x += d1;
else
{
if (x >= x2)
x += d2;
else
x = LINK->curs[ref1] + MulDiv( x - x1,
LINK->curs[ref2] - LINK->curs[ref1],
x2 - x1);
}
LINK->curs[i] = x;
}
return;
}
/* x2 < x1 */
for (i = p1; i <= p2; i++)
{
x = LINK->orgs[i];
if (x <= x2)
x += d2;
else
{
if (x >= x1)
x += d1;
else
x = LINK->curs[ref1] + MulDiv( x - x1,
LINK->curs[ref2] - LINK->curs[ref1],
x2 - x1);
}
LINK->curs[i] = x;
}
}
/**********************************************/
/* IUP[a] : Interpolate Untouched Points */
/* CodeRange : $30-$31 */
static void Ins_IUP( INS_ARG )
{
struct LOC_Ins_IUP V;
unsigned char mask;
Long first_point; /* first point of contour */
Long end_point; /* end point (last+1) of contour */
Long first_touched; /* first touched point in contour */
Long cur_touched; /* current touched point in contour */
Long point; /* current point */
Long contour; /* current contour */
if (CUR.opcode & 1)
{
mask = TT_Flag_Touched_X;
V.orgs = CUR.pts.org_x;
V.curs = CUR.pts.cur_x;
}
else
{
mask = TT_Flag_Touched_Y;
V.orgs = CUR.pts.org_y;
V.curs = CUR.pts.cur_y;
}
contour = 0;
point = 0;
do
{
end_point = CUR.endContours[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)
{
Interp( (Int)(cur_touched + 1),
(Int)(point - 1),
(Int)cur_touched,
(Int)point,
&V);
cur_touched = point;
}
point++;
}
if (cur_touched == first_touched)
Shift((Int)first_point, (Int)end_point, (Int)cur_touched, &V);
else
{
Interp((Int)(cur_touched + 1),
(Int)(end_point),
(Int)(cur_touched),
(Int)(first_touched),
&V);
Interp((Int)(first_point),
(Int)(first_touched - 1),
(Int)(cur_touched),
(Int)(first_touched),
&V);
}
}
contour++;
} while (contour < CUR.numContours);
}
/**********************************************/
/* DELTAPn[] : DELTA Exceptions P1, P2, P3 */
/* CodeRange : $5D,$71,$72 */
static void Ins_DELTAP( INS_ARG )
{
Int k;
Long A, B, C, nump;
nump = args[0];
for (k = 1; k <= nump; k++)
{
if (CUR.args < 2)
{
CUR.error = TT_Err_Too_Few_Arguments;
return;
}
CUR.args -= 2;
A = CUR.stack[CUR.args + 1];
B = CUR.stack[CUR.args];
if (A >= CUR.zp0.n)
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
C = (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 (CUR_Ppem() == C)
{
B = (B & 0xF) - 8;
if (B >= 0)
B++;
B = B * 64 / (1L << CUR.GS.delta_shift);
CUR_Func_move(&CUR.zp0, (Int)A, (Int)B);
}
}
CUR.new_top = CUR.args;
}
/**********************************************/
/* DELTACn[] : DELTA Exceptions C1, C2, C3 */
/* CodeRange : $73,$74,$75 */
static void Ins_DELTAC( INS_ARG )
{
Long nump, k;
Long A, B, C;
nump = args[0];
for (k = 1; k <= nump; k++)
{
if (CUR.args < 2)
{
CUR.error = TT_Err_Too_Few_Arguments;
return;
}
CUR.args -= 2;
A = CUR.stack[CUR.args + 1];
B = CUR.stack[CUR.args];
if (A >= CUR.cvtSize)
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
C = ((unsigned long)(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 (CUR_Ppem() == C)
{
B = (B & 0xF) - 8;
if (B >= 0)
B++;
B = B * 64 / (1L << CUR.GS.delta_shift);
CUR.cvt[A] += (Int)B;
}
}
CUR.new_top = CUR.args;
}
/****************************************************************/
/* */
/* MISC. INSTRUCTIONS */
/* */
/****************************************************************/
/***********************************************************/
/* DEBUG[] : DEBUG. Unsupported */
/* CodeRange : $4F */
/* NOTE : The original instruction pops a value from the stack */
static void Ins_DEBUG( INS_ARG )
{
CUR.error = TT_Err_Debug_OpCode;
}
/**********************************************/
/* GETINFO[] : GET INFOrmation */
/* CodeRange : $88 */
static void Ins_GETINFO( INS_ARG )
{
Long K;
K = 0;
if ((args[0] & 1) != 0)
K = 3;
/* We return then Windows 3.1 version number */
/* for the font scaler */
if (CUR.metrics.rotated)
K |= 0x80;
/* Has the glyph been rotated ? */
if (CUR.metrics.stretched)
K |= 0x100;
/* Has the glyph been stretched ? */
args[0] = K;
}
static void Ins_UNKNOWN( INS_ARG )
{
CUR.error = TT_Err_Invalid_Opcode;
}
static TInstruction_Function Instruct_Dispatch[256] = {
/* opcodes are gathered in groups of 16 */
/* please keep the spaces as they are */
/* SVTCA y */ Ins_SVTCA,
/* SVTCA x */ Ins_SVTCA,
/* SPvTCA y */ Ins_SPVTCA,
/* SPvTCA x */ Ins_SPVTCA,
/* SFvTCA y */ Ins_SFVTCA,
/* SFvTCA x */ Ins_SFVTCA,
/* SPvTL // */ Ins_SPVTL,
/* SPvTL + */ Ins_SPVTL,
/* SFvTL // */ Ins_SFVTL,
/* SFvTL + */ Ins_SFVTL,
/* SPvFS */ Ins_SPVFS,
/* SFvFS */ Ins_SFVFS,
/* GPV */ Ins_GPV,
/* GFV */ Ins_GFV,
/* SFvTPv */ Ins_SFVTPV,
/* ISECT */ Ins_ISECT,
/* SRP0 */ Ins_SRP0,
/* SRP1 */ Ins_SRP1,
/* SRP2 */ Ins_SRP2,
/* SZP0 */ Ins_SZP0,
/* SZP1 */ Ins_SZP1,
/* SZP2 */ Ins_SZP2,
/* SZPS */ Ins_SZPS,
/* SLOOP */ Ins_SLOOP,
/* RTG */ Ins_RTG,
/* RTHG */ Ins_RTHG,
/* SMD */ Ins_SMD,
/* ELSE */ Ins_ELSE,
/* JMPR */ Ins_JMPR,
/* SCvTCi */ Ins_SCVTCI,
/* SSwCi */ Ins_SSWCI,
/* SSW */ Ins_SSW,
/* DUP */ Ins_DUP,
/* POP */ Ins_POP,
/* CLEAR */ Ins_CLEAR,
/* SWAP */ Ins_SWAP,
/* DEPTH */ Ins_DEPTH,
/* CINDEX */ Ins_CINDEX,
/* MINDEX */ Ins_MINDEX,
/* AlignPTS */ Ins_ALIGNPTS,
/* INS_$28 */ Ins_UNKNOWN,
/* UTP */ Ins_UTP,
/* LOOPCALL */ Ins_LOOPCALL,
/* CALL */ Ins_CALL,
/* FDEF */ Ins_FDEF,
/* ENDF */ Ins_ENDF,
/* MDAP[0] */ Ins_MDAP,
/* MDAP[1] */ Ins_MDAP,
/* IUP[0] */ Ins_IUP,
/* IUP[1] */ Ins_IUP,
/* SHP[0] */ Ins_SHP,
/* SHP[1] */ Ins_SHP,
/* SHC[0] */ Ins_SHC,
/* SHC[1] */ Ins_SHC,
/* SHZ[0] */ Ins_SHZ,
/* SHZ[1] */ Ins_SHZ,
/* SHPIX */ Ins_SHPIX,
/* IP */ Ins_IP,
/* MSIRP[0] */ Ins_MSIRP,
/* MSIRP[1] */ Ins_MSIRP,
/* AlignRP */ Ins_ALIGNRP,
/* RTDG */ Ins_RTDG,
/* MIAP[0] */ Ins_MIAP,
/* MIAP[1] */ Ins_MIAP,
/* NPushB */ Ins_NPUSHB,
/* NPushW */ Ins_NPUSHW,
/* WS */ Ins_WS,
/* RS */ Ins_RS,
/* WCvtP */ Ins_WCVTP,
/* RCvt */ Ins_RCVT,
/* GC[0] */ Ins_GC,
/* GC[1] */ Ins_GC,
/* SCFS */ Ins_SCFS,
/* MD[0] */ Ins_MD,
/* MD[1] */ Ins_MD,
/* MPPEM */ Ins_MPPEM,
/* MPS */ Ins_MPS,
/* FlipON */ Ins_FLIPON,
/* FlipOFF */ Ins_FLIPOFF,
/* DEBUG */ Ins_DEBUG,
/* LT */ Ins_LT,
/* LTEQ */ Ins_LTEQ,
/* GT */ Ins_GT,
/* GTEQ */ Ins_GTEQ,
/* EQ */ Ins_EQ,
/* NEQ */ Ins_NEQ,
/* ODD */ Ins_ODD,
/* EVEN */ Ins_EVEN,
/* IF */ Ins_IF,
/* EIF */ Ins_EIF,
/* AND */ Ins_AND,
/* OR */ Ins_OR,
/* NOT */ Ins_NOT,
/* DeltaP1 */ Ins_DELTAP,
/* SDB */ Ins_SDB,
/* SDS */ Ins_SDS,
/* ADD */ Ins_ADD,
/* SUB */ Ins_SUB,
/* DIV */ Ins_DIV,
/* MUL */ Ins_MUL,
/* ABS */ Ins_ABS,
/* NEG */ Ins_NEG,
/* FLOOR */ Ins_FLOOR,
/* CEILING */ Ins_CEILING,
/* ROUND[0] */ Ins_ROUND,
/* ROUND[1] */ Ins_ROUND,
/* ROUND[2] */ Ins_ROUND,
/* ROUND[3] */ Ins_ROUND,
/* NROUND[0] */ Ins_NROUND,
/* NROUND[1] */ Ins_NROUND,
/* NROUND[2] */ Ins_NROUND,
/* NROUND[3] */ Ins_NROUND,
/* WCvtF */ Ins_WCVTF,
/* DeltaP2 */ Ins_DELTAP,
/* DeltaP3 */ Ins_DELTAP,
/* DeltaCn[0] */ Ins_DELTAC,
/* DeltaCn[1] */ Ins_DELTAC,
/* DeltaCn[2] */ Ins_DELTAC,
/* SROUND */ Ins_SROUND,
/* S45Round */ Ins_S45ROUND,
/* JROT */ Ins_JROT,
/* JROF */ Ins_JROF,
/* ROFF */ Ins_ROFF,
/* INS_$7B */ Ins_UNKNOWN,
/* RUTG */ Ins_RUTG,
/* RDTG */ Ins_RDTG,
/* SANGW */ Ins_SANGW,
/* AA */ Ins_AA,
/* FlipPT */ Ins_FLIPPT,
/* FlipRgON */ Ins_FLIPRGON,
/* FlipRgOFF */ Ins_FLIPRGOFF,
/* INS_$83 */ Ins_UNKNOWN,
/* INS_$84 */ Ins_UNKNOWN,
/* ScanCTRL */ Ins_SCANCTRL,
/* SDPVTL[0] */ Ins_SDPVTL,
/* SDPVTL[1] */ Ins_SDPVTL,
/* GetINFO */ Ins_GETINFO,
/* IDEF */ Ins_IDEF,
/* ROLL */ Ins_ROLL,
/* MAX */ Ins_MAX,
/* MIN */ Ins_MIN,
/* ScanTYPE */ Ins_SCANTYPE,
/* InstCTRL */ Ins_INSTCTRL,
/* INS_$8F */ Ins_UNKNOWN,
/* INS_$90 */ Ins_UNKNOWN,
/* INS_$91 */ Ins_UNKNOWN,
/* INS_$92 */ Ins_UNKNOWN,
/* INS_$93 */ Ins_UNKNOWN,
/* INS_$94 */ Ins_UNKNOWN,
/* INS_$95 */ Ins_UNKNOWN,
/* INS_$96 */ Ins_UNKNOWN,
/* INS_$97 */ Ins_UNKNOWN,
/* INS_$98 */ Ins_UNKNOWN,
/* INS_$99 */ Ins_UNKNOWN,
/* INS_$9A */ Ins_UNKNOWN,
/* INS_$9B */ Ins_UNKNOWN,
/* INS_$9C */ Ins_UNKNOWN,
/* INS_$9D */ Ins_UNKNOWN,
/* INS_$9E */ Ins_UNKNOWN,
/* INS_$9F */ Ins_UNKNOWN,
/* INS_$A0 */ Ins_UNKNOWN,
/* INS_$A1 */ Ins_UNKNOWN,
/* INS_$A2 */ Ins_UNKNOWN,
/* INS_$A3 */ Ins_UNKNOWN,
/* INS_$A4 */ Ins_UNKNOWN,
/* INS_$A5 */ Ins_UNKNOWN,
/* INS_$A6 */ Ins_UNKNOWN,
/* INS_$A7 */ Ins_UNKNOWN,
/* INS_$A8 */ Ins_UNKNOWN,
/* INS_$A9 */ Ins_UNKNOWN,
/* INS_$AA */ Ins_UNKNOWN,
/* INS_$AB */ Ins_UNKNOWN,
/* INS_$AC */ Ins_UNKNOWN,
/* INS_$AD */ Ins_UNKNOWN,
/* INS_$AE */ Ins_UNKNOWN,
/* INS_$AF */ Ins_UNKNOWN,
/* PushB[0] */ Ins_PUSHB,
/* PushB[1] */ Ins_PUSHB,
/* PushB[2] */ Ins_PUSHB,
/* PushB[3] */ Ins_PUSHB,
/* PushB[4] */ Ins_PUSHB,
/* PushB[5] */ Ins_PUSHB,
/* PushB[6] */ Ins_PUSHB,
/* PushB[7] */ Ins_PUSHB,
/* PushW[0] */ Ins_PUSHW,
/* PushW[1] */ Ins_PUSHW,
/* PushW[2] */ Ins_PUSHW,
/* PushW[3] */ Ins_PUSHW,
/* PushW[4] */ Ins_PUSHW,
/* PushW[5] */ Ins_PUSHW,
/* PushW[6] */ Ins_PUSHW,
/* PushW[7] */ Ins_PUSHW,
/* MDRP[00] */ Ins_MDRP,
/* MDRP[01] */ Ins_MDRP,
/* MDRP[02] */ Ins_MDRP,
/* MDRP[03] */ Ins_MDRP,
/* MDRP[04] */ Ins_MDRP,
/* MDRP[05] */ Ins_MDRP,
/* MDRP[06] */ Ins_MDRP,
/* MDRP[07] */ Ins_MDRP,
/* MDRP[08] */ Ins_MDRP,
/* MDRP[09] */ Ins_MDRP,
/* MDRP[10] */ Ins_MDRP,
/* MDRP[11] */ Ins_MDRP,
/* MDRP[12] */ Ins_MDRP,
/* MDRP[13] */ Ins_MDRP,
/* MDRP[14] */ Ins_MDRP,
/* MDRP[15] */ Ins_MDRP,
/* MDRP[16] */ Ins_MDRP,
/* MDRP[17] */ Ins_MDRP,
/* MDRP[18] */ Ins_MDRP,
/* MDRP[19] */ Ins_MDRP,
/* MDRP[20] */ Ins_MDRP,
/* MDRP[21] */ Ins_MDRP,
/* MDRP[22] */ Ins_MDRP,
/* MDRP[23] */ Ins_MDRP,
/* MDRP[24] */ Ins_MDRP,
/* MDRP[25] */ Ins_MDRP,
/* MDRP[26] */ Ins_MDRP,
/* MDRP[27] */ Ins_MDRP,
/* MDRP[28] */ Ins_MDRP,
/* MDRP[29] */ Ins_MDRP,
/* MDRP[30] */ Ins_MDRP,
/* MDRP[31] */ Ins_MDRP,
/* MIRP[00] */ Ins_MIRP,
/* MIRP[01] */ Ins_MIRP,
/* MIRP[02] */ Ins_MIRP,
/* MIRP[03] */ Ins_MIRP,
/* MIRP[04] */ Ins_MIRP,
/* MIRP[05] */ Ins_MIRP,
/* MIRP[06] */ Ins_MIRP,
/* MIRP[07] */ Ins_MIRP,
/* MIRP[08] */ Ins_MIRP,
/* MIRP[09] */ Ins_MIRP,
/* MIRP[10] */ Ins_MIRP,
/* MIRP[11] */ Ins_MIRP,
/* MIRP[12] */ Ins_MIRP,
/* MIRP[13] */ Ins_MIRP,
/* MIRP[14] */ Ins_MIRP,
/* MIRP[15] */ Ins_MIRP,
/* MIRP[16] */ Ins_MIRP,
/* MIRP[17] */ Ins_MIRP,
/* MIRP[18] */ Ins_MIRP,
/* MIRP[19] */ Ins_MIRP,
/* MIRP[20] */ Ins_MIRP,
/* MIRP[21] */ Ins_MIRP,
/* MIRP[22] */ Ins_MIRP,
/* MIRP[23] */ Ins_MIRP,
/* MIRP[24] */ Ins_MIRP,
/* MIRP[25] */ Ins_MIRP,
/* MIRP[26] */ Ins_MIRP,
/* MIRP[27] */ Ins_MIRP,
/* MIRP[28] */ Ins_MIRP,
/* MIRP[29] */ Ins_MIRP,
/* MIRP[30] */ Ins_MIRP,
/* MIRP[31] */ Ins_MIRP
};
/****************************************************************/
/* */
/* RUN */
/* */
/* This function executes a run of opcodes. It will exit */
/* in the following cases : */
/* */
/* - Errors ( in which case it returns FALSE ) */
/* */
/* - Reaching the end of the main code range (returns TRUE) */
/* reaching the end of a code range within a function */
/* call is an error. */
/* */
/* - After executing one single opcode, if the flag */
/* 'Instruction_Trap' is set to TRUE. (returns TRUE) */
/* */
/* On exit whith TRUE, test IP < CodeSize to know wether it */
/* comes from a instruction trap or a normal termination */
/* */
/* */
/* Note : The documented DEBUG opcode pops a value from */
/* the stack. This behaviour is unsupported, here */
/* a DEBUG opcode is always an error. */
/* */
/* */
/* THIS IS THE INTERPRETER'S MAIN LOOP */
/* */
/* Instructions appear in the specs' order */
/* */
/****************************************************************/
#ifndef DEBUG
TT_Error RunIns( PExecution_Context exc )
#else
TT_Error RunIns2( PExecution_Context exc )
#endif
{
Bool Result;
Int A;
TDefRecord *WITH;
TCallRecord *WITH1;
COMPUTE_Funcs();
Compute_Round( EXEC_ARGS exc->GS.round_state);
do
{
CALC_Length();
/* First, let's check for empty stack and overflow */
CUR.args = CUR.top - Pop_Push_Count[ CUR.opcode*2 ];
/* args is the top of the stack once arguments have been popped */
/* one can also see it as the index of the last argument */
if (CUR.args < 0)
{
CUR.error = TT_Err_Too_Few_Arguments;
goto _LErrorLabel;
}
CUR.new_top = CUR.args + Pop_Push_Count[ CUR.opcode*2+1 ];
/* new_top is the new top of the stack, after the instruction's */
/* execution. top will be set to new_top after the 'case' */
if (CUR.new_top > CUR.stackSize)
{
CUR.error = TT_Err_Stack_Overflow;
goto _LErrorLabel;
}
CUR.step_ins = TRUE;
CUR.error = TT_Err_Ok;
Instruct_Dispatch[CUR.opcode]( EXEC_ARGS &CUR.stack[CUR.args] );
if (CUR.error != TT_Err_Ok)
{
switch (CUR.error)
{
case TT_Err_Invalid_Opcode: /* looking for redefined instructions */
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;
break;
default:
CUR.error = CUR.error;
goto _LErrorLabel;
break;
}
}
CUR.top = CUR.new_top;
if (CUR.step_ins)
CUR.IP += CUR.length;
_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:
Result = SUCCESS;
/* Load_Instance_Context(aIns); */
return TT_Err_Ok;
_LErrorLabel:
Result = FAILURE;
/* Load_Instance_Context(aIns); */
return CUR.error;
}
#ifdef DEBUG
TT_Error RunIns( PExecution_Context exc )
{
Bool Result;
Int A, next_IP, diff;
char ch, *temp;
TT_Error error;
TVecRecord save;
TVecRecord 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 char* round_str[8] =
{
"to half-grid",
"to grid",
"to double grid",
"down to grid",
"up to grid",
"off",
"super",
"super 45"
};
/*
if ( !Goto_CodeRange( exc, TT_CodeRange_Glyph, 0 ) )
return FAILURE;
exc->pts = ((PInstance)exc->owner)->pts;
exc->numContours = ((PInstance)exc)->numContours;
exc->zp0 = exc->pts;
exc->zp1 = exc->pts;
exc->zp2 = exc->pts;
exc->GS = exc->default_GS;
exc->GS.gep0 = 1;
exc->GS.gep1 = 1;
exc->GS.gep2 = 1;
exc->GS.projVector.x = 0x4000;
exc->GS.projVector.y = 0x0000;
exc->GS.freeVector.x = 0x4000;
exc->GS.freeVector.y = 0x0000;
exc->GS.dualVector.x = 0x4000;
exc->GS.dualVector.y = 0x0000;
exc->GS.round_state = 1;
exc->top = 0;
/ * some glyphs leave something on the stack !! * /
/ * we must empty it * /
*/
if ( exc->curRange != TT_CodeRange_Cvt )
return RunIns2( exc );
pts = exc->pts;
save.n = pts.n;
save.org_x = (PCoordinates)malloc( sizeof(TT_F26Dot6)*save.n );
save.org_y = (PCoordinates)malloc( sizeof(TT_F26Dot6)*save.n );
save.cur_x = (PCoordinates)malloc( sizeof(TT_F26Dot6)*save.n );
save.cur_y = (PCoordinates)malloc( sizeof(TT_F26Dot6)*save.n );
save.touch = (PByte)malloc( save.n );
exc->instruction_trap = 1;
do
{
if ( CUR.IP < CUR.codeSize )
{
CALC_Length();
CUR.args = CUR.top - Pop_Push_Count[ CUR.opcode*2 ];
/* args is the top of the stack once arguments have been popped */
/* one can also see it as the index of the last argument */
/* First print the current stack */
A = CUR.args-4;
if ( A < 0 ) A = 0;
while ( A < CUR.top )
{
DebugTrace(( "%04lx ", CUR.stack[A] ));
A++;
if ( A == CUR.args ) DebugTrace(( "* " ));
}
DebugTrace(( "\n" ));
/* Now print the current line */
#if 1
DebugTrace(( "%s\n", (char*)Cur_U_Line( &CUR ) ));
#endif
/* First, check for empty stack and overflow */
if (CUR.args < 0)
{
DebugTrace(( "ERROR : Too Few Arguments\n" ));
CUR.error = TT_Err_Too_Few_Arguments;
goto _LErrorLabel;
}
CUR.new_top = CUR.args + Pop_Push_Count[ CUR.opcode*2+1 ];
/* new_top is the new top of the stack, after the instruction's */
/* execution. top will be set to new_top after the 'case' */
if (CUR.new_top > CUR.stackSize)
{
DebugTrace(( "ERROR : Stack overflow\n" ));
CUR.error = TT_Err_Stack_Overflow;
goto _LErrorLabel;
}
}
else
DebugTrace(( "End of program reached.\n" ));
do
{
#ifdef OS2
ch = getch();
if ( ch > ' ' ) DebugTrace(( "%c\n", ch ));
#else
ch = getchar();
#endif
switch (ch)
{
case '\n':
ch = '\0';
break;
case '?' :
DebugTrace(( "Help\n\n" ));
DebugTrace(( "? Show this page\n" ));
DebugTrace(( "q Quit debugger\n" ));
DebugTrace(( "n Next instruction\n" ));
DebugTrace(( "s Step into\n" ));
DebugTrace(( "v Show vector info\n" ));
DebugTrace(( "p Show points zone\n\n" ));
ch = '\0';
break;
case 'v' :
DebugTrace(( "freedom (%04hx,%04hx)\n",
exc->GS.freeVector.x,
exc->GS.freeVector.y ));
DebugTrace(( "projection (%04hx,%04hx)\n",
exc->GS.projVector.x,
exc->GS.projVector.y ));
DebugTrace(( "dual (%04hx,%04hx)\n\n",
exc->GS.dualVector.x,
exc->GS.dualVector.y ));
ch = '\0';
break;
case 'g' :
DebugTrace(( "rounding %s\n", round_str[exc->GS.round_state] ));
DebugTrace(( "min dist %04lx\n", exc->GS.minimum_distance ));
DebugTrace(( "cvt_cutin %04lx\n", exc->GS.control_value_cutin ));
ch = '\0';
break;
case 'p' :
for ( A = 0; A < exc->pts.n; A++ )
{
DebugTrace(( "%02hx ", A ));
DebugTrace(( "%08lx,%08lx - ",
pts.org_x[A],
pts.org_y[A] ));
DebugTrace(( "%08lx,%08lx\n",
pts.cur_x[A],
pts.cur_y[A] ));
}
DebugTrace(( "\n" ));
ch = '\0';
break;
}
}
while ( ch == '\0' );
MEM_Copy( save.org_x, pts.org_x, pts.n * sizeof(TT_F26Dot6) );
MEM_Copy( save.org_y, pts.org_y, pts.n * sizeof(TT_F26Dot6) );
MEM_Copy( save.cur_x, pts.cur_x, pts.n * sizeof(TT_F26Dot6) );
MEM_Copy( save.cur_y, pts.cur_y, pts.n * sizeof(TT_F26Dot6) );
MEM_Copy( save.touch, pts.touch, pts.n );
switch (ch)
{
case 'q':
goto _LErrorLabel;
case 's' :
if ( CUR.IP < CUR.codeSize )
if ( (error = RunIns2( exc )) )
goto _LErrorLabel;
break;
case 'n' :
if ( CUR.IP < CUR.codeSize )
{
next_IP = CUR.IP + CUR.length;
while ( CUR.IP != next_IP )
{
if ( (error = RunIns2( exc )) )
goto _LErrorLabel;
}
}
break;
default:
DebugTrace(( "unknown command. Press ? for help\n" ));
}
for ( A = 0; A < pts.n; A++ )
{
diff = 0;
if ( save.org_x[A] != pts.org_x[A] ) diff |= 1;
if ( save.org_y[A] != pts.org_y[A] ) diff |= 2;
if ( save.cur_x[A] != pts.cur_x[A] ) diff |= 4;
if ( save.cur_y[A] != pts.cur_y[A] ) diff |= 8;
if ( save.touch[A] != pts.touch[A] ) diff |= 16;
if ( diff )
{
DebugTrace(( "%02hx ", A ));
if ( diff & 16 ) temp = "(%01hx)"; else temp = " %01hx ";
DebugTrace(( temp, save.touch[A] & 7 ));
if ( diff & 1 ) temp = "(%08lx)"; else temp = " %08lx ";
DebugTrace(( temp, save.org_x[A] ));
if ( diff & 2 ) temp = "(%08lx)"; else temp = " %08lx ";
DebugTrace(( temp, save.org_y[A] ));
if ( diff & 4 ) temp = "(%08lx)"; else temp = " %08lx ";
DebugTrace(( temp, save.cur_x[A] ));
if ( diff & 8 ) temp = "(%08lx)"; else temp = " %08lx ";
DebugTrace(( temp, save.cur_y[A] ));
DebugTrace(( "\n" ));
DebugTrace(( "%02hx ", A ));
if ( diff & 16 ) temp = "[%01hx]"; else temp = " %01hx ";
DebugTrace(( temp, pts.touch[A] & 7 ));
if ( diff & 1 ) temp = "[%08lx]"; else temp = " %08lx ";
DebugTrace(( temp, pts.org_x[A] ));
if ( diff & 2 ) temp = "[%08lx]"; else temp = " %08lx ";
DebugTrace(( temp, pts.org_y[A] ));
if ( diff & 4 ) temp = "[%08lx]"; else temp = " %08lx ";
DebugTrace(( temp, pts.cur_x[A] ));
if ( diff & 8 ) temp = "[%08lx]"; else temp = " %08lx ";
DebugTrace(( temp, pts.cur_y[A] ));
DebugTrace(( "\n\n" ));
}
}
} while ( TRUE );
_LErrorLabel:
Result = FAILURE;
/* Load_Instance_Context(aIns); */
return error;
}
#endif /* DEBUG */
/* End. */