-/***************************************************************************/
-/* */
-/* ttinterp.c */
-/* */
-/* TrueType bytecode interpreter (body). */
-/* */
-/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007 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. */
-/* */
-/***************************************************************************/
-
-
-#include <ft2build.h>
-#include FT_INTERNAL_DEBUG_H
-#include FT_INTERNAL_CALC_H
-#include FT_TRIGONOMETRY_H
-#include FT_SYSTEM_H
-
-#include "ttinterp.h"
-
-#include "tterrors.h"
-
-
-#ifdef TT_USE_BYTECODE_INTERPRETER
-
-
-#define TT_MULFIX FT_MulFix
-#define TT_MULDIV FT_MulDiv
-#define TT_MULDIV_NO_ROUND FT_MulDiv_No_Round
-
-
- /*************************************************************************/
- /* */
- /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
- /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
- /* messages during execution. */
- /* */
-#undef FT_COMPONENT
-#define FT_COMPONENT trace_ttinterp
-
- /*************************************************************************/
- /* */
- /* In order to detect infinite loops in the code, we set up a counter */
- /* within the run loop. A single stroke of interpretation is now */
- /* limited to a maximal number of opcodes defined below. */
- /* */
-#define MAX_RUNNABLE_OPCODES 1000000L
-
-
- /*************************************************************************/
- /* */
- /* There are two kinds of implementations: */
- /* */
- /* 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 fully re-entrant. */
- /* */
- /* The idea is that an indirect implementation may be slower to execute */
- /* on low-end processors that are used in some systems (like 386s or */
- /* even 486s). */
- /* */
- /* 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 code used for */
- /* development. */
- /* */
- /* - It's much more readable that way! */
- /* */
- /* - It's still open to experimentation and tuning. */
- /* */
- /*************************************************************************/
-
-
-#ifndef TT_CONFIG_OPTION_STATIC_INTERPRETER /* indirect implementation */
-
-#define CUR (*exc) /* see ttobjs.h */
-
- /*************************************************************************/
- /* */
- /* This macro is used whenever `exec' is unused in a function, to avoid */
- /* stupid warnings from pedantic compilers. */
- /* */
-#define FT_UNUSED_EXEC FT_UNUSED( exc )
-
-#else /* static implementation */
-
-#define CUR cur
-
-#define FT_UNUSED_EXEC int __dummy = __dummy
-
- static
- TT_ExecContextRec cur; /* static exec. context variable */
-
- /* apparently, we have a _lot_ of direct indexing when accessing */
- /* the static `cur', which makes the code bigger (due to all the */
- /* four bytes addresses). */
-
-#endif /* TT_CONFIG_OPTION_STATIC_INTERPRETER */
-
-
- /*************************************************************************/
- /* */
- /* The instruction argument stack. */
- /* */
-#define INS_ARG EXEC_OP_ FT_Long* args /* see ttobjs.h for EXEC_OP_ */
-
-
- /*************************************************************************/
- /* */
- /* This macro is used whenever `args' is unused in a function, to avoid */
- /* stupid warnings from pedantic compilers. */
- /* */
-#define FT_UNUSED_ARG FT_UNUSED_EXEC; FT_UNUSED( args )
-
-
- /*************************************************************************/
- /* */
- /* The following macros hide the use of EXEC_ARG and EXEC_ARG_ to */
- /* increase readability of the code. */
- /* */
- /*************************************************************************/
-
-
-#define SKIP_Code() \
- SkipCode( EXEC_ARG )
-
-#define GET_ShortIns() \
- GetShortIns( EXEC_ARG )
-
-#define NORMalize( x, y, v ) \
- Normalize( EXEC_ARG_ x, y, v )
-
-#define SET_SuperRound( scale, flags ) \
- SetSuperRound( EXEC_ARG_ scale, flags )
-
-#define ROUND_None( d, c ) \
- Round_None( EXEC_ARG_ d, c )
-
-#define INS_Goto_CodeRange( range, ip ) \
- Ins_Goto_CodeRange( EXEC_ARG_ range, ip )
-
-#define CUR_Func_move( z, p, d ) \
- CUR.func_move( EXEC_ARG_ z, p, d )
-
-#define CUR_Func_move_orig( z, p, d ) \
- CUR.func_move_orig( EXEC_ARG_ z, p, d )
-
-#define CUR_Func_round( d, c ) \
- CUR.func_round( EXEC_ARG_ d, c )
-
-#define CUR_Func_read_cvt( index ) \
- CUR.func_read_cvt( EXEC_ARG_ index )
-
-#define CUR_Func_write_cvt( index, val ) \
- CUR.func_write_cvt( EXEC_ARG_ index, val )
-
-#define CUR_Func_move_cvt( index, val ) \
- CUR.func_move_cvt( EXEC_ARG_ index, val )
-
-#define CURRENT_Ratio() \
- Current_Ratio( EXEC_ARG )
-
-#define CURRENT_Ppem() \
- Current_Ppem( EXEC_ARG )
-
-#define CUR_Ppem() \
- Cur_PPEM( EXEC_ARG )
-
-#define INS_SxVTL( a, b, c, d ) \
- Ins_SxVTL( EXEC_ARG_ a, b, c, d )
-
-#define COMPUTE_Funcs() \
- Compute_Funcs( EXEC_ARG )
-
-#define COMPUTE_Round( a ) \
- Compute_Round( EXEC_ARG_ a )
-
-#define COMPUTE_Point_Displacement( a, b, c, d ) \
- Compute_Point_Displacement( EXEC_ARG_ a, b, c, d )
-
-#define MOVE_Zp2_Point( a, b, c, t ) \
- Move_Zp2_Point( EXEC_ARG_ a, b, c, t )
-
-
-#define CUR_Func_project( v1, v2 ) \
- CUR.func_project( EXEC_ARG_ (v1)->x - (v2)->x, (v1)->y - (v2)->y )
-
-#define CUR_Func_dualproj( v1, v2 ) \
- CUR.func_dualproj( EXEC_ARG_ (v1)->x - (v2)->x, (v1)->y - (v2)->y )
-
-#define CUR_fast_project( v ) \
- CUR.func_project( EXEC_ARG_ (v)->x, (v)->y )
-
-#define CUR_fast_dualproj( v ) \
- CUR.func_dualproj( EXEC_ARG_ (v)->x, (v)->y )
-
-
- /*************************************************************************/
- /* */
- /* Instruction dispatch function, as used by the interpreter. */
- /* */
- typedef void (*TInstruction_Function)( INS_ARG );
-
-
- /*************************************************************************/
- /* */
- /* A simple bounds-checking macro. */
- /* */
-#define BOUNDS( x, n ) ( (FT_UInt)(x) >= (FT_UInt)(n) )
-
-#undef SUCCESS
-#define SUCCESS 0
-
-#undef FAILURE
-#define FAILURE 1
-
-#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
-#define GUESS_VECTOR( V ) \
- if ( CUR.face->unpatented_hinting ) \
- { \
- CUR.GS.V.x = (FT_F2Dot14)( CUR.GS.both_x_axis ? 0x4000 : 0 ); \
- CUR.GS.V.y = (FT_F2Dot14)( CUR.GS.both_x_axis ? 0 : 0x4000 ); \
- }
-#else
-#define GUESS_VECTOR( V )
-#endif
-
- /*************************************************************************/
- /* */
- /* CODERANGE FUNCTIONS */
- /* */
- /*************************************************************************/
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* TT_Goto_CodeRange */
- /* */
- /* <Description> */
- /* Switches to a new code range (updates the code related elements in */
- /* `exec', and `IP'). */
- /* */
- /* <Input> */
- /* range :: The new execution code range. */
- /* */
- /* IP :: The new IP in the new code range. */
- /* */
- /* <InOut> */
- /* exec :: The target execution context. */
- /* */
- /* <Return> */
- /* FreeType error code. 0 means success. */
- /* */
- FT_LOCAL_DEF( FT_Error )
- TT_Goto_CodeRange( TT_ExecContext exec,
- FT_Int range,
- FT_Long IP )
- {
- TT_CodeRange* coderange;
-
-
- FT_ASSERT( range >= 1 && range <= 3 );
-
- coderange = &exec->codeRangeTable[range - 1];
-
- FT_ASSERT( coderange->base != NULL );
-
- /* 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 IP <= Size instead of IP < Size. */
- /* */
- FT_ASSERT( (FT_ULong)IP <= coderange->size );
-
- exec->code = coderange->base;
- exec->codeSize = coderange->size;
- exec->IP = IP;
- exec->curRange = range;
-
- return TT_Err_Ok;
- }
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* TT_Set_CodeRange */
- /* */
- /* <Description> */
- /* Sets a code range. */
- /* */
- /* <Input> */
- /* range :: The code range index. */
- /* */
- /* base :: The new code base. */
- /* */
- /* length :: The range size in bytes. */
- /* */
- /* <InOut> */
- /* exec :: The target execution context. */
- /* */
- /* <Return> */
- /* FreeType error code. 0 means success. */
- /* */
- FT_LOCAL_DEF( FT_Error )
- TT_Set_CodeRange( TT_ExecContext exec,
- FT_Int range,
- void* base,
- FT_Long length )
- {
- FT_ASSERT( range >= 1 && range <= 3 );
-
- exec->codeRangeTable[range - 1].base = (FT_Byte*)base;
- exec->codeRangeTable[range - 1].size = length;
-
- return TT_Err_Ok;
- }
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* TT_Clear_CodeRange */
- /* */
- /* <Description> */
- /* Clears a code range. */
- /* */
- /* <Input> */
- /* range :: The code range index. */
- /* */
- /* <InOut> */
- /* exec :: The target execution context. */
- /* */
- /* <Return> */
- /* FreeType error code. 0 means success. */
- /* */
- /* <Note> */
- /* Does not set the Error variable. */
- /* */
- FT_LOCAL_DEF( FT_Error )
- TT_Clear_CodeRange( TT_ExecContext exec,
- FT_Int range )
- {
- FT_ASSERT( range >= 1 && range <= 3 );
-
- exec->codeRangeTable[range - 1].base = NULL;
- exec->codeRangeTable[range - 1].size = 0;
-
- return TT_Err_Ok;
- }
-
-
- /*************************************************************************/
- /* */
- /* EXECUTION CONTEXT ROUTINES */
- /* */
- /*************************************************************************/
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* TT_Done_Context */
- /* */
- /* <Description> */
- /* Destroys a given context. */
- /* */
- /* <Input> */
- /* exec :: A handle to the target execution context. */
- /* */
- /* memory :: A handle to the parent memory object. */
- /* */
- /* <Return> */
- /* FreeType error code. 0 means success. */
- /* */
- /* <Note> */
- /* Only the glyph loader and debugger should call this function. */
- /* */
- FT_LOCAL_DEF( FT_Error )
- TT_Done_Context( TT_ExecContext exec )
- {
- FT_Memory memory = exec->memory;
-
-
- /* points zone */
- exec->maxPoints = 0;
- exec->maxContours = 0;
-
- /* free stack */
- FT_FREE( exec->stack );
- exec->stackSize = 0;
-
- /* free call stack */
- FT_FREE( exec->callStack );
- exec->callSize = 0;
- exec->callTop = 0;
-
- /* free glyph code range */
- FT_FREE( exec->glyphIns );
- exec->glyphSize = 0;
-
- exec->size = NULL;
- exec->face = NULL;
-
- FT_FREE( exec );
-
- return TT_Err_Ok;
- }
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Init_Context */
- /* */
- /* <Description> */
- /* Initializes a context object. */
- /* */
- /* <Input> */
- /* memory :: A handle to the parent memory object. */
- /* */
- /* <InOut> */
- /* exec :: A handle to the target execution context. */
- /* */
- /* <Return> */
- /* FreeType error code. 0 means success. */
- /* */
- static FT_Error
- Init_Context( TT_ExecContext exec,
- FT_Memory memory )
- {
- FT_Error error;
-
-
- FT_TRACE1(( "Init_Context: new object at 0x%08p\n", exec ));
-
- exec->memory = memory;
- exec->callSize = 32;
-
- if ( FT_NEW_ARRAY( exec->callStack, exec->callSize ) )
- goto Fail_Memory;
-
- /* all values in the context are set to 0 already, but this is */
- /* here as a remainder */
- exec->maxPoints = 0;
- exec->maxContours = 0;
-
- exec->stackSize = 0;
- exec->glyphSize = 0;
-
- exec->stack = NULL;
- exec->glyphIns = NULL;
-
- exec->face = NULL;
- exec->size = NULL;
-
- return TT_Err_Ok;
-
- Fail_Memory:
- FT_ERROR(( "Init_Context: not enough memory for 0x%08lx\n",
- (FT_Long)exec ));
- TT_Done_Context( exec );
-
- return error;
- }
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Update_Max */
- /* */
- /* <Description> */
- /* Checks the size of a buffer and reallocates it if necessary. */
- /* */
- /* <Input> */
- /* memory :: A handle to the parent memory object. */
- /* */
- /* multiplier :: The size in bytes of each element in the buffer. */
- /* */
- /* new_max :: The new capacity (size) of the buffer. */
- /* */
- /* <InOut> */
- /* size :: The address of the buffer's current size expressed */
- /* in elements. */
- /* */
- /* buff :: The address of the buffer base pointer. */
- /* */
- /* <Return> */
- /* FreeType error code. 0 means success. */
- /* */
- static FT_Error
- Update_Max( FT_Memory memory,
- FT_ULong* size,
- FT_Long multiplier,
- void* _pbuff,
- FT_ULong new_max )
- {
- FT_Error error;
- void** pbuff = (void**)_pbuff;
-
-
- if ( *size < new_max )
- {
- if ( FT_REALLOC( *pbuff, *size * multiplier, new_max * multiplier ) )
- return error;
- *size = new_max;
- }
-
- return TT_Err_Ok;
- }
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* TT_Load_Context */
- /* */
- /* <Description> */
- /* Prepare an execution context for glyph hinting. */
- /* */
- /* <Input> */
- /* face :: A handle to the source face object. */
- /* */
- /* size :: A handle to the source size object. */
- /* */
- /* <InOut> */
- /* exec :: A handle to the target execution context. */
- /* */
- /* <Return> */
- /* FreeType error code. 0 means success. */
- /* */
- /* <Note> */
- /* Only the glyph loader and debugger should call this function. */
- /* */
- FT_LOCAL_DEF( FT_Error )
- TT_Load_Context( TT_ExecContext exec,
- TT_Face face,
- TT_Size size )
- {
- FT_Int i;
- FT_ULong tmp;
- TT_MaxProfile* maxp;
- FT_Error error;
-
-
- exec->face = face;
- maxp = &face->max_profile;
- exec->size = size;
-
- if ( size )
- {
- exec->numFDefs = size->num_function_defs;
- exec->maxFDefs = size->max_function_defs;
- exec->numIDefs = size->num_instruction_defs;
- exec->maxIDefs = size->max_instruction_defs;
- exec->FDefs = size->function_defs;
- exec->IDefs = size->instruction_defs;
- exec->tt_metrics = size->ttmetrics;
- exec->metrics = size->metrics;
-
- exec->maxFunc = size->max_func;
- exec->maxIns = size->max_ins;
-
- for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
- exec->codeRangeTable[i] = size->codeRangeTable[i];
-
- /* set graphics state */
- exec->GS = size->GS;
-
- exec->cvtSize = size->cvt_size;
- exec->cvt = size->cvt;
-
- exec->storeSize = size->storage_size;
- exec->storage = size->storage;
-
- exec->twilight = size->twilight;
- }
-
- /* XXX: We reserve a little more elements on the stack to deal safely */
- /* with broken fonts like arialbs, courbs, timesbs, etc. */
- tmp = exec->stackSize;
- error = Update_Max( exec->memory,
- &tmp,
- sizeof ( FT_F26Dot6 ),
- (void*)&exec->stack,
- maxp->maxStackElements + 32 );
- exec->stackSize = (FT_UInt)tmp;
- if ( error )
- return error;
-
- tmp = exec->glyphSize;
- error = Update_Max( exec->memory,
- &tmp,
- sizeof ( FT_Byte ),
- (void*)&exec->glyphIns,
- maxp->maxSizeOfInstructions );
- exec->glyphSize = (FT_UShort)tmp;
- if ( error )
- return error;
-
- exec->pts.n_points = 0;
- exec->pts.n_contours = 0;
-
- exec->zp1 = exec->pts;
- exec->zp2 = exec->pts;
- exec->zp0 = exec->pts;
-
- exec->instruction_trap = FALSE;
-
- return TT_Err_Ok;
- }
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* TT_Save_Context */
- /* */
- /* <Description> */
- /* Saves the code ranges in a `size' object. */
- /* */
- /* <Input> */
- /* exec :: A handle to the source execution context. */
- /* */
- /* <InOut> */
- /* size :: A handle to the target size object. */
- /* */
- /* <Return> */
- /* FreeType error code. 0 means success. */
- /* */
- /* <Note> */
- /* Only the glyph loader and debugger should call this function. */
- /* */
- FT_LOCAL_DEF( FT_Error )
- TT_Save_Context( TT_ExecContext exec,
- TT_Size size )
- {
- FT_Int i;
-
-
- /* XXXX: Will probably disappear soon with all the code range */
- /* management, which is now rather obsolete. */
- /* */
- size->num_function_defs = exec->numFDefs;
- size->num_instruction_defs = exec->numIDefs;
-
- size->max_func = exec->maxFunc;
- size->max_ins = exec->maxIns;
-
- for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
- size->codeRangeTable[i] = exec->codeRangeTable[i];
-
- return TT_Err_Ok;
- }
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* TT_Run_Context */
- /* */
- /* <Description> */
- /* Executes one or more instructions in the execution context. */
- /* */
- /* <Input> */
- /* debug :: A Boolean flag. If set, the function sets some internal */
- /* variables and returns immediately, otherwise TT_RunIns() */
- /* is called. */
- /* */
- /* This is commented out currently. */
- /* */
- /* <Input> */
- /* exec :: A handle to the target execution context. */
- /* */
- /* <Return> */
- /* TrueTyoe error code. 0 means success. */
- /* */
- /* <Note> */
- /* Only the glyph loader and debugger should call this function. */
- /* */
- FT_LOCAL_DEF( FT_Error )
- TT_Run_Context( TT_ExecContext exec,
- FT_Bool debug )
- {
- FT_Error error;
-
-
- if ( ( error = TT_Goto_CodeRange( exec, tt_coderange_glyph, 0 ) )
- != TT_Err_Ok )
- return error;
-
- exec->zp0 = exec->pts;
- exec->zp1 = exec->pts;
- exec->zp2 = exec->pts;
-
- exec->GS.gep0 = 1;
- exec->GS.gep1 = 1;
- exec->GS.gep2 = 1;
-
- exec->GS.projVector.x = 0x4000;
- exec->GS.projVector.y = 0x0000;
-
- exec->GS.freeVector = exec->GS.projVector;
- exec->GS.dualVector = exec->GS.projVector;
-
-#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
- exec->GS.both_x_axis = TRUE;
-#endif
-
- exec->GS.round_state = 1;
- exec->GS.loop = 1;
-
- /* some glyphs leave something on the stack. so we clean it */
- /* before a new execution. */
- exec->top = 0;
- exec->callTop = 0;
-
-#if 1
- FT_UNUSED( debug );
-
- return exec->face->interpreter( exec );
-#else
- if ( !debug )
- return TT_RunIns( exec );
- else
- return TT_Err_Ok;
-#endif
- }
-
-
- const TT_GraphicsState tt_default_graphics_state =
- {
- 0, 0, 0,
- { 0x4000, 0 },
- { 0x4000, 0 },
- { 0x4000, 0 },
-
-#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
- TRUE,
-#endif
-
- 1, 64, 1,
- TRUE, 68, 0, 0, 9, 3,
- 0, FALSE, 2, 1, 1, 1
- };
-
-
- /* documentation is in ttinterp.h */
-
- FT_EXPORT_DEF( TT_ExecContext )
- TT_New_Context( TT_Driver driver )
- {
- TT_ExecContext exec;
- FT_Memory memory;
-
-
- memory = driver->root.root.memory;
- exec = driver->context;
-
- if ( !driver->context )
- {
- FT_Error error;
-
-
- /* allocate object */
- if ( FT_NEW( exec ) )
- goto Exit;
-
- /* initialize it */
- error = Init_Context( exec, memory );
- if ( error )
- goto Fail;
-
- /* store it into the driver */
- driver->context = exec;
- }
-
- Exit:
- return driver->context;
-
- Fail:
- FT_FREE( exec );
-
- return 0;
- }
-
-
- /*************************************************************************/
- /* */
- /* 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. */
- /* */
- /* Opcodes which have a varying number of parameters in the data stream */
- /* (NPUSHB, NPUSHW) are handled specially; they have a negative value in */
- /* the `opcode_length' table, and the value in `Pop_Push_Count' is set */
- /* to zero. */
- /* */
- /*************************************************************************/
-
-
-#undef PACK
-#define PACK( x, y ) ( ( x << 4 ) | y )
-
-
- static
- const FT_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 FT_Char opcode_length[256] =
- {
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-
- -1,-2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 2, 3, 4, 5, 6, 7, 8, 9, 3, 5, 7, 9, 11,13,15,17,
-
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
- };
-
-#undef PACK
-
-#if 1
-
- static FT_Int32
- TT_MulFix14( FT_Int32 a,
- FT_Int b )
- {
- FT_Int32 sign;
- FT_UInt32 ah, al, mid, lo, hi;
-
-
- sign = a ^ b;
-
- if ( a < 0 )
- a = -a;
- if ( b < 0 )
- b = -b;
-
- ah = (FT_UInt32)( ( a >> 16 ) & 0xFFFFU );
- al = (FT_UInt32)( a & 0xFFFFU );
-
- lo = al * b;
- mid = ah * b;
- hi = mid >> 16;
- mid = ( mid << 16 ) + ( 1 << 13 ); /* rounding */
- lo += mid;
- if ( lo < mid )
- hi += 1;
-
- mid = ( lo >> 14 ) | ( hi << 18 );
-
- return sign >= 0 ? (FT_Int32)mid : -(FT_Int32)mid;
- }
-
-#else
-
- /* compute (a*b)/2^14 with maximal accuracy and rounding */
- static FT_Int32
- TT_MulFix14( FT_Int32 a,
- FT_Int b )
- {
- FT_Int32 m, s, hi;
- FT_UInt32 l, lo;
-
-
- /* compute ax*bx as 64-bit value */
- l = (FT_UInt32)( ( a & 0xFFFFU ) * b );
- m = ( a >> 16 ) * b;
-
- lo = l + (FT_UInt32)( m << 16 );
- hi = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo < l );
-
- /* divide the result by 2^14 with rounding */
- s = hi >> 31;
- l = lo + (FT_UInt32)s;
- hi += s + ( l < lo );
- lo = l;
-
- l = lo + 0x2000U;
- hi += l < lo;
-
- return ( hi << 18 ) | ( l >> 14 );
- }
-#endif
-
-
- /* compute (ax*bx+ay*by)/2^14 with maximal accuracy and rounding */
- static FT_Int32
- TT_DotFix14( FT_Int32 ax,
- FT_Int32 ay,
- FT_Int bx,
- FT_Int by )
- {
- FT_Int32 m, s, hi1, hi2, hi;
- FT_UInt32 l, lo1, lo2, lo;
-
-
- /* compute ax*bx as 64-bit value */
- l = (FT_UInt32)( ( ax & 0xFFFFU ) * bx );
- m = ( ax >> 16 ) * bx;
-
- lo1 = l + (FT_UInt32)( m << 16 );
- hi1 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo1 < l );
-
- /* compute ay*by as 64-bit value */
- l = (FT_UInt32)( ( ay & 0xFFFFU ) * by );
- m = ( ay >> 16 ) * by;
-
- lo2 = l + (FT_UInt32)( m << 16 );
- hi2 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo2 < l );
-
- /* add them */
- lo = lo1 + lo2;
- hi = hi1 + hi2 + ( lo < lo1 );
-
- /* divide the result by 2^14 with rounding */
- s = hi >> 31;
- l = lo + (FT_UInt32)s;
- hi += s + ( l < lo );
- lo = l;
-
- l = lo + 0x2000U;
- hi += ( l < lo );
-
- return ( hi << 18 ) | ( l >> 14 );
- }
-
-
- /* return length of given vector */
-
-#if 0
-
- static FT_Int32
- TT_VecLen( FT_Int32 x,
- FT_Int32 y )
- {
- FT_Int32 m, hi1, hi2, hi;
- FT_UInt32 l, lo1, lo2, lo;
-
-
- /* compute x*x as 64-bit value */
- lo = (FT_UInt32)( x & 0xFFFFU );
- hi = x >> 16;
-
- l = lo * lo;
- m = hi * lo;
- hi = hi * hi;
-
- lo1 = l + (FT_UInt32)( m << 17 );
- hi1 = hi + ( m >> 15 ) + ( lo1 < l );
-
- /* compute y*y as 64-bit value */
- lo = (FT_UInt32)( y & 0xFFFFU );
- hi = y >> 16;
-
- l = lo * lo;
- m = hi * lo;
- hi = hi * hi;
-
- lo2 = l + (FT_UInt32)( m << 17 );
- hi2 = hi + ( m >> 15 ) + ( lo2 < l );
-
- /* add them to get 'x*x+y*y' as 64-bit value */
- lo = lo1 + lo2;
- hi = hi1 + hi2 + ( lo < lo1 );
-
- /* compute the square root of this value */
- {
- FT_UInt32 root, rem, test_div;
- FT_Int count;
-
-
- root = 0;
-
- {
- rem = 0;
- count = 32;
- do
- {
- rem = ( rem << 2 ) | ( (FT_UInt32)hi >> 30 );
- hi = ( hi << 2 ) | ( lo >> 30 );
- lo <<= 2;
- root <<= 1;
- test_div = ( root << 1 ) + 1;
-
- if ( rem >= test_div )
- {
- rem -= test_div;
- root += 1;
- }
- } while ( --count );
- }
-
- return (FT_Int32)root;
- }
- }
-
-#else
-
- /* this version uses FT_Vector_Length which computes the same value */
- /* much, much faster.. */
- /* */
- static FT_F26Dot6
- TT_VecLen( FT_F26Dot6 X,
- FT_F26Dot6 Y )
- {
- FT_Vector v;
-
-
- v.x = X;
- v.y = Y;
-
- return FT_Vector_Length( &v );
- }
-
-#endif
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Current_Ratio */
- /* */
- /* <Description> */
- /* Returns the current aspect ratio scaling factor depending on the */
- /* projection vector's state and device resolutions. */
- /* */
- /* <Return> */
- /* The aspect ratio in 16.16 format, always <= 1.0 . */
- /* */
- static FT_Long
- Current_Ratio( EXEC_OP )
- {
- if ( !CUR.tt_metrics.ratio )
- {
-#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
- if ( CUR.face->unpatented_hinting )
- {
- if ( CUR.GS.both_x_axis )
- CUR.tt_metrics.ratio = CUR.tt_metrics.x_ratio;
- else
- CUR.tt_metrics.ratio = CUR.tt_metrics.y_ratio;
- }
- else
-#endif
- {
- if ( CUR.GS.projVector.y == 0 )
- CUR.tt_metrics.ratio = CUR.tt_metrics.x_ratio;
-
- else if ( CUR.GS.projVector.x == 0 )
- CUR.tt_metrics.ratio = CUR.tt_metrics.y_ratio;
-
- else
- {
- FT_Long x, y;
-
-
- x = TT_MULDIV( CUR.GS.projVector.x,
- CUR.tt_metrics.x_ratio, 0x4000 );
- y = TT_MULDIV( CUR.GS.projVector.y,
- CUR.tt_metrics.y_ratio, 0x4000 );
- CUR.tt_metrics.ratio = TT_VecLen( x, y );
- }
- }
- }
- return CUR.tt_metrics.ratio;
- }
-
-
- static FT_Long
- Current_Ppem( EXEC_OP )
- {
- return TT_MULFIX( CUR.tt_metrics.ppem, CURRENT_Ratio() );
- }
-
-
- /*************************************************************************/
- /* */
- /* Functions related to the control value table (CVT). */
- /* */
- /*************************************************************************/
-
-
- FT_CALLBACK_DEF( FT_F26Dot6 )
- Read_CVT( EXEC_OP_ FT_ULong idx )
- {
- return CUR.cvt[idx];
- }
-
-
- FT_CALLBACK_DEF( FT_F26Dot6 )
- Read_CVT_Stretched( EXEC_OP_ FT_ULong idx )
- {
- return TT_MULFIX( CUR.cvt[idx], CURRENT_Ratio() );
- }
-
-
- FT_CALLBACK_DEF( void )
- Write_CVT( EXEC_OP_ FT_ULong idx,
- FT_F26Dot6 value )
- {
- CUR.cvt[idx] = value;
- }
-
-
- FT_CALLBACK_DEF( void )
- Write_CVT_Stretched( EXEC_OP_ FT_ULong idx,
- FT_F26Dot6 value )
- {
- CUR.cvt[idx] = FT_DivFix( value, CURRENT_Ratio() );
- }
-
-
- FT_CALLBACK_DEF( void )
- Move_CVT( EXEC_OP_ FT_ULong idx,
- FT_F26Dot6 value )
- {
- CUR.cvt[idx] += value;
- }
-
-
- FT_CALLBACK_DEF( void )
- Move_CVT_Stretched( EXEC_OP_ FT_ULong idx,
- FT_F26Dot6 value )
- {
- CUR.cvt[idx] += FT_DivFix( value, CURRENT_Ratio() );
- }
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* GetShortIns */
- /* */
- /* <Description> */
- /* Returns a short integer taken from the instruction stream at */
- /* address IP. */
- /* */
- /* <Return> */
- /* Short read at code[IP]. */
- /* */
- /* <Note> */
- /* This one could become a macro. */
- /* */
- static FT_Short
- GetShortIns( EXEC_OP )
- {
- /* Reading a byte stream so there is no endianess (DaveP) */
- CUR.IP += 2;
- return (FT_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 :: The index of the code range. */
- /* */
- /* aIP :: The new IP address in the code range. */
- /* */
- /* <Return> */
- /* SUCCESS or FAILURE. */
- /* */
- static FT_Bool
- Ins_Goto_CodeRange( EXEC_OP_ FT_Int aRange,
- FT_ULong aIP )
- {
- TT_CodeRange* range;
-
-
- if ( aRange < 1 || aRange > 3 )
- {
- CUR.error = TT_Err_Bad_Argument;
- return FAILURE;
- }
-
- range = &CUR.codeRangeTable[aRange - 1];
-
- if ( range->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 > range->size )
- {
- CUR.error = TT_Err_Code_Overflow;
- return FAILURE;
- }
-
- CUR.code = range->base;
- CUR.codeSize = range->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 :: The index of the point to move. */
- /* */
- /* distance :: The distance to apply. */
- /* */
- /* <InOut> */
- /* zone :: The affected glyph zone. */
- /* */
- static void
- Direct_Move( EXEC_OP_ TT_GlyphZone zone,
- FT_UShort point,
- FT_F26Dot6 distance )
- {
- FT_F26Dot6 v;
-
-
-#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
- FT_ASSERT( !CUR.face->unpatented_hinting );
-#endif
-
- v = CUR.GS.freeVector.x;
-
- if ( v != 0 )
- {
- zone->cur[point].x += TT_MULDIV( distance,
- v * 0x10000L,
- CUR.F_dot_P );
-
- zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;
- }
-
- v = CUR.GS.freeVector.y;
-
- if ( v != 0 )
- {
- zone->cur[point].y += TT_MULDIV( distance,
- v * 0x10000L,
- CUR.F_dot_P );
-
- zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
- }
- }
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Direct_Move_Orig */
- /* */
- /* <Description> */
- /* Moves the *original* position of a point by a given distance along */
- /* the freedom vector. Obviously, the point will not be `touched'. */
- /* */
- /* <Input> */
- /* point :: The index of the point to move. */
- /* */
- /* distance :: The distance to apply. */
- /* */
- /* <InOut> */
- /* zone :: The affected glyph zone. */
- /* */
- static void
- Direct_Move_Orig( EXEC_OP_ TT_GlyphZone zone,
- FT_UShort point,
- FT_F26Dot6 distance )
- {
- FT_F26Dot6 v;
-
-
-#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
- FT_ASSERT( !CUR.face->unpatented_hinting );
-#endif
-
- v = CUR.GS.freeVector.x;
-
- if ( v != 0 )
- zone->org[point].x += TT_MULDIV( distance,
- v * 0x10000L,
- CUR.F_dot_P );
-
- v = CUR.GS.freeVector.y;
-
- if ( v != 0 )
- zone->org[point].y += TT_MULDIV( distance,
- v * 0x10000L,
- CUR.F_dot_P );
- }
-
-
- /*************************************************************************/
- /* */
- /* Special versions of Direct_Move() */
- /* */
- /* The following versions are used whenever both vectors are both */
- /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */
- /* */
- /*************************************************************************/
-
-
- static void
- Direct_Move_X( EXEC_OP_ TT_GlyphZone zone,
- FT_UShort point,
- FT_F26Dot6 distance )
- {
- FT_UNUSED_EXEC;
-
- zone->cur[point].x += distance;
- zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;
- }
-
-
- static void
- Direct_Move_Y( EXEC_OP_ TT_GlyphZone zone,
- FT_UShort point,
- FT_F26Dot6 distance )
- {
- FT_UNUSED_EXEC;
-
- zone->cur[point].y += distance;
- zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
- }
-
-
- /*************************************************************************/
- /* */
- /* Special versions of Direct_Move_Orig() */
- /* */
- /* The following versions are used whenever both vectors are both */
- /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */
- /* */
- /*************************************************************************/
-
-
- static void
- Direct_Move_Orig_X( EXEC_OP_ TT_GlyphZone zone,
- FT_UShort point,
- FT_F26Dot6 distance )
- {
- FT_UNUSED_EXEC;
-
- zone->org[point].x += distance;
- }
-
-
- static void
- Direct_Move_Orig_Y( EXEC_OP_ TT_GlyphZone zone,
- FT_UShort point,
- FT_F26Dot6 distance )
- {
- FT_UNUSED_EXEC;
-
- zone->org[point].y += distance;
- }
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Round_None */
- /* */
- /* <Description> */
- /* Does not round, but adds engine compensation. */
- /* */
- /* <Input> */
- /* distance :: The distance (not) to round. */
- /* */
- /* compensation :: The engine compensation. */
- /* */
- /* <Return> */
- /* The compensated distance. */
- /* */
- /* <Note> */
- /* The TrueType specification says very few about the relationship */
- /* between rounding and engine compensation. However, it seems from */
- /* the description of super round that we should add the compensation */
- /* before rounding. */
- /* */
- static FT_F26Dot6
- Round_None( EXEC_OP_ FT_F26Dot6 distance,
- FT_F26Dot6 compensation )
- {
- FT_F26Dot6 val;
-
- FT_UNUSED_EXEC;
-
-
- if ( distance >= 0 )
- {
- val = distance + compensation;
- if ( distance && 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 :: The distance to round. */
- /* */
- /* compensation :: The engine compensation. */
- /* */
- /* <Return> */
- /* Rounded distance. */
- /* */
- static FT_F26Dot6
- Round_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
- FT_F26Dot6 compensation )
- {
- FT_F26Dot6 val;
-
- FT_UNUSED_EXEC;
-
-
- if ( distance >= 0 )
- {
- val = distance + compensation + 32;
- if ( distance && val > 0 )
- val &= ~63;
- else
- val = 0;
- }
- else
- {
- val = -FT_PIX_ROUND( compensation - distance );
- if ( val > 0 )
- val = 0;
- }
-
- return val;
- }
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Round_To_Half_Grid */
- /* */
- /* <Description> */
- /* Rounds value to half grid after adding engine compensation. */
- /* */
- /* <Input> */
- /* distance :: The distance to round. */
- /* */
- /* compensation :: The engine compensation. */
- /* */
- /* <Return> */
- /* Rounded distance. */
- /* */
- static FT_F26Dot6
- Round_To_Half_Grid( EXEC_OP_ FT_F26Dot6 distance,
- FT_F26Dot6 compensation )
- {
- FT_F26Dot6 val;
-
- FT_UNUSED_EXEC;
-
-
- if ( distance >= 0 )
- {
- val = FT_PIX_FLOOR( distance + compensation ) + 32;
- if ( distance && val < 0 )
- val = 0;
- }
- else
- {
- val = -( FT_PIX_FLOOR( compensation - distance ) + 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 :: The distance to round. */
- /* */
- /* compensation :: The engine compensation. */
- /* */
- /* <Return> */
- /* Rounded distance. */
- /* */
- static FT_F26Dot6
- Round_Down_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
- FT_F26Dot6 compensation )
- {
- FT_F26Dot6 val;
-
- FT_UNUSED_EXEC;
-
-
- if ( distance >= 0 )
- {
- val = distance + compensation;
- if ( distance && 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 :: The distance to round. */
- /* */
- /* compensation :: The engine compensation. */
- /* */
- /* <Return> */
- /* Rounded distance. */
- /* */
- static FT_F26Dot6
- Round_Up_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
- FT_F26Dot6 compensation )
- {
- FT_F26Dot6 val;
-
- FT_UNUSED_EXEC;
-
-
- if ( distance >= 0 )
- {
- val = distance + compensation + 63;
- if ( distance && val > 0 )
- val &= ~63;
- else
- val = 0;
- }
- else
- {
- val = - FT_PIX_CEIL( compensation - distance );
- if ( val > 0 )
- val = 0;
- }
-
- return val;
- }
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Round_To_Double_Grid */
- /* */
- /* <Description> */
- /* Rounds value to double grid after adding engine compensation. */
- /* */
- /* <Input> */
- /* distance :: The distance to round. */
- /* */
- /* compensation :: The engine compensation. */
- /* */
- /* <Return> */
- /* Rounded distance. */
- /* */
- static FT_F26Dot6
- Round_To_Double_Grid( EXEC_OP_ FT_F26Dot6 distance,
- FT_F26Dot6 compensation )
- {
- FT_F26Dot6 val;
-
- FT_UNUSED_EXEC;
-
-
- if ( distance >= 0 )
- {
- val = distance + compensation + 16;
- if ( distance && val > 0 )
- val &= ~31;
- else
- val = 0;
- }
- else
- {
- val = -FT_PAD_ROUND( compensation - distance, 32 );
- if ( val > 0 )
- val = 0;
- }
-
- return val;
- }
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Round_Super */
- /* */
- /* <Description> */
- /* Super-rounds value to grid after adding engine compensation. */
- /* */
- /* <Input> */
- /* distance :: The distance to round. */
- /* */
- /* compensation :: The engine compensation. */
- /* */
- /* <Return> */
- /* Rounded distance. */
- /* */
- /* <Note> */
- /* The TrueType specification says very few about the relationship */
- /* between rounding and engine compensation. However, it seems from */
- /* the description of super round that we should add the compensation */
- /* before rounding. */
- /* */
- static FT_F26Dot6
- Round_Super( EXEC_OP_ FT_F26Dot6 distance,
- FT_F26Dot6 compensation )
- {
- FT_F26Dot6 val;
-
-
- if ( distance >= 0 )
- {
- val = ( distance - CUR.phase + CUR.threshold + compensation ) &
- -CUR.period;
- if ( distance && 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 :: The distance to round. */
- /* */
- /* compensation :: The engine compensation. */
- /* */
- /* <Return> */
- /* Rounded distance. */
- /* */
- /* <Note> */
- /* There is a separate function for Round_Super_45() as we may need */
- /* greater precision. */
- /* */
- static FT_F26Dot6
- Round_Super_45( EXEC_OP_ FT_F26Dot6 distance,
- FT_F26Dot6 compensation )
- {
- FT_F26Dot6 val;
-
-
- if ( distance >= 0 )
- {
- val = ( ( distance - CUR.phase + CUR.threshold + compensation ) /
- CUR.period ) * CUR.period;
- if ( distance && 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;
- }
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Compute_Round */
- /* */
- /* <Description> */
- /* Sets the rounding mode. */
- /* */
- /* <Input> */
- /* round_mode :: The rounding mode to be used. */
- /* */
- static void
- Compute_Round( EXEC_OP_ FT_Byte round_mode )
- {
- switch ( round_mode )
- {
- case TT_Round_Off:
- CUR.func_round = (TT_Round_Func)Round_None;
- break;
-
- case TT_Round_To_Grid:
- CUR.func_round = (TT_Round_Func)Round_To_Grid;
- break;
-
- case TT_Round_Up_To_Grid:
- CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
- break;
-
- case TT_Round_Down_To_Grid:
- CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
- break;
-
- case TT_Round_To_Half_Grid:
- CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
- break;
-
- case TT_Round_To_Double_Grid:
- CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
- break;
-
- case TT_Round_Super:
- CUR.func_round = (TT_Round_Func)Round_Super;
- break;
-
- case TT_Round_Super_45:
- CUR.func_round = (TT_Round_Func)Round_Super_45;
- break;
- }
- }
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* SetSuperRound */
- /* */
- /* <Description> */
- /* Sets Super Round parameters. */
- /* */
- /* <Input> */
- /* GridPeriod :: Grid period */
- /* selector :: SROUND opcode */
- /* */
- static void
- SetSuperRound( EXEC_OP_ FT_F26Dot6 GridPeriod,
- FT_Long selector )
- {
- switch ( (FT_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 ( (FT_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 = CUR.period * 3 / 4;
- break;
- }
-
- if ( ( selector & 0x0F ) == 0 )
- CUR.threshold = CUR.period - 1;
- else
- CUR.threshold = ( (FT_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 :: First input vector. */
- /* v2 :: Second input vector. */
- /* */
- /* <Return> */
- /* The distance in F26dot6 format. */
- /* */
- static FT_F26Dot6
- Project( EXEC_OP_ FT_Pos dx,
- FT_Pos dy )
- {
-#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
- FT_ASSERT( !CUR.face->unpatented_hinting );
-#endif
-
- return TT_DotFix14( dx, dy,
- CUR.GS.projVector.x,
- CUR.GS.projVector.y );
- }
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Dual_Project */
- /* */
- /* <Description> */
- /* Computes the projection of the vector given by (v2-v1) along the */
- /* current dual vector. */
- /* */
- /* <Input> */
- /* v1 :: First input vector. */
- /* v2 :: Second input vector. */
- /* */
- /* <Return> */
- /* The distance in F26dot6 format. */
- /* */
- static FT_F26Dot6
- Dual_Project( EXEC_OP_ FT_Pos dx,
- FT_Pos dy )
- {
- return TT_DotFix14( dx, dy,
- CUR.GS.dualVector.x,
- CUR.GS.dualVector.y );
- }
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Project_x */
- /* */
- /* <Description> */
- /* Computes the projection of the vector given by (v2-v1) along the */
- /* horizontal axis. */
- /* */
- /* <Input> */
- /* v1 :: First input vector. */
- /* v2 :: Second input vector. */
- /* */
- /* <Return> */
- /* The distance in F26dot6 format. */
- /* */
- static FT_F26Dot6
- Project_x( EXEC_OP_ FT_Pos dx,
- FT_Pos dy )
- {
- FT_UNUSED_EXEC;
- FT_UNUSED( dy );
-
- return dx;
- }
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Project_y */
- /* */
- /* <Description> */
- /* Computes the projection of the vector given by (v2-v1) along the */
- /* vertical axis. */
- /* */
- /* <Input> */
- /* v1 :: First input vector. */
- /* v2 :: Second input vector. */
- /* */
- /* <Return> */
- /* The distance in F26dot6 format. */
- /* */
- static FT_F26Dot6
- Project_y( EXEC_OP_ FT_Pos dx,
- FT_Pos dy )
- {
- FT_UNUSED_EXEC;
- FT_UNUSED( dx );
-
- return dy;
- }
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Compute_Funcs */
- /* */
- /* <Description> */
- /* Computes the projection and movement function pointers according */
- /* to the current graphics state. */
- /* */
- static void
- Compute_Funcs( EXEC_OP )
- {
-#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
- if ( CUR.face->unpatented_hinting )
- {
- /* If both vectors point rightwards along the x axis, set */
- /* `both-x-axis' true, otherwise set it false. The x values only */
- /* need be tested because the vector has been normalised to a unit */
- /* vector of length 0x4000 = unity. */
- CUR.GS.both_x_axis = (FT_Bool)( CUR.GS.projVector.x == 0x4000 &&
- CUR.GS.freeVector.x == 0x4000 );
-
- /* Throw away projection and freedom vector information */
- /* because the patents don't allow them to be stored. */
- /* The relevant US Patents are 5155805 and 5325479. */
- CUR.GS.projVector.x = 0;
- CUR.GS.projVector.y = 0;
- CUR.GS.freeVector.x = 0;
- CUR.GS.freeVector.y = 0;
-
- if ( CUR.GS.both_x_axis )
- {
- CUR.func_project = Project_x;
- CUR.func_move = Direct_Move_X;
- CUR.func_move_orig = Direct_Move_Orig_X;
- }
- else
- {
- CUR.func_project = Project_y;
- CUR.func_move = Direct_Move_Y;
- CUR.func_move_orig = Direct_Move_Orig_Y;
- }
-
- if ( CUR.GS.dualVector.x == 0x4000 )
- CUR.func_dualproj = Project_x;
- else
- {
- if ( CUR.GS.dualVector.y == 0x4000 )
- CUR.func_dualproj = Project_y;
- else
- CUR.func_dualproj = Dual_Project;
- }
-
- /* Force recalculation of cached aspect ratio */
- CUR.tt_metrics.ratio = 0;
-
- return;
- }
-#endif /* TT_CONFIG_OPTION_UNPATENTED_HINTING */
-
- if ( CUR.GS.freeVector.x == 0x4000 )
- CUR.F_dot_P = CUR.GS.projVector.x * 0x10000L;
- else
- {
- if ( CUR.GS.freeVector.y == 0x4000 )
- CUR.F_dot_P = CUR.GS.projVector.y * 0x10000L;
- else
- CUR.F_dot_P = (FT_Long)CUR.GS.projVector.x * CUR.GS.freeVector.x * 4 +
- (FT_Long)CUR.GS.projVector.y * CUR.GS.freeVector.y * 4;
- }
-
- if ( CUR.GS.projVector.x == 0x4000 )
- CUR.func_project = (TT_Project_Func)Project_x;
- else
- {
- if ( CUR.GS.projVector.y == 0x4000 )
- CUR.func_project = (TT_Project_Func)Project_y;
- else
- CUR.func_project = (TT_Project_Func)Project;
- }
-
- if ( CUR.GS.dualVector.x == 0x4000 )
- CUR.func_dualproj = (TT_Project_Func)Project_x;
- else
- {
- if ( CUR.GS.dualVector.y == 0x4000 )
- CUR.func_dualproj = (TT_Project_Func)Project_y;
- else
- CUR.func_dualproj = (TT_Project_Func)Dual_Project;
- }
-
- CUR.func_move = (TT_Move_Func)Direct_Move;
- CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig;
-
- if ( CUR.F_dot_P == 0x40000000L )
- {
- if ( CUR.GS.freeVector.x == 0x4000 )
- {
- CUR.func_move = (TT_Move_Func)Direct_Move_X;
- CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig_X;
- }
- else
- {
- if ( CUR.GS.freeVector.y == 0x4000 )
- {
- CUR.func_move = (TT_Move_Func)Direct_Move_Y;
- CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig_Y;
- }
- }
- }
-
- /* at small sizes, F_dot_P can become too small, resulting */
- /* in overflows and `spikes' in a number of glyphs like `w'. */
-
- if ( FT_ABS( CUR.F_dot_P ) < 0x4000000L )
- CUR.F_dot_P = 0x40000000L;
-
- /* Disable cached aspect ratio */
- CUR.tt_metrics.ratio = 0;
- }
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* Normalize */
- /* */
- /* <Description> */
- /* Norms a vector. */
- /* */
- /* <Input> */
- /* Vx :: The horizontal input vector coordinate. */
- /* Vy :: The vertical input vector coordinate. */
- /* */
- /* <Output> */
- /* R :: The normed unit vector. */
- /* */
- /* <Return> */
- /* Returns FAILURE if a vector parameter is zero. */
- /* */
- /* <Note> */
- /* In case Vx and Vy are both zero, Normalize() returns SUCCESS, and */
- /* R is undefined. */
- /* */
-
-
- static FT_Bool
- Normalize( EXEC_OP_ FT_F26Dot6 Vx,
- FT_F26Dot6 Vy,
- FT_UnitVector* R )
- {
- FT_F26Dot6 W;
- FT_Bool S1, S2;
-
- FT_UNUSED_EXEC;
-
-
- if ( FT_ABS( Vx ) < 0x10000L && FT_ABS( Vy ) < 0x10000L )
- {
- Vx *= 0x100;
- Vy *= 0x100;
-
- W = TT_VecLen( Vx, Vy );
-
- if ( W == 0 )
- {
- /* XXX: UNDOCUMENTED! It seems that it is possible to try */
- /* to normalize the vector (0,0). Return immediately. */
- return SUCCESS;
- }
-
- R->x = (FT_F2Dot14)FT_MulDiv( Vx, 0x4000L, W );
- R->y = (FT_F2Dot14)FT_MulDiv( Vy, 0x4000L, W );
-
- return SUCCESS;
- }
-
- W = TT_VecLen( Vx, Vy );
-
- Vx = FT_MulDiv( Vx, 0x4000L, W );
- Vy = FT_MulDiv( Vy, 0x4000L, W );
-
- W = Vx * Vx + Vy * Vy;
-
- /* Now, we want that Sqrt( W ) = 0x4000 */
- /* Or 0x10000000 <= W < 0x10004000 */
-
- if ( Vx < 0 )
- {
- Vx = -Vx;
- S1 = TRUE;
- }
- else
- S1 = FALSE;
-
- if ( Vy < 0 )
- {
- Vy = -Vy;
- S2 = TRUE;
- }
- else
- S2 = FALSE;
-
- while ( W < 0x10000000L )
- {
- /* We need to increase W by a minimal amount */
- if ( Vx < Vy )
- Vx++;
- else
- Vy++;
-
- W = Vx * Vx + Vy * Vy;
- }
-
- while ( W >= 0x10004000L )
- {
- /* 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 = (FT_F2Dot14)Vx; /* Type conversion */
- R->y = (FT_F2Dot14)Vy; /* Type conversion */
-
- return SUCCESS;
- }
-
-
- /*************************************************************************/
- /* */
- /* Here we start with the implementation of the various opcodes. */
- /* */
- /*************************************************************************/
-
-
- static FT_Bool
- Ins_SxVTL( EXEC_OP_ FT_UShort aIdx1,
- FT_UShort aIdx2,
- FT_Int aOpc,
- FT_UnitVector* Vec )
- {
- FT_Long A, B, C;
- FT_Vector* p1;
- FT_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; /* counter clockwise 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 are all defined there. */
-
-#define DO_SVTCA \
- { \
- FT_Short A, B; \
- \
- \
- A = (FT_Short)( CUR.opcode & 1 ) << 14; \
- B = A ^ (FT_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 \
- { \
- FT_Short A, B; \
- \
- \
- A = (FT_Short)( CUR.opcode & 1 ) << 14; \
- B = A ^ (FT_Short)0x4000; \
- \
- CUR.GS.projVector.x = A; \
- CUR.GS.dualVector.x = A; \
- \
- CUR.GS.projVector.y = B; \
- CUR.GS.dualVector.y = B; \
- \
- GUESS_VECTOR( freeVector ); \
- \
- COMPUTE_Funcs(); \
- }
-
-
-#define DO_SFVTCA \
- { \
- FT_Short A, B; \
- \
- \
- A = (FT_Short)( CUR.opcode & 1 ) << 14; \
- B = A ^ (FT_Short)0x4000; \
- \
- CUR.GS.freeVector.x = A; \
- CUR.GS.freeVector.y = B; \
- \
- GUESS_VECTOR( projVector ); \
- \
- COMPUTE_Funcs(); \
- }
-
-
-#define DO_SPVTL \
- if ( INS_SxVTL( (FT_UShort)args[1], \
- (FT_UShort)args[0], \
- CUR.opcode, \
- &CUR.GS.projVector ) == SUCCESS ) \
- { \
- CUR.GS.dualVector = CUR.GS.projVector; \
- GUESS_VECTOR( freeVector ); \
- COMPUTE_Funcs(); \
- }
-
-
-#define DO_SFVTL \
- if ( INS_SxVTL( (FT_UShort)args[1], \
- (FT_UShort)args[0], \
- CUR.opcode, \
- &CUR.GS.freeVector ) == SUCCESS ) \
- { \
- GUESS_VECTOR( projVector ); \
- COMPUTE_Funcs(); \
- }
-
-
-#define DO_SFVTPV \
- GUESS_VECTOR( projVector ); \
- CUR.GS.freeVector = CUR.GS.projVector; \
- COMPUTE_Funcs();
-
-
-#define DO_SPVFS \
- { \
- FT_Short S; \
- FT_Long X, Y; \
- \
- \
- /* Only use low 16bits, then sign extend */ \
- S = (FT_Short)args[1]; \
- Y = (FT_Long)S; \
- S = (FT_Short)args[0]; \
- X = (FT_Long)S; \
- \
- NORMalize( X, Y, &CUR.GS.projVector ); \
- \
- CUR.GS.dualVector = CUR.GS.projVector; \
- GUESS_VECTOR( freeVector ); \
- COMPUTE_Funcs(); \
- }
-
-
-#define DO_SFVFS \
- { \
- FT_Short S; \
- FT_Long X, Y; \
- \
- \
- /* Only use low 16bits, then sign extend */ \
- S = (FT_Short)args[1]; \
- Y = (FT_Long)S; \
- S = (FT_Short)args[0]; \
- X = S; \
- \
- NORMalize( X, Y, &CUR.GS.freeVector ); \
- GUESS_VECTOR( projVector ); \
- COMPUTE_Funcs(); \
- }
-
-
-#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
-#define DO_GPV \
- if ( CUR.face->unpatented_hinting ) \
- { \
- args[0] = CUR.GS.both_x_axis ? 0x4000 : 0; \
- args[1] = CUR.GS.both_x_axis ? 0 : 0x4000; \
- } \
- else \
- { \
- args[0] = CUR.GS.projVector.x; \
- args[1] = CUR.GS.projVector.y; \
- }
-#else
-#define DO_GPV \
- args[0] = CUR.GS.projVector.x; \
- args[1] = CUR.GS.projVector.y;
-#endif
-
-
-#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
-#define DO_GFV \
- if ( CUR.face->unpatented_hinting ) \
- { \
- args[0] = CUR.GS.both_x_axis ? 0x4000 : 0; \
- args[1] = CUR.GS.both_x_axis ? 0 : 0x4000; \
- } \
- else \
- { \
- args[0] = CUR.GS.freeVector.x; \
- args[1] = CUR.GS.freeVector.y; \
- }
-#else
-#define DO_GFV \
- args[0] = CUR.GS.freeVector.x; \
- args[1] = CUR.GS.freeVector.y;
-#endif
-
-
-#define DO_SRP0 \
- CUR.GS.rp0 = (FT_UShort)args[0];
-
-
-#define DO_SRP1 \
- CUR.GS.rp1 = (FT_UShort)args[0];
-
-
-#define DO_SRP2 \
- CUR.GS.rp2 = (FT_UShort)args[0];
-
-
-#define DO_RTHG \
- CUR.GS.round_state = TT_Round_To_Half_Grid; \
- CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
-
-
-#define DO_RTG \
- CUR.GS.round_state = TT_Round_To_Grid; \
- CUR.func_round = (TT_Round_Func)Round_To_Grid;
-
-
-#define DO_RTDG \
- CUR.GS.round_state = TT_Round_To_Double_Grid; \
- CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
-
-
-#define DO_RUTG \
- CUR.GS.round_state = TT_Round_Up_To_Grid; \
- CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
-
-
-#define DO_RDTG \
- CUR.GS.round_state = TT_Round_Down_To_Grid; \
- CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
-
-
-#define DO_ROFF \
- CUR.GS.round_state = TT_Round_Off; \
- CUR.func_round = (TT_Round_Func)Round_None;
-
-
-#define DO_SROUND \
- SET_SuperRound( 0x4000, args[0] ); \
- CUR.GS.round_state = TT_Round_Super; \
- CUR.func_round = (TT_Round_Func)Round_Super;
-
-
-#define DO_S45ROUND \
- SET_SuperRound( 0x2D41, args[0] ); \
- CUR.GS.round_state = TT_Round_Super_45; \
- CUR.func_round = (TT_Round_Func)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 = args[0];
-
-
-#define DO_SCVTCI \
- CUR.GS.control_value_cutin = (FT_F26Dot6)args[0];
-
-
-#define DO_SSWCI \
- CUR.GS.single_width_cutin = (FT_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 = (FT_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 = (FT_Short)args[0];
-
-
-#define DO_SDS \
- CUR.GS.delta_shift = (FT_Short)args[0];
-
-
-#define DO_MD /* nothing */
-
-
-#define DO_MPPEM \
- args[0] = CURRENT_Ppem();
-
-
- /* Note: The pointSize should be irrelevant in a given font program; */
- /* we thus decide to return only the ppem. */
-#if 0
-
-#define DO_MPS \
- args[0] = CUR.metrics.pointSize;
-
-#else
-
-#define DO_MPS \
- args[0] = CURRENT_Ppem();
-
-#endif /* 0 */
-
-
-#define DO_DUP \
- args[1] = args[0];
-
-
-#define DO_CLEAR \
- CUR.new_top = 0;
-
-
-#define DO_SWAP \
- { \
- FT_Long L; \
- \
- \
- L = args[0]; \
- args[0] = args[1]; \
- args[1] = L; \
- }
-
-
-#define DO_DEPTH \
- args[0] = CUR.top;
-
-
-#define DO_CINDEX \
- { \
- FT_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_NO_ROUND( args[0], 64L, args[1] );
-
-
-#define DO_MUL \
- args[0] = TT_MULDIV( args[0], args[1], 64L );
-
-
-#define DO_ABS \
- args[0] = FT_ABS( args[0] );
-
-
-#define DO_NEG \
- args[0] = -args[0];
-
-
-#define DO_FLOOR \
- args[0] = FT_PIX_FLOOR( args[0] );
-
-
-#define DO_CEILING \
- args[0] = FT_PIX_CEIL( args[0] );
-
-
-#define DO_RS \
- { \
- FT_ULong I = (FT_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 \
- { \
- FT_ULong I = (FT_ULong)args[0]; \
- \
- \
- if ( BOUNDS( I, CUR.storeSize ) ) \
- { \
- if ( CUR.pedantic_hinting ) \
- { \
- ARRAY_BOUND_ERROR; \
- } \
- } \
- else \
- CUR.storage[I] = args[1]; \
- }
-
-
-#define DO_RCVT \
- { \
- FT_ULong I = (FT_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 \
- { \
- FT_ULong I = (FT_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 \
- { \
- FT_ULong I = (FT_ULong)args[0]; \
- \
- \
- if ( BOUNDS( I, CUR.cvtSize ) ) \
- { \
- if ( CUR.pedantic_hinting ) \
- { \
- ARRAY_BOUND_ERROR; \
- } \
- } \
- else \
- CUR.cvt[I] = TT_MULFIX( args[1], CUR.tt_metrics.scale ); \
- }
-
-
-#define DO_DEBUG \
- CUR.error = TT_Err_Debug_OpCode;
-
-
-#define DO_ROUND \
- args[0] = CUR_Func_round( \
- args[0], \
- CUR.tt_metrics.compensations[CUR.opcode - 0x68] );
-
-
-#define DO_NROUND \
- args[0] = ROUND_None( args[0], \
- CUR.tt_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 Coordinate Axis */
- /* Opcode range: 0x00-0x01 */
- /* Stack: --> */
- /* */
- static void
- Ins_SVTCA( INS_ARG )
- {
- DO_SVTCA
- }
-
-
- /*************************************************************************/
- /* */
- /* SPVTCA[a]: Set PVector to Coordinate Axis */
- /* Opcode range: 0x02-0x03 */
- /* Stack: --> */
- /* */
- static void
- Ins_SPVTCA( INS_ARG )
- {
- DO_SPVTCA
- }
-
-
- /*************************************************************************/
- /* */
- /* SFVTCA[a]: Set FVector to Coordinate Axis */
- /* Opcode range: 0x04-0x05 */
- /* Stack: --> */
- /* */
- static void
- Ins_SFVTCA( INS_ARG )
- {
- DO_SFVTCA
- }
-
-
- /*************************************************************************/
- /* */
- /* SPVTL[a]: Set PVector To Line */
- /* Opcode range: 0x06-0x07 */
- /* Stack: uint32 uint32 --> */
- /* */
- static void
- Ins_SPVTL( INS_ARG )
- {
- DO_SPVTL
- }
-
-
- /*************************************************************************/
- /* */
- /* SFVTL[a]: Set FVector To Line */
- /* Opcode range: 0x08-0x09 */
- /* Stack: uint32 uint32 --> */
- /* */
- static void
- Ins_SFVTL( INS_ARG )
- {
- DO_SFVTL
- }
-
-
- /*************************************************************************/
- /* */
- /* SFVTPV[]: Set FVector To PVector */
- /* Opcode range: 0x0E */
- /* Stack: --> */
- /* */
- static void
- Ins_SFVTPV( INS_ARG )
- {
- DO_SFVTPV
- }
-
-
- /*************************************************************************/
- /* */
- /* SPVFS[]: Set PVector From Stack */
- /* Opcode range: 0x0A */
- /* Stack: f2.14 f2.14 --> */
- /* */
- static void
- Ins_SPVFS( INS_ARG )
- {
- DO_SPVFS
- }
-
-
- /*************************************************************************/
- /* */
- /* SFVFS[]: Set FVector From Stack */
- /* Opcode range: 0x0B */
- /* Stack: f2.14 f2.14 --> */
- /* */
- static void
- Ins_SFVFS( INS_ARG )
- {
- DO_SFVFS
- }
-
-
- /*************************************************************************/
- /* */
- /* GPV[]: Get Projection Vector */
- /* Opcode range: 0x0C */
- /* Stack: ef2.14 --> ef2.14 */
- /* */
- static void
- Ins_GPV( INS_ARG )
- {
- DO_GPV
- }
-
-
- /*************************************************************************/
- /* GFV[]: Get Freedom Vector */
- /* Opcode range: 0x0D */
- /* Stack: ef2.14 --> ef2.14 */
- /* */
- static void
- Ins_GFV( INS_ARG )
- {
- DO_GFV
- }
-
-
- /*************************************************************************/
- /* */
- /* SRP0[]: Set Reference Point 0 */
- /* Opcode range: 0x10 */
- /* Stack: uint32 --> */
- /* */
- static void
- Ins_SRP0( INS_ARG )
- {
- DO_SRP0
- }
-
-
- /*************************************************************************/
- /* */
- /* SRP1[]: Set Reference Point 1 */
- /* Opcode range: 0x11 */
- /* Stack: uint32 --> */
- /* */
- static void
- Ins_SRP1( INS_ARG )
- {
- DO_SRP1
- }
-
-
- /*************************************************************************/
- /* */
- /* SRP2[]: Set Reference Point 2 */
- /* Opcode range: 0x12 */
- /* Stack: uint32 --> */
- /* */
- static void
- Ins_SRP2( INS_ARG )
- {
- DO_SRP2
- }
-
-
- /*************************************************************************/
- /* */
- /* RTHG[]: Round To Half Grid */
- /* Opcode range: 0x19 */
- /* Stack: --> */
- /* */
- static void
- Ins_RTHG( INS_ARG )
- {
- DO_RTHG
- }
-
-
- /*************************************************************************/
- /* */
- /* RTG[]: Round To Grid */
- /* Opcode range: 0x18 */
- /* Stack: --> */
- /* */
- static void
- Ins_RTG( INS_ARG )
- {
- DO_RTG
- }
-
-
- /*************************************************************************/
- /* RTDG[]: Round To Double Grid */
- /* Opcode range: 0x3D */
- /* Stack: --> */
- /* */
- static void
- Ins_RTDG( INS_ARG )
- {
- DO_RTDG
- }
-
-
- /*************************************************************************/
- /* RUTG[]: Round Up To Grid */
- /* Opcode range: 0x7C */
- /* Stack: --> */
- /* */
- static void
- Ins_RUTG( INS_ARG )
- {
- DO_RUTG
- }
-
-
- /*************************************************************************/
- /* */
- /* RDTG[]: Round Down To Grid */
- /* Opcode range: 0x7D */
- /* Stack: --> */
- /* */
- static void
- Ins_RDTG( INS_ARG )
- {
- DO_RDTG
- }
-
-
- /*************************************************************************/
- /* */
- /* ROFF[]: Round OFF */
- /* Opcode range: 0x7A */
- /* Stack: --> */
- /* */
- static void
- Ins_ROFF( INS_ARG )
- {
- DO_ROFF
- }
-
-
- /*************************************************************************/
- /* */
- /* SROUND[]: Super ROUND */
- /* Opcode range: 0x76 */
- /* Stack: Eint8 --> */
- /* */
- static void
- Ins_SROUND( INS_ARG )
- {
- DO_SROUND
- }
-
-
- /*************************************************************************/
- /* */
- /* S45ROUND[]: Super ROUND 45 degrees */
- /* Opcode range: 0x77 */
- /* Stack: uint32 --> */
- /* */
- static void
- Ins_S45ROUND( INS_ARG )
- {
- DO_S45ROUND
- }
-
-
- /*************************************************************************/
- /* */
- /* SLOOP[]: Set LOOP variable */
- /* Opcode range: 0x17 */
- /* Stack: int32? --> */
- /* */
- static void
- Ins_SLOOP( INS_ARG )
- {
- DO_SLOOP
- }
-
-
- /*************************************************************************/
- /* */
- /* SMD[]: Set Minimum Distance */
- /* Opcode range: 0x1A */
- /* Stack: f26.6 --> */
- /* */
- static void
- Ins_SMD( INS_ARG )
- {
- DO_SMD
- }
-
-
- /*************************************************************************/
- /* */
- /* SCVTCI[]: Set Control Value Table Cut In */
- /* Opcode range: 0x1D */
- /* Stack: f26.6 --> */
- /* */
- static void
- Ins_SCVTCI( INS_ARG )
- {
- DO_SCVTCI
- }
-
-
- /*************************************************************************/
- /* */
- /* SSWCI[]: Set Single Width Cut In */
- /* Opcode range: 0x1E */
- /* Stack: f26.6 --> */
- /* */
- static void
- Ins_SSWCI( INS_ARG )
- {
- DO_SSWCI
- }
-
-
- /*************************************************************************/
- /* */
- /* SSW[]: Set Single Width */
- /* Opcode range: 0x1F */
- /* Stack: int32? --> */
- /* */
- static void
- Ins_SSW( INS_ARG )
- {
- DO_SSW
- }
-
-
- /*************************************************************************/
- /* */
- /* FLIPON[]: Set auto-FLIP to ON */
- /* Opcode range: 0x4D */
- /* Stack: --> */
- /* */
- static void
- Ins_FLIPON( INS_ARG )
- {
- DO_FLIPON
- }
-
-
- /*************************************************************************/
- /* */
- /* FLIPOFF[]: Set auto-FLIP to OFF */
- /* Opcode range: 0x4E */
- /* Stack: --> */
- /* */
- static void
- Ins_FLIPOFF( INS_ARG )
- {
- DO_FLIPOFF
- }
-
-
- /*************************************************************************/
- /* */
- /* SANGW[]: Set ANGle Weight */
- /* Opcode range: 0x7E */
- /* Stack: uint32 --> */
- /* */
- static void
- Ins_SANGW( INS_ARG )
- {
- /* instruction not supported anymore */
- }
-
-
- /*************************************************************************/
- /* */
- /* SDB[]: Set Delta Base */
- /* Opcode range: 0x5E */
- /* Stack: uint32 --> */
- /* */
- static void
- Ins_SDB( INS_ARG )
- {
- DO_SDB
- }
-
-
- /*************************************************************************/
- /* */
- /* SDS[]: Set Delta Shift */
- /* Opcode range: 0x5F */
- /* Stack: uint32 --> */
- /* */
- static void
- Ins_SDS( INS_ARG )
- {
- DO_SDS
- }
-
-
- /*************************************************************************/
- /* */
- /* MPPEM[]: Measure Pixel Per EM */
- /* Opcode range: 0x4B */
- /* Stack: --> Euint16 */
- /* */
- static void
- Ins_MPPEM( INS_ARG )
- {
- DO_MPPEM
- }
-
-
- /*************************************************************************/
- /* */
- /* MPS[]: Measure Point Size */
- /* Opcode range: 0x4C */
- /* Stack: --> Euint16 */
- /* */
- static void
- Ins_MPS( INS_ARG )
- {
- DO_MPS
- }
-
-
- /*************************************************************************/
- /* */
- /* DUP[]: DUPlicate the top stack's element */
- /* Opcode range: 0x20 */
- /* Stack: StkElt --> StkElt StkElt */
- /* */
- static void
- Ins_DUP( INS_ARG )
- {
- DO_DUP
- }
-
-
- /*************************************************************************/
- /* */
- /* POP[]: POP the stack's top element */
- /* Opcode range: 0x21 */
- /* Stack: StkElt --> */
- /* */
- static void
- Ins_POP( INS_ARG )
- {
- /* nothing to do */
- }
-
-
- /*************************************************************************/
- /* */
- /* CLEAR[]: CLEAR the entire stack */
- /* Opcode range: 0x22 */
- /* Stack: StkElt... --> */
- /* */
- static void
- Ins_CLEAR( INS_ARG )
- {
- DO_CLEAR
- }
-
-
- /*************************************************************************/
- /* */
- /* SWAP[]: SWAP the stack's top two elements */
- /* Opcode range: 0x23 */
- /* Stack: 2 * StkElt --> 2 * StkElt */
- /* */
- static void
- Ins_SWAP( INS_ARG )
- {
- DO_SWAP
- }
-
-
- /*************************************************************************/
- /* */
- /* DEPTH[]: return the stack DEPTH */
- /* Opcode range: 0x24 */
- /* Stack: --> uint32 */
- /* */
- static void
- Ins_DEPTH( INS_ARG )
- {
- DO_DEPTH
- }
-
-
- /*************************************************************************/
- /* */
- /* CINDEX[]: Copy INDEXed element */
- /* Opcode range: 0x25 */
- /* Stack: int32 --> StkElt */
- /* */
- static void
- Ins_CINDEX( INS_ARG )
- {
- DO_CINDEX
- }
-
-
- /*************************************************************************/
- /* */
- /* EIF[]: End IF */
- /* Opcode range: 0x59 */
- /* Stack: --> */
- /* */
- static void
- Ins_EIF( INS_ARG )
- {
- /* nothing to do */
- }
-
-
- /*************************************************************************/
- /* */
- /* JROT[]: Jump Relative On True */
- /* Opcode range: 0x78 */
- /* Stack: StkElt int32 --> */
- /* */
- static void
- Ins_JROT( INS_ARG )
- {
- DO_JROT
- }
-
-
- /*************************************************************************/
- /* */
- /* JMPR[]: JuMP Relative */
- /* Opcode range: 0x1C */
- /* Stack: int32 --> */
- /* */
- static void
- Ins_JMPR( INS_ARG )
- {
- DO_JMPR
- }
-
-
- /*************************************************************************/
- /* */
- /* JROF[]: Jump Relative On False */
- /* Opcode range: 0x79 */
- /* Stack: StkElt int32 --> */
- /* */
- static void
- Ins_JROF( INS_ARG )
- {
- DO_JROF
- }
-
-
- /*************************************************************************/
- /* */
- /* LT[]: Less Than */
- /* Opcode range: 0x50 */
- /* Stack: int32? int32? --> bool */
- /* */
- static void
- Ins_LT( INS_ARG )
- {
- DO_LT
- }
-
-
- /*************************************************************************/
- /* */
- /* LTEQ[]: Less Than or EQual */
- /* Opcode range: 0x51 */
- /* Stack: int32? int32? --> bool */
- /* */
- static void
- Ins_LTEQ( INS_ARG )
- {
- DO_LTEQ
- }
-
-
- /*************************************************************************/
- /* */
- /* GT[]: Greater Than */
- /* Opcode range: 0x52 */
- /* Stack: int32? int32? --> bool */
- /* */
- static void
- Ins_GT( INS_ARG )
- {
- DO_GT
- }
-
-
- /*************************************************************************/
- /* */
- /* GTEQ[]: Greater Than or EQual */
- /* Opcode range: 0x53 */
- /* Stack: int32? int32? --> bool */
- /* */
- static void
- Ins_GTEQ( INS_ARG )
- {
- DO_GTEQ
- }
-
-
- /*************************************************************************/
- /* */
- /* EQ[]: EQual */
- /* Opcode range: 0x54 */
- /* Stack: StkElt StkElt --> bool */
- /* */
- static void
- Ins_EQ( INS_ARG )
- {
- DO_EQ
- }
-
-
- /*************************************************************************/
- /* */
- /* NEQ[]: Not EQual */
- /* Opcode range: 0x55 */
- /* Stack: StkElt StkElt --> bool */
- /* */
- static void
- Ins_NEQ( INS_ARG )
- {
- DO_NEQ
- }
-
-
- /*************************************************************************/
- /* */
- /* ODD[]: Is ODD */
- /* Opcode range: 0x56 */
- /* Stack: f26.6 --> bool */
- /* */
- static void
- Ins_ODD( INS_ARG )
- {
- DO_ODD
- }
-
-
- /*************************************************************************/
- /* */
- /* EVEN[]: Is EVEN */
- /* Opcode range: 0x57 */
- /* Stack: f26.6 --> bool */
- /* */
- static void
- Ins_EVEN( INS_ARG )
- {
- DO_EVEN
- }
-
-
- /*************************************************************************/
- /* */
- /* AND[]: logical AND */
- /* Opcode range: 0x5A */
- /* Stack: uint32 uint32 --> uint32 */
- /* */
- static void
- Ins_AND( INS_ARG )
- {
- DO_AND
- }
-
-
- /*************************************************************************/
- /* */
- /* OR[]: logical OR */
- /* Opcode range: 0x5B */
- /* Stack: uint32 uint32 --> uint32 */
- /* */
- static void
- Ins_OR( INS_ARG )
- {
- DO_OR
- }
-
-
- /*************************************************************************/
- /* */
- /* NOT[]: logical NOT */
- /* Opcode range: 0x5C */
- /* Stack: StkElt --> uint32 */
- /* */
- static void
- Ins_NOT( INS_ARG )
- {
- DO_NOT
- }
-
-
- /*************************************************************************/
- /* */
- /* ADD[]: ADD */
- /* Opcode range: 0x60 */
- /* Stack: f26.6 f26.6 --> f26.6 */
- /* */
- static void
- Ins_ADD( INS_ARG )
- {
- DO_ADD
- }
-
-
- /*************************************************************************/
- /* */
- /* SUB[]: SUBtract */
- /* Opcode range: 0x61 */
- /* Stack: f26.6 f26.6 --> f26.6 */
- /* */
- static void
- Ins_SUB( INS_ARG )
- {
- DO_SUB
- }
-
-
- /*************************************************************************/
- /* */
- /* DIV[]: DIVide */
- /* Opcode range: 0x62 */
- /* Stack: f26.6 f26.6 --> f26.6 */
- /* */
- static void
- Ins_DIV( INS_ARG )
- {
- DO_DIV
- }
-
-
- /*************************************************************************/
- /* */
- /* MUL[]: MULtiply */
- /* Opcode range: 0x63 */
- /* Stack: f26.6 f26.6 --> f26.6 */
- /* */
- static void
- Ins_MUL( INS_ARG )
- {
- DO_MUL
- }
-
-
- /*************************************************************************/
- /* */
- /* ABS[]: ABSolute value */
- /* Opcode range: 0x64 */
- /* Stack: f26.6 --> f26.6 */
- /* */
- static void
- Ins_ABS( INS_ARG )
- {
- DO_ABS
- }
-
-
- /*************************************************************************/
- /* */
- /* NEG[]: NEGate */
- /* Opcode range: 0x65 */
- /* Stack: f26.6 --> f26.6 */
- /* */
- static void
- Ins_NEG( INS_ARG )
- {
- DO_NEG
- }
-
-
- /*************************************************************************/
- /* */
- /* FLOOR[]: FLOOR */
- /* Opcode range: 0x66 */
- /* Stack: f26.6 --> f26.6 */
- /* */
- static void
- Ins_FLOOR( INS_ARG )
- {
- DO_FLOOR
- }
-
-
- /*************************************************************************/
- /* */
- /* CEILING[]: CEILING */
- /* Opcode range: 0x67 */
- /* Stack: f26.6 --> f26.6 */
- /* */
- static void
- Ins_CEILING( INS_ARG )
- {
- DO_CEILING
- }
-
-
- /*************************************************************************/
- /* */
- /* RS[]: Read Store */
- /* Opcode range: 0x43 */
- /* Stack: uint32 --> uint32 */
- /* */
- static void
- Ins_RS( INS_ARG )
- {
- DO_RS
- }
-
-
- /*************************************************************************/
- /* */
- /* WS[]: Write Store */
- /* Opcode range: 0x42 */
- /* Stack: uint32 uint32 --> */
- /* */
- static void
- Ins_WS( INS_ARG )
- {
- DO_WS
- }
-
-
- /*************************************************************************/
- /* */
- /* WCVTP[]: Write CVT in Pixel units */
- /* Opcode range: 0x44 */
- /* Stack: f26.6 uint32 --> */
- /* */
- static void
- Ins_WCVTP( INS_ARG )
- {
- DO_WCVTP
- }
-
-
- /*************************************************************************/
- /* */
- /* WCVTF[]: Write CVT in Funits */
- /* Opcode range: 0x70 */
- /* Stack: uint32 uint32 --> */
- /* */
- static void
- Ins_WCVTF( INS_ARG )
- {
- DO_WCVTF
- }
-
-
- /*************************************************************************/
- /* */
- /* RCVT[]: Read CVT */
- /* Opcode range: 0x45 */
- /* Stack: uint32 --> f26.6 */
- /* */
- static void
- Ins_RCVT( INS_ARG )
- {
- DO_RCVT
- }
-
-
- /*************************************************************************/
- /* */
- /* AA[]: Adjust Angle */
- /* Opcode range: 0x7F */
- /* Stack: uint32 --> */
- /* */
- static void
- Ins_AA( INS_ARG )
- {
- /* intentionally no longer supported */
- }
-
-
- /*************************************************************************/
- /* */
- /* DEBUG[]: DEBUG. Unsupported. */
- /* Opcode range: 0x4F */
- /* Stack: uint32 --> */
- /* */
- /* Note: The original instruction pops a value from the stack. */
- /* */
- static void
- Ins_DEBUG( INS_ARG )
- {
- DO_DEBUG
- }
-
-
- /*************************************************************************/
- /* */
- /* ROUND[ab]: ROUND value */
- /* Opcode range: 0x68-0x6B */
- /* Stack: f26.6 --> f26.6 */
- /* */
- static void
- Ins_ROUND( INS_ARG )
- {
- DO_ROUND
- }
-
-
- /*************************************************************************/
- /* */
- /* NROUND[ab]: No ROUNDing of value */
- /* Opcode range: 0x6C-0x6F */
- /* Stack: f26.6 --> f26.6 */
- /* */
- static void
- Ins_NROUND( INS_ARG )
- {
- DO_NROUND
- }
-
-
- /*************************************************************************/
- /* */
- /* MAX[]: MAXimum */
- /* Opcode range: 0x68 */
- /* Stack: int32? int32? --> int32 */
- /* */
- static void
- Ins_MAX( INS_ARG )
- {
- DO_MAX
- }
-
-
- /*************************************************************************/
- /* */
- /* MIN[]: MINimum */
- /* Opcode range: 0x69 */
- /* 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 */
- /* Opcode range: 0x26 */
- /* Stack: int32? --> StkElt */
- /* */
- static void
- Ins_MINDEX( INS_ARG )
- {
- FT_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];
-
- FT_ARRAY_MOVE( &CUR.stack[CUR.args - L ],
- &CUR.stack[CUR.args - L + 1],
- ( L - 1 ) );
-
- CUR.stack[CUR.args - 1] = K;
- }
-
-
- /*************************************************************************/
- /* */
- /* ROLL[]: ROLL top three elements */
- /* Opcode range: 0x8A */
- /* Stack: 3 * StkElt --> 3 * StkElt */
- /* */
- static void
- Ins_ROLL( INS_ARG )
- {
- FT_Long A, B, C;
-
- FT_UNUSED_EXEC;
-
-
- 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 specification's order. */
- /* */
- /*************************************************************************/
-
-
- static FT_Bool
- SkipCode( EXEC_OP )
- {
- CUR.IP += CUR.length;
-
- if ( CUR.IP < CUR.codeSize )
- {
- CUR.opcode = CUR.code[CUR.IP];
-
- CUR.length = opcode_length[CUR.opcode];
- if ( CUR.length < 0 )
- {
- if ( CUR.IP + 1 > CUR.codeSize )
- goto Fail_Overflow;
- CUR.length = 2 - CUR.length * CUR.code[CUR.IP + 1];
- }
-
- if ( CUR.IP + CUR.length <= CUR.codeSize )
- return SUCCESS;
- }
-
- Fail_Overflow:
- CUR.error = TT_Err_Code_Overflow;
- return FAILURE;
- }
-
-
- /*************************************************************************/
- /* */
- /* IF[]: IF test */
- /* Opcode range: 0x58 */
- /* Stack: StkElt --> */
- /* */
- static void
- Ins_IF( INS_ARG )
- {
- FT_Int nIfs;
- FT_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 = FT_BOOL( nIfs == 1 );
- break;
-
- case 0x59: /* EIF */
- nIfs--;
- Out = FT_BOOL( nIfs == 0 );
- break;
- }
- } while ( Out == 0 );
- }
-
-
- /*************************************************************************/
- /* */
- /* ELSE[]: ELSE */
- /* Opcode range: 0x1B */
- /* Stack: --> */
- /* */
- static void
- Ins_ELSE( INS_ARG )
- {
- FT_Int nIfs;
-
- FT_UNUSED_ARG;
-
-
- 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 specification's order. */
- /* */
- /*************************************************************************/
-
-
- /*************************************************************************/
- /* */
- /* FDEF[]: Function DEFinition */
- /* Opcode range: 0x2C */
- /* Stack: uint32 --> */
- /* */
- static void
- Ins_FDEF( INS_ARG )
- {
- FT_ULong n;
- TT_DefRecord* rec;
- TT_DefRecord* limit;
-
-
- /* some font programs are broken enough to redefine functions! */
- /* We will then parse the current table. */
-
- rec = CUR.FDefs;
- limit = rec + CUR.numFDefs;
- n = args[0];
-
- for ( ; rec < limit; rec++ )
- {
- if ( rec->opc == n )
- break;
- }
-
- if ( rec == limit )
- {
- /* check that there is enough room for new functions */
- if ( CUR.numFDefs >= CUR.maxFDefs )
- {
- CUR.error = TT_Err_Too_Many_Function_Defs;
- return;
- }
- CUR.numFDefs++;
- }
-
- rec->range = CUR.curRange;
- rec->opc = n;
- rec->start = CUR.IP + 1;
- rec->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 */
- /* Opcode range: 0x2D */
- /* Stack: --> */
- /* */
- static void
- Ins_ENDF( INS_ARG )
- {
- TT_CallRec* pRec;
-
- FT_UNUSED_ARG;
-
-
- 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: If the last instruction of a program is a */
- /* CALL or LOOPCALL, the return address is */
- /* always out of the code range. This is a */
- /* valid address, and it is why we do not test */
- /* the result of Ins_Goto_CodeRange() here! */
- }
-
-
- /*************************************************************************/
- /* */
- /* CALL[]: CALL function */
- /* Opcode range: 0x2B */
- /* Stack: uint32? --> */
- /* */
- static void
- Ins_CALL( INS_ARG )
- {
- FT_ULong F;
- TT_CallRec* pCrec;
- TT_DefRecord* def;
-
-
- /* first of all, check the index */
-
- F = args[0];
- if ( BOUNDS( F, CUR.maxFunc + 1 ) )
- goto Fail;
-
- /* Except for some old Apple fonts, all functions in a TrueType */
- /* font are defined in increasing order, starting from 0. This */
- /* means that we normally have */
- /* */
- /* CUR.maxFunc+1 == CUR.numFDefs */
- /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */
- /* */
- /* If this isn't true, we need to look up the function table. */
-
- def = CUR.FDefs + F;
- if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F )
- {
- /* look up the FDefs table */
- TT_DefRecord* limit;
-
-
- def = CUR.FDefs;
- limit = def + CUR.numFDefs;
-
- while ( def < limit && def->opc != F )
- def++;
-
- if ( def == limit )
- goto Fail;
- }
-
- /* check that the function is active */
- if ( !def->active )
- goto Fail;
-
- /* check the 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;
-
- Fail:
- CUR.error = TT_Err_Invalid_Reference;
- }
-
-
- /*************************************************************************/
- /* */
- /* LOOPCALL[]: LOOP and CALL function */
- /* Opcode range: 0x2A */
- /* Stack: uint32? Eint16? --> */
- /* */
- static void
- Ins_LOOPCALL( INS_ARG )
- {
- FT_ULong F;
- TT_CallRec* pCrec;
- TT_DefRecord* def;
-
-
- /* first of all, check the index */
- F = args[1];
- if ( BOUNDS( F, CUR.maxFunc + 1 ) )
- goto Fail;
-
- /* Except for some old Apple fonts, all functions in a TrueType */
- /* font are defined in increasing order, starting from 0. This */
- /* means that we normally have */
- /* */
- /* CUR.maxFunc+1 == CUR.numFDefs */
- /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */
- /* */
- /* If this isn't true, we need to look up the function table. */
-
- def = CUR.FDefs + F;
- if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F )
- {
- /* look up the FDefs table */
- TT_DefRecord* limit;
-
-
- def = CUR.FDefs;
- limit = def + CUR.numFDefs;
-
- while ( def < limit && def->opc != F )
- def++;
-
- if ( def == limit )
- goto Fail;
- }
-
- /* check that the function is active */
- if ( !def->active )
- goto Fail;
-
- /* check stack */
- if ( CUR.callTop >= CUR.callSize )
- {
- CUR.error = TT_Err_Stack_Overflow;
- return;
- }
-
- if ( args[0] > 0 )
- {
- pCrec = CUR.callStack + CUR.callTop;
-
- pCrec->Caller_Range = CUR.curRange;
- pCrec->Caller_IP = CUR.IP + 1;
- pCrec->Cur_Count = (FT_Int)args[0];
- pCrec->Cur_Restart = def->start;
-
- CUR.callTop++;
-
- INS_Goto_CodeRange( def->range, def->start );
-
- CUR.step_ins = FALSE;
- }
- return;
-
- Fail:
- CUR.error = TT_Err_Invalid_Reference;
- }
-
-
- /*************************************************************************/
- /* */
- /* IDEF[]: Instruction DEFinition */
- /* Opcode range: 0x89 */
- /* Stack: Eint8 --> */
- /* */
- static void
- Ins_IDEF( INS_ARG )
- {
- TT_DefRecord* def;
- TT_DefRecord* limit;
-
-
- /* First of all, look for the same function in our table */
-
- def = CUR.IDefs;
- limit = def + CUR.numIDefs;
-
- for ( ; def < limit; def++ )
- if ( def->opc == (FT_ULong)args[0] )
- break;
-
- if ( def == limit )
- {
- /* check that there is enough room for a new instruction */
- if ( CUR.numIDefs >= CUR.maxIDefs )
- {
- CUR.error = TT_Err_Too_Many_Instruction_Defs;
- return;
- }
- CUR.numIDefs++;
- }
-
- def->opc = args[0];
- def->start = CUR.IP+1;
- def->range = CUR.curRange;
- def->active = TRUE;
-
- if ( (FT_ULong)args[0] > CUR.maxIns )
- CUR.maxIns = args[0];
-
- /* 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 specification's order. */
- /* */
- /*************************************************************************/
-
-
- /*************************************************************************/
- /* */
- /* NPUSHB[]: PUSH N Bytes */
- /* Opcode range: 0x40 */
- /* Stack: --> uint32... */
- /* */
- static void
- Ins_NPUSHB( INS_ARG )
- {
- FT_UShort L, K;
-
-
- L = (FT_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 */
- /* Opcode range: 0x41 */
- /* Stack: --> int32... */
- /* */
- static void
- Ins_NPUSHW( INS_ARG )
- {
- FT_UShort L, K;
-
-
- L = (FT_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 */
- /* Opcode range: 0xB0-0xB7 */
- /* Stack: --> uint32... */
- /* */
- static void
- Ins_PUSHB( INS_ARG )
- {
- FT_UShort L, K;
-
-
- L = (FT_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 */
- /* Opcode range: 0xB8-0xBF */
- /* Stack: --> int32... */
- /* */
- static void
- Ins_PUSHW( INS_ARG )
- {
- FT_UShort L, K;
-
-
- L = (FT_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 */
- /* Opcode range: 0x46-0x47 */
- /* Stack: uint32 --> f26.6 */
- /* */
- /* BULLSHIT: Measures from the original glyph must be taken along the */
- /* dual projection vector! */
- /* */
- static void
- Ins_GC( INS_ARG )
- {
- FT_ULong L;
- FT_F26Dot6 R;
-
-
- L = (FT_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_fast_dualproj( &CUR.zp2.org[L] );
- else
- R = CUR_fast_project( &CUR.zp2.cur[L] );
- }
-
- args[0] = R;
- }
-
-
- /*************************************************************************/
- /* */
- /* SCFS[]: Set Coordinate From Stack */
- /* Opcode range: 0x48 */
- /* Stack: f26.6 uint32 --> */
- /* */
- /* Formula: */
- /* */
- /* OA := OA + ( value - OA.p )/( f.p ) * f */
- /* */
- static void
- Ins_SCFS( INS_ARG )
- {
- FT_Long K;
- FT_UShort L;
-
-
- L = (FT_UShort)args[0];
-
- if ( BOUNDS( L, CUR.zp2.n_points ) )
- {
- if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
- return;
- }
-
- K = CUR_fast_project( &CUR.zp2.cur[L] );
-
- CUR_Func_move( &CUR.zp2, L, args[1] - K );
-
- /* not part of the specs, but here for safety */
-
- if ( CUR.GS.gep2 == 0 )
- CUR.zp2.org[L] = CUR.zp2.cur[L];
- }
-
-
- /*************************************************************************/
- /* */
- /* MD[a]: Measure Distance */
- /* Opcode range: 0x49-0x4A */
- /* 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 )
- {
- FT_UShort K, L;
- FT_F26Dot6 D;
-
-
- K = (FT_UShort)args[1];
- L = (FT_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;
- }
- 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 */
- /* Opcode range: 0x86-0x87 */
- /* Stack: uint32 uint32 --> */
- /* */
- static void
- Ins_SDPVTL( INS_ARG )
- {
- FT_Long A, B, C;
- FT_UShort p1, p2; /* was FT_Int in pas type ERROR */
-
-
- p1 = (FT_UShort)args[1];
- p2 = (FT_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;
- }
-
- {
- FT_Vector* v1 = CUR.zp1.org + p2;
- FT_Vector* v2 = CUR.zp2.org + p1;
-
-
- A = v1->x - v2->x;
- B = v1->y - v2->y;
- }
-
- if ( ( CUR.opcode & 1 ) != 0 )
- {
- C = B; /* counter clockwise rotation */
- B = A;
- A = -C;
- }
-
- NORMalize( A, B, &CUR.GS.dualVector );
-
- {
- FT_Vector* v1 = CUR.zp1.cur + p2;
- FT_Vector* v2 = CUR.zp2.cur + p1;
-
-
- A = v1->x - v2->x;
- B = v1->y - v2->y;
- }
-
- if ( ( CUR.opcode & 1 ) != 0 )
- {
- C = B; /* counter clockwise rotation */
- B = A;
- A = -C;
- }
-
- NORMalize( A, B, &CUR.GS.projVector );
-
- GUESS_VECTOR( freeVector );
-
- COMPUTE_Funcs();
- }
-
-
- /*************************************************************************/
- /* */
- /* SZP0[]: Set Zone Pointer 0 */
- /* Opcode range: 0x13 */
- /* Stack: uint32 --> */
- /* */
- static void
- Ins_SZP0( INS_ARG )
- {
- switch ( (FT_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 = (FT_UShort)args[0];
- }
-
-
- /*************************************************************************/
- /* */
- /* SZP1[]: Set Zone Pointer 1 */
- /* Opcode range: 0x14 */
- /* Stack: uint32 --> */
- /* */
- static void
- Ins_SZP1( INS_ARG )
- {
- switch ( (FT_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 = (FT_UShort)args[0];
- }
-
-
- /*************************************************************************/
- /* */
- /* SZP2[]: Set Zone Pointer 2 */
- /* Opcode range: 0x15 */
- /* Stack: uint32 --> */
- /* */
- static void
- Ins_SZP2( INS_ARG )
- {
- switch ( (FT_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 = (FT_UShort)args[0];
- }
-
-
- /*************************************************************************/
- /* */
- /* SZPS[]: Set Zone PointerS */
- /* Opcode range: 0x16 */
- /* Stack: uint32 --> */
- /* */
- static void
- Ins_SZPS( INS_ARG )
- {
- switch ( (FT_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 = (FT_UShort)args[0];
- CUR.GS.gep1 = (FT_UShort)args[0];
- CUR.GS.gep2 = (FT_UShort)args[0];
- }
-
-
- /*************************************************************************/
- /* */
- /* INSTCTRL[]: INSTruction ConTRoL */
- /* Opcode range: 0x8e */
- /* Stack: int32 int32 --> */
- /* */
- static void
- Ins_INSTCTRL( INS_ARG )
- {
- FT_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 = FT_BOOL(
- ( (FT_Byte)CUR.GS.instruct_control & ~(FT_Byte)K ) | (FT_Byte)L );
- }
-
-
- /*************************************************************************/
- /* */
- /* SCANCTRL[]: SCAN ConTRoL */
- /* Opcode range: 0x85 */
- /* Stack: uint32? --> */
- /* */
- static void
- Ins_SCANCTRL( INS_ARG )
- {
- FT_Int A;
-
-
- /* Get Threshold */
- A = (FT_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 0
- if ( ( args[0] & 0x100 ) != 0 && CUR.metrics.pointSize <= A )
- CUR.GS.scan_control = TRUE;
-#endif
-
- if ( ( args[0] & 0x200 ) != 0 && CUR.tt_metrics.rotated )
- CUR.GS.scan_control = TRUE;
-
- if ( ( args[0] & 0x400 ) != 0 && CUR.tt_metrics.stretched )
- CUR.GS.scan_control = TRUE;
-
-#if 0
- if ( ( args[0] & 0x800 ) != 0 && CUR.metrics.pointSize > A )
- CUR.GS.scan_control = FALSE;
-#endif
-
- if ( ( args[0] & 0x1000 ) != 0 && CUR.tt_metrics.rotated )
- CUR.GS.scan_control = FALSE;
-
- if ( ( args[0] & 0x2000 ) != 0 && CUR.tt_metrics.stretched )
- CUR.GS.scan_control = FALSE;
- }
-
-
- /*************************************************************************/
- /* */
- /* SCANTYPE[]: SCAN TYPE */
- /* Opcode range: 0x8D */
- /* 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 = (FT_Int)args[0];
- }
- }
-
-
- /*************************************************************************/
- /* */
- /* MANAGING OUTLINES */
- /* */
- /* Instructions appear in the specification's order. */
- /* */
- /*************************************************************************/
-
-
- /*************************************************************************/
- /* */
- /* FLIPPT[]: FLIP PoinT */
- /* Opcode range: 0x80 */
- /* Stack: uint32... --> */
- /* */
- static void
- Ins_FLIPPT( INS_ARG )
- {
- FT_UShort point;
-
- FT_UNUSED_ARG;
-
-
- if ( CUR.top < CUR.GS.loop )
- {
- CUR.error = TT_Err_Too_Few_Arguments;
- return;
- }
-
- while ( CUR.GS.loop > 0 )
- {
- CUR.args--;
-
- point = (FT_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.tags[point] ^= FT_CURVE_TAG_ON;
-
- CUR.GS.loop--;
- }
-
- CUR.GS.loop = 1;
- CUR.new_top = CUR.args;
- }
-
-
- /*************************************************************************/
- /* */
- /* FLIPRGON[]: FLIP RanGe ON */
- /* Opcode range: 0x81 */
- /* Stack: uint32 uint32 --> */
- /* */
- static void
- Ins_FLIPRGON( INS_ARG )
- {
- FT_UShort I, K, L;
-
-
- K = (FT_UShort)args[1];
- L = (FT_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.tags[I] |= FT_CURVE_TAG_ON;
- }
-
-
- /*************************************************************************/
- /* */
- /* FLIPRGOFF: FLIP RanGe OFF */
- /* Opcode range: 0x82 */
- /* Stack: uint32 uint32 --> */
- /* */
- static void
- Ins_FLIPRGOFF( INS_ARG )
- {
- FT_UShort I, K, L;
-
-
- K = (FT_UShort)args[1];
- L = (FT_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.tags[I] &= ~FT_CURVE_TAG_ON;
- }
-
-
- static FT_Bool
- Compute_Point_Displacement( EXEC_OP_ FT_F26Dot6* x,
- FT_F26Dot6* y,
- TT_GlyphZone zone,
- FT_UShort* refp )
- {
- TT_GlyphZoneRec zp;
- FT_UShort p;
- FT_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_Reference;
- *refp = 0;
- return FAILURE;
- }
-
- *zone = zp;
- *refp = p;
-
- d = CUR_Func_project( zp.cur + p, zp.org + p );
-
-#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
- if ( CUR.face->unpatented_hinting )
- {
- if ( CUR.GS.both_x_axis )
- {
- *x = d;
- *y = 0;
- }
- else
- {
- *x = 0;
- *y = d;
- }
- }
- else
-#endif
- {
- *x = TT_MULDIV( d,
- (FT_Long)CUR.GS.freeVector.x * 0x10000L,
- CUR.F_dot_P );
- *y = TT_MULDIV( d,
- (FT_Long)CUR.GS.freeVector.y * 0x10000L,
- CUR.F_dot_P );
- }
-
- return SUCCESS;
- }
-
-
- static void
- Move_Zp2_Point( EXEC_OP_ FT_UShort point,
- FT_F26Dot6 dx,
- FT_F26Dot6 dy,
- FT_Bool touch )
- {
-#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
- if ( CUR.face->unpatented_hinting )
- {
- if ( CUR.GS.both_x_axis )
- {
- CUR.zp2.cur[point].x += dx;
- if ( touch )
- CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X;
- }
- else
- {
- CUR.zp2.cur[point].y += dy;
- if ( touch )
- CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y;
- }
- return;
- }
-#endif
-
- if ( CUR.GS.freeVector.x != 0 )
- {
- CUR.zp2.cur[point].x += dx;
- if ( touch )
- CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X;
- }
-
- if ( CUR.GS.freeVector.y != 0 )
- {
- CUR.zp2.cur[point].y += dy;
- if ( touch )
- CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y;
- }
- }
-
-
- /*************************************************************************/
- /* */
- /* SHP[a]: SHift Point by the last point */
- /* Opcode range: 0x32-0x33 */
- /* Stack: uint32... --> */
- /* */
- static void
- Ins_SHP( INS_ARG )
- {
- TT_GlyphZoneRec zp;
- FT_UShort refp;
-
- FT_F26Dot6 dx,
- dy;
- FT_UShort point;
-
- FT_UNUSED_ARG;
-
-
- 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 = (FT_UShort)CUR.stack[CUR.args];
-
- if ( BOUNDS( point, CUR.zp2.n_points ) )
- {
- if ( CUR.pedantic_hinting )
- {
- CUR.error = TT_Err_Invalid_Reference;
- return;
- }
- }
- else
- /* XXX: 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 */
- /* Opcode range: 0x34-35 */
- /* Stack: uint32 --> */
- /* */
- static void
- Ins_SHC( INS_ARG )
- {
- TT_GlyphZoneRec zp;
- FT_UShort refp;
- FT_F26Dot6 dx,
- dy;
-
- FT_Short contour;
- FT_UShort first_point, last_point, i;
-
-
- contour = (FT_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 = (FT_UShort)( CUR.pts.contours[contour - 1] + 1 -
- CUR.pts.first_point );
-
- last_point = (FT_UShort)( CUR.pts.contours[contour] -
- CUR.pts.first_point );
-
- /* 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 = (FT_UShort)(CUR.zp2.n_points - 1);
- else
- last_point = 0;
- }
-
- /* XXX: UNDOCUMENTED! SHC touches the points */
- for ( i = first_point; i <= last_point; i++ )
- {
- if ( zp.cur != CUR.zp2.cur || refp != i )
- MOVE_Zp2_Point( i, dx, dy, TRUE );
- }
- }
-
-
- /*************************************************************************/
- /* */
- /* SHZ[a]: SHift Zone */
- /* Opcode range: 0x36-37 */
- /* Stack: uint32 --> */
- /* */
- static void
- Ins_SHZ( INS_ARG )
- {
- TT_GlyphZoneRec zp;
- FT_UShort refp;
- FT_F26Dot6 dx,
- dy;
-
- FT_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;
-
- /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points. */
- /* Twilight zone has no contours, so use `n_points'. */
- /* Normal zone's `n_points' includes phantoms, so must */
- /* use end of last contour. */
- if ( CUR.GS.gep2 == 0 && CUR.zp2.n_points > 0 )
- last_point = (FT_UShort)( CUR.zp2.n_points - 1 );
- else if ( CUR.GS.gep2 == 1 && CUR.zp2.n_contours > 0 )
- last_point = (FT_UShort)( CUR.zp2.contours[CUR.zp2.n_contours - 1] );
- else
- last_point = 0;
-
- /* XXX: 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 */
- /* Opcode range: 0x38 */
- /* Stack: f26.6 uint32... --> */
- /* */
- static void
- Ins_SHPIX( INS_ARG )
- {
- FT_F26Dot6 dx, dy;
- FT_UShort point;
-
-
- if ( CUR.top < CUR.GS.loop + 1 )
- {
- CUR.error = TT_Err_Invalid_Reference;
- return;
- }
-
-#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
- if ( CUR.face->unpatented_hinting )
- {
- if ( CUR.GS.both_x_axis )
- {
- dx = TT_MulFix14( args[0], 0x4000 );
- dy = 0;
- }
- else
- {
- dx = 0;
- dy = TT_MulFix14( args[0], 0x4000 );
- }
- }
- else
-#endif
- {
- dx = TT_MulFix14( args[0], CUR.GS.freeVector.x );
- dy = TT_MulFix14( args[0], CUR.GS.freeVector.y );
- }
-
- while ( CUR.GS.loop > 0 )
- {
- CUR.args--;
-
- point = (FT_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 Position */
- /* Opcode range: 0x3A-0x3B */
- /* Stack: f26.6 uint32 --> */
- /* */
- static void
- Ins_MSIRP( INS_ARG )
- {
- FT_UShort point;
- FT_F26Dot6 distance;
-
-
- point = (FT_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.gep1 == 0 ) /* if the point that is to be moved */
- /* is in twilight zone */
- {
- CUR.zp1.org[point] = CUR.zp0.org[CUR.GS.rp0];
- CUR_Func_move_orig( &CUR.zp1, point, args[1] );
- 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 */
- /* Opcode range: 0x2E-0x2F */
- /* Stack: uint32 --> */
- /* */
- static void
- Ins_MDAP( INS_ARG )
- {
- FT_UShort point;
- FT_F26Dot6 cur_dist,
- distance;
-
-
- point = (FT_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_fast_project( &CUR.zp0.cur[point] );
- distance = CUR_Func_round( cur_dist,
- CUR.tt_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 */
- /* Opcode range: 0x3E-0x3F */
- /* Stack: uint32 uint32 --> */
- /* */
- static void
- Ins_MIAP( INS_ARG )
- {
- FT_ULong cvtEntry;
- FT_UShort point;
- FT_F26Dot6 distance,
- org_dist;
-
-
- cvtEntry = (FT_ULong)args[1];
- point = (FT_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;
- }
-
- /* XXX: UNDOCUMENTED! */
- /* */
- /* The behaviour of an MIAP instruction is quite */
- /* different when used in the twilight zone. */
- /* */
- /* First, no control value cut-in 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 */
- /* specification. */
- /* */
- /* 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_MulFix14( distance, CUR.GS.freeVector.x );
- CUR.zp0.org[point].y = TT_MulFix14( distance, CUR.GS.freeVector.y ),
- CUR.zp0.cur[point] = CUR.zp0.org[point];
- }
-
- org_dist = CUR_fast_project( &CUR.zp0.cur[point] );
-
- if ( ( CUR.opcode & 1 ) != 0 ) /* rounding and control cutin flag */
- {
- if ( FT_ABS( distance - org_dist ) > CUR.GS.control_value_cutin )
- distance = org_dist;
-
- distance = CUR_Func_round( distance, CUR.tt_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 */
- /* Opcode range: 0xC0-0xDF */
- /* Stack: uint32 --> */
- /* */
- static void
- Ins_MDRP( INS_ARG )
- {
- FT_UShort point;
- FT_F26Dot6 org_dist, distance;
-
-
- point = (FT_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? */
-
- /* XXX: UNDOCUMENTED: twilight zone special case */
-
- if ( CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 )
- {
- FT_Vector* vec1 = &CUR.zp1.org[point];
- FT_Vector* vec2 = &CUR.zp0.org[CUR.GS.rp0];
-
-
- org_dist = CUR_Func_dualproj( vec1, vec2 );
- }
- else
- {
- FT_Vector* vec1 = &CUR.zp1.orus[point];
- FT_Vector* vec2 = &CUR.zp0.orus[CUR.GS.rp0];
-
-
- if ( CUR.metrics.x_scale == CUR.metrics.y_scale )
- {
- /* this should be faster */
- org_dist = CUR_Func_dualproj( vec1, vec2 );
- org_dist = TT_MULFIX( org_dist, CUR.metrics.x_scale );
- }
- else
- {
- FT_Vector vec;
-
-
- vec.x = TT_MULFIX( vec1->x - vec2->x, CUR.metrics.x_scale );
- vec.y = TT_MULFIX( vec1->y - vec2->y, CUR.metrics.y_scale );
-
- org_dist = CUR_fast_dualproj( &vec );
- }
- }
-
- /* single width cut-in test */
-
- if ( FT_ABS( org_dist - CUR.GS.single_width_value ) <
- 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.tt_metrics.compensations[CUR.opcode & 3] );
- else
- distance = ROUND_None(
- org_dist,
- CUR.tt_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 */
- /* Opcode range: 0xE0-0xFF */
- /* Stack: int32? uint32 --> */
- /* */
- static void
- Ins_MIRP( INS_ARG )
- {
- FT_UShort point;
- FT_ULong cvtEntry;
-
- FT_F26Dot6 cvt_dist,
- distance,
- cur_dist,
- org_dist;
-
-
- point = (FT_UShort)args[0];
- cvtEntry = (FT_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 ( FT_ABS( cvt_dist - CUR.GS.single_width_value ) <
- 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_MulFix14( cvt_dist, CUR.GS.freeVector.x );
-
- CUR.zp1.org[point].y = CUR.zp0.org[CUR.GS.rp0].y +
- TT_MulFix14( cvt_dist, CUR.GS.freeVector.y );
-
- CUR.zp1.cur[point] = CUR.zp0.cur[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 ( FT_ABS( cvt_dist - org_dist ) >= CUR.GS.control_value_cutin )
- cvt_dist = org_dist;
-
- distance = CUR_Func_round(
- cvt_dist,
- CUR.tt_metrics.compensations[CUR.opcode & 3] );
- }
- else
- distance = ROUND_None(
- cvt_dist,
- CUR.tt_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;
-
- /* XXX: UNDOCUMENTED! */
- CUR.GS.rp2 = point;
- }
-
-
- /*************************************************************************/
- /* */
- /* ALIGNRP[]: ALIGN Relative Point */
- /* Opcode range: 0x3C */
- /* Stack: uint32 uint32... --> */
- /* */
- static void
- Ins_ALIGNRP( INS_ARG )
- {
- FT_UShort point;
- FT_F26Dot6 distance;
-
- FT_UNUSED_ARG;
-
-
- 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 = (FT_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 */
- /* Opcode range: 0x0F */
- /* Stack: 5 * uint32 --> */
- /* */
- static void
- Ins_ISECT( INS_ARG )
- {
- FT_UShort point,
- a0, a1,
- b0, b1;
-
- FT_F26Dot6 discriminant;
-
- FT_F26Dot6 dx, dy,
- dax, day,
- dbx, dby;
-
- FT_F26Dot6 val;
-
- FT_Vector R;
-
-
- point = (FT_UShort)args[0];
-
- a0 = (FT_UShort)args[1];
- a1 = (FT_UShort)args[2];
- b0 = (FT_UShort)args[3];
- b1 = (FT_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.tags[point] |= FT_CURVE_TAG_TOUCH_BOTH;
-
- discriminant = TT_MULDIV( dax, -dby, 0x40 ) +
- TT_MULDIV( day, dbx, 0x40 );
-
- if ( FT_ABS( discriminant ) >= 0x40 )
- {
- val = TT_MULDIV( dx, -dby, 0x40 ) + TT_MULDIV( dy, dbx, 0x40 );
-
- 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 */
- /* Opcode range: 0x27 */
- /* Stack: uint32 uint32 --> */
- /* */
- static void
- Ins_ALIGNPTS( INS_ARG )
- {
- FT_UShort p1, p2;
- FT_F26Dot6 distance;
-
-
- p1 = (FT_UShort)args[0];
- p2 = (FT_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 */
- /* Opcode range: 0x39 */
- /* Stack: uint32... --> */
- /* */
-
- /* SOMETIMES, DUMBER CODE IS BETTER CODE */
-
- static void
- Ins_IP( INS_ARG )
- {
- FT_F26Dot6 old_range, cur_range;
- FT_Vector* orus_base;
- FT_Vector* cur_base;
- FT_Int twilight;
-
- FT_UNUSED_ARG;
-
-
- if ( CUR.top < CUR.GS.loop )
- {
- CUR.error = TT_Err_Invalid_Reference;
- return;
- }
-
- /*
- * We need to deal in a special way with the twilight zone.
- * Otherwise, by definition, the value of CUR.twilight.orus[n] is (0,0),
- * for every n.
- */
- twilight = CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 || CUR.GS.gep2 == 0;
-
- if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) )
- {
- if ( CUR.pedantic_hinting )
- CUR.error = TT_Err_Invalid_Reference;
- return;
- }
-
- if ( twilight )
- orus_base = &CUR.zp0.org[CUR.GS.rp1];
- else
- orus_base = &CUR.zp0.orus[CUR.GS.rp1];
-
- cur_base = &CUR.zp0.cur[CUR.GS.rp1];
-
- /* 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 ) )
- {
- old_range = 0;
- cur_range = 0;
- }
- else
- {
- if ( twilight )
- old_range = CUR_Func_dualproj( &CUR.zp1.org[CUR.GS.rp2],
- orus_base );
- else
- old_range = CUR_Func_dualproj( &CUR.zp1.orus[CUR.GS.rp2],
- orus_base );
-
- cur_range = CUR_Func_project ( &CUR.zp1.cur[CUR.GS.rp2], cur_base );
- }
-
- for ( ; CUR.GS.loop > 0; --CUR.GS.loop )
- {
- FT_UInt point = (FT_UInt)CUR.stack[--CUR.args];
- FT_F26Dot6 org_dist, cur_dist, new_dist;
-
-
- /* check point bounds */
- if ( BOUNDS( point, CUR.zp2.n_points ) )
- {
- if ( CUR.pedantic_hinting )
- {
- CUR.error = TT_Err_Invalid_Reference;
- return;
- }
- continue;
- }
-
- if ( twilight )
- org_dist = CUR_Func_dualproj( &CUR.zp2.org[point], orus_base );
- else
- org_dist = CUR_Func_dualproj( &CUR.zp2.orus[point], orus_base );
-
- cur_dist = CUR_Func_project ( &CUR.zp2.cur[point], cur_base );
- new_dist = ( old_range != 0 )
- ? TT_MULDIV( org_dist, cur_range, old_range )
- : cur_dist;
-
- CUR_Func_move( &CUR.zp2, (FT_UShort)point, new_dist - cur_dist );
- }
- CUR.GS.loop = 1;
- CUR.new_top = CUR.args;
- }
-
-
- /*************************************************************************/
- /* */
- /* UTP[a]: UnTouch Point */
- /* Opcode range: 0x29 */
- /* Stack: uint32 --> */
- /* */
- static void
- Ins_UTP( INS_ARG )
- {
- FT_UShort point;
- FT_Byte mask;
-
-
- point = (FT_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 &= ~FT_CURVE_TAG_TOUCH_X;
-
- if ( CUR.GS.freeVector.y != 0 )
- mask &= ~FT_CURVE_TAG_TOUCH_Y;
-
- CUR.zp0.tags[point] &= mask;
- }
-
-
- /* Local variables for Ins_IUP: */
- typedef struct
- {
- FT_Vector* orgs; /* original and current coordinate */
- FT_Vector* curs; /* arrays */
- FT_Vector* orus;
- FT_UInt max_points;
-
- } IUP_WorkerRec, *IUP_Worker;
-
-
- static void
- _iup_worker_shift( IUP_Worker worker,
- FT_UInt p1,
- FT_UInt p2,
- FT_UInt p )
- {
- FT_UInt i;
- FT_F26Dot6 dx;
-
-
- dx = worker->curs[p].x - worker->orgs[p].x;
- if ( dx != 0 )
- {
- for ( i = p1; i < p; i++ )
- worker->curs[i].x += dx;
-
- for ( i = p + 1; i <= p2; i++ )
- worker->curs[i].x += dx;
- }
- }
-
-
- static void
- _iup_worker_interpolate( IUP_Worker worker,
- FT_UInt p1,
- FT_UInt p2,
- FT_UInt ref1,
- FT_UInt ref2 )
- {
- FT_UInt i;
- FT_F26Dot6 orus1, orus2, org1, org2, delta1, delta2;
-
-
- if ( p1 > p2 )
- return;
-
- if ( BOUNDS( ref1, worker->max_points ) ||
- BOUNDS( ref2, worker->max_points ) )
- return;
-
- orus1 = worker->orus[ref1].x;
- orus2 = worker->orus[ref2].x;
-
- if ( orus1 > orus2 )
- {
- FT_F26Dot6 tmp_o;
- FT_UInt tmp_r;
-
-
- tmp_o = orus1;
- orus1 = orus2;
- orus2 = tmp_o;
-
- tmp_r = ref1;
- ref1 = ref2;
- ref2 = tmp_r;
- }
-
- org1 = worker->orgs[ref1].x;
- org2 = worker->orgs[ref2].x;
- delta1 = worker->curs[ref1].x - org1;
- delta2 = worker->curs[ref2].x - org2;
-
- if ( orus1 == orus2 )
- {
- /* simple shift of untouched points */
- for ( i = p1; i <= p2; i++ )
- {
- FT_F26Dot6 x = worker->orgs[i].x;
-
-
- if ( x <= org1 )
- x += delta1;
- else
- x += delta2;
-
- worker->curs[i].x = x;
- }
- }
- else
- {
- FT_Fixed scale = 0;
- FT_Bool scale_valid = 0;
-
-
- /* interpolation */
- for ( i = p1; i <= p2; i++ )
- {
- FT_F26Dot6 x = worker->orgs[i].x;
-
-
- if ( x <= org1 )
- x += delta1;
-
- else if ( x >= org2 )
- x += delta2;
-
- else
- {
- if ( !scale_valid )
- {
- scale_valid = 1;
- scale = TT_MULDIV( org2 + delta2 - ( org1 + delta1 ),
- 0x10000, orus2 - orus1 );
- }
-
- x = ( org1 + delta1 ) +
- TT_MULFIX( worker->orus[i].x - orus1, scale );
- }
- worker->curs[i].x = x;
- }
- }
- }
-
-
- /*************************************************************************/
- /* */
- /* IUP[a]: Interpolate Untouched Points */
- /* Opcode range: 0x30-0x31 */
- /* Stack: --> */
- /* */
- static void
- Ins_IUP( INS_ARG )
- {
- IUP_WorkerRec V;
- FT_Byte mask;
-
- FT_UInt first_point; /* first point of contour */
- FT_UInt end_point; /* end point (last+1) of contour */
-
- FT_UInt first_touched; /* first touched point in contour */
- FT_UInt cur_touched; /* current touched point in contour */
-
- FT_UInt point; /* current point */
- FT_Short contour; /* current contour */
-
- FT_UNUSED_ARG;
-
-
- /* ignore empty outlines */
- if ( CUR.pts.n_contours == 0 )
- return;
-
- if ( CUR.opcode & 1 )
- {
- mask = FT_CURVE_TAG_TOUCH_X;
- V.orgs = CUR.pts.org;
- V.curs = CUR.pts.cur;
- V.orus = CUR.pts.orus;
- }
- else
- {
- mask = FT_CURVE_TAG_TOUCH_Y;
- V.orgs = (FT_Vector*)( (FT_Pos*)CUR.pts.org + 1 );
- V.curs = (FT_Vector*)( (FT_Pos*)CUR.pts.cur + 1 );
- V.orus = (FT_Vector*)( (FT_Pos*)CUR.pts.orus + 1 );
- }
- V.max_points = CUR.pts.n_points;
-
- contour = 0;
- point = 0;
-
- do
- {
- end_point = CUR.pts.contours[contour] - CUR.pts.first_point;
- first_point = point;
-
- while ( point <= end_point && ( CUR.pts.tags[point] & mask ) == 0 )
- point++;
-
- if ( point <= end_point )
- {
- first_touched = point;
- cur_touched = point;
-
- point++;
-
- while ( point <= end_point )
- {
- if ( ( CUR.pts.tags[point] & mask ) != 0 )
- {
- if ( point > 0 )
- _iup_worker_interpolate( &V,
- cur_touched + 1,
- point - 1,
- cur_touched,
- point );
- cur_touched = point;
- }
-
- point++;
- }
-
- if ( cur_touched == first_touched )
- _iup_worker_shift( &V, first_point, end_point, cur_touched );
- else
- {
- _iup_worker_interpolate( &V,
- (FT_UShort)( cur_touched + 1 ),
- end_point,
- cur_touched,
- first_touched );
-
- if ( first_touched > 0 )
- _iup_worker_interpolate( &V,
- first_point,
- first_touched - 1,
- cur_touched,
- first_touched );
- }
- }
- contour++;
- } while ( contour < CUR.pts.n_contours );
- }
-
-
- /*************************************************************************/
- /* */
- /* DELTAPn[]: DELTA exceptions P1, P2, P3 */
- /* Opcode range: 0x5D,0x71,0x72 */
- /* Stack: uint32 (2 * uint32)... --> */
- /* */
- static void
- Ins_DELTAP( INS_ARG )
- {
- FT_ULong k, nump;
- FT_UShort A;
- FT_ULong C;
- FT_Long B;
-
-
-#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
- /* Delta hinting is covered by US Patent 5159668. */
- if ( CUR.face->unpatented_hinting )
- {
- FT_Long n = args[0] * 2;
-
-
- if ( CUR.args < n )
- {
- CUR.error = TT_Err_Too_Few_Arguments;
- return;
- }
-
- CUR.args -= n;
- CUR.new_top = CUR.args;
- return;
- }
-#endif
-
- nump = (FT_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 = (FT_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 = ( (FT_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() == (FT_Long)C )
- {
- B = ( (FT_ULong)B & 0xF ) - 8;
- if ( B >= 0 )
- B++;
- B = B * 64 / ( 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 */
- /* Opcode range: 0x73,0x74,0x75 */
- /* Stack: uint32 (2 * uint32)... --> */
- /* */
- static void
- Ins_DELTAC( INS_ARG )
- {
- FT_ULong nump, k;
- FT_ULong A, C;
- FT_Long B;
-
-
-#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
- /* Delta hinting is covered by US Patent 5159668. */
- if ( CUR.face->unpatented_hinting )
- {
- FT_Long n = args[0] * 2;
-
-
- if ( CUR.args < n )
- {
- CUR.error = TT_Err_Too_Few_Arguments;
- return;
- }
-
- CUR.args -= n;
- CUR.new_top = CUR.args;
- return;
- }
-#endif
-
- nump = (FT_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 = (FT_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 = ( (FT_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() == (FT_Long)C )
- {
- B = ( (FT_ULong)B & 0xF ) - 8;
- if ( B >= 0 )
- B++;
- B = B * 64 / ( 1L << CUR.GS.delta_shift );
-
- CUR_Func_move_cvt( A, B );
- }
- }
- }
-
- CUR.new_top = CUR.args;
- }
-
-
- /*************************************************************************/
- /* */
- /* MISC. INSTRUCTIONS */
- /* */
- /*************************************************************************/
-
-
- /*************************************************************************/
- /* */
- /* GETINFO[]: GET INFOrmation */
- /* Opcode range: 0x88 */
- /* Stack: uint32 --> uint32 */
- /* */
- static void
- Ins_GETINFO( INS_ARG )
- {
- FT_Long K;
-
-
- K = 0;
-
- /* We return MS rasterizer version 1.7 for the font scaler. */
- if ( ( args[0] & 1 ) != 0 )
- K = 35;
-
- /* Has the glyph been rotated? */
- if ( ( args[0] & 2 ) != 0 && CUR.tt_metrics.rotated )
- K |= 0x80;
-
- /* Has the glyph been stretched? */
- if ( ( args[0] & 4 ) != 0 && CUR.tt_metrics.stretched )
- K |= 1 << 8;
-
- /* Are we hinting for grayscale? */
- if ( ( args[0] & 32 ) != 0 && CUR.grayscale )
- K |= 1 << 12;
-
- args[0] = K;
- }
-
-
- static void
- Ins_UNKNOWN( INS_ARG )
- {
- TT_DefRecord* def = CUR.IDefs;
- TT_DefRecord* limit = def + CUR.numIDefs;
-
- FT_UNUSED_ARG;
-
-
- for ( ; def < limit; def++ )
- {
- if ( (FT_Byte)def->opc == CUR.opcode && def->active )
- {
- TT_CallRec* call;
-
-
- if ( CUR.callTop >= CUR.callSize )
- {
- CUR.error = TT_Err_Stack_Overflow;
- return;
- }
-
- call = CUR.callStack + CUR.callTop++;
-
- call->Caller_Range = CUR.curRange;
- call->Caller_IP = CUR.IP+1;
- call->Cur_Count = 1;
- call->Cur_Restart = def->start;
-
- 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_0x28 */ 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_0x7B */ Ins_UNKNOWN,
- /* RUTG */ Ins_RUTG,
- /* RDTG */ Ins_RDTG,
- /* SANGW */ Ins_SANGW,
- /* AA */ Ins_AA,
-
- /* FlipPT */ Ins_FLIPPT,
- /* FlipRgON */ Ins_FLIPRGON,
- /* FlipRgOFF */ Ins_FLIPRGOFF,
- /* INS_0x83 */ Ins_UNKNOWN,
- /* INS_0x84 */ 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_0x8F */ Ins_UNKNOWN,
-
- /* INS_0x90 */ Ins_UNKNOWN,
- /* INS_0x91 */ Ins_UNKNOWN,
- /* INS_0x92 */ Ins_UNKNOWN,
- /* INS_0x93 */ Ins_UNKNOWN,
- /* INS_0x94 */ Ins_UNKNOWN,
- /* INS_0x95 */ Ins_UNKNOWN,
- /* INS_0x96 */ Ins_UNKNOWN,
- /* INS_0x97 */ Ins_UNKNOWN,
- /* INS_0x98 */ Ins_UNKNOWN,
- /* INS_0x99 */ Ins_UNKNOWN,
- /* INS_0x9A */ Ins_UNKNOWN,
- /* INS_0x9B */ Ins_UNKNOWN,
- /* INS_0x9C */ Ins_UNKNOWN,
- /* INS_0x9D */ Ins_UNKNOWN,
- /* INS_0x9E */ Ins_UNKNOWN,
- /* INS_0x9F */ Ins_UNKNOWN,
-
- /* INS_0xA0 */ Ins_UNKNOWN,
- /* INS_0xA1 */ Ins_UNKNOWN,
- /* INS_0xA2 */ Ins_UNKNOWN,
- /* INS_0xA3 */ Ins_UNKNOWN,
- /* INS_0xA4 */ Ins_UNKNOWN,
- /* INS_0xA5 */ Ins_UNKNOWN,
- /* INS_0xA6 */ Ins_UNKNOWN,
- /* INS_0xA7 */ Ins_UNKNOWN,
- /* INS_0xA8 */ Ins_UNKNOWN,
- /* INS_0xA9 */ Ins_UNKNOWN,
- /* INS_0xAA */ Ins_UNKNOWN,
- /* INS_0xAB */ Ins_UNKNOWN,
- /* INS_0xAC */ Ins_UNKNOWN,
- /* INS_0xAD */ Ins_UNKNOWN,
- /* INS_0xAE */ Ins_UNKNOWN,
- /* INS_0xAF */ 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 /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
-
-
- /*************************************************************************/
- /* */
- /* 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 with TRUE, test IP < CodeSize to know whether it comes from */
- /* an 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 specification's order. */
- /* */
- /*************************************************************************/
-
-
- /* documentation is in ttinterp.h */
-
- FT_EXPORT_DEF( FT_Error )
- TT_RunIns( TT_ExecContext exc )
- {
- FT_Long ins_counter = 0; /* executed instructions counter */
-
-
-#ifdef TT_CONFIG_OPTION_STATIC_RASTER
- cur = *exc;
-#endif
-
- /* set CVT functions */
- CUR.tt_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( (FT_Byte)exc->GS.round_state );
-
- do
- {
- CUR.opcode = CUR.code[CUR.IP];
-
- if ( ( CUR.length = opcode_length[CUR.opcode] ) < 0 )
- {
- if ( CUR.IP + 1 > CUR.codeSize )
- goto LErrorCodeOverflow_;
-
- CUR.length = 2 - CUR.length * CUR.code[CUR.IP + 1];
- }
-
- if ( CUR.IP + CUR.length > CUR.codeSize )
- goto LErrorCodeOverflow_;
-
- /* 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
-
- {
- FT_Long* args = CUR.stack + CUR.args;
- FT_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 */
- {
- FT_Short AA, BB;
-
-
- AA = (FT_Short)( ( opcode & 1 ) << 14 );
- BB = (FT_Short)( AA ^ 0x4000 );
-
- if ( opcode < 4 )
- {
- CUR.GS.projVector.x = AA;
- CUR.GS.projVector.y = BB;
-
- CUR.GS.dualVector.x = AA;
- CUR.GS.dualVector.y = BB;
- }
- else
- {
- GUESS_VECTOR( projVector );
- }
-
- if ( ( opcode & 2 ) == 0 )
- {
- CUR.GS.freeVector.x = AA;
- CUR.GS.freeVector.y = BB;
- }
- else
- {
- GUESS_VECTOR( freeVector );
- }
-
- 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_ARG_ 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_ARG_ args );
- break;
-
- case 0x14: /* SZP1 */
- Ins_SZP1( EXEC_ARG_ args );
- break;
-
- case 0x15: /* SZP2 */
- Ins_SZP2( EXEC_ARG_ args );
- break;
-
- case 0x16: /* SZPS */
- Ins_SZPS( EXEC_ARG_ 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_ARG_ 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_ARG_ args );
- break;
-
- case 0x27: /* ALIGNPTS */
- Ins_ALIGNPTS( EXEC_ARG_ args );
- break;
-
- case 0x28: /* ???? */
- Ins_UNKNOWN( EXEC_ARG_ args );
- break;
-
- case 0x29: /* UTP */
- Ins_UTP( EXEC_ARG_ args );
- break;
-
- case 0x2A: /* LOOPCALL */
- Ins_LOOPCALL( EXEC_ARG_ args );
- break;
-
- case 0x2B: /* CALL */
- Ins_CALL( EXEC_ARG_ args );
- break;
-
- case 0x2C: /* FDEF */
- Ins_FDEF( EXEC_ARG_ args );
- break;
-
- case 0x2D: /* ENDF */
- Ins_ENDF( EXEC_ARG_ args );
- break;
-
- case 0x2E: /* MDAP */
- case 0x2F: /* MDAP */
- Ins_MDAP( EXEC_ARG_ args );
- break;
-
-
- case 0x30: /* IUP */
- case 0x31: /* IUP */
- Ins_IUP( EXEC_ARG_ args );
- break;
-
- case 0x32: /* SHP */
- case 0x33: /* SHP */
- Ins_SHP( EXEC_ARG_ args );
- break;
-
- case 0x34: /* SHC */
- case 0x35: /* SHC */
- Ins_SHC( EXEC_ARG_ args );
- break;
-
- case 0x36: /* SHZ */
- case 0x37: /* SHZ */
- Ins_SHZ( EXEC_ARG_ args );
- break;
-
- case 0x38: /* SHPIX */
- Ins_SHPIX( EXEC_ARG_ args );
- break;
-
- case 0x39: /* IP */
- Ins_IP( EXEC_ARG_ args );
- break;
-
- case 0x3A: /* MSIRP */
- case 0x3B: /* MSIRP */
- Ins_MSIRP( EXEC_ARG_ args );
- break;
-
- case 0x3C: /* AlignRP */
- Ins_ALIGNRP( EXEC_ARG_ args );
- break;
-
- case 0x3D: /* RTDG */
- DO_RTDG
- break;
-
- case 0x3E: /* MIAP */
- case 0x3F: /* MIAP */
- Ins_MIAP( EXEC_ARG_ args );
- break;
-
- case 0x40: /* NPUSHB */
- Ins_NPUSHB( EXEC_ARG_ args );
- break;
-
- case 0x41: /* NPUSHW */
- Ins_NPUSHW( EXEC_ARG_ 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_ARG_ args );
- break;
-
- case 0x48: /* SCFS */
- Ins_SCFS( EXEC_ARG_ args );
- break;
-
- case 0x49: /* MD */
- case 0x4A: /* MD */
- Ins_MD( EXEC_ARG_ 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_ARG_ 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_ARG_ 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_ARG_ args );
- break;
-
- case 0x73: /* DELTAC0 */
- case 0x74: /* DELTAC1 */
- case 0x75: /* DELTAC2 */
- Ins_DELTAC( EXEC_ARG_ 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_ARG_ 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_ARG_ args );
- break;
-
- case 0x81: /* FLIPRGON */
- Ins_FLIPRGON( EXEC_ARG_ args );
- break;
-
- case 0x82: /* FLIPRGOFF */
- Ins_FLIPRGOFF( EXEC_ARG_ args );
- break;
-
- case 0x83: /* UNKNOWN */
- case 0x84: /* UNKNOWN */
- Ins_UNKNOWN( EXEC_ARG_ args );
- break;
-
- case 0x85: /* SCANCTRL */
- Ins_SCANCTRL( EXEC_ARG_ args );
- break;
-
- case 0x86: /* SDPVTL */
- case 0x87: /* SDPVTL */
- Ins_SDPVTL( EXEC_ARG_ args );
- break;
-
- case 0x88: /* GETINFO */
- Ins_GETINFO( EXEC_ARG_ args );
- break;
-
- case 0x89: /* IDEF */
- Ins_IDEF( EXEC_ARG_ args );
- break;
-
- case 0x8A: /* ROLL */
- Ins_ROLL( EXEC_ARG_ args );
- break;
-
- case 0x8B: /* MAX */
- DO_MAX
- break;
-
- case 0x8C: /* MIN */
- DO_MIN
- break;
-
- case 0x8D: /* SCANTYPE */
- Ins_SCANTYPE( EXEC_ARG_ args );
- break;
-
- case 0x8E: /* INSTCTRL */
- Ins_INSTCTRL( EXEC_ARG_ args );
- break;
-
- case 0x8F:
- Ins_UNKNOWN( EXEC_ARG_ args );
- break;
-
- default:
- if ( opcode >= 0xE0 )
- Ins_MIRP( EXEC_ARG_ args );
- else if ( opcode >= 0xC0 )
- Ins_MDRP( EXEC_ARG_ args );
- else if ( opcode >= 0xB8 )
- Ins_PUSHW( EXEC_ARG_ args );
- else if ( opcode >= 0xB0 )
- Ins_PUSHB( EXEC_ARG_ args );
- else
- Ins_UNKNOWN( EXEC_ARG_ args );
- }
-
- }
-
-#else
-
- Instruct_Dispatch[CUR.opcode]( EXEC_ARG_ &CUR.stack[CUR.args] );
-
-#endif /* TT_CONFIG_OPTION_INTERPRETER_SWITCH */
-
- if ( CUR.error != TT_Err_Ok )
- {
- switch ( CUR.error )
- {
- case TT_Err_Invalid_Opcode: /* looking for redefined instructions */
- {
- TT_DefRecord* def = CUR.IDefs;
- TT_DefRecord* limit = def + CUR.numIDefs;
-
-
- for ( ; def < limit; def++ )
- {
- if ( def->active && CUR.opcode == (FT_Byte)def->opc )
- {
- TT_CallRec* callrec;
-
-
- if ( CUR.callTop >= CUR.callSize )
- {
- CUR.error = TT_Err_Invalid_Reference;
- goto LErrorLabel_;
- }
-
- callrec = &CUR.callStack[CUR.callTop];
-
- callrec->Caller_Range = CUR.curRange;
- callrec->Caller_IP = CUR.IP + 1;
- callrec->Cur_Count = 1;
- callrec->Cur_Restart = def->start;
-
- if ( INS_Goto_CodeRange( def->range, def->start ) == FAILURE )
- goto LErrorLabel_;
-
- goto LSuiteLabel_;
- }
- }
- }
-
- CUR.error = TT_Err_Invalid_Opcode;
- goto LErrorLabel_;
-
-#if 0
- break; /* Unreachable code warning suppression. */
- /* Leave to remind in case a later change the editor */
- /* to consider break; */
-#endif
-
- default:
- goto LErrorLabel_;
-
-#if 0
- break;
-#endif
- }
- }
-
- 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 )
- return TT_Err_Execution_Too_Long;
-
- 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_:
-
-#ifdef TT_CONFIG_OPTION_STATIC_RASTER
- *exc = cur;
-#endif
-
- return TT_Err_Ok;
-
- LErrorCodeOverflow_:
- CUR.error = TT_Err_Code_Overflow;
-
- LErrorLabel_:
-
-#ifdef TT_CONFIG_OPTION_STATIC_RASTER
- *exc = cur;
-#endif
-
- return CUR.error;
- }
-
-
-#endif /* TT_USE_BYTECODE_INTERPRETER */
-
-
-/* END */
+/***************************************************************************/\r
+/* */\r
+/* ttinterp.c */\r
+/* */\r
+/* TrueType bytecode interpreter (body). */\r
+/* */\r
+/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007 by */\r
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */\r
+/* */\r
+/* This file is part of the FreeType project, and may only be used, */\r
+/* modified, and distributed under the terms of the FreeType project */\r
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */\r
+/* this file you indicate that you have read the license and */\r
+/* understand and accept it fully. */\r
+/* */\r
+/***************************************************************************/\r
+\r
+\r
+#include <ft2build.h>\r
+#include FT_INTERNAL_DEBUG_H\r
+#include FT_INTERNAL_CALC_H\r
+#include FT_TRIGONOMETRY_H\r
+#include FT_SYSTEM_H\r
+\r
+#include "ttinterp.h"\r
+\r
+#include "tterrors.h"\r
+\r
+\r
+#ifdef TT_USE_BYTECODE_INTERPRETER\r
+\r
+\r
+#define TT_MULFIX FT_MulFix\r
+#define TT_MULDIV FT_MulDiv\r
+#define TT_MULDIV_NO_ROUND FT_MulDiv_No_Round\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */\r
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */\r
+ /* messages during execution. */\r
+ /* */\r
+#undef FT_COMPONENT\r
+#define FT_COMPONENT trace_ttinterp\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* In order to detect infinite loops in the code, we set up a counter */\r
+ /* within the run loop. A single stroke of interpretation is now */\r
+ /* limited to a maximal number of opcodes defined below. */\r
+ /* */\r
+#define MAX_RUNNABLE_OPCODES 1000000L\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* There are two kinds of implementations: */\r
+ /* */\r
+ /* a. static implementation */\r
+ /* */\r
+ /* The current execution context is a static variable, which fields */\r
+ /* are accessed directly by the interpreter during execution. The */\r
+ /* context is named `cur'. */\r
+ /* */\r
+ /* This version is non-reentrant, of course. */\r
+ /* */\r
+ /* b. indirect implementation */\r
+ /* */\r
+ /* The current execution context is passed to _each_ function as its */\r
+ /* first argument, and each field is thus accessed indirectly. */\r
+ /* */\r
+ /* This version is fully re-entrant. */\r
+ /* */\r
+ /* The idea is that an indirect implementation may be slower to execute */\r
+ /* on low-end processors that are used in some systems (like 386s or */\r
+ /* even 486s). */\r
+ /* */\r
+ /* As a consequence, the indirect implementation is now the default, as */\r
+ /* its performance costs can be considered negligible in our context. */\r
+ /* Note, however, that we kept the same source with macros because: */\r
+ /* */\r
+ /* - The code is kept very close in design to the Pascal code used for */\r
+ /* development. */\r
+ /* */\r
+ /* - It's much more readable that way! */\r
+ /* */\r
+ /* - It's still open to experimentation and tuning. */\r
+ /* */\r
+ /*************************************************************************/\r
+\r
+\r
+#ifndef TT_CONFIG_OPTION_STATIC_INTERPRETER /* indirect implementation */\r
+\r
+#define CUR (*exc) /* see ttobjs.h */\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* This macro is used whenever `exec' is unused in a function, to avoid */\r
+ /* stupid warnings from pedantic compilers. */\r
+ /* */\r
+#define FT_UNUSED_EXEC FT_UNUSED( exc )\r
+\r
+#else /* static implementation */\r
+\r
+#define CUR cur\r
+\r
+#define FT_UNUSED_EXEC int __dummy = __dummy\r
+\r
+ static\r
+ TT_ExecContextRec cur; /* static exec. context variable */\r
+\r
+ /* apparently, we have a _lot_ of direct indexing when accessing */\r
+ /* the static `cur', which makes the code bigger (due to all the */\r
+ /* four bytes addresses). */\r
+\r
+#endif /* TT_CONFIG_OPTION_STATIC_INTERPRETER */\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* The instruction argument stack. */\r
+ /* */\r
+#define INS_ARG EXEC_OP_ FT_Long* args /* see ttobjs.h for EXEC_OP_ */\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* This macro is used whenever `args' is unused in a function, to avoid */\r
+ /* stupid warnings from pedantic compilers. */\r
+ /* */\r
+#define FT_UNUSED_ARG FT_UNUSED_EXEC; FT_UNUSED( args )\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* The following macros hide the use of EXEC_ARG and EXEC_ARG_ to */\r
+ /* increase readability of the code. */\r
+ /* */\r
+ /*************************************************************************/\r
+\r
+\r
+#define SKIP_Code() \\r
+ SkipCode( EXEC_ARG )\r
+\r
+#define GET_ShortIns() \\r
+ GetShortIns( EXEC_ARG )\r
+\r
+#define NORMalize( x, y, v ) \\r
+ Normalize( EXEC_ARG_ x, y, v )\r
+\r
+#define SET_SuperRound( scale, flags ) \\r
+ SetSuperRound( EXEC_ARG_ scale, flags )\r
+\r
+#define ROUND_None( d, c ) \\r
+ Round_None( EXEC_ARG_ d, c )\r
+\r
+#define INS_Goto_CodeRange( range, ip ) \\r
+ Ins_Goto_CodeRange( EXEC_ARG_ range, ip )\r
+\r
+#define CUR_Func_move( z, p, d ) \\r
+ CUR.func_move( EXEC_ARG_ z, p, d )\r
+\r
+#define CUR_Func_move_orig( z, p, d ) \\r
+ CUR.func_move_orig( EXEC_ARG_ z, p, d )\r
+\r
+#define CUR_Func_round( d, c ) \\r
+ CUR.func_round( EXEC_ARG_ d, c )\r
+\r
+#define CUR_Func_read_cvt( index ) \\r
+ CUR.func_read_cvt( EXEC_ARG_ index )\r
+\r
+#define CUR_Func_write_cvt( index, val ) \\r
+ CUR.func_write_cvt( EXEC_ARG_ index, val )\r
+\r
+#define CUR_Func_move_cvt( index, val ) \\r
+ CUR.func_move_cvt( EXEC_ARG_ index, val )\r
+\r
+#define CURRENT_Ratio() \\r
+ Current_Ratio( EXEC_ARG )\r
+\r
+#define CURRENT_Ppem() \\r
+ Current_Ppem( EXEC_ARG )\r
+\r
+#define CUR_Ppem() \\r
+ Cur_PPEM( EXEC_ARG )\r
+\r
+#define INS_SxVTL( a, b, c, d ) \\r
+ Ins_SxVTL( EXEC_ARG_ a, b, c, d )\r
+\r
+#define COMPUTE_Funcs() \\r
+ Compute_Funcs( EXEC_ARG )\r
+\r
+#define COMPUTE_Round( a ) \\r
+ Compute_Round( EXEC_ARG_ a )\r
+\r
+#define COMPUTE_Point_Displacement( a, b, c, d ) \\r
+ Compute_Point_Displacement( EXEC_ARG_ a, b, c, d )\r
+\r
+#define MOVE_Zp2_Point( a, b, c, t ) \\r
+ Move_Zp2_Point( EXEC_ARG_ a, b, c, t )\r
+\r
+\r
+#define CUR_Func_project( v1, v2 ) \\r
+ CUR.func_project( EXEC_ARG_ (v1)->x - (v2)->x, (v1)->y - (v2)->y )\r
+\r
+#define CUR_Func_dualproj( v1, v2 ) \\r
+ CUR.func_dualproj( EXEC_ARG_ (v1)->x - (v2)->x, (v1)->y - (v2)->y )\r
+\r
+#define CUR_fast_project( v ) \\r
+ CUR.func_project( EXEC_ARG_ (v)->x, (v)->y )\r
+\r
+#define CUR_fast_dualproj( v ) \\r
+ CUR.func_dualproj( EXEC_ARG_ (v)->x, (v)->y )\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* Instruction dispatch function, as used by the interpreter. */\r
+ /* */\r
+ typedef void (*TInstruction_Function)( INS_ARG );\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* A simple bounds-checking macro. */\r
+ /* */\r
+#define BOUNDS( x, n ) ( (FT_UInt)(x) >= (FT_UInt)(n) )\r
+\r
+#undef SUCCESS\r
+#define SUCCESS 0\r
+\r
+#undef FAILURE\r
+#define FAILURE 1\r
+\r
+#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING\r
+#define GUESS_VECTOR( V ) \\r
+ if ( CUR.face->unpatented_hinting ) \\r
+ { \\r
+ CUR.GS.V.x = (FT_F2Dot14)( CUR.GS.both_x_axis ? 0x4000 : 0 ); \\r
+ CUR.GS.V.y = (FT_F2Dot14)( CUR.GS.both_x_axis ? 0 : 0x4000 ); \\r
+ }\r
+#else\r
+#define GUESS_VECTOR( V )\r
+#endif\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* CODERANGE FUNCTIONS */\r
+ /* */\r
+ /*************************************************************************/\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* <Function> */\r
+ /* TT_Goto_CodeRange */\r
+ /* */\r
+ /* <Description> */\r
+ /* Switches to a new code range (updates the code related elements in */\r
+ /* `exec', and `IP'). */\r
+ /* */\r
+ /* <Input> */\r
+ /* range :: The new execution code range. */\r
+ /* */\r
+ /* IP :: The new IP in the new code range. */\r
+ /* */\r
+ /* <InOut> */\r
+ /* exec :: The target execution context. */\r
+ /* */\r
+ /* <Return> */\r
+ /* FreeType error code. 0 means success. */\r
+ /* */\r
+ FT_LOCAL_DEF( FT_Error )\r
+ TT_Goto_CodeRange( TT_ExecContext exec,\r
+ FT_Int range,\r
+ FT_Long IP )\r
+ {\r
+ TT_CodeRange* coderange;\r
+\r
+\r
+ FT_ASSERT( range >= 1 && range <= 3 );\r
+\r
+ coderange = &exec->codeRangeTable[range - 1];\r
+\r
+ FT_ASSERT( coderange->base != NULL );\r
+\r
+ /* NOTE: Because the last instruction of a program may be a CALL */\r
+ /* which will return to the first byte *after* the code */\r
+ /* range, we test for IP <= Size instead of IP < Size. */\r
+ /* */\r
+ FT_ASSERT( (FT_ULong)IP <= coderange->size );\r
+\r
+ exec->code = coderange->base;\r
+ exec->codeSize = coderange->size;\r
+ exec->IP = IP;\r
+ exec->curRange = range;\r
+\r
+ return TT_Err_Ok;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* <Function> */\r
+ /* TT_Set_CodeRange */\r
+ /* */\r
+ /* <Description> */\r
+ /* Sets a code range. */\r
+ /* */\r
+ /* <Input> */\r
+ /* range :: The code range index. */\r
+ /* */\r
+ /* base :: The new code base. */\r
+ /* */\r
+ /* length :: The range size in bytes. */\r
+ /* */\r
+ /* <InOut> */\r
+ /* exec :: The target execution context. */\r
+ /* */\r
+ /* <Return> */\r
+ /* FreeType error code. 0 means success. */\r
+ /* */\r
+ FT_LOCAL_DEF( FT_Error )\r
+ TT_Set_CodeRange( TT_ExecContext exec,\r
+ FT_Int range,\r
+ void* base,\r
+ FT_Long length )\r
+ {\r
+ FT_ASSERT( range >= 1 && range <= 3 );\r
+\r
+ exec->codeRangeTable[range - 1].base = (FT_Byte*)base;\r
+ exec->codeRangeTable[range - 1].size = length;\r
+\r
+ return TT_Err_Ok;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* <Function> */\r
+ /* TT_Clear_CodeRange */\r
+ /* */\r
+ /* <Description> */\r
+ /* Clears a code range. */\r
+ /* */\r
+ /* <Input> */\r
+ /* range :: The code range index. */\r
+ /* */\r
+ /* <InOut> */\r
+ /* exec :: The target execution context. */\r
+ /* */\r
+ /* <Return> */\r
+ /* FreeType error code. 0 means success. */\r
+ /* */\r
+ /* <Note> */\r
+ /* Does not set the Error variable. */\r
+ /* */\r
+ FT_LOCAL_DEF( FT_Error )\r
+ TT_Clear_CodeRange( TT_ExecContext exec,\r
+ FT_Int range )\r
+ {\r
+ FT_ASSERT( range >= 1 && range <= 3 );\r
+\r
+ exec->codeRangeTable[range - 1].base = NULL;\r
+ exec->codeRangeTable[range - 1].size = 0;\r
+\r
+ return TT_Err_Ok;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* EXECUTION CONTEXT ROUTINES */\r
+ /* */\r
+ /*************************************************************************/\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* <Function> */\r
+ /* TT_Done_Context */\r
+ /* */\r
+ /* <Description> */\r
+ /* Destroys a given context. */\r
+ /* */\r
+ /* <Input> */\r
+ /* exec :: A handle to the target execution context. */\r
+ /* */\r
+ /* memory :: A handle to the parent memory object. */\r
+ /* */\r
+ /* <Return> */\r
+ /* FreeType error code. 0 means success. */\r
+ /* */\r
+ /* <Note> */\r
+ /* Only the glyph loader and debugger should call this function. */\r
+ /* */\r
+ FT_LOCAL_DEF( FT_Error )\r
+ TT_Done_Context( TT_ExecContext exec )\r
+ {\r
+ FT_Memory memory = exec->memory;\r
+\r
+\r
+ /* points zone */\r
+ exec->maxPoints = 0;\r
+ exec->maxContours = 0;\r
+\r
+ /* free stack */\r
+ FT_FREE( exec->stack );\r
+ exec->stackSize = 0;\r
+\r
+ /* free call stack */\r
+ FT_FREE( exec->callStack );\r
+ exec->callSize = 0;\r
+ exec->callTop = 0;\r
+\r
+ /* free glyph code range */\r
+ FT_FREE( exec->glyphIns );\r
+ exec->glyphSize = 0;\r
+\r
+ exec->size = NULL;\r
+ exec->face = NULL;\r
+\r
+ FT_FREE( exec );\r
+\r
+ return TT_Err_Ok;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* <Function> */\r
+ /* Init_Context */\r
+ /* */\r
+ /* <Description> */\r
+ /* Initializes a context object. */\r
+ /* */\r
+ /* <Input> */\r
+ /* memory :: A handle to the parent memory object. */\r
+ /* */\r
+ /* <InOut> */\r
+ /* exec :: A handle to the target execution context. */\r
+ /* */\r
+ /* <Return> */\r
+ /* FreeType error code. 0 means success. */\r
+ /* */\r
+ static FT_Error\r
+ Init_Context( TT_ExecContext exec,\r
+ FT_Memory memory )\r
+ {\r
+ FT_Error error;\r
+\r
+\r
+ FT_TRACE1(( "Init_Context: new object at 0x%08p\n", exec ));\r
+\r
+ exec->memory = memory;\r
+ exec->callSize = 32;\r
+\r
+ if ( FT_NEW_ARRAY( exec->callStack, exec->callSize ) )\r
+ goto Fail_Memory;\r
+\r
+ /* all values in the context are set to 0 already, but this is */\r
+ /* here as a remainder */\r
+ exec->maxPoints = 0;\r
+ exec->maxContours = 0;\r
+\r
+ exec->stackSize = 0;\r
+ exec->glyphSize = 0;\r
+\r
+ exec->stack = NULL;\r
+ exec->glyphIns = NULL;\r
+\r
+ exec->face = NULL;\r
+ exec->size = NULL;\r
+\r
+ return TT_Err_Ok;\r
+\r
+ Fail_Memory:\r
+ FT_ERROR(( "Init_Context: not enough memory for 0x%08lx\n",\r
+ (FT_Long)exec ));\r
+ TT_Done_Context( exec );\r
+\r
+ return error;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* <Function> */\r
+ /* Update_Max */\r
+ /* */\r
+ /* <Description> */\r
+ /* Checks the size of a buffer and reallocates it if necessary. */\r
+ /* */\r
+ /* <Input> */\r
+ /* memory :: A handle to the parent memory object. */\r
+ /* */\r
+ /* multiplier :: The size in bytes of each element in the buffer. */\r
+ /* */\r
+ /* new_max :: The new capacity (size) of the buffer. */\r
+ /* */\r
+ /* <InOut> */\r
+ /* size :: The address of the buffer's current size expressed */\r
+ /* in elements. */\r
+ /* */\r
+ /* buff :: The address of the buffer base pointer. */\r
+ /* */\r
+ /* <Return> */\r
+ /* FreeType error code. 0 means success. */\r
+ /* */\r
+ static FT_Error\r
+ Update_Max( FT_Memory memory,\r
+ FT_ULong* size,\r
+ FT_Long multiplier,\r
+ void* _pbuff,\r
+ FT_ULong new_max )\r
+ {\r
+ FT_Error error;\r
+ void** pbuff = (void**)_pbuff;\r
+\r
+\r
+ if ( *size < new_max )\r
+ {\r
+ if ( FT_REALLOC( *pbuff, *size * multiplier, new_max * multiplier ) )\r
+ return error;\r
+ *size = new_max;\r
+ }\r
+\r
+ return TT_Err_Ok;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* <Function> */\r
+ /* TT_Load_Context */\r
+ /* */\r
+ /* <Description> */\r
+ /* Prepare an execution context for glyph hinting. */\r
+ /* */\r
+ /* <Input> */\r
+ /* face :: A handle to the source face object. */\r
+ /* */\r
+ /* size :: A handle to the source size object. */\r
+ /* */\r
+ /* <InOut> */\r
+ /* exec :: A handle to the target execution context. */\r
+ /* */\r
+ /* <Return> */\r
+ /* FreeType error code. 0 means success. */\r
+ /* */\r
+ /* <Note> */\r
+ /* Only the glyph loader and debugger should call this function. */\r
+ /* */\r
+ FT_LOCAL_DEF( FT_Error )\r
+ TT_Load_Context( TT_ExecContext exec,\r
+ TT_Face face,\r
+ TT_Size size )\r
+ {\r
+ FT_Int i;\r
+ FT_ULong tmp;\r
+ TT_MaxProfile* maxp;\r
+ FT_Error error;\r
+\r
+\r
+ exec->face = face;\r
+ maxp = &face->max_profile;\r
+ exec->size = size;\r
+\r
+ if ( size )\r
+ {\r
+ exec->numFDefs = size->num_function_defs;\r
+ exec->maxFDefs = size->max_function_defs;\r
+ exec->numIDefs = size->num_instruction_defs;\r
+ exec->maxIDefs = size->max_instruction_defs;\r
+ exec->FDefs = size->function_defs;\r
+ exec->IDefs = size->instruction_defs;\r
+ exec->tt_metrics = size->ttmetrics;\r
+ exec->metrics = size->metrics;\r
+\r
+ exec->maxFunc = size->max_func;\r
+ exec->maxIns = size->max_ins;\r
+\r
+ for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )\r
+ exec->codeRangeTable[i] = size->codeRangeTable[i];\r
+\r
+ /* set graphics state */\r
+ exec->GS = size->GS;\r
+\r
+ exec->cvtSize = size->cvt_size;\r
+ exec->cvt = size->cvt;\r
+\r
+ exec->storeSize = size->storage_size;\r
+ exec->storage = size->storage;\r
+\r
+ exec->twilight = size->twilight;\r
+ }\r
+\r
+ /* XXX: We reserve a little more elements on the stack to deal safely */\r
+ /* with broken fonts like arialbs, courbs, timesbs, etc. */\r
+ tmp = exec->stackSize;\r
+ error = Update_Max( exec->memory,\r
+ &tmp,\r
+ sizeof ( FT_F26Dot6 ),\r
+ (void*)&exec->stack,\r
+ maxp->maxStackElements + 32 );\r
+ exec->stackSize = (FT_UInt)tmp;\r
+ if ( error )\r
+ return error;\r
+\r
+ tmp = exec->glyphSize;\r
+ error = Update_Max( exec->memory,\r
+ &tmp,\r
+ sizeof ( FT_Byte ),\r
+ (void*)&exec->glyphIns,\r
+ maxp->maxSizeOfInstructions );\r
+ exec->glyphSize = (FT_UShort)tmp;\r
+ if ( error )\r
+ return error;\r
+\r
+ exec->pts.n_points = 0;\r
+ exec->pts.n_contours = 0;\r
+\r
+ exec->zp1 = exec->pts;\r
+ exec->zp2 = exec->pts;\r
+ exec->zp0 = exec->pts;\r
+\r
+ exec->instruction_trap = FALSE;\r
+\r
+ return TT_Err_Ok;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* <Function> */\r
+ /* TT_Save_Context */\r
+ /* */\r
+ /* <Description> */\r
+ /* Saves the code ranges in a `size' object. */\r
+ /* */\r
+ /* <Input> */\r
+ /* exec :: A handle to the source execution context. */\r
+ /* */\r
+ /* <InOut> */\r
+ /* size :: A handle to the target size object. */\r
+ /* */\r
+ /* <Return> */\r
+ /* FreeType error code. 0 means success. */\r
+ /* */\r
+ /* <Note> */\r
+ /* Only the glyph loader and debugger should call this function. */\r
+ /* */\r
+ FT_LOCAL_DEF( FT_Error )\r
+ TT_Save_Context( TT_ExecContext exec,\r
+ TT_Size size )\r
+ {\r
+ FT_Int i;\r
+\r
+\r
+ /* XXXX: Will probably disappear soon with all the code range */\r
+ /* management, which is now rather obsolete. */\r
+ /* */\r
+ size->num_function_defs = exec->numFDefs;\r
+ size->num_instruction_defs = exec->numIDefs;\r
+\r
+ size->max_func = exec->maxFunc;\r
+ size->max_ins = exec->maxIns;\r
+\r
+ for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )\r
+ size->codeRangeTable[i] = exec->codeRangeTable[i];\r
+\r
+ return TT_Err_Ok;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* <Function> */\r
+ /* TT_Run_Context */\r
+ /* */\r
+ /* <Description> */\r
+ /* Executes one or more instructions in the execution context. */\r
+ /* */\r
+ /* <Input> */\r
+ /* debug :: A Boolean flag. If set, the function sets some internal */\r
+ /* variables and returns immediately, otherwise TT_RunIns() */\r
+ /* is called. */\r
+ /* */\r
+ /* This is commented out currently. */\r
+ /* */\r
+ /* <Input> */\r
+ /* exec :: A handle to the target execution context. */\r
+ /* */\r
+ /* <Return> */\r
+ /* TrueTyoe error code. 0 means success. */\r
+ /* */\r
+ /* <Note> */\r
+ /* Only the glyph loader and debugger should call this function. */\r
+ /* */\r
+ FT_LOCAL_DEF( FT_Error )\r
+ TT_Run_Context( TT_ExecContext exec,\r
+ FT_Bool debug )\r
+ {\r
+ FT_Error error;\r
+\r
+\r
+ if ( ( error = TT_Goto_CodeRange( exec, tt_coderange_glyph, 0 ) )\r
+ != TT_Err_Ok )\r
+ return error;\r
+\r
+ exec->zp0 = exec->pts;\r
+ exec->zp1 = exec->pts;\r
+ exec->zp2 = exec->pts;\r
+\r
+ exec->GS.gep0 = 1;\r
+ exec->GS.gep1 = 1;\r
+ exec->GS.gep2 = 1;\r
+\r
+ exec->GS.projVector.x = 0x4000;\r
+ exec->GS.projVector.y = 0x0000;\r
+\r
+ exec->GS.freeVector = exec->GS.projVector;\r
+ exec->GS.dualVector = exec->GS.projVector;\r
+\r
+#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING\r
+ exec->GS.both_x_axis = TRUE;\r
+#endif\r
+\r
+ exec->GS.round_state = 1;\r
+ exec->GS.loop = 1;\r
+\r
+ /* some glyphs leave something on the stack. so we clean it */\r
+ /* before a new execution. */\r
+ exec->top = 0;\r
+ exec->callTop = 0;\r
+\r
+#if 1\r
+ FT_UNUSED( debug );\r
+\r
+ return exec->face->interpreter( exec );\r
+#else\r
+ if ( !debug )\r
+ return TT_RunIns( exec );\r
+ else\r
+ return TT_Err_Ok;\r
+#endif\r
+ }\r
+\r
+\r
+ const TT_GraphicsState tt_default_graphics_state =\r
+ {\r
+ 0, 0, 0,\r
+ { 0x4000, 0 },\r
+ { 0x4000, 0 },\r
+ { 0x4000, 0 },\r
+\r
+#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING\r
+ TRUE,\r
+#endif\r
+\r
+ 1, 64, 1,\r
+ TRUE, 68, 0, 0, 9, 3,\r
+ 0, FALSE, 2, 1, 1, 1\r
+ };\r
+\r
+\r
+ /* documentation is in ttinterp.h */\r
+\r
+ FT_EXPORT_DEF( TT_ExecContext )\r
+ TT_New_Context( TT_Driver driver )\r
+ {\r
+ TT_ExecContext exec;\r
+ FT_Memory memory;\r
+\r
+\r
+ memory = driver->root.root.memory;\r
+ exec = driver->context;\r
+\r
+ if ( !driver->context )\r
+ {\r
+ FT_Error error;\r
+\r
+\r
+ /* allocate object */\r
+ if ( FT_NEW( exec ) )\r
+ goto Exit;\r
+\r
+ /* initialize it */\r
+ error = Init_Context( exec, memory );\r
+ if ( error )\r
+ goto Fail;\r
+\r
+ /* store it into the driver */\r
+ driver->context = exec;\r
+ }\r
+\r
+ Exit:\r
+ return driver->context;\r
+\r
+ Fail:\r
+ FT_FREE( exec );\r
+\r
+ return 0;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* Before an opcode is executed, the interpreter verifies that there are */\r
+ /* enough arguments on the stack, with the help of the `Pop_Push_Count' */\r
+ /* table. */\r
+ /* */\r
+ /* For each opcode, the first column gives the number of arguments that */\r
+ /* are popped from the stack; the second one gives the number of those */\r
+ /* that are pushed in result. */\r
+ /* */\r
+ /* Opcodes which have a varying number of parameters in the data stream */\r
+ /* (NPUSHB, NPUSHW) are handled specially; they have a negative value in */\r
+ /* the `opcode_length' table, and the value in `Pop_Push_Count' is set */\r
+ /* to zero. */\r
+ /* */\r
+ /*************************************************************************/\r
+\r
+\r
+#undef PACK\r
+#define PACK( x, y ) ( ( x << 4 ) | y )\r
+\r
+\r
+ static\r
+ const FT_Byte Pop_Push_Count[256] =\r
+ {\r
+ /* opcodes are gathered in groups of 16 */\r
+ /* please keep the spaces as they are */\r
+\r
+ /* SVTCA y */ PACK( 0, 0 ),\r
+ /* SVTCA x */ PACK( 0, 0 ),\r
+ /* SPvTCA y */ PACK( 0, 0 ),\r
+ /* SPvTCA x */ PACK( 0, 0 ),\r
+ /* SFvTCA y */ PACK( 0, 0 ),\r
+ /* SFvTCA x */ PACK( 0, 0 ),\r
+ /* SPvTL // */ PACK( 2, 0 ),\r
+ /* SPvTL + */ PACK( 2, 0 ),\r
+ /* SFvTL // */ PACK( 2, 0 ),\r
+ /* SFvTL + */ PACK( 2, 0 ),\r
+ /* SPvFS */ PACK( 2, 0 ),\r
+ /* SFvFS */ PACK( 2, 0 ),\r
+ /* GPV */ PACK( 0, 2 ),\r
+ /* GFV */ PACK( 0, 2 ),\r
+ /* SFvTPv */ PACK( 0, 0 ),\r
+ /* ISECT */ PACK( 5, 0 ),\r
+\r
+ /* SRP0 */ PACK( 1, 0 ),\r
+ /* SRP1 */ PACK( 1, 0 ),\r
+ /* SRP2 */ PACK( 1, 0 ),\r
+ /* SZP0 */ PACK( 1, 0 ),\r
+ /* SZP1 */ PACK( 1, 0 ),\r
+ /* SZP2 */ PACK( 1, 0 ),\r
+ /* SZPS */ PACK( 1, 0 ),\r
+ /* SLOOP */ PACK( 1, 0 ),\r
+ /* RTG */ PACK( 0, 0 ),\r
+ /* RTHG */ PACK( 0, 0 ),\r
+ /* SMD */ PACK( 1, 0 ),\r
+ /* ELSE */ PACK( 0, 0 ),\r
+ /* JMPR */ PACK( 1, 0 ),\r
+ /* SCvTCi */ PACK( 1, 0 ),\r
+ /* SSwCi */ PACK( 1, 0 ),\r
+ /* SSW */ PACK( 1, 0 ),\r
+\r
+ /* DUP */ PACK( 1, 2 ),\r
+ /* POP */ PACK( 1, 0 ),\r
+ /* CLEAR */ PACK( 0, 0 ),\r
+ /* SWAP */ PACK( 2, 2 ),\r
+ /* DEPTH */ PACK( 0, 1 ),\r
+ /* CINDEX */ PACK( 1, 1 ),\r
+ /* MINDEX */ PACK( 1, 0 ),\r
+ /* AlignPTS */ PACK( 2, 0 ),\r
+ /* INS_$28 */ PACK( 0, 0 ),\r
+ /* UTP */ PACK( 1, 0 ),\r
+ /* LOOPCALL */ PACK( 2, 0 ),\r
+ /* CALL */ PACK( 1, 0 ),\r
+ /* FDEF */ PACK( 1, 0 ),\r
+ /* ENDF */ PACK( 0, 0 ),\r
+ /* MDAP[0] */ PACK( 1, 0 ),\r
+ /* MDAP[1] */ PACK( 1, 0 ),\r
+\r
+ /* IUP[0] */ PACK( 0, 0 ),\r
+ /* IUP[1] */ PACK( 0, 0 ),\r
+ /* SHP[0] */ PACK( 0, 0 ),\r
+ /* SHP[1] */ PACK( 0, 0 ),\r
+ /* SHC[0] */ PACK( 1, 0 ),\r
+ /* SHC[1] */ PACK( 1, 0 ),\r
+ /* SHZ[0] */ PACK( 1, 0 ),\r
+ /* SHZ[1] */ PACK( 1, 0 ),\r
+ /* SHPIX */ PACK( 1, 0 ),\r
+ /* IP */ PACK( 0, 0 ),\r
+ /* MSIRP[0] */ PACK( 2, 0 ),\r
+ /* MSIRP[1] */ PACK( 2, 0 ),\r
+ /* AlignRP */ PACK( 0, 0 ),\r
+ /* RTDG */ PACK( 0, 0 ),\r
+ /* MIAP[0] */ PACK( 2, 0 ),\r
+ /* MIAP[1] */ PACK( 2, 0 ),\r
+\r
+ /* NPushB */ PACK( 0, 0 ),\r
+ /* NPushW */ PACK( 0, 0 ),\r
+ /* WS */ PACK( 2, 0 ),\r
+ /* RS */ PACK( 1, 1 ),\r
+ /* WCvtP */ PACK( 2, 0 ),\r
+ /* RCvt */ PACK( 1, 1 ),\r
+ /* GC[0] */ PACK( 1, 1 ),\r
+ /* GC[1] */ PACK( 1, 1 ),\r
+ /* SCFS */ PACK( 2, 0 ),\r
+ /* MD[0] */ PACK( 2, 1 ),\r
+ /* MD[1] */ PACK( 2, 1 ),\r
+ /* MPPEM */ PACK( 0, 1 ),\r
+ /* MPS */ PACK( 0, 1 ),\r
+ /* FlipON */ PACK( 0, 0 ),\r
+ /* FlipOFF */ PACK( 0, 0 ),\r
+ /* DEBUG */ PACK( 1, 0 ),\r
+\r
+ /* LT */ PACK( 2, 1 ),\r
+ /* LTEQ */ PACK( 2, 1 ),\r
+ /* GT */ PACK( 2, 1 ),\r
+ /* GTEQ */ PACK( 2, 1 ),\r
+ /* EQ */ PACK( 2, 1 ),\r
+ /* NEQ */ PACK( 2, 1 ),\r
+ /* ODD */ PACK( 1, 1 ),\r
+ /* EVEN */ PACK( 1, 1 ),\r
+ /* IF */ PACK( 1, 0 ),\r
+ /* EIF */ PACK( 0, 0 ),\r
+ /* AND */ PACK( 2, 1 ),\r
+ /* OR */ PACK( 2, 1 ),\r
+ /* NOT */ PACK( 1, 1 ),\r
+ /* DeltaP1 */ PACK( 1, 0 ),\r
+ /* SDB */ PACK( 1, 0 ),\r
+ /* SDS */ PACK( 1, 0 ),\r
+\r
+ /* ADD */ PACK( 2, 1 ),\r
+ /* SUB */ PACK( 2, 1 ),\r
+ /* DIV */ PACK( 2, 1 ),\r
+ /* MUL */ PACK( 2, 1 ),\r
+ /* ABS */ PACK( 1, 1 ),\r
+ /* NEG */ PACK( 1, 1 ),\r
+ /* FLOOR */ PACK( 1, 1 ),\r
+ /* CEILING */ PACK( 1, 1 ),\r
+ /* ROUND[0] */ PACK( 1, 1 ),\r
+ /* ROUND[1] */ PACK( 1, 1 ),\r
+ /* ROUND[2] */ PACK( 1, 1 ),\r
+ /* ROUND[3] */ PACK( 1, 1 ),\r
+ /* NROUND[0] */ PACK( 1, 1 ),\r
+ /* NROUND[1] */ PACK( 1, 1 ),\r
+ /* NROUND[2] */ PACK( 1, 1 ),\r
+ /* NROUND[3] */ PACK( 1, 1 ),\r
+\r
+ /* WCvtF */ PACK( 2, 0 ),\r
+ /* DeltaP2 */ PACK( 1, 0 ),\r
+ /* DeltaP3 */ PACK( 1, 0 ),\r
+ /* DeltaCn[0] */ PACK( 1, 0 ),\r
+ /* DeltaCn[1] */ PACK( 1, 0 ),\r
+ /* DeltaCn[2] */ PACK( 1, 0 ),\r
+ /* SROUND */ PACK( 1, 0 ),\r
+ /* S45Round */ PACK( 1, 0 ),\r
+ /* JROT */ PACK( 2, 0 ),\r
+ /* JROF */ PACK( 2, 0 ),\r
+ /* ROFF */ PACK( 0, 0 ),\r
+ /* INS_$7B */ PACK( 0, 0 ),\r
+ /* RUTG */ PACK( 0, 0 ),\r
+ /* RDTG */ PACK( 0, 0 ),\r
+ /* SANGW */ PACK( 1, 0 ),\r
+ /* AA */ PACK( 1, 0 ),\r
+\r
+ /* FlipPT */ PACK( 0, 0 ),\r
+ /* FlipRgON */ PACK( 2, 0 ),\r
+ /* FlipRgOFF */ PACK( 2, 0 ),\r
+ /* INS_$83 */ PACK( 0, 0 ),\r
+ /* INS_$84 */ PACK( 0, 0 ),\r
+ /* ScanCTRL */ PACK( 1, 0 ),\r
+ /* SDVPTL[0] */ PACK( 2, 0 ),\r
+ /* SDVPTL[1] */ PACK( 2, 0 ),\r
+ /* GetINFO */ PACK( 1, 1 ),\r
+ /* IDEF */ PACK( 1, 0 ),\r
+ /* ROLL */ PACK( 3, 3 ),\r
+ /* MAX */ PACK( 2, 1 ),\r
+ /* MIN */ PACK( 2, 1 ),\r
+ /* ScanTYPE */ PACK( 1, 0 ),\r
+ /* InstCTRL */ PACK( 2, 0 ),\r
+ /* INS_$8F */ PACK( 0, 0 ),\r
+\r
+ /* INS_$90 */ PACK( 0, 0 ),\r
+ /* INS_$91 */ PACK( 0, 0 ),\r
+ /* INS_$92 */ PACK( 0, 0 ),\r
+ /* INS_$93 */ PACK( 0, 0 ),\r
+ /* INS_$94 */ PACK( 0, 0 ),\r
+ /* INS_$95 */ PACK( 0, 0 ),\r
+ /* INS_$96 */ PACK( 0, 0 ),\r
+ /* INS_$97 */ PACK( 0, 0 ),\r
+ /* INS_$98 */ PACK( 0, 0 ),\r
+ /* INS_$99 */ PACK( 0, 0 ),\r
+ /* INS_$9A */ PACK( 0, 0 ),\r
+ /* INS_$9B */ PACK( 0, 0 ),\r
+ /* INS_$9C */ PACK( 0, 0 ),\r
+ /* INS_$9D */ PACK( 0, 0 ),\r
+ /* INS_$9E */ PACK( 0, 0 ),\r
+ /* INS_$9F */ PACK( 0, 0 ),\r
+\r
+ /* INS_$A0 */ PACK( 0, 0 ),\r
+ /* INS_$A1 */ PACK( 0, 0 ),\r
+ /* INS_$A2 */ PACK( 0, 0 ),\r
+ /* INS_$A3 */ PACK( 0, 0 ),\r
+ /* INS_$A4 */ PACK( 0, 0 ),\r
+ /* INS_$A5 */ PACK( 0, 0 ),\r
+ /* INS_$A6 */ PACK( 0, 0 ),\r
+ /* INS_$A7 */ PACK( 0, 0 ),\r
+ /* INS_$A8 */ PACK( 0, 0 ),\r
+ /* INS_$A9 */ PACK( 0, 0 ),\r
+ /* INS_$AA */ PACK( 0, 0 ),\r
+ /* INS_$AB */ PACK( 0, 0 ),\r
+ /* INS_$AC */ PACK( 0, 0 ),\r
+ /* INS_$AD */ PACK( 0, 0 ),\r
+ /* INS_$AE */ PACK( 0, 0 ),\r
+ /* INS_$AF */ PACK( 0, 0 ),\r
+\r
+ /* PushB[0] */ PACK( 0, 1 ),\r
+ /* PushB[1] */ PACK( 0, 2 ),\r
+ /* PushB[2] */ PACK( 0, 3 ),\r
+ /* PushB[3] */ PACK( 0, 4 ),\r
+ /* PushB[4] */ PACK( 0, 5 ),\r
+ /* PushB[5] */ PACK( 0, 6 ),\r
+ /* PushB[6] */ PACK( 0, 7 ),\r
+ /* PushB[7] */ PACK( 0, 8 ),\r
+ /* PushW[0] */ PACK( 0, 1 ),\r
+ /* PushW[1] */ PACK( 0, 2 ),\r
+ /* PushW[2] */ PACK( 0, 3 ),\r
+ /* PushW[3] */ PACK( 0, 4 ),\r
+ /* PushW[4] */ PACK( 0, 5 ),\r
+ /* PushW[5] */ PACK( 0, 6 ),\r
+ /* PushW[6] */ PACK( 0, 7 ),\r
+ /* PushW[7] */ PACK( 0, 8 ),\r
+\r
+ /* MDRP[00] */ PACK( 1, 0 ),\r
+ /* MDRP[01] */ PACK( 1, 0 ),\r
+ /* MDRP[02] */ PACK( 1, 0 ),\r
+ /* MDRP[03] */ PACK( 1, 0 ),\r
+ /* MDRP[04] */ PACK( 1, 0 ),\r
+ /* MDRP[05] */ PACK( 1, 0 ),\r
+ /* MDRP[06] */ PACK( 1, 0 ),\r
+ /* MDRP[07] */ PACK( 1, 0 ),\r
+ /* MDRP[08] */ PACK( 1, 0 ),\r
+ /* MDRP[09] */ PACK( 1, 0 ),\r
+ /* MDRP[10] */ PACK( 1, 0 ),\r
+ /* MDRP[11] */ PACK( 1, 0 ),\r
+ /* MDRP[12] */ PACK( 1, 0 ),\r
+ /* MDRP[13] */ PACK( 1, 0 ),\r
+ /* MDRP[14] */ PACK( 1, 0 ),\r
+ /* MDRP[15] */ PACK( 1, 0 ),\r
+\r
+ /* MDRP[16] */ PACK( 1, 0 ),\r
+ /* MDRP[17] */ PACK( 1, 0 ),\r
+ /* MDRP[18] */ PACK( 1, 0 ),\r
+ /* MDRP[19] */ PACK( 1, 0 ),\r
+ /* MDRP[20] */ PACK( 1, 0 ),\r
+ /* MDRP[21] */ PACK( 1, 0 ),\r
+ /* MDRP[22] */ PACK( 1, 0 ),\r
+ /* MDRP[23] */ PACK( 1, 0 ),\r
+ /* MDRP[24] */ PACK( 1, 0 ),\r
+ /* MDRP[25] */ PACK( 1, 0 ),\r
+ /* MDRP[26] */ PACK( 1, 0 ),\r
+ /* MDRP[27] */ PACK( 1, 0 ),\r
+ /* MDRP[28] */ PACK( 1, 0 ),\r
+ /* MDRP[29] */ PACK( 1, 0 ),\r
+ /* MDRP[30] */ PACK( 1, 0 ),\r
+ /* MDRP[31] */ PACK( 1, 0 ),\r
+\r
+ /* MIRP[00] */ PACK( 2, 0 ),\r
+ /* MIRP[01] */ PACK( 2, 0 ),\r
+ /* MIRP[02] */ PACK( 2, 0 ),\r
+ /* MIRP[03] */ PACK( 2, 0 ),\r
+ /* MIRP[04] */ PACK( 2, 0 ),\r
+ /* MIRP[05] */ PACK( 2, 0 ),\r
+ /* MIRP[06] */ PACK( 2, 0 ),\r
+ /* MIRP[07] */ PACK( 2, 0 ),\r
+ /* MIRP[08] */ PACK( 2, 0 ),\r
+ /* MIRP[09] */ PACK( 2, 0 ),\r
+ /* MIRP[10] */ PACK( 2, 0 ),\r
+ /* MIRP[11] */ PACK( 2, 0 ),\r
+ /* MIRP[12] */ PACK( 2, 0 ),\r
+ /* MIRP[13] */ PACK( 2, 0 ),\r
+ /* MIRP[14] */ PACK( 2, 0 ),\r
+ /* MIRP[15] */ PACK( 2, 0 ),\r
+\r
+ /* MIRP[16] */ PACK( 2, 0 ),\r
+ /* MIRP[17] */ PACK( 2, 0 ),\r
+ /* MIRP[18] */ PACK( 2, 0 ),\r
+ /* MIRP[19] */ PACK( 2, 0 ),\r
+ /* MIRP[20] */ PACK( 2, 0 ),\r
+ /* MIRP[21] */ PACK( 2, 0 ),\r
+ /* MIRP[22] */ PACK( 2, 0 ),\r
+ /* MIRP[23] */ PACK( 2, 0 ),\r
+ /* MIRP[24] */ PACK( 2, 0 ),\r
+ /* MIRP[25] */ PACK( 2, 0 ),\r
+ /* MIRP[26] */ PACK( 2, 0 ),\r
+ /* MIRP[27] */ PACK( 2, 0 ),\r
+ /* MIRP[28] */ PACK( 2, 0 ),\r
+ /* MIRP[29] */ PACK( 2, 0 ),\r
+ /* MIRP[30] */ PACK( 2, 0 ),\r
+ /* MIRP[31] */ PACK( 2, 0 )\r
+ };\r
+\r
+\r
+ static\r
+ const FT_Char opcode_length[256] =\r
+ {\r
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
+\r
+ -1,-2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
+\r
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
+ 2, 3, 4, 5, 6, 7, 8, 9, 3, 5, 7, 9, 11,13,15,17,\r
+\r
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1\r
+ };\r
+\r
+#undef PACK\r
+\r
+#if 1\r
+\r
+ static FT_Int32\r
+ TT_MulFix14( FT_Int32 a,\r
+ FT_Int b )\r
+ {\r
+ FT_Int32 sign;\r
+ FT_UInt32 ah, al, mid, lo, hi;\r
+\r
+\r
+ sign = a ^ b;\r
+\r
+ if ( a < 0 )\r
+ a = -a;\r
+ if ( b < 0 )\r
+ b = -b;\r
+\r
+ ah = (FT_UInt32)( ( a >> 16 ) & 0xFFFFU );\r
+ al = (FT_UInt32)( a & 0xFFFFU );\r
+\r
+ lo = al * b;\r
+ mid = ah * b;\r
+ hi = mid >> 16;\r
+ mid = ( mid << 16 ) + ( 1 << 13 ); /* rounding */\r
+ lo += mid;\r
+ if ( lo < mid )\r
+ hi += 1;\r
+\r
+ mid = ( lo >> 14 ) | ( hi << 18 );\r
+\r
+ return sign >= 0 ? (FT_Int32)mid : -(FT_Int32)mid;\r
+ }\r
+\r
+#else\r
+\r
+ /* compute (a*b)/2^14 with maximal accuracy and rounding */\r
+ static FT_Int32\r
+ TT_MulFix14( FT_Int32 a,\r
+ FT_Int b )\r
+ {\r
+ FT_Int32 m, s, hi;\r
+ FT_UInt32 l, lo;\r
+\r
+\r
+ /* compute ax*bx as 64-bit value */\r
+ l = (FT_UInt32)( ( a & 0xFFFFU ) * b );\r
+ m = ( a >> 16 ) * b;\r
+\r
+ lo = l + (FT_UInt32)( m << 16 );\r
+ hi = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo < l );\r
+\r
+ /* divide the result by 2^14 with rounding */\r
+ s = hi >> 31;\r
+ l = lo + (FT_UInt32)s;\r
+ hi += s + ( l < lo );\r
+ lo = l;\r
+\r
+ l = lo + 0x2000U;\r
+ hi += l < lo;\r
+\r
+ return ( hi << 18 ) | ( l >> 14 );\r
+ }\r
+#endif\r
+\r
+\r
+ /* compute (ax*bx+ay*by)/2^14 with maximal accuracy and rounding */\r
+ static FT_Int32\r
+ TT_DotFix14( FT_Int32 ax,\r
+ FT_Int32 ay,\r
+ FT_Int bx,\r
+ FT_Int by )\r
+ {\r
+ FT_Int32 m, s, hi1, hi2, hi;\r
+ FT_UInt32 l, lo1, lo2, lo;\r
+\r
+\r
+ /* compute ax*bx as 64-bit value */\r
+ l = (FT_UInt32)( ( ax & 0xFFFFU ) * bx );\r
+ m = ( ax >> 16 ) * bx;\r
+\r
+ lo1 = l + (FT_UInt32)( m << 16 );\r
+ hi1 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo1 < l );\r
+\r
+ /* compute ay*by as 64-bit value */\r
+ l = (FT_UInt32)( ( ay & 0xFFFFU ) * by );\r
+ m = ( ay >> 16 ) * by;\r
+\r
+ lo2 = l + (FT_UInt32)( m << 16 );\r
+ hi2 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo2 < l );\r
+\r
+ /* add them */\r
+ lo = lo1 + lo2;\r
+ hi = hi1 + hi2 + ( lo < lo1 );\r
+\r
+ /* divide the result by 2^14 with rounding */\r
+ s = hi >> 31;\r
+ l = lo + (FT_UInt32)s;\r
+ hi += s + ( l < lo );\r
+ lo = l;\r
+\r
+ l = lo + 0x2000U;\r
+ hi += ( l < lo );\r
+\r
+ return ( hi << 18 ) | ( l >> 14 );\r
+ }\r
+\r
+\r
+ /* return length of given vector */\r
+\r
+#if 0\r
+\r
+ static FT_Int32\r
+ TT_VecLen( FT_Int32 x,\r
+ FT_Int32 y )\r
+ {\r
+ FT_Int32 m, hi1, hi2, hi;\r
+ FT_UInt32 l, lo1, lo2, lo;\r
+\r
+\r
+ /* compute x*x as 64-bit value */\r
+ lo = (FT_UInt32)( x & 0xFFFFU );\r
+ hi = x >> 16;\r
+\r
+ l = lo * lo;\r
+ m = hi * lo;\r
+ hi = hi * hi;\r
+\r
+ lo1 = l + (FT_UInt32)( m << 17 );\r
+ hi1 = hi + ( m >> 15 ) + ( lo1 < l );\r
+\r
+ /* compute y*y as 64-bit value */\r
+ lo = (FT_UInt32)( y & 0xFFFFU );\r
+ hi = y >> 16;\r
+\r
+ l = lo * lo;\r
+ m = hi * lo;\r
+ hi = hi * hi;\r
+\r
+ lo2 = l + (FT_UInt32)( m << 17 );\r
+ hi2 = hi + ( m >> 15 ) + ( lo2 < l );\r
+\r
+ /* add them to get 'x*x+y*y' as 64-bit value */\r
+ lo = lo1 + lo2;\r
+ hi = hi1 + hi2 + ( lo < lo1 );\r
+\r
+ /* compute the square root of this value */\r
+ {\r
+ FT_UInt32 root, rem, test_div;\r
+ FT_Int count;\r
+\r
+\r
+ root = 0;\r
+\r
+ {\r
+ rem = 0;\r
+ count = 32;\r
+ do\r
+ {\r
+ rem = ( rem << 2 ) | ( (FT_UInt32)hi >> 30 );\r
+ hi = ( hi << 2 ) | ( lo >> 30 );\r
+ lo <<= 2;\r
+ root <<= 1;\r
+ test_div = ( root << 1 ) + 1;\r
+\r
+ if ( rem >= test_div )\r
+ {\r
+ rem -= test_div;\r
+ root += 1;\r
+ }\r
+ } while ( --count );\r
+ }\r
+\r
+ return (FT_Int32)root;\r
+ }\r
+ }\r
+\r
+#else\r
+\r
+ /* this version uses FT_Vector_Length which computes the same value */\r
+ /* much, much faster.. */\r
+ /* */\r
+ static FT_F26Dot6\r
+ TT_VecLen( FT_F26Dot6 X,\r
+ FT_F26Dot6 Y )\r
+ {\r
+ FT_Vector v;\r
+\r
+\r
+ v.x = X;\r
+ v.y = Y;\r
+\r
+ return FT_Vector_Length( &v );\r
+ }\r
+\r
+#endif\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* <Function> */\r
+ /* Current_Ratio */\r
+ /* */\r
+ /* <Description> */\r
+ /* Returns the current aspect ratio scaling factor depending on the */\r
+ /* projection vector's state and device resolutions. */\r
+ /* */\r
+ /* <Return> */\r
+ /* The aspect ratio in 16.16 format, always <= 1.0 . */\r
+ /* */\r
+ static FT_Long\r
+ Current_Ratio( EXEC_OP )\r
+ {\r
+ if ( !CUR.tt_metrics.ratio )\r
+ {\r
+#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING\r
+ if ( CUR.face->unpatented_hinting )\r
+ {\r
+ if ( CUR.GS.both_x_axis )\r
+ CUR.tt_metrics.ratio = CUR.tt_metrics.x_ratio;\r
+ else\r
+ CUR.tt_metrics.ratio = CUR.tt_metrics.y_ratio;\r
+ }\r
+ else\r
+#endif\r
+ {\r
+ if ( CUR.GS.projVector.y == 0 )\r
+ CUR.tt_metrics.ratio = CUR.tt_metrics.x_ratio;\r
+\r
+ else if ( CUR.GS.projVector.x == 0 )\r
+ CUR.tt_metrics.ratio = CUR.tt_metrics.y_ratio;\r
+\r
+ else\r
+ {\r
+ FT_Long x, y;\r
+\r
+\r
+ x = TT_MULDIV( CUR.GS.projVector.x,\r
+ CUR.tt_metrics.x_ratio, 0x4000 );\r
+ y = TT_MULDIV( CUR.GS.projVector.y,\r
+ CUR.tt_metrics.y_ratio, 0x4000 );\r
+ CUR.tt_metrics.ratio = TT_VecLen( x, y );\r
+ }\r
+ }\r
+ }\r
+ return CUR.tt_metrics.ratio;\r
+ }\r
+\r
+\r
+ static FT_Long\r
+ Current_Ppem( EXEC_OP )\r
+ {\r
+ return TT_MULFIX( CUR.tt_metrics.ppem, CURRENT_Ratio() );\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* Functions related to the control value table (CVT). */\r
+ /* */\r
+ /*************************************************************************/\r
+\r
+\r
+ FT_CALLBACK_DEF( FT_F26Dot6 )\r
+ Read_CVT( EXEC_OP_ FT_ULong idx )\r
+ {\r
+ return CUR.cvt[idx];\r
+ }\r
+\r
+\r
+ FT_CALLBACK_DEF( FT_F26Dot6 )\r
+ Read_CVT_Stretched( EXEC_OP_ FT_ULong idx )\r
+ {\r
+ return TT_MULFIX( CUR.cvt[idx], CURRENT_Ratio() );\r
+ }\r
+\r
+\r
+ FT_CALLBACK_DEF( void )\r
+ Write_CVT( EXEC_OP_ FT_ULong idx,\r
+ FT_F26Dot6 value )\r
+ {\r
+ CUR.cvt[idx] = value;\r
+ }\r
+\r
+\r
+ FT_CALLBACK_DEF( void )\r
+ Write_CVT_Stretched( EXEC_OP_ FT_ULong idx,\r
+ FT_F26Dot6 value )\r
+ {\r
+ CUR.cvt[idx] = FT_DivFix( value, CURRENT_Ratio() );\r
+ }\r
+\r
+\r
+ FT_CALLBACK_DEF( void )\r
+ Move_CVT( EXEC_OP_ FT_ULong idx,\r
+ FT_F26Dot6 value )\r
+ {\r
+ CUR.cvt[idx] += value;\r
+ }\r
+\r
+\r
+ FT_CALLBACK_DEF( void )\r
+ Move_CVT_Stretched( EXEC_OP_ FT_ULong idx,\r
+ FT_F26Dot6 value )\r
+ {\r
+ CUR.cvt[idx] += FT_DivFix( value, CURRENT_Ratio() );\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* <Function> */\r
+ /* GetShortIns */\r
+ /* */\r
+ /* <Description> */\r
+ /* Returns a short integer taken from the instruction stream at */\r
+ /* address IP. */\r
+ /* */\r
+ /* <Return> */\r
+ /* Short read at code[IP]. */\r
+ /* */\r
+ /* <Note> */\r
+ /* This one could become a macro. */\r
+ /* */\r
+ static FT_Short\r
+ GetShortIns( EXEC_OP )\r
+ {\r
+ /* Reading a byte stream so there is no endianess (DaveP) */\r
+ CUR.IP += 2;\r
+ return (FT_Short)( ( CUR.code[CUR.IP - 2] << 8 ) +\r
+ CUR.code[CUR.IP - 1] );\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* <Function> */\r
+ /* Ins_Goto_CodeRange */\r
+ /* */\r
+ /* <Description> */\r
+ /* Goes to a certain code range in the instruction stream. */\r
+ /* */\r
+ /* <Input> */\r
+ /* aRange :: The index of the code range. */\r
+ /* */\r
+ /* aIP :: The new IP address in the code range. */\r
+ /* */\r
+ /* <Return> */\r
+ /* SUCCESS or FAILURE. */\r
+ /* */\r
+ static FT_Bool\r
+ Ins_Goto_CodeRange( EXEC_OP_ FT_Int aRange,\r
+ FT_ULong aIP )\r
+ {\r
+ TT_CodeRange* range;\r
+\r
+\r
+ if ( aRange < 1 || aRange > 3 )\r
+ {\r
+ CUR.error = TT_Err_Bad_Argument;\r
+ return FAILURE;\r
+ }\r
+\r
+ range = &CUR.codeRangeTable[aRange - 1];\r
+\r
+ if ( range->base == NULL ) /* invalid coderange */\r
+ {\r
+ CUR.error = TT_Err_Invalid_CodeRange;\r
+ return FAILURE;\r
+ }\r
+\r
+ /* NOTE: Because the last instruction of a program may be a CALL */\r
+ /* which will return to the first byte *after* the code */\r
+ /* range, we test for AIP <= Size, instead of AIP < Size. */\r
+\r
+ if ( aIP > range->size )\r
+ {\r
+ CUR.error = TT_Err_Code_Overflow;\r
+ return FAILURE;\r
+ }\r
+\r
+ CUR.code = range->base;\r
+ CUR.codeSize = range->size;\r
+ CUR.IP = aIP;\r
+ CUR.curRange = aRange;\r
+\r
+ return SUCCESS;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* <Function> */\r
+ /* Direct_Move */\r
+ /* */\r
+ /* <Description> */\r
+ /* Moves a point by a given distance along the freedom vector. The */\r
+ /* point will be `touched'. */\r
+ /* */\r
+ /* <Input> */\r
+ /* point :: The index of the point to move. */\r
+ /* */\r
+ /* distance :: The distance to apply. */\r
+ /* */\r
+ /* <InOut> */\r
+ /* zone :: The affected glyph zone. */\r
+ /* */\r
+ static void\r
+ Direct_Move( EXEC_OP_ TT_GlyphZone zone,\r
+ FT_UShort point,\r
+ FT_F26Dot6 distance )\r
+ {\r
+ FT_F26Dot6 v;\r
+\r
+\r
+#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING\r
+ FT_ASSERT( !CUR.face->unpatented_hinting );\r
+#endif\r
+\r
+ v = CUR.GS.freeVector.x;\r
+\r
+ if ( v != 0 )\r
+ {\r
+ zone->cur[point].x += TT_MULDIV( distance,\r
+ v * 0x10000L,\r
+ CUR.F_dot_P );\r
+\r
+ zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;\r
+ }\r
+\r
+ v = CUR.GS.freeVector.y;\r
+\r
+ if ( v != 0 )\r
+ {\r
+ zone->cur[point].y += TT_MULDIV( distance,\r
+ v * 0x10000L,\r
+ CUR.F_dot_P );\r
+\r
+ zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;\r
+ }\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* <Function> */\r
+ /* Direct_Move_Orig */\r
+ /* */\r
+ /* <Description> */\r
+ /* Moves the *original* position of a point by a given distance along */\r
+ /* the freedom vector. Obviously, the point will not be `touched'. */\r
+ /* */\r
+ /* <Input> */\r
+ /* point :: The index of the point to move. */\r
+ /* */\r
+ /* distance :: The distance to apply. */\r
+ /* */\r
+ /* <InOut> */\r
+ /* zone :: The affected glyph zone. */\r
+ /* */\r
+ static void\r
+ Direct_Move_Orig( EXEC_OP_ TT_GlyphZone zone,\r
+ FT_UShort point,\r
+ FT_F26Dot6 distance )\r
+ {\r
+ FT_F26Dot6 v;\r
+\r
+\r
+#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING\r
+ FT_ASSERT( !CUR.face->unpatented_hinting );\r
+#endif\r
+\r
+ v = CUR.GS.freeVector.x;\r
+\r
+ if ( v != 0 )\r
+ zone->org[point].x += TT_MULDIV( distance,\r
+ v * 0x10000L,\r
+ CUR.F_dot_P );\r
+\r
+ v = CUR.GS.freeVector.y;\r
+\r
+ if ( v != 0 )\r
+ zone->org[point].y += TT_MULDIV( distance,\r
+ v * 0x10000L,\r
+ CUR.F_dot_P );\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* Special versions of Direct_Move() */\r
+ /* */\r
+ /* The following versions are used whenever both vectors are both */\r
+ /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */\r
+ /* */\r
+ /*************************************************************************/\r
+\r
+\r
+ static void\r
+ Direct_Move_X( EXEC_OP_ TT_GlyphZone zone,\r
+ FT_UShort point,\r
+ FT_F26Dot6 distance )\r
+ {\r
+ FT_UNUSED_EXEC;\r
+\r
+ zone->cur[point].x += distance;\r
+ zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;\r
+ }\r
+\r
+\r
+ static void\r
+ Direct_Move_Y( EXEC_OP_ TT_GlyphZone zone,\r
+ FT_UShort point,\r
+ FT_F26Dot6 distance )\r
+ {\r
+ FT_UNUSED_EXEC;\r
+\r
+ zone->cur[point].y += distance;\r
+ zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* Special versions of Direct_Move_Orig() */\r
+ /* */\r
+ /* The following versions are used whenever both vectors are both */\r
+ /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */\r
+ /* */\r
+ /*************************************************************************/\r
+\r
+\r
+ static void\r
+ Direct_Move_Orig_X( EXEC_OP_ TT_GlyphZone zone,\r
+ FT_UShort point,\r
+ FT_F26Dot6 distance )\r
+ {\r
+ FT_UNUSED_EXEC;\r
+\r
+ zone->org[point].x += distance;\r
+ }\r
+\r
+\r
+ static void\r
+ Direct_Move_Orig_Y( EXEC_OP_ TT_GlyphZone zone,\r
+ FT_UShort point,\r
+ FT_F26Dot6 distance )\r
+ {\r
+ FT_UNUSED_EXEC;\r
+\r
+ zone->org[point].y += distance;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* <Function> */\r
+ /* Round_None */\r
+ /* */\r
+ /* <Description> */\r
+ /* Does not round, but adds engine compensation. */\r
+ /* */\r
+ /* <Input> */\r
+ /* distance :: The distance (not) to round. */\r
+ /* */\r
+ /* compensation :: The engine compensation. */\r
+ /* */\r
+ /* <Return> */\r
+ /* The compensated distance. */\r
+ /* */\r
+ /* <Note> */\r
+ /* The TrueType specification says very few about the relationship */\r
+ /* between rounding and engine compensation. However, it seems from */\r
+ /* the description of super round that we should add the compensation */\r
+ /* before rounding. */\r
+ /* */\r
+ static FT_F26Dot6\r
+ Round_None( EXEC_OP_ FT_F26Dot6 distance,\r
+ FT_F26Dot6 compensation )\r
+ {\r
+ FT_F26Dot6 val;\r
+\r
+ FT_UNUSED_EXEC;\r
+\r
+\r
+ if ( distance >= 0 )\r
+ {\r
+ val = distance + compensation;\r
+ if ( distance && val < 0 )\r
+ val = 0;\r
+ }\r
+ else {\r
+ val = distance - compensation;\r
+ if ( val > 0 )\r
+ val = 0;\r
+ }\r
+ return val;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* <Function> */\r
+ /* Round_To_Grid */\r
+ /* */\r
+ /* <Description> */\r
+ /* Rounds value to grid after adding engine compensation. */\r
+ /* */\r
+ /* <Input> */\r
+ /* distance :: The distance to round. */\r
+ /* */\r
+ /* compensation :: The engine compensation. */\r
+ /* */\r
+ /* <Return> */\r
+ /* Rounded distance. */\r
+ /* */\r
+ static FT_F26Dot6\r
+ Round_To_Grid( EXEC_OP_ FT_F26Dot6 distance,\r
+ FT_F26Dot6 compensation )\r
+ {\r
+ FT_F26Dot6 val;\r
+\r
+ FT_UNUSED_EXEC;\r
+\r
+\r
+ if ( distance >= 0 )\r
+ {\r
+ val = distance + compensation + 32;\r
+ if ( distance && val > 0 )\r
+ val &= ~63;\r
+ else\r
+ val = 0;\r
+ }\r
+ else\r
+ {\r
+ val = -FT_PIX_ROUND( compensation - distance );\r
+ if ( val > 0 )\r
+ val = 0;\r
+ }\r
+\r
+ return val;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* <Function> */\r
+ /* Round_To_Half_Grid */\r
+ /* */\r
+ /* <Description> */\r
+ /* Rounds value to half grid after adding engine compensation. */\r
+ /* */\r
+ /* <Input> */\r
+ /* distance :: The distance to round. */\r
+ /* */\r
+ /* compensation :: The engine compensation. */\r
+ /* */\r
+ /* <Return> */\r
+ /* Rounded distance. */\r
+ /* */\r
+ static FT_F26Dot6\r
+ Round_To_Half_Grid( EXEC_OP_ FT_F26Dot6 distance,\r
+ FT_F26Dot6 compensation )\r
+ {\r
+ FT_F26Dot6 val;\r
+\r
+ FT_UNUSED_EXEC;\r
+\r
+\r
+ if ( distance >= 0 )\r
+ {\r
+ val = FT_PIX_FLOOR( distance + compensation ) + 32;\r
+ if ( distance && val < 0 )\r
+ val = 0;\r
+ }\r
+ else\r
+ {\r
+ val = -( FT_PIX_FLOOR( compensation - distance ) + 32 );\r
+ if ( val > 0 )\r
+ val = 0;\r
+ }\r
+\r
+ return val;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* <Function> */\r
+ /* Round_Down_To_Grid */\r
+ /* */\r
+ /* <Description> */\r
+ /* Rounds value down to grid after adding engine compensation. */\r
+ /* */\r
+ /* <Input> */\r
+ /* distance :: The distance to round. */\r
+ /* */\r
+ /* compensation :: The engine compensation. */\r
+ /* */\r
+ /* <Return> */\r
+ /* Rounded distance. */\r
+ /* */\r
+ static FT_F26Dot6\r
+ Round_Down_To_Grid( EXEC_OP_ FT_F26Dot6 distance,\r
+ FT_F26Dot6 compensation )\r
+ {\r
+ FT_F26Dot6 val;\r
+\r
+ FT_UNUSED_EXEC;\r
+\r
+\r
+ if ( distance >= 0 )\r
+ {\r
+ val = distance + compensation;\r
+ if ( distance && val > 0 )\r
+ val &= ~63;\r
+ else\r
+ val = 0;\r
+ }\r
+ else\r
+ {\r
+ val = -( ( compensation - distance ) & -64 );\r
+ if ( val > 0 )\r
+ val = 0;\r
+ }\r
+\r
+ return val;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* <Function> */\r
+ /* Round_Up_To_Grid */\r
+ /* */\r
+ /* <Description> */\r
+ /* Rounds value up to grid after adding engine compensation. */\r
+ /* */\r
+ /* <Input> */\r
+ /* distance :: The distance to round. */\r
+ /* */\r
+ /* compensation :: The engine compensation. */\r
+ /* */\r
+ /* <Return> */\r
+ /* Rounded distance. */\r
+ /* */\r
+ static FT_F26Dot6\r
+ Round_Up_To_Grid( EXEC_OP_ FT_F26Dot6 distance,\r
+ FT_F26Dot6 compensation )\r
+ {\r
+ FT_F26Dot6 val;\r
+\r
+ FT_UNUSED_EXEC;\r
+\r
+\r
+ if ( distance >= 0 )\r
+ {\r
+ val = distance + compensation + 63;\r
+ if ( distance && val > 0 )\r
+ val &= ~63;\r
+ else\r
+ val = 0;\r
+ }\r
+ else\r
+ {\r
+ val = - FT_PIX_CEIL( compensation - distance );\r
+ if ( val > 0 )\r
+ val = 0;\r
+ }\r
+\r
+ return val;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* <Function> */\r
+ /* Round_To_Double_Grid */\r
+ /* */\r
+ /* <Description> */\r
+ /* Rounds value to double grid after adding engine compensation. */\r
+ /* */\r
+ /* <Input> */\r
+ /* distance :: The distance to round. */\r
+ /* */\r
+ /* compensation :: The engine compensation. */\r
+ /* */\r
+ /* <Return> */\r
+ /* Rounded distance. */\r
+ /* */\r
+ static FT_F26Dot6\r
+ Round_To_Double_Grid( EXEC_OP_ FT_F26Dot6 distance,\r
+ FT_F26Dot6 compensation )\r
+ {\r
+ FT_F26Dot6 val;\r
+\r
+ FT_UNUSED_EXEC;\r
+\r
+\r
+ if ( distance >= 0 )\r
+ {\r
+ val = distance + compensation + 16;\r
+ if ( distance && val > 0 )\r
+ val &= ~31;\r
+ else\r
+ val = 0;\r
+ }\r
+ else\r
+ {\r
+ val = -FT_PAD_ROUND( compensation - distance, 32 );\r
+ if ( val > 0 )\r
+ val = 0;\r
+ }\r
+\r
+ return val;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* <Function> */\r
+ /* Round_Super */\r
+ /* */\r
+ /* <Description> */\r
+ /* Super-rounds value to grid after adding engine compensation. */\r
+ /* */\r
+ /* <Input> */\r
+ /* distance :: The distance to round. */\r
+ /* */\r
+ /* compensation :: The engine compensation. */\r
+ /* */\r
+ /* <Return> */\r
+ /* Rounded distance. */\r
+ /* */\r
+ /* <Note> */\r
+ /* The TrueType specification says very few about the relationship */\r
+ /* between rounding and engine compensation. However, it seems from */\r
+ /* the description of super round that we should add the compensation */\r
+ /* before rounding. */\r
+ /* */\r
+ static FT_F26Dot6\r
+ Round_Super( EXEC_OP_ FT_F26Dot6 distance,\r
+ FT_F26Dot6 compensation )\r
+ {\r
+ FT_F26Dot6 val;\r
+\r
+\r
+ if ( distance >= 0 )\r
+ {\r
+ val = ( distance - CUR.phase + CUR.threshold + compensation ) &\r
+ -CUR.period;\r
+ if ( distance && val < 0 )\r
+ val = 0;\r
+ val += CUR.phase;\r
+ }\r
+ else\r
+ {\r
+ val = -( ( CUR.threshold - CUR.phase - distance + compensation ) &\r
+ -CUR.period );\r
+ if ( val > 0 )\r
+ val = 0;\r
+ val -= CUR.phase;\r
+ }\r
+\r
+ return val;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* <Function> */\r
+ /* Round_Super_45 */\r
+ /* */\r
+ /* <Description> */\r
+ /* Super-rounds value to grid after adding engine compensation. */\r
+ /* */\r
+ /* <Input> */\r
+ /* distance :: The distance to round. */\r
+ /* */\r
+ /* compensation :: The engine compensation. */\r
+ /* */\r
+ /* <Return> */\r
+ /* Rounded distance. */\r
+ /* */\r
+ /* <Note> */\r
+ /* There is a separate function for Round_Super_45() as we may need */\r
+ /* greater precision. */\r
+ /* */\r
+ static FT_F26Dot6\r
+ Round_Super_45( EXEC_OP_ FT_F26Dot6 distance,\r
+ FT_F26Dot6 compensation )\r
+ {\r
+ FT_F26Dot6 val;\r
+\r
+\r
+ if ( distance >= 0 )\r
+ {\r
+ val = ( ( distance - CUR.phase + CUR.threshold + compensation ) /\r
+ CUR.period ) * CUR.period;\r
+ if ( distance && val < 0 )\r
+ val = 0;\r
+ val += CUR.phase;\r
+ }\r
+ else\r
+ {\r
+ val = -( ( ( CUR.threshold - CUR.phase - distance + compensation ) /\r
+ CUR.period ) * CUR.period );\r
+ if ( val > 0 )\r
+ val = 0;\r
+ val -= CUR.phase;\r
+ }\r
+\r
+ return val;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* <Function> */\r
+ /* Compute_Round */\r
+ /* */\r
+ /* <Description> */\r
+ /* Sets the rounding mode. */\r
+ /* */\r
+ /* <Input> */\r
+ /* round_mode :: The rounding mode to be used. */\r
+ /* */\r
+ static void\r
+ Compute_Round( EXEC_OP_ FT_Byte round_mode )\r
+ {\r
+ switch ( round_mode )\r
+ {\r
+ case TT_Round_Off:\r
+ CUR.func_round = (TT_Round_Func)Round_None;\r
+ break;\r
+\r
+ case TT_Round_To_Grid:\r
+ CUR.func_round = (TT_Round_Func)Round_To_Grid;\r
+ break;\r
+\r
+ case TT_Round_Up_To_Grid:\r
+ CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;\r
+ break;\r
+\r
+ case TT_Round_Down_To_Grid:\r
+ CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;\r
+ break;\r
+\r
+ case TT_Round_To_Half_Grid:\r
+ CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;\r
+ break;\r
+\r
+ case TT_Round_To_Double_Grid:\r
+ CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;\r
+ break;\r
+\r
+ case TT_Round_Super:\r
+ CUR.func_round = (TT_Round_Func)Round_Super;\r
+ break;\r
+\r
+ case TT_Round_Super_45:\r
+ CUR.func_round = (TT_Round_Func)Round_Super_45;\r
+ break;\r
+ }\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* <Function> */\r
+ /* SetSuperRound */\r
+ /* */\r
+ /* <Description> */\r
+ /* Sets Super Round parameters. */\r
+ /* */\r
+ /* <Input> */\r
+ /* GridPeriod :: Grid period */\r
+ /* selector :: SROUND opcode */\r
+ /* */\r
+ static void\r
+ SetSuperRound( EXEC_OP_ FT_F26Dot6 GridPeriod,\r
+ FT_Long selector )\r
+ {\r
+ switch ( (FT_Int)( selector & 0xC0 ) )\r
+ {\r
+ case 0:\r
+ CUR.period = GridPeriod / 2;\r
+ break;\r
+\r
+ case 0x40:\r
+ CUR.period = GridPeriod;\r
+ break;\r
+\r
+ case 0x80:\r
+ CUR.period = GridPeriod * 2;\r
+ break;\r
+\r
+ /* This opcode is reserved, but... */\r
+\r
+ case 0xC0:\r
+ CUR.period = GridPeriod;\r
+ break;\r
+ }\r
+\r
+ switch ( (FT_Int)( selector & 0x30 ) )\r
+ {\r
+ case 0:\r
+ CUR.phase = 0;\r
+ break;\r
+\r
+ case 0x10:\r
+ CUR.phase = CUR.period / 4;\r
+ break;\r
+\r
+ case 0x20:\r
+ CUR.phase = CUR.period / 2;\r
+ break;\r
+\r
+ case 0x30:\r
+ CUR.phase = CUR.period * 3 / 4;\r
+ break;\r
+ }\r
+\r
+ if ( ( selector & 0x0F ) == 0 )\r
+ CUR.threshold = CUR.period - 1;\r
+ else\r
+ CUR.threshold = ( (FT_Int)( selector & 0x0F ) - 4 ) * CUR.period / 8;\r
+\r
+ CUR.period /= 256;\r
+ CUR.phase /= 256;\r
+ CUR.threshold /= 256;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* <Function> */\r
+ /* Project */\r
+ /* */\r
+ /* <Description> */\r
+ /* Computes the projection of vector given by (v2-v1) along the */\r
+ /* current projection vector. */\r
+ /* */\r
+ /* <Input> */\r
+ /* v1 :: First input vector. */\r
+ /* v2 :: Second input vector. */\r
+ /* */\r
+ /* <Return> */\r
+ /* The distance in F26dot6 format. */\r
+ /* */\r
+ static FT_F26Dot6\r
+ Project( EXEC_OP_ FT_Pos dx,\r
+ FT_Pos dy )\r
+ {\r
+#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING\r
+ FT_ASSERT( !CUR.face->unpatented_hinting );\r
+#endif\r
+\r
+ return TT_DotFix14( dx, dy,\r
+ CUR.GS.projVector.x,\r
+ CUR.GS.projVector.y );\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* <Function> */\r
+ /* Dual_Project */\r
+ /* */\r
+ /* <Description> */\r
+ /* Computes the projection of the vector given by (v2-v1) along the */\r
+ /* current dual vector. */\r
+ /* */\r
+ /* <Input> */\r
+ /* v1 :: First input vector. */\r
+ /* v2 :: Second input vector. */\r
+ /* */\r
+ /* <Return> */\r
+ /* The distance in F26dot6 format. */\r
+ /* */\r
+ static FT_F26Dot6\r
+ Dual_Project( EXEC_OP_ FT_Pos dx,\r
+ FT_Pos dy )\r
+ {\r
+ return TT_DotFix14( dx, dy,\r
+ CUR.GS.dualVector.x,\r
+ CUR.GS.dualVector.y );\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* <Function> */\r
+ /* Project_x */\r
+ /* */\r
+ /* <Description> */\r
+ /* Computes the projection of the vector given by (v2-v1) along the */\r
+ /* horizontal axis. */\r
+ /* */\r
+ /* <Input> */\r
+ /* v1 :: First input vector. */\r
+ /* v2 :: Second input vector. */\r
+ /* */\r
+ /* <Return> */\r
+ /* The distance in F26dot6 format. */\r
+ /* */\r
+ static FT_F26Dot6\r
+ Project_x( EXEC_OP_ FT_Pos dx,\r
+ FT_Pos dy )\r
+ {\r
+ FT_UNUSED_EXEC;\r
+ FT_UNUSED( dy );\r
+\r
+ return dx;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* <Function> */\r
+ /* Project_y */\r
+ /* */\r
+ /* <Description> */\r
+ /* Computes the projection of the vector given by (v2-v1) along the */\r
+ /* vertical axis. */\r
+ /* */\r
+ /* <Input> */\r
+ /* v1 :: First input vector. */\r
+ /* v2 :: Second input vector. */\r
+ /* */\r
+ /* <Return> */\r
+ /* The distance in F26dot6 format. */\r
+ /* */\r
+ static FT_F26Dot6\r
+ Project_y( EXEC_OP_ FT_Pos dx,\r
+ FT_Pos dy )\r
+ {\r
+ FT_UNUSED_EXEC;\r
+ FT_UNUSED( dx );\r
+\r
+ return dy;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* <Function> */\r
+ /* Compute_Funcs */\r
+ /* */\r
+ /* <Description> */\r
+ /* Computes the projection and movement function pointers according */\r
+ /* to the current graphics state. */\r
+ /* */\r
+ static void\r
+ Compute_Funcs( EXEC_OP )\r
+ {\r
+#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING\r
+ if ( CUR.face->unpatented_hinting )\r
+ {\r
+ /* If both vectors point rightwards along the x axis, set */\r
+ /* `both-x-axis' true, otherwise set it false. The x values only */\r
+ /* need be tested because the vector has been normalised to a unit */\r
+ /* vector of length 0x4000 = unity. */\r
+ CUR.GS.both_x_axis = (FT_Bool)( CUR.GS.projVector.x == 0x4000 &&\r
+ CUR.GS.freeVector.x == 0x4000 );\r
+\r
+ /* Throw away projection and freedom vector information */\r
+ /* because the patents don't allow them to be stored. */\r
+ /* The relevant US Patents are 5155805 and 5325479. */\r
+ CUR.GS.projVector.x = 0;\r
+ CUR.GS.projVector.y = 0;\r
+ CUR.GS.freeVector.x = 0;\r
+ CUR.GS.freeVector.y = 0;\r
+\r
+ if ( CUR.GS.both_x_axis )\r
+ {\r
+ CUR.func_project = Project_x;\r
+ CUR.func_move = Direct_Move_X;\r
+ CUR.func_move_orig = Direct_Move_Orig_X;\r
+ }\r
+ else\r
+ {\r
+ CUR.func_project = Project_y;\r
+ CUR.func_move = Direct_Move_Y;\r
+ CUR.func_move_orig = Direct_Move_Orig_Y;\r
+ }\r
+\r
+ if ( CUR.GS.dualVector.x == 0x4000 )\r
+ CUR.func_dualproj = Project_x;\r
+ else\r
+ {\r
+ if ( CUR.GS.dualVector.y == 0x4000 )\r
+ CUR.func_dualproj = Project_y;\r
+ else\r
+ CUR.func_dualproj = Dual_Project;\r
+ }\r
+\r
+ /* Force recalculation of cached aspect ratio */\r
+ CUR.tt_metrics.ratio = 0;\r
+\r
+ return;\r
+ }\r
+#endif /* TT_CONFIG_OPTION_UNPATENTED_HINTING */\r
+\r
+ if ( CUR.GS.freeVector.x == 0x4000 )\r
+ CUR.F_dot_P = CUR.GS.projVector.x * 0x10000L;\r
+ else\r
+ {\r
+ if ( CUR.GS.freeVector.y == 0x4000 )\r
+ CUR.F_dot_P = CUR.GS.projVector.y * 0x10000L;\r
+ else\r
+ CUR.F_dot_P = (FT_Long)CUR.GS.projVector.x * CUR.GS.freeVector.x * 4 +\r
+ (FT_Long)CUR.GS.projVector.y * CUR.GS.freeVector.y * 4;\r
+ }\r
+\r
+ if ( CUR.GS.projVector.x == 0x4000 )\r
+ CUR.func_project = (TT_Project_Func)Project_x;\r
+ else\r
+ {\r
+ if ( CUR.GS.projVector.y == 0x4000 )\r
+ CUR.func_project = (TT_Project_Func)Project_y;\r
+ else\r
+ CUR.func_project = (TT_Project_Func)Project;\r
+ }\r
+\r
+ if ( CUR.GS.dualVector.x == 0x4000 )\r
+ CUR.func_dualproj = (TT_Project_Func)Project_x;\r
+ else\r
+ {\r
+ if ( CUR.GS.dualVector.y == 0x4000 )\r
+ CUR.func_dualproj = (TT_Project_Func)Project_y;\r
+ else\r
+ CUR.func_dualproj = (TT_Project_Func)Dual_Project;\r
+ }\r
+\r
+ CUR.func_move = (TT_Move_Func)Direct_Move;\r
+ CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig;\r
+\r
+ if ( CUR.F_dot_P == 0x40000000L )\r
+ {\r
+ if ( CUR.GS.freeVector.x == 0x4000 )\r
+ {\r
+ CUR.func_move = (TT_Move_Func)Direct_Move_X;\r
+ CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig_X;\r
+ }\r
+ else\r
+ {\r
+ if ( CUR.GS.freeVector.y == 0x4000 )\r
+ {\r
+ CUR.func_move = (TT_Move_Func)Direct_Move_Y;\r
+ CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig_Y;\r
+ }\r
+ }\r
+ }\r
+\r
+ /* at small sizes, F_dot_P can become too small, resulting */\r
+ /* in overflows and `spikes' in a number of glyphs like `w'. */\r
+\r
+ if ( FT_ABS( CUR.F_dot_P ) < 0x4000000L )\r
+ CUR.F_dot_P = 0x40000000L;\r
+\r
+ /* Disable cached aspect ratio */\r
+ CUR.tt_metrics.ratio = 0;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* <Function> */\r
+ /* Normalize */\r
+ /* */\r
+ /* <Description> */\r
+ /* Norms a vector. */\r
+ /* */\r
+ /* <Input> */\r
+ /* Vx :: The horizontal input vector coordinate. */\r
+ /* Vy :: The vertical input vector coordinate. */\r
+ /* */\r
+ /* <Output> */\r
+ /* R :: The normed unit vector. */\r
+ /* */\r
+ /* <Return> */\r
+ /* Returns FAILURE if a vector parameter is zero. */\r
+ /* */\r
+ /* <Note> */\r
+ /* In case Vx and Vy are both zero, Normalize() returns SUCCESS, and */\r
+ /* R is undefined. */\r
+ /* */\r
+\r
+\r
+ static FT_Bool\r
+ Normalize( EXEC_OP_ FT_F26Dot6 Vx,\r
+ FT_F26Dot6 Vy,\r
+ FT_UnitVector* R )\r
+ {\r
+ FT_F26Dot6 W;\r
+ FT_Bool S1, S2;\r
+\r
+ FT_UNUSED_EXEC;\r
+\r
+\r
+ if ( FT_ABS( Vx ) < 0x10000L && FT_ABS( Vy ) < 0x10000L )\r
+ {\r
+ Vx *= 0x100;\r
+ Vy *= 0x100;\r
+\r
+ W = TT_VecLen( Vx, Vy );\r
+\r
+ if ( W == 0 )\r
+ {\r
+ /* XXX: UNDOCUMENTED! It seems that it is possible to try */\r
+ /* to normalize the vector (0,0). Return immediately. */\r
+ return SUCCESS;\r
+ }\r
+\r
+ R->x = (FT_F2Dot14)FT_MulDiv( Vx, 0x4000L, W );\r
+ R->y = (FT_F2Dot14)FT_MulDiv( Vy, 0x4000L, W );\r
+\r
+ return SUCCESS;\r
+ }\r
+\r
+ W = TT_VecLen( Vx, Vy );\r
+\r
+ Vx = FT_MulDiv( Vx, 0x4000L, W );\r
+ Vy = FT_MulDiv( Vy, 0x4000L, W );\r
+\r
+ W = Vx * Vx + Vy * Vy;\r
+\r
+ /* Now, we want that Sqrt( W ) = 0x4000 */\r
+ /* Or 0x10000000 <= W < 0x10004000 */\r
+\r
+ if ( Vx < 0 )\r
+ {\r
+ Vx = -Vx;\r
+ S1 = TRUE;\r
+ }\r
+ else\r
+ S1 = FALSE;\r
+\r
+ if ( Vy < 0 )\r
+ {\r
+ Vy = -Vy;\r
+ S2 = TRUE;\r
+ }\r
+ else\r
+ S2 = FALSE;\r
+\r
+ while ( W < 0x10000000L )\r
+ {\r
+ /* We need to increase W by a minimal amount */\r
+ if ( Vx < Vy )\r
+ Vx++;\r
+ else\r
+ Vy++;\r
+\r
+ W = Vx * Vx + Vy * Vy;\r
+ }\r
+\r
+ while ( W >= 0x10004000L )\r
+ {\r
+ /* We need to decrease W by a minimal amount */\r
+ if ( Vx < Vy )\r
+ Vx--;\r
+ else\r
+ Vy--;\r
+\r
+ W = Vx * Vx + Vy * Vy;\r
+ }\r
+\r
+ /* Note that in various cases, we can only */\r
+ /* compute a Sqrt(W) of 0x3FFF, eg. Vx = Vy */\r
+\r
+ if ( S1 )\r
+ Vx = -Vx;\r
+\r
+ if ( S2 )\r
+ Vy = -Vy;\r
+\r
+ R->x = (FT_F2Dot14)Vx; /* Type conversion */\r
+ R->y = (FT_F2Dot14)Vy; /* Type conversion */\r
+\r
+ return SUCCESS;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* Here we start with the implementation of the various opcodes. */\r
+ /* */\r
+ /*************************************************************************/\r
+\r
+\r
+ static FT_Bool\r
+ Ins_SxVTL( EXEC_OP_ FT_UShort aIdx1,\r
+ FT_UShort aIdx2,\r
+ FT_Int aOpc,\r
+ FT_UnitVector* Vec )\r
+ {\r
+ FT_Long A, B, C;\r
+ FT_Vector* p1;\r
+ FT_Vector* p2;\r
+\r
+\r
+ if ( BOUNDS( aIdx1, CUR.zp2.n_points ) ||\r
+ BOUNDS( aIdx2, CUR.zp1.n_points ) )\r
+ {\r
+ if ( CUR.pedantic_hinting )\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return FAILURE;\r
+ }\r
+\r
+ p1 = CUR.zp1.cur + aIdx2;\r
+ p2 = CUR.zp2.cur + aIdx1;\r
+\r
+ A = p1->x - p2->x;\r
+ B = p1->y - p2->y;\r
+\r
+ if ( ( aOpc & 1 ) != 0 )\r
+ {\r
+ C = B; /* counter clockwise rotation */\r
+ B = A;\r
+ A = -C;\r
+ }\r
+\r
+ NORMalize( A, B, Vec );\r
+\r
+ return SUCCESS;\r
+ }\r
+\r
+\r
+ /* When not using the big switch statements, the interpreter uses a */\r
+ /* call table defined later below in this source. Each opcode must */\r
+ /* thus have a corresponding function, even trivial ones. */\r
+ /* */\r
+ /* They are all defined there. */\r
+\r
+#define DO_SVTCA \\r
+ { \\r
+ FT_Short A, B; \\r
+ \\r
+ \\r
+ A = (FT_Short)( CUR.opcode & 1 ) << 14; \\r
+ B = A ^ (FT_Short)0x4000; \\r
+ \\r
+ CUR.GS.freeVector.x = A; \\r
+ CUR.GS.projVector.x = A; \\r
+ CUR.GS.dualVector.x = A; \\r
+ \\r
+ CUR.GS.freeVector.y = B; \\r
+ CUR.GS.projVector.y = B; \\r
+ CUR.GS.dualVector.y = B; \\r
+ \\r
+ COMPUTE_Funcs(); \\r
+ }\r
+\r
+\r
+#define DO_SPVTCA \\r
+ { \\r
+ FT_Short A, B; \\r
+ \\r
+ \\r
+ A = (FT_Short)( CUR.opcode & 1 ) << 14; \\r
+ B = A ^ (FT_Short)0x4000; \\r
+ \\r
+ CUR.GS.projVector.x = A; \\r
+ CUR.GS.dualVector.x = A; \\r
+ \\r
+ CUR.GS.projVector.y = B; \\r
+ CUR.GS.dualVector.y = B; \\r
+ \\r
+ GUESS_VECTOR( freeVector ); \\r
+ \\r
+ COMPUTE_Funcs(); \\r
+ }\r
+\r
+\r
+#define DO_SFVTCA \\r
+ { \\r
+ FT_Short A, B; \\r
+ \\r
+ \\r
+ A = (FT_Short)( CUR.opcode & 1 ) << 14; \\r
+ B = A ^ (FT_Short)0x4000; \\r
+ \\r
+ CUR.GS.freeVector.x = A; \\r
+ CUR.GS.freeVector.y = B; \\r
+ \\r
+ GUESS_VECTOR( projVector ); \\r
+ \\r
+ COMPUTE_Funcs(); \\r
+ }\r
+\r
+\r
+#define DO_SPVTL \\r
+ if ( INS_SxVTL( (FT_UShort)args[1], \\r
+ (FT_UShort)args[0], \\r
+ CUR.opcode, \\r
+ &CUR.GS.projVector ) == SUCCESS ) \\r
+ { \\r
+ CUR.GS.dualVector = CUR.GS.projVector; \\r
+ GUESS_VECTOR( freeVector ); \\r
+ COMPUTE_Funcs(); \\r
+ }\r
+\r
+\r
+#define DO_SFVTL \\r
+ if ( INS_SxVTL( (FT_UShort)args[1], \\r
+ (FT_UShort)args[0], \\r
+ CUR.opcode, \\r
+ &CUR.GS.freeVector ) == SUCCESS ) \\r
+ { \\r
+ GUESS_VECTOR( projVector ); \\r
+ COMPUTE_Funcs(); \\r
+ }\r
+\r
+\r
+#define DO_SFVTPV \\r
+ GUESS_VECTOR( projVector ); \\r
+ CUR.GS.freeVector = CUR.GS.projVector; \\r
+ COMPUTE_Funcs();\r
+\r
+\r
+#define DO_SPVFS \\r
+ { \\r
+ FT_Short S; \\r
+ FT_Long X, Y; \\r
+ \\r
+ \\r
+ /* Only use low 16bits, then sign extend */ \\r
+ S = (FT_Short)args[1]; \\r
+ Y = (FT_Long)S; \\r
+ S = (FT_Short)args[0]; \\r
+ X = (FT_Long)S; \\r
+ \\r
+ NORMalize( X, Y, &CUR.GS.projVector ); \\r
+ \\r
+ CUR.GS.dualVector = CUR.GS.projVector; \\r
+ GUESS_VECTOR( freeVector ); \\r
+ COMPUTE_Funcs(); \\r
+ }\r
+\r
+\r
+#define DO_SFVFS \\r
+ { \\r
+ FT_Short S; \\r
+ FT_Long X, Y; \\r
+ \\r
+ \\r
+ /* Only use low 16bits, then sign extend */ \\r
+ S = (FT_Short)args[1]; \\r
+ Y = (FT_Long)S; \\r
+ S = (FT_Short)args[0]; \\r
+ X = S; \\r
+ \\r
+ NORMalize( X, Y, &CUR.GS.freeVector ); \\r
+ GUESS_VECTOR( projVector ); \\r
+ COMPUTE_Funcs(); \\r
+ }\r
+\r
+\r
+#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING\r
+#define DO_GPV \\r
+ if ( CUR.face->unpatented_hinting ) \\r
+ { \\r
+ args[0] = CUR.GS.both_x_axis ? 0x4000 : 0; \\r
+ args[1] = CUR.GS.both_x_axis ? 0 : 0x4000; \\r
+ } \\r
+ else \\r
+ { \\r
+ args[0] = CUR.GS.projVector.x; \\r
+ args[1] = CUR.GS.projVector.y; \\r
+ }\r
+#else\r
+#define DO_GPV \\r
+ args[0] = CUR.GS.projVector.x; \\r
+ args[1] = CUR.GS.projVector.y;\r
+#endif\r
+\r
+\r
+#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING\r
+#define DO_GFV \\r
+ if ( CUR.face->unpatented_hinting ) \\r
+ { \\r
+ args[0] = CUR.GS.both_x_axis ? 0x4000 : 0; \\r
+ args[1] = CUR.GS.both_x_axis ? 0 : 0x4000; \\r
+ } \\r
+ else \\r
+ { \\r
+ args[0] = CUR.GS.freeVector.x; \\r
+ args[1] = CUR.GS.freeVector.y; \\r
+ }\r
+#else\r
+#define DO_GFV \\r
+ args[0] = CUR.GS.freeVector.x; \\r
+ args[1] = CUR.GS.freeVector.y;\r
+#endif\r
+\r
+\r
+#define DO_SRP0 \\r
+ CUR.GS.rp0 = (FT_UShort)args[0];\r
+\r
+\r
+#define DO_SRP1 \\r
+ CUR.GS.rp1 = (FT_UShort)args[0];\r
+\r
+\r
+#define DO_SRP2 \\r
+ CUR.GS.rp2 = (FT_UShort)args[0];\r
+\r
+\r
+#define DO_RTHG \\r
+ CUR.GS.round_state = TT_Round_To_Half_Grid; \\r
+ CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;\r
+\r
+\r
+#define DO_RTG \\r
+ CUR.GS.round_state = TT_Round_To_Grid; \\r
+ CUR.func_round = (TT_Round_Func)Round_To_Grid;\r
+\r
+\r
+#define DO_RTDG \\r
+ CUR.GS.round_state = TT_Round_To_Double_Grid; \\r
+ CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;\r
+\r
+\r
+#define DO_RUTG \\r
+ CUR.GS.round_state = TT_Round_Up_To_Grid; \\r
+ CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;\r
+\r
+\r
+#define DO_RDTG \\r
+ CUR.GS.round_state = TT_Round_Down_To_Grid; \\r
+ CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;\r
+\r
+\r
+#define DO_ROFF \\r
+ CUR.GS.round_state = TT_Round_Off; \\r
+ CUR.func_round = (TT_Round_Func)Round_None;\r
+\r
+\r
+#define DO_SROUND \\r
+ SET_SuperRound( 0x4000, args[0] ); \\r
+ CUR.GS.round_state = TT_Round_Super; \\r
+ CUR.func_round = (TT_Round_Func)Round_Super;\r
+\r
+\r
+#define DO_S45ROUND \\r
+ SET_SuperRound( 0x2D41, args[0] ); \\r
+ CUR.GS.round_state = TT_Round_Super_45; \\r
+ CUR.func_round = (TT_Round_Func)Round_Super_45;\r
+\r
+\r
+#define DO_SLOOP \\r
+ if ( args[0] < 0 ) \\r
+ CUR.error = TT_Err_Bad_Argument; \\r
+ else \\r
+ CUR.GS.loop = args[0];\r
+\r
+\r
+#define DO_SMD \\r
+ CUR.GS.minimum_distance = args[0];\r
+\r
+\r
+#define DO_SCVTCI \\r
+ CUR.GS.control_value_cutin = (FT_F26Dot6)args[0];\r
+\r
+\r
+#define DO_SSWCI \\r
+ CUR.GS.single_width_cutin = (FT_F26Dot6)args[0];\r
+\r
+\r
+ /* XXX: UNDOCUMENTED! or bug in the Windows engine? */\r
+ /* */\r
+ /* It seems that the value that is read here is */\r
+ /* expressed in 16.16 format rather than in font */\r
+ /* units. */\r
+ /* */\r
+#define DO_SSW \\r
+ CUR.GS.single_width_value = (FT_F26Dot6)( args[0] >> 10 );\r
+\r
+\r
+#define DO_FLIPON \\r
+ CUR.GS.auto_flip = TRUE;\r
+\r
+\r
+#define DO_FLIPOFF \\r
+ CUR.GS.auto_flip = FALSE;\r
+\r
+\r
+#define DO_SDB \\r
+ CUR.GS.delta_base = (FT_Short)args[0];\r
+\r
+\r
+#define DO_SDS \\r
+ CUR.GS.delta_shift = (FT_Short)args[0];\r
+\r
+\r
+#define DO_MD /* nothing */\r
+\r
+\r
+#define DO_MPPEM \\r
+ args[0] = CURRENT_Ppem();\r
+\r
+\r
+ /* Note: The pointSize should be irrelevant in a given font program; */\r
+ /* we thus decide to return only the ppem. */\r
+#if 0\r
+\r
+#define DO_MPS \\r
+ args[0] = CUR.metrics.pointSize;\r
+\r
+#else\r
+\r
+#define DO_MPS \\r
+ args[0] = CURRENT_Ppem();\r
+\r
+#endif /* 0 */\r
+\r
+\r
+#define DO_DUP \\r
+ args[1] = args[0];\r
+\r
+\r
+#define DO_CLEAR \\r
+ CUR.new_top = 0;\r
+\r
+\r
+#define DO_SWAP \\r
+ { \\r
+ FT_Long L; \\r
+ \\r
+ \\r
+ L = args[0]; \\r
+ args[0] = args[1]; \\r
+ args[1] = L; \\r
+ }\r
+\r
+\r
+#define DO_DEPTH \\r
+ args[0] = CUR.top;\r
+\r
+\r
+#define DO_CINDEX \\r
+ { \\r
+ FT_Long L; \\r
+ \\r
+ \\r
+ L = args[0]; \\r
+ \\r
+ if ( L <= 0 || L > CUR.args ) \\r
+ CUR.error = TT_Err_Invalid_Reference; \\r
+ else \\r
+ args[0] = CUR.stack[CUR.args - L]; \\r
+ }\r
+\r
+\r
+#define DO_JROT \\r
+ if ( args[1] != 0 ) \\r
+ { \\r
+ CUR.IP += args[0]; \\r
+ CUR.step_ins = FALSE; \\r
+ }\r
+\r
+\r
+#define DO_JMPR \\r
+ CUR.IP += args[0]; \\r
+ CUR.step_ins = FALSE;\r
+\r
+\r
+#define DO_JROF \\r
+ if ( args[1] == 0 ) \\r
+ { \\r
+ CUR.IP += args[0]; \\r
+ CUR.step_ins = FALSE; \\r
+ }\r
+\r
+\r
+#define DO_LT \\r
+ args[0] = ( args[0] < args[1] );\r
+\r
+\r
+#define DO_LTEQ \\r
+ args[0] = ( args[0] <= args[1] );\r
+\r
+\r
+#define DO_GT \\r
+ args[0] = ( args[0] > args[1] );\r
+\r
+\r
+#define DO_GTEQ \\r
+ args[0] = ( args[0] >= args[1] );\r
+\r
+\r
+#define DO_EQ \\r
+ args[0] = ( args[0] == args[1] );\r
+\r
+\r
+#define DO_NEQ \\r
+ args[0] = ( args[0] != args[1] );\r
+\r
+\r
+#define DO_ODD \\r
+ args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 64 );\r
+\r
+\r
+#define DO_EVEN \\r
+ args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 0 );\r
+\r
+\r
+#define DO_AND \\r
+ args[0] = ( args[0] && args[1] );\r
+\r
+\r
+#define DO_OR \\r
+ args[0] = ( args[0] || args[1] );\r
+\r
+\r
+#define DO_NOT \\r
+ args[0] = !args[0];\r
+\r
+\r
+#define DO_ADD \\r
+ args[0] += args[1];\r
+\r
+\r
+#define DO_SUB \\r
+ args[0] -= args[1];\r
+\r
+\r
+#define DO_DIV \\r
+ if ( args[1] == 0 ) \\r
+ CUR.error = TT_Err_Divide_By_Zero; \\r
+ else \\r
+ args[0] = TT_MULDIV_NO_ROUND( args[0], 64L, args[1] );\r
+\r
+\r
+#define DO_MUL \\r
+ args[0] = TT_MULDIV( args[0], args[1], 64L );\r
+\r
+\r
+#define DO_ABS \\r
+ args[0] = FT_ABS( args[0] );\r
+\r
+\r
+#define DO_NEG \\r
+ args[0] = -args[0];\r
+\r
+\r
+#define DO_FLOOR \\r
+ args[0] = FT_PIX_FLOOR( args[0] );\r
+\r
+\r
+#define DO_CEILING \\r
+ args[0] = FT_PIX_CEIL( args[0] );\r
+\r
+\r
+#define DO_RS \\r
+ { \\r
+ FT_ULong I = (FT_ULong)args[0]; \\r
+ \\r
+ \\r
+ if ( BOUNDS( I, CUR.storeSize ) ) \\r
+ { \\r
+ if ( CUR.pedantic_hinting ) \\r
+ { \\r
+ ARRAY_BOUND_ERROR; \\r
+ } \\r
+ else \\r
+ args[0] = 0; \\r
+ } \\r
+ else \\r
+ args[0] = CUR.storage[I]; \\r
+ }\r
+\r
+\r
+#define DO_WS \\r
+ { \\r
+ FT_ULong I = (FT_ULong)args[0]; \\r
+ \\r
+ \\r
+ if ( BOUNDS( I, CUR.storeSize ) ) \\r
+ { \\r
+ if ( CUR.pedantic_hinting ) \\r
+ { \\r
+ ARRAY_BOUND_ERROR; \\r
+ } \\r
+ } \\r
+ else \\r
+ CUR.storage[I] = args[1]; \\r
+ }\r
+\r
+\r
+#define DO_RCVT \\r
+ { \\r
+ FT_ULong I = (FT_ULong)args[0]; \\r
+ \\r
+ \\r
+ if ( BOUNDS( I, CUR.cvtSize ) ) \\r
+ { \\r
+ if ( CUR.pedantic_hinting ) \\r
+ { \\r
+ ARRAY_BOUND_ERROR; \\r
+ } \\r
+ else \\r
+ args[0] = 0; \\r
+ } \\r
+ else \\r
+ args[0] = CUR_Func_read_cvt( I ); \\r
+ }\r
+\r
+\r
+#define DO_WCVTP \\r
+ { \\r
+ FT_ULong I = (FT_ULong)args[0]; \\r
+ \\r
+ \\r
+ if ( BOUNDS( I, CUR.cvtSize ) ) \\r
+ { \\r
+ if ( CUR.pedantic_hinting ) \\r
+ { \\r
+ ARRAY_BOUND_ERROR; \\r
+ } \\r
+ } \\r
+ else \\r
+ CUR_Func_write_cvt( I, args[1] ); \\r
+ }\r
+\r
+\r
+#define DO_WCVTF \\r
+ { \\r
+ FT_ULong I = (FT_ULong)args[0]; \\r
+ \\r
+ \\r
+ if ( BOUNDS( I, CUR.cvtSize ) ) \\r
+ { \\r
+ if ( CUR.pedantic_hinting ) \\r
+ { \\r
+ ARRAY_BOUND_ERROR; \\r
+ } \\r
+ } \\r
+ else \\r
+ CUR.cvt[I] = TT_MULFIX( args[1], CUR.tt_metrics.scale ); \\r
+ }\r
+\r
+\r
+#define DO_DEBUG \\r
+ CUR.error = TT_Err_Debug_OpCode;\r
+\r
+\r
+#define DO_ROUND \\r
+ args[0] = CUR_Func_round( \\r
+ args[0], \\r
+ CUR.tt_metrics.compensations[CUR.opcode - 0x68] );\r
+\r
+\r
+#define DO_NROUND \\r
+ args[0] = ROUND_None( args[0], \\r
+ CUR.tt_metrics.compensations[CUR.opcode - 0x6C] );\r
+\r
+\r
+#define DO_MAX \\r
+ if ( args[1] > args[0] ) \\r
+ args[0] = args[1];\r
+\r
+\r
+#define DO_MIN \\r
+ if ( args[1] < args[0] ) \\r
+ args[0] = args[1];\r
+\r
+\r
+#ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH\r
+\r
+\r
+#undef ARRAY_BOUND_ERROR\r
+#define ARRAY_BOUND_ERROR \\r
+ { \\r
+ CUR.error = TT_Err_Invalid_Reference; \\r
+ return; \\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SVTCA[a]: Set (F and P) Vectors to Coordinate Axis */\r
+ /* Opcode range: 0x00-0x01 */\r
+ /* Stack: --> */\r
+ /* */\r
+ static void\r
+ Ins_SVTCA( INS_ARG )\r
+ {\r
+ DO_SVTCA\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SPVTCA[a]: Set PVector to Coordinate Axis */\r
+ /* Opcode range: 0x02-0x03 */\r
+ /* Stack: --> */\r
+ /* */\r
+ static void\r
+ Ins_SPVTCA( INS_ARG )\r
+ {\r
+ DO_SPVTCA\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SFVTCA[a]: Set FVector to Coordinate Axis */\r
+ /* Opcode range: 0x04-0x05 */\r
+ /* Stack: --> */\r
+ /* */\r
+ static void\r
+ Ins_SFVTCA( INS_ARG )\r
+ {\r
+ DO_SFVTCA\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SPVTL[a]: Set PVector To Line */\r
+ /* Opcode range: 0x06-0x07 */\r
+ /* Stack: uint32 uint32 --> */\r
+ /* */\r
+ static void\r
+ Ins_SPVTL( INS_ARG )\r
+ {\r
+ DO_SPVTL\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SFVTL[a]: Set FVector To Line */\r
+ /* Opcode range: 0x08-0x09 */\r
+ /* Stack: uint32 uint32 --> */\r
+ /* */\r
+ static void\r
+ Ins_SFVTL( INS_ARG )\r
+ {\r
+ DO_SFVTL\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SFVTPV[]: Set FVector To PVector */\r
+ /* Opcode range: 0x0E */\r
+ /* Stack: --> */\r
+ /* */\r
+ static void\r
+ Ins_SFVTPV( INS_ARG )\r
+ {\r
+ DO_SFVTPV\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SPVFS[]: Set PVector From Stack */\r
+ /* Opcode range: 0x0A */\r
+ /* Stack: f2.14 f2.14 --> */\r
+ /* */\r
+ static void\r
+ Ins_SPVFS( INS_ARG )\r
+ {\r
+ DO_SPVFS\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SFVFS[]: Set FVector From Stack */\r
+ /* Opcode range: 0x0B */\r
+ /* Stack: f2.14 f2.14 --> */\r
+ /* */\r
+ static void\r
+ Ins_SFVFS( INS_ARG )\r
+ {\r
+ DO_SFVFS\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* GPV[]: Get Projection Vector */\r
+ /* Opcode range: 0x0C */\r
+ /* Stack: ef2.14 --> ef2.14 */\r
+ /* */\r
+ static void\r
+ Ins_GPV( INS_ARG )\r
+ {\r
+ DO_GPV\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* GFV[]: Get Freedom Vector */\r
+ /* Opcode range: 0x0D */\r
+ /* Stack: ef2.14 --> ef2.14 */\r
+ /* */\r
+ static void\r
+ Ins_GFV( INS_ARG )\r
+ {\r
+ DO_GFV\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SRP0[]: Set Reference Point 0 */\r
+ /* Opcode range: 0x10 */\r
+ /* Stack: uint32 --> */\r
+ /* */\r
+ static void\r
+ Ins_SRP0( INS_ARG )\r
+ {\r
+ DO_SRP0\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SRP1[]: Set Reference Point 1 */\r
+ /* Opcode range: 0x11 */\r
+ /* Stack: uint32 --> */\r
+ /* */\r
+ static void\r
+ Ins_SRP1( INS_ARG )\r
+ {\r
+ DO_SRP1\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SRP2[]: Set Reference Point 2 */\r
+ /* Opcode range: 0x12 */\r
+ /* Stack: uint32 --> */\r
+ /* */\r
+ static void\r
+ Ins_SRP2( INS_ARG )\r
+ {\r
+ DO_SRP2\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* RTHG[]: Round To Half Grid */\r
+ /* Opcode range: 0x19 */\r
+ /* Stack: --> */\r
+ /* */\r
+ static void\r
+ Ins_RTHG( INS_ARG )\r
+ {\r
+ DO_RTHG\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* RTG[]: Round To Grid */\r
+ /* Opcode range: 0x18 */\r
+ /* Stack: --> */\r
+ /* */\r
+ static void\r
+ Ins_RTG( INS_ARG )\r
+ {\r
+ DO_RTG\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* RTDG[]: Round To Double Grid */\r
+ /* Opcode range: 0x3D */\r
+ /* Stack: --> */\r
+ /* */\r
+ static void\r
+ Ins_RTDG( INS_ARG )\r
+ {\r
+ DO_RTDG\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* RUTG[]: Round Up To Grid */\r
+ /* Opcode range: 0x7C */\r
+ /* Stack: --> */\r
+ /* */\r
+ static void\r
+ Ins_RUTG( INS_ARG )\r
+ {\r
+ DO_RUTG\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* RDTG[]: Round Down To Grid */\r
+ /* Opcode range: 0x7D */\r
+ /* Stack: --> */\r
+ /* */\r
+ static void\r
+ Ins_RDTG( INS_ARG )\r
+ {\r
+ DO_RDTG\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* ROFF[]: Round OFF */\r
+ /* Opcode range: 0x7A */\r
+ /* Stack: --> */\r
+ /* */\r
+ static void\r
+ Ins_ROFF( INS_ARG )\r
+ {\r
+ DO_ROFF\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SROUND[]: Super ROUND */\r
+ /* Opcode range: 0x76 */\r
+ /* Stack: Eint8 --> */\r
+ /* */\r
+ static void\r
+ Ins_SROUND( INS_ARG )\r
+ {\r
+ DO_SROUND\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* S45ROUND[]: Super ROUND 45 degrees */\r
+ /* Opcode range: 0x77 */\r
+ /* Stack: uint32 --> */\r
+ /* */\r
+ static void\r
+ Ins_S45ROUND( INS_ARG )\r
+ {\r
+ DO_S45ROUND\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SLOOP[]: Set LOOP variable */\r
+ /* Opcode range: 0x17 */\r
+ /* Stack: int32? --> */\r
+ /* */\r
+ static void\r
+ Ins_SLOOP( INS_ARG )\r
+ {\r
+ DO_SLOOP\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SMD[]: Set Minimum Distance */\r
+ /* Opcode range: 0x1A */\r
+ /* Stack: f26.6 --> */\r
+ /* */\r
+ static void\r
+ Ins_SMD( INS_ARG )\r
+ {\r
+ DO_SMD\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SCVTCI[]: Set Control Value Table Cut In */\r
+ /* Opcode range: 0x1D */\r
+ /* Stack: f26.6 --> */\r
+ /* */\r
+ static void\r
+ Ins_SCVTCI( INS_ARG )\r
+ {\r
+ DO_SCVTCI\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SSWCI[]: Set Single Width Cut In */\r
+ /* Opcode range: 0x1E */\r
+ /* Stack: f26.6 --> */\r
+ /* */\r
+ static void\r
+ Ins_SSWCI( INS_ARG )\r
+ {\r
+ DO_SSWCI\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SSW[]: Set Single Width */\r
+ /* Opcode range: 0x1F */\r
+ /* Stack: int32? --> */\r
+ /* */\r
+ static void\r
+ Ins_SSW( INS_ARG )\r
+ {\r
+ DO_SSW\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* FLIPON[]: Set auto-FLIP to ON */\r
+ /* Opcode range: 0x4D */\r
+ /* Stack: --> */\r
+ /* */\r
+ static void\r
+ Ins_FLIPON( INS_ARG )\r
+ {\r
+ DO_FLIPON\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* FLIPOFF[]: Set auto-FLIP to OFF */\r
+ /* Opcode range: 0x4E */\r
+ /* Stack: --> */\r
+ /* */\r
+ static void\r
+ Ins_FLIPOFF( INS_ARG )\r
+ {\r
+ DO_FLIPOFF\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SANGW[]: Set ANGle Weight */\r
+ /* Opcode range: 0x7E */\r
+ /* Stack: uint32 --> */\r
+ /* */\r
+ static void\r
+ Ins_SANGW( INS_ARG )\r
+ {\r
+ /* instruction not supported anymore */\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SDB[]: Set Delta Base */\r
+ /* Opcode range: 0x5E */\r
+ /* Stack: uint32 --> */\r
+ /* */\r
+ static void\r
+ Ins_SDB( INS_ARG )\r
+ {\r
+ DO_SDB\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SDS[]: Set Delta Shift */\r
+ /* Opcode range: 0x5F */\r
+ /* Stack: uint32 --> */\r
+ /* */\r
+ static void\r
+ Ins_SDS( INS_ARG )\r
+ {\r
+ DO_SDS\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* MPPEM[]: Measure Pixel Per EM */\r
+ /* Opcode range: 0x4B */\r
+ /* Stack: --> Euint16 */\r
+ /* */\r
+ static void\r
+ Ins_MPPEM( INS_ARG )\r
+ {\r
+ DO_MPPEM\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* MPS[]: Measure Point Size */\r
+ /* Opcode range: 0x4C */\r
+ /* Stack: --> Euint16 */\r
+ /* */\r
+ static void\r
+ Ins_MPS( INS_ARG )\r
+ {\r
+ DO_MPS\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* DUP[]: DUPlicate the top stack's element */\r
+ /* Opcode range: 0x20 */\r
+ /* Stack: StkElt --> StkElt StkElt */\r
+ /* */\r
+ static void\r
+ Ins_DUP( INS_ARG )\r
+ {\r
+ DO_DUP\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* POP[]: POP the stack's top element */\r
+ /* Opcode range: 0x21 */\r
+ /* Stack: StkElt --> */\r
+ /* */\r
+ static void\r
+ Ins_POP( INS_ARG )\r
+ {\r
+ /* nothing to do */\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* CLEAR[]: CLEAR the entire stack */\r
+ /* Opcode range: 0x22 */\r
+ /* Stack: StkElt... --> */\r
+ /* */\r
+ static void\r
+ Ins_CLEAR( INS_ARG )\r
+ {\r
+ DO_CLEAR\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SWAP[]: SWAP the stack's top two elements */\r
+ /* Opcode range: 0x23 */\r
+ /* Stack: 2 * StkElt --> 2 * StkElt */\r
+ /* */\r
+ static void\r
+ Ins_SWAP( INS_ARG )\r
+ {\r
+ DO_SWAP\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* DEPTH[]: return the stack DEPTH */\r
+ /* Opcode range: 0x24 */\r
+ /* Stack: --> uint32 */\r
+ /* */\r
+ static void\r
+ Ins_DEPTH( INS_ARG )\r
+ {\r
+ DO_DEPTH\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* CINDEX[]: Copy INDEXed element */\r
+ /* Opcode range: 0x25 */\r
+ /* Stack: int32 --> StkElt */\r
+ /* */\r
+ static void\r
+ Ins_CINDEX( INS_ARG )\r
+ {\r
+ DO_CINDEX\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* EIF[]: End IF */\r
+ /* Opcode range: 0x59 */\r
+ /* Stack: --> */\r
+ /* */\r
+ static void\r
+ Ins_EIF( INS_ARG )\r
+ {\r
+ /* nothing to do */\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* JROT[]: Jump Relative On True */\r
+ /* Opcode range: 0x78 */\r
+ /* Stack: StkElt int32 --> */\r
+ /* */\r
+ static void\r
+ Ins_JROT( INS_ARG )\r
+ {\r
+ DO_JROT\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* JMPR[]: JuMP Relative */\r
+ /* Opcode range: 0x1C */\r
+ /* Stack: int32 --> */\r
+ /* */\r
+ static void\r
+ Ins_JMPR( INS_ARG )\r
+ {\r
+ DO_JMPR\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* JROF[]: Jump Relative On False */\r
+ /* Opcode range: 0x79 */\r
+ /* Stack: StkElt int32 --> */\r
+ /* */\r
+ static void\r
+ Ins_JROF( INS_ARG )\r
+ {\r
+ DO_JROF\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* LT[]: Less Than */\r
+ /* Opcode range: 0x50 */\r
+ /* Stack: int32? int32? --> bool */\r
+ /* */\r
+ static void\r
+ Ins_LT( INS_ARG )\r
+ {\r
+ DO_LT\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* LTEQ[]: Less Than or EQual */\r
+ /* Opcode range: 0x51 */\r
+ /* Stack: int32? int32? --> bool */\r
+ /* */\r
+ static void\r
+ Ins_LTEQ( INS_ARG )\r
+ {\r
+ DO_LTEQ\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* GT[]: Greater Than */\r
+ /* Opcode range: 0x52 */\r
+ /* Stack: int32? int32? --> bool */\r
+ /* */\r
+ static void\r
+ Ins_GT( INS_ARG )\r
+ {\r
+ DO_GT\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* GTEQ[]: Greater Than or EQual */\r
+ /* Opcode range: 0x53 */\r
+ /* Stack: int32? int32? --> bool */\r
+ /* */\r
+ static void\r
+ Ins_GTEQ( INS_ARG )\r
+ {\r
+ DO_GTEQ\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* EQ[]: EQual */\r
+ /* Opcode range: 0x54 */\r
+ /* Stack: StkElt StkElt --> bool */\r
+ /* */\r
+ static void\r
+ Ins_EQ( INS_ARG )\r
+ {\r
+ DO_EQ\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* NEQ[]: Not EQual */\r
+ /* Opcode range: 0x55 */\r
+ /* Stack: StkElt StkElt --> bool */\r
+ /* */\r
+ static void\r
+ Ins_NEQ( INS_ARG )\r
+ {\r
+ DO_NEQ\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* ODD[]: Is ODD */\r
+ /* Opcode range: 0x56 */\r
+ /* Stack: f26.6 --> bool */\r
+ /* */\r
+ static void\r
+ Ins_ODD( INS_ARG )\r
+ {\r
+ DO_ODD\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* EVEN[]: Is EVEN */\r
+ /* Opcode range: 0x57 */\r
+ /* Stack: f26.6 --> bool */\r
+ /* */\r
+ static void\r
+ Ins_EVEN( INS_ARG )\r
+ {\r
+ DO_EVEN\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* AND[]: logical AND */\r
+ /* Opcode range: 0x5A */\r
+ /* Stack: uint32 uint32 --> uint32 */\r
+ /* */\r
+ static void\r
+ Ins_AND( INS_ARG )\r
+ {\r
+ DO_AND\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* OR[]: logical OR */\r
+ /* Opcode range: 0x5B */\r
+ /* Stack: uint32 uint32 --> uint32 */\r
+ /* */\r
+ static void\r
+ Ins_OR( INS_ARG )\r
+ {\r
+ DO_OR\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* NOT[]: logical NOT */\r
+ /* Opcode range: 0x5C */\r
+ /* Stack: StkElt --> uint32 */\r
+ /* */\r
+ static void\r
+ Ins_NOT( INS_ARG )\r
+ {\r
+ DO_NOT\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* ADD[]: ADD */\r
+ /* Opcode range: 0x60 */\r
+ /* Stack: f26.6 f26.6 --> f26.6 */\r
+ /* */\r
+ static void\r
+ Ins_ADD( INS_ARG )\r
+ {\r
+ DO_ADD\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SUB[]: SUBtract */\r
+ /* Opcode range: 0x61 */\r
+ /* Stack: f26.6 f26.6 --> f26.6 */\r
+ /* */\r
+ static void\r
+ Ins_SUB( INS_ARG )\r
+ {\r
+ DO_SUB\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* DIV[]: DIVide */\r
+ /* Opcode range: 0x62 */\r
+ /* Stack: f26.6 f26.6 --> f26.6 */\r
+ /* */\r
+ static void\r
+ Ins_DIV( INS_ARG )\r
+ {\r
+ DO_DIV\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* MUL[]: MULtiply */\r
+ /* Opcode range: 0x63 */\r
+ /* Stack: f26.6 f26.6 --> f26.6 */\r
+ /* */\r
+ static void\r
+ Ins_MUL( INS_ARG )\r
+ {\r
+ DO_MUL\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* ABS[]: ABSolute value */\r
+ /* Opcode range: 0x64 */\r
+ /* Stack: f26.6 --> f26.6 */\r
+ /* */\r
+ static void\r
+ Ins_ABS( INS_ARG )\r
+ {\r
+ DO_ABS\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* NEG[]: NEGate */\r
+ /* Opcode range: 0x65 */\r
+ /* Stack: f26.6 --> f26.6 */\r
+ /* */\r
+ static void\r
+ Ins_NEG( INS_ARG )\r
+ {\r
+ DO_NEG\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* FLOOR[]: FLOOR */\r
+ /* Opcode range: 0x66 */\r
+ /* Stack: f26.6 --> f26.6 */\r
+ /* */\r
+ static void\r
+ Ins_FLOOR( INS_ARG )\r
+ {\r
+ DO_FLOOR\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* CEILING[]: CEILING */\r
+ /* Opcode range: 0x67 */\r
+ /* Stack: f26.6 --> f26.6 */\r
+ /* */\r
+ static void\r
+ Ins_CEILING( INS_ARG )\r
+ {\r
+ DO_CEILING\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* RS[]: Read Store */\r
+ /* Opcode range: 0x43 */\r
+ /* Stack: uint32 --> uint32 */\r
+ /* */\r
+ static void\r
+ Ins_RS( INS_ARG )\r
+ {\r
+ DO_RS\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* WS[]: Write Store */\r
+ /* Opcode range: 0x42 */\r
+ /* Stack: uint32 uint32 --> */\r
+ /* */\r
+ static void\r
+ Ins_WS( INS_ARG )\r
+ {\r
+ DO_WS\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* WCVTP[]: Write CVT in Pixel units */\r
+ /* Opcode range: 0x44 */\r
+ /* Stack: f26.6 uint32 --> */\r
+ /* */\r
+ static void\r
+ Ins_WCVTP( INS_ARG )\r
+ {\r
+ DO_WCVTP\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* WCVTF[]: Write CVT in Funits */\r
+ /* Opcode range: 0x70 */\r
+ /* Stack: uint32 uint32 --> */\r
+ /* */\r
+ static void\r
+ Ins_WCVTF( INS_ARG )\r
+ {\r
+ DO_WCVTF\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* RCVT[]: Read CVT */\r
+ /* Opcode range: 0x45 */\r
+ /* Stack: uint32 --> f26.6 */\r
+ /* */\r
+ static void\r
+ Ins_RCVT( INS_ARG )\r
+ {\r
+ DO_RCVT\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* AA[]: Adjust Angle */\r
+ /* Opcode range: 0x7F */\r
+ /* Stack: uint32 --> */\r
+ /* */\r
+ static void\r
+ Ins_AA( INS_ARG )\r
+ {\r
+ /* intentionally no longer supported */\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* DEBUG[]: DEBUG. Unsupported. */\r
+ /* Opcode range: 0x4F */\r
+ /* Stack: uint32 --> */\r
+ /* */\r
+ /* Note: The original instruction pops a value from the stack. */\r
+ /* */\r
+ static void\r
+ Ins_DEBUG( INS_ARG )\r
+ {\r
+ DO_DEBUG\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* ROUND[ab]: ROUND value */\r
+ /* Opcode range: 0x68-0x6B */\r
+ /* Stack: f26.6 --> f26.6 */\r
+ /* */\r
+ static void\r
+ Ins_ROUND( INS_ARG )\r
+ {\r
+ DO_ROUND\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* NROUND[ab]: No ROUNDing of value */\r
+ /* Opcode range: 0x6C-0x6F */\r
+ /* Stack: f26.6 --> f26.6 */\r
+ /* */\r
+ static void\r
+ Ins_NROUND( INS_ARG )\r
+ {\r
+ DO_NROUND\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* MAX[]: MAXimum */\r
+ /* Opcode range: 0x68 */\r
+ /* Stack: int32? int32? --> int32 */\r
+ /* */\r
+ static void\r
+ Ins_MAX( INS_ARG )\r
+ {\r
+ DO_MAX\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* MIN[]: MINimum */\r
+ /* Opcode range: 0x69 */\r
+ /* Stack: int32? int32? --> int32 */\r
+ /* */\r
+ static void\r
+ Ins_MIN( INS_ARG )\r
+ {\r
+ DO_MIN\r
+ }\r
+\r
+\r
+#endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* The following functions are called as is within the switch statement. */\r
+ /* */\r
+ /*************************************************************************/\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* MINDEX[]: Move INDEXed element */\r
+ /* Opcode range: 0x26 */\r
+ /* Stack: int32? --> StkElt */\r
+ /* */\r
+ static void\r
+ Ins_MINDEX( INS_ARG )\r
+ {\r
+ FT_Long L, K;\r
+\r
+\r
+ L = args[0];\r
+\r
+ if ( L <= 0 || L > CUR.args )\r
+ {\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+\r
+ K = CUR.stack[CUR.args - L];\r
+\r
+ FT_ARRAY_MOVE( &CUR.stack[CUR.args - L ],\r
+ &CUR.stack[CUR.args - L + 1],\r
+ ( L - 1 ) );\r
+\r
+ CUR.stack[CUR.args - 1] = K;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* ROLL[]: ROLL top three elements */\r
+ /* Opcode range: 0x8A */\r
+ /* Stack: 3 * StkElt --> 3 * StkElt */\r
+ /* */\r
+ static void\r
+ Ins_ROLL( INS_ARG )\r
+ {\r
+ FT_Long A, B, C;\r
+\r
+ FT_UNUSED_EXEC;\r
+\r
+\r
+ A = args[2];\r
+ B = args[1];\r
+ C = args[0];\r
+\r
+ args[2] = C;\r
+ args[1] = A;\r
+ args[0] = B;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* MANAGING THE FLOW OF CONTROL */\r
+ /* */\r
+ /* Instructions appear in the specification's order. */\r
+ /* */\r
+ /*************************************************************************/\r
+\r
+\r
+ static FT_Bool\r
+ SkipCode( EXEC_OP )\r
+ {\r
+ CUR.IP += CUR.length;\r
+\r
+ if ( CUR.IP < CUR.codeSize )\r
+ {\r
+ CUR.opcode = CUR.code[CUR.IP];\r
+\r
+ CUR.length = opcode_length[CUR.opcode];\r
+ if ( CUR.length < 0 )\r
+ {\r
+ if ( CUR.IP + 1 > CUR.codeSize )\r
+ goto Fail_Overflow;\r
+ CUR.length = 2 - CUR.length * CUR.code[CUR.IP + 1];\r
+ }\r
+\r
+ if ( CUR.IP + CUR.length <= CUR.codeSize )\r
+ return SUCCESS;\r
+ }\r
+\r
+ Fail_Overflow:\r
+ CUR.error = TT_Err_Code_Overflow;\r
+ return FAILURE;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* IF[]: IF test */\r
+ /* Opcode range: 0x58 */\r
+ /* Stack: StkElt --> */\r
+ /* */\r
+ static void\r
+ Ins_IF( INS_ARG )\r
+ {\r
+ FT_Int nIfs;\r
+ FT_Bool Out;\r
+\r
+\r
+ if ( args[0] != 0 )\r
+ return;\r
+\r
+ nIfs = 1;\r
+ Out = 0;\r
+\r
+ do\r
+ {\r
+ if ( SKIP_Code() == FAILURE )\r
+ return;\r
+\r
+ switch ( CUR.opcode )\r
+ {\r
+ case 0x58: /* IF */\r
+ nIfs++;\r
+ break;\r
+\r
+ case 0x1B: /* ELSE */\r
+ Out = FT_BOOL( nIfs == 1 );\r
+ break;\r
+\r
+ case 0x59: /* EIF */\r
+ nIfs--;\r
+ Out = FT_BOOL( nIfs == 0 );\r
+ break;\r
+ }\r
+ } while ( Out == 0 );\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* ELSE[]: ELSE */\r
+ /* Opcode range: 0x1B */\r
+ /* Stack: --> */\r
+ /* */\r
+ static void\r
+ Ins_ELSE( INS_ARG )\r
+ {\r
+ FT_Int nIfs;\r
+\r
+ FT_UNUSED_ARG;\r
+\r
+\r
+ nIfs = 1;\r
+\r
+ do\r
+ {\r
+ if ( SKIP_Code() == FAILURE )\r
+ return;\r
+\r
+ switch ( CUR.opcode )\r
+ {\r
+ case 0x58: /* IF */\r
+ nIfs++;\r
+ break;\r
+\r
+ case 0x59: /* EIF */\r
+ nIfs--;\r
+ break;\r
+ }\r
+ } while ( nIfs != 0 );\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS */\r
+ /* */\r
+ /* Instructions appear in the specification's order. */\r
+ /* */\r
+ /*************************************************************************/\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* FDEF[]: Function DEFinition */\r
+ /* Opcode range: 0x2C */\r
+ /* Stack: uint32 --> */\r
+ /* */\r
+ static void\r
+ Ins_FDEF( INS_ARG )\r
+ {\r
+ FT_ULong n;\r
+ TT_DefRecord* rec;\r
+ TT_DefRecord* limit;\r
+\r
+\r
+ /* some font programs are broken enough to redefine functions! */\r
+ /* We will then parse the current table. */\r
+\r
+ rec = CUR.FDefs;\r
+ limit = rec + CUR.numFDefs;\r
+ n = args[0];\r
+\r
+ for ( ; rec < limit; rec++ )\r
+ {\r
+ if ( rec->opc == n )\r
+ break;\r
+ }\r
+\r
+ if ( rec == limit )\r
+ {\r
+ /* check that there is enough room for new functions */\r
+ if ( CUR.numFDefs >= CUR.maxFDefs )\r
+ {\r
+ CUR.error = TT_Err_Too_Many_Function_Defs;\r
+ return;\r
+ }\r
+ CUR.numFDefs++;\r
+ }\r
+\r
+ rec->range = CUR.curRange;\r
+ rec->opc = n;\r
+ rec->start = CUR.IP + 1;\r
+ rec->active = TRUE;\r
+\r
+ if ( n > CUR.maxFunc )\r
+ CUR.maxFunc = n;\r
+\r
+ /* Now skip the whole function definition. */\r
+ /* We don't allow nested IDEFS & FDEFs. */\r
+\r
+ while ( SKIP_Code() == SUCCESS )\r
+ {\r
+ switch ( CUR.opcode )\r
+ {\r
+ case 0x89: /* IDEF */\r
+ case 0x2C: /* FDEF */\r
+ CUR.error = TT_Err_Nested_DEFS;\r
+ return;\r
+\r
+ case 0x2D: /* ENDF */\r
+ return;\r
+ }\r
+ }\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* ENDF[]: END Function definition */\r
+ /* Opcode range: 0x2D */\r
+ /* Stack: --> */\r
+ /* */\r
+ static void\r
+ Ins_ENDF( INS_ARG )\r
+ {\r
+ TT_CallRec* pRec;\r
+\r
+ FT_UNUSED_ARG;\r
+\r
+\r
+ if ( CUR.callTop <= 0 ) /* We encountered an ENDF without a call */\r
+ {\r
+ CUR.error = TT_Err_ENDF_In_Exec_Stream;\r
+ return;\r
+ }\r
+\r
+ CUR.callTop--;\r
+\r
+ pRec = &CUR.callStack[CUR.callTop];\r
+\r
+ pRec->Cur_Count--;\r
+\r
+ CUR.step_ins = FALSE;\r
+\r
+ if ( pRec->Cur_Count > 0 )\r
+ {\r
+ CUR.callTop++;\r
+ CUR.IP = pRec->Cur_Restart;\r
+ }\r
+ else\r
+ /* Loop through the current function */\r
+ INS_Goto_CodeRange( pRec->Caller_Range,\r
+ pRec->Caller_IP );\r
+\r
+ /* Exit the current call frame. */\r
+\r
+ /* NOTE: If the last instruction of a program is a */\r
+ /* CALL or LOOPCALL, the return address is */\r
+ /* always out of the code range. This is a */\r
+ /* valid address, and it is why we do not test */\r
+ /* the result of Ins_Goto_CodeRange() here! */\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* CALL[]: CALL function */\r
+ /* Opcode range: 0x2B */\r
+ /* Stack: uint32? --> */\r
+ /* */\r
+ static void\r
+ Ins_CALL( INS_ARG )\r
+ {\r
+ FT_ULong F;\r
+ TT_CallRec* pCrec;\r
+ TT_DefRecord* def;\r
+\r
+\r
+ /* first of all, check the index */\r
+\r
+ F = args[0];\r
+ if ( BOUNDS( F, CUR.maxFunc + 1 ) )\r
+ goto Fail;\r
+\r
+ /* Except for some old Apple fonts, all functions in a TrueType */\r
+ /* font are defined in increasing order, starting from 0. This */\r
+ /* means that we normally have */\r
+ /* */\r
+ /* CUR.maxFunc+1 == CUR.numFDefs */\r
+ /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */\r
+ /* */\r
+ /* If this isn't true, we need to look up the function table. */\r
+\r
+ def = CUR.FDefs + F;\r
+ if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F )\r
+ {\r
+ /* look up the FDefs table */\r
+ TT_DefRecord* limit;\r
+\r
+\r
+ def = CUR.FDefs;\r
+ limit = def + CUR.numFDefs;\r
+\r
+ while ( def < limit && def->opc != F )\r
+ def++;\r
+\r
+ if ( def == limit )\r
+ goto Fail;\r
+ }\r
+\r
+ /* check that the function is active */\r
+ if ( !def->active )\r
+ goto Fail;\r
+\r
+ /* check the call stack */\r
+ if ( CUR.callTop >= CUR.callSize )\r
+ {\r
+ CUR.error = TT_Err_Stack_Overflow;\r
+ return;\r
+ }\r
+\r
+ pCrec = CUR.callStack + CUR.callTop;\r
+\r
+ pCrec->Caller_Range = CUR.curRange;\r
+ pCrec->Caller_IP = CUR.IP + 1;\r
+ pCrec->Cur_Count = 1;\r
+ pCrec->Cur_Restart = def->start;\r
+\r
+ CUR.callTop++;\r
+\r
+ INS_Goto_CodeRange( def->range,\r
+ def->start );\r
+\r
+ CUR.step_ins = FALSE;\r
+ return;\r
+\r
+ Fail:\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* LOOPCALL[]: LOOP and CALL function */\r
+ /* Opcode range: 0x2A */\r
+ /* Stack: uint32? Eint16? --> */\r
+ /* */\r
+ static void\r
+ Ins_LOOPCALL( INS_ARG )\r
+ {\r
+ FT_ULong F;\r
+ TT_CallRec* pCrec;\r
+ TT_DefRecord* def;\r
+\r
+\r
+ /* first of all, check the index */\r
+ F = args[1];\r
+ if ( BOUNDS( F, CUR.maxFunc + 1 ) )\r
+ goto Fail;\r
+\r
+ /* Except for some old Apple fonts, all functions in a TrueType */\r
+ /* font are defined in increasing order, starting from 0. This */\r
+ /* means that we normally have */\r
+ /* */\r
+ /* CUR.maxFunc+1 == CUR.numFDefs */\r
+ /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */\r
+ /* */\r
+ /* If this isn't true, we need to look up the function table. */\r
+\r
+ def = CUR.FDefs + F;\r
+ if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F )\r
+ {\r
+ /* look up the FDefs table */\r
+ TT_DefRecord* limit;\r
+\r
+\r
+ def = CUR.FDefs;\r
+ limit = def + CUR.numFDefs;\r
+\r
+ while ( def < limit && def->opc != F )\r
+ def++;\r
+\r
+ if ( def == limit )\r
+ goto Fail;\r
+ }\r
+\r
+ /* check that the function is active */\r
+ if ( !def->active )\r
+ goto Fail;\r
+\r
+ /* check stack */\r
+ if ( CUR.callTop >= CUR.callSize )\r
+ {\r
+ CUR.error = TT_Err_Stack_Overflow;\r
+ return;\r
+ }\r
+\r
+ if ( args[0] > 0 )\r
+ {\r
+ pCrec = CUR.callStack + CUR.callTop;\r
+\r
+ pCrec->Caller_Range = CUR.curRange;\r
+ pCrec->Caller_IP = CUR.IP + 1;\r
+ pCrec->Cur_Count = (FT_Int)args[0];\r
+ pCrec->Cur_Restart = def->start;\r
+\r
+ CUR.callTop++;\r
+\r
+ INS_Goto_CodeRange( def->range, def->start );\r
+\r
+ CUR.step_ins = FALSE;\r
+ }\r
+ return;\r
+\r
+ Fail:\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* IDEF[]: Instruction DEFinition */\r
+ /* Opcode range: 0x89 */\r
+ /* Stack: Eint8 --> */\r
+ /* */\r
+ static void\r
+ Ins_IDEF( INS_ARG )\r
+ {\r
+ TT_DefRecord* def;\r
+ TT_DefRecord* limit;\r
+\r
+\r
+ /* First of all, look for the same function in our table */\r
+\r
+ def = CUR.IDefs;\r
+ limit = def + CUR.numIDefs;\r
+\r
+ for ( ; def < limit; def++ )\r
+ if ( def->opc == (FT_ULong)args[0] )\r
+ break;\r
+\r
+ if ( def == limit )\r
+ {\r
+ /* check that there is enough room for a new instruction */\r
+ if ( CUR.numIDefs >= CUR.maxIDefs )\r
+ {\r
+ CUR.error = TT_Err_Too_Many_Instruction_Defs;\r
+ return;\r
+ }\r
+ CUR.numIDefs++;\r
+ }\r
+\r
+ def->opc = args[0];\r
+ def->start = CUR.IP+1;\r
+ def->range = CUR.curRange;\r
+ def->active = TRUE;\r
+\r
+ if ( (FT_ULong)args[0] > CUR.maxIns )\r
+ CUR.maxIns = args[0];\r
+\r
+ /* Now skip the whole function definition. */\r
+ /* We don't allow nested IDEFs & FDEFs. */\r
+\r
+ while ( SKIP_Code() == SUCCESS )\r
+ {\r
+ switch ( CUR.opcode )\r
+ {\r
+ case 0x89: /* IDEF */\r
+ case 0x2C: /* FDEF */\r
+ CUR.error = TT_Err_Nested_DEFS;\r
+ return;\r
+ case 0x2D: /* ENDF */\r
+ return;\r
+ }\r
+ }\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* PUSHING DATA ONTO THE INTERPRETER STACK */\r
+ /* */\r
+ /* Instructions appear in the specification's order. */\r
+ /* */\r
+ /*************************************************************************/\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* NPUSHB[]: PUSH N Bytes */\r
+ /* Opcode range: 0x40 */\r
+ /* Stack: --> uint32... */\r
+ /* */\r
+ static void\r
+ Ins_NPUSHB( INS_ARG )\r
+ {\r
+ FT_UShort L, K;\r
+\r
+\r
+ L = (FT_UShort)CUR.code[CUR.IP + 1];\r
+\r
+ if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )\r
+ {\r
+ CUR.error = TT_Err_Stack_Overflow;\r
+ return;\r
+ }\r
+\r
+ for ( K = 1; K <= L; K++ )\r
+ args[K - 1] = CUR.code[CUR.IP + K + 1];\r
+\r
+ CUR.new_top += L;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* NPUSHW[]: PUSH N Words */\r
+ /* Opcode range: 0x41 */\r
+ /* Stack: --> int32... */\r
+ /* */\r
+ static void\r
+ Ins_NPUSHW( INS_ARG )\r
+ {\r
+ FT_UShort L, K;\r
+\r
+\r
+ L = (FT_UShort)CUR.code[CUR.IP + 1];\r
+\r
+ if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )\r
+ {\r
+ CUR.error = TT_Err_Stack_Overflow;\r
+ return;\r
+ }\r
+\r
+ CUR.IP += 2;\r
+\r
+ for ( K = 0; K < L; K++ )\r
+ args[K] = GET_ShortIns();\r
+\r
+ CUR.step_ins = FALSE;\r
+ CUR.new_top += L;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* PUSHB[abc]: PUSH Bytes */\r
+ /* Opcode range: 0xB0-0xB7 */\r
+ /* Stack: --> uint32... */\r
+ /* */\r
+ static void\r
+ Ins_PUSHB( INS_ARG )\r
+ {\r
+ FT_UShort L, K;\r
+\r
+\r
+ L = (FT_UShort)( CUR.opcode - 0xB0 + 1 );\r
+\r
+ if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )\r
+ {\r
+ CUR.error = TT_Err_Stack_Overflow;\r
+ return;\r
+ }\r
+\r
+ for ( K = 1; K <= L; K++ )\r
+ args[K - 1] = CUR.code[CUR.IP + K];\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* PUSHW[abc]: PUSH Words */\r
+ /* Opcode range: 0xB8-0xBF */\r
+ /* Stack: --> int32... */\r
+ /* */\r
+ static void\r
+ Ins_PUSHW( INS_ARG )\r
+ {\r
+ FT_UShort L, K;\r
+\r
+\r
+ L = (FT_UShort)( CUR.opcode - 0xB8 + 1 );\r
+\r
+ if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )\r
+ {\r
+ CUR.error = TT_Err_Stack_Overflow;\r
+ return;\r
+ }\r
+\r
+ CUR.IP++;\r
+\r
+ for ( K = 0; K < L; K++ )\r
+ args[K] = GET_ShortIns();\r
+\r
+ CUR.step_ins = FALSE;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* MANAGING THE GRAPHICS STATE */\r
+ /* */\r
+ /* Instructions appear in the specs' order. */\r
+ /* */\r
+ /*************************************************************************/\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* GC[a]: Get Coordinate projected onto */\r
+ /* Opcode range: 0x46-0x47 */\r
+ /* Stack: uint32 --> f26.6 */\r
+ /* */\r
+ /* BULLSHIT: Measures from the original glyph must be taken along the */\r
+ /* dual projection vector! */\r
+ /* */\r
+ static void\r
+ Ins_GC( INS_ARG )\r
+ {\r
+ FT_ULong L;\r
+ FT_F26Dot6 R;\r
+\r
+\r
+ L = (FT_ULong)args[0];\r
+\r
+ if ( BOUNDS( L, CUR.zp2.n_points ) )\r
+ {\r
+ if ( CUR.pedantic_hinting )\r
+ {\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+ else\r
+ R = 0;\r
+ }\r
+ else\r
+ {\r
+ if ( CUR.opcode & 1 )\r
+ R = CUR_fast_dualproj( &CUR.zp2.org[L] );\r
+ else\r
+ R = CUR_fast_project( &CUR.zp2.cur[L] );\r
+ }\r
+\r
+ args[0] = R;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SCFS[]: Set Coordinate From Stack */\r
+ /* Opcode range: 0x48 */\r
+ /* Stack: f26.6 uint32 --> */\r
+ /* */\r
+ /* Formula: */\r
+ /* */\r
+ /* OA := OA + ( value - OA.p )/( f.p ) * f */\r
+ /* */\r
+ static void\r
+ Ins_SCFS( INS_ARG )\r
+ {\r
+ FT_Long K;\r
+ FT_UShort L;\r
+\r
+\r
+ L = (FT_UShort)args[0];\r
+\r
+ if ( BOUNDS( L, CUR.zp2.n_points ) )\r
+ {\r
+ if ( CUR.pedantic_hinting )\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+\r
+ K = CUR_fast_project( &CUR.zp2.cur[L] );\r
+\r
+ CUR_Func_move( &CUR.zp2, L, args[1] - K );\r
+\r
+ /* not part of the specs, but here for safety */\r
+\r
+ if ( CUR.GS.gep2 == 0 )\r
+ CUR.zp2.org[L] = CUR.zp2.cur[L];\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* MD[a]: Measure Distance */\r
+ /* Opcode range: 0x49-0x4A */\r
+ /* Stack: uint32 uint32 --> f26.6 */\r
+ /* */\r
+ /* BULLSHIT: Measure taken in the original glyph must be along the dual */\r
+ /* projection vector. */\r
+ /* */\r
+ /* Second BULLSHIT: Flag attributes are inverted! */\r
+ /* 0 => measure distance in original outline */\r
+ /* 1 => measure distance in grid-fitted outline */\r
+ /* */\r
+ /* Third one: `zp0 - zp1', and not `zp2 - zp1! */\r
+ /* */\r
+ static void\r
+ Ins_MD( INS_ARG )\r
+ {\r
+ FT_UShort K, L;\r
+ FT_F26Dot6 D;\r
+\r
+\r
+ K = (FT_UShort)args[1];\r
+ L = (FT_UShort)args[0];\r
+\r
+ if( BOUNDS( L, CUR.zp0.n_points ) ||\r
+ BOUNDS( K, CUR.zp1.n_points ) )\r
+ {\r
+ if ( CUR.pedantic_hinting )\r
+ {\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+ D = 0;\r
+ }\r
+ else\r
+ {\r
+ if ( CUR.opcode & 1 )\r
+ D = CUR_Func_project( CUR.zp0.cur + L, CUR.zp1.cur + K );\r
+ else\r
+ D = CUR_Func_dualproj( CUR.zp0.org + L, CUR.zp1.org + K );\r
+ }\r
+\r
+ args[0] = D;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SDPVTL[a]: Set Dual PVector to Line */\r
+ /* Opcode range: 0x86-0x87 */\r
+ /* Stack: uint32 uint32 --> */\r
+ /* */\r
+ static void\r
+ Ins_SDPVTL( INS_ARG )\r
+ {\r
+ FT_Long A, B, C;\r
+ FT_UShort p1, p2; /* was FT_Int in pas type ERROR */\r
+\r
+\r
+ p1 = (FT_UShort)args[1];\r
+ p2 = (FT_UShort)args[0];\r
+\r
+ if ( BOUNDS( p2, CUR.zp1.n_points ) ||\r
+ BOUNDS( p1, CUR.zp2.n_points ) )\r
+ {\r
+ if ( CUR.pedantic_hinting )\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+\r
+ {\r
+ FT_Vector* v1 = CUR.zp1.org + p2;\r
+ FT_Vector* v2 = CUR.zp2.org + p1;\r
+\r
+\r
+ A = v1->x - v2->x;\r
+ B = v1->y - v2->y;\r
+ }\r
+\r
+ if ( ( CUR.opcode & 1 ) != 0 )\r
+ {\r
+ C = B; /* counter clockwise rotation */\r
+ B = A;\r
+ A = -C;\r
+ }\r
+\r
+ NORMalize( A, B, &CUR.GS.dualVector );\r
+\r
+ {\r
+ FT_Vector* v1 = CUR.zp1.cur + p2;\r
+ FT_Vector* v2 = CUR.zp2.cur + p1;\r
+\r
+\r
+ A = v1->x - v2->x;\r
+ B = v1->y - v2->y;\r
+ }\r
+\r
+ if ( ( CUR.opcode & 1 ) != 0 )\r
+ {\r
+ C = B; /* counter clockwise rotation */\r
+ B = A;\r
+ A = -C;\r
+ }\r
+\r
+ NORMalize( A, B, &CUR.GS.projVector );\r
+\r
+ GUESS_VECTOR( freeVector );\r
+\r
+ COMPUTE_Funcs();\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SZP0[]: Set Zone Pointer 0 */\r
+ /* Opcode range: 0x13 */\r
+ /* Stack: uint32 --> */\r
+ /* */\r
+ static void\r
+ Ins_SZP0( INS_ARG )\r
+ {\r
+ switch ( (FT_Int)args[0] )\r
+ {\r
+ case 0:\r
+ CUR.zp0 = CUR.twilight;\r
+ break;\r
+\r
+ case 1:\r
+ CUR.zp0 = CUR.pts;\r
+ break;\r
+\r
+ default:\r
+ if ( CUR.pedantic_hinting )\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+\r
+ CUR.GS.gep0 = (FT_UShort)args[0];\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SZP1[]: Set Zone Pointer 1 */\r
+ /* Opcode range: 0x14 */\r
+ /* Stack: uint32 --> */\r
+ /* */\r
+ static void\r
+ Ins_SZP1( INS_ARG )\r
+ {\r
+ switch ( (FT_Int)args[0] )\r
+ {\r
+ case 0:\r
+ CUR.zp1 = CUR.twilight;\r
+ break;\r
+\r
+ case 1:\r
+ CUR.zp1 = CUR.pts;\r
+ break;\r
+\r
+ default:\r
+ if ( CUR.pedantic_hinting )\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+\r
+ CUR.GS.gep1 = (FT_UShort)args[0];\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SZP2[]: Set Zone Pointer 2 */\r
+ /* Opcode range: 0x15 */\r
+ /* Stack: uint32 --> */\r
+ /* */\r
+ static void\r
+ Ins_SZP2( INS_ARG )\r
+ {\r
+ switch ( (FT_Int)args[0] )\r
+ {\r
+ case 0:\r
+ CUR.zp2 = CUR.twilight;\r
+ break;\r
+\r
+ case 1:\r
+ CUR.zp2 = CUR.pts;\r
+ break;\r
+\r
+ default:\r
+ if ( CUR.pedantic_hinting )\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+\r
+ CUR.GS.gep2 = (FT_UShort)args[0];\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SZPS[]: Set Zone PointerS */\r
+ /* Opcode range: 0x16 */\r
+ /* Stack: uint32 --> */\r
+ /* */\r
+ static void\r
+ Ins_SZPS( INS_ARG )\r
+ {\r
+ switch ( (FT_Int)args[0] )\r
+ {\r
+ case 0:\r
+ CUR.zp0 = CUR.twilight;\r
+ break;\r
+\r
+ case 1:\r
+ CUR.zp0 = CUR.pts;\r
+ break;\r
+\r
+ default:\r
+ if ( CUR.pedantic_hinting )\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+\r
+ CUR.zp1 = CUR.zp0;\r
+ CUR.zp2 = CUR.zp0;\r
+\r
+ CUR.GS.gep0 = (FT_UShort)args[0];\r
+ CUR.GS.gep1 = (FT_UShort)args[0];\r
+ CUR.GS.gep2 = (FT_UShort)args[0];\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* INSTCTRL[]: INSTruction ConTRoL */\r
+ /* Opcode range: 0x8e */\r
+ /* Stack: int32 int32 --> */\r
+ /* */\r
+ static void\r
+ Ins_INSTCTRL( INS_ARG )\r
+ {\r
+ FT_Long K, L;\r
+\r
+\r
+ K = args[1];\r
+ L = args[0];\r
+\r
+ if ( K < 1 || K > 2 )\r
+ {\r
+ if ( CUR.pedantic_hinting )\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+\r
+ if ( L != 0 )\r
+ L = K;\r
+\r
+ CUR.GS.instruct_control = FT_BOOL(\r
+ ( (FT_Byte)CUR.GS.instruct_control & ~(FT_Byte)K ) | (FT_Byte)L );\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SCANCTRL[]: SCAN ConTRoL */\r
+ /* Opcode range: 0x85 */\r
+ /* Stack: uint32? --> */\r
+ /* */\r
+ static void\r
+ Ins_SCANCTRL( INS_ARG )\r
+ {\r
+ FT_Int A;\r
+\r
+\r
+ /* Get Threshold */\r
+ A = (FT_Int)( args[0] & 0xFF );\r
+\r
+ if ( A == 0xFF )\r
+ {\r
+ CUR.GS.scan_control = TRUE;\r
+ return;\r
+ }\r
+ else if ( A == 0 )\r
+ {\r
+ CUR.GS.scan_control = FALSE;\r
+ return;\r
+ }\r
+\r
+ A *= 64;\r
+\r
+#if 0\r
+ if ( ( args[0] & 0x100 ) != 0 && CUR.metrics.pointSize <= A )\r
+ CUR.GS.scan_control = TRUE;\r
+#endif\r
+\r
+ if ( ( args[0] & 0x200 ) != 0 && CUR.tt_metrics.rotated )\r
+ CUR.GS.scan_control = TRUE;\r
+\r
+ if ( ( args[0] & 0x400 ) != 0 && CUR.tt_metrics.stretched )\r
+ CUR.GS.scan_control = TRUE;\r
+\r
+#if 0\r
+ if ( ( args[0] & 0x800 ) != 0 && CUR.metrics.pointSize > A )\r
+ CUR.GS.scan_control = FALSE;\r
+#endif\r
+\r
+ if ( ( args[0] & 0x1000 ) != 0 && CUR.tt_metrics.rotated )\r
+ CUR.GS.scan_control = FALSE;\r
+\r
+ if ( ( args[0] & 0x2000 ) != 0 && CUR.tt_metrics.stretched )\r
+ CUR.GS.scan_control = FALSE;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SCANTYPE[]: SCAN TYPE */\r
+ /* Opcode range: 0x8D */\r
+ /* Stack: uint32? --> */\r
+ /* */\r
+ static void\r
+ Ins_SCANTYPE( INS_ARG )\r
+ {\r
+ /* for compatibility with future enhancements, */\r
+ /* we must ignore new modes */\r
+\r
+ if ( args[0] >= 0 && args[0] <= 5 )\r
+ {\r
+ if ( args[0] == 3 )\r
+ args[0] = 2;\r
+\r
+ CUR.GS.scan_type = (FT_Int)args[0];\r
+ }\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* MANAGING OUTLINES */\r
+ /* */\r
+ /* Instructions appear in the specification's order. */\r
+ /* */\r
+ /*************************************************************************/\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* FLIPPT[]: FLIP PoinT */\r
+ /* Opcode range: 0x80 */\r
+ /* Stack: uint32... --> */\r
+ /* */\r
+ static void\r
+ Ins_FLIPPT( INS_ARG )\r
+ {\r
+ FT_UShort point;\r
+\r
+ FT_UNUSED_ARG;\r
+\r
+\r
+ if ( CUR.top < CUR.GS.loop )\r
+ {\r
+ CUR.error = TT_Err_Too_Few_Arguments;\r
+ return;\r
+ }\r
+\r
+ while ( CUR.GS.loop > 0 )\r
+ {\r
+ CUR.args--;\r
+\r
+ point = (FT_UShort)CUR.stack[CUR.args];\r
+\r
+ if ( BOUNDS( point, CUR.pts.n_points ) )\r
+ {\r
+ if ( CUR.pedantic_hinting )\r
+ {\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+ }\r
+ else\r
+ CUR.pts.tags[point] ^= FT_CURVE_TAG_ON;\r
+\r
+ CUR.GS.loop--;\r
+ }\r
+\r
+ CUR.GS.loop = 1;\r
+ CUR.new_top = CUR.args;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* FLIPRGON[]: FLIP RanGe ON */\r
+ /* Opcode range: 0x81 */\r
+ /* Stack: uint32 uint32 --> */\r
+ /* */\r
+ static void\r
+ Ins_FLIPRGON( INS_ARG )\r
+ {\r
+ FT_UShort I, K, L;\r
+\r
+\r
+ K = (FT_UShort)args[1];\r
+ L = (FT_UShort)args[0];\r
+\r
+ if ( BOUNDS( K, CUR.pts.n_points ) ||\r
+ BOUNDS( L, CUR.pts.n_points ) )\r
+ {\r
+ if ( CUR.pedantic_hinting )\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+\r
+ for ( I = L; I <= K; I++ )\r
+ CUR.pts.tags[I] |= FT_CURVE_TAG_ON;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* FLIPRGOFF: FLIP RanGe OFF */\r
+ /* Opcode range: 0x82 */\r
+ /* Stack: uint32 uint32 --> */\r
+ /* */\r
+ static void\r
+ Ins_FLIPRGOFF( INS_ARG )\r
+ {\r
+ FT_UShort I, K, L;\r
+\r
+\r
+ K = (FT_UShort)args[1];\r
+ L = (FT_UShort)args[0];\r
+\r
+ if ( BOUNDS( K, CUR.pts.n_points ) ||\r
+ BOUNDS( L, CUR.pts.n_points ) )\r
+ {\r
+ if ( CUR.pedantic_hinting )\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+\r
+ for ( I = L; I <= K; I++ )\r
+ CUR.pts.tags[I] &= ~FT_CURVE_TAG_ON;\r
+ }\r
+\r
+\r
+ static FT_Bool\r
+ Compute_Point_Displacement( EXEC_OP_ FT_F26Dot6* x,\r
+ FT_F26Dot6* y,\r
+ TT_GlyphZone zone,\r
+ FT_UShort* refp )\r
+ {\r
+ TT_GlyphZoneRec zp;\r
+ FT_UShort p;\r
+ FT_F26Dot6 d;\r
+\r
+\r
+ if ( CUR.opcode & 1 )\r
+ {\r
+ zp = CUR.zp0;\r
+ p = CUR.GS.rp1;\r
+ }\r
+ else\r
+ {\r
+ zp = CUR.zp1;\r
+ p = CUR.GS.rp2;\r
+ }\r
+\r
+ if ( BOUNDS( p, zp.n_points ) )\r
+ {\r
+ if ( CUR.pedantic_hinting )\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ *refp = 0;\r
+ return FAILURE;\r
+ }\r
+\r
+ *zone = zp;\r
+ *refp = p;\r
+\r
+ d = CUR_Func_project( zp.cur + p, zp.org + p );\r
+\r
+#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING\r
+ if ( CUR.face->unpatented_hinting )\r
+ {\r
+ if ( CUR.GS.both_x_axis )\r
+ {\r
+ *x = d;\r
+ *y = 0;\r
+ }\r
+ else\r
+ {\r
+ *x = 0;\r
+ *y = d;\r
+ }\r
+ }\r
+ else\r
+#endif\r
+ {\r
+ *x = TT_MULDIV( d,\r
+ (FT_Long)CUR.GS.freeVector.x * 0x10000L,\r
+ CUR.F_dot_P );\r
+ *y = TT_MULDIV( d,\r
+ (FT_Long)CUR.GS.freeVector.y * 0x10000L,\r
+ CUR.F_dot_P );\r
+ }\r
+\r
+ return SUCCESS;\r
+ }\r
+\r
+\r
+ static void\r
+ Move_Zp2_Point( EXEC_OP_ FT_UShort point,\r
+ FT_F26Dot6 dx,\r
+ FT_F26Dot6 dy,\r
+ FT_Bool touch )\r
+ {\r
+#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING\r
+ if ( CUR.face->unpatented_hinting )\r
+ {\r
+ if ( CUR.GS.both_x_axis )\r
+ {\r
+ CUR.zp2.cur[point].x += dx;\r
+ if ( touch )\r
+ CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X;\r
+ }\r
+ else\r
+ {\r
+ CUR.zp2.cur[point].y += dy;\r
+ if ( touch )\r
+ CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y;\r
+ }\r
+ return;\r
+ }\r
+#endif\r
+\r
+ if ( CUR.GS.freeVector.x != 0 )\r
+ {\r
+ CUR.zp2.cur[point].x += dx;\r
+ if ( touch )\r
+ CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X;\r
+ }\r
+\r
+ if ( CUR.GS.freeVector.y != 0 )\r
+ {\r
+ CUR.zp2.cur[point].y += dy;\r
+ if ( touch )\r
+ CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y;\r
+ }\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SHP[a]: SHift Point by the last point */\r
+ /* Opcode range: 0x32-0x33 */\r
+ /* Stack: uint32... --> */\r
+ /* */\r
+ static void\r
+ Ins_SHP( INS_ARG )\r
+ {\r
+ TT_GlyphZoneRec zp;\r
+ FT_UShort refp;\r
+\r
+ FT_F26Dot6 dx,\r
+ dy;\r
+ FT_UShort point;\r
+\r
+ FT_UNUSED_ARG;\r
+\r
+\r
+ if ( CUR.top < CUR.GS.loop )\r
+ {\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+\r
+ if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )\r
+ return;\r
+\r
+ while ( CUR.GS.loop > 0 )\r
+ {\r
+ CUR.args--;\r
+ point = (FT_UShort)CUR.stack[CUR.args];\r
+\r
+ if ( BOUNDS( point, CUR.zp2.n_points ) )\r
+ {\r
+ if ( CUR.pedantic_hinting )\r
+ {\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+ }\r
+ else\r
+ /* XXX: UNDOCUMENTED! SHP touches the points */\r
+ MOVE_Zp2_Point( point, dx, dy, TRUE );\r
+\r
+ CUR.GS.loop--;\r
+ }\r
+\r
+ CUR.GS.loop = 1;\r
+ CUR.new_top = CUR.args;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SHC[a]: SHift Contour */\r
+ /* Opcode range: 0x34-35 */\r
+ /* Stack: uint32 --> */\r
+ /* */\r
+ static void\r
+ Ins_SHC( INS_ARG )\r
+ {\r
+ TT_GlyphZoneRec zp;\r
+ FT_UShort refp;\r
+ FT_F26Dot6 dx,\r
+ dy;\r
+\r
+ FT_Short contour;\r
+ FT_UShort first_point, last_point, i;\r
+\r
+\r
+ contour = (FT_UShort)args[0];\r
+\r
+ if ( BOUNDS( contour, CUR.pts.n_contours ) )\r
+ {\r
+ if ( CUR.pedantic_hinting )\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+\r
+ if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )\r
+ return;\r
+\r
+ if ( contour == 0 )\r
+ first_point = 0;\r
+ else\r
+ first_point = (FT_UShort)( CUR.pts.contours[contour - 1] + 1 -\r
+ CUR.pts.first_point );\r
+\r
+ last_point = (FT_UShort)( CUR.pts.contours[contour] -\r
+ CUR.pts.first_point );\r
+\r
+ /* XXX: this is probably wrong... at least it prevents memory */\r
+ /* corruption when zp2 is the twilight zone */\r
+ if ( last_point > CUR.zp2.n_points )\r
+ {\r
+ if ( CUR.zp2.n_points > 0 )\r
+ last_point = (FT_UShort)(CUR.zp2.n_points - 1);\r
+ else\r
+ last_point = 0;\r
+ }\r
+\r
+ /* XXX: UNDOCUMENTED! SHC touches the points */\r
+ for ( i = first_point; i <= last_point; i++ )\r
+ {\r
+ if ( zp.cur != CUR.zp2.cur || refp != i )\r
+ MOVE_Zp2_Point( i, dx, dy, TRUE );\r
+ }\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SHZ[a]: SHift Zone */\r
+ /* Opcode range: 0x36-37 */\r
+ /* Stack: uint32 --> */\r
+ /* */\r
+ static void\r
+ Ins_SHZ( INS_ARG )\r
+ {\r
+ TT_GlyphZoneRec zp;\r
+ FT_UShort refp;\r
+ FT_F26Dot6 dx,\r
+ dy;\r
+\r
+ FT_UShort last_point, i;\r
+\r
+\r
+ if ( BOUNDS( args[0], 2 ) )\r
+ {\r
+ if ( CUR.pedantic_hinting )\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+\r
+ if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )\r
+ return;\r
+\r
+ /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points. */\r
+ /* Twilight zone has no contours, so use `n_points'. */\r
+ /* Normal zone's `n_points' includes phantoms, so must */\r
+ /* use end of last contour. */\r
+ if ( CUR.GS.gep2 == 0 && CUR.zp2.n_points > 0 )\r
+ last_point = (FT_UShort)( CUR.zp2.n_points - 1 );\r
+ else if ( CUR.GS.gep2 == 1 && CUR.zp2.n_contours > 0 )\r
+ last_point = (FT_UShort)( CUR.zp2.contours[CUR.zp2.n_contours - 1] );\r
+ else\r
+ last_point = 0;\r
+\r
+ /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */\r
+ for ( i = 0; i <= last_point; i++ )\r
+ {\r
+ if ( zp.cur != CUR.zp2.cur || refp != i )\r
+ MOVE_Zp2_Point( i, dx, dy, FALSE );\r
+ }\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* SHPIX[]: SHift points by a PIXel amount */\r
+ /* Opcode range: 0x38 */\r
+ /* Stack: f26.6 uint32... --> */\r
+ /* */\r
+ static void\r
+ Ins_SHPIX( INS_ARG )\r
+ {\r
+ FT_F26Dot6 dx, dy;\r
+ FT_UShort point;\r
+\r
+\r
+ if ( CUR.top < CUR.GS.loop + 1 )\r
+ {\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+\r
+#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING\r
+ if ( CUR.face->unpatented_hinting )\r
+ {\r
+ if ( CUR.GS.both_x_axis )\r
+ {\r
+ dx = TT_MulFix14( args[0], 0x4000 );\r
+ dy = 0;\r
+ }\r
+ else\r
+ {\r
+ dx = 0;\r
+ dy = TT_MulFix14( args[0], 0x4000 );\r
+ }\r
+ }\r
+ else\r
+#endif\r
+ {\r
+ dx = TT_MulFix14( args[0], CUR.GS.freeVector.x );\r
+ dy = TT_MulFix14( args[0], CUR.GS.freeVector.y );\r
+ }\r
+\r
+ while ( CUR.GS.loop > 0 )\r
+ {\r
+ CUR.args--;\r
+\r
+ point = (FT_UShort)CUR.stack[CUR.args];\r
+\r
+ if ( BOUNDS( point, CUR.zp2.n_points ) )\r
+ {\r
+ if ( CUR.pedantic_hinting )\r
+ {\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+ }\r
+ else\r
+ MOVE_Zp2_Point( point, dx, dy, TRUE );\r
+\r
+ CUR.GS.loop--;\r
+ }\r
+\r
+ CUR.GS.loop = 1;\r
+ CUR.new_top = CUR.args;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* MSIRP[a]: Move Stack Indirect Relative Position */\r
+ /* Opcode range: 0x3A-0x3B */\r
+ /* Stack: f26.6 uint32 --> */\r
+ /* */\r
+ static void\r
+ Ins_MSIRP( INS_ARG )\r
+ {\r
+ FT_UShort point;\r
+ FT_F26Dot6 distance;\r
+\r
+\r
+ point = (FT_UShort)args[0];\r
+\r
+ if ( BOUNDS( point, CUR.zp1.n_points ) ||\r
+ BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )\r
+ {\r
+ if ( CUR.pedantic_hinting )\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+\r
+ /* XXX: UNDOCUMENTED! behaviour */\r
+ if ( CUR.GS.gep1 == 0 ) /* if the point that is to be moved */\r
+ /* is in twilight zone */\r
+ {\r
+ CUR.zp1.org[point] = CUR.zp0.org[CUR.GS.rp0];\r
+ CUR_Func_move_orig( &CUR.zp1, point, args[1] );\r
+ CUR.zp1.cur[point] = CUR.zp1.org[point];\r
+ }\r
+\r
+ distance = CUR_Func_project( CUR.zp1.cur + point,\r
+ CUR.zp0.cur + CUR.GS.rp0 );\r
+\r
+ CUR_Func_move( &CUR.zp1, point, args[1] - distance );\r
+\r
+ CUR.GS.rp1 = CUR.GS.rp0;\r
+ CUR.GS.rp2 = point;\r
+\r
+ if ( ( CUR.opcode & 1 ) != 0 )\r
+ CUR.GS.rp0 = point;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* MDAP[a]: Move Direct Absolute Point */\r
+ /* Opcode range: 0x2E-0x2F */\r
+ /* Stack: uint32 --> */\r
+ /* */\r
+ static void\r
+ Ins_MDAP( INS_ARG )\r
+ {\r
+ FT_UShort point;\r
+ FT_F26Dot6 cur_dist,\r
+ distance;\r
+\r
+\r
+ point = (FT_UShort)args[0];\r
+\r
+ if ( BOUNDS( point, CUR.zp0.n_points ) )\r
+ {\r
+ if ( CUR.pedantic_hinting )\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+\r
+ /* XXX: Is there some undocumented feature while in the */\r
+ /* twilight zone? ? */\r
+ if ( ( CUR.opcode & 1 ) != 0 )\r
+ {\r
+ cur_dist = CUR_fast_project( &CUR.zp0.cur[point] );\r
+ distance = CUR_Func_round( cur_dist,\r
+ CUR.tt_metrics.compensations[0] ) - cur_dist;\r
+ }\r
+ else\r
+ distance = 0;\r
+\r
+ CUR_Func_move( &CUR.zp0, point, distance );\r
+\r
+ CUR.GS.rp0 = point;\r
+ CUR.GS.rp1 = point;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* MIAP[a]: Move Indirect Absolute Point */\r
+ /* Opcode range: 0x3E-0x3F */\r
+ /* Stack: uint32 uint32 --> */\r
+ /* */\r
+ static void\r
+ Ins_MIAP( INS_ARG )\r
+ {\r
+ FT_ULong cvtEntry;\r
+ FT_UShort point;\r
+ FT_F26Dot6 distance,\r
+ org_dist;\r
+\r
+\r
+ cvtEntry = (FT_ULong)args[1];\r
+ point = (FT_UShort)args[0];\r
+\r
+ if ( BOUNDS( point, CUR.zp0.n_points ) ||\r
+ BOUNDS( cvtEntry, CUR.cvtSize ) )\r
+ {\r
+ if ( CUR.pedantic_hinting )\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+\r
+ /* XXX: UNDOCUMENTED! */\r
+ /* */\r
+ /* The behaviour of an MIAP instruction is quite */\r
+ /* different when used in the twilight zone. */\r
+ /* */\r
+ /* First, no control value cut-in test is performed */\r
+ /* as it would fail anyway. Second, the original */\r
+ /* point, i.e. (org_x,org_y) of zp0.point, is set */\r
+ /* to the absolute, unrounded distance found in */\r
+ /* the CVT. */\r
+ /* */\r
+ /* This is used in the CVT programs of the Microsoft */\r
+ /* fonts Arial, Times, etc., in order to re-adjust */\r
+ /* some key font heights. It allows the use of the */\r
+ /* IP instruction in the twilight zone, which */\r
+ /* otherwise would be `illegal' according to the */\r
+ /* specification. */\r
+ /* */\r
+ /* We implement it with a special sequence for the */\r
+ /* twilight zone. This is a bad hack, but it seems */\r
+ /* to work. */\r
+\r
+ distance = CUR_Func_read_cvt( cvtEntry );\r
+\r
+ if ( CUR.GS.gep0 == 0 ) /* If in twilight zone */\r
+ {\r
+ CUR.zp0.org[point].x = TT_MulFix14( distance, CUR.GS.freeVector.x );\r
+ CUR.zp0.org[point].y = TT_MulFix14( distance, CUR.GS.freeVector.y ),\r
+ CUR.zp0.cur[point] = CUR.zp0.org[point];\r
+ }\r
+\r
+ org_dist = CUR_fast_project( &CUR.zp0.cur[point] );\r
+\r
+ if ( ( CUR.opcode & 1 ) != 0 ) /* rounding and control cutin flag */\r
+ {\r
+ if ( FT_ABS( distance - org_dist ) > CUR.GS.control_value_cutin )\r
+ distance = org_dist;\r
+\r
+ distance = CUR_Func_round( distance, CUR.tt_metrics.compensations[0] );\r
+ }\r
+\r
+ CUR_Func_move( &CUR.zp0, point, distance - org_dist );\r
+\r
+ CUR.GS.rp0 = point;\r
+ CUR.GS.rp1 = point;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* MDRP[abcde]: Move Direct Relative Point */\r
+ /* Opcode range: 0xC0-0xDF */\r
+ /* Stack: uint32 --> */\r
+ /* */\r
+ static void\r
+ Ins_MDRP( INS_ARG )\r
+ {\r
+ FT_UShort point;\r
+ FT_F26Dot6 org_dist, distance;\r
+\r
+\r
+ point = (FT_UShort)args[0];\r
+\r
+ if ( BOUNDS( point, CUR.zp1.n_points ) ||\r
+ BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )\r
+ {\r
+ if ( CUR.pedantic_hinting )\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+\r
+ /* XXX: Is there some undocumented feature while in the */\r
+ /* twilight zone? */\r
+\r
+ /* XXX: UNDOCUMENTED: twilight zone special case */\r
+\r
+ if ( CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 )\r
+ {\r
+ FT_Vector* vec1 = &CUR.zp1.org[point];\r
+ FT_Vector* vec2 = &CUR.zp0.org[CUR.GS.rp0];\r
+\r
+\r
+ org_dist = CUR_Func_dualproj( vec1, vec2 );\r
+ }\r
+ else\r
+ {\r
+ FT_Vector* vec1 = &CUR.zp1.orus[point];\r
+ FT_Vector* vec2 = &CUR.zp0.orus[CUR.GS.rp0];\r
+\r
+\r
+ if ( CUR.metrics.x_scale == CUR.metrics.y_scale )\r
+ {\r
+ /* this should be faster */\r
+ org_dist = CUR_Func_dualproj( vec1, vec2 );\r
+ org_dist = TT_MULFIX( org_dist, CUR.metrics.x_scale );\r
+ }\r
+ else\r
+ {\r
+ FT_Vector vec;\r
+\r
+\r
+ vec.x = TT_MULFIX( vec1->x - vec2->x, CUR.metrics.x_scale );\r
+ vec.y = TT_MULFIX( vec1->y - vec2->y, CUR.metrics.y_scale );\r
+\r
+ org_dist = CUR_fast_dualproj( &vec );\r
+ }\r
+ }\r
+\r
+ /* single width cut-in test */\r
+\r
+ if ( FT_ABS( org_dist - CUR.GS.single_width_value ) <\r
+ CUR.GS.single_width_cutin )\r
+ {\r
+ if ( org_dist >= 0 )\r
+ org_dist = CUR.GS.single_width_value;\r
+ else\r
+ org_dist = -CUR.GS.single_width_value;\r
+ }\r
+\r
+ /* round flag */\r
+\r
+ if ( ( CUR.opcode & 4 ) != 0 )\r
+ distance = CUR_Func_round(\r
+ org_dist,\r
+ CUR.tt_metrics.compensations[CUR.opcode & 3] );\r
+ else\r
+ distance = ROUND_None(\r
+ org_dist,\r
+ CUR.tt_metrics.compensations[CUR.opcode & 3] );\r
+\r
+ /* minimum distance flag */\r
+\r
+ if ( ( CUR.opcode & 8 ) != 0 )\r
+ {\r
+ if ( org_dist >= 0 )\r
+ {\r
+ if ( distance < CUR.GS.minimum_distance )\r
+ distance = CUR.GS.minimum_distance;\r
+ }\r
+ else\r
+ {\r
+ if ( distance > -CUR.GS.minimum_distance )\r
+ distance = -CUR.GS.minimum_distance;\r
+ }\r
+ }\r
+\r
+ /* now move the point */\r
+\r
+ org_dist = CUR_Func_project( CUR.zp1.cur + point,\r
+ CUR.zp0.cur + CUR.GS.rp0 );\r
+\r
+ CUR_Func_move( &CUR.zp1, point, distance - org_dist );\r
+\r
+ CUR.GS.rp1 = CUR.GS.rp0;\r
+ CUR.GS.rp2 = point;\r
+\r
+ if ( ( CUR.opcode & 16 ) != 0 )\r
+ CUR.GS.rp0 = point;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* MIRP[abcde]: Move Indirect Relative Point */\r
+ /* Opcode range: 0xE0-0xFF */\r
+ /* Stack: int32? uint32 --> */\r
+ /* */\r
+ static void\r
+ Ins_MIRP( INS_ARG )\r
+ {\r
+ FT_UShort point;\r
+ FT_ULong cvtEntry;\r
+\r
+ FT_F26Dot6 cvt_dist,\r
+ distance,\r
+ cur_dist,\r
+ org_dist;\r
+\r
+\r
+ point = (FT_UShort)args[0];\r
+ cvtEntry = (FT_ULong)( args[1] + 1 );\r
+\r
+ /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */\r
+\r
+ if ( BOUNDS( point, CUR.zp1.n_points ) ||\r
+ BOUNDS( cvtEntry, CUR.cvtSize + 1 ) ||\r
+ BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )\r
+ {\r
+ if ( CUR.pedantic_hinting )\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+\r
+ if ( !cvtEntry )\r
+ cvt_dist = 0;\r
+ else\r
+ cvt_dist = CUR_Func_read_cvt( cvtEntry - 1 );\r
+\r
+ /* single width test */\r
+\r
+ if ( FT_ABS( cvt_dist - CUR.GS.single_width_value ) <\r
+ CUR.GS.single_width_cutin )\r
+ {\r
+ if ( cvt_dist >= 0 )\r
+ cvt_dist = CUR.GS.single_width_value;\r
+ else\r
+ cvt_dist = -CUR.GS.single_width_value;\r
+ }\r
+\r
+ /* XXX: UNDOCUMENTED! -- twilight zone */\r
+\r
+ if ( CUR.GS.gep1 == 0 )\r
+ {\r
+ CUR.zp1.org[point].x = CUR.zp0.org[CUR.GS.rp0].x +\r
+ TT_MulFix14( cvt_dist, CUR.GS.freeVector.x );\r
+\r
+ CUR.zp1.org[point].y = CUR.zp0.org[CUR.GS.rp0].y +\r
+ TT_MulFix14( cvt_dist, CUR.GS.freeVector.y );\r
+\r
+ CUR.zp1.cur[point] = CUR.zp0.cur[point];\r
+ }\r
+\r
+ org_dist = CUR_Func_dualproj( &CUR.zp1.org[point],\r
+ &CUR.zp0.org[CUR.GS.rp0] );\r
+ cur_dist = CUR_Func_project ( &CUR.zp1.cur[point],\r
+ &CUR.zp0.cur[CUR.GS.rp0] );\r
+\r
+ /* auto-flip test */\r
+\r
+ if ( CUR.GS.auto_flip )\r
+ {\r
+ if ( ( org_dist ^ cvt_dist ) < 0 )\r
+ cvt_dist = -cvt_dist;\r
+ }\r
+\r
+ /* control value cutin and round */\r
+\r
+ if ( ( CUR.opcode & 4 ) != 0 )\r
+ {\r
+ /* XXX: UNDOCUMENTED! Only perform cut-in test when both points */\r
+ /* refer to the same zone. */\r
+\r
+ if ( CUR.GS.gep0 == CUR.GS.gep1 )\r
+ if ( FT_ABS( cvt_dist - org_dist ) >= CUR.GS.control_value_cutin )\r
+ cvt_dist = org_dist;\r
+\r
+ distance = CUR_Func_round(\r
+ cvt_dist,\r
+ CUR.tt_metrics.compensations[CUR.opcode & 3] );\r
+ }\r
+ else\r
+ distance = ROUND_None(\r
+ cvt_dist,\r
+ CUR.tt_metrics.compensations[CUR.opcode & 3] );\r
+\r
+ /* minimum distance test */\r
+\r
+ if ( ( CUR.opcode & 8 ) != 0 )\r
+ {\r
+ if ( org_dist >= 0 )\r
+ {\r
+ if ( distance < CUR.GS.minimum_distance )\r
+ distance = CUR.GS.minimum_distance;\r
+ }\r
+ else\r
+ {\r
+ if ( distance > -CUR.GS.minimum_distance )\r
+ distance = -CUR.GS.minimum_distance;\r
+ }\r
+ }\r
+\r
+ CUR_Func_move( &CUR.zp1, point, distance - cur_dist );\r
+\r
+ CUR.GS.rp1 = CUR.GS.rp0;\r
+\r
+ if ( ( CUR.opcode & 16 ) != 0 )\r
+ CUR.GS.rp0 = point;\r
+\r
+ /* XXX: UNDOCUMENTED! */\r
+ CUR.GS.rp2 = point;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* ALIGNRP[]: ALIGN Relative Point */\r
+ /* Opcode range: 0x3C */\r
+ /* Stack: uint32 uint32... --> */\r
+ /* */\r
+ static void\r
+ Ins_ALIGNRP( INS_ARG )\r
+ {\r
+ FT_UShort point;\r
+ FT_F26Dot6 distance;\r
+\r
+ FT_UNUSED_ARG;\r
+\r
+\r
+ if ( CUR.top < CUR.GS.loop ||\r
+ BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )\r
+ {\r
+ if ( CUR.pedantic_hinting )\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+\r
+ while ( CUR.GS.loop > 0 )\r
+ {\r
+ CUR.args--;\r
+\r
+ point = (FT_UShort)CUR.stack[CUR.args];\r
+\r
+ if ( BOUNDS( point, CUR.zp1.n_points ) )\r
+ {\r
+ if ( CUR.pedantic_hinting )\r
+ {\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ distance = CUR_Func_project( CUR.zp1.cur + point,\r
+ CUR.zp0.cur + CUR.GS.rp0 );\r
+\r
+ CUR_Func_move( &CUR.zp1, point, -distance );\r
+ }\r
+\r
+ CUR.GS.loop--;\r
+ }\r
+\r
+ CUR.GS.loop = 1;\r
+ CUR.new_top = CUR.args;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* ISECT[]: moves point to InterSECTion */\r
+ /* Opcode range: 0x0F */\r
+ /* Stack: 5 * uint32 --> */\r
+ /* */\r
+ static void\r
+ Ins_ISECT( INS_ARG )\r
+ {\r
+ FT_UShort point,\r
+ a0, a1,\r
+ b0, b1;\r
+\r
+ FT_F26Dot6 discriminant;\r
+\r
+ FT_F26Dot6 dx, dy,\r
+ dax, day,\r
+ dbx, dby;\r
+\r
+ FT_F26Dot6 val;\r
+\r
+ FT_Vector R;\r
+\r
+\r
+ point = (FT_UShort)args[0];\r
+\r
+ a0 = (FT_UShort)args[1];\r
+ a1 = (FT_UShort)args[2];\r
+ b0 = (FT_UShort)args[3];\r
+ b1 = (FT_UShort)args[4];\r
+\r
+ if ( BOUNDS( b0, CUR.zp0.n_points ) ||\r
+ BOUNDS( b1, CUR.zp0.n_points ) ||\r
+ BOUNDS( a0, CUR.zp1.n_points ) ||\r
+ BOUNDS( a1, CUR.zp1.n_points ) ||\r
+ BOUNDS( point, CUR.zp2.n_points ) )\r
+ {\r
+ if ( CUR.pedantic_hinting )\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+\r
+ dbx = CUR.zp0.cur[b1].x - CUR.zp0.cur[b0].x;\r
+ dby = CUR.zp0.cur[b1].y - CUR.zp0.cur[b0].y;\r
+\r
+ dax = CUR.zp1.cur[a1].x - CUR.zp1.cur[a0].x;\r
+ day = CUR.zp1.cur[a1].y - CUR.zp1.cur[a0].y;\r
+\r
+ dx = CUR.zp0.cur[b0].x - CUR.zp1.cur[a0].x;\r
+ dy = CUR.zp0.cur[b0].y - CUR.zp1.cur[a0].y;\r
+\r
+ CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_BOTH;\r
+\r
+ discriminant = TT_MULDIV( dax, -dby, 0x40 ) +\r
+ TT_MULDIV( day, dbx, 0x40 );\r
+\r
+ if ( FT_ABS( discriminant ) >= 0x40 )\r
+ {\r
+ val = TT_MULDIV( dx, -dby, 0x40 ) + TT_MULDIV( dy, dbx, 0x40 );\r
+\r
+ R.x = TT_MULDIV( val, dax, discriminant );\r
+ R.y = TT_MULDIV( val, day, discriminant );\r
+\r
+ CUR.zp2.cur[point].x = CUR.zp1.cur[a0].x + R.x;\r
+ CUR.zp2.cur[point].y = CUR.zp1.cur[a0].y + R.y;\r
+ }\r
+ else\r
+ {\r
+ /* else, take the middle of the middles of A and B */\r
+\r
+ CUR.zp2.cur[point].x = ( CUR.zp1.cur[a0].x +\r
+ CUR.zp1.cur[a1].x +\r
+ CUR.zp0.cur[b0].x +\r
+ CUR.zp0.cur[b1].x ) / 4;\r
+ CUR.zp2.cur[point].y = ( CUR.zp1.cur[a0].y +\r
+ CUR.zp1.cur[a1].y +\r
+ CUR.zp0.cur[b0].y +\r
+ CUR.zp0.cur[b1].y ) / 4;\r
+ }\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* ALIGNPTS[]: ALIGN PoinTS */\r
+ /* Opcode range: 0x27 */\r
+ /* Stack: uint32 uint32 --> */\r
+ /* */\r
+ static void\r
+ Ins_ALIGNPTS( INS_ARG )\r
+ {\r
+ FT_UShort p1, p2;\r
+ FT_F26Dot6 distance;\r
+\r
+\r
+ p1 = (FT_UShort)args[0];\r
+ p2 = (FT_UShort)args[1];\r
+\r
+ if ( BOUNDS( args[0], CUR.zp1.n_points ) ||\r
+ BOUNDS( args[1], CUR.zp0.n_points ) )\r
+ {\r
+ if ( CUR.pedantic_hinting )\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+\r
+ distance = CUR_Func_project( CUR.zp0.cur + p2,\r
+ CUR.zp1.cur + p1 ) / 2;\r
+\r
+ CUR_Func_move( &CUR.zp1, p1, distance );\r
+ CUR_Func_move( &CUR.zp0, p2, -distance );\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* IP[]: Interpolate Point */\r
+ /* Opcode range: 0x39 */\r
+ /* Stack: uint32... --> */\r
+ /* */\r
+\r
+ /* SOMETIMES, DUMBER CODE IS BETTER CODE */\r
+\r
+ static void\r
+ Ins_IP( INS_ARG )\r
+ {\r
+ FT_F26Dot6 old_range, cur_range;\r
+ FT_Vector* orus_base;\r
+ FT_Vector* cur_base;\r
+ FT_Int twilight;\r
+\r
+ FT_UNUSED_ARG;\r
+\r
+\r
+ if ( CUR.top < CUR.GS.loop )\r
+ {\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+\r
+ /*\r
+ * We need to deal in a special way with the twilight zone.\r
+ * Otherwise, by definition, the value of CUR.twilight.orus[n] is (0,0),\r
+ * for every n.\r
+ */\r
+ twilight = CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 || CUR.GS.gep2 == 0;\r
+\r
+ if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) )\r
+ {\r
+ if ( CUR.pedantic_hinting )\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+\r
+ if ( twilight )\r
+ orus_base = &CUR.zp0.org[CUR.GS.rp1];\r
+ else\r
+ orus_base = &CUR.zp0.orus[CUR.GS.rp1];\r
+\r
+ cur_base = &CUR.zp0.cur[CUR.GS.rp1];\r
+\r
+ /* XXX: There are some glyphs in some braindead but popular */\r
+ /* fonts out there (e.g. [aeu]grave in monotype.ttf) */\r
+ /* calling IP[] with bad values of rp[12]. */\r
+ /* Do something sane when this odd thing happens. */\r
+ if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) ||\r
+ BOUNDS( CUR.GS.rp2, CUR.zp1.n_points ) )\r
+ {\r
+ old_range = 0;\r
+ cur_range = 0;\r
+ }\r
+ else\r
+ {\r
+ if ( twilight )\r
+ old_range = CUR_Func_dualproj( &CUR.zp1.org[CUR.GS.rp2],\r
+ orus_base );\r
+ else\r
+ old_range = CUR_Func_dualproj( &CUR.zp1.orus[CUR.GS.rp2],\r
+ orus_base );\r
+\r
+ cur_range = CUR_Func_project ( &CUR.zp1.cur[CUR.GS.rp2], cur_base );\r
+ }\r
+\r
+ for ( ; CUR.GS.loop > 0; --CUR.GS.loop )\r
+ {\r
+ FT_UInt point = (FT_UInt)CUR.stack[--CUR.args];\r
+ FT_F26Dot6 org_dist, cur_dist, new_dist;\r
+\r
+\r
+ /* check point bounds */\r
+ if ( BOUNDS( point, CUR.zp2.n_points ) )\r
+ {\r
+ if ( CUR.pedantic_hinting )\r
+ {\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+ continue;\r
+ }\r
+\r
+ if ( twilight )\r
+ org_dist = CUR_Func_dualproj( &CUR.zp2.org[point], orus_base );\r
+ else\r
+ org_dist = CUR_Func_dualproj( &CUR.zp2.orus[point], orus_base );\r
+\r
+ cur_dist = CUR_Func_project ( &CUR.zp2.cur[point], cur_base );\r
+ new_dist = ( old_range != 0 )\r
+ ? TT_MULDIV( org_dist, cur_range, old_range )\r
+ : cur_dist;\r
+\r
+ CUR_Func_move( &CUR.zp2, (FT_UShort)point, new_dist - cur_dist );\r
+ }\r
+ CUR.GS.loop = 1;\r
+ CUR.new_top = CUR.args;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* UTP[a]: UnTouch Point */\r
+ /* Opcode range: 0x29 */\r
+ /* Stack: uint32 --> */\r
+ /* */\r
+ static void\r
+ Ins_UTP( INS_ARG )\r
+ {\r
+ FT_UShort point;\r
+ FT_Byte mask;\r
+\r
+\r
+ point = (FT_UShort)args[0];\r
+\r
+ if ( BOUNDS( point, CUR.zp0.n_points ) )\r
+ {\r
+ if ( CUR.pedantic_hinting )\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+\r
+ mask = 0xFF;\r
+\r
+ if ( CUR.GS.freeVector.x != 0 )\r
+ mask &= ~FT_CURVE_TAG_TOUCH_X;\r
+\r
+ if ( CUR.GS.freeVector.y != 0 )\r
+ mask &= ~FT_CURVE_TAG_TOUCH_Y;\r
+\r
+ CUR.zp0.tags[point] &= mask;\r
+ }\r
+\r
+\r
+ /* Local variables for Ins_IUP: */\r
+ typedef struct\r
+ {\r
+ FT_Vector* orgs; /* original and current coordinate */\r
+ FT_Vector* curs; /* arrays */\r
+ FT_Vector* orus;\r
+ FT_UInt max_points;\r
+\r
+ } IUP_WorkerRec, *IUP_Worker;\r
+\r
+\r
+ static void\r
+ _iup_worker_shift( IUP_Worker worker,\r
+ FT_UInt p1,\r
+ FT_UInt p2,\r
+ FT_UInt p )\r
+ {\r
+ FT_UInt i;\r
+ FT_F26Dot6 dx;\r
+\r
+\r
+ dx = worker->curs[p].x - worker->orgs[p].x;\r
+ if ( dx != 0 )\r
+ {\r
+ for ( i = p1; i < p; i++ )\r
+ worker->curs[i].x += dx;\r
+\r
+ for ( i = p + 1; i <= p2; i++ )\r
+ worker->curs[i].x += dx;\r
+ }\r
+ }\r
+\r
+\r
+ static void\r
+ _iup_worker_interpolate( IUP_Worker worker,\r
+ FT_UInt p1,\r
+ FT_UInt p2,\r
+ FT_UInt ref1,\r
+ FT_UInt ref2 )\r
+ {\r
+ FT_UInt i;\r
+ FT_F26Dot6 orus1, orus2, org1, org2, delta1, delta2;\r
+\r
+\r
+ if ( p1 > p2 )\r
+ return;\r
+\r
+ if ( BOUNDS( ref1, worker->max_points ) ||\r
+ BOUNDS( ref2, worker->max_points ) )\r
+ return;\r
+\r
+ orus1 = worker->orus[ref1].x;\r
+ orus2 = worker->orus[ref2].x;\r
+\r
+ if ( orus1 > orus2 )\r
+ {\r
+ FT_F26Dot6 tmp_o;\r
+ FT_UInt tmp_r;\r
+\r
+\r
+ tmp_o = orus1;\r
+ orus1 = orus2;\r
+ orus2 = tmp_o;\r
+\r
+ tmp_r = ref1;\r
+ ref1 = ref2;\r
+ ref2 = tmp_r;\r
+ }\r
+\r
+ org1 = worker->orgs[ref1].x;\r
+ org2 = worker->orgs[ref2].x;\r
+ delta1 = worker->curs[ref1].x - org1;\r
+ delta2 = worker->curs[ref2].x - org2;\r
+\r
+ if ( orus1 == orus2 )\r
+ {\r
+ /* simple shift of untouched points */\r
+ for ( i = p1; i <= p2; i++ )\r
+ {\r
+ FT_F26Dot6 x = worker->orgs[i].x;\r
+\r
+\r
+ if ( x <= org1 )\r
+ x += delta1;\r
+ else\r
+ x += delta2;\r
+\r
+ worker->curs[i].x = x;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ FT_Fixed scale = 0;\r
+ FT_Bool scale_valid = 0;\r
+\r
+\r
+ /* interpolation */\r
+ for ( i = p1; i <= p2; i++ )\r
+ {\r
+ FT_F26Dot6 x = worker->orgs[i].x;\r
+\r
+\r
+ if ( x <= org1 )\r
+ x += delta1;\r
+\r
+ else if ( x >= org2 )\r
+ x += delta2;\r
+\r
+ else\r
+ {\r
+ if ( !scale_valid )\r
+ {\r
+ scale_valid = 1;\r
+ scale = TT_MULDIV( org2 + delta2 - ( org1 + delta1 ),\r
+ 0x10000, orus2 - orus1 );\r
+ }\r
+\r
+ x = ( org1 + delta1 ) +\r
+ TT_MULFIX( worker->orus[i].x - orus1, scale );\r
+ }\r
+ worker->curs[i].x = x;\r
+ }\r
+ }\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* IUP[a]: Interpolate Untouched Points */\r
+ /* Opcode range: 0x30-0x31 */\r
+ /* Stack: --> */\r
+ /* */\r
+ static void\r
+ Ins_IUP( INS_ARG )\r
+ {\r
+ IUP_WorkerRec V;\r
+ FT_Byte mask;\r
+\r
+ FT_UInt first_point; /* first point of contour */\r
+ FT_UInt end_point; /* end point (last+1) of contour */\r
+\r
+ FT_UInt first_touched; /* first touched point in contour */\r
+ FT_UInt cur_touched; /* current touched point in contour */\r
+\r
+ FT_UInt point; /* current point */\r
+ FT_Short contour; /* current contour */\r
+\r
+ FT_UNUSED_ARG;\r
+\r
+\r
+ /* ignore empty outlines */\r
+ if ( CUR.pts.n_contours == 0 )\r
+ return;\r
+\r
+ if ( CUR.opcode & 1 )\r
+ {\r
+ mask = FT_CURVE_TAG_TOUCH_X;\r
+ V.orgs = CUR.pts.org;\r
+ V.curs = CUR.pts.cur;\r
+ V.orus = CUR.pts.orus;\r
+ }\r
+ else\r
+ {\r
+ mask = FT_CURVE_TAG_TOUCH_Y;\r
+ V.orgs = (FT_Vector*)( (FT_Pos*)CUR.pts.org + 1 );\r
+ V.curs = (FT_Vector*)( (FT_Pos*)CUR.pts.cur + 1 );\r
+ V.orus = (FT_Vector*)( (FT_Pos*)CUR.pts.orus + 1 );\r
+ }\r
+ V.max_points = CUR.pts.n_points;\r
+\r
+ contour = 0;\r
+ point = 0;\r
+\r
+ do\r
+ {\r
+ end_point = CUR.pts.contours[contour] - CUR.pts.first_point;\r
+ first_point = point;\r
+\r
+ while ( point <= end_point && ( CUR.pts.tags[point] & mask ) == 0 )\r
+ point++;\r
+\r
+ if ( point <= end_point )\r
+ {\r
+ first_touched = point;\r
+ cur_touched = point;\r
+\r
+ point++;\r
+\r
+ while ( point <= end_point )\r
+ {\r
+ if ( ( CUR.pts.tags[point] & mask ) != 0 )\r
+ {\r
+ if ( point > 0 )\r
+ _iup_worker_interpolate( &V,\r
+ cur_touched + 1,\r
+ point - 1,\r
+ cur_touched,\r
+ point );\r
+ cur_touched = point;\r
+ }\r
+\r
+ point++;\r
+ }\r
+\r
+ if ( cur_touched == first_touched )\r
+ _iup_worker_shift( &V, first_point, end_point, cur_touched );\r
+ else\r
+ {\r
+ _iup_worker_interpolate( &V,\r
+ (FT_UShort)( cur_touched + 1 ),\r
+ end_point,\r
+ cur_touched,\r
+ first_touched );\r
+\r
+ if ( first_touched > 0 )\r
+ _iup_worker_interpolate( &V,\r
+ first_point,\r
+ first_touched - 1,\r
+ cur_touched,\r
+ first_touched );\r
+ }\r
+ }\r
+ contour++;\r
+ } while ( contour < CUR.pts.n_contours );\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* DELTAPn[]: DELTA exceptions P1, P2, P3 */\r
+ /* Opcode range: 0x5D,0x71,0x72 */\r
+ /* Stack: uint32 (2 * uint32)... --> */\r
+ /* */\r
+ static void\r
+ Ins_DELTAP( INS_ARG )\r
+ {\r
+ FT_ULong k, nump;\r
+ FT_UShort A;\r
+ FT_ULong C;\r
+ FT_Long B;\r
+\r
+\r
+#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING\r
+ /* Delta hinting is covered by US Patent 5159668. */\r
+ if ( CUR.face->unpatented_hinting )\r
+ {\r
+ FT_Long n = args[0] * 2;\r
+\r
+\r
+ if ( CUR.args < n )\r
+ {\r
+ CUR.error = TT_Err_Too_Few_Arguments;\r
+ return;\r
+ }\r
+\r
+ CUR.args -= n;\r
+ CUR.new_top = CUR.args;\r
+ return;\r
+ }\r
+#endif\r
+\r
+ nump = (FT_ULong)args[0]; /* some points theoretically may occur more\r
+ than once, thus UShort isn't enough */\r
+\r
+ for ( k = 1; k <= nump; k++ )\r
+ {\r
+ if ( CUR.args < 2 )\r
+ {\r
+ CUR.error = TT_Err_Too_Few_Arguments;\r
+ return;\r
+ }\r
+\r
+ CUR.args -= 2;\r
+\r
+ A = (FT_UShort)CUR.stack[CUR.args + 1];\r
+ B = CUR.stack[CUR.args];\r
+\r
+ /* XXX: Because some popular fonts contain some invalid DeltaP */\r
+ /* instructions, we simply ignore them when the stacked */\r
+ /* point reference is off limit, rather than returning an */\r
+ /* error. As a delta instruction doesn't change a glyph */\r
+ /* in great ways, this shouldn't be a problem. */\r
+\r
+ if ( !BOUNDS( A, CUR.zp0.n_points ) )\r
+ {\r
+ C = ( (FT_ULong)B & 0xF0 ) >> 4;\r
+\r
+ switch ( CUR.opcode )\r
+ {\r
+ case 0x5D:\r
+ break;\r
+\r
+ case 0x71:\r
+ C += 16;\r
+ break;\r
+\r
+ case 0x72:\r
+ C += 32;\r
+ break;\r
+ }\r
+\r
+ C += CUR.GS.delta_base;\r
+\r
+ if ( CURRENT_Ppem() == (FT_Long)C )\r
+ {\r
+ B = ( (FT_ULong)B & 0xF ) - 8;\r
+ if ( B >= 0 )\r
+ B++;\r
+ B = B * 64 / ( 1L << CUR.GS.delta_shift );\r
+\r
+ CUR_Func_move( &CUR.zp0, A, B );\r
+ }\r
+ }\r
+ else\r
+ if ( CUR.pedantic_hinting )\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ }\r
+\r
+ CUR.new_top = CUR.args;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* DELTACn[]: DELTA exceptions C1, C2, C3 */\r
+ /* Opcode range: 0x73,0x74,0x75 */\r
+ /* Stack: uint32 (2 * uint32)... --> */\r
+ /* */\r
+ static void\r
+ Ins_DELTAC( INS_ARG )\r
+ {\r
+ FT_ULong nump, k;\r
+ FT_ULong A, C;\r
+ FT_Long B;\r
+\r
+\r
+#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING\r
+ /* Delta hinting is covered by US Patent 5159668. */\r
+ if ( CUR.face->unpatented_hinting )\r
+ {\r
+ FT_Long n = args[0] * 2;\r
+\r
+\r
+ if ( CUR.args < n )\r
+ {\r
+ CUR.error = TT_Err_Too_Few_Arguments;\r
+ return;\r
+ }\r
+\r
+ CUR.args -= n;\r
+ CUR.new_top = CUR.args;\r
+ return;\r
+ }\r
+#endif\r
+\r
+ nump = (FT_ULong)args[0];\r
+\r
+ for ( k = 1; k <= nump; k++ )\r
+ {\r
+ if ( CUR.args < 2 )\r
+ {\r
+ CUR.error = TT_Err_Too_Few_Arguments;\r
+ return;\r
+ }\r
+\r
+ CUR.args -= 2;\r
+\r
+ A = (FT_ULong)CUR.stack[CUR.args + 1];\r
+ B = CUR.stack[CUR.args];\r
+\r
+ if ( BOUNDS( A, CUR.cvtSize ) )\r
+ {\r
+ if ( CUR.pedantic_hinting )\r
+ {\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ return;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ C = ( (FT_ULong)B & 0xF0 ) >> 4;\r
+\r
+ switch ( CUR.opcode )\r
+ {\r
+ case 0x73:\r
+ break;\r
+\r
+ case 0x74:\r
+ C += 16;\r
+ break;\r
+\r
+ case 0x75:\r
+ C += 32;\r
+ break;\r
+ }\r
+\r
+ C += CUR.GS.delta_base;\r
+\r
+ if ( CURRENT_Ppem() == (FT_Long)C )\r
+ {\r
+ B = ( (FT_ULong)B & 0xF ) - 8;\r
+ if ( B >= 0 )\r
+ B++;\r
+ B = B * 64 / ( 1L << CUR.GS.delta_shift );\r
+\r
+ CUR_Func_move_cvt( A, B );\r
+ }\r
+ }\r
+ }\r
+\r
+ CUR.new_top = CUR.args;\r
+ }\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* MISC. INSTRUCTIONS */\r
+ /* */\r
+ /*************************************************************************/\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* GETINFO[]: GET INFOrmation */\r
+ /* Opcode range: 0x88 */\r
+ /* Stack: uint32 --> uint32 */\r
+ /* */\r
+ static void\r
+ Ins_GETINFO( INS_ARG )\r
+ {\r
+ FT_Long K;\r
+\r
+\r
+ K = 0;\r
+\r
+ /* We return MS rasterizer version 1.7 for the font scaler. */\r
+ if ( ( args[0] & 1 ) != 0 )\r
+ K = 35;\r
+\r
+ /* Has the glyph been rotated? */\r
+ if ( ( args[0] & 2 ) != 0 && CUR.tt_metrics.rotated )\r
+ K |= 0x80;\r
+\r
+ /* Has the glyph been stretched? */\r
+ if ( ( args[0] & 4 ) != 0 && CUR.tt_metrics.stretched )\r
+ K |= 1 << 8;\r
+\r
+ /* Are we hinting for grayscale? */\r
+ if ( ( args[0] & 32 ) != 0 && CUR.grayscale )\r
+ K |= 1 << 12;\r
+\r
+ args[0] = K;\r
+ }\r
+\r
+\r
+ static void\r
+ Ins_UNKNOWN( INS_ARG )\r
+ {\r
+ TT_DefRecord* def = CUR.IDefs;\r
+ TT_DefRecord* limit = def + CUR.numIDefs;\r
+\r
+ FT_UNUSED_ARG;\r
+\r
+\r
+ for ( ; def < limit; def++ )\r
+ {\r
+ if ( (FT_Byte)def->opc == CUR.opcode && def->active )\r
+ {\r
+ TT_CallRec* call;\r
+\r
+\r
+ if ( CUR.callTop >= CUR.callSize )\r
+ {\r
+ CUR.error = TT_Err_Stack_Overflow;\r
+ return;\r
+ }\r
+\r
+ call = CUR.callStack + CUR.callTop++;\r
+\r
+ call->Caller_Range = CUR.curRange;\r
+ call->Caller_IP = CUR.IP+1;\r
+ call->Cur_Count = 1;\r
+ call->Cur_Restart = def->start;\r
+\r
+ INS_Goto_CodeRange( def->range, def->start );\r
+\r
+ CUR.step_ins = FALSE;\r
+ return;\r
+ }\r
+ }\r
+\r
+ CUR.error = TT_Err_Invalid_Opcode;\r
+ }\r
+\r
+\r
+#ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH\r
+\r
+\r
+ static\r
+ TInstruction_Function Instruct_Dispatch[256] =\r
+ {\r
+ /* Opcodes are gathered in groups of 16. */\r
+ /* Please keep the spaces as they are. */\r
+\r
+ /* SVTCA y */ Ins_SVTCA,\r
+ /* SVTCA x */ Ins_SVTCA,\r
+ /* SPvTCA y */ Ins_SPVTCA,\r
+ /* SPvTCA x */ Ins_SPVTCA,\r
+ /* SFvTCA y */ Ins_SFVTCA,\r
+ /* SFvTCA x */ Ins_SFVTCA,\r
+ /* SPvTL // */ Ins_SPVTL,\r
+ /* SPvTL + */ Ins_SPVTL,\r
+ /* SFvTL // */ Ins_SFVTL,\r
+ /* SFvTL + */ Ins_SFVTL,\r
+ /* SPvFS */ Ins_SPVFS,\r
+ /* SFvFS */ Ins_SFVFS,\r
+ /* GPV */ Ins_GPV,\r
+ /* GFV */ Ins_GFV,\r
+ /* SFvTPv */ Ins_SFVTPV,\r
+ /* ISECT */ Ins_ISECT,\r
+\r
+ /* SRP0 */ Ins_SRP0,\r
+ /* SRP1 */ Ins_SRP1,\r
+ /* SRP2 */ Ins_SRP2,\r
+ /* SZP0 */ Ins_SZP0,\r
+ /* SZP1 */ Ins_SZP1,\r
+ /* SZP2 */ Ins_SZP2,\r
+ /* SZPS */ Ins_SZPS,\r
+ /* SLOOP */ Ins_SLOOP,\r
+ /* RTG */ Ins_RTG,\r
+ /* RTHG */ Ins_RTHG,\r
+ /* SMD */ Ins_SMD,\r
+ /* ELSE */ Ins_ELSE,\r
+ /* JMPR */ Ins_JMPR,\r
+ /* SCvTCi */ Ins_SCVTCI,\r
+ /* SSwCi */ Ins_SSWCI,\r
+ /* SSW */ Ins_SSW,\r
+\r
+ /* DUP */ Ins_DUP,\r
+ /* POP */ Ins_POP,\r
+ /* CLEAR */ Ins_CLEAR,\r
+ /* SWAP */ Ins_SWAP,\r
+ /* DEPTH */ Ins_DEPTH,\r
+ /* CINDEX */ Ins_CINDEX,\r
+ /* MINDEX */ Ins_MINDEX,\r
+ /* AlignPTS */ Ins_ALIGNPTS,\r
+ /* INS_0x28 */ Ins_UNKNOWN,\r
+ /* UTP */ Ins_UTP,\r
+ /* LOOPCALL */ Ins_LOOPCALL,\r
+ /* CALL */ Ins_CALL,\r
+ /* FDEF */ Ins_FDEF,\r
+ /* ENDF */ Ins_ENDF,\r
+ /* MDAP[0] */ Ins_MDAP,\r
+ /* MDAP[1] */ Ins_MDAP,\r
+\r
+ /* IUP[0] */ Ins_IUP,\r
+ /* IUP[1] */ Ins_IUP,\r
+ /* SHP[0] */ Ins_SHP,\r
+ /* SHP[1] */ Ins_SHP,\r
+ /* SHC[0] */ Ins_SHC,\r
+ /* SHC[1] */ Ins_SHC,\r
+ /* SHZ[0] */ Ins_SHZ,\r
+ /* SHZ[1] */ Ins_SHZ,\r
+ /* SHPIX */ Ins_SHPIX,\r
+ /* IP */ Ins_IP,\r
+ /* MSIRP[0] */ Ins_MSIRP,\r
+ /* MSIRP[1] */ Ins_MSIRP,\r
+ /* AlignRP */ Ins_ALIGNRP,\r
+ /* RTDG */ Ins_RTDG,\r
+ /* MIAP[0] */ Ins_MIAP,\r
+ /* MIAP[1] */ Ins_MIAP,\r
+\r
+ /* NPushB */ Ins_NPUSHB,\r
+ /* NPushW */ Ins_NPUSHW,\r
+ /* WS */ Ins_WS,\r
+ /* RS */ Ins_RS,\r
+ /* WCvtP */ Ins_WCVTP,\r
+ /* RCvt */ Ins_RCVT,\r
+ /* GC[0] */ Ins_GC,\r
+ /* GC[1] */ Ins_GC,\r
+ /* SCFS */ Ins_SCFS,\r
+ /* MD[0] */ Ins_MD,\r
+ /* MD[1] */ Ins_MD,\r
+ /* MPPEM */ Ins_MPPEM,\r
+ /* MPS */ Ins_MPS,\r
+ /* FlipON */ Ins_FLIPON,\r
+ /* FlipOFF */ Ins_FLIPOFF,\r
+ /* DEBUG */ Ins_DEBUG,\r
+\r
+ /* LT */ Ins_LT,\r
+ /* LTEQ */ Ins_LTEQ,\r
+ /* GT */ Ins_GT,\r
+ /* GTEQ */ Ins_GTEQ,\r
+ /* EQ */ Ins_EQ,\r
+ /* NEQ */ Ins_NEQ,\r
+ /* ODD */ Ins_ODD,\r
+ /* EVEN */ Ins_EVEN,\r
+ /* IF */ Ins_IF,\r
+ /* EIF */ Ins_EIF,\r
+ /* AND */ Ins_AND,\r
+ /* OR */ Ins_OR,\r
+ /* NOT */ Ins_NOT,\r
+ /* DeltaP1 */ Ins_DELTAP,\r
+ /* SDB */ Ins_SDB,\r
+ /* SDS */ Ins_SDS,\r
+\r
+ /* ADD */ Ins_ADD,\r
+ /* SUB */ Ins_SUB,\r
+ /* DIV */ Ins_DIV,\r
+ /* MUL */ Ins_MUL,\r
+ /* ABS */ Ins_ABS,\r
+ /* NEG */ Ins_NEG,\r
+ /* FLOOR */ Ins_FLOOR,\r
+ /* CEILING */ Ins_CEILING,\r
+ /* ROUND[0] */ Ins_ROUND,\r
+ /* ROUND[1] */ Ins_ROUND,\r
+ /* ROUND[2] */ Ins_ROUND,\r
+ /* ROUND[3] */ Ins_ROUND,\r
+ /* NROUND[0] */ Ins_NROUND,\r
+ /* NROUND[1] */ Ins_NROUND,\r
+ /* NROUND[2] */ Ins_NROUND,\r
+ /* NROUND[3] */ Ins_NROUND,\r
+\r
+ /* WCvtF */ Ins_WCVTF,\r
+ /* DeltaP2 */ Ins_DELTAP,\r
+ /* DeltaP3 */ Ins_DELTAP,\r
+ /* DeltaCn[0] */ Ins_DELTAC,\r
+ /* DeltaCn[1] */ Ins_DELTAC,\r
+ /* DeltaCn[2] */ Ins_DELTAC,\r
+ /* SROUND */ Ins_SROUND,\r
+ /* S45Round */ Ins_S45ROUND,\r
+ /* JROT */ Ins_JROT,\r
+ /* JROF */ Ins_JROF,\r
+ /* ROFF */ Ins_ROFF,\r
+ /* INS_0x7B */ Ins_UNKNOWN,\r
+ /* RUTG */ Ins_RUTG,\r
+ /* RDTG */ Ins_RDTG,\r
+ /* SANGW */ Ins_SANGW,\r
+ /* AA */ Ins_AA,\r
+\r
+ /* FlipPT */ Ins_FLIPPT,\r
+ /* FlipRgON */ Ins_FLIPRGON,\r
+ /* FlipRgOFF */ Ins_FLIPRGOFF,\r
+ /* INS_0x83 */ Ins_UNKNOWN,\r
+ /* INS_0x84 */ Ins_UNKNOWN,\r
+ /* ScanCTRL */ Ins_SCANCTRL,\r
+ /* SDPVTL[0] */ Ins_SDPVTL,\r
+ /* SDPVTL[1] */ Ins_SDPVTL,\r
+ /* GetINFO */ Ins_GETINFO,\r
+ /* IDEF */ Ins_IDEF,\r
+ /* ROLL */ Ins_ROLL,\r
+ /* MAX */ Ins_MAX,\r
+ /* MIN */ Ins_MIN,\r
+ /* ScanTYPE */ Ins_SCANTYPE,\r
+ /* InstCTRL */ Ins_INSTCTRL,\r
+ /* INS_0x8F */ Ins_UNKNOWN,\r
+\r
+ /* INS_0x90 */ Ins_UNKNOWN,\r
+ /* INS_0x91 */ Ins_UNKNOWN,\r
+ /* INS_0x92 */ Ins_UNKNOWN,\r
+ /* INS_0x93 */ Ins_UNKNOWN,\r
+ /* INS_0x94 */ Ins_UNKNOWN,\r
+ /* INS_0x95 */ Ins_UNKNOWN,\r
+ /* INS_0x96 */ Ins_UNKNOWN,\r
+ /* INS_0x97 */ Ins_UNKNOWN,\r
+ /* INS_0x98 */ Ins_UNKNOWN,\r
+ /* INS_0x99 */ Ins_UNKNOWN,\r
+ /* INS_0x9A */ Ins_UNKNOWN,\r
+ /* INS_0x9B */ Ins_UNKNOWN,\r
+ /* INS_0x9C */ Ins_UNKNOWN,\r
+ /* INS_0x9D */ Ins_UNKNOWN,\r
+ /* INS_0x9E */ Ins_UNKNOWN,\r
+ /* INS_0x9F */ Ins_UNKNOWN,\r
+\r
+ /* INS_0xA0 */ Ins_UNKNOWN,\r
+ /* INS_0xA1 */ Ins_UNKNOWN,\r
+ /* INS_0xA2 */ Ins_UNKNOWN,\r
+ /* INS_0xA3 */ Ins_UNKNOWN,\r
+ /* INS_0xA4 */ Ins_UNKNOWN,\r
+ /* INS_0xA5 */ Ins_UNKNOWN,\r
+ /* INS_0xA6 */ Ins_UNKNOWN,\r
+ /* INS_0xA7 */ Ins_UNKNOWN,\r
+ /* INS_0xA8 */ Ins_UNKNOWN,\r
+ /* INS_0xA9 */ Ins_UNKNOWN,\r
+ /* INS_0xAA */ Ins_UNKNOWN,\r
+ /* INS_0xAB */ Ins_UNKNOWN,\r
+ /* INS_0xAC */ Ins_UNKNOWN,\r
+ /* INS_0xAD */ Ins_UNKNOWN,\r
+ /* INS_0xAE */ Ins_UNKNOWN,\r
+ /* INS_0xAF */ Ins_UNKNOWN,\r
+\r
+ /* PushB[0] */ Ins_PUSHB,\r
+ /* PushB[1] */ Ins_PUSHB,\r
+ /* PushB[2] */ Ins_PUSHB,\r
+ /* PushB[3] */ Ins_PUSHB,\r
+ /* PushB[4] */ Ins_PUSHB,\r
+ /* PushB[5] */ Ins_PUSHB,\r
+ /* PushB[6] */ Ins_PUSHB,\r
+ /* PushB[7] */ Ins_PUSHB,\r
+ /* PushW[0] */ Ins_PUSHW,\r
+ /* PushW[1] */ Ins_PUSHW,\r
+ /* PushW[2] */ Ins_PUSHW,\r
+ /* PushW[3] */ Ins_PUSHW,\r
+ /* PushW[4] */ Ins_PUSHW,\r
+ /* PushW[5] */ Ins_PUSHW,\r
+ /* PushW[6] */ Ins_PUSHW,\r
+ /* PushW[7] */ Ins_PUSHW,\r
+\r
+ /* MDRP[00] */ Ins_MDRP,\r
+ /* MDRP[01] */ Ins_MDRP,\r
+ /* MDRP[02] */ Ins_MDRP,\r
+ /* MDRP[03] */ Ins_MDRP,\r
+ /* MDRP[04] */ Ins_MDRP,\r
+ /* MDRP[05] */ Ins_MDRP,\r
+ /* MDRP[06] */ Ins_MDRP,\r
+ /* MDRP[07] */ Ins_MDRP,\r
+ /* MDRP[08] */ Ins_MDRP,\r
+ /* MDRP[09] */ Ins_MDRP,\r
+ /* MDRP[10] */ Ins_MDRP,\r
+ /* MDRP[11] */ Ins_MDRP,\r
+ /* MDRP[12] */ Ins_MDRP,\r
+ /* MDRP[13] */ Ins_MDRP,\r
+ /* MDRP[14] */ Ins_MDRP,\r
+ /* MDRP[15] */ Ins_MDRP,\r
+\r
+ /* MDRP[16] */ Ins_MDRP,\r
+ /* MDRP[17] */ Ins_MDRP,\r
+ /* MDRP[18] */ Ins_MDRP,\r
+ /* MDRP[19] */ Ins_MDRP,\r
+ /* MDRP[20] */ Ins_MDRP,\r
+ /* MDRP[21] */ Ins_MDRP,\r
+ /* MDRP[22] */ Ins_MDRP,\r
+ /* MDRP[23] */ Ins_MDRP,\r
+ /* MDRP[24] */ Ins_MDRP,\r
+ /* MDRP[25] */ Ins_MDRP,\r
+ /* MDRP[26] */ Ins_MDRP,\r
+ /* MDRP[27] */ Ins_MDRP,\r
+ /* MDRP[28] */ Ins_MDRP,\r
+ /* MDRP[29] */ Ins_MDRP,\r
+ /* MDRP[30] */ Ins_MDRP,\r
+ /* MDRP[31] */ Ins_MDRP,\r
+\r
+ /* MIRP[00] */ Ins_MIRP,\r
+ /* MIRP[01] */ Ins_MIRP,\r
+ /* MIRP[02] */ Ins_MIRP,\r
+ /* MIRP[03] */ Ins_MIRP,\r
+ /* MIRP[04] */ Ins_MIRP,\r
+ /* MIRP[05] */ Ins_MIRP,\r
+ /* MIRP[06] */ Ins_MIRP,\r
+ /* MIRP[07] */ Ins_MIRP,\r
+ /* MIRP[08] */ Ins_MIRP,\r
+ /* MIRP[09] */ Ins_MIRP,\r
+ /* MIRP[10] */ Ins_MIRP,\r
+ /* MIRP[11] */ Ins_MIRP,\r
+ /* MIRP[12] */ Ins_MIRP,\r
+ /* MIRP[13] */ Ins_MIRP,\r
+ /* MIRP[14] */ Ins_MIRP,\r
+ /* MIRP[15] */ Ins_MIRP,\r
+\r
+ /* MIRP[16] */ Ins_MIRP,\r
+ /* MIRP[17] */ Ins_MIRP,\r
+ /* MIRP[18] */ Ins_MIRP,\r
+ /* MIRP[19] */ Ins_MIRP,\r
+ /* MIRP[20] */ Ins_MIRP,\r
+ /* MIRP[21] */ Ins_MIRP,\r
+ /* MIRP[22] */ Ins_MIRP,\r
+ /* MIRP[23] */ Ins_MIRP,\r
+ /* MIRP[24] */ Ins_MIRP,\r
+ /* MIRP[25] */ Ins_MIRP,\r
+ /* MIRP[26] */ Ins_MIRP,\r
+ /* MIRP[27] */ Ins_MIRP,\r
+ /* MIRP[28] */ Ins_MIRP,\r
+ /* MIRP[29] */ Ins_MIRP,\r
+ /* MIRP[30] */ Ins_MIRP,\r
+ /* MIRP[31] */ Ins_MIRP\r
+ };\r
+\r
+\r
+#endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */\r
+\r
+\r
+ /*************************************************************************/\r
+ /* */\r
+ /* RUN */\r
+ /* */\r
+ /* This function executes a run of opcodes. It will exit in the */\r
+ /* following cases: */\r
+ /* */\r
+ /* - Errors (in which case it returns FALSE). */\r
+ /* */\r
+ /* - Reaching the end of the main code range (returns TRUE). */\r
+ /* Reaching the end of a code range within a function call is an */\r
+ /* error. */\r
+ /* */\r
+ /* - After executing one single opcode, if the flag `Instruction_Trap' */\r
+ /* is set to TRUE (returns TRUE). */\r
+ /* */\r
+ /* On exit with TRUE, test IP < CodeSize to know whether it comes from */\r
+ /* an instruction trap or a normal termination. */\r
+ /* */\r
+ /* */\r
+ /* Note: The documented DEBUG opcode pops a value from the stack. This */\r
+ /* behaviour is unsupported; here a DEBUG opcode is always an */\r
+ /* error. */\r
+ /* */\r
+ /* */\r
+ /* THIS IS THE INTERPRETER'S MAIN LOOP. */\r
+ /* */\r
+ /* Instructions appear in the specification's order. */\r
+ /* */\r
+ /*************************************************************************/\r
+\r
+\r
+ /* documentation is in ttinterp.h */\r
+\r
+ FT_EXPORT_DEF( FT_Error )\r
+ TT_RunIns( TT_ExecContext exc )\r
+ {\r
+ FT_Long ins_counter = 0; /* executed instructions counter */\r
+\r
+\r
+#ifdef TT_CONFIG_OPTION_STATIC_RASTER\r
+ cur = *exc;\r
+#endif\r
+\r
+ /* set CVT functions */\r
+ CUR.tt_metrics.ratio = 0;\r
+ if ( CUR.metrics.x_ppem != CUR.metrics.y_ppem )\r
+ {\r
+ /* non-square pixels, use the stretched routines */\r
+ CUR.func_read_cvt = Read_CVT_Stretched;\r
+ CUR.func_write_cvt = Write_CVT_Stretched;\r
+ CUR.func_move_cvt = Move_CVT_Stretched;\r
+ }\r
+ else\r
+ {\r
+ /* square pixels, use normal routines */\r
+ CUR.func_read_cvt = Read_CVT;\r
+ CUR.func_write_cvt = Write_CVT;\r
+ CUR.func_move_cvt = Move_CVT;\r
+ }\r
+\r
+ COMPUTE_Funcs();\r
+ COMPUTE_Round( (FT_Byte)exc->GS.round_state );\r
+\r
+ do\r
+ {\r
+ CUR.opcode = CUR.code[CUR.IP];\r
+\r
+ if ( ( CUR.length = opcode_length[CUR.opcode] ) < 0 )\r
+ {\r
+ if ( CUR.IP + 1 > CUR.codeSize )\r
+ goto LErrorCodeOverflow_;\r
+\r
+ CUR.length = 2 - CUR.length * CUR.code[CUR.IP + 1];\r
+ }\r
+\r
+ if ( CUR.IP + CUR.length > CUR.codeSize )\r
+ goto LErrorCodeOverflow_;\r
+\r
+ /* First, let's check for empty stack and overflow */\r
+ CUR.args = CUR.top - ( Pop_Push_Count[CUR.opcode] >> 4 );\r
+\r
+ /* `args' is the top of the stack once arguments have been popped. */\r
+ /* One can also interpret it as the index of the last argument. */\r
+ if ( CUR.args < 0 )\r
+ {\r
+ CUR.error = TT_Err_Too_Few_Arguments;\r
+ goto LErrorLabel_;\r
+ }\r
+\r
+ CUR.new_top = CUR.args + ( Pop_Push_Count[CUR.opcode] & 15 );\r
+\r
+ /* `new_top' is the new top of the stack, after the instruction's */\r
+ /* execution. `top' will be set to `new_top' after the `switch' */\r
+ /* statement. */\r
+ if ( CUR.new_top > CUR.stackSize )\r
+ {\r
+ CUR.error = TT_Err_Stack_Overflow;\r
+ goto LErrorLabel_;\r
+ }\r
+\r
+ CUR.step_ins = TRUE;\r
+ CUR.error = TT_Err_Ok;\r
+\r
+#ifdef TT_CONFIG_OPTION_INTERPRETER_SWITCH\r
+\r
+ {\r
+ FT_Long* args = CUR.stack + CUR.args;\r
+ FT_Byte opcode = CUR.opcode;\r
+\r
+\r
+#undef ARRAY_BOUND_ERROR\r
+#define ARRAY_BOUND_ERROR goto Set_Invalid_Ref\r
+\r
+\r
+ switch ( opcode )\r
+ {\r
+ case 0x00: /* SVTCA y */\r
+ case 0x01: /* SVTCA x */\r
+ case 0x02: /* SPvTCA y */\r
+ case 0x03: /* SPvTCA x */\r
+ case 0x04: /* SFvTCA y */\r
+ case 0x05: /* SFvTCA x */\r
+ {\r
+ FT_Short AA, BB;\r
+\r
+\r
+ AA = (FT_Short)( ( opcode & 1 ) << 14 );\r
+ BB = (FT_Short)( AA ^ 0x4000 );\r
+\r
+ if ( opcode < 4 )\r
+ {\r
+ CUR.GS.projVector.x = AA;\r
+ CUR.GS.projVector.y = BB;\r
+\r
+ CUR.GS.dualVector.x = AA;\r
+ CUR.GS.dualVector.y = BB;\r
+ }\r
+ else\r
+ {\r
+ GUESS_VECTOR( projVector );\r
+ }\r
+\r
+ if ( ( opcode & 2 ) == 0 )\r
+ {\r
+ CUR.GS.freeVector.x = AA;\r
+ CUR.GS.freeVector.y = BB;\r
+ }\r
+ else\r
+ {\r
+ GUESS_VECTOR( freeVector );\r
+ }\r
+\r
+ COMPUTE_Funcs();\r
+ }\r
+ break;\r
+\r
+ case 0x06: /* SPvTL // */\r
+ case 0x07: /* SPvTL + */\r
+ DO_SPVTL\r
+ break;\r
+\r
+ case 0x08: /* SFvTL // */\r
+ case 0x09: /* SFvTL + */\r
+ DO_SFVTL\r
+ break;\r
+\r
+ case 0x0A: /* SPvFS */\r
+ DO_SPVFS\r
+ break;\r
+\r
+ case 0x0B: /* SFvFS */\r
+ DO_SFVFS\r
+ break;\r
+\r
+ case 0x0C: /* GPV */\r
+ DO_GPV\r
+ break;\r
+\r
+ case 0x0D: /* GFV */\r
+ DO_GFV\r
+ break;\r
+\r
+ case 0x0E: /* SFvTPv */\r
+ DO_SFVTPV\r
+ break;\r
+\r
+ case 0x0F: /* ISECT */\r
+ Ins_ISECT( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x10: /* SRP0 */\r
+ DO_SRP0\r
+ break;\r
+\r
+ case 0x11: /* SRP1 */\r
+ DO_SRP1\r
+ break;\r
+\r
+ case 0x12: /* SRP2 */\r
+ DO_SRP2\r
+ break;\r
+\r
+ case 0x13: /* SZP0 */\r
+ Ins_SZP0( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x14: /* SZP1 */\r
+ Ins_SZP1( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x15: /* SZP2 */\r
+ Ins_SZP2( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x16: /* SZPS */\r
+ Ins_SZPS( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x17: /* SLOOP */\r
+ DO_SLOOP\r
+ break;\r
+\r
+ case 0x18: /* RTG */\r
+ DO_RTG\r
+ break;\r
+\r
+ case 0x19: /* RTHG */\r
+ DO_RTHG\r
+ break;\r
+\r
+ case 0x1A: /* SMD */\r
+ DO_SMD\r
+ break;\r
+\r
+ case 0x1B: /* ELSE */\r
+ Ins_ELSE( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x1C: /* JMPR */\r
+ DO_JMPR\r
+ break;\r
+\r
+ case 0x1D: /* SCVTCI */\r
+ DO_SCVTCI\r
+ break;\r
+\r
+ case 0x1E: /* SSWCI */\r
+ DO_SSWCI\r
+ break;\r
+\r
+ case 0x1F: /* SSW */\r
+ DO_SSW\r
+ break;\r
+\r
+ case 0x20: /* DUP */\r
+ DO_DUP\r
+ break;\r
+\r
+ case 0x21: /* POP */\r
+ /* nothing :-) */\r
+ break;\r
+\r
+ case 0x22: /* CLEAR */\r
+ DO_CLEAR\r
+ break;\r
+\r
+ case 0x23: /* SWAP */\r
+ DO_SWAP\r
+ break;\r
+\r
+ case 0x24: /* DEPTH */\r
+ DO_DEPTH\r
+ break;\r
+\r
+ case 0x25: /* CINDEX */\r
+ DO_CINDEX\r
+ break;\r
+\r
+ case 0x26: /* MINDEX */\r
+ Ins_MINDEX( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x27: /* ALIGNPTS */\r
+ Ins_ALIGNPTS( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x28: /* ???? */\r
+ Ins_UNKNOWN( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x29: /* UTP */\r
+ Ins_UTP( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x2A: /* LOOPCALL */\r
+ Ins_LOOPCALL( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x2B: /* CALL */\r
+ Ins_CALL( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x2C: /* FDEF */\r
+ Ins_FDEF( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x2D: /* ENDF */\r
+ Ins_ENDF( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x2E: /* MDAP */\r
+ case 0x2F: /* MDAP */\r
+ Ins_MDAP( EXEC_ARG_ args );\r
+ break;\r
+\r
+\r
+ case 0x30: /* IUP */\r
+ case 0x31: /* IUP */\r
+ Ins_IUP( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x32: /* SHP */\r
+ case 0x33: /* SHP */\r
+ Ins_SHP( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x34: /* SHC */\r
+ case 0x35: /* SHC */\r
+ Ins_SHC( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x36: /* SHZ */\r
+ case 0x37: /* SHZ */\r
+ Ins_SHZ( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x38: /* SHPIX */\r
+ Ins_SHPIX( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x39: /* IP */\r
+ Ins_IP( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x3A: /* MSIRP */\r
+ case 0x3B: /* MSIRP */\r
+ Ins_MSIRP( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x3C: /* AlignRP */\r
+ Ins_ALIGNRP( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x3D: /* RTDG */\r
+ DO_RTDG\r
+ break;\r
+\r
+ case 0x3E: /* MIAP */\r
+ case 0x3F: /* MIAP */\r
+ Ins_MIAP( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x40: /* NPUSHB */\r
+ Ins_NPUSHB( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x41: /* NPUSHW */\r
+ Ins_NPUSHW( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x42: /* WS */\r
+ DO_WS\r
+ break;\r
+\r
+ Set_Invalid_Ref:\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ break;\r
+\r
+ case 0x43: /* RS */\r
+ DO_RS\r
+ break;\r
+\r
+ case 0x44: /* WCVTP */\r
+ DO_WCVTP\r
+ break;\r
+\r
+ case 0x45: /* RCVT */\r
+ DO_RCVT\r
+ break;\r
+\r
+ case 0x46: /* GC */\r
+ case 0x47: /* GC */\r
+ Ins_GC( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x48: /* SCFS */\r
+ Ins_SCFS( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x49: /* MD */\r
+ case 0x4A: /* MD */\r
+ Ins_MD( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x4B: /* MPPEM */\r
+ DO_MPPEM\r
+ break;\r
+\r
+ case 0x4C: /* MPS */\r
+ DO_MPS\r
+ break;\r
+\r
+ case 0x4D: /* FLIPON */\r
+ DO_FLIPON\r
+ break;\r
+\r
+ case 0x4E: /* FLIPOFF */\r
+ DO_FLIPOFF\r
+ break;\r
+\r
+ case 0x4F: /* DEBUG */\r
+ DO_DEBUG\r
+ break;\r
+\r
+ case 0x50: /* LT */\r
+ DO_LT\r
+ break;\r
+\r
+ case 0x51: /* LTEQ */\r
+ DO_LTEQ\r
+ break;\r
+\r
+ case 0x52: /* GT */\r
+ DO_GT\r
+ break;\r
+\r
+ case 0x53: /* GTEQ */\r
+ DO_GTEQ\r
+ break;\r
+\r
+ case 0x54: /* EQ */\r
+ DO_EQ\r
+ break;\r
+\r
+ case 0x55: /* NEQ */\r
+ DO_NEQ\r
+ break;\r
+\r
+ case 0x56: /* ODD */\r
+ DO_ODD\r
+ break;\r
+\r
+ case 0x57: /* EVEN */\r
+ DO_EVEN\r
+ break;\r
+\r
+ case 0x58: /* IF */\r
+ Ins_IF( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x59: /* EIF */\r
+ /* do nothing */\r
+ break;\r
+\r
+ case 0x5A: /* AND */\r
+ DO_AND\r
+ break;\r
+\r
+ case 0x5B: /* OR */\r
+ DO_OR\r
+ break;\r
+\r
+ case 0x5C: /* NOT */\r
+ DO_NOT\r
+ break;\r
+\r
+ case 0x5D: /* DELTAP1 */\r
+ Ins_DELTAP( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x5E: /* SDB */\r
+ DO_SDB\r
+ break;\r
+\r
+ case 0x5F: /* SDS */\r
+ DO_SDS\r
+ break;\r
+\r
+ case 0x60: /* ADD */\r
+ DO_ADD\r
+ break;\r
+\r
+ case 0x61: /* SUB */\r
+ DO_SUB\r
+ break;\r
+\r
+ case 0x62: /* DIV */\r
+ DO_DIV\r
+ break;\r
+\r
+ case 0x63: /* MUL */\r
+ DO_MUL\r
+ break;\r
+\r
+ case 0x64: /* ABS */\r
+ DO_ABS\r
+ break;\r
+\r
+ case 0x65: /* NEG */\r
+ DO_NEG\r
+ break;\r
+\r
+ case 0x66: /* FLOOR */\r
+ DO_FLOOR\r
+ break;\r
+\r
+ case 0x67: /* CEILING */\r
+ DO_CEILING\r
+ break;\r
+\r
+ case 0x68: /* ROUND */\r
+ case 0x69: /* ROUND */\r
+ case 0x6A: /* ROUND */\r
+ case 0x6B: /* ROUND */\r
+ DO_ROUND\r
+ break;\r
+\r
+ case 0x6C: /* NROUND */\r
+ case 0x6D: /* NROUND */\r
+ case 0x6E: /* NRRUND */\r
+ case 0x6F: /* NROUND */\r
+ DO_NROUND\r
+ break;\r
+\r
+ case 0x70: /* WCVTF */\r
+ DO_WCVTF\r
+ break;\r
+\r
+ case 0x71: /* DELTAP2 */\r
+ case 0x72: /* DELTAP3 */\r
+ Ins_DELTAP( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x73: /* DELTAC0 */\r
+ case 0x74: /* DELTAC1 */\r
+ case 0x75: /* DELTAC2 */\r
+ Ins_DELTAC( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x76: /* SROUND */\r
+ DO_SROUND\r
+ break;\r
+\r
+ case 0x77: /* S45Round */\r
+ DO_S45ROUND\r
+ break;\r
+\r
+ case 0x78: /* JROT */\r
+ DO_JROT\r
+ break;\r
+\r
+ case 0x79: /* JROF */\r
+ DO_JROF\r
+ break;\r
+\r
+ case 0x7A: /* ROFF */\r
+ DO_ROFF\r
+ break;\r
+\r
+ case 0x7B: /* ???? */\r
+ Ins_UNKNOWN( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x7C: /* RUTG */\r
+ DO_RUTG\r
+ break;\r
+\r
+ case 0x7D: /* RDTG */\r
+ DO_RDTG\r
+ break;\r
+\r
+ case 0x7E: /* SANGW */\r
+ case 0x7F: /* AA */\r
+ /* nothing - obsolete */\r
+ break;\r
+\r
+ case 0x80: /* FLIPPT */\r
+ Ins_FLIPPT( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x81: /* FLIPRGON */\r
+ Ins_FLIPRGON( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x82: /* FLIPRGOFF */\r
+ Ins_FLIPRGOFF( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x83: /* UNKNOWN */\r
+ case 0x84: /* UNKNOWN */\r
+ Ins_UNKNOWN( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x85: /* SCANCTRL */\r
+ Ins_SCANCTRL( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x86: /* SDPVTL */\r
+ case 0x87: /* SDPVTL */\r
+ Ins_SDPVTL( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x88: /* GETINFO */\r
+ Ins_GETINFO( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x89: /* IDEF */\r
+ Ins_IDEF( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x8A: /* ROLL */\r
+ Ins_ROLL( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x8B: /* MAX */\r
+ DO_MAX\r
+ break;\r
+\r
+ case 0x8C: /* MIN */\r
+ DO_MIN\r
+ break;\r
+\r
+ case 0x8D: /* SCANTYPE */\r
+ Ins_SCANTYPE( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x8E: /* INSTCTRL */\r
+ Ins_INSTCTRL( EXEC_ARG_ args );\r
+ break;\r
+\r
+ case 0x8F:\r
+ Ins_UNKNOWN( EXEC_ARG_ args );\r
+ break;\r
+\r
+ default:\r
+ if ( opcode >= 0xE0 )\r
+ Ins_MIRP( EXEC_ARG_ args );\r
+ else if ( opcode >= 0xC0 )\r
+ Ins_MDRP( EXEC_ARG_ args );\r
+ else if ( opcode >= 0xB8 )\r
+ Ins_PUSHW( EXEC_ARG_ args );\r
+ else if ( opcode >= 0xB0 )\r
+ Ins_PUSHB( EXEC_ARG_ args );\r
+ else\r
+ Ins_UNKNOWN( EXEC_ARG_ args );\r
+ }\r
+\r
+ }\r
+\r
+#else\r
+\r
+ Instruct_Dispatch[CUR.opcode]( EXEC_ARG_ &CUR.stack[CUR.args] );\r
+\r
+#endif /* TT_CONFIG_OPTION_INTERPRETER_SWITCH */\r
+\r
+ if ( CUR.error != TT_Err_Ok )\r
+ {\r
+ switch ( CUR.error )\r
+ {\r
+ case TT_Err_Invalid_Opcode: /* looking for redefined instructions */\r
+ {\r
+ TT_DefRecord* def = CUR.IDefs;\r
+ TT_DefRecord* limit = def + CUR.numIDefs;\r
+\r
+\r
+ for ( ; def < limit; def++ )\r
+ {\r
+ if ( def->active && CUR.opcode == (FT_Byte)def->opc )\r
+ {\r
+ TT_CallRec* callrec;\r
+\r
+\r
+ if ( CUR.callTop >= CUR.callSize )\r
+ {\r
+ CUR.error = TT_Err_Invalid_Reference;\r
+ goto LErrorLabel_;\r
+ }\r
+\r
+ callrec = &CUR.callStack[CUR.callTop];\r
+\r
+ callrec->Caller_Range = CUR.curRange;\r
+ callrec->Caller_IP = CUR.IP + 1;\r
+ callrec->Cur_Count = 1;\r
+ callrec->Cur_Restart = def->start;\r
+\r
+ if ( INS_Goto_CodeRange( def->range, def->start ) == FAILURE )\r
+ goto LErrorLabel_;\r
+\r
+ goto LSuiteLabel_;\r
+ }\r
+ }\r
+ }\r
+\r
+ CUR.error = TT_Err_Invalid_Opcode;\r
+ goto LErrorLabel_;\r
+\r
+#if 0\r
+ break; /* Unreachable code warning suppression. */\r
+ /* Leave to remind in case a later change the editor */\r
+ /* to consider break; */\r
+#endif\r
+\r
+ default:\r
+ goto LErrorLabel_;\r
+\r
+#if 0\r
+ break;\r
+#endif\r
+ }\r
+ }\r
+\r
+ CUR.top = CUR.new_top;\r
+\r
+ if ( CUR.step_ins )\r
+ CUR.IP += CUR.length;\r
+\r
+ /* increment instruction counter and check if we didn't */\r
+ /* run this program for too long (e.g. infinite loops). */\r
+ if ( ++ins_counter > MAX_RUNNABLE_OPCODES )\r
+ return TT_Err_Execution_Too_Long;\r
+\r
+ LSuiteLabel_:\r
+ if ( CUR.IP >= CUR.codeSize )\r
+ {\r
+ if ( CUR.callTop > 0 )\r
+ {\r
+ CUR.error = TT_Err_Code_Overflow;\r
+ goto LErrorLabel_;\r
+ }\r
+ else\r
+ goto LNo_Error_;\r
+ }\r
+ } while ( !CUR.instruction_trap );\r
+\r
+ LNo_Error_:\r
+\r
+#ifdef TT_CONFIG_OPTION_STATIC_RASTER\r
+ *exc = cur;\r
+#endif\r
+\r
+ return TT_Err_Ok;\r
+\r
+ LErrorCodeOverflow_:\r
+ CUR.error = TT_Err_Code_Overflow;\r
+\r
+ LErrorLabel_:\r
+\r
+#ifdef TT_CONFIG_OPTION_STATIC_RASTER\r
+ *exc = cur;\r
+#endif\r
+\r
+ return CUR.error;\r
+ }\r
+\r
+\r
+#endif /* TT_USE_BYTECODE_INTERPRETER */\r
+\r
+\r
+/* END */\r