summaryrefslogtreecommitdiff
path: root/Build/source/libs/freetype/freetype-1.5/lib/ttinterp.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/freetype/freetype-1.5/lib/ttinterp.c')
-rw-r--r--Build/source/libs/freetype/freetype-1.5/lib/ttinterp.c6681
1 files changed, 6681 insertions, 0 deletions
diff --git a/Build/source/libs/freetype/freetype-1.5/lib/ttinterp.c b/Build/source/libs/freetype/freetype-1.5/lib/ttinterp.c
new file mode 100644
index 00000000000..3c991a5e130
--- /dev/null
+++ b/Build/source/libs/freetype/freetype-1.5/lib/ttinterp.c
@@ -0,0 +1,6681 @@
+/*******************************************************************
+ *
+ * ttinterp.c 3.1
+ *
+ * TrueType bytecode intepreter.
+ *
+ * Copyright 1996-2002 by
+ * David Turner, Robert Wilhelm, and Werner Lemberg
+ *
+ * This file is part of the FreeType project, and may only be used
+ * modified and distributed under the terms of the FreeType project
+ * license, LICENSE.TXT. By continuing to use, modify, or distribute
+ * this file you indicate that you have read the license and
+ * understand and accept it fully.
+ *
+ *
+ * Changes between 3.1 and 3.0:
+ *
+ * - A more relaxed version of the interpreter. It is now able to
+ * ignore errors like out-of-bound array access and writes in
+ * order to silently support broken glyphs (even if the results
+ * are not always pretty).
+ *
+ * Note that one can use the flag TTLOAD_PEDANTIC to force
+ * TrueType-compliant interpretation.
+ *
+ * - A big #if used to completely disable the interpreter, which
+ * is due to the Apple patents issue.
+ *
+ ******************************************************************/
+
+#include "freetype.h"
+#include "tttypes.h"
+#include "ttdebug.h"
+#include "ttcalc.h"
+#include "ttmemory.h"
+#include "ttinterp.h"
+
+
+#ifndef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ FT_INTERNAL_FUNC( TT_Error )
+ RunIns( EXEC_OP )
+ {
+ /* do nothing - always successful */
+
+#ifndef TT_CONFIG_OPTION_STATIC_INTERPRETER
+ /* make picky compilers happy */
+ (void)exc;
+#endif
+ return TT_Err_Ok;
+ }
+
+#else /* ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+
+#ifdef DEBUG_INTERPRETER
+ /* The debugger uses a special version of the TrueType */
+ /* interpreter, with some hooks and a simple user interface. */
+ /* Here we declare the needed additions. */
+#include "ttdebug.h"
+
+/* Define the `getch()' function, used for get user inputs. */
+
+#ifndef UNIX
+
+/* Outside Unix, we rely on getch() being defined by <conio.h>. */
+/* This has become a standard, coming from MS-DOS libraries, and */
+/* has been ported to OS/2, Win32, and perhaps others. */
+/* If it does not work for you, investigate the code for Unix */
+/* (here, and in test/fdebug.c). */
+#include <conio.h>
+#if defined( _M_I86 )
+ /* a recent compiler, which do not pollute name spaces... */
+#define getch(x) _getch(x)
+#endif /* modern compiler */
+
+#else /* !defined( UNIX ) */
+
+/* On Unix systems, it is an alias for `getchar()', and the */
+/* debugger front end must ensure that the `stdin' file */
+/* descriptor is not in line-by-line input mode. */
+#define getch getchar
+
+#endif
+
+#endif /* DEBUG_INTEPRETER */
+
+
+/* required by the tracing mode */
+#undef TT_COMPONENT
+#define TT_COMPONENT trace_interp
+
+
+/* In order to detect infinite loops in the code, we set-up a */
+/* counter within the run loop. a singly stroke of interpretation */
+/* is now limited to a maximum number of opcodes defined below. */
+/* */
+#define MAX_RUNNABLE_OPCODES 1000000
+
+
+/******************************************************************/
+/* */
+/* 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 386's or even 486's). */
+/* */
+/* 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 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 'fttimer' 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. */
+/* */
+/* TT_CONFIG_OPTION_STATIC_INTERPRETER (in ft_conf.h) toggles */
+/* the use of the static interpreter. */
+/* */
+
+#ifndef TT_CONFIG_OPTION_STATIC_INTERPRETER /* indirect implementation */
+
+#define CUR (*exc)
+
+#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 byte addresses). */
+
+#endif /* !TT_CONFIG_OPTION_STATIC_INTERPRETER */
+
+
+/* A bunch of macros to save typing (and ease reading). */
+
+#define INS_ARG EXEC_OPS PStorage args /* see ttobjs.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 CUR_Func_read_cvt( index ) \
+ CUR.func_read_cvt( EXEC_ARGS index )
+
+#define CUR_Func_write_cvt( index, val ) \
+ CUR.func_write_cvt( EXEC_ARGS index, val )
+
+#define CUR_Func_move_cvt( index, val ) \
+ CUR.func_move_cvt( EXEC_ARGS index, val )
+
+#define CURRENT_Ratio() Current_Ratio( EXEC_ARG )
+#define CURRENT_Ppem() Current_Ppem( EXEC_ARG )
+
+#define CALC_Length() Calc_Length( EXEC_ARG )
+
+#define INS_SxVTL( a, b, c, d ) Ins_SxVTL( EXEC_ARGS a, b, c, d )
+
+#define COMPUTE_Point_Displacement( a, b, c, d ) \
+ Compute_Point_Displacement( EXEC_ARGS a, b, c, d )
+
+#define MOVE_Zp2_Point( a, b, c, t ) Move_Zp2_Point( EXEC_ARGS a, b, c, t )
+
+#define CUR_Ppem() Cur_PPEM( EXEC_ARG )
+
+ /* Instruction dispatch function, as used by the interpreter */
+ typedef void (*TInstruction_Function)( INS_ARG );
+
+#define BOUNDS( x, n ) ( (TT_UInt)(x) >= (TT_UInt)(n) )
+
+
+
+/*********************************************************************/
+/* */
+/* 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. */
+/* */
+
+#undef PACK
+#define PACK( x, y ) ((x << 4) | y)
+
+ static const Byte Pop_Push_Count[256] =
+ {
+ /* opcodes are gathered in groups of 16 */
+ /* please keep the spaces as they are */
+
+ /* SVTCA y */ PACK( 0, 0 ),
+ /* SVTCA x */ PACK( 0, 0 ),
+ /* SPvTCA y */ PACK( 0, 0 ),
+ /* SPvTCA x */ PACK( 0, 0 ),
+ /* SFvTCA y */ PACK( 0, 0 ),
+ /* SFvTCA x */ PACK( 0, 0 ),
+ /* SPvTL // */ PACK( 2, 0 ),
+ /* SPvTL + */ PACK( 2, 0 ),
+ /* SFvTL // */ PACK( 2, 0 ),
+ /* SFvTL + */ PACK( 2, 0 ),
+ /* SPvFS */ PACK( 2, 0 ),
+ /* SFvFS */ PACK( 2, 0 ),
+ /* GPV */ PACK( 0, 2 ),
+ /* GFV */ PACK( 0, 2 ),
+ /* SFvTPv */ PACK( 0, 0 ),
+ /* ISECT */ PACK( 5, 0 ),
+
+ /* SRP0 */ PACK( 1, 0 ),
+ /* SRP1 */ PACK( 1, 0 ),
+ /* SRP2 */ PACK( 1, 0 ),
+ /* SZP0 */ PACK( 1, 0 ),
+ /* SZP1 */ PACK( 1, 0 ),
+ /* SZP2 */ PACK( 1, 0 ),
+ /* SZPS */ PACK( 1, 0 ),
+ /* SLOOP */ PACK( 1, 0 ),
+ /* RTG */ PACK( 0, 0 ),
+ /* RTHG */ PACK( 0, 0 ),
+ /* SMD */ PACK( 1, 0 ),
+ /* ELSE */ PACK( 0, 0 ),
+ /* JMPR */ PACK( 1, 0 ),
+ /* SCvTCi */ PACK( 1, 0 ),
+ /* SSwCi */ PACK( 1, 0 ),
+ /* SSW */ PACK( 1, 0 ),
+
+ /* DUP */ PACK( 1, 2 ),
+ /* POP */ PACK( 1, 0 ),
+ /* CLEAR */ PACK( 0, 0 ),
+ /* SWAP */ PACK( 2, 2 ),
+ /* DEPTH */ PACK( 0, 1 ),
+ /* CINDEX */ PACK( 1, 1 ),
+ /* MINDEX */ PACK( 1, 0 ),
+ /* AlignPTS */ PACK( 2, 0 ),
+ /* INS_$28 */ PACK( 0, 0 ),
+ /* UTP */ PACK( 1, 0 ),
+ /* LOOPCALL */ PACK( 2, 0 ),
+ /* CALL */ PACK( 1, 0 ),
+ /* FDEF */ PACK( 1, 0 ),
+ /* ENDF */ PACK( 0, 0 ),
+ /* MDAP[0] */ PACK( 1, 0 ),
+ /* MDAP[1] */ PACK( 1, 0 ),
+
+ /* IUP[0] */ PACK( 0, 0 ),
+ /* IUP[1] */ PACK( 0, 0 ),
+ /* SHP[0] */ PACK( 0, 0 ),
+ /* SHP[1] */ PACK( 0, 0 ),
+ /* SHC[0] */ PACK( 1, 0 ),
+ /* SHC[1] */ PACK( 1, 0 ),
+ /* SHZ[0] */ PACK( 1, 0 ),
+ /* SHZ[1] */ PACK( 1, 0 ),
+ /* SHPIX */ PACK( 1, 0 ),
+ /* IP */ PACK( 0, 0 ),
+ /* MSIRP[0] */ PACK( 2, 0 ),
+ /* MSIRP[1] */ PACK( 2, 0 ),
+ /* AlignRP */ PACK( 0, 0 ),
+ /* RTDG */ PACK( 0, 0 ),
+ /* MIAP[0] */ PACK( 2, 0 ),
+ /* MIAP[1] */ PACK( 2, 0 ),
+
+ /* NPushB */ PACK( 0, 0 ),
+ /* NPushW */ PACK( 0, 0 ),
+ /* WS */ PACK( 2, 0 ),
+ /* RS */ PACK( 1, 1 ),
+ /* WCvtP */ PACK( 2, 0 ),
+ /* RCvt */ PACK( 1, 1 ),
+ /* GC[0] */ PACK( 1, 1 ),
+ /* GC[1] */ PACK( 1, 1 ),
+ /* SCFS */ PACK( 2, 0 ),
+ /* MD[0] */ PACK( 2, 1 ),
+ /* MD[1] */ PACK( 2, 1 ),
+ /* MPPEM */ PACK( 0, 1 ),
+ /* MPS */ PACK( 0, 1 ),
+ /* FlipON */ PACK( 0, 0 ),
+ /* FlipOFF */ PACK( 0, 0 ),
+ /* DEBUG */ PACK( 1, 0 ),
+
+ /* LT */ PACK( 2, 1 ),
+ /* LTEQ */ PACK( 2, 1 ),
+ /* GT */ PACK( 2, 1 ),
+ /* GTEQ */ PACK( 2, 1 ),
+ /* EQ */ PACK( 2, 1 ),
+ /* NEQ */ PACK( 2, 1 ),
+ /* ODD */ PACK( 1, 1 ),
+ /* EVEN */ PACK( 1, 1 ),
+ /* IF */ PACK( 1, 0 ),
+ /* EIF */ PACK( 0, 0 ),
+ /* AND */ PACK( 2, 1 ),
+ /* OR */ PACK( 2, 1 ),
+ /* NOT */ PACK( 1, 1 ),
+ /* DeltaP1 */ PACK( 1, 0 ),
+ /* SDB */ PACK( 1, 0 ),
+ /* SDS */ PACK( 1, 0 ),
+
+ /* ADD */ PACK( 2, 1 ),
+ /* SUB */ PACK( 2, 1 ),
+ /* DIV */ PACK( 2, 1 ),
+ /* MUL */ PACK( 2, 1 ),
+ /* ABS */ PACK( 1, 1 ),
+ /* NEG */ PACK( 1, 1 ),
+ /* FLOOR */ PACK( 1, 1 ),
+ /* CEILING */ PACK( 1, 1 ),
+ /* ROUND[0] */ PACK( 1, 1 ),
+ /* ROUND[1] */ PACK( 1, 1 ),
+ /* ROUND[2] */ PACK( 1, 1 ),
+ /* ROUND[3] */ PACK( 1, 1 ),
+ /* NROUND[0] */ PACK( 1, 1 ),
+ /* NROUND[1] */ PACK( 1, 1 ),
+ /* NROUND[2] */ PACK( 1, 1 ),
+ /* NROUND[3] */ PACK( 1, 1 ),
+
+ /* WCvtF */ PACK( 2, 0 ),
+ /* DeltaP2 */ PACK( 1, 0 ),
+ /* DeltaP3 */ PACK( 1, 0 ),
+ /* DeltaCn[0] */ PACK( 1, 0 ),
+ /* DeltaCn[1] */ PACK( 1, 0 ),
+ /* DeltaCn[2] */ PACK( 1, 0 ),
+ /* SROUND */ PACK( 1, 0 ),
+ /* S45Round */ PACK( 1, 0 ),
+ /* JROT */ PACK( 2, 0 ),
+ /* JROF */ PACK( 2, 0 ),
+ /* ROFF */ PACK( 0, 0 ),
+ /* INS_$7B */ PACK( 0, 0 ),
+ /* RUTG */ PACK( 0, 0 ),
+ /* RDTG */ PACK( 0, 0 ),
+ /* SANGW */ PACK( 1, 0 ),
+ /* AA */ PACK( 1, 0 ),
+
+ /* FlipPT */ PACK( 0, 0 ),
+ /* FlipRgON */ PACK( 2, 0 ),
+ /* FlipRgOFF */ PACK( 2, 0 ),
+ /* INS_$83 */ PACK( 0, 0 ),
+ /* INS_$84 */ PACK( 0, 0 ),
+ /* ScanCTRL */ PACK( 1, 0 ),
+ /* SDVPTL[0] */ PACK( 2, 0 ),
+ /* SDVPTL[1] */ PACK( 2, 0 ),
+ /* GetINFO */ PACK( 1, 1 ),
+ /* IDEF */ PACK( 1, 0 ),
+ /* ROLL */ PACK( 3, 3 ),
+ /* MAX */ PACK( 2, 1 ),
+ /* MIN */ PACK( 2, 1 ),
+ /* ScanTYPE */ PACK( 1, 0 ),
+ /* InstCTRL */ PACK( 2, 0 ),
+ /* INS_$8F */ PACK( 0, 0 ),
+
+ /* INS_$90 */ PACK( 0, 0 ),
+ /* INS_$91 */ PACK( 0, 0 ),
+ /* INS_$92 */ PACK( 0, 0 ),
+ /* INS_$93 */ PACK( 0, 0 ),
+ /* INS_$94 */ PACK( 0, 0 ),
+ /* INS_$95 */ PACK( 0, 0 ),
+ /* INS_$96 */ PACK( 0, 0 ),
+ /* INS_$97 */ PACK( 0, 0 ),
+ /* INS_$98 */ PACK( 0, 0 ),
+ /* INS_$99 */ PACK( 0, 0 ),
+ /* INS_$9A */ PACK( 0, 0 ),
+ /* INS_$9B */ PACK( 0, 0 ),
+ /* INS_$9C */ PACK( 0, 0 ),
+ /* INS_$9D */ PACK( 0, 0 ),
+ /* INS_$9E */ PACK( 0, 0 ),
+ /* INS_$9F */ PACK( 0, 0 ),
+
+ /* INS_$A0 */ PACK( 0, 0 ),
+ /* INS_$A1 */ PACK( 0, 0 ),
+ /* INS_$A2 */ PACK( 0, 0 ),
+ /* INS_$A3 */ PACK( 0, 0 ),
+ /* INS_$A4 */ PACK( 0, 0 ),
+ /* INS_$A5 */ PACK( 0, 0 ),
+ /* INS_$A6 */ PACK( 0, 0 ),
+ /* INS_$A7 */ PACK( 0, 0 ),
+ /* INS_$A8 */ PACK( 0, 0 ),
+ /* INS_$A9 */ PACK( 0, 0 ),
+ /* INS_$AA */ PACK( 0, 0 ),
+ /* INS_$AB */ PACK( 0, 0 ),
+ /* INS_$AC */ PACK( 0, 0 ),
+ /* INS_$AD */ PACK( 0, 0 ),
+ /* INS_$AE */ PACK( 0, 0 ),
+ /* INS_$AF */ PACK( 0, 0 ),
+
+ /* PushB[0] */ PACK( 0, 1 ),
+ /* PushB[1] */ PACK( 0, 2 ),
+ /* PushB[2] */ PACK( 0, 3 ),
+ /* PushB[3] */ PACK( 0, 4 ),
+ /* PushB[4] */ PACK( 0, 5 ),
+ /* PushB[5] */ PACK( 0, 6 ),
+ /* PushB[6] */ PACK( 0, 7 ),
+ /* PushB[7] */ PACK( 0, 8 ),
+ /* PushW[0] */ PACK( 0, 1 ),
+ /* PushW[1] */ PACK( 0, 2 ),
+ /* PushW[2] */ PACK( 0, 3 ),
+ /* PushW[3] */ PACK( 0, 4 ),
+ /* PushW[4] */ PACK( 0, 5 ),
+ /* PushW[5] */ PACK( 0, 6 ),
+ /* PushW[6] */ PACK( 0, 7 ),
+ /* PushW[7] */ PACK( 0, 8 ),
+
+ /* MDRP[00] */ PACK( 1, 0 ),
+ /* MDRP[01] */ PACK( 1, 0 ),
+ /* MDRP[02] */ PACK( 1, 0 ),
+ /* MDRP[03] */ PACK( 1, 0 ),
+ /* MDRP[04] */ PACK( 1, 0 ),
+ /* MDRP[05] */ PACK( 1, 0 ),
+ /* MDRP[06] */ PACK( 1, 0 ),
+ /* MDRP[07] */ PACK( 1, 0 ),
+ /* MDRP[08] */ PACK( 1, 0 ),
+ /* MDRP[09] */ PACK( 1, 0 ),
+ /* MDRP[10] */ PACK( 1, 0 ),
+ /* MDRP[11] */ PACK( 1, 0 ),
+ /* MDRP[12] */ PACK( 1, 0 ),
+ /* MDRP[13] */ PACK( 1, 0 ),
+ /* MDRP[14] */ PACK( 1, 0 ),
+ /* MDRP[15] */ PACK( 1, 0 ),
+
+ /* MDRP[16] */ PACK( 1, 0 ),
+ /* MDRP[17] */ PACK( 1, 0 ),
+ /* MDRP[18] */ PACK( 1, 0 ),
+ /* MDRP[19] */ PACK( 1, 0 ),
+ /* MDRP[20] */ PACK( 1, 0 ),
+ /* MDRP[21] */ PACK( 1, 0 ),
+ /* MDRP[22] */ PACK( 1, 0 ),
+ /* MDRP[23] */ PACK( 1, 0 ),
+ /* MDRP[24] */ PACK( 1, 0 ),
+ /* MDRP[25] */ PACK( 1, 0 ),
+ /* MDRP[26] */ PACK( 1, 0 ),
+ /* MDRP[27] */ PACK( 1, 0 ),
+ /* MDRP[28] */ PACK( 1, 0 ),
+ /* MDRP[29] */ PACK( 1, 0 ),
+ /* MDRP[30] */ PACK( 1, 0 ),
+ /* MDRP[31] */ PACK( 1, 0 ),
+
+ /* MIRP[00] */ PACK( 2, 0 ),
+ /* MIRP[01] */ PACK( 2, 0 ),
+ /* MIRP[02] */ PACK( 2, 0 ),
+ /* MIRP[03] */ PACK( 2, 0 ),
+ /* MIRP[04] */ PACK( 2, 0 ),
+ /* MIRP[05] */ PACK( 2, 0 ),
+ /* MIRP[06] */ PACK( 2, 0 ),
+ /* MIRP[07] */ PACK( 2, 0 ),
+ /* MIRP[08] */ PACK( 2, 0 ),
+ /* MIRP[09] */ PACK( 2, 0 ),
+ /* MIRP[10] */ PACK( 2, 0 ),
+ /* MIRP[11] */ PACK( 2, 0 ),
+ /* MIRP[12] */ PACK( 2, 0 ),
+ /* MIRP[13] */ PACK( 2, 0 ),
+ /* MIRP[14] */ PACK( 2, 0 ),
+ /* MIRP[15] */ PACK( 2, 0 ),
+
+ /* MIRP[16] */ PACK( 2, 0 ),
+ /* MIRP[17] */ PACK( 2, 0 ),
+ /* MIRP[18] */ PACK( 2, 0 ),
+ /* MIRP[19] */ PACK( 2, 0 ),
+ /* MIRP[20] */ PACK( 2, 0 ),
+ /* MIRP[21] */ PACK( 2, 0 ),
+ /* MIRP[22] */ PACK( 2, 0 ),
+ /* MIRP[23] */ PACK( 2, 0 ),
+ /* MIRP[24] */ PACK( 2, 0 ),
+ /* MIRP[25] */ PACK( 2, 0 ),
+ /* MIRP[26] */ PACK( 2, 0 ),
+ /* MIRP[27] */ PACK( 2, 0 ),
+ /* MIRP[28] */ PACK( 2, 0 ),
+ /* MIRP[29] */ PACK( 2, 0 ),
+ /* MIRP[30] */ PACK( 2, 0 ),
+ /* MIRP[31] */ PACK( 2, 0 )
+ };
+
+ static const TT_Vector Null_Vector = {0,0};
+
+#undef NULL_Vector
+#define NULL_Vector (TT_Vector*)&Null_Vector
+
+
+/*******************************************************************
+ *
+ * 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 )
+ {
+ TT_Int64 T1, T2;
+
+
+ MUL_64( X, X, T1 );
+ MUL_64( Y, Y, T2 );
+
+ ADD_64( T1, T2, T1 );
+
+ return (TT_F26Dot6)SQRT_64( T1 );
+ }
+
+
+/*******************************************************************
+ *
+ * Function : FUnits_To_Pixels
+ *
+ * Description : Scale a distance in FUnits to pixel coordinates.
+ *
+ * Input : Distance in FUnits
+ *
+ * Output : Distance in 26.6 format.
+ *
+ *****************************************************************/
+
+ static TT_F26Dot6 FUnits_To_Pixels( EXEC_OPS Short distance )
+ {
+ return TT_MulDiv( distance,
+ CUR.metrics.scale1,
+ CUR.metrics.scale2 );
+ }
+
+
+/*******************************************************************
+ *
+ * Function : Current_Ratio
+ *
+ * Description : Return the current aspect ratio scaling factor
+ * depending on the projection vector's state and
+ * device resolutions.
+ *
+ * Input : None
+ *
+ * Output : Aspect ratio in 16.16 format, always <= 1.0 .
+ *
+ *****************************************************************/
+
+ static Long Current_Ratio( EXEC_OP )
+ {
+ if ( CUR.metrics.ratio )
+ return CUR.metrics.ratio;
+
+ if ( CUR.GS.projVector.y == 0 )
+ CUR.metrics.ratio = CUR.metrics.x_ratio;
+
+ else if ( CUR.GS.projVector.x == 0 )
+ CUR.metrics.ratio = CUR.metrics.y_ratio;
+
+ else
+ {
+ Long x, y;
+
+
+ x = TT_MulDiv( CUR.GS.projVector.x, CUR.metrics.x_ratio, 0x4000 );
+ y = TT_MulDiv( CUR.GS.projVector.y, CUR.metrics.y_ratio, 0x4000 );
+ CUR.metrics.ratio = Norm( x, y );
+ }
+
+ return CUR.metrics.ratio;
+ }
+
+
+ static Long Current_Ppem( EXEC_OP )
+ {
+ return TT_MulFix( CUR.metrics.ppem, CURRENT_Ratio() );
+ }
+
+
+ static TT_F26Dot6 Read_CVT( EXEC_OPS ULong index )
+ {
+ return CUR.cvt[index];
+ }
+
+
+ static TT_F26Dot6 Read_CVT_Stretched( EXEC_OPS ULong index )
+ {
+ return TT_MulFix( CUR.cvt[index], CURRENT_Ratio() );
+ }
+
+
+ static void Write_CVT( EXEC_OPS ULong index, TT_F26Dot6 value )
+ {
+ CUR.cvt[index] = value;
+ }
+
+ static void Write_CVT_Stretched( EXEC_OPS ULong index, TT_F26Dot6 value )
+ {
+ CUR.cvt[index] = TT_MulDiv( value, 0x10000, CURRENT_Ratio() );
+ }
+
+
+ static void Move_CVT( EXEC_OPS ULong index, TT_F26Dot6 value )
+ {
+ CUR.cvt[index] += value;
+ }
+
+ static void Move_CVT_Stretched( EXEC_OPS ULong index, TT_F26Dot6 value )
+ {
+ CUR.cvt[index] += TT_MulDiv( value, 0x10000, CURRENT_Ratio() );
+ }
+
+
+/******************************************************************
+ *
+ * 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 : Returns a short integer taken from the instruction
+ * stream at address IP.
+ *
+ * Input : None
+ *
+ * Output : Short read at Code^[IP..IP+1]
+ *
+ * Notes : Called through the GET_ShortIns() macro.
+ *
+ *****************************************************************/
+
+ static Short GetShortIns( EXEC_OP )
+ {
+ /* Reading a byte stream so there is no endianess (DaveP) */
+ CUR.IP += 2;
+ return (Short)((CUR.code[CUR.IP - 2] << 8) + CUR.code[CUR.IP - 1]);
+ }
+
+
+/*******************************************************************
+ *
+ * Function : Ins_Goto_CodeRange
+ *
+ * Description : Goes to a certain code range in the instruction
+ * stream.
+ *
+ * Input : aRange
+ * aIP
+ *
+ * Output : SUCCESS or FAILURE.
+ *
+ *****************************************************************/
+
+ static Bool Ins_Goto_CodeRange( EXEC_OPS Int aRange, ULong aIP )
+ {
+ TCodeRange* WITH;
+
+
+ if ( aRange < 1 || aRange > 3 )
+ {
+ CUR.error = TT_Err_Bad_Argument;
+ return FAILURE;
+ }
+
+ WITH = &CUR.codeRangeTable[aRange - 1];
+
+ if ( WITH->Base == NULL ) /* 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. The point will be touched.
+ *
+ * Input : point index of point to move
+ * distance distance to apply
+ * zone affected glyph zone
+ *
+ * Output : None
+ *
+ *****************************************************************/
+
+ static void Direct_Move( EXEC_OPS PGlyph_Zone zone,
+ UShort point,
+ TT_F26Dot6 distance )
+ {
+ TT_F26Dot6 v;
+
+
+ v = CUR.GS.freeVector.x;
+
+ if ( v != 0 )
+ {
+ zone->cur[point].x += TT_MulDiv( distance,
+ v * 0x10000L,
+ CUR.F_dot_P );
+
+ zone->touch[point] |= TT_Flag_Touched_X;
+ }
+
+ v = CUR.GS.freeVector.y;
+
+ if ( v != 0 )
+ {
+ zone->cur[point].y += TT_MulDiv( distance,
+ v * 0x10000L,
+ CUR.F_dot_P );
+
+ zone->touch[point] |= TT_Flag_Touched_Y;
+ }
+ }
+
+
+/******************************************************************/
+/* */
+/* 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 PGlyph_Zone zone,
+ UShort point,
+ TT_F26Dot6 distance )
+ {
+ zone->cur[point].x += distance;
+ zone->touch[point] |= TT_Flag_Touched_X;
+ }
+
+
+/*******************************************************************
+ * Direct_Move_Y
+ *
+ *******************************************************************/
+
+ static void Direct_Move_Y( EXEC_OPS PGlyph_Zone zone,
+ UShort point,
+ TT_F26Dot6 distance )
+ {
+ zone->cur[point].y += distance;
+ zone->touch[point] |= TT_Flag_Touched_Y;
+ }
+
+
+/*******************************************************************
+ *
+ * Function : Round_None
+ *
+ * Description : Does not round, but adds 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 : Rounds 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;
+ if ( val > 0 )
+ val &= ~63;
+ else
+ val = 0;
+ }
+ else
+ {
+ val = -( (compensation - distance + 32) & (-64) );
+ if ( val > 0 )
+ val = 0;
+ }
+
+ return val;
+ }
+
+
+/*******************************************************************
+ *
+ * Function : Round_To_Half_Grid
+ *
+ * Description : Rounds 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 : Rounds 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;
+ if ( val > 0 )
+ val &= ~63;
+ else
+ val = 0;
+ }
+ else
+ {
+ val = -( (compensation - distance) & (-64) );
+ if ( val > 0 )
+ val = 0;
+ }
+
+ return val;
+ }
+
+
+/*******************************************************************
+ *
+ * Function : Round_Up_To_Grid
+ *
+ * Description : Rounds 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;
+ if ( val > 0 )
+ val &= ~63;
+ else
+ val = 0;
+ }
+ else
+ {
+ val = -( (compensation - distance + 63) & (-64) );
+ if ( val > 0 )
+ val = 0;
+ }
+
+ return val;
+ }
+
+
+/*******************************************************************
+ *
+ * Function : Round_To_Double_Grid
+ *
+ * Description : Rounds 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;
+ if ( val > 0 )
+ val &= ~31;
+ else
+ val = 0;
+ }
+ else
+ {
+ val = -( (compensation - distance + 16) & (-32) );
+ if ( val > 0 )
+ val = 0;
+ }
+
+ return val;
+ }
+
+
+/*******************************************************************
+ *
+ * Function : Round_Super
+ *
+ * Description : Super-rounds 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-rounds 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 : Sets Super Round parameters.
+ *
+ * Input : GridPeriod Grid period
+ * selector SROUND opcode
+ *
+ * Output : None.
+ *
+ *****************************************************************/
+
+ static void SetSuperRound( EXEC_OPS TT_F26Dot6 GridPeriod,
+ Long selector )
+ {
+ switch ( (Int)(selector & 0xC0) )
+ {
+ case 0:
+ CUR.period = GridPeriod / 2;
+ break;
+
+ case 0x40:
+ CUR.period = GridPeriod;
+ break;
+
+ case 0x80:
+ CUR.period = GridPeriod * 2;
+ break;
+
+ /* This opcode is reserved, but... */
+
+ case 0xC0:
+ CUR.period = GridPeriod;
+ break;
+ }
+
+ switch ( (Int)(selector & 0x30) )
+ {
+ case 0:
+ CUR.phase = 0;
+ break;
+
+ case 0x10:
+ CUR.phase = CUR.period / 4;
+ break;
+
+ case 0x20:
+ CUR.phase = CUR.period / 2;
+ break;
+
+ case 0x30:
+ CUR.phase = GridPeriod * 3 / 4;
+ break;
+ }
+
+ if ( (selector & 0x0F) == 0 )
+ CUR.threshold = CUR.period - 1;
+ else
+ CUR.threshold = ( (Int)(selector & 0x0F) - 4 ) * CUR.period / 8;
+
+ CUR.period /= 256;
+ CUR.phase /= 256;
+ CUR.threshold /= 256;
+ }
+
+
+/*******************************************************************
+ *
+ * Function : Project
+ *
+ * Description : Computes the projection of vector given by (v2-v1)
+ * along the current projection vector.
+ *
+ * Input : v1, v2 input vector
+ *
+ * Output : Returns distance in F26dot6 format.
+ *
+ *****************************************************************/
+
+ static TT_F26Dot6 Project( EXEC_OPS TT_Vector* v1,
+ TT_Vector* v2 )
+ {
+ TT_Int64 T1, T2;
+
+
+ MUL_64( v1->x - v2->x, CUR.GS.projVector.x, T1 );
+ MUL_64( v1->y - v2->y, CUR.GS.projVector.y, T2 );
+
+ ADD_64( T1, T2, T1 );
+
+ return (TT_F26Dot6)DIV_64( T1, 0x4000L );
+ }
+
+
+/*******************************************************************
+ *
+ * Function : Dual_Project
+ *
+ * Description : Computes the projection of the vector given by
+ * (v2-v1) along the current dual vector.
+ *
+ * Input : v1, v2 input vector
+ *
+ * Output : Returns distance in F26dot6 format.
+ *
+ *****************************************************************/
+
+ static TT_F26Dot6 Dual_Project( EXEC_OPS TT_Vector* v1,
+ TT_Vector* v2 )
+ {
+ TT_Int64 T1, T2;
+
+
+ MUL_64( v1->x - v2->x, CUR.GS.dualVector.x, T1 );
+ MUL_64( v1->y - v2->y, CUR.GS.dualVector.y, T2 );
+
+ ADD_64( T1, T2, T1 );
+
+ return (TT_F26Dot6)DIV_64( T1, 0x4000L );
+ }
+
+
+/*******************************************************************
+ *
+ * Function : Free_Project
+ *
+ * Description : Computes the projection of the vector given by
+ * (v2-v1) along the current freedom vector.
+ *
+ * Input : v1, v2 input vector
+ *
+ * Output : Returns distance in F26dot6 format.
+ *
+ *****************************************************************/
+
+ static TT_F26Dot6 Free_Project( EXEC_OPS TT_Vector* v1,
+ TT_Vector* v2 )
+ {
+ TT_Int64 T1, T2;
+
+
+ MUL_64( v1->x - v2->x, CUR.GS.freeVector.x, T1 );
+ MUL_64( v1->y - v2->y, CUR.GS.freeVector.y, T2 );
+
+ ADD_64( T1, T2, T1 );
+
+ return (TT_F26Dot6)DIV_64( T1, 0x4000L );
+ }
+
+
+/*******************************************************************
+ *
+ * Function : Project_x
+ *
+ * Input : Vx, Vy input vector
+ *
+ * Output : Returns Vx.
+ *
+ * Note : Used as a dummy function.
+ *
+ *****************************************************************/
+
+ static TT_F26Dot6 Project_x( EXEC_OPS TT_Vector* v1,
+ TT_Vector* v2 )
+ {
+ return (v1->x - v2->x);
+ }
+
+
+/*******************************************************************
+ *
+ * Function : Project_y
+ *
+ * Input : Vx, Vy input vector
+ *
+ * Output : Returns Vy.
+ *
+ * Note : Used as a dummy function.
+ *
+ *****************************************************************/
+
+ static TT_F26Dot6 Project_y( EXEC_OPS TT_Vector* v1,
+ TT_Vector* v2 )
+ {
+ return (v1->y - v2->y);
+ }
+
+
+/*******************************************************************
+ *
+ * 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_freeProj = (TProject_Function)Free_Project;
+ CUR.F_dot_P = (Long)CUR.GS.projVector.x * CUR.GS.freeVector.x * 4 +
+ (Long)CUR.GS.projVector.y * CUR.GS.freeVector.y * 4;
+ }
+ }
+
+ CUR.cached_metrics = FALSE;
+
+ if ( CUR.GS.projVector.x == 0x4000 )
+ CUR.func_project = (TProject_Function)Project_x;
+ else
+ {
+ if ( CUR.GS.projVector.y == 0x4000 )
+ CUR.func_project = (TProject_Function)Project_y;
+ else
+ CUR.func_project = (TProject_Function)Project;
+ }
+
+ if ( CUR.GS.dualVector.x == 0x4000 )
+ CUR.func_dualproj = (TProject_Function)Project_x;
+ else
+ {
+ if ( CUR.GS.dualVector.y == 0x4000 )
+ CUR.func_dualproj = (TProject_Function)Project_y;
+ else
+ CUR.func_dualproj = (TProject_Function)Dual_Project;
+ }
+
+ CUR.func_move = (TMove_Function)Direct_Move;
+
+ if ( CUR.F_dot_P == 0x40000000L )
+ {
+ if ( CUR.GS.freeVector.x == 0x4000 )
+ CUR.func_move = (TMove_Function)Direct_Move_X;
+ else
+ {
+ if ( CUR.GS.freeVector.y == 0x4000 )
+ CUR.func_move = (TMove_Function)Direct_Move_Y;
+ }
+ }
+
+ /* at small sizes, F_dot_P can become too small, resulting */
+ /* in overflows and 'spikes' in a number of glyphs like 'w'. */
+
+ if ( ABS( CUR.F_dot_P ) < 0x4000000L )
+ CUR.F_dot_P = 0x40000000L;
+
+ /* Disable cached aspect ratio */
+ CUR.metrics.ratio = 0;
+ }
+
+
+/*******************************************************************
+ *
+ * Function : Normalize
+ *
+ * Description : Norms a vector
+ *
+ * Input : Vx, Vy input vector
+ * R normed unit vector
+ *
+ * Output : Returns FAILURE if a vector parameter is zero.
+ *
+ *****************************************************************/
+
+ static Bool Normalize( EXEC_OPS TT_F26Dot6 Vx,
+ TT_F26Dot6 Vy,
+ TT_UnitVector* R )
+ {
+ TT_F26Dot6 W;
+ Bool S1, S2;
+
+
+ if ( ABS( Vx ) < 0x10000L && ABS( Vy ) < 0x10000L )
+ {
+ Vx *= 0x100;
+ Vy *= 0x100;
+
+ W = Norm( Vx, Vy );
+
+ if ( W == 0 )
+ {
+ /* UNDOCUMENTED! It seems that it's possible to try to */
+ /* normalize the vector (0,0). Return immediately. */
+ return SUCCESS;
+ }
+
+ R->x = (TT_F2Dot14)TT_MulDiv( Vx, 0x4000L, W );
+ R->y = (TT_F2Dot14)TT_MulDiv( Vy, 0x4000L, W );
+
+ return SUCCESS;
+ }
+
+ W = Norm( Vx, Vy );
+
+ Vx = TT_MulDiv( Vx, 0x4000L, W );
+ Vy = TT_MulDiv( Vy, 0x4000L, W );
+
+ W = Vx * Vx + Vy * Vy;
+
+ /* Now, we want that Sqrt( W ) = 0x4000 */
+ /* Or 0x1000000 <= W < 0x1004000 */
+
+ if ( Vx < 0 )
+ {
+ Vx = -Vx;
+ S1 = TRUE;
+ }
+ else
+ S1 = FALSE;
+
+ if ( Vy < 0 )
+ {
+ Vy = -Vy;
+ S2 = TRUE;
+ }
+ else
+ S2 = FALSE;
+
+ while ( W < 0x1000000L )
+ {
+ /* We need to increase W, by a minimal amount */
+ if ( Vx < Vy )
+ Vx++;
+ else
+ Vy++;
+
+ W = Vx * Vx + Vy * Vy;
+ }
+
+ while ( W >= 0x1004000L )
+ {
+ /* We need to decrease W, by a minimal amount */
+ if ( Vx < Vy )
+ Vx--;
+ else
+ Vy--;
+
+ W = Vx * Vx + Vy * Vy;
+ }
+
+ /* Note that in various cases, we can only */
+ /* compute a Sqrt(W) of 0x3FFF, eg. Vx = Vy */
+
+ if ( S1 )
+ Vx = -Vx;
+
+ if ( S2 )
+ Vy = -Vy;
+
+ R->x = (TT_F2Dot14)Vx; /* Type conversion */
+ R->y = (TT_F2Dot14)Vy; /* Type conversion */
+
+ return SUCCESS;
+ }
+
+
+/****************************************************************
+ *
+ * Opcodes
+ *
+ ****************************************************************/
+
+
+ static Bool Ins_SxVTL( EXEC_OPS UShort aIdx1,
+ UShort aIdx2,
+ Int aOpc,
+ TT_UnitVector* Vec )
+ {
+ Long A, B, C;
+ TT_Vector* p1;
+ TT_Vector* p2;
+
+
+ if ( BOUNDS( aIdx1, CUR.zp2.n_points ) ||
+ BOUNDS( aIdx2, CUR.zp1.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return FAILURE;
+ }
+
+ p1 = CUR.zp1.cur + aIdx2;
+ p2 = CUR.zp2.cur + aIdx1;
+
+ A = p1->x - p2->x;
+ B = p1->y - p2->y;
+
+ if ( (aOpc & 1) != 0 )
+ {
+ C = B; /* CounterClockwise rotation */
+ B = A;
+ A = -C;
+ }
+
+ NORMalize( A, B, Vec );
+ return SUCCESS;
+ }
+
+
+/* When not using the big switch statements, the interpreter uses a */
+/* call table defined later below in this source. Each opcode must */
+/* thus have a corresponding function, even trivial ones. */
+/* */
+/* They're all defined there. */
+
+#define DO_SVTCA \
+ { \
+ Short A, B; \
+ \
+ \
+ A = (Short)(CUR.opcode & 1) << 14; \
+ B = A ^ (Short)0x4000; \
+ \
+ CUR.GS.freeVector.x = A; \
+ CUR.GS.projVector.x = A; \
+ CUR.GS.dualVector.x = A; \
+ \
+ CUR.GS.freeVector.y = B; \
+ CUR.GS.projVector.y = B; \
+ CUR.GS.dualVector.y = B; \
+ \
+ COMPUTE_Funcs(); \
+ }
+
+
+#define DO_SPVTCA \
+ { \
+ Short A, B; \
+ \
+ \
+ A = (Short)(CUR.opcode & 1) << 14; \
+ B = A ^ (Short)0x4000; \
+ \
+ CUR.GS.projVector.x = A; \
+ CUR.GS.dualVector.x = A; \
+ \
+ CUR.GS.projVector.y = B; \
+ CUR.GS.dualVector.y = B; \
+ \
+ COMPUTE_Funcs(); \
+ }
+
+
+#define DO_SFVTCA \
+ { \
+ Short A, B; \
+ \
+ \
+ A = (Short)(CUR.opcode & 1) << 14; \
+ B = A ^ (Short)0x4000; \
+ \
+ CUR.GS.freeVector.x = A; \
+ CUR.GS.freeVector.y = B; \
+ \
+ COMPUTE_Funcs(); \
+ }
+
+
+#define DO_SPVTL \
+ if ( INS_SxVTL( (UShort)args[1], \
+ (UShort)args[0], \
+ CUR.opcode, \
+ &CUR.GS.projVector) == SUCCESS ) \
+ { \
+ CUR.GS.dualVector = CUR.GS.projVector; \
+ COMPUTE_Funcs(); \
+ }
+
+
+#define DO_SFVTL \
+ if ( INS_SxVTL( (UShort)args[1], \
+ (UShort)args[0], \
+ CUR.opcode, \
+ &CUR.GS.freeVector) == SUCCESS ) \
+ COMPUTE_Funcs();
+
+
+#define DO_SFVTPV \
+ CUR.GS.freeVector = CUR.GS.projVector; \
+ COMPUTE_Funcs();
+
+
+#define DO_SPVFS \
+ { \
+ Short S; \
+ Long X, Y; \
+ \
+ \
+ /* Only use low 16bits, then sign extend */ \
+ S = (Short)args[1]; \
+ Y = (Long)S; \
+ S = (Short)args[0]; \
+ X = (Long)S; \
+ \
+ NORMalize( X, Y, &CUR.GS.projVector ); \
+ \
+ CUR.GS.dualVector = CUR.GS.projVector; \
+ COMPUTE_Funcs(); \
+ }
+
+
+#define DO_SFVFS \
+ { \
+ Short S; \
+ Long X, Y; \
+ \
+ \
+ /* Only use low 16bits, then sign extend */ \
+ S = (Short)args[1]; \
+ Y = (Long)S; \
+ S = (Short)args[0]; \
+ X = S; \
+ \
+ NORMalize( X, Y, &CUR.GS.freeVector ); \
+ COMPUTE_Funcs(); \
+ }
+
+
+#define DO_GPV \
+ args[0] = CUR.GS.projVector.x; \
+ args[1] = CUR.GS.projVector.y;
+
+
+#define DO_GFV \
+ args[0] = CUR.GS.freeVector.x; \
+ args[1] = CUR.GS.freeVector.y;
+
+
+#define DO_SRP0 \
+ CUR.GS.rp0 = (UShort)args[0];
+
+
+#define DO_SRP1 \
+ CUR.GS.rp1 = (UShort)args[0];
+
+
+#define DO_SRP2 \
+ CUR.GS.rp2 = (UShort)args[0];
+
+
+#define DO_RTHG \
+ CUR.GS.round_state = TT_Round_To_Half_Grid; \
+ CUR.func_round = (TRound_Function)Round_To_Half_Grid;
+
+
+#define DO_RTG \
+ CUR.GS.round_state = TT_Round_To_Grid; \
+ CUR.func_round = (TRound_Function)Round_To_Grid;
+
+
+#define DO_RTDG \
+ CUR.GS.round_state = TT_Round_To_Double_Grid; \
+ CUR.func_round = (TRound_Function)Round_To_Double_Grid;
+
+
+#define DO_RUTG \
+ CUR.GS.round_state = TT_Round_Up_To_Grid; \
+ CUR.func_round = (TRound_Function)Round_Up_To_Grid;
+
+
+#define DO_RDTG \
+ CUR.GS.round_state = TT_Round_Down_To_Grid; \
+ CUR.func_round = (TRound_Function)Round_Down_To_Grid;
+
+
+#define DO_ROFF \
+ CUR.GS.round_state = TT_Round_Off; \
+ CUR.func_round = (TRound_Function)Round_None;
+
+
+#define DO_SROUND \
+ SET_SuperRound( 0x4000L, args[0] ); \
+ CUR.GS.round_state = TT_Round_Super; \
+ CUR.func_round = (TRound_Function)Round_Super;
+
+
+#define DO_S45ROUND \
+ SET_SuperRound( 0x2D41L, args[0] ); \
+ CUR.GS.round_state = TT_Round_Super_45; \
+ CUR.func_round = (TRound_Function)Round_Super_45;
+
+
+#define DO_SLOOP \
+ if ( args[0] < 0 ) \
+ CUR.error = TT_Err_Bad_Argument; \
+ else \
+ CUR.GS.loop = args[0];
+
+
+#define DO_SMD \
+ CUR.GS.minimum_distance = (TT_F26Dot6)args[0];
+
+
+#define DO_SCVTCI \
+ CUR.GS.control_value_cutin = (TT_F26Dot6)args[0];
+
+
+#define DO_SSWCI \
+ CUR.GS.single_width_cutin = (TT_F26Dot6)args[0];
+
+
+ /* XXX : UNDOCUMENTED! or bug in the Windows engine? */
+ /* */
+ /* It seems that the value that is read here is */
+ /* expressed in 16.16 format, rather than in */
+ /* font units.. */
+ /* */
+#define DO_SSW \
+ CUR.GS.single_width_value = (TT_F26Dot6)(args[0] >> 10);
+
+
+#define DO_FLIPON \
+ CUR.GS.auto_flip = TRUE;
+
+
+#define DO_FLIPOFF \
+ CUR.GS.auto_flip = FALSE;
+
+
+#define DO_SDB \
+ CUR.GS.delta_base = (Short)args[0];
+
+
+#define DO_SDS \
+ CUR.GS.delta_shift = (Short)args[0];
+
+
+#define DO_MD /* nothing */
+
+
+#define DO_MPPEM \
+ args[0] = CURRENT_Ppem();
+
+
+#define DO_MPS \
+ args[0] = CUR.metrics.pointSize;
+
+
+#define DO_DUP \
+ args[1] = args[0];
+
+
+#define DO_CLEAR \
+ CUR.new_top = 0;
+
+
+#define DO_SWAP \
+ { \
+ Long L; \
+ \
+ L = args[0]; \
+ args[0] = args[1]; \
+ args[1] = L; \
+ }
+
+
+#define DO_DEPTH \
+ args[0] = CUR.top;
+
+
+#define DO_CINDEX \
+ { \
+ Long L; \
+ \
+ \
+ L = args[0]; \
+ \
+ if ( L <= 0 || L > CUR.args ) \
+ CUR.error = TT_Err_Invalid_Reference; \
+ else \
+ args[0] = CUR.stack[CUR.args - L]; \
+ }
+
+
+#define DO_JROT \
+ if ( args[1] != 0 ) \
+ { \
+ CUR.IP += args[0]; \
+ CUR.step_ins = FALSE; \
+ }
+
+
+#define DO_JMPR \
+ CUR.IP += args[0]; \
+ CUR.step_ins = FALSE;
+
+
+#define DO_JROF \
+ if ( args[1] == 0 ) \
+ { \
+ CUR.IP += args[0]; \
+ CUR.step_ins = FALSE; \
+ }
+
+
+#define DO_LT \
+ args[0] = (args[0] < args[1]);
+
+
+#define DO_LTEQ \
+ args[0] = (args[0] <= args[1]);
+
+
+#define DO_GT \
+ args[0] = (args[0] > args[1]);
+
+
+#define DO_GTEQ \
+ args[0] = (args[0] >= args[1]);
+
+
+#define DO_EQ \
+ args[0] = (args[0] == args[1]);
+
+
+#define DO_NEQ \
+ args[0] = (args[0] != args[1]);
+
+
+#define DO_ODD \
+ args[0] = ( (CUR_Func_round( args[0], 0 ) & 127) == 64 );
+
+
+#define DO_EVEN \
+ args[0] = ( (CUR_Func_round( args[0], 0 ) & 127) == 0 );
+
+
+#define DO_AND \
+ args[0] = ( args[0] && args[1] );
+
+
+#define DO_OR \
+ args[0] = ( args[0] || args[1] );
+
+
+#define DO_NOT \
+ args[0] = !args[0];
+
+
+#define DO_ADD \
+ args[0] += args[1];
+
+
+#define DO_SUB \
+ args[0] -= args[1];
+
+
+#define DO_DIV \
+ if ( args[1] == 0 ) \
+ CUR.error = TT_Err_Divide_By_Zero; \
+ else \
+ args[0] = TT_MulDiv( args[0], 64L, args[1] );
+
+
+#define DO_MUL \
+ args[0] = TT_MulDiv( args[0], args[1], 64L );
+
+
+#define DO_ABS \
+ args[0] = ABS( args[0] );
+
+
+#define DO_NEG \
+ args[0] = -args[0];
+
+
+#define DO_FLOOR \
+ args[0] &= -64;
+
+
+#define DO_CEILING \
+ args[0] = (args[0] + 63) & (-64);
+
+
+#define DO_RS \
+ { \
+ ULong I = (ULong)args[0]; \
+ if ( BOUNDS( I, CUR.storeSize ) ) \
+ { \
+ if ( CUR.pedantic_hinting ) \
+ { \
+ ARRAY_BOUND_ERROR; \
+ } \
+ else \
+ args[0] = 0; \
+ } \
+ else \
+ args[0] = CUR.storage[I]; \
+ }
+
+
+#define DO_WS \
+ { \
+ ULong I = (ULong)args[0]; \
+ if ( BOUNDS( I, CUR.storeSize ) ) \
+ { \
+ if ( CUR.pedantic_hinting ) \
+ { \
+ ARRAY_BOUND_ERROR; \
+ } \
+ } \
+ else \
+ CUR.storage[I] = args[1]; \
+ }
+
+
+
+#define DO_RCVT \
+ { \
+ ULong I = (ULong)args[0]; \
+ if ( BOUNDS( I, CUR.cvtSize ) ) \
+ { \
+ if ( CUR.pedantic_hinting ) \
+ { \
+ ARRAY_BOUND_ERROR; \
+ } \
+ else \
+ args[0] = 0; \
+ } \
+ else \
+ args[0] = CUR_Func_read_cvt(I); \
+ }
+
+
+#define DO_WCVTP \
+ { \
+ ULong I = (ULong)args[0]; \
+ if ( BOUNDS( I, CUR.cvtSize ) ) \
+ { \
+ if ( CUR.pedantic_hinting ) \
+ { \
+ ARRAY_BOUND_ERROR; \
+ } \
+ } \
+ else \
+ CUR_Func_write_cvt( I, args[1] ); \
+ }
+
+
+#define DO_WCVTF \
+ { \
+ ULong I = (ULong)args[0]; \
+ if ( BOUNDS( I, CUR.cvtSize ) ) \
+ { \
+ if ( CUR.pedantic_hinting ) \
+ { \
+ ARRAY_BOUND_ERROR; \
+ } \
+ } \
+ else \
+ CUR.cvt[I] = FUnits_To_Pixels( EXEC_ARGS (Short)args[1] ); \
+ }
+
+
+#define DO_DEBUG \
+ CUR.error = TT_Err_Debug_OpCode;
+
+
+#define DO_ROUND \
+ args[0] = CUR_Func_round( args[0], \
+ CUR.metrics.compensations[CUR.opcode-0x68] );
+
+
+#define DO_NROUND \
+ args[0] = Round_None( EXEC_ARGS \
+ args[0], \
+ CUR.metrics.compensations[CUR.opcode - 0x6C] );
+
+
+#define DO_MAX \
+ if ( args[1] > args[0] ) \
+ args[0] = args[1];
+
+
+#define DO_MIN \
+ if ( args[1] < args[0] ) \
+ args[0] = args[1];
+
+
+#ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
+
+
+#undef ARRAY_BOUND_ERROR
+#define ARRAY_BOUND_ERROR \
+ { \
+ CUR.error = TT_Err_Invalid_Reference; \
+ return; \
+ }
+
+
+/*******************************************/
+/* SVTCA[a] : Set F and P vectors to axis */
+/* CodeRange : $00-$01 */
+/* Stack : --> */
+
+ static void Ins_SVTCA( INS_ARG )
+ {
+ DO_SVTCA
+ }
+
+
+/*******************************************/
+/* SPVTCA[a] : Set PVector to Axis */
+/* CodeRange : $02-$03 */
+/* Stack : --> */
+
+ static void Ins_SPVTCA( INS_ARG )
+ {
+ DO_SPVTCA
+ }
+
+
+/*******************************************/
+/* SFVTCA[a] : Set FVector to Axis */
+/* CodeRange : $04-$05 */
+/* Stack : --> */
+
+ static void Ins_SFVTCA( INS_ARG )
+ {
+ DO_SFVTCA
+ }
+
+/*******************************************/
+/* SPVTL[a] : Set PVector to Line */
+/* CodeRange : $06-$07 */
+/* Stack : uint32 uint32 --> */
+
+ static void Ins_SPVTL( INS_ARG )
+ {
+ DO_SPVTL
+ }
+
+
+/*******************************************/
+/* SFVTL[a] : Set FVector to Line */
+/* CodeRange : $08-$09 */
+/* Stack : uint32 uint32 --> */
+
+ static void Ins_SFVTL( INS_ARG )
+ {
+ DO_SFVTL
+ }
+
+
+/*******************************************/
+/* SFVTPV[] : Set FVector to PVector */
+/* CodeRange : $0E */
+/* Stack : --> */
+
+ static void Ins_SFVTPV( INS_ARG )
+ {
+ DO_SFVTPV
+ }
+
+
+/*******************************************/
+/* SPVFS[] : Set PVector From Stack */
+/* CodeRange : $0A */
+/* Stack : f2.14 f2.14 --> */
+
+ static void Ins_SPVFS( INS_ARG )
+ {
+ DO_SPVFS
+ }
+
+
+/*******************************************/
+/* SFVFS[] : Set FVector From Stack */
+/* CodeRange : $0B */
+/* Stack : f2.14 f2.14 --> */
+
+ static void Ins_SFVFS( INS_ARG )
+ {
+ DO_SFVFS
+ }
+
+
+/*******************************************/
+/* GPV[] : Get Projection Vector */
+/* CodeRange : $0C */
+/* Stack : ef2.14 --> ef2.14 */
+
+ static void Ins_GPV( INS_ARG )
+ {
+ DO_GPV
+ }
+
+
+/*******************************************/
+/* GFV[] : Get Freedom Vector */
+/* CodeRange : $0D */
+/* Stack : ef2.14 --> ef2.14 */
+
+ static void Ins_GFV( INS_ARG )
+ {
+ DO_GFV
+ }
+
+
+/*******************************************/
+/* SRP0[] : Set Reference Point 0 */
+/* CodeRange : $10 */
+/* Stack : uint32 --> */
+
+ static void Ins_SRP0( INS_ARG )
+ {
+ DO_SRP0
+ }
+
+
+/*******************************************/
+/* SRP1[] : Set Reference Point 1 */
+/* CodeRange : $11 */
+/* Stack : uint32 --> */
+
+ static void Ins_SRP1( INS_ARG )
+ {
+ DO_SRP1
+ }
+
+
+/*******************************************/
+/* SRP2[] : Set Reference Point 2 */
+/* CodeRange : $12 */
+/* Stack : uint32 --> */
+
+ static void Ins_SRP2( INS_ARG )
+ {
+ DO_SRP2
+ }
+
+
+/*******************************************/
+/* RTHG[] : Round To Half Grid */
+/* CodeRange : $19 */
+/* Stack : --> */
+
+ static void Ins_RTHG( INS_ARG )
+ {
+ DO_RTHG
+ }
+
+
+/*******************************************/
+/* RTG[] : Round To Grid */
+/* CodeRange : $18 */
+/* Stack : --> */
+
+ static void Ins_RTG( INS_ARG )
+ {
+ DO_RTG
+ }
+
+
+/*******************************************/
+/* RTDG[] : Round To Double Grid */
+/* CodeRange : $3D */
+/* Stack : --> */
+
+ static void Ins_RTDG( INS_ARG )
+ {
+ DO_RTDG
+ }
+
+
+/*******************************************/
+/* RUTG[] : Round Up To Grid */
+/* CodeRange : $7C */
+/* Stack : --> */
+
+ static void Ins_RUTG( INS_ARG )
+ {
+ DO_RUTG
+ }
+
+
+/*******************************************/
+/* RDTG[] : Round Down To Grid */
+/* CodeRange : $7D */
+/* Stack : --> */
+
+ static void Ins_RDTG( INS_ARG )
+ {
+ DO_RDTG
+ }
+
+
+/*******************************************/
+/* ROFF[] : Round OFF */
+/* CodeRange : $7A */
+/* Stack : --> */
+
+ static void Ins_ROFF( INS_ARG )
+ {
+ DO_ROFF
+ }
+
+
+/*******************************************/
+/* SROUND[] : Super ROUND */
+/* CodeRange : $76 */
+/* Stack : Eint8 --> */
+
+ static void Ins_SROUND( INS_ARG )
+ {
+ DO_SROUND
+ }
+
+
+/*******************************************/
+/* S45ROUND[]: Super ROUND 45 degrees */
+/* CodeRange : $77 */
+/* Stack : uint32 --> */
+
+ static void Ins_S45ROUND( INS_ARG )
+ {
+ DO_S45ROUND
+ }
+
+
+/*******************************************/
+/* SLOOP[] : Set LOOP variable */
+/* CodeRange : $17 */
+/* Stack : int32? --> */
+
+ static void Ins_SLOOP( INS_ARG )
+ {
+ DO_SLOOP
+ }
+
+
+/*******************************************/
+/* SMD[] : Set Minimum Distance */
+/* CodeRange : $1A */
+/* Stack : f26.6 --> */
+
+ static void Ins_SMD( INS_ARG )
+ {
+ DO_SMD
+ }
+
+
+/**********************************************/
+/* SCVTCI[] : Set Control Value Table Cut In */
+/* CodeRange : $1D */
+/* Stack : f26.6 --> */
+
+ static void Ins_SCVTCI( INS_ARG )
+ {
+ DO_SCVTCI
+ }
+
+
+/**********************************************/
+/* SSWCI[] : Set Single Width Cut In */
+/* CodeRange : $1E */
+/* Stack : f26.6 --> */
+
+ static void Ins_SSWCI( INS_ARG )
+ {
+ DO_SSWCI
+ }
+
+
+/**********************************************/
+/* SSW[] : Set Single Width */
+/* CodeRange : $1F */
+/* Stack : int32? --> */
+
+ static void Ins_SSW( INS_ARG )
+ {
+ DO_SSW
+ }
+
+
+/**********************************************/
+/* FLIPON[] : Set Auto_flip to On */
+/* CodeRange : $4D */
+/* Stack : --> */
+
+ static void Ins_FLIPON( INS_ARG )
+ {
+ DO_FLIPON
+ }
+
+
+/**********************************************/
+/* FLIPOFF[] : Set Auto_flip to Off */
+/* CodeRange : $4E */
+/* Stack : --> */
+
+ static void Ins_FLIPOFF( INS_ARG )
+ {
+ DO_FLIPOFF
+ }
+
+
+/**********************************************/
+/* SANGW[] : Set Angle Weight */
+/* CodeRange : $7E */
+/* Stack : uint32 --> */
+
+ static void Ins_SANGW( INS_ARG )
+ {
+ /* instruction not supported anymore */
+ }
+
+
+/**********************************************/
+/* SDB[] : Set Delta Base */
+/* CodeRange : $5E */
+/* Stack : uint32 --> */
+
+ static void Ins_SDB( INS_ARG )
+ {
+ DO_SDB
+ }
+
+
+/**********************************************/
+/* SDS[] : Set Delta Shift */
+/* CodeRange : $5F */
+/* Stack : uint32 --> */
+
+ static void Ins_SDS( INS_ARG )
+ {
+ DO_SDS
+ }
+
+
+/**********************************************/
+/* MPPEM[] : Measure Pixel Per EM */
+/* CodeRange : $4B */
+/* Stack : --> Euint16 */
+
+ static void Ins_MPPEM( INS_ARG )
+ {
+ DO_MPPEM
+ }
+
+
+/**********************************************/
+/* MPS[] : Measure PointSize */
+/* CodeRange : $4C */
+/* Stack : --> Euint16 */
+
+ static void Ins_MPS( INS_ARG )
+ {
+ DO_MPS
+ }
+
+/*******************************************/
+/* DUP[] : Duplicate top stack element */
+/* CodeRange : $20 */
+/* Stack : StkElt --> StkElt StkElt */
+
+ static void Ins_DUP( INS_ARG )
+ {
+ DO_DUP
+ }
+
+
+/*******************************************/
+/* POP[] : POPs the stack's top elt. */
+/* CodeRange : $21 */
+/* Stack : StkElt --> */
+
+ static void Ins_POP( INS_ARG )
+ {
+ /* nothing to do */
+ }
+
+
+/*******************************************/
+/* CLEAR[] : Clear the entire stack */
+/* CodeRange : $22 */
+/* Stack : StkElt... --> */
+
+ static void Ins_CLEAR( INS_ARG )
+ {
+ DO_CLEAR
+ }
+
+
+/*******************************************/
+/* SWAP[] : Swap the top two elements */
+/* CodeRange : $23 */
+/* Stack : 2 * StkElt --> 2 * StkElt */
+
+ static void Ins_SWAP( INS_ARG )
+ {
+ DO_SWAP
+ }
+
+
+/*******************************************/
+/* DEPTH[] : return the stack depth */
+/* CodeRange : $24 */
+/* Stack : --> uint32 */
+
+ static void Ins_DEPTH( INS_ARG )
+ {
+ DO_DEPTH
+ }
+
+
+/*******************************************/
+/* CINDEX[] : copy indexed element */
+/* CodeRange : $25 */
+/* Stack : int32 --> StkElt */
+
+ static void Ins_CINDEX( INS_ARG )
+ {
+ DO_CINDEX
+ }
+
+
+/*******************************************/
+/* EIF[] : End IF */
+/* CodeRange : $59 */
+/* Stack : --> */
+
+ static void Ins_EIF( INS_ARG )
+ {
+ /* nothing to do */
+ }
+
+
+/*******************************************/
+/* JROT[] : Jump Relative On True */
+/* CodeRange : $78 */
+/* Stack : StkElt int32 --> */
+
+ static void Ins_JROT( INS_ARG )
+ {
+ DO_JROT
+ }
+
+
+/*******************************************/
+/* JMPR[] : JuMP Relative */
+/* CodeRange : $1C */
+/* Stack : int32 --> */
+
+ static void Ins_JMPR( INS_ARG )
+ {
+ DO_JMPR
+ }
+
+
+/*******************************************/
+/* JROF[] : Jump Relative On False */
+/* CodeRange : $79 */
+/* Stack : StkElt int32 --> */
+
+ static void Ins_JROF( INS_ARG )
+ {
+ DO_JROF
+ }
+
+
+/*******************************************/
+/* LT[] : Less Than */
+/* CodeRange : $50 */
+/* Stack : int32? int32? --> bool */
+
+ static void Ins_LT( INS_ARG )
+ {
+ DO_LT
+ }
+
+
+/*******************************************/
+/* LTEQ[] : Less Than or EQual */
+/* CodeRange : $51 */
+/* Stack : int32? int32? --> bool */
+
+ static void Ins_LTEQ( INS_ARG )
+ {
+ DO_LTEQ
+ }
+
+
+/*******************************************/
+/* GT[] : Greater Than */
+/* CodeRange : $52 */
+/* Stack : int32? int32? --> bool */
+
+ static void Ins_GT( INS_ARG )
+ {
+ DO_GT
+ }
+
+
+/*******************************************/
+/* GTEQ[] : Greater Than or EQual */
+/* CodeRange : $53 */
+/* Stack : int32? int32? --> bool */
+
+ static void Ins_GTEQ( INS_ARG )
+ {
+ DO_GTEQ
+ }
+
+
+/*******************************************/
+/* EQ[] : EQual */
+/* CodeRange : $54 */
+/* Stack : StkElt StkElt --> bool */
+
+ static void Ins_EQ( INS_ARG )
+ {
+ DO_EQ
+ }
+
+
+/*******************************************/
+/* NEQ[] : Not EQual */
+/* CodeRange : $55 */
+/* Stack : StkElt StkElt --> bool */
+
+ static void Ins_NEQ( INS_ARG )
+ {
+ DO_NEQ
+ }
+
+
+/*******************************************/
+/* ODD[] : Odd */
+/* CodeRange : $56 */
+/* Stack : f26.6 --> bool */
+
+ static void Ins_ODD( INS_ARG )
+ {
+ DO_ODD
+ }
+
+
+/*******************************************/
+/* EVEN[] : Even */
+/* CodeRange : $57 */
+/* Stack : f26.6 --> bool */
+
+ static void Ins_EVEN( INS_ARG )
+ {
+ DO_EVEN
+ }
+
+
+/*******************************************/
+/* AND[] : logical AND */
+/* CodeRange : $5A */
+/* Stack : uint32 uint32 --> uint32 */
+
+ static void Ins_AND( INS_ARG )
+ {
+ DO_AND
+ }
+
+
+/*******************************************/
+/* OR[] : logical OR */
+/* CodeRange : $5B */
+/* Stack : uint32 uint32 --> uint32 */
+
+ static void Ins_OR( INS_ARG )
+ {
+ DO_OR
+ }
+
+
+/*******************************************/
+/* NOT[] : logical NOT */
+/* CodeRange : $5C */
+/* Stack : StkElt --> uint32 */
+
+ static void Ins_NOT( INS_ARG )
+ {
+ DO_NOT
+ }
+
+
+/*******************************************/
+/* ADD[] : ADD */
+/* CodeRange : $60 */
+/* Stack : f26.6 f26.6 --> f26.6 */
+
+ static void Ins_ADD( INS_ARG )
+ {
+ DO_ADD
+ }
+
+
+/*******************************************/
+/* SUB[] : SUBstract */
+/* CodeRange : $61 */
+/* Stack : f26.6 f26.6 --> f26.6 */
+
+ static void Ins_SUB( INS_ARG )
+ {
+ DO_SUB
+ }
+
+
+/*******************************************/
+/* DIV[] : DIVide */
+/* CodeRange : $62 */
+/* Stack : f26.6 f26.6 --> f26.6 */
+
+ static void Ins_DIV( INS_ARG )
+ {
+ DO_DIV
+ }
+
+
+/*******************************************/
+/* MUL[] : MULtiply */
+/* CodeRange : $63 */
+/* Stack : f26.6 f26.6 --> f26.6 */
+
+ static void Ins_MUL( INS_ARG )
+ {
+ DO_MUL
+ }
+
+
+/*******************************************/
+/* ABS[] : ABSolute value */
+/* CodeRange : $64 */
+/* Stack : f26.6 --> f26.6 */
+
+ static void Ins_ABS( INS_ARG )
+ {
+ DO_ABS
+ }
+
+
+/*******************************************/
+/* NEG[] : NEGate */
+/* CodeRange : $65 */
+/* Stack : f26.6 --> f26.6 */
+
+ static void Ins_NEG( INS_ARG )
+ {
+ DO_NEG
+ }
+
+
+/*******************************************/
+/* FLOOR[] : FLOOR */
+/* CodeRange : $66 */
+/* Stack : f26.6 --> f26.6 */
+
+ static void Ins_FLOOR( INS_ARG )
+ {
+ DO_FLOOR
+ }
+
+
+/*******************************************/
+/* CEILING[] : CEILING */
+/* CodeRange : $67 */
+/* f26.6 --> f26.6 */
+
+ static void Ins_CEILING( INS_ARG )
+ {
+ DO_CEILING
+ }
+
+/*******************************************/
+/* RS[] : Read Store */
+/* CodeRange : $43 */
+/* Stack : uint32 --> uint32 */
+
+ static void Ins_RS( INS_ARG )
+ {
+ DO_RS
+ }
+
+
+/*******************************************/
+/* WS[] : Write Store */
+/* CodeRange : $42 */
+/* Stack : uint32 uint32 --> */
+
+ static void Ins_WS( INS_ARG )
+ {
+ DO_WS
+ }
+
+
+/*******************************************/
+/* WCVTP[] : Write CVT in Pixel units */
+/* CodeRange : $44 */
+/* Stack : f26.6 uint32 --> */
+
+ static void Ins_WCVTP( INS_ARG )
+ {
+ DO_WCVTP
+ }
+
+
+/*******************************************/
+/* WCVTF[] : Write CVT in FUnits */
+/* CodeRange : $70 */
+/* Stack : uint32 uint32 --> */
+
+ static void Ins_WCVTF( INS_ARG )
+ {
+ DO_WCVTF
+ }
+
+
+/*******************************************/
+/* RCVT[] : Read CVT */
+/* CodeRange : $45 */
+/* Stack : uint32 --> f26.6 */
+
+ static void Ins_RCVT( INS_ARG )
+ {
+ DO_RCVT
+ }
+
+
+/********************************************/
+/* AA[] : Adjust Angle */
+/* CodeRange : $7F */
+/* Stack : uint32 --> */
+
+ static void Ins_AA( INS_ARG )
+ {
+ /* Intentional - no longer supported */
+ }
+
+
+/********************************************/
+/* DEBUG[] : DEBUG. Unsupported */
+/* CodeRange : $4F */
+/* Stack : uint32 --> */
+
+/* NOTE : The original instruction pops a value from the stack */
+
+ static void Ins_DEBUG( INS_ARG )
+ {
+ DO_DEBUG
+ }
+
+/*******************************************/
+/* ROUND[ab] : ROUND value */
+/* CodeRange : $68-$6B */
+/* Stack : f26.6 --> f26.6 */
+
+ static void Ins_ROUND( INS_ARG )
+ {
+ DO_ROUND
+ }
+
+/*******************************************/
+/* NROUND[ab]: No ROUNDing of value */
+/* CodeRange : $6C-$6F */
+/* Stack : f26.6 --> f26.6 */
+
+ static void Ins_NROUND( INS_ARG )
+ {
+ DO_NROUND
+ }
+
+
+
+/*******************************************/
+/* MAX[] : MAXimum */
+/* CodeRange : $68 */
+/* Stack : int32? int32? --> int32 */
+
+ static void Ins_MAX( INS_ARG )
+ {
+ DO_MAX
+ }
+
+
+/*******************************************/
+/* MIN[] : MINimum */
+/* CodeRange : $69 */
+/* Stack : int32? int32? --> int32 */
+
+ static void Ins_MIN( INS_ARG )
+ {
+ DO_MIN
+ }
+
+
+#endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
+
+
+/* The following functions are called as is within the switch statement */
+
+/*******************************************/
+/* MINDEX[] : move indexed element */
+/* CodeRange : $26 */
+/* Stack : int32? --> StkElt */
+
+ static void Ins_MINDEX( INS_ARG )
+ {
+ Long L, K;
+
+
+ L = args[0];
+
+ if ( L <= 0 || L > CUR.args )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ K = CUR.stack[CUR.args - L];
+
+ MEM_Move( (&CUR.stack[CUR.args - L ]),
+ (&CUR.stack[CUR.args - L + 1]),
+ (L - 1) * sizeof ( Long ) );
+
+ CUR.stack[CUR.args - 1] = K;
+ }
+
+
+/*******************************************/
+/* ROLL[] : roll top three elements */
+/* CodeRange : $8A */
+/* Stack : 3 * StkElt --> 3 * StkElt */
+
+ 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 */
+/* Stack : StkElt --> */
+
+ 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 */
+/* Stack : --> */
+
+ 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 );
+ }
+
+
+/****************************************************************/
+/* */
+/* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS */
+/* */
+/* Instructions appear in the specs' order. */
+/* */
+/****************************************************************/
+
+ static PDefRecord Locate_FDef( EXEC_OPS Int n, Bool new_def )
+ {
+ PDefRecord def;
+ UShort hash;
+ UShort cnt;
+
+ /* The function table is interpreted as a simple hash table */
+ /* with indexes computed modulo maxFDefs and the linear search */
+ /* of free cells in the case of a collision. */
+ /* Except for some old Apple fonts, all functions in a TrueType */
+ /* font fit into 0..maxFDefs - 1 range and the lookup is */
+ /* reduced to a single step. */
+
+ /* Minor optimization. */
+ if ( !new_def && ( n < 0 || n > CUR.maxFunc ) )
+ return NULL;
+
+ for ( cnt = 0; cnt < CUR.maxFDefs; ++cnt )
+ {
+ hash = ( (UShort)n + cnt ) % CUR.maxFDefs;
+ def = &CUR.FDefs[ hash ];
+ if ( !def->Active )
+ return new_def ? def : NULL;
+ if ( def->Opc == n )
+ return def;
+ }
+
+ /* The table is full and the entry has not been found. */
+ return NULL;
+ }
+
+
+/*******************************************/
+/* FDEF[] : Function DEFinition */
+/* CodeRange : $2C */
+/* Stack : uint32 --> */
+
+ static void Ins_FDEF( INS_ARG )
+ {
+ Int n;
+ PDefRecord def;
+
+
+ /* check that there is enough room */
+ if ( CUR.numFDefs >= CUR.maxFDefs )
+ {
+ CUR.error = TT_Err_Too_Many_FDefs;
+ return;
+ }
+
+ n = (Int)args[0];
+ if ( n < 0 || n != (int)args[0] )
+ {
+ /* Gotcha. Function index is uint32 according to the specs */
+ /* but TDefRecord.Opc is defined as Int. We cannot store */
+ /* the definition of this function. */
+ CUR.error = TT_Err_Bad_Argument;
+ return;
+ }
+
+ def = Locate_FDef( EXEC_ARGS n, TRUE );
+ if ( !def )
+ {
+ /* Oh, oh. Something is wrong. Locate_FDef should never fail here. */
+ CUR.error = TT_Err_Too_Many_Ins;
+ return;
+ }
+
+ /* Some font programs are broken enough to redefine functions! */
+ if ( !def->Active )
+ CUR.numFDefs++;
+
+ def->Range = CUR.curRange;
+ def->Opc = n;
+ def->Start = CUR.IP + 1;
+ def->Active = TRUE;
+
+ if ( n > CUR.maxFunc )
+ CUR.maxFunc = n;
+
+ /* 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 */
+/* Stack : --> */
+
+ static void Ins_ENDF( INS_ARG )
+ {
+ PCallRecord 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
+ /* Loop through the current function */
+ INS_Goto_CodeRange( pRec->Caller_Range,
+ pRec->Caller_IP );
+
+ /* 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 */
+ /* a valid address, and it's why we do not test */
+ /* the result of Ins_Goto_CodeRange() here! */
+ }
+
+
+/*******************************************/
+/* CALL[] : CALL function */
+/* CodeRange : $2B */
+/* Stack : uint32? --> */
+
+ static void Ins_CALL( INS_ARG )
+ {
+ Int n;
+ PDefRecord def;
+ PCallRecord pCrec;
+
+
+ n = (Int)args[0];
+ def = Locate_FDef( EXEC_ARGS n, FALSE );
+ if ( !def )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ /* check call stack */
+ if ( CUR.callTop >= CUR.callSize )
+ {
+ CUR.error = TT_Err_Stack_Overflow;
+ return;
+ }
+
+ pCrec = CUR.callStack + CUR.callTop;
+
+ pCrec->Caller_Range = CUR.curRange;
+ pCrec->Caller_IP = CUR.IP + 1;
+ pCrec->Cur_Count = 1;
+ pCrec->Cur_Restart = def->Start;
+
+ CUR.callTop++;
+
+ INS_Goto_CodeRange( def->Range,
+ def->Start );
+
+ CUR.step_ins = FALSE;
+ }
+
+
+/*******************************************/
+/* LOOPCALL[]: LOOP and CALL function */
+/* CodeRange : $2A */
+/* Stack : uint32? Eint16? --> */
+
+ static void Ins_LOOPCALL( INS_ARG )
+ {
+ Int n;
+ Long count;
+ PDefRecord def;
+ PCallRecord pTCR;
+
+
+ n = (Int)args[1];
+ def = Locate_FDef( EXEC_ARGS n, FALSE );
+ if ( !def )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ if ( CUR.callTop >= CUR.callSize )
+ {
+ CUR.error = TT_Err_Stack_Overflow;
+ return;
+ }
+
+ count = (Long)args[0];
+ if ( count <= 0 )
+ return;
+
+ pTCR = &CUR.callStack[CUR.callTop];
+
+ pTCR->Caller_Range = CUR.curRange;
+ pTCR->Caller_IP = CUR.IP + 1;
+ pTCR->Cur_Count = count;
+ pTCR->Cur_Restart = def->Start;
+
+ CUR.callTop++;
+
+ INS_Goto_CodeRange( def->Range,
+ def->Start );
+
+ CUR.step_ins = FALSE;
+ }
+
+
+/*******************************************/
+/* IDEF[] : Instruction DEFinition */
+/* CodeRange : $89 */
+/* Stack : Eint8 --> */
+
+ static void Ins_IDEF( INS_ARG )
+ {
+ Byte opcode;
+ PDefRecord def;
+ PDefRecord limit;
+
+
+ opcode = (Byte)args[0];
+
+ /* First of all, look for the same instruction in our table */
+ def = CUR.IDefs;
+ limit = def + CUR.numIDefs;
+ for ( ; def < limit; def++ )
+ if ( def->Opc == opcode )
+ break;
+
+ if ( def == limit )
+ {
+ /* check that there is enough room for a new instruction */
+ if ( CUR.numIDefs >= CUR.maxIDefs )
+ {
+ /* We could introduce a new error message (the same as for FDEF), */
+ /* but we're too close from the release to change all the 'po' */
+ /* files again... */
+ CUR.error = TT_Err_Too_Many_Ins;
+ return;
+ }
+ CUR.numIDefs++;
+ }
+
+ def->Opc = opcode;
+ def->Start = CUR.IP + 1;
+ def->Range = CUR.curRange;
+ def->Active = TRUE;
+
+ if ( opcode > CUR.maxIns )
+ CUR.maxIns = opcode;
+
+ /* 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;
+ }
+ }
+ }
+
+
+/****************************************************************/
+/* */
+/* PUSHING DATA ONTO THE INTERPRETER STACK */
+/* */
+/* Instructions appear in the specs' order. */
+/* */
+/****************************************************************/
+
+/*******************************************/
+/* NPUSHB[] : PUSH N Bytes */
+/* CodeRange : $40 */
+/* Stack : --> uint32... */
+
+ static void Ins_NPUSHB( INS_ARG )
+ {
+ UShort L, K;
+
+
+ L = (UShort)CUR.code[CUR.IP + 1];
+
+ if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
+ {
+ CUR.error = TT_Err_Stack_Overflow;
+ return;
+ }
+
+ for ( K = 1; K <= L; K++ )
+ args[K - 1] = CUR.code[CUR.IP + K + 1];
+
+ CUR.new_top += L;
+ }
+
+
+/*******************************************/
+/* NPUSHW[] : PUSH N Words */
+/* CodeRange : $41 */
+/* Stack : --> int32... */
+
+ static void Ins_NPUSHW( INS_ARG )
+ {
+ UShort L, K;
+
+
+ L = (UShort)CUR.code[CUR.IP + 1];
+
+ if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
+ {
+ CUR.error = TT_Err_Stack_Overflow;
+ return;
+ }
+
+ CUR.IP += 2;
+
+ for ( K = 0; K < L; K++ )
+ args[K] = GET_ShortIns();
+
+ CUR.step_ins = FALSE;
+ CUR.new_top += L;
+ }
+
+
+/*******************************************/
+/* PUSHB[abc]: PUSH Bytes */
+/* CodeRange : $B0-$B7 */
+/* Stack : --> uint32... */
+
+ static void Ins_PUSHB( INS_ARG )
+ {
+ UShort L, K;
+
+
+ L = (UShort)CUR.opcode - 0xB0 + 1;
+
+ if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
+ {
+ CUR.error = TT_Err_Stack_Overflow;
+ return;
+ }
+
+ for ( K = 1; K <= L; K++ )
+ args[K - 1] = CUR.code[CUR.IP + K];
+ }
+
+
+/*******************************************/
+/* PUSHW[abc]: PUSH Words */
+/* CodeRange : $B8-$BF */
+/* Stack : --> int32... */
+
+ static void Ins_PUSHW( INS_ARG )
+ {
+ UShort L, K;
+
+
+ L = (UShort)CUR.opcode - 0xB8 + 1;
+
+ if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
+ {
+ CUR.error = TT_Err_Stack_Overflow;
+ return;
+ }
+
+ CUR.IP++;
+
+ for ( K = 0; K < L; K++ )
+ args[K] = GET_ShortIns();
+
+ CUR.step_ins = FALSE;
+ }
+
+
+
+/****************************************************************/
+/* */
+/* MANAGING THE GRAPHICS STATE */
+/* */
+/* Instructions appear in the specs' order. */
+/* */
+/****************************************************************/
+
+/**********************************************/
+/* GC[a] : Get Coordinate projected onto */
+/* CodeRange : $46-$47 */
+/* Stack : uint32 --> f26.6 */
+
+/* BULLSHIT: Measures from the original glyph must be taken */
+/* along the dual projection vector! */
+
+ static void Ins_GC( INS_ARG )
+ {
+ ULong L;
+ TT_F26Dot6 R;
+
+
+ L = (ULong)args[0];
+
+ if ( BOUNDS( L, CUR.zp2.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+ else
+ R = 0;
+ }
+ else
+ {
+ if ( CUR.opcode & 1 )
+ R = CUR_Func_dualproj( CUR.zp2.org + L, NULL_Vector );
+ else
+ R = CUR_Func_project( CUR.zp2.cur + L, NULL_Vector );
+ }
+
+ args[0] = R;
+ }
+
+
+/**********************************************/
+/* SCFS[] : Set Coordinate From Stack */
+/* CodeRange : $48 */
+/* Stack : f26.6 uint32 --> */
+/* */
+/* Formula: */
+/* */
+/* OA := OA + ( value - OA.p )/( f.p ) * f */
+/* */
+
+ static void Ins_SCFS( INS_ARG )
+ {
+ Long K;
+ UShort L;
+
+
+ L = (UShort)args[0];
+
+ if ( BOUNDS( L, CUR.zp2.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ K = CUR_Func_project( CUR.zp2.cur + L, NULL_Vector );
+
+ CUR_Func_move( &CUR.zp2, L, args[1] - K );
+
+ /* not part of the specs, but here for safety */
+
+ if ( CUR.GS.gep2 == 0 )
+ CUR.zp2.org[L] = CUR.zp2.cur[L];
+ }
+
+
+/**********************************************/
+/* MD[a] : Measure Distance */
+/* CodeRange : $49-$4A */
+/* Stack : uint32 uint32 --> f26.6 */
+
+/* BULLSHIT: Measure taken in the original glyph must be along */
+/* the dual projection vector. */
+
+/* Second BULLSHIT: Flag attributes are inverted! */
+/* 0 => measure distance in original outline */
+/* 1 => measure distance in grid-fitted outline */
+
+/* Third one !! : zp0 - zp1, and not "zp2 - zp1" !!! */
+/* */
+
+ static void Ins_MD( INS_ARG )
+ {
+ UShort K, L;
+ TT_F26Dot6 D;
+
+
+ K = (UShort)args[1];
+ L = (UShort)args[0];
+
+ if( BOUNDS( L, CUR.zp0.n_points ) ||
+ BOUNDS( K, CUR.zp1.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+ else
+ D = 0;
+ }
+ else
+ {
+ if ( CUR.opcode & 1 )
+ D = CUR_Func_project( CUR.zp0.cur + L, CUR.zp1.cur + K );
+ else
+ D = CUR_Func_dualproj( CUR.zp0.org + L, CUR.zp1.org + K );
+ }
+
+ args[0] = D;
+ }
+
+
+/*******************************************/
+/* SDPVTL[a] : Set Dual PVector to Line */
+/* CodeRange : $86-$87 */
+/* Stack : uint32 uint32 --> */
+
+ static void Ins_SDPVTL( INS_ARG )
+ {
+ Long A, B, C;
+ UShort p1, p2; /* was Int in pas type ERROR */
+
+
+ p1 = (UShort)args[1];
+ p2 = (UShort)args[0];
+
+ if ( BOUNDS( p2, CUR.zp1.n_points ) ||
+ BOUNDS( p1, CUR.zp2.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ {
+ TT_Vector* v1 = CUR.zp1.org + p2;
+ TT_Vector* v2 = CUR.zp2.org + p1;
+
+
+ A = v1->x - v2->x;
+ B = v1->y - v2->y;
+ }
+
+ if ( (CUR.opcode & 1) != 0 )
+ {
+ C = B; /* CounterClockwise rotation */
+ B = A;
+ A = -C;
+ }
+
+ NORMalize( A, B, &CUR.GS.dualVector );
+
+ {
+ TT_Vector* v1 = CUR.zp1.cur + p2;
+ TT_Vector* v2 = CUR.zp2.cur + p1;
+
+
+ A = v1->x - v2->x;
+ B = v1->y - v2->y;
+ }
+
+ if ( (CUR.opcode & 1) != 0 )
+ {
+ C = B; /* CounterClockwise rotation */
+ B = A;
+ A = -C;
+ }
+
+ NORMalize( A, B, &CUR.GS.projVector );
+
+ COMPUTE_Funcs();
+ }
+
+
+/*******************************************/
+/* SZP0[] : Set Zone Pointer 0 */
+/* CodeRange : $13 */
+/* Stack : uint32 --> */
+
+ static void Ins_SZP0( INS_ARG )
+ {
+ switch ( (Int)args[0] )
+ {
+ case 0:
+ CUR.zp0 = CUR.twilight;
+ break;
+
+ case 1:
+ CUR.zp0 = CUR.pts;
+ break;
+
+ default:
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ CUR.GS.gep0 = (UShort)args[0];
+ }
+
+
+/*******************************************/
+/* SZP1[] : Set Zone Pointer 1 */
+/* CodeRange : $14 */
+/* Stack : uint32 --> */
+
+ static void Ins_SZP1( INS_ARG )
+ {
+ switch ( (Int)args[0] )
+ {
+ case 0:
+ CUR.zp1 = CUR.twilight;
+ break;
+
+ case 1:
+ CUR.zp1 = CUR.pts;
+ break;
+
+ default:
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ CUR.GS.gep1 = (UShort)args[0];
+ }
+
+
+/*******************************************/
+/* SZP2[] : Set Zone Pointer 2 */
+/* CodeRange : $15 */
+/* Stack : uint32 --> */
+
+ static void Ins_SZP2( INS_ARG )
+ {
+ switch ( (Int)args[0] )
+ {
+ case 0:
+ CUR.zp2 = CUR.twilight;
+ break;
+
+ case 1:
+ CUR.zp2 = CUR.pts;
+ break;
+
+ default:
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ CUR.GS.gep2 = (UShort)args[0];
+ }
+
+
+/*******************************************/
+/* SZPS[] : Set Zone Pointers */
+/* CodeRange : $16 */
+/* Stack : uint32 --> */
+
+ static void Ins_SZPS( INS_ARG )
+ {
+ switch ( (Int)args[0] )
+ {
+ case 0:
+ CUR.zp0 = CUR.twilight;
+ break;
+
+ case 1:
+ CUR.zp0 = CUR.pts;
+ break;
+
+ default:
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ CUR.zp1 = CUR.zp0;
+ CUR.zp2 = CUR.zp0;
+
+ CUR.GS.gep0 = (UShort)args[0];
+ CUR.GS.gep1 = (UShort)args[0];
+ CUR.GS.gep2 = (UShort)args[0];
+ }
+
+
+/*******************************************/
+/* INSTCTRL[]: INSTruction ConTRol */
+/* CodeRange : $8e */
+/* Stack : int32 int32 --> */
+
+ static void Ins_INSTCTRL( INS_ARG )
+ {
+ Long K, L;
+
+
+ K = args[1];
+ L = args[0];
+
+ if ( K < 1 || K > 2 )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ if ( L != 0 )
+ L = K;
+
+ CUR.GS.instruct_control =
+ (Byte)( CUR.GS.instruct_control & ~(Byte)K ) | (Byte)L;
+ }
+
+
+/*******************************************/
+/* SCANCTRL[]: SCAN ConTRol */
+/* CodeRange : $85 */
+/* Stack : uint32? --> */
+
+ static void Ins_SCANCTRL( INS_ARG )
+ {
+ Int A;
+
+
+ /* Get Threshold */
+ A = (Int)(args[0] & 0xFF);
+
+ if ( A == 0xFF )
+ {
+ CUR.GS.scan_control = TRUE;
+ return;
+ }
+ else if ( A == 0 )
+ {
+ CUR.GS.scan_control = FALSE;
+ return;
+ }
+
+ A *= 64;
+
+ if ( (args[0] & 0x100) != 0 && CUR.metrics.pointSize <= A )
+ CUR.GS.scan_control = TRUE;
+
+ if ( (args[0] & 0x200) != 0 && CUR.metrics.rotated )
+ CUR.GS.scan_control = TRUE;
+
+ if ( (args[0] & 0x400) != 0 && CUR.metrics.stretched )
+ CUR.GS.scan_control = TRUE;
+
+ if ( (args[0] & 0x800) != 0 && CUR.metrics.pointSize > A )
+ CUR.GS.scan_control = FALSE;
+
+ if ( (args[0] & 0x1000) != 0 && CUR.metrics.rotated )
+ CUR.GS.scan_control = FALSE;
+
+ if ( (args[0] & 0x2000) != 0 && CUR.metrics.stretched )
+ CUR.GS.scan_control = FALSE;
+}
+
+
+/*******************************************/
+/* SCANTYPE[]: SCAN TYPE */
+/* CodeRange : $8D */
+/* Stack : uint32? --> */
+
+ 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];
+ }
+ }
+
+
+
+/****************************************************************/
+/* */
+/* MANAGING OUTLINES */
+/* */
+/* Instructions appear in the specs' order. */
+/* */
+/****************************************************************/
+
+/**********************************************/
+/* FLIPPT[] : FLIP PoinT */
+/* CodeRange : $80 */
+/* Stack : uint32... --> */
+
+ static void Ins_FLIPPT( INS_ARG )
+ {
+ UShort point;
+
+
+ if ( CUR.top < CUR.GS.loop )
+ {
+ CUR.error = TT_Err_Too_Few_Arguments;
+ return;
+ }
+
+ while ( CUR.GS.loop > 0 )
+ {
+ CUR.args--;
+
+ point = (UShort)CUR.stack[CUR.args];
+
+ if ( BOUNDS( point, CUR.pts.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+ }
+ else
+ CUR.pts.touch[point] ^= TT_Flag_On_Curve;
+
+ CUR.GS.loop--;
+ }
+
+ CUR.GS.loop = 1;
+ CUR.new_top = CUR.args;
+ }
+
+
+/**********************************************/
+/* FLIPRGON[]: FLIP RanGe ON */
+/* CodeRange : $81 */
+/* Stack : uint32 uint32 --> */
+/* (but UShorts are sufficient) */
+
+ static void Ins_FLIPRGON( INS_ARG )
+ {
+ UShort I, K, L;
+
+
+ K = (UShort)args[1];
+ L = (UShort)args[0];
+
+ if ( BOUNDS( K, CUR.pts.n_points ) ||
+ BOUNDS( L, CUR.pts.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ for ( I = L; I <= K; I++ )
+ CUR.pts.touch[I] |= TT_Flag_On_Curve;
+ }
+
+
+/**********************************************/
+/* FLIPRGOFF : FLIP RanGe OFF */
+/* CodeRange : $82 */
+/* Stack : uint32 uint32 --> */
+/* (but UShorts are sufficient) */
+
+ static void Ins_FLIPRGOFF( INS_ARG )
+ {
+ UShort I, K, L;
+
+
+ K = (UShort)args[1];
+ L = (UShort)args[0];
+
+ if ( BOUNDS( K, CUR.pts.n_points ) ||
+ BOUNDS( L, CUR.pts.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ for ( I = L; I <= K; I++ )
+ CUR.pts.touch[I] &= ~TT_Flag_On_Curve;
+ }
+
+
+ static Bool Compute_Point_Displacement( EXEC_OPS
+ PCoordinates x,
+ PCoordinates y,
+ PGlyph_Zone zone,
+ UShort* refp )
+ {
+ TGlyph_Zone zp;
+ UShort p;
+ TT_F26Dot6 d;
+
+
+ if ( CUR.opcode & 1 )
+ {
+ zp = CUR.zp0;
+ p = CUR.GS.rp1;
+ }
+ else
+ {
+ zp = CUR.zp1;
+ p = CUR.GS.rp2;
+ }
+
+ if ( BOUNDS( p, zp.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Displacement;
+ return FAILURE;
+ }
+
+ *zone = zp;
+ *refp = p;
+
+ d = CUR_Func_project( zp.cur + p, zp.org + p );
+
+ *x = TT_MulDiv(d, (Long)CUR.GS.freeVector.x * 0x10000L, CUR.F_dot_P );
+ *y = TT_MulDiv(d, (Long)CUR.GS.freeVector.y * 0x10000L, CUR.F_dot_P );
+
+ return SUCCESS;
+ }
+
+
+ static void Move_Zp2_Point( EXEC_OPS
+ UShort point,
+ TT_F26Dot6 dx,
+ TT_F26Dot6 dy,
+ Bool touch )
+ {
+ if ( CUR.GS.freeVector.x != 0 )
+ {
+ CUR.zp2.cur[point].x += dx;
+ if ( touch )
+ CUR.zp2.touch[point] |= TT_Flag_Touched_X;
+ }
+
+ if ( CUR.GS.freeVector.y != 0 )
+ {
+ CUR.zp2.cur[point].y += dy;
+ if ( touch )
+ CUR.zp2.touch[point] |= TT_Flag_Touched_Y;
+ }
+ }
+
+
+/**********************************************/
+/* SHP[a] : SHift Point by the last point */
+/* CodeRange : $32-33 */
+/* Stack : uint32... --> */
+
+ static void Ins_SHP( INS_ARG )
+ {
+ TGlyph_Zone zp;
+ UShort refp;
+
+ TT_F26Dot6 dx,
+ dy;
+ UShort point;
+
+
+ if ( CUR.top < CUR.GS.loop )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
+ return;
+
+ while ( CUR.GS.loop > 0 )
+ {
+ CUR.args--;
+ point = (UShort)CUR.stack[CUR.args];
+
+ if ( BOUNDS( point, CUR.zp2.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+ }
+ else
+ /* UNDOCUMENTED! SHP touches the points */
+ MOVE_Zp2_Point( point, dx, dy, TRUE );
+
+ CUR.GS.loop--;
+ }
+
+ CUR.GS.loop = 1;
+ CUR.new_top = CUR.args;
+ }
+
+
+/**********************************************/
+/* SHC[a] : SHift Contour */
+/* CodeRange : $34-35 */
+/* Stack : uint32 --> */
+
+ static void Ins_SHC( INS_ARG )
+ {
+ TGlyph_Zone zp;
+ UShort refp;
+ TT_F26Dot6 dx,
+ dy;
+
+ Short contour;
+ UShort first_point, last_point, i;
+
+
+ contour = (UShort)args[0];
+
+ if ( BOUNDS( contour, CUR.pts.n_contours ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
+ return;
+
+ if ( contour == 0 )
+ first_point = 0;
+ else
+ first_point = CUR.pts.contours[contour - 1] + 1;
+
+ last_point = CUR.pts.contours[contour];
+
+ /* XXX: this is probably wrong... at least it prevents memory */
+ /* corruption when zp2 is the twilight zone */
+ if ( last_point > CUR.zp2.n_points )
+ {
+ if ( CUR.zp2.n_points > 0 )
+ last_point = CUR.zp2.n_points - 1;
+ else
+ last_point = 0;
+ }
+
+ /* UNDOCUMENTED! SHC doesn't touch the points */
+ for ( i = first_point; i <= last_point; i++ )
+ {
+ if ( zp.cur != CUR.zp2.cur || refp != i )
+ MOVE_Zp2_Point( i, dx, dy, FALSE );
+ }
+ }
+
+
+/**********************************************/
+/* SHZ[a] : SHift Zone */
+/* CodeRange : $36-37 */
+/* Stack : uint32 --> */
+
+ static void Ins_SHZ( INS_ARG )
+ {
+ TGlyph_Zone zp;
+ UShort refp;
+ TT_F26Dot6 dx,
+ dy;
+
+ UShort last_point, i;
+
+
+ if ( BOUNDS( args[0], 2 ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
+ return;
+
+ if ( CUR.zp2.n_points > 0 )
+ last_point = CUR.zp2.n_points - 1;
+ else
+ last_point = 0;
+
+ /* UNDOCUMENTED! SHZ doesn't touch the points */
+ for ( i = 0; i <= last_point; i++ )
+ {
+ if ( zp.cur != CUR.zp2.cur || refp != i )
+ MOVE_Zp2_Point( i, dx, dy, FALSE );
+ }
+ }
+
+
+/**********************************************/
+/* SHPIX[] : SHift points by a PIXel amount */
+/* CodeRange : $38 */
+/* Stack : f26.6 uint32... --> */
+
+ static void Ins_SHPIX( INS_ARG )
+ {
+ TT_F26Dot6 dx, dy;
+ UShort point;
+
+
+ if ( CUR.top < CUR.GS.loop + 1 )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ dx = TT_MulDiv( args[0],
+ (Long)CUR.GS.freeVector.x,
+ 0x4000 );
+ dy = TT_MulDiv( args[0],
+ (Long)CUR.GS.freeVector.y,
+ 0x4000 );
+
+ while ( CUR.GS.loop > 0 )
+ {
+ CUR.args--;
+
+ point = (UShort)CUR.stack[CUR.args];
+
+ if ( BOUNDS( point, CUR.zp2.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+ }
+ else
+ MOVE_Zp2_Point( point, dx, dy, TRUE );
+
+ CUR.GS.loop--;
+ }
+
+ CUR.GS.loop = 1;
+ CUR.new_top = CUR.args;
+ }
+
+
+/**********************************************/
+/* MSIRP[a] : Move Stack Indirect Relative */
+/* CodeRange : $3A-$3B */
+/* Stack : f26.6 uint32 --> */
+
+ static void Ins_MSIRP( INS_ARG )
+ {
+ UShort point;
+ TT_F26Dot6 distance;
+
+
+ point = (UShort)args[0];
+
+ if ( BOUNDS( point, CUR.zp1.n_points ) ||
+ BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ /* XXX: UNDOCUMENTED! behaviour */
+ if ( CUR.GS.gep0 == 0 ) /* if in twilight zone */
+ {
+ CUR.zp1.org[point] = CUR.zp0.org[CUR.GS.rp0];
+ CUR.zp1.cur[point] = CUR.zp1.org[point];
+ }
+
+ distance = CUR_Func_project( CUR.zp1.cur + point,
+ CUR.zp0.cur + CUR.GS.rp0 );
+
+ CUR_Func_move( &CUR.zp1, point, args[1] - distance );
+
+ CUR.GS.rp1 = CUR.GS.rp0;
+ CUR.GS.rp2 = point;
+
+ if ( (CUR.opcode & 1) != 0 )
+ CUR.GS.rp0 = point;
+ }
+
+
+/**********************************************/
+/* MDAP[a] : Move Direct Absolute Point */
+/* CodeRange : $2E-$2F */
+/* Stack : uint32 --> */
+
+ static void Ins_MDAP( INS_ARG )
+ {
+ UShort point;
+ TT_F26Dot6 cur_dist,
+ distance;
+
+
+ point = (UShort)args[0];
+
+ if ( BOUNDS( point, CUR.zp0.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ /* XXX: Is there some undocumented feature while in the */
+ /* twilight zone? ? */
+ if ( (CUR.opcode & 1) != 0 )
+ {
+ cur_dist = CUR_Func_project( CUR.zp0.cur + point, NULL_Vector );
+ distance = CUR_Func_round( cur_dist,
+ CUR.metrics.compensations[0] ) - cur_dist;
+ }
+ else
+ distance = 0;
+
+ CUR_Func_move( &CUR.zp0, point, distance );
+
+ CUR.GS.rp0 = point;
+ CUR.GS.rp1 = point;
+ }
+
+
+/**********************************************/
+/* MIAP[a] : Move Indirect Absolute Point */
+/* CodeRange : $3E-$3F */
+/* Stack : uint32 uint32 --> */
+
+ static void Ins_MIAP( INS_ARG )
+ {
+ ULong cvtEntry;
+ UShort point;
+ TT_F26Dot6 distance,
+ org_dist;
+
+
+ cvtEntry = (ULong)args[1];
+ point = (UShort)args[0];
+
+ if ( BOUNDS( point, CUR.zp0.n_points ) ||
+ BOUNDS( cvtEntry, CUR.cvtSize ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ /* 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" according to the */
+ /* specs :) */
+ /* */
+ /* We implement it with a special sequence for the */
+ /* twilight zone. This is a bad hack, but it seems */
+ /* to work. */
+
+ distance = CUR_Func_read_cvt( cvtEntry );
+
+ if ( CUR.GS.gep0 == 0 ) /* If in twilight zone */
+ {
+ CUR.zp0.org[point].x = TT_MulDiv( CUR.GS.freeVector.x,
+ distance, 0x4000L );
+ CUR.zp0.org[point].y = TT_MulDiv( CUR.GS.freeVector.y,
+ distance, 0x4000L );
+ CUR.zp0.cur[point] = CUR.zp0.org[point];
+ }
+
+ org_dist = CUR_Func_project( CUR.zp0.cur + point, NULL_Vector );
+
+ if ( (CUR.opcode & 1) != 0 ) /* 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 */
+/* Stack : uint32 --> */
+
+ static void Ins_MDRP( INS_ARG )
+ {
+ UShort point;
+ TT_F26Dot6 org_dist, distance;
+
+
+ point = (UShort)args[0];
+
+ if ( BOUNDS( point, CUR.zp1.n_points ) ||
+ BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ /* XXX: Is there some undocumented feature while in the */
+ /* twilight zone? */
+
+ org_dist = CUR_Func_dualproj( CUR.zp1.org + point,
+ CUR.zp0.org + 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 + point,
+ CUR.zp0.cur + CUR.GS.rp0 );
+
+ CUR_Func_move( &CUR.zp1, point, distance - org_dist );
+
+ CUR.GS.rp1 = CUR.GS.rp0;
+ CUR.GS.rp2 = point;
+
+ if ( (CUR.opcode & 16) != 0 )
+ CUR.GS.rp0 = point;
+ }
+
+
+/**********************************************/
+/* MIRP[abcde] : Move Indirect Relative Point */
+/* CodeRange : $E0-$FF */
+/* Stack : int32? uint32 --> */
+
+ static void Ins_MIRP( INS_ARG )
+ {
+ UShort point;
+ ULong cvtEntry;
+
+ TT_F26Dot6 cvt_dist,
+ distance,
+ cur_dist,
+ org_dist;
+
+
+ point = (UShort)args[0];
+ cvtEntry = (ULong)(args[1] + 1);
+
+ /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */
+
+ if ( BOUNDS( point, CUR.zp1.n_points ) ||
+ BOUNDS( cvtEntry, CUR.cvtSize + 1 ) ||
+ BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ if ( !cvtEntry )
+ cvt_dist = 0;
+ else
+ cvt_dist = CUR_Func_read_cvt( cvtEntry - 1 );
+
+ /* 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;
+ }
+
+ /* XXX : UNDOCUMENTED! -- twilight zone */
+
+ if ( CUR.GS.gep1 == 0 )
+ {
+ CUR.zp1.org[point].x = CUR.zp0.org[CUR.GS.rp0].x +
+ TT_MulDiv( cvt_dist,
+ CUR.GS.freeVector.x,
+ 0x4000 );
+
+ CUR.zp1.org[point].y = CUR.zp0.org[CUR.GS.rp0].y +
+ TT_MulDiv( cvt_dist,
+ CUR.GS.freeVector.y,
+ 0x4000 );
+
+ CUR.zp1.cur[point] = CUR.zp1.org[point];
+ }
+
+ org_dist = CUR_Func_dualproj( CUR.zp1.org + point,
+ CUR.zp0.org + CUR.GS.rp0 );
+
+ cur_dist = CUR_Func_project( CUR.zp1.cur + point,
+ CUR.zp0.cur + CUR.GS.rp0 );
+
+ /* 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 )
+ {
+ /* XXX: UNDOCUMENTED! Only perform cut-in test when both points */
+ /* refer to the same zone. */
+
+ if ( CUR.GS.gep0 == CUR.GS.gep1 )
+ if ( ABS( cvt_dist - org_dist ) >= CUR.GS.control_value_cutin )
+ cvt_dist = org_dist;
+
+ distance = CUR_Func_round( cvt_dist,
+ CUR.metrics.compensations[CUR.opcode & 3] );
+ }
+ else
+ distance = Round_None( EXEC_ARGS
+ cvt_dist,
+ CUR.metrics.compensations[CUR.opcode & 3] );
+
+ /* 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 */
+/* Stack : uint32 uint32... --> */
+
+ static void Ins_ALIGNRP( INS_ARG )
+ {
+ UShort point;
+ TT_F26Dot6 distance;
+
+
+ if ( CUR.top < CUR.GS.loop ||
+ BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ while ( CUR.GS.loop > 0 )
+ {
+ CUR.args--;
+
+ point = (UShort)CUR.stack[CUR.args];
+
+ if ( BOUNDS( point, CUR.zp1.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+ }
+ else
+ {
+ distance = CUR_Func_project( CUR.zp1.cur + point,
+ CUR.zp0.cur + CUR.GS.rp0 );
+
+ CUR_Func_move( &CUR.zp1, point, -distance );
+ }
+
+ CUR.GS.loop--;
+ }
+
+ CUR.GS.loop = 1;
+ CUR.new_top = CUR.args;
+ }
+
+
+/**********************************************/
+/* ISECT[] : moves point to InterSECTion */
+/* CodeRange : $0F */
+/* Stack : 5 * uint32 --> */
+
+ static void Ins_ISECT( INS_ARG )
+ {
+ UShort point,
+ a0, a1,
+ b0, b1;
+
+ TT_F26Dot6 discriminant;
+
+ TT_F26Dot6 dx, dy,
+ dax, day,
+ dbx, dby;
+
+ TT_F26Dot6 val;
+
+ TT_Vector R;
+
+
+ point = (UShort)args[0];
+
+ a0 = (UShort)args[1];
+ a1 = (UShort)args[2];
+ b0 = (UShort)args[3];
+ b1 = (UShort)args[4];
+
+ if ( BOUNDS( b0, CUR.zp0.n_points ) ||
+ BOUNDS( b1, CUR.zp0.n_points ) ||
+ BOUNDS( a0, CUR.zp1.n_points ) ||
+ BOUNDS( a1, CUR.zp1.n_points ) ||
+ BOUNDS( point, CUR.zp2.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ dbx = CUR.zp0.cur[b1].x - CUR.zp0.cur[b0].x;
+ dby = CUR.zp0.cur[b1].y - CUR.zp0.cur[b0].y;
+
+ dax = CUR.zp1.cur[a1].x - CUR.zp1.cur[a0].x;
+ day = CUR.zp1.cur[a1].y - CUR.zp1.cur[a0].y;
+
+ dx = CUR.zp0.cur[b0].x - CUR.zp1.cur[a0].x;
+ dy = CUR.zp0.cur[b0].y - CUR.zp1.cur[a0].y;
+
+ CUR.zp2.touch[point] |= TT_Flag_Touched_Both;
+
+ discriminant = TT_MulDiv( dax, -dby, 0x40L ) +
+ TT_MulDiv( day, dbx, 0x40L );
+
+ if ( ABS( discriminant ) >= 0x40 )
+ {
+ val = TT_MulDiv( dx, -dby, 0x40L ) + TT_MulDiv( dy, dbx, 0x40L );
+
+ R.x = TT_MulDiv( val, dax, discriminant );
+ R.y = TT_MulDiv( val, day, discriminant );
+
+ CUR.zp2.cur[point].x = CUR.zp1.cur[a0].x + R.x;
+ CUR.zp2.cur[point].y = CUR.zp1.cur[a0].y + R.y;
+ }
+ else
+ {
+ /* else, take the middle of the middles of A and B */
+
+ CUR.zp2.cur[point].x = ( CUR.zp1.cur[a0].x +
+ CUR.zp1.cur[a1].x +
+ CUR.zp0.cur[b0].x +
+ CUR.zp0.cur[b1].x ) / 4;
+ CUR.zp2.cur[point].y = ( CUR.zp1.cur[a0].y +
+ CUR.zp1.cur[a1].y +
+ CUR.zp0.cur[b0].y +
+ CUR.zp0.cur[b1].y ) / 4;
+ }
+ }
+
+
+/**********************************************/
+/* ALIGNPTS[] : ALIGN PoinTS */
+/* CodeRange : $27 */
+/* Stack : uint32 uint32 --> */
+
+ static void Ins_ALIGNPTS( INS_ARG )
+ {
+ UShort p1, p2;
+ TT_F26Dot6 distance;
+
+
+ p1 = (UShort)args[0];
+ p2 = (UShort)args[1];
+
+ if ( BOUNDS( args[0], CUR.zp1.n_points ) ||
+ BOUNDS( args[1], CUR.zp0.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ distance = CUR_Func_project( CUR.zp0.cur + p2,
+ CUR.zp1.cur + p1 ) / 2;
+
+ CUR_Func_move( &CUR.zp1, p1, distance );
+ CUR_Func_move( &CUR.zp0, p2, -distance );
+ }
+
+
+/**********************************************/
+/* IP[] : Interpolate Point */
+/* CodeRange : $39 */
+/* Stack : uint32... --> */
+
+ static void Ins_IP( INS_ARG )
+ {
+ TT_F26Dot6 org_a, org_b, org_x,
+ cur_a, cur_b, cur_x,
+ distance;
+ UShort point;
+
+
+ if ( CUR.top < CUR.GS.loop )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ /* XXX: there are some glyphs in some braindead but popular */
+ /* fonts out there (e.g. [aeu]grave in monotype.ttf) */
+ /* calling IP[] with bad values of rp[12] */
+ /* do something sane when this odd thing happens */
+
+ if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) ||
+ BOUNDS( CUR.GS.rp2, CUR.zp1.n_points ) )
+ {
+ org_a = cur_a = 0;
+ org_b = cur_b = 0;
+ }
+ else
+ {
+ org_a = CUR_Func_dualproj( CUR.zp0.org + CUR.GS.rp1, NULL_Vector );
+ org_b = CUR_Func_dualproj( CUR.zp1.org + CUR.GS.rp2, NULL_Vector );
+
+ cur_a = CUR_Func_project( CUR.zp0.cur + CUR.GS.rp1, NULL_Vector );
+ cur_b = CUR_Func_project( CUR.zp1.cur + CUR.GS.rp2, NULL_Vector );
+ }
+
+ while ( CUR.GS.loop > 0 )
+ {
+ CUR.args--;
+
+ point = (UShort)CUR.stack[CUR.args];
+ if ( BOUNDS( point, CUR.zp2.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+ }
+ else
+ {
+ org_x = CUR_Func_dualproj( CUR.zp2.org + point, NULL_Vector );
+ cur_x = CUR_Func_project ( CUR.zp2.cur + point, NULL_Vector );
+
+ if ( ( org_a <= org_b && org_x <= org_a ) ||
+ ( org_a > org_b && org_x >= org_a ) )
+
+ distance = ( cur_a - org_a ) + ( org_x - cur_x );
+
+ else if ( ( org_a <= org_b && org_x >= org_b ) ||
+ ( org_a > org_b && org_x < org_b ) )
+
+ distance = ( cur_b - org_b ) + ( org_x - cur_x );
+
+ else
+ /* note: it seems that rounding this value isn't a good */
+ /* idea (cf. width of capital 'S' in Times) */
+
+ distance = TT_MulDiv( cur_b - cur_a,
+ org_x - org_a,
+ org_b - org_a ) + ( cur_a - cur_x );
+
+ CUR_Func_move( &CUR.zp2, point, distance );
+ }
+
+ CUR.GS.loop--;
+ }
+
+ CUR.GS.loop = 1;
+ CUR.new_top = CUR.args;
+ }
+
+
+/**********************************************/
+/* UTP[a] : UnTouch Point */
+/* CodeRange : $29 */
+/* Stack : uint32 --> */
+
+ static void Ins_UTP( INS_ARG )
+ {
+ UShort point;
+ Byte mask;
+
+
+ point = (UShort)args[0];
+
+ if ( BOUNDS( point, CUR.zp0.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ mask = 0xFF;
+
+ if ( CUR.GS.freeVector.x != 0 )
+ mask &= ~TT_Flag_Touched_X;
+
+ if ( CUR.GS.freeVector.y != 0 )
+ mask &= ~TT_Flag_Touched_Y;
+
+ CUR.zp0.touch[point] &= mask;
+ }
+
+
+ /* Local variables for Ins_IUP: */
+ struct LOC_Ins_IUP
+ {
+ TT_Vector* orgs; /* original and current coordinate */
+ TT_Vector* curs; /* arrays */
+ };
+
+
+ static void Shift( UShort p1,
+ UShort p2,
+ UShort p,
+ struct LOC_Ins_IUP* LINK )
+ {
+ UShort i;
+ TT_F26Dot6 x;
+
+
+ x = LINK->curs[p].x - LINK->orgs[p].x;
+
+ for ( i = p1; i < p; i++ )
+ LINK->curs[i].x += x;
+
+ for ( i = p + 1; i <= p2; i++ )
+ LINK->curs[i].x += x;
+ }
+
+
+ static void Interp( UShort p1,
+ UShort p2,
+ UShort ref1,
+ UShort ref2,
+ struct LOC_Ins_IUP* LINK )
+ {
+ UShort i;
+ TT_F26Dot6 x, x1, x2, d1, d2;
+
+
+ if ( p1 > p2 )
+ return;
+
+ x1 = LINK->orgs[ref1].x;
+ d1 = LINK->curs[ref1].x - LINK->orgs[ref1].x;
+ x2 = LINK->orgs[ref2].x;
+ d2 = LINK->curs[ref2].x - LINK->orgs[ref2].x;
+
+ if ( x1 == x2 )
+ {
+ for ( i = p1; i <= p2; i++ )
+ {
+ x = LINK->orgs[i].x;
+
+ if ( x <= x1 )
+ x += d1;
+ else
+ x += d2;
+
+ LINK->curs[i].x = x;
+ }
+ return;
+ }
+
+ if ( x1 < x2 )
+ {
+ for ( i = p1; i <= p2; i++ )
+ {
+ x = LINK->orgs[i].x;
+
+ if ( x <= x1 )
+ x += d1;
+ else
+ {
+ if ( x >= x2 )
+ x += d2;
+ else
+ x = LINK->curs[ref1].x +
+ TT_MulDiv( x - x1,
+ LINK->curs[ref2].x - LINK->curs[ref1].x,
+ x2 - x1 );
+ }
+ LINK->curs[i].x = x;
+ }
+ return;
+ }
+
+ /* x2 < x1 */
+
+ for ( i = p1; i <= p2; i++ )
+ {
+ x = LINK->orgs[i].x;
+ if ( x <= x2 )
+ x += d2;
+ else
+ {
+ if ( x >= x1 )
+ x += d1;
+ else
+ x = LINK->curs[ref1].x +
+ TT_MulDiv( x - x1,
+ LINK->curs[ref2].x - LINK->curs[ref1].x,
+ x2 - x1 );
+ }
+ LINK->curs[i].x = x;
+ }
+ }
+
+
+/**********************************************/
+/* IUP[a] : Interpolate Untouched Points */
+/* CodeRange : $30-$31 */
+/* Stack : --> */
+
+ static void Ins_IUP( INS_ARG )
+ {
+ struct LOC_Ins_IUP V;
+ Byte mask;
+
+ UShort first_point; /* first point of contour */
+ UShort end_point; /* end point (last+1) of contour */
+
+ UShort first_touched; /* first touched point in contour */
+ UShort cur_touched; /* current touched point in contour */
+
+ UShort point; /* current point */
+ Short contour; /* current contour */
+
+
+ if ( CUR.opcode & 1 )
+ {
+ mask = TT_Flag_Touched_X;
+ V.orgs = CUR.pts.org;
+ V.curs = CUR.pts.cur;
+ }
+ else
+ {
+ mask = TT_Flag_Touched_Y;
+ V.orgs = (TT_Vector*)( ((TT_F26Dot6*)CUR.pts.org) + 1 );
+ V.curs = (TT_Vector*)( ((TT_F26Dot6*)CUR.pts.cur) + 1 );
+ }
+
+ contour = 0;
+ point = 0;
+
+ do
+ {
+ end_point = CUR.pts.contours[contour];
+ first_point = point;
+
+ while ( point <= end_point && (CUR.pts.touch[point] & mask) == 0 )
+ point++;
+
+ if ( point <= end_point )
+ {
+ first_touched = point;
+ cur_touched = point;
+
+ point++;
+
+ while ( point <= end_point )
+ {
+ if ( (CUR.pts.touch[point] & mask) != 0 )
+ {
+ if ( point > 0 )
+ Interp( cur_touched + 1,
+ point - 1,
+ cur_touched,
+ point,
+ &V );
+ cur_touched = point;
+ }
+
+ point++;
+ }
+
+ if ( cur_touched == first_touched )
+ Shift( first_point, end_point, cur_touched, &V );
+ else
+ {
+ Interp( cur_touched + 1,
+ end_point,
+ cur_touched,
+ first_touched,
+ &V );
+
+ if ( first_touched > 0 )
+ Interp( first_point,
+ first_touched - 1,
+ cur_touched,
+ first_touched,
+ &V );
+ }
+ }
+ contour++;
+ } while ( contour < CUR.pts.n_contours );
+ }
+
+
+/**********************************************/
+/* DELTAPn[] : DELTA Exceptions P1, P2, P3 */
+/* CodeRange : $5D,$71,$72 */
+/* Stack : uint32 (2 * uint32)... --> */
+
+ static void Ins_DELTAP( INS_ARG )
+ {
+ ULong nump, k;
+ UShort A;
+ ULong C;
+ Long B;
+
+
+ nump = (ULong)args[0]; /* some points theoretically may occur more
+ than once, thus UShort isn't enough */
+
+ for ( k = 1; k <= nump; k++ )
+ {
+ if ( CUR.args < 2 )
+ {
+ CUR.error = TT_Err_Too_Few_Arguments;
+ return;
+ }
+
+ CUR.args -= 2;
+
+ A = (UShort)CUR.stack[CUR.args + 1];
+ B = CUR.stack[CUR.args];
+
+ /* XXX : because some popular fonts contain some invalid DeltaP */
+ /* instructions, we simply ignore them when the stacked */
+ /* point reference is off limit, rather than returning an */
+ /* error. As a delta instruction doesn't change a glyph */
+ /* in great ways, this shouldn't be a problem.. */
+
+ if ( !BOUNDS( A, CUR.zp0.n_points ) )
+ {
+ C = ((ULong)B & 0xF0) >> 4;
+
+ switch ( CUR.opcode )
+ {
+ case 0x5d:
+ break;
+
+ case 0x71:
+ C += 16;
+ break;
+
+ case 0x72:
+ C += 32;
+ break;
+ }
+
+ C += CUR.GS.delta_base;
+
+ if ( CURRENT_Ppem() == (Long)C )
+ {
+ B = ((ULong)B & 0xF) - 8;
+ if ( B >= 0 )
+ B++;
+ B = B * 64L / (1L << CUR.GS.delta_shift);
+
+ CUR_Func_move( &CUR.zp0, A, B );
+ }
+ }
+ else
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ }
+
+ CUR.new_top = CUR.args;
+ }
+
+
+/**********************************************/
+/* DELTACn[] : DELTA Exceptions C1, C2, C3 */
+/* CodeRange : $73,$74,$75 */
+/* Stack : uint32 (2 * uint32)... --> */
+
+ static void Ins_DELTAC( INS_ARG )
+ {
+ ULong nump, k;
+ ULong A, C;
+ Long B;
+
+
+ nump = (ULong)args[0];
+
+ for ( k = 1; k <= nump; k++ )
+ {
+ if ( CUR.args < 2 )
+ {
+ CUR.error = TT_Err_Too_Few_Arguments;
+ return;
+ }
+
+ CUR.args -= 2;
+
+ A = (ULong)CUR.stack[CUR.args + 1];
+ B = CUR.stack[CUR.args];
+
+ if ( BOUNDS( A, CUR.cvtSize ) )
+ {
+ if ( CUR.pedantic_hinting )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+ }
+ else
+ {
+ C = ((ULong)B & 0xF0) >> 4;
+
+ switch ( CUR.opcode )
+ {
+ case 0x73:
+ break;
+
+ case 0x74:
+ C += 16;
+ break;
+
+ case 0x75:
+ C += 32;
+ break;
+ }
+
+ C += CUR.GS.delta_base;
+
+ if ( CURRENT_Ppem() == (Long)C )
+ {
+ B = ((ULong)B & 0xF) - 8;
+ if ( B >= 0 )
+ B++;
+ B = B * 64L / (1L << CUR.GS.delta_shift);
+
+ CUR_Func_move_cvt( A, B );
+ }
+ }
+ }
+
+ CUR.new_top = CUR.args;
+ }
+
+
+
+/****************************************************************/
+/* */
+/* MISC. INSTRUCTIONS */
+/* */
+/****************************************************************/
+
+
+/**********************************************/
+/* GETINFO[] : GET INFOrmation */
+/* CodeRange : $88 */
+/* Stack : uint32 --> uint32 */
+
+/* XXX According to Apple specs, bits 1 & 2 of the argument ought to be */
+/* consulted before rotated / stretched info is returned */
+
+ static void Ins_GETINFO( INS_ARG )
+ {
+ Long K;
+
+
+ K = 0;
+
+ /* We return then Windows 3.1 version number */
+ /* for the font scaler */
+ if ( (args[0] & 1) != 0 )
+ K = 3;
+
+ /* Has the glyph been rotated ? */
+ if ( CUR.metrics.rotated )
+ K |= 0x80;
+
+ /* Has the glyph been stretched ? */
+ if ( CUR.metrics.stretched )
+ K |= 0x100;
+
+ args[0] = K;
+ }
+
+
+ static void Ins_UNKNOWN( INS_ARG )
+ {
+ /* look up the current instruction in our table */
+ PDefRecord def, limit;
+
+ def = CUR.IDefs;
+ limit = def + CUR.numIDefs;
+ for ( ; def < limit; def++ )
+ {
+ if ( def->Opc == CUR.opcode && def->Active )
+ {
+ PCallRecord pCrec;
+
+ /* implement instruction as a function call */
+
+ /* check call stack */
+ if ( CUR.callTop >= CUR.callSize )
+ {
+ CUR.error = TT_Err_Stack_Overflow;
+ return;
+ }
+
+ pCrec = CUR.callStack + CUR.callTop;
+
+ pCrec->Caller_Range = CUR.curRange;
+ pCrec->Caller_IP = CUR.IP + 1;
+ pCrec->Cur_Count = 1;
+ pCrec->Cur_Restart = def->Start;
+
+ CUR.callTop++;
+
+ INS_Goto_CodeRange( def->Range,
+ def->Start );
+
+ CUR.step_ins = FALSE;
+ return;
+ }
+ }
+
+ CUR.error = TT_Err_Invalid_Opcode;
+ }
+
+
+#ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
+ static TInstruction_Function Instruct_Dispatch[256] =
+ {
+ /* 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
+ };
+#endif
+
+
+/****************************************************************/
+/* */
+/* 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. */
+/* */
+/****************************************************************/
+
+ FT_INTERNAL_FUNC( TT_Error )
+#ifndef DEBUG_INTERPRETER
+ RunIns( PExecution_Context exc )
+#else
+ RunIns2( PExecution_Context exc )
+#endif
+ {
+ UShort A;
+ PDefRecord WITH;
+ PCallRecord WITH1;
+
+ Long ins_counter = 0; /* executed instructions counter */
+
+#ifdef TT_CONFIG_OPTION_STATIC_INTERPRETER
+ cur = *exc;
+#endif
+
+ /* set CVT functions */
+ CUR.metrics.ratio = 0;
+ if ( CUR.metrics.x_ppem != CUR.metrics.y_ppem )
+ {
+ /* non-square pixels, use the stretched routines */
+ CUR.func_read_cvt = Read_CVT_Stretched;
+ CUR.func_write_cvt = Write_CVT_Stretched;
+ CUR.func_move_cvt = Move_CVT_Stretched;
+ }
+ else
+ {
+ /* square pixels, use normal routines */
+ CUR.func_read_cvt = Read_CVT;
+ CUR.func_write_cvt = Write_CVT;
+ CUR.func_move_cvt = Move_CVT;
+ }
+
+ COMPUTE_Funcs();
+ Compute_Round( EXEC_ARGS (Byte)( CUR.GS.round_state ) );
+
+ do
+ {
+ if ( CALC_Length() != SUCCESS )
+ {
+ CUR.error = TT_Err_Code_Overflow;
+ goto LErrorLabel_;
+ }
+
+ /* First, let's check for empty stack and overflow */
+
+ CUR.args = CUR.top - (Pop_Push_Count[CUR.opcode] >> 4);
+
+ /* `args' is the top of the stack once arguments have been popped. */
+ /* One can also interpret 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] & 15);
+
+ /* `new_top' is the new top of the stack, after the instruction's */
+ /* execution. `top' will be set to `new_top' after the 'switch' */
+ /* statement. */
+
+ if ( CUR.new_top > CUR.stackSize )
+ {
+ CUR.error = TT_Err_Stack_Overflow;
+ goto LErrorLabel_;
+ }
+
+ CUR.step_ins = TRUE;
+ CUR.error = TT_Err_Ok;
+
+#ifdef TT_CONFIG_OPTION_INTERPRETER_SWITCH
+ {
+ PStorage args = CUR.stack + CUR.args;
+ Byte opcode = CUR.opcode;
+
+
+#undef ARRAY_BOUND_ERROR
+#define ARRAY_BOUND_ERROR goto Set_Invalid_Ref
+
+ switch ( opcode )
+ {
+ case 0x00: /* SVTCA y */
+ case 0x01: /* SVTCA x */
+ case 0x02: /* SPvTCA y */
+ case 0x03: /* SPvTCA x */
+ case 0x04: /* SFvTCA y */
+ case 0x05: /* SFvTCA x */
+ {
+ Short AA, BB;
+
+
+ AA = (Short)(opcode & 1) << 14;
+ BB = AA ^ (Short)0x4000;
+
+ if ( opcode < 4 )
+ {
+ CUR.GS.projVector.x = AA;
+ CUR.GS.projVector.y = BB;
+
+ CUR.GS.dualVector.x = AA;
+ CUR.GS.dualVector.y = BB;
+ }
+
+ if ( (opcode & 2) == 0 )
+ {
+ CUR.GS.freeVector.x = AA;
+ CUR.GS.freeVector.y = BB;
+ }
+
+ COMPUTE_Funcs();
+ }
+ break;
+
+ case 0x06: /* SPvTL // */
+ case 0x07: /* SPvTL + */
+ DO_SPVTL
+ break;
+
+ case 0x08: /* SFvTL // */
+ case 0x09: /* SFvTL + */
+ DO_SFVTL
+ break;
+
+ case 0x0A: /* SPvFS */
+ DO_SPVFS
+ break;
+
+ case 0x0B: /* SFvFS */
+ DO_SFVFS
+ break;
+
+ case 0x0C: /* GPV */
+ DO_GPV
+ break;
+
+ case 0x0D: /* GFV */
+ DO_GFV
+ break;
+
+ case 0x0E: /* SFvTPv */
+ DO_SFVTPV
+ break;
+
+ case 0x0F: /* ISECT */
+ Ins_ISECT( EXEC_ARGS args );
+ break;
+
+ case 0x10: /* SRP0 */
+ DO_SRP0
+ break;
+
+ case 0x11: /* SRP1 */
+ DO_SRP1
+ break;
+
+ case 0x12: /* SRP2 */
+ DO_SRP2
+ break;
+
+ case 0x13: /* SZP0 */
+ Ins_SZP0( EXEC_ARGS args );
+ break;
+
+ case 0x14: /* SZP1 */
+ Ins_SZP1( EXEC_ARGS args );
+ break;
+
+ case 0x15: /* SZP2 */
+ Ins_SZP2( EXEC_ARGS args );
+ break;
+
+ case 0x16: /* SZPS */
+ Ins_SZPS( EXEC_ARGS args );
+ break;
+
+ case 0x17: /* SLOOP */
+ DO_SLOOP
+ break;
+
+ case 0x18: /* RTG */
+ DO_RTG
+ break;
+
+ case 0x19: /* RTHG */
+ DO_RTHG
+ break;
+
+ case 0x1A: /* SMD */
+ DO_SMD
+ break;
+
+ case 0x1B: /* ELSE */
+ Ins_ELSE( EXEC_ARGS args );
+ break;
+
+ case 0x1C: /* JMPR */
+ DO_JMPR
+ break;
+
+ case 0x1D: /* SCVTCI */
+ DO_SCVTCI
+ break;
+
+ case 0x1E: /* SSWCI */
+ DO_SSWCI
+ break;
+
+ case 0x1F: /* SSW */
+ DO_SSW
+ break;
+
+ case 0x20: /* DUP */
+ DO_DUP
+ break;
+
+ case 0x21: /* POP */
+ /* nothing :-) !! */
+ break;
+
+ case 0x22: /* CLEAR */
+ DO_CLEAR
+ break;
+
+ case 0x23: /* SWAP */
+ DO_SWAP
+ break;
+
+ case 0x24: /* DEPTH */
+ DO_DEPTH
+ break;
+
+ case 0x25: /* CINDEX */
+ DO_CINDEX
+ break;
+
+ case 0x26: /* MINDEX */
+ Ins_MINDEX( EXEC_ARGS args );
+ break;
+
+ case 0x27: /* ALIGNPTS */
+ Ins_ALIGNPTS( EXEC_ARGS args );
+ break;
+
+ case 0x28: /* ???? */
+ Ins_UNKNOWN( EXEC_ARGS args );
+ break;
+
+ case 0x29: /* UTP */
+ Ins_UTP( EXEC_ARGS args );
+ break;
+
+ case 0x2A: /* LOOPCALL */
+ Ins_LOOPCALL( EXEC_ARGS args );
+ break;
+
+ case 0x2B: /* CALL */
+ Ins_CALL( EXEC_ARGS args );
+ break;
+
+ case 0x2C: /* FDEF */
+ Ins_FDEF( EXEC_ARGS args );
+ break;
+
+ case 0x2D: /* ENDF */
+ Ins_ENDF( EXEC_ARGS args );
+ break;
+
+ case 0x2E: /* MDAP */
+ case 0x2F: /* MDAP */
+ Ins_MDAP( EXEC_ARGS args );
+ break;
+
+
+ case 0x30: /* IUP */
+ case 0x31: /* IUP */
+ Ins_IUP( EXEC_ARGS args );
+ break;
+
+ case 0x32: /* SHP */
+ case 0x33: /* SHP */
+ Ins_SHP( EXEC_ARGS args );
+ break;
+
+ case 0x34: /* SHC */
+ case 0x35: /* SHC */
+ Ins_SHC( EXEC_ARGS args );
+ break;
+
+ case 0x36: /* SHZ */
+ case 0x37: /* SHZ */
+ Ins_SHZ( EXEC_ARGS args );
+ break;
+
+ case 0x38: /* SHPIX */
+ Ins_SHPIX( EXEC_ARGS args );
+ break;
+
+ case 0x39: /* IP */
+ Ins_IP( EXEC_ARGS args );
+ break;
+
+ case 0x3A: /* MSIRP */
+ case 0x3B: /* MSIRP */
+ Ins_MSIRP( EXEC_ARGS args );
+ break;
+
+ case 0x3C: /* AlignRP */
+ Ins_ALIGNRP( EXEC_ARGS args );
+ break;
+
+ case 0x3D: /* RTDG */
+ DO_RTDG
+ break;
+
+ case 0x3E: /* MIAP */
+ case 0x3F: /* MIAP */
+ Ins_MIAP( EXEC_ARGS args );
+ break;
+
+ case 0x40: /* NPUSHB */
+ Ins_NPUSHB( EXEC_ARGS args );
+ break;
+
+ case 0x41: /* NPUSHW */
+ Ins_NPUSHW( EXEC_ARGS args );
+ break;
+
+ case 0x42: /* WS */
+ DO_WS
+ break;
+
+ Set_Invalid_Ref:
+ CUR.error = TT_Err_Invalid_Reference;
+ break;
+
+ case 0x43: /* RS */
+ DO_RS
+ break;
+
+ case 0x44: /* WCVTP */
+ DO_WCVTP
+ break;
+
+ case 0x45: /* RCVT */
+ DO_RCVT
+ break;
+
+ case 0x46: /* GC */
+ case 0x47: /* GC */
+ Ins_GC( EXEC_ARGS args );
+ break;
+
+ case 0x48: /* SCFS */
+ Ins_SCFS( EXEC_ARGS args );
+ break;
+
+ case 0x49: /* MD */
+ case 0x4A: /* MD */
+ Ins_MD( EXEC_ARGS args );
+ break;
+
+ case 0x4B: /* MPPEM */
+ DO_MPPEM
+ break;
+
+ case 0x4C: /* MPS */
+ DO_MPS
+ break;
+
+ case 0x4D: /* FLIPON */
+ DO_FLIPON
+ break;
+
+ case 0x4E: /* FLIPOFF */
+ DO_FLIPOFF
+ break;
+
+ case 0x4F: /* DEBUG */
+ DO_DEBUG
+ break;
+
+ case 0x50: /* LT */
+ DO_LT
+ break;
+
+ case 0x51: /* LTEQ */
+ DO_LTEQ
+ break;
+
+ case 0x52: /* GT */
+ DO_GT
+ break;
+
+ case 0x53: /* GTEQ */
+ DO_GTEQ
+ break;
+
+ case 0x54: /* EQ */
+ DO_EQ
+ break;
+
+ case 0x55: /* NEQ */
+ DO_NEQ
+ break;
+
+ case 0x56: /* ODD */
+ DO_ODD
+ break;
+
+ case 0x57: /* EVEN */
+ DO_EVEN
+ break;
+
+ case 0x58: /* IF */
+ Ins_IF( EXEC_ARGS args );
+ break;
+
+ case 0x59: /* EIF */
+ /* do nothing */
+ break;
+
+ case 0x5A: /* AND */
+ DO_AND
+ break;
+
+ case 0x5B: /* OR */
+ DO_OR
+ break;
+
+ case 0x5C: /* NOT */
+ DO_NOT
+ break;
+
+ case 0x5D: /* DELTAP1 */
+ Ins_DELTAP( EXEC_ARGS args );
+ break;
+
+ case 0x5E: /* SDB */
+ DO_SDB
+ break;
+
+ case 0x5F: /* SDS */
+ DO_SDS
+ break;
+
+ case 0x60: /* ADD */
+ DO_ADD
+ break;
+
+ case 0x61: /* SUB */
+ DO_SUB
+ break;
+
+ case 0x62: /* DIV */
+ DO_DIV
+ break;
+
+ case 0x63: /* MUL */
+ DO_MUL
+ break;
+
+ case 0x64: /* ABS */
+ DO_ABS
+ break;
+
+ case 0x65: /* NEG */
+ DO_NEG
+ break;
+
+ case 0x66: /* FLOOR */
+ DO_FLOOR
+ break;
+
+ case 0x67: /* CEILING */
+ DO_CEILING
+ break;
+
+ case 0x68: /* ROUND */
+ case 0x69: /* ROUND */
+ case 0x6A: /* ROUND */
+ case 0x6B: /* ROUND */
+ DO_ROUND
+ break;
+
+ case 0x6C: /* NROUND */
+ case 0x6D: /* NROUND */
+ case 0x6E: /* NRRUND */
+ case 0x6F: /* NROUND */
+ DO_NROUND
+ break;
+
+ case 0x70: /* WCVTF */
+ DO_WCVTF
+ break;
+
+ case 0x71: /* DELTAP2 */
+ case 0x72: /* DELTAP3 */
+ Ins_DELTAP( EXEC_ARGS args );
+ break;
+
+ case 0x73: /* DELTAC0 */
+ case 0x74: /* DELTAC1 */
+ case 0x75: /* DELTAC2 */
+ Ins_DELTAC( EXEC_ARGS args );
+ break;
+
+ case 0x76: /* SROUND */
+ DO_SROUND
+ break;
+
+ case 0x77: /* S45Round */
+ DO_S45ROUND
+ break;
+
+ case 0x78: /* JROT */
+ DO_JROT
+ break;
+
+ case 0x79: /* JROF */
+ DO_JROF
+ break;
+
+ case 0x7A: /* ROFF */
+ DO_ROFF
+ break;
+
+ case 0x7B: /* ???? */
+ Ins_UNKNOWN( EXEC_ARGS args );
+ break;
+
+ case 0x7C: /* RUTG */
+ DO_RUTG
+ break;
+
+ case 0x7D: /* RDTG */
+ DO_RDTG
+ break;
+
+ case 0x7E: /* SANGW */
+ case 0x7F: /* AA */
+ /* nothing - obsolete */
+ break;
+
+ case 0x80: /* FLIPPT */
+ Ins_FLIPPT( EXEC_ARGS args );
+ break;
+
+ case 0x81: /* FLIPRGON */
+ Ins_FLIPRGON( EXEC_ARGS args );
+ break;
+
+ case 0x82: /* FLIPRGOFF */
+ Ins_FLIPRGOFF( EXEC_ARGS args );
+ break;
+
+ case 0x83: /* UNKNOWN */
+ case 0x84: /* UNKNOWN */
+ Ins_UNKNOWN( EXEC_ARGS args );
+ break;
+
+ case 0x85: /* SCANCTRL */
+ Ins_SCANCTRL( EXEC_ARGS args );
+ break;
+
+ case 0x86: /* SDPVTL */
+ case 0x87: /* SDPVTL */
+ Ins_SDPVTL( EXEC_ARGS args );
+ break;
+
+ case 0x88: /* GETINFO */
+ Ins_GETINFO( EXEC_ARGS args );
+ break;
+
+ case 0x89: /* IDEF */
+ Ins_IDEF( EXEC_ARGS args );
+ break;
+
+ case 0x8A: /* ROLL */
+ Ins_ROLL( EXEC_ARGS args );
+ break;
+
+ case 0x8B: /* MAX */
+ DO_MAX
+ break;
+
+ case 0x8C: /* MIN */
+ DO_MIN
+ break;
+
+ case 0x8D: /* SCANTYPE */
+ Ins_SCANTYPE( EXEC_ARGS args );
+ break;
+
+ case 0x8E: /* INSTCTRL */
+ Ins_INSTCTRL( EXEC_ARGS args );
+ break;
+
+ case 0x8F:
+ Ins_UNKNOWN( EXEC_ARGS args );
+ break;
+
+ default:
+ if ( opcode >= 0xE0 )
+ Ins_MIRP( EXEC_ARGS args );
+ else if ( opcode >= 0xC0 )
+ Ins_MDRP( EXEC_ARGS args );
+ else if ( opcode >= 0xB8 )
+ Ins_PUSHW( EXEC_ARGS args );
+ else if ( opcode >= 0xB0 )
+ Ins_PUSHB( EXEC_ARGS args );
+ else
+ Ins_UNKNOWN( EXEC_ARGS args );
+ }
+
+ }
+#else
+ Instruct_Dispatch[CUR.opcode]( EXEC_ARGS &CUR.stack[CUR.args] );
+#endif
+ if ( CUR.error != TT_Err_Ok )
+ {
+ switch ( (Int)(CUR.error) )
+ {
+ case TT_Err_Invalid_Opcode: /* 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; Unreachable code warning suppress. Leave in case a later
+ change to remind the editor to consider break; */
+
+ default:
+ goto LErrorLabel_;
+/* break; */
+ }
+ }
+
+ CUR.top = CUR.new_top;
+
+ if ( CUR.step_ins )
+ CUR.IP += CUR.length;
+
+ /* increment instruction counter and check if we didn't */
+ /* run this program for too long ?? (e.g. infinite loops) */
+ if ( ++ins_counter > MAX_RUNNABLE_OPCODES )
+ {
+ CUR.error = TT_Err_Execution_Too_Long;
+ goto LErrorLabel_;
+ }
+
+ LSuiteLabel_:
+
+ if ( CUR.IP >= CUR.codeSize )
+ {
+ if ( CUR.callTop > 0 )
+ {
+ CUR.error = TT_Err_Code_Overflow;
+ goto LErrorLabel_;
+ }
+ else
+ goto LNo_Error_;
+ }
+ } while ( !CUR.instruction_trap );
+
+ LNo_Error_:
+ CUR.error = TT_Err_Ok;
+
+ LErrorLabel_:
+
+#ifdef TT_CONFIG_OPTION_STATIC_INTERPRETER
+ *exc = cur;
+#endif
+
+ return CUR.error;
+
+
+ }
+
+
+
+#ifdef DEBUG_INTERPRETER
+
+ /* This function must be declared by the debugger front end */
+ /* in order to specify which code range to debug. */
+
+ int debug_coderange = TT_CodeRange_Glyph;
+
+ FT_INTERNAL_FUNC( TT_Error )
+ RunIns( PExecution_Context exc )
+ {
+ Int A, diff;
+ ULong next_IP;
+ Char ch, oldch;
+ char *temp;
+ int key;
+
+ TT_Error error = 0;
+
+ TGlyph_Zone save;
+ TGlyph_Zone pts;
+
+#define TT_Round_Off 5
+#define TT_Round_To_Half_Grid 0
+#define TT_Round_To_Grid 1
+#define TT_Round_To_Double_Grid 2
+#define TT_Round_Up_To_Grid 4
+#define TT_Round_Down_To_Grid 3
+#define TT_Round_Super 6
+#define TT_Round_Super_45 7
+
+ const String* round_str[8] =
+ {
+ "to half-grid",
+ "to grid",
+ "to double grid",
+ "down to grid",
+ "up to grid",
+ "off",
+ "super",
+ "super 45"
+ };
+
+ /* Check that we're running the code range that is effectively */
+ /* asked by the debugger front end. */
+ if ( CUR.curRange != debug_coderange )
+ return RunIns2( &CUR );
+
+ pts = CUR.pts;
+
+ save.n_points = pts.n_points;
+ save.n_contours = pts.n_contours;
+
+ MEM_Alloc( save.org, sizeof ( TT_Vector ) * save.n_points );
+ MEM_Alloc( save.cur, sizeof ( TT_Vector ) * save.n_points );
+ MEM_Alloc( save.touch, sizeof ( Byte ) * save.n_points );
+
+ CUR.instruction_trap = 1;
+
+ oldch = '\0';
+
+ do
+ {
+ if ( CUR.IP < CUR.codeSize )
+ {
+#ifdef TT_CONFIG_OPTION_STATIC_INTERPRETER
+ cur = *exc;
+#endif
+ CALC_Length();
+
+ CUR.args = CUR.top - (Pop_Push_Count[CUR.opcode] >> 4);
+
+ /* `args' is the top of the stack once arguments have been popped. */
+ /* One can also interpret it as the index of the last argument. */
+
+ /* Print the current line. We use a 80-columns console with the */
+ /* following formatting: */
+ /* */
+ /* [loc]:[addr] [opcode] [disassemby] [a][b]|[c][d] */
+ /* */
+
+ {
+ char temp[80];
+ int n, col, pop;
+ int args = CUR.args;
+
+
+ sprintf( temp, "%78c\n", ' ' );
+
+ /* first letter of location */
+ switch ( CUR.curRange )
+ {
+ case TT_CodeRange_Glyph:
+ temp[0] = 'g';
+ break;
+ case TT_CodeRange_Cvt:
+ temp[0] = 'c';
+ break;
+ default:
+ temp[0] = 'f';
+ }
+
+ /* current IP */
+ sprintf( temp+1, "%04lx: %02x %-36.36s",
+ CUR.IP,
+ CUR.opcode,
+ Cur_U_Line(&CUR) );
+
+ strncpy( temp+46, " (", 2 );
+
+ args = CUR.top - 1;
+ pop = Pop_Push_Count[CUR.opcode] >> 4;
+ col = 48;
+ for ( n = 6; n > 0; n-- )
+ {
+ if ( pop == 0 )
+ temp[col-1] = (temp[col-1] == '(' ? ' ' : ')' );
+
+ if ( args < CUR.top && args >= 0 )
+ sprintf( temp+col, "%04lx", CUR.stack[args] );
+ else
+ sprintf( temp+col, " " );
+
+ temp[col+4] = ' ';
+ col += 5;
+ pop--;
+ args--;
+ }
+ temp[78] = '\n';
+ temp[79] = '\0';
+ PTRACE0(( temp ));
+ }
+
+ /* First, check for empty stack and overflow */
+ if ( CUR.args < 0 )
+ {
+ PTRACE0(( "ERROR : Too few arguments\n" ));
+ CUR.error = TT_Err_Too_Few_Arguments;
+ goto LErrorLabel_;
+ }
+
+ CUR.new_top = CUR.args + (Pop_Push_Count[CUR.opcode] & 15);
+
+ /* 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 )
+ {
+ PTRACE0(( "ERROR : Stack overflow\n" ));
+ CUR.error = TT_Err_Stack_Overflow;
+ goto LErrorLabel_;
+ }
+
+#ifdef TT_CONFIG_OPTION_STATIC_INTERPRETER
+ *exc = cur;
+#endif
+ }
+ else
+ PTRACE0(( "End of program reached.\n" ));
+
+ key = 0;
+ do
+ {
+ /* read keyboard */
+
+ ch = getch();
+
+ switch ( ch )
+ {
+ /* Help - show keybindings */
+ case '?':
+ PTRACE0(( "FDebug Help\n\n" ));
+ PTRACE0(( "? Show this page\n" ));
+ PTRACE0(( "q Quit debugger\n" ));
+ PTRACE0(( "n Skip to next instruction\n" ));
+ PTRACE0(( "s Step into\n" ));
+ PTRACE0(( "v Show vector info\n" ));
+ PTRACE0(( "g Show graphics state\n" ));
+ PTRACE0(( "p Show points zone\n\n" ));
+ break;
+
+ /* Show vectors */
+ case 'v':
+ PTRACE0(( "freedom (%04hx,%04hx)\n", CUR.GS.freeVector.x,
+ CUR.GS.freeVector.y ));
+ PTRACE0(( "projection (%04hx,%04hx)\n", CUR.GS.projVector.x,
+ CUR.GS.projVector.y ));
+ PTRACE0(( "dual (%04hx,%04hx)\n\n", CUR.GS.dualVector.x,
+ CUR.GS.dualVector.y ));
+ break;
+
+ /* Show graphics state */
+ case 'g':
+ PTRACE0(( "rounding %s\n", round_str[CUR.GS.round_state] ));
+ PTRACE0(( "min dist %04lx\n", CUR.GS.minimum_distance ));
+ PTRACE0(( "cvt_cutin %04lx\n", CUR.GS.control_value_cutin ));
+ break;
+
+ /* Show points table */
+ case 'p':
+ for ( A = 0; A < CUR.pts.n_points; A++ )
+ {
+ PTRACE0(( "%02hx ", A ));
+ PTRACE0(( "%08lx,%08lx - ", pts.org[A].x, pts.org[A].y ));
+ PTRACE0(( "%08lx,%08lx\n", pts.cur[A].x, pts.cur[A].y ));
+ }
+ PTRACE0(( "\n" ));
+ break;
+
+ default:
+ key = 1;
+ }
+ } while ( !key );
+
+ MEM_Copy( save.org, pts.org, pts.n_points * sizeof ( TT_Vector ) );
+ MEM_Copy( save.cur, pts.cur, pts.n_points * sizeof ( TT_Vector ) );
+ MEM_Copy( save.touch, pts.touch, pts.n_points );
+
+ /* a return indicate the last command */
+ if (ch == '\r')
+ ch = oldch;
+
+ switch ( ch )
+ {
+ /* Quit debugger */
+ case 'q':
+ goto LErrorLabel_;
+
+ /* Step over */
+ case 'n':
+ if ( CUR.IP < CUR.codeSize )
+ {
+ /* `step over' is equivalent to `step into' except if */
+ /* the current opcode is a CALL or LOOPCALL */
+ if ( CUR.opcode != 0x2a && CUR.opcode != 0x2b )
+ goto Step_into;
+
+ /* otherwise, loop execution until we reach the next opcode */
+ next_IP = CUR.IP + CUR.length;
+ while ( CUR.IP != next_IP )
+ {
+ if ( ( error = RunIns2( &CUR ) ) != 0 )
+ goto LErrorLabel_;
+ }
+ }
+ oldch = ch;
+ break;
+
+ /* Step into */
+ case 's':
+ if ( CUR.IP < CUR.codeSize )
+
+ Step_into:
+ if ( ( error = RunIns2( &CUR ) ) != 0 )
+ goto LErrorLabel_;
+ oldch = ch;
+ break;
+
+ default:
+ PTRACE0(( "unknown command. Press ? for help\n" ));
+ oldch = '\0';
+ }
+
+ for ( A = 0; A < pts.n_points; A++ )
+ {
+ diff = 0;
+ if ( save.org[A].x != pts.org[A].x ) diff |= 1;
+ if ( save.org[A].y != pts.org[A].y ) diff |= 2;
+ if ( save.cur[A].x != pts.cur[A].x ) diff |= 4;
+ if ( save.cur[A].y != pts.cur[A].y ) diff |= 8;
+ if ( save.touch[A] != pts.touch[A] ) diff |= 16;
+
+ if ( diff )
+ {
+ PTRACE0(( "%02hx ", A ));
+
+ if ( diff & 16 ) temp = "(%01hx)"; else temp = " %01hx ";
+ PTRACE0(( temp, save.touch[A] & 7 ));
+
+ if ( diff & 1 ) temp = "(%08lx)"; else temp = " %08lx ";
+ PTRACE0(( temp, save.org[A].x ));
+
+ if ( diff & 2 ) temp = "(%08lx)"; else temp = " %08lx ";
+ PTRACE0(( temp, save.org[A].y ));
+
+ if ( diff & 4 ) temp = "(%08lx)"; else temp = " %08lx ";
+ PTRACE0(( temp, save.cur[A].x ));
+
+ if ( diff & 8 ) temp = "(%08lx)"; else temp = " %08lx ";
+ PTRACE0(( temp, save.cur[A].y ));
+
+ PTRACE0(( "\n" ));
+
+ PTRACE0(( "%02hx ", A ));
+
+ if ( diff & 16 ) temp = "[%01hx]"; else temp = " %01hx ";
+ PTRACE0(( temp, pts.touch[A] & 7 ));
+
+ if ( diff & 1 ) temp = "[%08lx]"; else temp = " %08lx ";
+ PTRACE0(( temp, pts.org[A].x ));
+
+ if ( diff & 2 ) temp = "[%08lx]"; else temp = " %08lx ";
+ PTRACE0(( temp, pts.org[A].y ));
+
+ if ( diff & 4 ) temp = "[%08lx]"; else temp = " %08lx ";
+ PTRACE0(( temp, pts.cur[A].x ));
+
+ if ( diff & 8 ) temp = "[%08lx]"; else temp = " %08lx ";
+ PTRACE0(( temp, pts.cur[A].y ));
+
+ PTRACE0(( "\n\n" ));
+ }
+ }
+ } while ( TRUE );
+
+ LErrorLabel_:
+
+ return error;
+ }
+
+#endif /* DEBUG_INTERPRETER */
+
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+/* END */