Al-Qurtas-Islamic-bank-The-.../src/truetype/ttinterp.c

7917 lines
252 KiB
C
Raw Normal View History

1999-12-17 00:11:37 +01:00
/***************************************************************************/
/* */
/* ttinterp.c */
/* */
/* TrueType bytecode interpreter (body). */
1999-12-17 00:11:37 +01:00
/* */
2007-01-13 08:34:23 +01:00
/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007 by */
1999-12-17 00:11:37 +01:00
/* 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 */
1999-12-17 00:11:37 +01:00
/* 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. */
/* */
/***************************************************************************/
2000-12-08 17:17:16 +01:00
2006-08-19 13:18:09 +02:00
/* define FIX_BYTECODE to implement the bytecode interpreter fixes */
/* needed to match Windows behaviour more accurately */
#define FIX_BYTECODE
2006-08-19 13:18:09 +02:00
#include <ft2build.h>
#include FT_INTERNAL_DEBUG_H
#include FT_INTERNAL_CALC_H
#include FT_TRIGONOMETRY_H
#include FT_SYSTEM_H
Complete redesign of error codes. Please check ftmoderr.h for more details. * include/freetype/internal/cfferrs.h, include/freetype/internal/tterrors.h, include/freetype/internal/t1errors.h: Removed. Replaced with files local to the module. All extra error codes have been moved to `fterrors.h'. * src/sfnt/ttpost.h: Move error codes to `fterrors.h'. * src/autohint/aherrors.h, src/cache/ftcerror.h, src/cff/cfferrs.h, src/cid/ciderrs.h, src/pcf/pcferror.h, src/psaux/psauxerr.h, src/psnames/psnamerr.h, src/raster/rasterrs.h, src/sfnt/sferrors.h, src/smooth/ftsmerrs.h, src/truetype/tterrors.h, src/type1/t1errors.h, src/winfonts/fnterrs.h: New files defining the error names for the module it belongs to. * include/freetype/ftmoderr.h: New file, defining the module error offsets. Its structure is similar to `fterrors.h'. * include/freetype/fterrors.h (FT_NOERRORDEF): New macro. (FT_ERRORDEF): Redefined to use module error offsets. All internal error codes are now public; unused error codes have been removed, some are new. * include/freetype/config/ftheader.h (FT_MODULE_ERRORS_H): New macro. * include/freetype/config/ftoption.h (FT_CONFIG_OPTION_USE_MODULE_ERRORS): New macro. All other source files have been updated to use the new error codes; some already existing (internal) error codes local to a module have been renamed to give them the same name as in the base module. All make files have been updated to include the local error files. * src/cid/cidtokens.h: Replaced with... * src/cid/cidtoken.h: This file for 8+3 consistency. * src/raster/ftraster.c: Use macros for header file names.
2001-06-06 19:30:41 +02:00
#include "ttinterp.h"
Complete redesign of error codes. Please check ftmoderr.h for more details. * include/freetype/internal/cfferrs.h, include/freetype/internal/tterrors.h, include/freetype/internal/t1errors.h: Removed. Replaced with files local to the module. All extra error codes have been moved to `fterrors.h'. * src/sfnt/ttpost.h: Move error codes to `fterrors.h'. * src/autohint/aherrors.h, src/cache/ftcerror.h, src/cff/cfferrs.h, src/cid/ciderrs.h, src/pcf/pcferror.h, src/psaux/psauxerr.h, src/psnames/psnamerr.h, src/raster/rasterrs.h, src/sfnt/sferrors.h, src/smooth/ftsmerrs.h, src/truetype/tterrors.h, src/type1/t1errors.h, src/winfonts/fnterrs.h: New files defining the error names for the module it belongs to. * include/freetype/ftmoderr.h: New file, defining the module error offsets. Its structure is similar to `fterrors.h'. * include/freetype/fterrors.h (FT_NOERRORDEF): New macro. (FT_ERRORDEF): Redefined to use module error offsets. All internal error codes are now public; unused error codes have been removed, some are new. * include/freetype/config/ftheader.h (FT_MODULE_ERRORS_H): New macro. * include/freetype/config/ftoption.h (FT_CONFIG_OPTION_USE_MODULE_ERRORS): New macro. All other source files have been updated to use the new error codes; some already existing (internal) error codes local to a module have been renamed to give them the same name as in the base module. All make files have been updated to include the local error files. * src/cid/cidtokens.h: Replaced with... * src/cid/cidtoken.h: This file for 8+3 consistency. * src/raster/ftraster.c: Use macros for header file names.
2001-06-06 19:30:41 +02:00
#include "tterrors.h"
1999-12-17 00:11:37 +01:00
#ifdef TT_USE_BYTECODE_INTERPRETER
#define TT_MULFIX FT_MulFix
#define TT_MULDIV FT_MulDiv
#define TT_MULDIV_NO_ROUND FT_MulDiv_No_Round
1999-12-17 00:11:37 +01:00
/*************************************************************************/
/* */
/* 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. */
/* */
1999-12-17 00:11:37 +01:00
#undef FT_COMPONENT
#define FT_COMPONENT trace_ttinterp
1999-12-17 00:11:37 +01:00
/*************************************************************************/
/* */
/* 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 */
2007-01-26 23:18:56 +01:00
/* limited to a maximal number of opcodes defined below. */
1999-12-17 00:11:37 +01:00
/* */
#define MAX_RUNNABLE_OPCODES 1000000L
1999-12-17 00:11:37 +01:00
/*************************************************************************/
/* */
/* There are two kinds of implementations: */
/* */
/* a. static implementation */
1999-12-17 00:11:37 +01:00
/* */
/* 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 */
1999-12-17 00:11:37 +01:00
/* */
/* 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 */
1999-12-17 00:11:37 +01:00
#define CUR (*exc) /* see ttobjs.h */
1999-12-17 00:11:37 +01:00
2005-11-16 19:09:27 +01:00
/*************************************************************************/
/* */
/* 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 */
1999-12-17 00:11:37 +01:00
#define CUR cur
1999-12-17 00:11:37 +01:00
2005-11-16 19:09:27 +01:00
#define FT_UNUSED_EXEC int __dummy = __dummy
1999-12-17 00:11:37 +01:00
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. */
1999-12-17 00:11:37 +01:00
/* */
#define INS_ARG EXEC_OP_ FT_Long* args /* see ttobjs.h for EXEC_OP_ */
1999-12-17 00:11:37 +01:00
/*************************************************************************/
/* */
/* 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 )
1999-12-17 00:11:37 +01:00
/*************************************************************************/
/* */
/* The following macros hide the use of EXEC_ARG and EXEC_ARG_ to */
2007-01-26 23:18:56 +01:00
/* increase readability of the code. */
1999-12-17 00:11:37 +01:00
/* */
/*************************************************************************/
#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 )
1999-12-17 00:11:37 +01:00
#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 )
2007-02-12 23:01:18 +01:00
#define CUR_Func_project( v1, v2 ) \
CUR.func_project( EXEC_ARG_ (v1)->x - (v2)->x, (v1)->y - (v2)->y )
2007-02-12 23:01:18 +01:00
#define CUR_Func_dualproj( v1, v2 ) \
CUR.func_dualproj( EXEC_ARG_ (v1)->x - (v2)->x, (v1)->y - (v2)->y )
2007-02-12 23:01:18 +01:00
#define CUR_fast_project( v ) \
CUR.func_project( EXEC_ARG_ (v)->x, (v)->y )
2007-02-12 23:01:18 +01:00
#define CUR_fast_dualproj( v ) \
CUR.func_dualproj( EXEC_ARG_ (v)->x, (v)->y )
1999-12-17 00:11:37 +01:00
/*************************************************************************/
/* */
/* 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) )
1999-12-17 00:11:37 +01:00
#undef SUCCESS
#define SUCCESS 0
1999-12-17 00:11:37 +01:00
#undef FAILURE
#define FAILURE 1
1999-12-17 00:11:37 +01:00
#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2003-04-29 15:23:47 +02:00
#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
1999-12-17 00:11:37 +01:00
/*************************************************************************/
/* */
/* 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. */
1999-12-17 00:11:37 +01:00
/* */
/* <InOut> */
/* exec :: The target execution context. */
/* */
/* <Return> */
2000-06-25 08:47:11 +02:00
/* FreeType error code. 0 means success. */
1999-12-17 00:11:37 +01:00
/* */
FT_LOCAL_DEF( FT_Error )
2001-06-28 09:17:51 +02:00
TT_Goto_CodeRange( TT_ExecContext exec,
FT_Int range,
FT_Long IP )
1999-12-17 00:11:37 +01:00
{
TT_CodeRange* coderange;
FT_ASSERT( range >= 1 && range <= 3 );
1999-12-17 00:11:37 +01:00
coderange = &exec->codeRangeTable[range - 1];
FT_ASSERT( coderange->base != NULL );
1999-12-17 00:11:37 +01:00
/* 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. */
1999-12-17 00:11:37 +01:00
/* */
FT_ASSERT( (FT_ULong)IP <= coderange->size );
1999-12-17 00:11:37 +01:00
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. */
/* */
1999-12-17 00:11:37 +01:00
/* base :: The new code base. */
/* */
1999-12-17 00:11:37 +01:00
/* length :: The range size in bytes. */
/* */
/* <InOut> */
/* exec :: The target execution context. */
/* */
/* <Return> */
2000-06-25 08:47:11 +02:00
/* FreeType error code. 0 means success. */
1999-12-17 00:11:37 +01:00
/* */
FT_LOCAL_DEF( FT_Error )
2001-06-28 09:17:51 +02:00
TT_Set_CodeRange( TT_ExecContext exec,
FT_Int range,
void* base,
FT_Long length )
1999-12-17 00:11:37 +01:00
{
FT_ASSERT( range >= 1 && range <= 3 );
1999-12-17 00:11:37 +01:00
exec->codeRangeTable[range - 1].base = (FT_Byte*)base;
1999-12-17 00:11:37 +01:00
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> */
2000-06-25 08:47:11 +02:00
/* FreeType error code. 0 means success. */
1999-12-17 00:11:37 +01:00
/* */
/* <Note> */
/* Does not set the Error variable. */
/* */
FT_LOCAL_DEF( FT_Error )
2001-06-28 09:17:51 +02:00
TT_Clear_CodeRange( TT_ExecContext exec,
FT_Int range )
1999-12-17 00:11:37 +01:00
{
FT_ASSERT( range >= 1 && range <= 3 );
1999-12-17 00:11:37 +01:00
exec->codeRangeTable[range - 1].base = NULL;
exec->codeRangeTable[range - 1].size = 0;
return TT_Err_Ok;
}
/*************************************************************************/
/* */
/* EXECUTION CONTEXT ROUTINES */
/* */
/*************************************************************************/
/*************************************************************************/
/* */
/* <Function> */
/* TT_Done_Context */
1999-12-17 00:11:37 +01:00
/* */
/* <Description> */
/* Destroys a given context. */
/* */
/* <Input> */
/* exec :: A handle to the target execution context. */
/* */
/* memory :: A handle to the parent memory object. */
1999-12-17 00:11:37 +01:00
/* */
/* <Return> */
2000-06-25 08:47:11 +02:00
/* FreeType error code. 0 means success. */
1999-12-17 00:11:37 +01:00
/* */
/* <Note> */
/* Only the glyph loader and debugger should call this function. */
/* */
FT_LOCAL_DEF( FT_Error )
TT_Done_Context( TT_ExecContext exec )
1999-12-17 00:11:37 +01:00
{
FT_Memory memory = exec->memory;
1999-12-17 00:11:37 +01:00
/* points zone */
exec->maxPoints = 0;
exec->maxContours = 0;
/* free stack */
FT_FREE( exec->stack );
1999-12-17 00:11:37 +01:00
exec->stackSize = 0;
/* free call stack */
FT_FREE( exec->callStack );
1999-12-17 00:11:37 +01:00
exec->callSize = 0;
exec->callTop = 0;
/* free glyph code range */
FT_FREE( exec->glyphIns );
1999-12-17 00:11:37 +01:00
exec->glyphSize = 0;
exec->size = NULL;
exec->face = NULL;
FT_FREE( exec );
1999-12-17 00:11:37 +01:00
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> */
2000-06-25 08:47:11 +02:00
/* FreeType error code. 0 means success. */
1999-12-17 00:11:37 +01:00
/* */
2001-06-28 09:17:51 +02:00
static FT_Error
Init_Context( TT_ExecContext exec,
FT_Memory memory )
1999-12-17 00:11:37 +01:00
{
FT_Error error;
1999-12-17 00:11:37 +01:00
FT_TRACE1(( "Init_Context: new object at 0x%08p\n", exec ));
1999-12-17 00:11:37 +01:00
exec->memory = memory;
exec->callSize = 32;
if ( FT_NEW_ARRAY( exec->callStack, exec->callSize ) )
1999-12-17 00:11:37 +01:00
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;
1999-12-17 00:11:37 +01:00
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 );
1999-12-17 00:11:37 +01:00
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. */
/* */
1999-12-17 00:11:37 +01:00
/* 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> */
2000-06-25 08:47:11 +02:00
/* FreeType error code. 0 means success. */
1999-12-17 00:11:37 +01:00
/* */
2001-06-28 09:17:51 +02:00
static FT_Error
Update_Max( FT_Memory memory,
FT_ULong* size,
FT_Long multiplier,
void* _pbuff,
2001-06-28 09:17:51 +02:00
FT_ULong new_max )
1999-12-17 00:11:37 +01:00
{
FT_Error error;
void** pbuff = (void**)_pbuff;
1999-12-17 00:11:37 +01:00
if ( *size < new_max )
{
if ( FT_REALLOC( *pbuff, *size * multiplier, new_max * multiplier ) )
1999-12-17 00:11:37 +01:00
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. */
/* */
1999-12-17 00:11:37 +01:00
/* size :: A handle to the source size object. */
/* */
/* <InOut> */
/* exec :: A handle to the target execution context. */
/* */
/* <Return> */
2000-06-25 08:47:11 +02:00
/* FreeType error code. 0 means success. */
1999-12-17 00:11:37 +01:00
/* */
/* <Note> */
/* Only the glyph loader and debugger should call this function. */
/* */
FT_LOCAL_DEF( FT_Error )
2001-06-28 09:17:51 +02:00
TT_Load_Context( TT_ExecContext exec,
TT_Face face,
TT_Size size )
1999-12-17 00:11:37 +01:00
{
FT_Int i;
FT_ULong tmp;
1999-12-17 00:11:37 +01:00
TT_MaxProfile* maxp;
FT_Error error;
1999-12-17 00:11:37 +01:00
1999-12-17 00:11:37 +01:00
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;
1999-12-17 00:11:37 +01:00
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,
1999-12-17 00:11:37 +01:00
maxp->maxStackElements + 32 );
exec->stackSize = (FT_UInt)tmp;
1999-12-17 00:11:37 +01:00
if ( error )
return error;
tmp = exec->glyphSize;
error = Update_Max( exec->memory,
&tmp,
sizeof ( FT_Byte ),
(void*)&exec->glyphIns,
1999-12-17 00:11:37 +01:00
maxp->maxSizeOfInstructions );
exec->glyphSize = (FT_UShort)tmp;
1999-12-17 00:11:37 +01:00
if ( error )
return error;
exec->pts.n_points = 0;
exec->pts.n_contours = 0;
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. */
1999-12-17 00:11:37 +01:00
/* */
/* <Return> */
2000-06-25 08:47:11 +02:00
/* FreeType error code. 0 means success. */
1999-12-17 00:11:37 +01:00
/* */
/* <Note> */
/* Only the glyph loader and debugger should call this function. */
/* */
FT_LOCAL_DEF( FT_Error )
2001-06-28 09:17:51 +02:00
TT_Save_Context( TT_ExecContext exec,
TT_Size size )
1999-12-17 00:11:37 +01:00
{
FT_Int i;
1999-12-17 00:11:37 +01:00
1999-12-17 00:11:37 +01:00
/* 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. */
/* */
1999-12-17 00:11:37 +01:00
/* <Input> */
/* exec :: A handle to the target execution context. */
/* */
/* <Return> */
- MAJOR INTERNAL REDESIGN: A lot of internal modifications have been performed lately on the source in order to provide the following enhancements: - more generic module support: The FT_Module type is now defined to represent a handle to a given module. The file <freetype/ftmodule.h> contains the FT_Module_Class definition, as well as the module-loading public API The FT_Driver type is still defined, and still represents a pointer to a font driver. Note that FT_Add_Driver is replaced by FT_Add_Module, FT_Get_Driver by FT_Get_Module, etc.. - support for generic glyph image types: The FT_Renderer type is a pointer to a module used to perform various operations on glyph image. Each renderer is capable of handling images in a single format (e.g. ft_glyph_format_outline). Its functions are used to: - transform an glyph image - render a glyph image into a bitmap - return the control box (dimensions) of a given glyph image The scan converters "ftraster.c" and "ftgrays.c" have been moved to the new directory "src/renderer", and are used to provide two default renderer modules. One corresponds to the "standard" scan-converter, the other to the "smooth" one. The current renderer can be set through the new function FT_Set_Renderer. The old raster-related function FT_Set_Raster, FT_Get_Raster and FT_Set_Raster_Mode have now disappeared, in favor of the new: FT_Get_Renderer FT_Set_Renderer see the file <freetype/ftrender.h> for more details.. These changes were necessary to properly support different scalable formats in the future, like bi-color glyphs, etc.. - glyph loader object: A new internal object, called a 'glyph loader' has been introduced in the base layer. It is used by all scalable format font drivers to load glyphs and composites. This object has been created to reduce the code size of each driver, as each one of them basically re-implemented its functionality. See <freetype/internal/ftobjs.h> and the FT_GlyphLoader type for more information.. - FT_GlyphSlot had new fields: In order to support extended features (see below), the FT_GlyphSlot structure has a few new fields: linearHoriAdvance: this field gives the linearly scaled (i.e. scaled but unhinted) advance width for the glyph, expressed as a 16.16 fixed pixel value. This is useful to perform WYSIWYG text. linearVertAdvance: this field gives the linearly scaled advance height for the glyph (relevant in vertical glyph layouts only). This is useful to perform WYSIWYG text. Note that the two above field replace the removed "metrics2" field in the glyph slot. advance: this field is a vector that gives the transformed advance for the glyph. By default, it corresponds to the advance width, unless FT_LOAD_VERTICAL_LAYOUT was specified when calling FT_Load_Glyph or FT_Load_Char bitmap_left: this field gives the distance in integer pixels from the current pen position to the left-most pixel of a glyph image WHEN IT IS A BITMAP. It is only valid when the "format" field is set to "ft_glyph_format_bitmap", for example, after calling the new function FT_Render_Glyph. bitmap_top: this field gives the distance in integer pixels from the current pen position (located on the baseline) to the top-most pixel of the glyph image WHEN IT IS A BITMAP. Positive values correspond to upwards Y. loader: this is a new private field for the glyph slot. Client applications should not touch it.. - support for transforms and direct rendering in FT_Load_Glyph: Most of the functionality found in <freetype/ftglyph.h> has been moved to the core library. Hence, the following: - a transform can be specified for a face through FT_Set_Transform. this transform is applied by FT_Load_Glyph to scalable glyph images (i.e. NOT TO BITMAPS) before the function returns, unless the bit flag FT_LOAD_IGNORE_TRANSFORM was set in the load flags.. - once a glyph image has been loaded, it can be directly converted to a bitmap by using the new FT_Render_Glyph function. Note that this function takes the glyph image from the glyph slot, and converts it to a bitmap whose properties are returned in "face.glyph.bitmap", "face.glyph.bitmap_left" and "face.glyph.bitmap_top". The original native image might be lost after the conversion. - when using the new bit flag FT_LOAD_RENDER, the FT_Load_Glyph and FT_Load_Char functions will call FT_Render_Glyph automatically when needed.
2000-06-22 02:17:42 +02:00
/* TrueTyoe error code. 0 means success. */
1999-12-17 00:11:37 +01:00
/* */
/* <Note> */
/* Only the glyph loader and debugger should call this function. */
/* */
FT_LOCAL_DEF( FT_Error )
2001-06-28 09:17:51 +02:00
TT_Run_Context( TT_ExecContext exec,
FT_Bool debug )
1999-12-17 00:11:37 +01:00
{
FT_Error error;
1999-12-17 00:11:37 +01:00
if ( ( error = TT_Goto_CodeRange( exec, tt_coderange_glyph, 0 ) )
1999-12-17 00:11:37 +01:00
!= 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
1999-12-17 00:11:37 +01:00
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 );
1999-12-17 00:11:37 +01:00
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
2003-04-29 15:23:47 +02:00
TRUE,
#endif
1999-12-17 00:11:37 +01:00
1, 64, 1,
TRUE, 68, 0, 0, 9, 3,
0, FALSE, 2, 1, 1, 1
};
/* documentation is in ttinterp.h */
2001-06-28 09:17:51 +02:00
FT_EXPORT_DEF( TT_ExecContext )
TT_New_Context( TT_Driver driver )
1999-12-17 00:11:37 +01:00
{
TT_ExecContext exec;
FT_Memory memory;
- MAJOR INTERNAL REDESIGN: A lot of internal modifications have been performed lately on the source in order to provide the following enhancements: - more generic module support: The FT_Module type is now defined to represent a handle to a given module. The file <freetype/ftmodule.h> contains the FT_Module_Class definition, as well as the module-loading public API The FT_Driver type is still defined, and still represents a pointer to a font driver. Note that FT_Add_Driver is replaced by FT_Add_Module, FT_Get_Driver by FT_Get_Module, etc.. - support for generic glyph image types: The FT_Renderer type is a pointer to a module used to perform various operations on glyph image. Each renderer is capable of handling images in a single format (e.g. ft_glyph_format_outline). Its functions are used to: - transform an glyph image - render a glyph image into a bitmap - return the control box (dimensions) of a given glyph image The scan converters "ftraster.c" and "ftgrays.c" have been moved to the new directory "src/renderer", and are used to provide two default renderer modules. One corresponds to the "standard" scan-converter, the other to the "smooth" one. The current renderer can be set through the new function FT_Set_Renderer. The old raster-related function FT_Set_Raster, FT_Get_Raster and FT_Set_Raster_Mode have now disappeared, in favor of the new: FT_Get_Renderer FT_Set_Renderer see the file <freetype/ftrender.h> for more details.. These changes were necessary to properly support different scalable formats in the future, like bi-color glyphs, etc.. - glyph loader object: A new internal object, called a 'glyph loader' has been introduced in the base layer. It is used by all scalable format font drivers to load glyphs and composites. This object has been created to reduce the code size of each driver, as each one of them basically re-implemented its functionality. See <freetype/internal/ftobjs.h> and the FT_GlyphLoader type for more information.. - FT_GlyphSlot had new fields: In order to support extended features (see below), the FT_GlyphSlot structure has a few new fields: linearHoriAdvance: this field gives the linearly scaled (i.e. scaled but unhinted) advance width for the glyph, expressed as a 16.16 fixed pixel value. This is useful to perform WYSIWYG text. linearVertAdvance: this field gives the linearly scaled advance height for the glyph (relevant in vertical glyph layouts only). This is useful to perform WYSIWYG text. Note that the two above field replace the removed "metrics2" field in the glyph slot. advance: this field is a vector that gives the transformed advance for the glyph. By default, it corresponds to the advance width, unless FT_LOAD_VERTICAL_LAYOUT was specified when calling FT_Load_Glyph or FT_Load_Char bitmap_left: this field gives the distance in integer pixels from the current pen position to the left-most pixel of a glyph image WHEN IT IS A BITMAP. It is only valid when the "format" field is set to "ft_glyph_format_bitmap", for example, after calling the new function FT_Render_Glyph. bitmap_top: this field gives the distance in integer pixels from the current pen position (located on the baseline) to the top-most pixel of the glyph image WHEN IT IS A BITMAP. Positive values correspond to upwards Y. loader: this is a new private field for the glyph slot. Client applications should not touch it.. - support for transforms and direct rendering in FT_Load_Glyph: Most of the functionality found in <freetype/ftglyph.h> has been moved to the core library. Hence, the following: - a transform can be specified for a face through FT_Set_Transform. this transform is applied by FT_Load_Glyph to scalable glyph images (i.e. NOT TO BITMAPS) before the function returns, unless the bit flag FT_LOAD_IGNORE_TRANSFORM was set in the load flags.. - once a glyph image has been loaded, it can be directly converted to a bitmap by using the new FT_Render_Glyph function. Note that this function takes the glyph image from the glyph slot, and converts it to a bitmap whose properties are returned in "face.glyph.bitmap", "face.glyph.bitmap_left" and "face.glyph.bitmap_top". The original native image might be lost after the conversion. - when using the new bit flag FT_LOAD_RENDER, the FT_Load_Glyph and FT_Load_Char functions will call FT_Render_Glyph automatically when needed.
2000-06-22 02:17:42 +02:00
memory = driver->root.root.memory;
exec = driver->context;
1999-12-17 00:11:37 +01:00
if ( !driver->context )
{
FT_Error error;
1999-12-17 00:11:37 +01:00
/* allocate object */
if ( FT_NEW( exec ) )
1999-12-17 00:11:37 +01:00
goto Exit;
/* initialize it */
error = Init_Context( exec, memory );
1999-12-17 00:11:37 +01:00
if ( error )
goto Fail;
/* store it into the driver */
driver->context = exec;
}
Exit:
return driver->context;
Fail:
FT_FREE( exec );
1999-12-17 00:11:37 +01:00
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' */
1999-12-17 00:11:37 +01:00
/* 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. */
1999-12-17 00:11:37 +01:00
/* */
/*************************************************************************/
#undef PACK
#define PACK( x, y ) ( ( x << 4 ) | y )
1999-12-17 00:11:37 +01:00
static
const FT_Byte Pop_Push_Count[256] =
1999-12-17 00:11:37 +01:00
{
/* 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] =
1999-12-17 00:11:37 +01:00
{
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,
1999-12-17 00:11:37 +01:00
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
};
static
const FT_Vector Null_Vector = {0,0};
1999-12-17 00:11:37 +01:00
#undef PACK
1999-12-17 00:11:37 +01:00
#undef NULL_Vector
#define NULL_Vector (FT_Vector*)&Null_Vector
1999-12-17 00:11:37 +01:00
#if 1
2007-02-16 09:10:17 +01:00
static FT_Int32
TT_MulFix14( FT_Int32 a,
FT_Int b )
2007-02-16 09:10:17 +01:00
{
FT_Int32 sign;
FT_UInt32 ah, al, mid, lo, hi;
2007-02-16 09:10:17 +01:00
sign = a ^ b;
2007-02-16 09:10:17 +01:00
if ( a < 0 )
a = -a;
if ( b < 0 )
b = -b;
2007-02-16 09:10:17 +01:00
ah = (FT_UInt32)( ( a >> 16 ) & 0xFFFFU );
al = (FT_UInt32)( a & 0xFFFFU );
2007-02-16 09:10:17 +01:00
lo = al * b;
mid = ah * b;
hi = mid >> 16;
mid = ( mid << 16 ) + ( 1 << 13 ); /* rounding */
lo += mid;
if ( lo < mid )
hi += 1;
2007-02-16 09:10:17 +01:00
mid = ( lo >> 14 ) | ( hi << 18 );
return sign >= 0 ? (FT_Int32)mid : -(FT_Int32)mid;
}
#else
2007-02-16 09:10:17 +01:00
/* compute (a*b)/2^14 with maximal accuracy and rounding */
2002-03-25 18:02:26 +01:00
static FT_Int32
TT_MulFix14( FT_Int32 a,
FT_Int b )
2002-03-25 18:02:26 +01:00
{
FT_Int32 m, s, hi;
FT_UInt32 l, lo;
2002-03-25 18:02:26 +01:00
/* 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 );
2002-03-25 18:02:26 +01:00
/* divide the result by 2^14 with rounding */
s = hi >> 31;
2002-03-25 18:02:26 +01:00
l = lo + (FT_UInt32)s;
hi += s + ( l < lo );
2002-03-25 18:02:26 +01:00
lo = l;
l = lo + 0x2000U;
hi += (l < lo);
return ( hi << 18 ) | ( l >> 14 );
2002-03-25 18:02:26 +01:00
}
#endif
2002-03-25 18:02:26 +01:00
/* compute (ax*bx+ay*by)/2^14 with maximal accuracy and rounding */
2002-03-25 18:02:26 +01:00
static FT_Int32
TT_DotFix14( FT_Int32 ax,
FT_Int32 ay,
FT_Int bx,
FT_Int by )
2002-03-25 18:02:26 +01:00
{
FT_Int32 m, s, hi1, hi2, hi;
FT_UInt32 l, lo1, lo2, lo;
2002-03-25 18:02:26 +01:00
/* 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 );
2002-03-25 18:02:26 +01:00
/* 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 );
2002-03-25 18:02:26 +01:00
/* add them */
lo = lo1 + lo2;
hi = hi1 + hi2 + ( lo < lo1 );
2002-03-25 18:02:26 +01:00
/* divide the result by 2^14 with rounding */
s = hi >> 31;
2002-03-25 18:02:26 +01:00
l = lo + (FT_UInt32)s;
hi += s + ( l < lo );
2002-03-25 18:02:26 +01:00
lo = l;
l = lo + 0x2000U;
hi += ( l < lo );
return ( hi << 18 ) | ( l >> 14 );
2002-03-25 18:02:26 +01:00
}
/* return length of given vector */
2002-03-25 18:02:26 +01:00
#if 0
static FT_Int32
TT_VecLen( FT_Int32 x,
FT_Int32 y )
2002-03-25 18:02:26 +01:00
{
FT_Int32 m, hi1, hi2, hi;
FT_UInt32 l, lo1, lo2, lo;
2002-03-25 18:02:26 +01:00
/* 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 );
2002-03-25 18:02:26 +01:00
/* 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 );
2002-03-25 18:02:26 +01:00
/* add them to get 'x*x+y*y' as 64-bit value */
lo = lo1 + lo2;
hi = hi1 + hi2 + ( lo < lo1 );
2002-03-25 18:02:26 +01:00
/* 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 );
2002-03-25 18:02:26 +01:00
lo <<= 2;
root <<= 1;
test_div = ( root << 1 ) + 1;
if ( rem >= test_div )
{
rem -= test_div;
root += 1;
}
} while ( --count );
}
2002-03-25 18:02:26 +01:00
return (FT_Int32)root;
}
}
2002-03-25 18:02:26 +01:00
#else
/* this version uses FT_Vector_Length which computes the same value */
/* much, much faster.. */
/* */
2002-03-25 18:02:26 +01:00
static FT_F26Dot6
TT_VecLen( FT_F26Dot6 X,
FT_F26Dot6 Y )
{
FT_Vector v;
2002-03-25 18:02:26 +01:00
v.x = X;
v.y = Y;
2002-03-25 18:02:26 +01:00
return FT_Vector_Length( &v );
}
2002-03-25 18:02:26 +01:00
#endif
1999-12-17 00:11:37 +01:00
/*************************************************************************/
/* */
/* <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 . */
/* */
2001-06-28 09:17:51 +02:00
static FT_Long
Current_Ratio( EXEC_OP )
1999-12-17 00:11:37 +01:00
{
if ( !CUR.tt_metrics.ratio )
1999-12-17 00:11:37 +01:00
{
#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
2003-04-29 15:23:47 +02:00
{
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;
1999-12-17 00:11:37 +01:00
else
{
FT_Long x, y;
2003-04-29 15:23:47 +02:00
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 );
}
2003-04-29 15:23:47 +02:00
}
}
1999-12-17 00:11:37 +01:00
return CUR.tt_metrics.ratio;
}
2001-06-28 09:17:51 +02:00
static FT_Long
Current_Ppem( EXEC_OP )
1999-12-17 00:11:37 +01:00
{
return TT_MULFIX( CUR.tt_metrics.ppem, CURRENT_Ratio() );
}
/*************************************************************************/
/* */
/* Functions related to the control value table (CVT). */
/* */
/*************************************************************************/
2001-06-28 09:17:51 +02:00
FT_CALLBACK_DEF( FT_F26Dot6 )
Read_CVT( EXEC_OP_ FT_ULong idx )
1999-12-17 00:11:37 +01:00
{
return CUR.cvt[idx];
1999-12-17 00:11:37 +01:00
}
2001-06-28 09:17:51 +02:00
FT_CALLBACK_DEF( FT_F26Dot6 )
Read_CVT_Stretched( EXEC_OP_ FT_ULong idx )
1999-12-17 00:11:37 +01:00
{
return TT_MULFIX( CUR.cvt[idx], CURRENT_Ratio() );
1999-12-17 00:11:37 +01:00
}
2001-06-28 09:17:51 +02:00
FT_CALLBACK_DEF( void )
Write_CVT( EXEC_OP_ FT_ULong idx,
2001-06-28 09:17:51 +02:00
FT_F26Dot6 value )
1999-12-17 00:11:37 +01:00
{
CUR.cvt[idx] = value;
1999-12-17 00:11:37 +01:00
}
2001-06-28 09:17:51 +02:00
FT_CALLBACK_DEF( void )
Write_CVT_Stretched( EXEC_OP_ FT_ULong idx,
2001-06-28 09:17:51 +02:00
FT_F26Dot6 value )
1999-12-17 00:11:37 +01:00
{
CUR.cvt[idx] = FT_DivFix( value, CURRENT_Ratio() );
1999-12-17 00:11:37 +01:00
}
2001-06-28 09:17:51 +02:00
FT_CALLBACK_DEF( void )
Move_CVT( EXEC_OP_ FT_ULong idx,
2001-06-28 09:17:51 +02:00
FT_F26Dot6 value )
1999-12-17 00:11:37 +01:00
{
CUR.cvt[idx] += value;
1999-12-17 00:11:37 +01:00
}
2001-06-28 09:17:51 +02:00
FT_CALLBACK_DEF( void )
Move_CVT_Stretched( EXEC_OP_ FT_ULong idx,
2001-06-28 09:17:51 +02:00
FT_F26Dot6 value )
1999-12-17 00:11:37 +01:00
{
CUR.cvt[idx] += FT_DivFix( value, CURRENT_Ratio() );
1999-12-17 00:11:37 +01:00
}
/*************************************************************************/
/* */
/* <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. */
/* */
2001-06-28 09:17:51 +02:00
static FT_Short
GetShortIns( EXEC_OP )
1999-12-17 00:11:37 +01:00
{
/* 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] );
1999-12-17 00:11:37 +01:00
}
/*************************************************************************/
/* */
/* <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. */
/* */
2001-06-28 09:17:51 +02:00
static FT_Bool
Ins_Goto_CodeRange( EXEC_OP_ FT_Int aRange,
FT_ULong aIP )
1999-12-17 00:11:37 +01:00
{
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. */
/* */
1999-12-17 00:11:37 +01:00
/* distance :: The distance to apply. */
/* */
/* <InOut> */
/* zone :: The affected glyph zone. */
/* */
2001-06-28 09:17:51 +02:00
static void
Direct_Move( EXEC_OP_ TT_GlyphZone zone,
FT_UShort point,
FT_F26Dot6 distance )
1999-12-17 00:11:37 +01:00
{
FT_F26Dot6 v;
1999-12-17 00:11:37 +01:00
2003-04-29 15:23:47 +02:00
#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2003-04-29 15:23:47 +02:00
FT_ASSERT( !CUR.face->unpatented_hinting );
#endif
1999-12-17 00:11:37 +01:00
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;
1999-12-17 00:11:37 +01:00
}
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;
1999-12-17 00:11:37 +01:00
}
}
/*************************************************************************/
/* */
/* <Function> */
/* Direct_Move_Orig */
/* */
/* <Description> */
2003-11-28 23:47:26 +01:00
/* 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 );
}
1999-12-17 00:11:37 +01:00
/*************************************************************************/
/* */
/* 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. */
1999-12-17 00:11:37 +01:00
/* */
/*************************************************************************/
2001-06-28 09:17:51 +02:00
static void
Direct_Move_X( EXEC_OP_ TT_GlyphZone zone,
FT_UShort point,
FT_F26Dot6 distance )
1999-12-17 00:11:37 +01:00
{
FT_UNUSED_EXEC;
1999-12-17 00:11:37 +01:00
zone->cur[point].x += distance;
zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;
1999-12-17 00:11:37 +01:00
}
2001-06-28 09:17:51 +02:00
static void
Direct_Move_Y( EXEC_OP_ TT_GlyphZone zone,
FT_UShort point,
FT_F26Dot6 distance )
1999-12-17 00:11:37 +01:00
{
FT_UNUSED_EXEC;
1999-12-17 00:11:37 +01:00
zone->cur[point].y += distance;
zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
1999-12-17 00:11:37 +01:00
}
/*************************************************************************/
/* */
/* 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;
}
1999-12-17 00:11:37 +01:00
/*************************************************************************/
/* */
/* <Function> */
/* Round_None */
/* */
/* <Description> */
/* Does not round, but adds engine compensation. */
/* */
/* <Input> */
/* distance :: The distance (not) to round. */
/* */
1999-12-17 00:11:37 +01:00
/* 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. */
/* */
2001-06-28 09:17:51 +02:00
static FT_F26Dot6
Round_None( EXEC_OP_ FT_F26Dot6 distance,
FT_F26Dot6 compensation )
1999-12-17 00:11:37 +01:00
{
FT_F26Dot6 val;
1999-12-17 00:11:37 +01:00
FT_UNUSED_EXEC;
1999-12-17 00:11:37 +01:00
1999-12-17 00:11:37 +01:00
if ( distance >= 0 )
{
val = distance + compensation;
if ( distance && val < 0 )
1999-12-17 00:11:37 +01:00
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. */
/* */
1999-12-17 00:11:37 +01:00
/* compensation :: The engine compensation. */
/* */
/* <Return> */
/* Rounded distance. */
/* */
2001-06-28 09:17:51 +02:00
static FT_F26Dot6
Round_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
FT_F26Dot6 compensation )
1999-12-17 00:11:37 +01:00
{
FT_F26Dot6 val;
1999-12-17 00:11:37 +01:00
FT_UNUSED_EXEC;
1999-12-17 00:11:37 +01:00
1999-12-17 00:11:37 +01:00
if ( distance >= 0 )
{
val = distance + compensation + 32;
if ( distance && val > 0 )
1999-12-17 00:11:37 +01:00
val &= ~63;
else
val = 0;
}
else
{
val = -FT_PIX_ROUND( compensation - distance );
1999-12-17 00:11:37 +01:00
if ( val > 0 )
val = 0;
}
1999-12-17 00:11:37 +01:00
return val;
}
/*************************************************************************/
/* */
/* <Function> */
/* Round_To_Half_Grid */
/* */
/* <Description> */
/* Rounds value to half grid after adding engine compensation. */
/* */
/* <Input> */
/* distance :: The distance to round. */
/* */
1999-12-17 00:11:37 +01:00
/* compensation :: The engine compensation. */
/* */
/* <Return> */
/* Rounded distance. */
/* */
2001-06-28 09:17:51 +02:00
static FT_F26Dot6
Round_To_Half_Grid( EXEC_OP_ FT_F26Dot6 distance,
FT_F26Dot6 compensation )
1999-12-17 00:11:37 +01:00
{
FT_F26Dot6 val;
1999-12-17 00:11:37 +01:00
FT_UNUSED_EXEC;
2000-05-17 01:44:38 +02:00
1999-12-17 00:11:37 +01:00
if ( distance >= 0 )
{
val = FT_PIX_FLOOR( distance + compensation ) + 32;
if ( distance && val < 0 )
1999-12-17 00:11:37 +01:00
val = 0;
}
else
{
val = -( FT_PIX_FLOOR( compensation - distance ) + 32 );
1999-12-17 00:11:37 +01:00
if ( val > 0 )
val = 0;
}
1999-12-17 00:11:37 +01:00
return val;
}
/*************************************************************************/
/* */
/* <Function> */
/* Round_Down_To_Grid */
/* */
/* <Description> */
/* Rounds value down to grid after adding engine compensation. */
/* */
/* <Input> */
/* distance :: The distance to round. */
/* */
1999-12-17 00:11:37 +01:00
/* compensation :: The engine compensation. */
/* */
/* <Return> */
/* Rounded distance. */
/* */
2001-06-28 09:17:51 +02:00
static FT_F26Dot6
Round_Down_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
FT_F26Dot6 compensation )
1999-12-17 00:11:37 +01:00
{
FT_F26Dot6 val;
1999-12-17 00:11:37 +01:00
FT_UNUSED_EXEC;
1999-12-17 00:11:37 +01:00
1999-12-17 00:11:37 +01:00
if ( distance >= 0 )
{
val = distance + compensation;
if ( distance && val > 0 )
1999-12-17 00:11:37 +01:00
val &= ~63;
else
val = 0;
}
else
{
val = -( ( compensation - distance ) & -64 );
1999-12-17 00:11:37 +01:00
if ( val > 0 )
val = 0;
}
1999-12-17 00:11:37 +01:00
return val;
}
/*************************************************************************/
/* */
/* <Function> */
/* Round_Up_To_Grid */
/* */
/* <Description> */
/* Rounds value up to grid after adding engine compensation. */
/* */
/* <Input> */
/* distance :: The distance to round. */
/* */
1999-12-17 00:11:37 +01:00
/* compensation :: The engine compensation. */
/* */
/* <Return> */
/* Rounded distance. */
/* */
2001-06-28 09:17:51 +02:00
static FT_F26Dot6
Round_Up_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
FT_F26Dot6 compensation )
1999-12-17 00:11:37 +01:00
{
FT_F26Dot6 val;
1999-12-17 00:11:37 +01:00
FT_UNUSED_EXEC;
1999-12-17 00:11:37 +01:00
1999-12-17 00:11:37 +01:00
if ( distance >= 0 )
{
val = distance + compensation + 63;
if ( distance && val > 0 )
1999-12-17 00:11:37 +01:00
val &= ~63;
else
val = 0;
}
else
{
val = - FT_PIX_CEIL( compensation - distance );
1999-12-17 00:11:37 +01:00
if ( val > 0 )
val = 0;
}
1999-12-17 00:11:37 +01:00
return val;
}
/*************************************************************************/
/* */
/* <Function> */
/* Round_To_Double_Grid */
/* */
/* <Description> */
/* Rounds value to double grid after adding engine compensation. */
/* */
/* <Input> */
/* distance :: The distance to round. */
/* */
1999-12-17 00:11:37 +01:00
/* compensation :: The engine compensation. */
/* */
/* <Return> */
/* Rounded distance. */
/* */
2001-06-28 09:17:51 +02:00
static FT_F26Dot6
Round_To_Double_Grid( EXEC_OP_ FT_F26Dot6 distance,
FT_F26Dot6 compensation )
1999-12-17 00:11:37 +01:00
{
FT_F26Dot6 val;
1999-12-17 00:11:37 +01:00
FT_UNUSED_EXEC;
1999-12-17 00:11:37 +01:00
1999-12-17 00:11:37 +01:00
if ( distance >= 0 )
{
val = distance + compensation + 16;
if ( distance && val > 0 )
1999-12-17 00:11:37 +01:00
val &= ~31;
else
val = 0;
}
else
{
val = -FT_PAD_ROUND( compensation - distance, 32 );
1999-12-17 00:11:37 +01:00
if ( val > 0 )
val = 0;
}
1999-12-17 00:11:37 +01:00
return val;
}
/*************************************************************************/
/* */
/* <Function> */
/* Round_Super */
/* */
/* <Description> */
/* Super-rounds value to grid after adding engine compensation. */
/* */
/* <Input> */
/* distance :: The distance to round. */
/* */
1999-12-17 00:11:37 +01:00
/* 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. */
/* */
2001-06-28 09:17:51 +02:00
static FT_F26Dot6
Round_Super( EXEC_OP_ FT_F26Dot6 distance,
FT_F26Dot6 compensation )
1999-12-17 00:11:37 +01:00
{
FT_F26Dot6 val;
1999-12-17 00:11:37 +01:00
if ( distance >= 0 )
{
val = ( distance - CUR.phase + CUR.threshold + compensation ) &
-CUR.period;
if ( distance && val < 0 )
1999-12-17 00:11:37 +01:00
val = 0;
val += CUR.phase;
}
else
{
val = -( ( CUR.threshold - CUR.phase - distance + compensation ) &
-CUR.period );
1999-12-17 00:11:37 +01:00
if ( val > 0 )
val = 0;
val -= CUR.phase;
}
1999-12-17 00:11:37 +01:00
return val;
}
/*************************************************************************/
/* */
/* <Function> */
/* Round_Super_45 */
/* */
/* <Description> */
/* Super-rounds value to grid after adding engine compensation. */
/* */
/* <Input> */
/* distance :: The distance to round. */
/* */
1999-12-17 00:11:37 +01:00
/* compensation :: The engine compensation. */
/* */
/* <Return> */
/* Rounded distance. */
/* */
/* <Note> */
/* There is a separate function for Round_Super_45() as we may need */
/* greater precision. */
/* */
2001-06-28 09:17:51 +02:00
static FT_F26Dot6
Round_Super_45( EXEC_OP_ FT_F26Dot6 distance,
FT_F26Dot6 compensation )
1999-12-17 00:11:37 +01:00
{
FT_F26Dot6 val;
1999-12-17 00:11:37 +01:00
if ( distance >= 0 )
{
val = ( ( distance - CUR.phase + CUR.threshold + compensation ) /
1999-12-17 00:11:37 +01:00
CUR.period ) * CUR.period;
if ( distance && val < 0 )
1999-12-17 00:11:37 +01:00
val = 0;
val += CUR.phase;
}
else
{
val = -( ( ( CUR.threshold - CUR.phase - distance + compensation ) /
1999-12-17 00:11:37 +01:00
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. */
/* */
2001-06-28 09:17:51 +02:00
static void
Compute_Round( EXEC_OP_ FT_Byte round_mode )
1999-12-17 00:11:37 +01:00
{
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 */
/* */
2001-06-28 09:17:51 +02:00
static void
SetSuperRound( EXEC_OP_ FT_F26Dot6 GridPeriod,
FT_Long selector )
1999-12-17 00:11:37 +01:00
{
switch ( (FT_Int)( selector & 0xC0 ) )
1999-12-17 00:11:37 +01:00
{
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 ) )
1999-12-17 00:11:37 +01:00
{
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;
1999-12-17 00:11:37 +01:00
break;
}
if ( (selector & 0x0F) == 0 )
CUR.threshold = CUR.period - 1;
else
CUR.threshold = ( (FT_Int)( selector & 0x0F ) - 4 ) * CUR.period / 8;
1999-12-17 00:11:37 +01:00
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. */
/* */
2001-06-28 09:17:51 +02:00
static FT_F26Dot6
Project( EXEC_OP_ FT_Pos dx,
FT_Pos dy )
2007-02-12 23:01:18 +01:00
{
#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2003-04-29 15:23:47 +02:00
FT_ASSERT( !CUR.face->unpatented_hinting );
#endif
2003-04-29 15:23:47 +02:00
return TT_DotFix14( dx, dy,
2002-03-25 18:02:26 +01:00
CUR.GS.projVector.x,
CUR.GS.projVector.y );
2007-02-12 23:01:18 +01:00
}
1999-12-17 00:11:37 +01:00
/*************************************************************************/
/* */
/* <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. */
/* */
2001-06-28 09:17:51 +02:00
static FT_F26Dot6
Dual_Project( EXEC_OP_ FT_Pos dx,
FT_Pos dy )
1999-12-17 00:11:37 +01:00
{
return TT_DotFix14( dx, dy,
2002-03-25 18:02:26 +01:00
CUR.GS.dualVector.x,
CUR.GS.dualVector.y );
1999-12-17 00:11:37 +01:00
}
2007-02-12 23:01:18 +01:00
1999-12-17 00:11:37 +01:00
/*************************************************************************/
/* */
/* <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. */
/* */
2001-06-28 09:17:51 +02:00
static FT_F26Dot6
Project_x( EXEC_OP_ FT_Pos dx,
FT_Pos dy )
1999-12-17 00:11:37 +01:00
{
FT_UNUSED_EXEC;
FT_UNUSED( dy );
1999-12-17 00:11:37 +01:00
return dx;
1999-12-17 00:11:37 +01:00
}
2007-02-12 23:01:18 +01:00
1999-12-17 00:11:37 +01:00
/*************************************************************************/
/* */
/* <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. */
/* */
2001-06-28 09:17:51 +02:00
static FT_F26Dot6
Project_y( EXEC_OP_ FT_Pos dx,
FT_Pos dy )
1999-12-17 00:11:37 +01:00
{
FT_UNUSED_EXEC;
FT_UNUSED( dx );
2000-05-17 01:44:38 +02:00
return dy;
1999-12-17 00:11:37 +01:00
}
2007-02-12 23:01:18 +01:00
1999-12-17 00:11:37 +01:00
/*************************************************************************/
/* */
/* <Function> */
/* Compute_Funcs */
/* */
/* <Description> */
/* Computes the projection and movement function pointers according */
/* to the current graphics state. */
/* */
2001-06-28 09:17:51 +02:00
static void
Compute_Funcs( EXEC_OP )
1999-12-17 00:11:37 +01:00
{
#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
if ( CUR.face->unpatented_hinting )
2003-04-29 15:23:47 +02:00
{
/* If both vectors point rightwards along the x axis, set */
2003-04-29 15:23:47 +02:00
/* `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;
}
2003-04-29 15:23:47 +02:00
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 )
2003-04-29 15:23:47 +02:00
CUR.func_dualproj = Project_y;
else
CUR.func_dualproj = Dual_Project;
}
/* Force recalculation of cached aspect ratio */
CUR.tt_metrics.ratio = 0;
2003-04-29 15:23:47 +02:00
return;
}
#endif /* TT_CONFIG_OPTION_UNPATENTED_HINTING */
1999-12-17 00:11:37 +01:00
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;
1999-12-17 00:11:37 +01:00
}
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;
1999-12-17 00:11:37 +01:00
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;
}
1999-12-17 00:11:37 +01:00
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;
}
1999-12-17 00:11:37 +01:00
}
}
/* 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 )
1999-12-17 00:11:37 +01:00
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. */
/* */
2001-06-28 09:17:51 +02:00
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;
2000-05-17 01:44:38 +02:00
if ( FT_ABS( Vx ) < 0x10000L && FT_ABS( Vy ) < 0x10000L )
{
Vx *= 0x100;
Vy *= 0x100;
2002-03-25 18:02:26 +01:00
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;
}
2002-03-25 18:02:26 +01:00
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;
}
1999-12-17 00:11:37 +01:00
/*************************************************************************/
/* */
/* Here we start with the implementation of the various opcodes. */
/* */
/*************************************************************************/
2001-06-28 09:17:51 +02:00
static FT_Bool
Ins_SxVTL( EXEC_OP_ FT_UShort aIdx1,
FT_UShort aIdx2,
FT_Int aOpc,
FT_UnitVector* Vec )
1999-12-17 00:11:37 +01:00
{
FT_Long A, B, C;
FT_Vector* p1;
FT_Vector* p2;
1999-12-17 00:11:37 +01:00
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 )
1999-12-17 00:11:37 +01:00
{
C = B; /* counter clockwise rotation */
1999-12-17 00:11:37 +01:00
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(); \
}
1999-12-17 00:11:37 +01:00
#define DO_SFVTPV \
GUESS_VECTOR( projVector ); \
1999-12-17 00:11:37 +01:00
CUR.GS.freeVector = CUR.GS.projVector; \
COMPUTE_Funcs();
#define DO_SPVFS \
{ \
FT_Short S; \
FT_Long X, Y; \
1999-12-17 00:11:37 +01:00
\
\
/* 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; \
1999-12-17 00:11:37 +01:00
\
NORMalize( X, Y, &CUR.GS.projVector ); \
\
CUR.GS.dualVector = CUR.GS.projVector; \
GUESS_VECTOR( freeVector ); \
1999-12-17 00:11:37 +01:00
COMPUTE_Funcs(); \
}
#define DO_SFVFS \
{ \
FT_Short S; \
FT_Long X, Y; \
1999-12-17 00:11:37 +01:00
\
\
/* Only use low 16bits, then sign extend */ \
S = (FT_Short)args[1]; \
Y = (FT_Long)S; \
S = (FT_Short)args[0]; \
1999-12-17 00:11:37 +01:00
X = S; \
\
NORMalize( X, Y, &CUR.GS.freeVector ); \
GUESS_VECTOR( projVector ); \
1999-12-17 00:11:37 +01:00
COMPUTE_Funcs(); \
}
#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2003-04-29 15:23:47 +02:00
#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
2003-04-29 15:23:47 +02:00
#define DO_GPV \
args[0] = CUR.GS.projVector.x; \
1999-12-17 00:11:37 +01:00
args[1] = CUR.GS.projVector.y;
#endif
1999-12-17 00:11:37 +01:00
#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2003-04-29 15:23:47 +02:00
#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
2003-04-29 15:23:47 +02:00
#define DO_GFV \
args[0] = CUR.GS.freeVector.x; \
1999-12-17 00:11:37 +01:00
args[1] = CUR.GS.freeVector.y;
#endif
1999-12-17 00:11:37 +01:00
#define DO_SRP0 \
CUR.GS.rp0 = (FT_UShort)args[0];
1999-12-17 00:11:37 +01:00
#define DO_SRP1 \
CUR.GS.rp1 = (FT_UShort)args[0];
1999-12-17 00:11:37 +01:00
#define DO_SRP2 \
CUR.GS.rp2 = (FT_UShort)args[0];
1999-12-17 00:11:37 +01:00
#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];
1999-12-17 00:11:37 +01:00
#define DO_SSWCI \
CUR.GS.single_width_cutin = (FT_F26Dot6)args[0];
1999-12-17 00:11:37 +01:00
/* 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 );
1999-12-17 00:11:37 +01:00
#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];
1999-12-17 00:11:37 +01:00
#define DO_SDS \
CUR.GS.delta_shift = (FT_Short)args[0];
1999-12-17 00:11:37 +01:00
#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. */
1999-12-17 00:11:37 +01:00
#if 0
1999-12-17 00:11:37 +01:00
#define DO_MPS \
args[0] = CUR.metrics.pointSize;
1999-12-17 00:11:37 +01:00
#else
#define DO_MPS \
1999-12-17 00:11:37 +01:00
args[0] = CURRENT_Ppem();
#endif /* 0 */
1999-12-17 00:11:37 +01:00
#define DO_DUP \
args[1] = args[0];
#define DO_CLEAR \
CUR.new_top = 0;
#define DO_SWAP \
{ \
FT_Long L; \
1999-12-17 00:11:37 +01:00
\
\
1999-12-17 00:11:37 +01:00
L = args[0]; \
args[0] = args[1]; \
args[1] = L; \
}
#define DO_DEPTH \
args[0] = CUR.top;
#define DO_CINDEX \
{ \
FT_Long L; \
1999-12-17 00:11:37 +01:00
\
\
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] );
1999-12-17 00:11:37 +01:00
#define DO_LTEQ \
args[0] = ( args[0] <= args[1] );
1999-12-17 00:11:37 +01:00
#define DO_GT \
args[0] = ( args[0] > args[1] );
1999-12-17 00:11:37 +01:00
#define DO_GTEQ \
args[0] = ( args[0] >= args[1] );
1999-12-17 00:11:37 +01:00
#define DO_EQ \
args[0] = ( args[0] == args[1] );
1999-12-17 00:11:37 +01:00
#define DO_NEQ \
args[0] = ( args[0] != args[1] );
1999-12-17 00:11:37 +01:00
#define DO_ODD \
args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 64 );
1999-12-17 00:11:37 +01:00
#define DO_EVEN \
args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 0 );
1999-12-17 00:11:37 +01:00
#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] );
1999-12-17 00:11:37 +01:00
#define DO_MUL \
args[0] = TT_MULDIV( args[0], args[1], 64L );
#define DO_ABS \
args[0] = FT_ABS( args[0] );
1999-12-17 00:11:37 +01:00
#define DO_NEG \
args[0] = -args[0];
#define DO_FLOOR \
args[0] = FT_PIX_FLOOR( args[0] );
1999-12-17 00:11:37 +01:00
#define DO_CEILING \
args[0] = FT_PIX_CEIL( args[0] );
1999-12-17 00:11:37 +01:00
#define DO_RS \
{ \
FT_ULong I = (FT_ULong)args[0]; \
1999-12-17 00:11:37 +01:00
\
\
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]; \
1999-12-17 00:11:37 +01:00
\
\
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 ); \
1999-12-17 00:11:37 +01:00
}
#define DO_WCVTP \
{ \
FT_ULong I = (FT_ULong)args[0]; \
1999-12-17 00:11:37 +01:00
\
\
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]; \
1999-12-17 00:11:37 +01:00
\
\
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; \
}
1999-12-17 00:11:37 +01:00
/*************************************************************************/
/* */
/* SVTCA[a]: Set (F and P) Vectors to Coordinate Axis */
/* Opcode range: 0x00-0x01 */
/* Stack: --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SVTCA( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_SVTCA
}
/*************************************************************************/
/* */
/* SPVTCA[a]: Set PVector to Coordinate Axis */
/* Opcode range: 0x02-0x03 */
/* Stack: --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SPVTCA( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_SPVTCA
}
/*************************************************************************/
/* */
/* SFVTCA[a]: Set FVector to Coordinate Axis */
/* Opcode range: 0x04-0x05 */
/* Stack: --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SFVTCA( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_SFVTCA
}
/*************************************************************************/
/* */
/* SPVTL[a]: Set PVector To Line */
/* Opcode range: 0x06-0x07 */
/* Stack: uint32 uint32 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SPVTL( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_SPVTL
}
/*************************************************************************/
/* */
/* SFVTL[a]: Set FVector To Line */
/* Opcode range: 0x08-0x09 */
/* Stack: uint32 uint32 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SFVTL( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_SFVTL
}
/*************************************************************************/
/* */
/* SFVTPV[]: Set FVector To PVector */
/* Opcode range: 0x0E */
/* Stack: --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SFVTPV( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_SFVTPV
}
/*************************************************************************/
/* */
/* SPVFS[]: Set PVector From Stack */
/* Opcode range: 0x0A */
/* Stack: f2.14 f2.14 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SPVFS( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_SPVFS
}
/*************************************************************************/
/* */
/* SFVFS[]: Set FVector From Stack */
/* Opcode range: 0x0B */
/* Stack: f2.14 f2.14 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SFVFS( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_SFVFS
}
/*************************************************************************/
/* */
/* GPV[]: Get Projection Vector */
/* Opcode range: 0x0C */
/* Stack: ef2.14 --> ef2.14 */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_GPV( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_GPV
}
/*************************************************************************/
/* GFV[]: Get Freedom Vector */
/* Opcode range: 0x0D */
/* Stack: ef2.14 --> ef2.14 */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_GFV( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_GFV
}
/*************************************************************************/
/* */
/* SRP0[]: Set Reference Point 0 */
/* Opcode range: 0x10 */
/* Stack: uint32 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SRP0( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_SRP0
}
/*************************************************************************/
/* */
/* SRP1[]: Set Reference Point 1 */
/* Opcode range: 0x11 */
/* Stack: uint32 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SRP1( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_SRP1
}
/*************************************************************************/
/* */
/* SRP2[]: Set Reference Point 2 */
/* Opcode range: 0x12 */
/* Stack: uint32 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SRP2( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_SRP2
}
/*************************************************************************/
/* */
/* RTHG[]: Round To Half Grid */
/* Opcode range: 0x19 */
/* Stack: --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_RTHG( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_RTHG
}
/*************************************************************************/
/* */
/* RTG[]: Round To Grid */
/* Opcode range: 0x18 */
/* Stack: --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_RTG( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_RTG
}
/*************************************************************************/
/* RTDG[]: Round To Double Grid */
/* Opcode range: 0x3D */
/* Stack: --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_RTDG( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_RTDG
}
/*************************************************************************/
/* RUTG[]: Round Up To Grid */
/* Opcode range: 0x7C */
/* Stack: --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_RUTG( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_RUTG
}
/*************************************************************************/
/* */
/* RDTG[]: Round Down To Grid */
/* Opcode range: 0x7D */
/* Stack: --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_RDTG( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_RDTG
}
/*************************************************************************/
/* */
/* ROFF[]: Round OFF */
/* Opcode range: 0x7A */
/* Stack: --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_ROFF( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_ROFF
}
/*************************************************************************/
/* */
/* SROUND[]: Super ROUND */
/* Opcode range: 0x76 */
/* Stack: Eint8 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SROUND( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_SROUND
}
/*************************************************************************/
/* */
/* S45ROUND[]: Super ROUND 45 degrees */
/* Opcode range: 0x77 */
/* Stack: uint32 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_S45ROUND( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_S45ROUND
}
/*************************************************************************/
/* */
/* SLOOP[]: Set LOOP variable */
/* Opcode range: 0x17 */
/* Stack: int32? --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SLOOP( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_SLOOP
}
/*************************************************************************/
/* */
/* SMD[]: Set Minimum Distance */
/* Opcode range: 0x1A */
/* Stack: f26.6 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SMD( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_SMD
}
/*************************************************************************/
/* */
/* SCVTCI[]: Set Control Value Table Cut In */
/* Opcode range: 0x1D */
/* Stack: f26.6 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SCVTCI( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_SCVTCI
}
/*************************************************************************/
/* */
/* SSWCI[]: Set Single Width Cut In */
/* Opcode range: 0x1E */
/* Stack: f26.6 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SSWCI( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_SSWCI
}
/*************************************************************************/
/* */
/* SSW[]: Set Single Width */
/* Opcode range: 0x1F */
/* Stack: int32? --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SSW( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_SSW
}
/*************************************************************************/
/* */
/* FLIPON[]: Set auto-FLIP to ON */
/* Opcode range: 0x4D */
/* Stack: --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_FLIPON( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_FLIPON
}
/*************************************************************************/
/* */
/* FLIPOFF[]: Set auto-FLIP to OFF */
/* Opcode range: 0x4E */
/* Stack: --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_FLIPOFF( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_FLIPOFF
}
/*************************************************************************/
/* */
/* SANGW[]: Set ANGle Weight */
/* Opcode range: 0x7E */
/* Stack: uint32 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SANGW( INS_ARG )
1999-12-17 00:11:37 +01:00
{
/* instruction not supported anymore */
}
/*************************************************************************/
/* */
/* SDB[]: Set Delta Base */
/* Opcode range: 0x5E */
/* Stack: uint32 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SDB( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_SDB
}
/*************************************************************************/
/* */
/* SDS[]: Set Delta Shift */
/* Opcode range: 0x5F */
/* Stack: uint32 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SDS( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_SDS
}
/*************************************************************************/
/* */
/* MPPEM[]: Measure Pixel Per EM */
/* Opcode range: 0x4B */
/* Stack: --> Euint16 */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_MPPEM( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_MPPEM
}
/*************************************************************************/
/* */
/* MPS[]: Measure Point Size */
/* Opcode range: 0x4C */
/* Stack: --> Euint16 */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_MPS( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_MPS
}
/*************************************************************************/
/* */
/* DUP[]: DUPlicate the top stack's element */
1999-12-17 00:11:37 +01:00
/* Opcode range: 0x20 */
/* Stack: StkElt --> StkElt StkElt */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_DUP( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_DUP
}
/*************************************************************************/
/* */
/* POP[]: POP the stack's top element */
1999-12-17 00:11:37 +01:00
/* Opcode range: 0x21 */
/* Stack: StkElt --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_POP( INS_ARG )
1999-12-17 00:11:37 +01:00
{
/* nothing to do */
}
/*************************************************************************/
/* */
/* CLEAR[]: CLEAR the entire stack */
/* Opcode range: 0x22 */
/* Stack: StkElt... --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_CLEAR( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_CLEAR
}
/*************************************************************************/
/* */
/* SWAP[]: SWAP the stack's top two elements */
1999-12-17 00:11:37 +01:00
/* Opcode range: 0x23 */
/* Stack: 2 * StkElt --> 2 * StkElt */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SWAP( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_SWAP
}
/*************************************************************************/
/* */
/* DEPTH[]: return the stack DEPTH */
/* Opcode range: 0x24 */
/* Stack: --> uint32 */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_DEPTH( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_DEPTH
}
/*************************************************************************/
/* */
/* CINDEX[]: Copy INDEXed element */
/* Opcode range: 0x25 */
/* Stack: int32 --> StkElt */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_CINDEX( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_CINDEX
}
/*************************************************************************/
/* */
/* EIF[]: End IF */
/* Opcode range: 0x59 */
/* Stack: --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_EIF( INS_ARG )
1999-12-17 00:11:37 +01:00
{
/* nothing to do */
}
/*************************************************************************/
/* */
/* JROT[]: Jump Relative On True */
/* Opcode range: 0x78 */
/* Stack: StkElt int32 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_JROT( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_JROT
}
/*************************************************************************/
/* */
/* JMPR[]: JuMP Relative */
/* Opcode range: 0x1C */
/* Stack: int32 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_JMPR( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_JMPR
}
/*************************************************************************/
/* */
/* JROF[]: Jump Relative On False */
/* Opcode range: 0x79 */
/* Stack: StkElt int32 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_JROF( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_JROF
}
/*************************************************************************/
/* */
/* LT[]: Less Than */
/* Opcode range: 0x50 */
/* Stack: int32? int32? --> bool */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_LT( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_LT
}
/*************************************************************************/
/* */
/* LTEQ[]: Less Than or EQual */
/* Opcode range: 0x51 */
/* Stack: int32? int32? --> bool */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_LTEQ( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_LTEQ
}
/*************************************************************************/
/* */
/* GT[]: Greater Than */
/* Opcode range: 0x52 */
/* Stack: int32? int32? --> bool */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_GT( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_GT
}
/*************************************************************************/
/* */
/* GTEQ[]: Greater Than or EQual */
/* Opcode range: 0x53 */
/* Stack: int32? int32? --> bool */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_GTEQ( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_GTEQ
}
/*************************************************************************/
/* */
/* EQ[]: EQual */
/* Opcode range: 0x54 */
/* Stack: StkElt StkElt --> bool */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_EQ( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_EQ
}
/*************************************************************************/
/* */
/* NEQ[]: Not EQual */
/* Opcode range: 0x55 */
/* Stack: StkElt StkElt --> bool */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_NEQ( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_NEQ
}
/*************************************************************************/
/* */
/* ODD[]: Is ODD */
/* Opcode range: 0x56 */
/* Stack: f26.6 --> bool */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_ODD( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_ODD
}
/*************************************************************************/
/* */
/* EVEN[]: Is EVEN */
/* Opcode range: 0x57 */
/* Stack: f26.6 --> bool */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_EVEN( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_EVEN
}
/*************************************************************************/
/* */
/* AND[]: logical AND */
/* Opcode range: 0x5A */
/* Stack: uint32 uint32 --> uint32 */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_AND( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_AND
}
/*************************************************************************/
/* */
/* OR[]: logical OR */
/* Opcode range: 0x5B */
/* Stack: uint32 uint32 --> uint32 */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_OR( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_OR
}
/*************************************************************************/
/* */
/* NOT[]: logical NOT */
/* Opcode range: 0x5C */
/* Stack: StkElt --> uint32 */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_NOT( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_NOT
}
/*************************************************************************/
/* */
/* ADD[]: ADD */
/* Opcode range: 0x60 */
/* Stack: f26.6 f26.6 --> f26.6 */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_ADD( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_ADD
}
/*************************************************************************/
/* */
/* SUB[]: SUBtract */
/* Opcode range: 0x61 */
/* Stack: f26.6 f26.6 --> f26.6 */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SUB( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_SUB
}
/*************************************************************************/
/* */
/* DIV[]: DIVide */
/* Opcode range: 0x62 */
/* Stack: f26.6 f26.6 --> f26.6 */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_DIV( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_DIV
}
/*************************************************************************/
/* */
/* MUL[]: MULtiply */
/* Opcode range: 0x63 */
/* Stack: f26.6 f26.6 --> f26.6 */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_MUL( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_MUL
}
/*************************************************************************/
/* */
/* ABS[]: ABSolute value */
/* Opcode range: 0x64 */
/* Stack: f26.6 --> f26.6 */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_ABS( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_ABS
}
/*************************************************************************/
/* */
/* NEG[]: NEGate */
/* Opcode range: 0x65 */
/* Stack: f26.6 --> f26.6 */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_NEG( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_NEG
}
/*************************************************************************/
/* */
/* FLOOR[]: FLOOR */
/* Opcode range: 0x66 */
/* Stack: f26.6 --> f26.6 */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_FLOOR( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_FLOOR
}
/*************************************************************************/
/* */
/* CEILING[]: CEILING */
/* Opcode range: 0x67 */
/* Stack: f26.6 --> f26.6 */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_CEILING( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_CEILING
}
/*************************************************************************/
/* */
/* RS[]: Read Store */
/* Opcode range: 0x43 */
/* Stack: uint32 --> uint32 */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_RS( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_RS
}
/*************************************************************************/
/* */
/* WS[]: Write Store */
/* Opcode range: 0x42 */
/* Stack: uint32 uint32 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_WS( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_WS
}
/*************************************************************************/
/* */
/* WCVTP[]: Write CVT in Pixel units */
/* Opcode range: 0x44 */
/* Stack: f26.6 uint32 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_WCVTP( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_WCVTP
}
/*************************************************************************/
/* */
/* WCVTF[]: Write CVT in Funits */
/* Opcode range: 0x70 */
/* Stack: uint32 uint32 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_WCVTF( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_WCVTF
}
/*************************************************************************/
/* */
/* RCVT[]: Read CVT */
/* Opcode range: 0x45 */
/* Stack: uint32 --> f26.6 */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_RCVT( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_RCVT
}
/*************************************************************************/
/* */
/* AA[]: Adjust Angle */
/* Opcode range: 0x7F */
/* Stack: uint32 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_AA( INS_ARG )
1999-12-17 00:11:37 +01:00
{
/* intentionally no longer supported */
1999-12-17 00:11:37 +01:00
}
/*************************************************************************/
/* */
/* DEBUG[]: DEBUG. Unsupported. */
1999-12-17 00:11:37 +01:00
/* Opcode range: 0x4F */
/* Stack: uint32 --> */
/* */
/* Note: The original instruction pops a value from the stack. */
1999-12-17 00:11:37 +01:00
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_DEBUG( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_DEBUG
}
/*************************************************************************/
/* */
/* ROUND[ab]: ROUND value */
/* Opcode range: 0x68-0x6B */
/* Stack: f26.6 --> f26.6 */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_ROUND( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_ROUND
}
/*************************************************************************/
/* */
/* NROUND[ab]: No ROUNDing of value */
/* Opcode range: 0x6C-0x6F */
/* Stack: f26.6 --> f26.6 */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_NROUND( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_NROUND
}
/*************************************************************************/
/* */
/* MAX[]: MAXimum */
/* Opcode range: 0x68 */
/* Stack: int32? int32? --> int32 */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_MAX( INS_ARG )
1999-12-17 00:11:37 +01:00
{
DO_MAX
}
/*************************************************************************/
/* */
/* MIN[]: MINimum */
/* Opcode range: 0x69 */
/* Stack: int32? int32? --> int32 */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_MIN( INS_ARG )
1999-12-17 00:11:37 +01:00
{
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 */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_MINDEX( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_Long L, K;
1999-12-17 00:11:37 +01:00
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 ) );
1999-12-17 00:11:37 +01:00
CUR.stack[CUR.args - 1] = K;
}
/*************************************************************************/
/* */
/* ROLL[]: ROLL top three elements */
/* Opcode range: 0x8A */
/* Stack: 3 * StkElt --> 3 * StkElt */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_ROLL( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_Long A, B, C;
1999-12-17 00:11:37 +01:00
FT_UNUSED_EXEC;
1999-12-17 00:11:37 +01:00
1999-12-17 00:11:37 +01:00
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. */
1999-12-17 00:11:37 +01:00
/* */
/*************************************************************************/
2001-06-28 09:17:51 +02:00
static FT_Bool
SkipCode( EXEC_OP )
1999-12-17 00:11:37 +01:00
{
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];
1999-12-17 00:11:37 +01:00
}
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 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_IF( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_Int nIfs;
FT_Bool Out;
1999-12-17 00:11:37 +01:00
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 );
1999-12-17 00:11:37 +01:00
break;
case 0x59: /* EIF */
nIfs--;
Out = FT_BOOL( nIfs == 0 );
1999-12-17 00:11:37 +01:00
break;
}
} while ( Out == 0 );
}
/*************************************************************************/
/* */
/* ELSE[]: ELSE */
/* Opcode range: 0x1B */
/* Stack: --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_ELSE( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_Int nIfs;
1999-12-17 00:11:37 +01:00
FT_UNUSED_ARG;
1999-12-17 00:11:37 +01:00
1999-12-17 00:11:37 +01:00
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. */
1999-12-17 00:11:37 +01:00
/* */
/*************************************************************************/
/*************************************************************************/
/* */
/* FDEF[]: Function DEFinition */
/* Opcode range: 0x2C */
/* Stack: uint32 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_FDEF( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_ULong n;
1999-12-17 00:11:37 +01:00
TT_DefRecord* rec;
TT_DefRecord* limit;
1999-12-17 00:11:37 +01:00
/* some font programs are broken enough to redefine functions! */
/* We will then parse the current table. */
1999-12-17 00:11:37 +01:00
rec = CUR.FDefs;
limit = rec + CUR.numFDefs;
n = args[0];
2000-05-17 01:44:38 +02:00
1999-12-17 00:11:37 +01:00
for ( ; rec < limit; rec++ )
{
if ( rec->opc == n )
1999-12-17 00:11:37 +01:00
break;
}
2000-05-17 01:44:38 +02:00
1999-12-17 00:11:37 +01:00
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++;
}
2000-05-17 01:44:38 +02:00
1999-12-17 00:11:37 +01:00
rec->range = CUR.curRange;
rec->opc = n;
rec->start = CUR.IP + 1;
1999-12-17 00:11:37 +01:00
rec->active = TRUE;
2000-05-17 01:44:38 +02:00
1999-12-17 00:11:37 +01:00
if ( n > CUR.maxFunc )
CUR.maxFunc = n;
2000-05-17 01:44:38 +02:00
1999-12-17 00:11:37 +01:00
/* 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: --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_ENDF( INS_ARG )
1999-12-17 00:11:37 +01:00
{
TT_CallRec* pRec;
FT_UNUSED_ARG;
1999-12-17 00:11:37 +01:00
1999-12-17 00:11:37 +01:00
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. */
1999-12-17 00:11:37 +01:00
2007-01-26 23:18:56 +01:00
/* 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! */
1999-12-17 00:11:37 +01:00
}
/*************************************************************************/
/* */
/* CALL[]: CALL function */
/* Opcode range: 0x2B */
/* Stack: uint32? --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_CALL( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_ULong F;
1999-12-17 00:11:37 +01:00
TT_CallRec* pCrec;
TT_DefRecord* def;
1999-12-17 00:11:37 +01:00
/* first of all, check the index */
1999-12-17 00:11:37 +01:00
F = args[0];
if ( BOUNDS( F, CUR.maxFunc + 1 ) )
goto Fail;
2000-05-17 01:44:38 +02:00
1999-12-17 00:11:37 +01:00
/* Except for some old Apple fonts, all functions in a TrueType */
/* font are defined in increasing order, starting from 0. This */
1999-12-17 00:11:37 +01:00
/* 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 )
1999-12-17 00:11:37 +01:00
{
/* look up the FDefs table */
TT_DefRecord* limit;
2000-05-17 01:44:38 +02:00
1999-12-17 00:11:37 +01:00
def = CUR.FDefs;
limit = def + CUR.numFDefs;
2000-05-17 01:44:38 +02:00
while ( def < limit && def->opc != F )
1999-12-17 00:11:37 +01:00
def++;
2000-05-17 01:44:38 +02:00
if ( def == limit )
goto Fail;
1999-12-17 00:11:37 +01:00
}
2000-05-17 01:44:38 +02:00
1999-12-17 00:11:37 +01:00
/* check that the function is active */
if ( !def->active )
1999-12-17 00:11:37 +01:00
goto Fail;
2000-05-17 01:44:38 +02:00
1999-12-17 00:11:37 +01:00
/* 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 );
2000-05-17 01:44:38 +02:00
1999-12-17 00:11:37 +01:00
CUR.step_ins = FALSE;
return;
2000-05-17 01:44:38 +02:00
1999-12-17 00:11:37 +01:00
Fail:
CUR.error = TT_Err_Invalid_Reference;
}
/*************************************************************************/
/* */
/* LOOPCALL[]: LOOP and CALL function */
/* Opcode range: 0x2A */
/* Stack: uint32? Eint16? --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_LOOPCALL( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_ULong F;
1999-12-17 00:11:37 +01:00
TT_CallRec* pCrec;
TT_DefRecord* def;
1999-12-17 00:11:37 +01:00
/* first of all, check the index */
F = args[1];
if ( BOUNDS( F, CUR.maxFunc + 1 ) )
goto Fail;
2000-05-17 01:44:38 +02:00
1999-12-17 00:11:37 +01:00
/* Except for some old Apple fonts, all functions in a TrueType */
/* font are defined in increasing order, starting from 0. This */
1999-12-17 00:11:37 +01:00
/* 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 )
1999-12-17 00:11:37 +01:00
{
/* look up the FDefs table */
TT_DefRecord* limit;
2000-05-17 01:44:38 +02:00
1999-12-17 00:11:37 +01:00
def = CUR.FDefs;
limit = def + CUR.numFDefs;
2000-05-17 01:44:38 +02:00
while ( def < limit && def->opc != F )
1999-12-17 00:11:37 +01:00
def++;
2000-05-17 01:44:38 +02:00
if ( def == limit )
goto Fail;
1999-12-17 00:11:37 +01:00
}
2000-05-17 01:44:38 +02:00
1999-12-17 00:11:37 +01:00
/* check that the function is active */
if ( !def->active )
1999-12-17 00:11:37 +01:00
goto Fail;
2000-05-17 01:44:38 +02:00
/* check stack */
1999-12-17 00:11:37 +01:00
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];
1999-12-17 00:11:37 +01:00
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 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_IDEF( INS_ARG )
1999-12-17 00:11:37 +01:00
{
TT_DefRecord* def;
TT_DefRecord* limit;
1999-12-17 00:11:37 +01:00
/* First of all, look for the same function in our table */
1999-12-17 00:11:37 +01:00
def = CUR.IDefs;
limit = def + CUR.numIDefs;
1999-12-17 00:11:37 +01:00
for ( ; def < limit; def++ )
if ( def->opc == (FT_ULong)args[0] )
1999-12-17 00:11:37 +01:00
break;
2000-05-17 01:44:38 +02:00
1999-12-17 00:11:37 +01:00
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++;
}
2000-05-17 01:44:38 +02:00
1999-12-17 00:11:37 +01:00
def->opc = args[0];
def->start = CUR.IP+1;
def->range = CUR.curRange;
def->active = TRUE;
2000-05-17 01:44:38 +02:00
if ( (FT_ULong)args[0] > CUR.maxIns )
1999-12-17 00:11:37 +01:00
CUR.maxIns = args[0];
2000-05-17 01:44:38 +02:00
1999-12-17 00:11:37 +01:00
/* 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. */
1999-12-17 00:11:37 +01:00
/* */
/*************************************************************************/
/*************************************************************************/
/* */
/* NPUSHB[]: PUSH N Bytes */
/* Opcode range: 0x40 */
/* Stack: --> uint32... */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_NPUSHB( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_UShort L, K;
1999-12-17 00:11:37 +01:00
L = (FT_UShort)CUR.code[CUR.IP + 1];
1999-12-17 00:11:37 +01:00
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... */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_NPUSHW( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_UShort L, K;
1999-12-17 00:11:37 +01:00
L = (FT_UShort)CUR.code[CUR.IP + 1];
1999-12-17 00:11:37 +01:00
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... */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_PUSHB( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_UShort L, K;
1999-12-17 00:11:37 +01:00
L = (FT_UShort)(CUR.opcode - 0xB0 + 1);
1999-12-17 00:11:37 +01:00
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... */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_PUSHW( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_UShort L, K;
1999-12-17 00:11:37 +01:00
L = (FT_UShort)(CUR.opcode - 0xB8 + 1);
1999-12-17 00:11:37 +01:00
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! */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_GC( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_ULong L;
FT_F26Dot6 R;
1999-12-17 00:11:37 +01:00
L = (FT_ULong)args[0];
1999-12-17 00:11:37 +01:00
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] );
1999-12-17 00:11:37 +01:00
else
R = CUR_fast_project( &CUR.zp2.cur[L] );
1999-12-17 00:11:37 +01:00
}
args[0] = R;
}
/*************************************************************************/
/* */
/* SCFS[]: Set Coordinate From Stack */
/* Opcode range: 0x48 */
/* Stack: f26.6 uint32 --> */
/* */
/* Formula: */
/* */
/* OA := OA + ( value - OA.p )/( f.p ) * f */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SCFS( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_Long K;
FT_UShort L;
1999-12-17 00:11:37 +01:00
L = (FT_UShort)args[0];
1999-12-17 00:11:37 +01:00
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] );
1999-12-17 00:11:37 +01:00
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! */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_MD( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_UShort K, L;
FT_F26Dot6 D;
1999-12-17 00:11:37 +01:00
K = (FT_UShort)args[1];
L = (FT_UShort)args[0];
1999-12-17 00:11:37 +01:00
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
{
2006-08-19 13:18:09 +02:00
#ifdef FIX_BYTECODE
2006-08-19 13:18:09 +02:00
FT_Vector vec1;
2006-08-19 13:18:09 +02:00
if ( CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 )
FT_ARRAY_COPY( CUR.twilight.orus,
CUR.twilight.org,
CUR.twilight.n_points );
/* get scaled orus coordinates */
2007-02-16 09:10:17 +01:00
vec1.x = TT_MULFIX( CUR.zp0.orus[L].x - CUR.zp1.orus[K].x,
CUR.metrics.x_scale );
vec1.y = TT_MULFIX( CUR.zp0.orus[L].y - CUR.zp1.orus[L].y,
CUR.metrics.y_scale );
D = CUR_fast_dualproj( &vec1 );
2006-08-19 13:18:09 +02:00
#else
2006-08-19 13:18:09 +02:00
1999-12-17 00:11:37 +01:00
D = CUR_Func_dualproj( CUR.zp0.org + L, CUR.zp1.org + K );
2006-08-19 13:18:09 +02:00
#endif /* FIX_BYTECODE */
}
1999-12-17 00:11:37 +01:00
}
args[0] = D;
}
/*************************************************************************/
/* */
/* SDPVTL[a]: Set Dual PVector to Line */
/* Opcode range: 0x86-0x87 */
/* Stack: uint32 uint32 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SDPVTL( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_Long A, B, C;
FT_UShort p1, p2; /* was FT_Int in pas type ERROR */
1999-12-17 00:11:37 +01:00
p1 = (FT_UShort)args[1];
p2 = (FT_UShort)args[0];
1999-12-17 00:11:37 +01:00
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;
1999-12-17 00:11:37 +01:00
A = v1->x - v2->x;
B = v1->y - v2->y;
}
if ( ( CUR.opcode & 1 ) != 0 )
1999-12-17 00:11:37 +01:00
{
C = B; /* counter clockwise rotation */
1999-12-17 00:11:37 +01:00
B = A;
A = -C;
}
NORMalize( A, B, &CUR.GS.dualVector );
{
FT_Vector* v1 = CUR.zp1.cur + p2;
FT_Vector* v2 = CUR.zp2.cur + p1;
1999-12-17 00:11:37 +01:00
A = v1->x - v2->x;
B = v1->y - v2->y;
}
if ( ( CUR.opcode & 1 ) != 0 )
1999-12-17 00:11:37 +01:00
{
C = B; /* counter clockwise rotation */
1999-12-17 00:11:37 +01:00
B = A;
A = -C;
}
NORMalize( A, B, &CUR.GS.projVector );
GUESS_VECTOR( freeVector );
1999-12-17 00:11:37 +01:00
COMPUTE_Funcs();
}
/*************************************************************************/
/* */
/* SZP0[]: Set Zone Pointer 0 */
/* Opcode range: 0x13 */
/* Stack: uint32 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SZP0( INS_ARG )
1999-12-17 00:11:37 +01:00
{
switch ( (FT_Int)args[0] )
1999-12-17 00:11:37 +01:00
{
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];
1999-12-17 00:11:37 +01:00
}
/*************************************************************************/
/* */
/* SZP1[]: Set Zone Pointer 1 */
/* Opcode range: 0x14 */
/* Stack: uint32 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SZP1( INS_ARG )
1999-12-17 00:11:37 +01:00
{
switch ( (FT_Int)args[0] )
1999-12-17 00:11:37 +01:00
{
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];
1999-12-17 00:11:37 +01:00
}
/*************************************************************************/
/* */
/* SZP2[]: Set Zone Pointer 2 */
/* Opcode range: 0x15 */
/* Stack: uint32 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SZP2( INS_ARG )
1999-12-17 00:11:37 +01:00
{
switch ( (FT_Int)args[0] )
1999-12-17 00:11:37 +01:00
{
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];
1999-12-17 00:11:37 +01:00
}
/*************************************************************************/
/* */
/* SZPS[]: Set Zone PointerS */
/* Opcode range: 0x16 */
/* Stack: uint32 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SZPS( INS_ARG )
1999-12-17 00:11:37 +01:00
{
switch ( (FT_Int)args[0] )
1999-12-17 00:11:37 +01:00
{
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];
1999-12-17 00:11:37 +01:00
}
/*************************************************************************/
/* */
/* INSTCTRL[]: INSTruction ConTRoL */
/* Opcode range: 0x8e */
/* Stack: int32 int32 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_INSTCTRL( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_Long K, L;
1999-12-17 00:11:37 +01:00
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 );
1999-12-17 00:11:37 +01:00
}
/*************************************************************************/
/* */
/* SCANCTRL[]: SCAN ConTRoL */
/* Opcode range: 0x85 */
/* Stack: uint32? --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SCANCTRL( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_Int A;
1999-12-17 00:11:37 +01:00
/* Get Threshold */
A = (FT_Int)( args[0] & 0xFF );
1999-12-17 00:11:37 +01:00
if ( A == 0xFF )
{
CUR.GS.scan_control = TRUE;
return;
}
else if ( A == 0 )
{
CUR.GS.scan_control = FALSE;
return;
}
A *= 64;
#if 0
1999-12-17 00:11:37 +01:00
if ( (args[0] & 0x100) != 0 && CUR.metrics.pointSize <= A )
CUR.GS.scan_control = TRUE;
#endif
1999-12-17 00:11:37 +01:00
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
1999-12-17 00:11:37 +01:00
if ( (args[0] & 0x800) != 0 && CUR.metrics.pointSize > A )
CUR.GS.scan_control = FALSE;
#endif
1999-12-17 00:11:37 +01:00
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;
2001-06-28 09:17:51 +02:00
}
1999-12-17 00:11:37 +01:00
/*************************************************************************/
/* */
/* SCANTYPE[]: SCAN TYPE */
/* Opcode range: 0x8D */
/* Stack: uint32? --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SCANTYPE( INS_ARG )
1999-12-17 00:11:37 +01:00
{
/* for compatibility with future enhancements, */
1999-12-17 00:11:37 +01:00
/* 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];
1999-12-17 00:11:37 +01:00
}
}
/*************************************************************************/
/* */
/* MANAGING OUTLINES */
/* */
/* Instructions appear in the specification's order. */
1999-12-17 00:11:37 +01:00
/* */
/*************************************************************************/
/*************************************************************************/
/* */
/* FLIPPT[]: FLIP PoinT */
/* Opcode range: 0x80 */
/* Stack: uint32... --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_FLIPPT( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_UShort point;
1999-12-17 00:11:37 +01:00
FT_UNUSED_ARG;
1999-12-17 00:11:37 +01:00
1999-12-17 00:11:37 +01:00
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];
1999-12-17 00:11:37 +01:00
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;
1999-12-17 00:11:37 +01:00
CUR.GS.loop--;
}
CUR.GS.loop = 1;
CUR.new_top = CUR.args;
}
/*************************************************************************/
/* */
/* FLIPRGON[]: FLIP RanGe ON */
/* Opcode range: 0x81 */
/* Stack: uint32 uint32 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_FLIPRGON( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_UShort I, K, L;
1999-12-17 00:11:37 +01:00
K = (FT_UShort)args[1];
L = (FT_UShort)args[0];
1999-12-17 00:11:37 +01:00
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;
1999-12-17 00:11:37 +01:00
}
/*************************************************************************/
/* */
/* FLIPRGOFF: FLIP RanGe OFF */
/* Opcode range: 0x82 */
/* Stack: uint32 uint32 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_FLIPRGOFF( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_UShort I, K, L;
1999-12-17 00:11:37 +01:00
K = (FT_UShort)args[1];
L = (FT_UShort)args[0];
1999-12-17 00:11:37 +01:00
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;
1999-12-17 00:11:37 +01:00
}
2001-06-28 09:17:51 +02:00
static FT_Bool
Compute_Point_Displacement( EXEC_OP_ FT_F26Dot6* x,
FT_F26Dot6* y,
TT_GlyphZone zone,
FT_UShort* refp )
1999-12-17 00:11:37 +01:00
{
TT_GlyphZoneRec zp;
FT_UShort p;
FT_F26Dot6 d;
1999-12-17 00:11:37 +01:00
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;
1999-12-17 00:11:37 +01:00
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 );
}
1999-12-17 00:11:37 +01:00
return SUCCESS;
}
2001-06-28 09:17:51 +02:00
static void
Move_Zp2_Point( EXEC_OP_ FT_UShort point,
FT_F26Dot6 dx,
FT_F26Dot6 dy,
FT_Bool touch )
1999-12-17 00:11:37 +01:00
{
#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2003-04-29 15:23:47 +02:00
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
1999-12-17 00:11:37 +01:00
if ( CUR.GS.freeVector.x != 0 )
{
CUR.zp2.cur[point].x += dx;
if ( touch )
CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X;
1999-12-17 00:11:37 +01:00
}
if ( CUR.GS.freeVector.y != 0 )
{
CUR.zp2.cur[point].y += dy;
if ( touch )
CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y;
1999-12-17 00:11:37 +01:00
}
}
/*************************************************************************/
/* */
/* SHP[a]: SHift Point by the last point */
/* Opcode range: 0x32-0x33 */
/* Stack: uint32... --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SHP( INS_ARG )
1999-12-17 00:11:37 +01:00
{
TT_GlyphZoneRec zp;
FT_UShort refp;
1999-12-17 00:11:37 +01:00
FT_F26Dot6 dx,
dy;
FT_UShort point;
1999-12-17 00:11:37 +01:00
FT_UNUSED_ARG;
1999-12-17 00:11:37 +01:00
1999-12-17 00:11:37 +01:00
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];
1999-12-17 00:11:37 +01:00
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 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SHC( INS_ARG )
1999-12-17 00:11:37 +01:00
{
TT_GlyphZoneRec zp;
FT_UShort refp;
FT_F26Dot6 dx,
dy;
1999-12-17 00:11:37 +01:00
FT_Short contour;
FT_UShort first_point, last_point, i;
1999-12-17 00:11:37 +01:00
contour = (FT_UShort)args[0];
1999-12-17 00:11:37 +01:00
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 );
1999-12-17 00:11:37 +01:00
last_point = (FT_UShort)( CUR.pts.contours[contour] -
CUR.pts.first_point );
1999-12-17 00:11:37 +01:00
/* 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);
1999-12-17 00:11:37 +01:00
else
last_point = 0;
}
/* XXX: UNDOCUMENTED! SHC touches the points */
1999-12-17 00:11:37 +01:00
for ( i = first_point; i <= last_point; i++ )
{
if ( zp.cur != CUR.zp2.cur || refp != i )
MOVE_Zp2_Point( i, dx, dy, TRUE );
1999-12-17 00:11:37 +01:00
}
}
/*************************************************************************/
/* */
/* SHZ[a]: SHift Zone */
/* Opcode range: 0x36-37 */
/* Stack: uint32 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SHZ( INS_ARG )
1999-12-17 00:11:37 +01:00
{
TT_GlyphZoneRec zp;
FT_UShort refp;
FT_F26Dot6 dx,
dy;
1999-12-17 00:11:37 +01:00
FT_UShort last_point, i;
1999-12-17 00:11:37 +01:00
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] );
1999-12-17 00:11:37 +01:00
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... --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_SHPIX( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_F26Dot6 dx, dy;
FT_UShort point;
1999-12-17 00:11:37 +01:00
if ( CUR.top < CUR.GS.loop + 1 )
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2003-04-29 15:23:47 +02:00
if ( CUR.face->unpatented_hinting )
{
if ( CUR.GS.both_x_axis )
{
dx = TT_MulFix14( args[0], 0x4000 );
2003-04-29 15:23:47 +02:00
dy = 0;
}
else
{
2003-04-29 15:23:47 +02:00
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 );
}
1999-12-17 00:11:37 +01:00
while ( CUR.GS.loop > 0 )
{
CUR.args--;
point = (FT_UShort)CUR.stack[CUR.args];
1999-12-17 00:11:37 +01:00
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 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_MSIRP( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_UShort point;
FT_F26Dot6 distance;
1999-12-17 00:11:37 +01:00
point = (FT_UShort)args[0];
1999-12-17 00:11:37 +01:00
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 */
1999-12-17 00:11:37 +01:00
{
CUR.zp1.org[point] = CUR.zp0.org[CUR.GS.rp0];
CUR_Func_move_orig( &CUR.zp1, point, args[1] );
1999-12-17 00:11:37 +01:00
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 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_MDAP( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_UShort point;
FT_F26Dot6 cur_dist,
1999-12-17 00:11:37 +01:00
distance;
point = (FT_UShort)args[0];
1999-12-17 00:11:37 +01:00
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 )
1999-12-17 00:11:37 +01:00
{
cur_dist = CUR_fast_project( &CUR.zp0.cur[point] );
1999-12-17 00:11:37 +01:00
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 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_MIAP( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_ULong cvtEntry;
FT_UShort point;
FT_F26Dot6 distance,
1999-12-17 00:11:37 +01:00
org_dist;
cvtEntry = (FT_ULong)args[1];
point = (FT_UShort)args[0];
1999-12-17 00:11:37 +01:00
if ( BOUNDS( point, CUR.zp0.n_points ) ||
BOUNDS( cvtEntry, CUR.cvtSize ) )
{
if ( CUR.pedantic_hinting )
CUR.error = TT_Err_Invalid_Reference;
return;
}
/* UNDOCUMENTED! */
/* */
/* The behaviour of an MIAP instruction is quite */
/* different when used in the twilight zone. */
/* */
2007-02-12 23:01:18 +01:00
/* First, no control value cut-in test is performed */
1999-12-17 00:11:37 +01:00
/* 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. */
1999-12-17 00:11:37 +01:00
/* */
/* 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 */
{
2002-03-25 18:02:26 +01:00
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];
1999-12-17 00:11:37 +01:00
}
org_dist = CUR_fast_project( &CUR.zp0.cur[point] );
1999-12-17 00:11:37 +01:00
if ( ( CUR.opcode & 1 ) != 0 ) /* rounding and control cutin flag */
1999-12-17 00:11:37 +01:00
{
if ( FT_ABS( distance - org_dist ) > CUR.GS.control_value_cutin )
1999-12-17 00:11:37 +01:00
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 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_MDRP( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_UShort point;
FT_F26Dot6 org_dist, distance;
1999-12-17 00:11:37 +01:00
point = (FT_UShort)args[0];
1999-12-17 00:11:37 +01:00
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? */
#ifdef FIX_BYTECODE
2006-08-19 13:18:09 +02:00
{
FT_Vector* vec1 = &CUR.zp1.orus[point];
FT_Vector* vec2 = &CUR.zp0.orus[CUR.GS.rp0];
2006-08-19 13:18:09 +02:00
if ( CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 )
FT_ARRAY_COPY( CUR.twilight.orus,
CUR.twilight.org,
CUR.twilight.n_points );
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 );
}
}
2006-08-19 13:18:09 +02:00
#else
2006-08-19 13:18:09 +02:00
1999-12-17 00:11:37 +01:00
org_dist = CUR_Func_dualproj( CUR.zp1.org + point,
CUR.zp0.org + CUR.GS.rp0 );
2006-08-19 13:18:09 +02:00
#endif /* FIX_BYTECODE */
/* single width cut-in test */
1999-12-17 00:11:37 +01:00
if ( FT_ABS( org_dist - CUR.GS.single_width_value ) <
CUR.GS.single_width_cutin )
1999-12-17 00:11:37 +01:00
{
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] );
1999-12-17 00:11:37 +01:00
else
distance = ROUND_None(
org_dist,
CUR.tt_metrics.compensations[CUR.opcode & 3] );
1999-12-17 00:11:37 +01:00
/* minimum distance flag */
if ( ( CUR.opcode & 8 ) != 0 )
1999-12-17 00:11:37 +01:00
{
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 )
1999-12-17 00:11:37 +01:00
CUR.GS.rp0 = point;
}
/*************************************************************************/
/* */
/* MIRP[abcde]: Move Indirect Relative Point */
/* Opcode range: 0xE0-0xFF */
/* Stack: int32? uint32 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_MIRP( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_UShort point;
FT_ULong cvtEntry;
1999-12-17 00:11:37 +01:00
FT_F26Dot6 cvt_dist,
1999-12-17 00:11:37 +01:00
distance,
cur_dist,
org_dist;
point = (FT_UShort)args[0];
cvtEntry = (FT_ULong)( args[1] + 1 );
1999-12-17 00:11:37 +01:00
/* 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 )
1999-12-17 00:11:37 +01:00
{
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 +
2002-03-25 18:02:26 +01:00
TT_MulFix14( cvt_dist, CUR.GS.freeVector.x );
1999-12-17 00:11:37 +01:00
CUR.zp1.org[point].y = CUR.zp0.org[CUR.GS.rp0].y +
2002-03-25 18:02:26 +01:00
TT_MulFix14( cvt_dist, CUR.GS.freeVector.y );
1999-12-17 00:11:37 +01:00
CUR.zp1.cur[point] = CUR.zp0.cur[point];
1999-12-17 00:11:37 +01:00
}
2007-02-16 09:10:17 +01:00
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] );
1999-12-17 00:11:37 +01:00
/* auto-flip test */
if ( CUR.GS.auto_flip )
{
if ( ( org_dist ^ cvt_dist ) < 0 )
1999-12-17 00:11:37 +01:00
cvt_dist = -cvt_dist;
}
/* control value cutin and round */
if ( ( CUR.opcode & 4 ) != 0 )
1999-12-17 00:11:37 +01:00
{
/* 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 )
1999-12-17 00:11:37 +01:00
cvt_dist = org_dist;
distance = CUR_Func_round(
cvt_dist,
CUR.tt_metrics.compensations[CUR.opcode & 3] );
1999-12-17 00:11:37 +01:00
}
else
distance = ROUND_None(
cvt_dist,
CUR.tt_metrics.compensations[CUR.opcode & 3] );
1999-12-17 00:11:37 +01:00
/* minimum distance test */
if ( ( CUR.opcode & 8 ) != 0 )
1999-12-17 00:11:37 +01:00
{
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 )
1999-12-17 00:11:37 +01:00
CUR.GS.rp0 = point;
/* XXX: UNDOCUMENTED! */
CUR.GS.rp2 = point;
}
/*************************************************************************/
/* */
/* ALIGNRP[]: ALIGN Relative Point */
/* Opcode range: 0x3C */
/* Stack: uint32 uint32... --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_ALIGNRP( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_UShort point;
FT_F26Dot6 distance;
1999-12-17 00:11:37 +01:00
FT_UNUSED_ARG;
1999-12-17 00:11:37 +01:00
1999-12-17 00:11:37 +01:00
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];
1999-12-17 00:11:37 +01:00
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 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_ISECT( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_UShort point,
1999-12-17 00:11:37 +01:00
a0, a1,
b0, b1;
FT_F26Dot6 discriminant;
1999-12-17 00:11:37 +01:00
FT_F26Dot6 dx, dy,
1999-12-17 00:11:37 +01:00
dax, day,
dbx, dby;
FT_F26Dot6 val;
1999-12-17 00:11:37 +01:00
FT_Vector R;
1999-12-17 00:11:37 +01:00
point = (FT_UShort)args[0];
1999-12-17 00:11:37 +01:00
a0 = (FT_UShort)args[1];
a1 = (FT_UShort)args[2];
b0 = (FT_UShort)args[3];
b1 = (FT_UShort)args[4];
1999-12-17 00:11:37 +01:00
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;
1999-12-17 00:11:37 +01:00
discriminant = TT_MULDIV( dax, -dby, 0x40 ) +
TT_MULDIV( day, dbx, 0x40 );
if ( FT_ABS( discriminant ) >= 0x40 )
1999-12-17 00:11:37 +01:00
{
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 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_ALIGNPTS( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_UShort p1, p2;
FT_F26Dot6 distance;
1999-12-17 00:11:37 +01:00
p1 = (FT_UShort)args[0];
p2 = (FT_UShort)args[1];
1999-12-17 00:11:37 +01:00
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 */
2007-02-16 09:10:17 +01:00
#ifdef FIX_BYTECODE
2007-02-16 09:10:17 +01:00
2001-06-28 09:17:51 +02:00
static void
Ins_IP( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_F26Dot6 old_range, cur_range;
FT_Vector* orus_base;
FT_Vector* cur_base;
FT_Int twilight;
1999-12-17 00:11:37 +01:00
FT_UNUSED_ARG;
1999-12-17 00:11:37 +01:00
1999-12-17 00:11:37 +01:00
if ( CUR.top < CUR.GS.loop )
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
2007-02-16 09:10:17 +01:00
/*
* We need to deal in a special way with the twilight zone.
2007-02-16 09:10:17 +01:00
* Otherwise, by definition, the value of CUR.twilight.orus[n] is (0,0),
* for every n.
2007-02-16 09:10:17 +01:00
*/
twilight = ( CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 || CUR.GS.gep2 == 0 );
if (twilight)
orus_base = &CUR.zp0.org[CUR.GS.rp1];
else
orus_base = &CUR.zp0.orus[CUR.GS.rp1];
2006-08-19 13:18:09 +02:00
cur_base = &CUR.zp0.cur[CUR.GS.rp1];
/* XXX: There are some glyphs in some braindead but popular */
1999-12-17 00:11:37 +01:00
/* 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;
1999-12-17 00:11:37 +01:00
}
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 )
{
2007-02-16 09:10:17 +01:00
FT_UInt point = (FT_UInt)CUR.stack[--CUR.args];
FT_F26Dot6 org_dist, cur_dist, new_dist;
2006-08-19 13:18:09 +02:00
2007-02-16 09:10:17 +01:00
/* check point bounds */
if ( BOUNDS( point, CUR.zp2.n_points ) )
{
if ( CUR.pedantic_hinting )
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
continue;
}
2006-08-19 13:18:09 +02:00
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 );
2007-02-16 09:10:17 +01:00
new_dist = (old_range != 0)
? TT_MULDIV( org_dist, cur_range, old_range )
: cur_dist;
CUR_Func_move( &CUR.zp2, point, new_dist - cur_dist );
}
CUR.GS.loop = 1;
CUR.new_top = CUR.args;
}
2007-02-16 09:10:17 +01:00
#else /* !FIX_BYTECODE */
static void
Ins_IP( INS_ARG )
{
FT_F26Dot6 org_a, org_b, org_x,
cur_a, cur_b, cur_x,
distance = 0;
FT_UShort point;
2006-08-19 13:18:09 +02:00
FT_UNUSED_ARG;
2006-08-19 13:18:09 +02:00
if ( CUR.top < CUR.GS.loop )
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
/* XXX: There are some glyphs in some braindead but popular */
/* fonts out there (e.g. [aeu]grave in monotype.ttf) */
/* calling IP[] with bad values of rp[12]. */
/* Do something sane when this odd thing happens. */
2006-08-19 13:18:09 +02:00
if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) ||
BOUNDS( CUR.GS.rp2, CUR.zp1.n_points ) )
{
org_a = cur_a = 0;
org_b = cur_b = 0;
}
else
{
org_a = CUR_fast_dualproj( &CUR.zp0.org[CUR.GS.rp1] );
org_b = CUR_fast_dualproj( &CUR.zp1.org[CUR.GS.rp2] );
2006-08-19 13:18:09 +02:00
cur_a = CUR_fast_project( &CUR.zp0.cur[CUR.GS.rp1] );
cur_b = CUR_fast_project( &CUR.zp1.cur[CUR.GS.rp2] );
1999-12-17 00:11:37 +01:00
}
while ( CUR.GS.loop > 0 )
{
CUR.args--;
point = (FT_UShort)CUR.stack[CUR.args];
1999-12-17 00:11:37 +01:00
if ( BOUNDS( point, CUR.zp2.n_points ) )
{
if ( CUR.pedantic_hinting )
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
}
else
{
org_x = CUR_fast_dualproj( &CUR.zp2.org[point] );
cur_x = CUR_fast_project ( &CUR.zp2.cur[point] );
1999-12-17 00:11:37 +01:00
if ( ( org_a <= org_b && org_x <= org_a ) ||
( org_a > org_b && org_x >= org_a ) )
distance = ( cur_a - org_a ) + ( org_x - cur_x );
else if ( ( org_a <= org_b && org_x >= org_b ) ||
( org_a > org_b && org_x < org_b ) )
distance = ( cur_b - org_b ) + ( org_x - cur_x );
else if ( org_b != org_a )
1999-12-17 00:11:37 +01:00
/* note: it seems that rounding this value isn't a good */
/* idea (cf. width of capital `S' in Times) */
distance = TT_MULDIV( cur_b - cur_a,
org_x - org_a,
org_b - org_a ) + ( cur_a - cur_x );
CUR_Func_move( &CUR.zp2, point, distance );
}
CUR.GS.loop--;
}
CUR.GS.loop = 1;
CUR.new_top = CUR.args;
}
2007-02-16 09:10:17 +01:00
#endif /* !FIX_BYTECODE */
1999-12-17 00:11:37 +01:00
/*************************************************************************/
/* */
/* UTP[a]: UnTouch Point */
/* Opcode range: 0x29 */
/* Stack: uint32 --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_UTP( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_UShort point;
FT_Byte mask;
1999-12-17 00:11:37 +01:00
point = (FT_UShort)args[0];
1999-12-17 00:11:37 +01:00
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;
1999-12-17 00:11:37 +01:00
if ( CUR.GS.freeVector.y != 0 )
mask &= ~FT_CURVE_TAG_TOUCH_Y;
1999-12-17 00:11:37 +01:00
CUR.zp0.tags[point] &= mask;
1999-12-17 00:11:37 +01:00
}
/* Local variables for Ins_IUP: */
typedef struct
1999-12-17 00:11:37 +01:00
{
FT_Vector* orgs; /* original and current coordinate */
FT_Vector* curs; /* arrays */
FT_Vector* orus;
} IUP_WorkerRec, *IUP_Worker;
1999-12-17 00:11:37 +01:00
2001-06-28 09:17:51 +02:00
static void
_iup_worker_shift( IUP_Worker worker,
FT_UInt p1,
FT_UInt p2,
FT_UInt p )
1999-12-17 00:11:37 +01:00
{
FT_UInt i;
FT_F26Dot6 dx;
1999-12-17 00:11:37 +01:00
dx = worker->curs[p].x - worker->orgs[p].x;
if ( dx != 0 )
{
for ( i = p1; i < p; i++ )
worker->curs[i].x += dx;
1999-12-17 00:11:37 +01:00
for ( i = p + 1; i <= p2; i++ )
worker->curs[i].x += dx;
}
1999-12-17 00:11:37 +01:00
}
2001-06-28 09:17:51 +02:00
static void
_iup_worker_interpolate( IUP_Worker worker,
FT_UInt p1,
FT_UInt p2,
FT_UInt ref1,
FT_UInt ref2 )
1999-12-17 00:11:37 +01:00
{
FT_UInt i;
FT_F26Dot6 orus1, orus2, org1, org2, delta1, delta2;
1999-12-17 00:11:37 +01:00
1999-12-17 00:11:37 +01:00
if ( p1 > p2 )
return;
orus1 = worker->orus[ref1].x;
orus2 = worker->orus[ref2].x;
1999-12-17 00:11:37 +01:00
2006-08-19 13:18:09 +02:00
if ( orus1 > orus2 )
1999-12-17 00:11:37 +01:00
{
FT_F26Dot6 tmp_o;
FT_UInt tmp_r;
2006-08-19 13:18:09 +02:00
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 */
1999-12-17 00:11:37 +01:00
for ( i = p1; i <= p2; i++ )
{
FT_F26Dot6 x = worker->orgs[i].x;
1999-12-17 00:11:37 +01:00
2006-08-19 13:18:09 +02:00
if ( x <= org1 )
x += delta1;
1999-12-17 00:11:37 +01:00
else
x += delta2;
1999-12-17 00:11:37 +01:00
worker->curs[i].x = x;
1999-12-17 00:11:37 +01:00
}
}
else
1999-12-17 00:11:37 +01:00
{
FT_Fixed scale = 0;
FT_Bool scale_valid = 0;
2006-08-19 13:18:09 +02:00
/* interpolation */
1999-12-17 00:11:37 +01:00
for ( i = p1; i <= p2; i++ )
{
FT_F26Dot6 x = worker->orgs[i].x;
1999-12-17 00:11:37 +01:00
2006-08-19 13:18:09 +02:00
if ( x <= org1 )
x += delta1;
1999-12-17 00:11:37 +01:00
else if ( x >= org2 )
x += delta2;
1999-12-17 00:11:37 +01:00
else
{
if ( !scale_valid )
{
scale_valid = 1;
2006-08-19 13:18:09 +02:00
scale = TT_MULDIV( org2 + delta2 - ( org1 + delta1 ),
0x10000, orus2 - orus1 );
}
2006-08-19 13:18:09 +02:00
x = ( org1 + delta1 ) +
TT_MULFIX( worker->orus[i].x - orus1, scale );
}
worker->curs[i].x = x;
1999-12-17 00:11:37 +01:00
}
}
}
/*************************************************************************/
/* */
/* IUP[a]: Interpolate Untouched Points */
/* Opcode range: 0x30-0x31 */
/* Stack: --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_IUP( INS_ARG )
1999-12-17 00:11:37 +01:00
{
IUP_WorkerRec V;
FT_Byte mask;
1999-12-17 00:11:37 +01:00
FT_UInt first_point; /* first point of contour */
FT_UInt end_point; /* end point (last+1) of contour */
1999-12-17 00:11:37 +01:00
FT_UInt first_touched; /* first touched point in contour */
FT_UInt cur_touched; /* current touched point in contour */
1999-12-17 00:11:37 +01:00
FT_UInt point; /* current point */
FT_Short contour; /* current contour */
1999-12-17 00:11:37 +01:00
FT_UNUSED_ARG;
1999-12-17 00:11:37 +01:00
1999-12-17 00:11:37 +01:00
if ( CUR.opcode & 1 )
{
mask = FT_CURVE_TAG_TOUCH_X;
1999-12-17 00:11:37 +01:00
V.orgs = CUR.pts.org;
V.curs = CUR.pts.cur;
V.orus = CUR.pts.orus;
1999-12-17 00:11:37 +01:00
}
else
{
mask = FT_CURVE_TAG_TOUCH_Y;
2000-07-05 20:23:38 +02:00
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 );
1999-12-17 00:11:37 +01:00
}
contour = 0;
point = 0;
do
{
end_point = CUR.pts.contours[contour] - CUR.pts.first_point;
1999-12-17 00:11:37 +01:00
first_point = point;
while ( point <= end_point && (CUR.pts.tags[point] & mask) == 0 )
1999-12-17 00:11:37 +01:00
point++;
if ( point <= end_point )
{
first_touched = point;
cur_touched = point;
point++;
while ( point <= end_point )
{
if ( ( CUR.pts.tags[point] & mask ) != 0 )
1999-12-17 00:11:37 +01:00
{
if ( point > 0 )
_iup_worker_interpolate( &V,
cur_touched + 1,
point - 1,
cur_touched,
point );
1999-12-17 00:11:37 +01:00
cur_touched = point;
}
point++;
}
if ( cur_touched == first_touched )
_iup_worker_shift( &V, first_point, end_point, cur_touched );
1999-12-17 00:11:37 +01:00
else
{
_iup_worker_interpolate( &V,
(FT_UShort)( cur_touched + 1 ),
end_point,
cur_touched,
first_touched );
1999-12-17 00:11:37 +01:00
if ( first_touched > 0 )
_iup_worker_interpolate( &V,
first_point,
first_touched - 1,
cur_touched,
first_touched );
1999-12-17 00:11:37 +01:00
}
}
contour++;
} while ( contour < CUR.pts.n_contours );
}
/*************************************************************************/
/* */
/* DELTAPn[]: DELTA exceptions P1, P2, P3 */
/* Opcode range: 0x5D,0x71,0x72 */
/* Stack: uint32 (2 * uint32)... --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_DELTAP( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_ULong k, nump;
FT_UShort A;
FT_ULong C;
FT_Long B;
1999-12-17 00:11:37 +01:00
2006-11-20 10:19:26 +01:00
#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
/* Delta hinting is covered by US Patent 5159668. */
if ( CUR.face->unpatented_hinting )
2006-11-20 10:19:26 +01:00
{
FT_Long n = args[0] * 2;
if ( CUR.args < n )
{
CUR.error = TT_Err_Too_Few_Arguments;
return;
}
2003-04-29 15:23:47 +02:00
CUR.args -= n;
CUR.new_top = CUR.args;
return;
}
#endif
1999-12-17 00:11:37 +01:00
nump = (FT_ULong)args[0]; /* some points theoretically may occur more
1999-12-17 00:11:37 +01:00
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];
1999-12-17 00:11:37 +01:00
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. */
1999-12-17 00:11:37 +01:00
if ( !BOUNDS( A, CUR.zp0.n_points ) )
{
C = ( (FT_ULong)B & 0xF0 ) >> 4;
1999-12-17 00:11:37 +01:00
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 )
1999-12-17 00:11:37 +01:00
{
B = ( (FT_ULong)B & 0xF ) - 8;
1999-12-17 00:11:37 +01:00
if ( B >= 0 )
B++;
B = B * 64 / ( 1L << CUR.GS.delta_shift );
1999-12-17 00:11:37 +01:00
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)... --> */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_DELTAC( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_ULong nump, k;
FT_ULong A, C;
FT_Long B;
1999-12-17 00:11:37 +01:00
2003-04-29 15:23:47 +02:00
#ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
/* Delta hinting is covered by US Patent 5159668. */
if ( CUR.face->unpatented_hinting )
2003-04-29 15:23:47 +02:00
{
FT_Long n = args[0] * 2;
if ( CUR.args < n )
{
CUR.error = TT_Err_Too_Few_Arguments;
return;
}
2003-04-29 15:23:47 +02:00
CUR.args -= n;
CUR.new_top = CUR.args;
return;
}
#endif
1999-12-17 00:11:37 +01:00
nump = (FT_ULong)args[0];
1999-12-17 00:11:37 +01:00
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];
1999-12-17 00:11:37 +01:00
B = CUR.stack[CUR.args];
if ( BOUNDS( A, CUR.cvtSize ) )
{
if ( CUR.pedantic_hinting )
1999-12-17 00:11:37 +01:00
{
CUR.error = TT_Err_Invalid_Reference;
return;
}
}
else
{
C = ( (FT_ULong)B & 0xF0 ) >> 4;
1999-12-17 00:11:37 +01:00
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 )
1999-12-17 00:11:37 +01:00
{
B = ( (FT_ULong)B & 0xF ) - 8;
1999-12-17 00:11:37 +01:00
if ( B >= 0 )
B++;
B = B * 64 / ( 1L << CUR.GS.delta_shift );
1999-12-17 00:11:37 +01:00
CUR_Func_move_cvt( A, B );
}
}
}
CUR.new_top = CUR.args;
}
/*************************************************************************/
/* */
/* MISC. INSTRUCTIONS */
/* */
/*************************************************************************/
/*************************************************************************/
/* */
/* GETINFO[]: GET INFOrmation */
/* Opcode range: 0x88 */
/* Stack: uint32 --> uint32 */
/* */
2001-06-28 09:17:51 +02:00
static void
Ins_GETINFO( INS_ARG )
1999-12-17 00:11:37 +01:00
{
FT_Long K;
1999-12-17 00:11:37 +01:00
K = 0;
/* We return MS rasterizer version 1.7 for the font scaler. */
if ( ( args[0] & 1 ) != 0 )
K = 35;
1999-12-17 00:11:37 +01:00
/* Has the glyph been rotated? */
if ( ( args[0] & 2 ) != 0 && CUR.tt_metrics.rotated )
1999-12-17 00:11:37 +01:00
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 )
2006-11-22 10:37:03 +01:00
K |= 1 << 12;
1999-12-17 00:11:37 +01:00
args[0] = K;
}
2001-06-28 09:17:51 +02:00
static void
Ins_UNKNOWN( INS_ARG )
1999-12-17 00:11:37 +01:00
{
TT_DefRecord* def = CUR.IDefs;
TT_DefRecord* limit = def + CUR.numIDefs;
2000-05-17 01:44:38 +02:00
FT_UNUSED_ARG;
2000-05-17 01:44:38 +02:00
1999-12-17 00:11:37 +01:00
for ( ; def < limit; def++ )
{
if ( (FT_Byte)def->opc == CUR.opcode && def->active )
1999-12-17 00:11:37 +01:00
{
TT_CallRec* call;
2000-05-17 01:44:38 +02:00
1999-12-17 00:11:37 +01:00
if ( CUR.callTop >= CUR.callSize )
{
CUR.error = TT_Err_Stack_Overflow;
return;
}
2000-05-17 01:44:38 +02:00
1999-12-17 00:11:37 +01:00
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;
2000-05-17 01:44:38 +02:00
1999-12-17 00:11:37 +01:00
INS_Goto_CodeRange( def->range, def->start );
2000-05-17 01:44:38 +02:00
1999-12-17 00:11:37 +01:00
CUR.step_ins = FALSE;
return;
}
}
CUR.error = TT_Err_Invalid_Opcode;
}
#ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
1999-12-17 00:11:37 +01:00
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
};
1999-12-17 00:11:37 +01:00
#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). */
/* */
2007-01-26 23:18:56 +01:00
/* On exit with TRUE, test IP < CodeSize to know whether it comes from */
1999-12-17 00:11:37 +01:00
/* 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 */
1999-12-17 00:11:37 +01:00
/* error. */
/* */
/* */
/* THIS IS THE INTERPRETER'S MAIN LOOP. */
/* */
/* Instructions appear in the specification's order. */
1999-12-17 00:11:37 +01:00
/* */
/*************************************************************************/
/* documentation is in ttinterp.h */
2001-06-28 09:17:51 +02:00
FT_EXPORT_DEF( FT_Error )
TT_RunIns( TT_ExecContext exc )
1999-12-17 00:11:37 +01:00
{
FT_Long ins_counter = 0; /* executed instructions counter */
1999-12-17 00:11:37 +01:00
#ifdef TT_CONFIG_OPTION_STATIC_RASTER
1999-12-17 00:11:37 +01:00
cur = *exc;
#endif
1999-12-17 00:11:37 +01:00
/* 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 );
1999-12-17 00:11:37 +01:00
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];
1999-12-17 00:11:37 +01:00
}
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 );
1999-12-17 00:11:37 +01:00
/* `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 );
1999-12-17 00:11:37 +01:00
/* `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
1999-12-17 00:11:37 +01:00
{
FT_Long* args = CUR.stack + CUR.args;
FT_Byte opcode = CUR.opcode;
1999-12-17 00:11:37 +01:00
#undef ARRAY_BOUND_ERROR
#define ARRAY_BOUND_ERROR goto Set_Invalid_Ref
1999-12-17 00:11:37 +01:00
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;
1999-12-17 00:11:37 +01:00
2001-07-08 01:24:02 +02:00
AA = (FT_Short)( ( opcode & 1 ) << 14 );
BB = (FT_Short)( AA ^ 0x4000 );
1999-12-17 00:11:37 +01:00
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 );
}
1999-12-17 00:11:37 +01:00
if ( ( opcode & 2 ) == 0 )
1999-12-17 00:11:37 +01:00
{
CUR.GS.freeVector.x = AA;
CUR.GS.freeVector.y = BB;
}
else
{
GUESS_VECTOR( freeVector );
}
1999-12-17 00:11:37 +01:00
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 );
1999-12-17 00:11:37 +01:00
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 );
1999-12-17 00:11:37 +01:00
break;
case 0x14: /* SZP1 */
Ins_SZP1( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
case 0x15: /* SZP2 */
Ins_SZP2( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
case 0x16: /* SZPS */
Ins_SZPS( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
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 );
1999-12-17 00:11:37 +01:00
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 :-) */
1999-12-17 00:11:37 +01:00
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 );
1999-12-17 00:11:37 +01:00
break;
case 0x27: /* ALIGNPTS */
Ins_ALIGNPTS( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
case 0x28: /* ???? */
Ins_UNKNOWN( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
case 0x29: /* UTP */
Ins_UTP( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
case 0x2A: /* LOOPCALL */
Ins_LOOPCALL( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
case 0x2B: /* CALL */
Ins_CALL( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
case 0x2C: /* FDEF */
Ins_FDEF( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
case 0x2D: /* ENDF */
Ins_ENDF( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
case 0x2E: /* MDAP */
case 0x2F: /* MDAP */
Ins_MDAP( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
case 0x30: /* IUP */
case 0x31: /* IUP */
Ins_IUP( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
case 0x32: /* SHP */
case 0x33: /* SHP */
Ins_SHP( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
case 0x34: /* SHC */
case 0x35: /* SHC */
Ins_SHC( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
case 0x36: /* SHZ */
case 0x37: /* SHZ */
Ins_SHZ( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
case 0x38: /* SHPIX */
Ins_SHPIX( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
case 0x39: /* IP */
Ins_IP( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
case 0x3A: /* MSIRP */
case 0x3B: /* MSIRP */
Ins_MSIRP( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
case 0x3C: /* AlignRP */
Ins_ALIGNRP( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
case 0x3D: /* RTDG */
DO_RTDG
break;
case 0x3E: /* MIAP */
case 0x3F: /* MIAP */
Ins_MIAP( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
case 0x40: /* NPUSHB */
Ins_NPUSHB( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
case 0x41: /* NPUSHW */
Ins_NPUSHW( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
case 0x42: /* WS */
DO_WS
break;
Set_Invalid_Ref:
1999-12-17 00:11:37 +01:00
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 );
1999-12-17 00:11:37 +01:00
break;
case 0x48: /* SCFS */
Ins_SCFS( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
case 0x49: /* MD */
case 0x4A: /* MD */
Ins_MD( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
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 );
1999-12-17 00:11:37 +01:00
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 );
1999-12-17 00:11:37 +01:00
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 );
1999-12-17 00:11:37 +01:00
break;
case 0x73: /* DELTAC0 */
case 0x74: /* DELTAC1 */
case 0x75: /* DELTAC2 */
Ins_DELTAC( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
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 );
1999-12-17 00:11:37 +01:00
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 );
1999-12-17 00:11:37 +01:00
break;
case 0x81: /* FLIPRGON */
Ins_FLIPRGON( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
case 0x82: /* FLIPRGOFF */
Ins_FLIPRGOFF( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
case 0x83: /* UNKNOWN */
case 0x84: /* UNKNOWN */
Ins_UNKNOWN( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
case 0x85: /* SCANCTRL */
Ins_SCANCTRL( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
case 0x86: /* SDPVTL */
case 0x87: /* SDPVTL */
Ins_SDPVTL( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
case 0x88: /* GETINFO */
Ins_GETINFO( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
case 0x89: /* IDEF */
Ins_IDEF( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
case 0x8A: /* ROLL */
Ins_ROLL( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
case 0x8B: /* MAX */
DO_MAX
break;
case 0x8C: /* MIN */
DO_MIN
break;
case 0x8D: /* SCANTYPE */
Ins_SCANTYPE( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
case 0x8E: /* INSTCTRL */
Ins_INSTCTRL( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
case 0x8F:
Ins_UNKNOWN( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
break;
default:
if ( opcode >= 0xE0 )
Ins_MIRP( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
else if ( opcode >= 0xC0 )
Ins_MDRP( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
else if ( opcode >= 0xB8 )
Ins_PUSHW( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
else if ( opcode >= 0xB0 )
Ins_PUSHB( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
else
Ins_UNKNOWN( EXEC_ARG_ args );
1999-12-17 00:11:37 +01:00
}
}
1999-12-17 00:11:37 +01:00
#else
1999-12-17 00:11:37 +01:00
Instruct_Dispatch[CUR.opcode]( EXEC_ARG_ &CUR.stack[CUR.args] );
#endif /* TT_CONFIG_OPTION_INTERPRETER_SWITCH */
if ( CUR.error != TT_Err_Ok )
1999-12-17 00:11:37 +01:00
{
switch ( CUR.error )
{
case TT_Err_Invalid_Opcode: /* looking for redefined instructions */
{
TT_DefRecord* def = CUR.IDefs;
TT_DefRecord* limit = def + CUR.numIDefs;
2000-05-17 01:44:38 +02:00
1999-12-17 00:11:37 +01:00
for ( ; def < limit; def++ )
{
if ( def->active && CUR.opcode == (FT_Byte)def->opc )
1999-12-17 00:11:37 +01:00
{
TT_CallRec* callrec;
2000-05-17 01:44:38 +02:00
1999-12-17 00:11:37 +01:00
if ( CUR.callTop >= CUR.callSize )
{
CUR.error = TT_Err_Invalid_Reference;
goto LErrorLabel_;
}
2000-05-17 01:44:38 +02:00
1999-12-17 00:11:37 +01:00
callrec = &CUR.callStack[CUR.callTop];
2000-05-17 01:44:38 +02:00
1999-12-17 00:11:37 +01:00
callrec->Caller_Range = CUR.curRange;
callrec->Caller_IP = CUR.IP + 1;
callrec->Cur_Count = 1;
callrec->Cur_Restart = def->start;
2000-05-17 01:44:38 +02:00
1999-12-17 00:11:37 +01:00
if ( INS_Goto_CodeRange( def->range, def->start ) == FAILURE )
goto LErrorLabel_;
2000-05-17 01:44:38 +02:00
1999-12-17 00:11:37 +01:00
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
1999-12-17 00:11:37 +01:00
default:
goto LErrorLabel_;
#if 0
break;
#endif
1999-12-17 00:11:37 +01:00
}
}
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). */
1999-12-17 00:11:37 +01:00
if ( ++ins_counter > MAX_RUNNABLE_OPCODES )
return TT_Err_Execution_Too_Long;
LSuiteLabel_:
1999-12-17 00:11:37 +01:00
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
1999-12-17 00:11:37 +01:00
*exc = cur;
#endif
1999-12-17 00:11:37 +01:00
return TT_Err_Ok;
LErrorCodeOverflow_:
CUR.error = TT_Err_Code_Overflow;
LErrorLabel_:
#ifdef TT_CONFIG_OPTION_STATIC_RASTER
1999-12-17 00:11:37 +01:00
*exc = cur;
#endif
1999-12-17 00:11:37 +01:00
return CUR.error;
}
#endif /* TT_USE_BYTECODE_INTERPRETER */
1999-12-17 00:11:37 +01:00
1999-12-17 00:11:37 +01:00
/* END */