/**************************************************************************** * * ttinterp.c * * TrueType bytecode interpreter (body). * * Copyright (C) 1996-2023 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, * modified, and distributed under the terms of the FreeType project * license, LICENSE.TXT. By continuing to use, modify, or distribute * this file you indicate that you have read the license and * understand and accept it fully. * */ /* Greg Hitchcock from Microsoft has helped a lot in resolving unclear */ /* issues; many thanks! */ #include <freetype/internal/ftdebug.h> #include <freetype/internal/ftcalc.h> #include <freetype/fttrigon.h> #include <freetype/ftsystem.h> #include <freetype/ftdriver.h> #include <freetype/ftmm.h> #include "ttinterp.h" #include "tterrors.h" #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT #include "ttgxvar.h" #endif #ifdef TT_USE_BYTECODE_INTERPRETER /************************************************************************** * * The macro FT_COMPONENT is used in trace mode. It is an implicit * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log * messages during execution. */ #undef FT_COMPONENT #define FT_COMPONENT … #define NO_SUBPIXEL_HINTING … #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL #define SUBPIXEL_HINTING_MINIMAL … #endif #define PROJECT( v1, v2 ) … #define DUALPROJ( v1, v2 ) … #define FAST_PROJECT( v ) … #define FAST_DUALPROJ( v ) … /************************************************************************** * * Two simple bounds-checking macros. */ #define BOUNDS( x, n ) … #define BOUNDSL( x, n ) … #undef SUCCESS #define SUCCESS … #undef FAILURE #define FAILURE … /************************************************************************** * * CODERANGE FUNCTIONS * */ /************************************************************************** * * @Function: * TT_Goto_CodeRange * * @Description: * Switches to a new code range (updates the code related elements in * `exec', and `IP'). * * @Input: * range :: * The new execution code range. * * IP :: * The new IP in the new code range. * * @InOut: * exec :: * The target execution context. */ FT_LOCAL_DEF( void ) TT_Goto_CodeRange( TT_ExecContext exec, FT_Int range, FT_Long IP ) { … } /************************************************************************** * * @Function: * TT_Set_CodeRange * * @Description: * Sets a code range. * * @Input: * range :: * The code range index. * * base :: * The new code base. * * length :: * The range size in bytes. * * @InOut: * exec :: * The target execution context. */ FT_LOCAL_DEF( void ) TT_Set_CodeRange( TT_ExecContext exec, FT_Int range, void* base, FT_Long length ) { … } /************************************************************************** * * @Function: * TT_Clear_CodeRange * * @Description: * Clears a code range. * * @Input: * range :: * The code range index. * * @InOut: * exec :: * The target execution context. */ FT_LOCAL_DEF( void ) TT_Clear_CodeRange( TT_ExecContext exec, FT_Int range ) { … } /************************************************************************** * * EXECUTION CONTEXT ROUTINES * */ /************************************************************************** * * @Function: * TT_Done_Context * * @Description: * Destroys a given context. * * @Input: * exec :: * A handle to the target execution context. * * memory :: * A handle to the parent memory object. * * @Note: * Only the glyph loader and debugger should call this function. */ FT_LOCAL_DEF( void ) TT_Done_Context( TT_ExecContext exec ) { … } /************************************************************************** * * @Function: * TT_Load_Context * * @Description: * Prepare an execution context for glyph hinting. * * @Input: * face :: * A handle to the source face object. * * size :: * A handle to the source size object. * * @InOut: * exec :: * A handle to the target execution context. * * @Return: * FreeType error code. 0 means success. * * @Note: * Only the glyph loader and debugger should call this function. * * Note that not all members of `TT_ExecContext` get initialized. */ FT_LOCAL_DEF( FT_Error ) TT_Load_Context( TT_ExecContext exec, TT_Face face, TT_Size size ) { … } /************************************************************************** * * @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. * * @Note: * Only the glyph loader and debugger should call this function. */ FT_LOCAL_DEF( void ) TT_Save_Context( TT_ExecContext exec, TT_Size size ) { … } /************************************************************************** * * @Function: * TT_Run_Context * * @Description: * Executes one or more instructions in the execution context. * * @Input: * exec :: * A handle to the target execution context. * * @Return: * TrueType error code. 0 means success. */ FT_LOCAL_DEF( FT_Error ) TT_Run_Context( TT_ExecContext exec ) { … } /* The default value for `scan_control' is documented as FALSE in the */ /* TrueType specification. This is confusing since it implies a */ /* Boolean value. However, this is not the case, thus both the */ /* default values of our `scan_type' and `scan_control' fields (which */ /* the documentation's `scan_control' variable is split into) are */ /* zero. */ const TT_GraphicsState tt_default_graphics_state = …; /* documentation is in ttinterp.h */ FT_EXPORT_DEF( TT_ExecContext ) TT_New_Context( TT_Driver driver ) { … } /************************************************************************** * * Before an opcode is executed, the interpreter verifies that there are * enough arguments on the stack, with the help of the `Pop_Push_Count' * table. * * For each opcode, the first column gives the number of arguments that * are popped from the stack; the second one gives the number of those * that are pushed in result. * * Opcodes which have a varying number of parameters in the data stream * (NPUSHB, NPUSHW) are handled specially; they have a negative value in * the `opcode_length' table, and the value in `Pop_Push_Count' is set * to zero. * */ #undef PACK #define PACK … static const FT_Byte Pop_Push_Count[256] = …; #ifdef FT_DEBUG_LEVEL_TRACE /* the first hex digit gives the length of the opcode name; the space */ /* after the digit is here just to increase readability of the source */ /* code */ static const char* const opcode_name[256] = { /* 0x00 */ "8 SVTCA[y]", "8 SVTCA[x]", "9 SPVTCA[y]", "9 SPVTCA[x]", "9 SFVTCA[y]", "9 SFVTCA[x]", "9 SPVTL[||]", "8 SPVTL[+]", "9 SFVTL[||]", "8 SFVTL[+]", "5 SPVFS", "5 SFVFS", "3 GPV", "3 GFV", "6 SFVTPV", "5 ISECT", /* 0x10 */ "4 SRP0", "4 SRP1", "4 SRP2", "4 SZP0", "4 SZP1", "4 SZP2", "4 SZPS", "5 SLOOP", "3 RTG", "4 RTHG", "3 SMD", "4 ELSE", "4 JMPR", "6 SCVTCI", "5 SSWCI", "3 SSW", /* 0x20 */ "3 DUP", "3 POP", "5 CLEAR", "4 SWAP", "5 DEPTH", "6 CINDEX", "6 MINDEX", "8 ALIGNPTS", "7 INS_$28", "3 UTP", "8 LOOPCALL", "4 CALL", "4 FDEF", "4 ENDF", "6 MDAP[]", "9 MDAP[rnd]", /* 0x30 */ "6 IUP[y]", "6 IUP[x]", "8 SHP[rp2]", "8 SHP[rp1]", "8 SHC[rp2]", "8 SHC[rp1]", "8 SHZ[rp2]", "8 SHZ[rp1]", "5 SHPIX", "2 IP", "7 MSIRP[]", "A MSIRP[rp0]", "7 ALIGNRP", "4 RTDG", "6 MIAP[]", "9 MIAP[rnd]", /* 0x40 */ "6 NPUSHB", "6 NPUSHW", "2 WS", "2 RS", "5 WCVTP", "4 RCVT", "8 GC[curr]", "8 GC[orig]", "4 SCFS", "8 MD[curr]", "8 MD[orig]", "5 MPPEM", "3 MPS", "6 FLIPON", "7 FLIPOFF", "5 DEBUG", /* 0x50 */ "2 LT", "4 LTEQ", "2 GT", "4 GTEQ", "2 EQ", "3 NEQ", "3 ODD", "4 EVEN", "2 IF", "3 EIF", "3 AND", "2 OR", "3 NOT", "7 DELTAP1", "3 SDB", "3 SDS", /* 0x60 */ "3 ADD", "3 SUB", "3 DIV", "3 MUL", "3 ABS", "3 NEG", "5 FLOOR", "7 CEILING", "8 ROUND[G]", "8 ROUND[B]", "8 ROUND[W]", "7 ROUND[]", "9 NROUND[G]", "9 NROUND[B]", "9 NROUND[W]", "8 NROUND[]", /* 0x70 */ "5 WCVTF", "7 DELTAP2", "7 DELTAP3", "7 DELTAC1", "7 DELTAC2", "7 DELTAC3", "6 SROUND", "8 S45ROUND", "4 JROT", "4 JROF", "4 ROFF", "7 INS_$7B", "4 RUTG", "4 RDTG", "5 SANGW", "2 AA", /* 0x80 */ "6 FLIPPT", "8 FLIPRGON", "9 FLIPRGOFF", "7 INS_$83", "7 INS_$84", "8 SCANCTRL", "A SDPVTL[||]", "9 SDPVTL[+]", "7 GETINFO", "4 IDEF", "4 ROLL", "3 MAX", "3 MIN", "8 SCANTYPE", "8 INSTCTRL", "7 INS_$8F", /* 0x90 */ "7 INS_$90", #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT "C GETVARIATION", "7 GETDATA", #else "7 INS_$91", "7 INS_$92", #endif "7 INS_$93", "7 INS_$94", "7 INS_$95", "7 INS_$96", "7 INS_$97", "7 INS_$98", "7 INS_$99", "7 INS_$9A", "7 INS_$9B", "7 INS_$9C", "7 INS_$9D", "7 INS_$9E", "7 INS_$9F", /* 0xA0 */ "7 INS_$A0", "7 INS_$A1", "7 INS_$A2", "7 INS_$A3", "7 INS_$A4", "7 INS_$A5", "7 INS_$A6", "7 INS_$A7", "7 INS_$A8", "7 INS_$A9", "7 INS_$AA", "7 INS_$AB", "7 INS_$AC", "7 INS_$AD", "7 INS_$AE", "7 INS_$AF", /* 0xB0 */ "8 PUSHB[0]", "8 PUSHB[1]", "8 PUSHB[2]", "8 PUSHB[3]", "8 PUSHB[4]", "8 PUSHB[5]", "8 PUSHB[6]", "8 PUSHB[7]", "8 PUSHW[0]", "8 PUSHW[1]", "8 PUSHW[2]", "8 PUSHW[3]", "8 PUSHW[4]", "8 PUSHW[5]", "8 PUSHW[6]", "8 PUSHW[7]", /* 0xC0 */ "7 MDRP[G]", "7 MDRP[B]", "7 MDRP[W]", "6 MDRP[]", "8 MDRP[rG]", "8 MDRP[rB]", "8 MDRP[rW]", "7 MDRP[r]", "8 MDRP[mG]", "8 MDRP[mB]", "8 MDRP[mW]", "7 MDRP[m]", "9 MDRP[mrG]", "9 MDRP[mrB]", "9 MDRP[mrW]", "8 MDRP[mr]", /* 0xD0 */ "8 MDRP[pG]", "8 MDRP[pB]", "8 MDRP[pW]", "7 MDRP[p]", "9 MDRP[prG]", "9 MDRP[prB]", "9 MDRP[prW]", "8 MDRP[pr]", "9 MDRP[pmG]", "9 MDRP[pmB]", "9 MDRP[pmW]", "8 MDRP[pm]", "A MDRP[pmrG]", "A MDRP[pmrB]", "A MDRP[pmrW]", "9 MDRP[pmr]", /* 0xE0 */ "7 MIRP[G]", "7 MIRP[B]", "7 MIRP[W]", "6 MIRP[]", "8 MIRP[rG]", "8 MIRP[rB]", "8 MIRP[rW]", "7 MIRP[r]", "8 MIRP[mG]", "8 MIRP[mB]", "8 MIRP[mW]", "7 MIRP[m]", "9 MIRP[mrG]", "9 MIRP[mrB]", "9 MIRP[mrW]", "8 MIRP[mr]", /* 0xF0 */ "8 MIRP[pG]", "8 MIRP[pB]", "8 MIRP[pW]", "7 MIRP[p]", "9 MIRP[prG]", "9 MIRP[prB]", "9 MIRP[prW]", "8 MIRP[pr]", "9 MIRP[pmG]", "9 MIRP[pmB]", "9 MIRP[pmW]", "8 MIRP[pm]", "A MIRP[pmrG]", "A MIRP[pmrB]", "A MIRP[pmrW]", "9 MIRP[pmr]" }; #endif /* FT_DEBUG_LEVEL_TRACE */ static const FT_Char opcode_length[256] = …; #undef PACK #ifndef FT_CONFIG_OPTION_NO_ASSEMBLER #if defined( __arm__ ) && \ ( defined( __thumb2__ ) || !defined( __thumb__ ) ) #define TT_MulFix14 … static FT_Int32 TT_MulFix14_arm( FT_Int32 a, FT_Int b ) { FT_Int32 t, t2; #if defined( __CC_ARM ) || defined( __ARMCC__ ) __asm { smull t2, t, b, a /* (lo=t2,hi=t) = a*b */ mov a, t, asr #31 /* a = (hi >> 31) */ add a, a, #0x2000 /* a += 0x2000 */ adds t2, t2, a /* t2 += a */ adc t, t, #0 /* t += carry */ mov a, t2, lsr #14 /* a = t2 >> 14 */ orr a, a, t, lsl #18 /* a |= t << 18 */ } #elif defined( __GNUC__ ) __asm__ __volatile__ ( "smull %1, %2, %4, %3\n\t" /* (lo=%1,hi=%2) = a*b */ "mov %0, %2, asr #31\n\t" /* %0 = (hi >> 31) */ #if defined( __clang__ ) && defined( __thumb2__ ) "add.w %0, %0, #0x2000\n\t" /* %0 += 0x2000 */ #else "add %0, %0, #0x2000\n\t" /* %0 += 0x2000 */ #endif "adds %1, %1, %0\n\t" /* %1 += %0 */ "adc %2, %2, #0\n\t" /* %2 += carry */ "mov %0, %1, lsr #14\n\t" /* %0 = %1 >> 16 */ "orr %0, %0, %2, lsl #18\n\t" /* %0 |= %2 << 16 */ : "=r"(a), "=&r"(t2), "=&r"(t) : "r"(a), "r"(b) : "cc" ); #endif return a; } #endif /* __arm__ && ( __thumb2__ || !__thumb__ ) */ #endif /* !FT_CONFIG_OPTION_NO_ASSEMBLER */ #if defined( __GNUC__ ) && \ ( defined( __i386__ ) || defined( __x86_64__ ) ) #define TT_MulFix14 … /* Temporarily disable the warning that C90 doesn't support `long long'. */ #if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406 #pragma GCC diagnostic push #endif #pragma GCC diagnostic ignored "-Wlong-long" /* This is declared `noinline' because inlining the function results */ /* in slower code. The `pure' attribute indicates that the result */ /* only depends on the parameters. */ static __attribute__(( noinline )) __attribute__(( pure )) FT_Int32 TT_MulFix14_long_long( FT_Int32 a, FT_Int b ) { … } #if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406 #pragma GCC diagnostic pop #endif #endif /* __GNUC__ && ( __i386__ || __x86_64__ ) */ #ifndef TT_MulFix14 /* Compute (a*b)/2^14 with maximum accuracy and rounding. */ /* This is optimized to be faster than calling FT_MulFix() */ /* for platforms where sizeof(int) == 2. */ static FT_Int32 TT_MulFix14( FT_Int32 a, FT_Int b ) { FT_Int32 sign; FT_UInt32 ah, al, mid, lo, hi; sign = a ^ b; if ( a < 0 ) a = -a; if ( b < 0 ) b = -b; ah = (FT_UInt32)( ( a >> 16 ) & 0xFFFFU ); al = (FT_UInt32)( a & 0xFFFFU ); lo = al * b; mid = ah * b; hi = mid >> 16; mid = ( mid << 16 ) + ( 1 << 13 ); /* rounding */ lo += mid; if ( lo < mid ) hi += 1; mid = ( lo >> 14 ) | ( hi << 18 ); return sign >= 0 ? (FT_Int32)mid : -(FT_Int32)mid; } #endif /* !TT_MulFix14 */ #if defined( __GNUC__ ) && \ ( defined( __i386__ ) || \ defined( __x86_64__ ) || \ defined( __arm__ ) ) #define TT_DotFix14 … #if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406 #pragma GCC diagnostic push #endif #pragma GCC diagnostic ignored "-Wlong-long" static __attribute__(( pure )) FT_Int32 TT_DotFix14_long_long( FT_Int32 ax, FT_Int32 ay, FT_Int bx, FT_Int by ) { … } #if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406 #pragma GCC diagnostic pop #endif #endif /* __GNUC__ && (__arm__ || __i386__ || __x86_64__) */ #ifndef TT_DotFix14 /* compute (ax*bx+ay*by)/2^14 with maximum accuracy and rounding */ static FT_Int32 TT_DotFix14( FT_Int32 ax, FT_Int32 ay, FT_Int bx, FT_Int by ) { FT_Int32 m, s, hi1, hi2, hi; FT_UInt32 l, lo1, lo2, lo; /* compute ax*bx as 64-bit value */ l = (FT_UInt32)( ( ax & 0xFFFFU ) * bx ); m = ( ax >> 16 ) * bx; lo1 = l + ( (FT_UInt32)m << 16 ); hi1 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo1 < l ); /* compute ay*by as 64-bit value */ l = (FT_UInt32)( ( ay & 0xFFFFU ) * by ); m = ( ay >> 16 ) * by; lo2 = l + ( (FT_UInt32)m << 16 ); hi2 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo2 < l ); /* add them */ lo = lo1 + lo2; hi = hi1 + hi2 + ( lo < lo1 ); /* divide the result by 2^14 with rounding */ s = hi >> 31; l = lo + (FT_UInt32)s; hi += s + ( l < lo ); lo = l; l = lo + 0x2000U; hi += ( l < lo ); return (FT_Int32)( ( (FT_UInt32)hi << 18 ) | ( l >> 14 ) ); } #endif /* TT_DotFix14 */ /************************************************************************** * * @Function: * Current_Ratio * * @Description: * Returns the current aspect ratio scaling factor depending on the * projection vector's state and device resolutions. * * @Return: * The aspect ratio in 16.16 format, always <= 1.0 . */ static FT_Long Current_Ratio( TT_ExecContext exc ) { … } FT_CALLBACK_DEF( FT_Long ) Current_Ppem( TT_ExecContext exc ) { … } FT_CALLBACK_DEF( FT_Long ) Current_Ppem_Stretched( TT_ExecContext exc ) { … } /************************************************************************** * * Functions related to the control value table (CVT). * */ FT_CALLBACK_DEF( FT_F26Dot6 ) Read_CVT( TT_ExecContext exc, FT_ULong idx ) { … } FT_CALLBACK_DEF( FT_F26Dot6 ) Read_CVT_Stretched( TT_ExecContext exc, FT_ULong idx ) { … } static void Modify_CVT_Check( TT_ExecContext exc ) { … } FT_CALLBACK_DEF( void ) Write_CVT( TT_ExecContext exc, FT_ULong idx, FT_F26Dot6 value ) { … } FT_CALLBACK_DEF( void ) Write_CVT_Stretched( TT_ExecContext exc, FT_ULong idx, FT_F26Dot6 value ) { … } FT_CALLBACK_DEF( void ) Move_CVT( TT_ExecContext exc, FT_ULong idx, FT_F26Dot6 value ) { … } FT_CALLBACK_DEF( void ) Move_CVT_Stretched( TT_ExecContext exc, FT_ULong idx, FT_F26Dot6 value ) { … } /************************************************************************** * * @Function: * GetShortIns * * @Description: * Returns a short integer taken from the instruction stream at * address IP. * * @Return: * Short read at code[IP]. * * @Note: * This one could become a macro. */ static FT_Short GetShortIns( TT_ExecContext exc ) { … } /************************************************************************** * * @Function: * Ins_Goto_CodeRange * * @Description: * Goes to a certain code range in the instruction stream. * * @Input: * aRange :: * The index of the code range. * * aIP :: * The new IP address in the code range. * * @Return: * SUCCESS or FAILURE. */ static FT_Bool Ins_Goto_CodeRange( TT_ExecContext exc, FT_Int aRange, FT_Long aIP ) { … } /* * * Apple's TrueType specification at * * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM02/Chap2.html#order * * gives the following order of operations in instructions that move * points. * * - check single width cut-in (MIRP, MDRP) * * - check control value cut-in (MIRP, MIAP) * * - apply engine compensation (MIRP, MDRP) * * - round distance (MIRP, MDRP) or value (MIAP, MDAP) * * - check minimum distance (MIRP,MDRP) * * - move point (MIRP, MDRP, MIAP, MSIRP, MDAP) * * For rounding instructions, engine compensation happens before rounding. * */ /************************************************************************** * * @Function: * Direct_Move * * @Description: * Moves a point by a given distance along the freedom vector. The * point will be `touched'. * * @Input: * point :: * The index of the point to move. * * distance :: * The distance to apply. * * @InOut: * zone :: * The affected glyph zone. * * @Note: * See `ttinterp.h' for details on backward compatibility mode. * `Touches' the point. */ static void Direct_Move( TT_ExecContext exc, TT_GlyphZone zone, FT_UShort point, FT_F26Dot6 distance ) { … } /************************************************************************** * * @Function: * Direct_Move_Orig * * @Description: * Moves the *original* position of a point by a given distance along * the freedom vector. Obviously, the point will not be `touched'. * * @Input: * point :: * The index of the point to move. * * distance :: * The distance to apply. * * @InOut: * zone :: * The affected glyph zone. */ static void Direct_Move_Orig( TT_ExecContext exc, TT_GlyphZone zone, FT_UShort point, FT_F26Dot6 distance ) { … } /************************************************************************** * * 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. * See `ttinterp.h' for details on backward compatibility mode. * */ static void Direct_Move_X( TT_ExecContext exc, TT_GlyphZone zone, FT_UShort point, FT_F26Dot6 distance ) { … } static void Direct_Move_Y( TT_ExecContext exc, TT_GlyphZone zone, FT_UShort point, FT_F26Dot6 distance ) { … } /************************************************************************** * * 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( TT_ExecContext exc, TT_GlyphZone zone, FT_UShort point, FT_F26Dot6 distance ) { … } static void Direct_Move_Orig_Y( TT_ExecContext exc, TT_GlyphZone zone, FT_UShort point, FT_F26Dot6 distance ) { … } /************************************************************************** * * @Function: * Round_None * * @Description: * Does not round, but adds engine compensation. * * @Input: * distance :: * The distance (not) to round. * * color :: * The engine compensation color. * * @Return: * The compensated distance. */ static FT_F26Dot6 Round_None( TT_ExecContext exc, FT_F26Dot6 distance, FT_Int color ) { … } /************************************************************************** * * @Function: * Round_To_Grid * * @Description: * Rounds value to grid after adding engine compensation. * * @Input: * distance :: * The distance to round. * * color :: * The engine compensation color. * * @Return: * Rounded distance. */ static FT_F26Dot6 Round_To_Grid( TT_ExecContext exc, FT_F26Dot6 distance, FT_Int color ) { … } /************************************************************************** * * @Function: * Round_To_Half_Grid * * @Description: * Rounds value to half grid after adding engine compensation. * * @Input: * distance :: * The distance to round. * * color :: * The engine compensation color. * * @Return: * Rounded distance. */ static FT_F26Dot6 Round_To_Half_Grid( TT_ExecContext exc, FT_F26Dot6 distance, FT_Int color ) { … } /************************************************************************** * * @Function: * Round_Down_To_Grid * * @Description: * Rounds value down to grid after adding engine compensation. * * @Input: * distance :: * The distance to round. * * color :: * The engine compensation color. * * @Return: * Rounded distance. */ static FT_F26Dot6 Round_Down_To_Grid( TT_ExecContext exc, FT_F26Dot6 distance, FT_Int color ) { … } /************************************************************************** * * @Function: * Round_Up_To_Grid * * @Description: * Rounds value up to grid after adding engine compensation. * * @Input: * distance :: * The distance to round. * * color :: * The engine compensation color. * * @Return: * Rounded distance. */ static FT_F26Dot6 Round_Up_To_Grid( TT_ExecContext exc, FT_F26Dot6 distance, FT_Int color ) { … } /************************************************************************** * * @Function: * Round_To_Double_Grid * * @Description: * Rounds value to double grid after adding engine compensation. * * @Input: * distance :: * The distance to round. * * color :: * The engine compensation color. * * @Return: * Rounded distance. */ static FT_F26Dot6 Round_To_Double_Grid( TT_ExecContext exc, FT_F26Dot6 distance, FT_Int color ) { … } /************************************************************************** * * @Function: * Round_Super * * @Description: * Super-rounds value to grid after adding engine compensation. * * @Input: * distance :: * The distance to round. * * color :: * The engine compensation color. * * @Return: * Rounded distance. * * @Note: * The TrueType specification says very little about the relationship * between rounding and engine compensation. However, it seems from * the description of super round that we should add the compensation * before rounding. */ static FT_F26Dot6 Round_Super( TT_ExecContext exc, FT_F26Dot6 distance, FT_Int color ) { … } /************************************************************************** * * @Function: * Round_Super_45 * * @Description: * Super-rounds value to grid after adding engine compensation. * * @Input: * distance :: * The distance to round. * * color :: * The engine compensation color. * * @Return: * Rounded distance. * * @Note: * There is a separate function for Round_Super_45() as we may need * greater precision. */ static FT_F26Dot6 Round_Super_45( TT_ExecContext exc, FT_F26Dot6 distance, FT_Int color ) { … } /************************************************************************** * * @Function: * Compute_Round * * @Description: * Sets the rounding mode. * * @Input: * round_mode :: * The rounding mode to be used. */ static void Compute_Round( TT_ExecContext exc, FT_Byte round_mode ) { … } /************************************************************************** * * @Function: * SetSuperRound * * @Description: * Sets Super Round parameters. * * @Input: * GridPeriod :: * The grid period. * * selector :: * The SROUND opcode. */ static void SetSuperRound( TT_ExecContext exc, FT_F2Dot14 GridPeriod, FT_Long selector ) { … } /************************************************************************** * * @Function: * Project * * @Description: * Computes the projection of vector given by (v2-v1) along the * current projection vector. * * @Input: * v1 :: * First input vector. * v2 :: * Second input vector. * * @Return: * The distance in F26dot6 format. */ static FT_F26Dot6 Project( TT_ExecContext exc, FT_Pos dx, FT_Pos dy ) { … } /************************************************************************** * * @Function: * Dual_Project * * @Description: * Computes the projection of the vector given by (v2-v1) along the * current dual vector. * * @Input: * v1 :: * First input vector. * v2 :: * Second input vector. * * @Return: * The distance in F26dot6 format. */ static FT_F26Dot6 Dual_Project( TT_ExecContext exc, FT_Pos dx, FT_Pos dy ) { … } /************************************************************************** * * @Function: * Project_x * * @Description: * Computes the projection of the vector given by (v2-v1) along the * horizontal axis. * * @Input: * v1 :: * First input vector. * v2 :: * Second input vector. * * @Return: * The distance in F26dot6 format. */ static FT_F26Dot6 Project_x( TT_ExecContext exc, FT_Pos dx, FT_Pos dy ) { … } /************************************************************************** * * @Function: * Project_y * * @Description: * Computes the projection of the vector given by (v2-v1) along the * vertical axis. * * @Input: * v1 :: * First input vector. * v2 :: * Second input vector. * * @Return: * The distance in F26dot6 format. */ static FT_F26Dot6 Project_y( TT_ExecContext exc, FT_Pos dx, FT_Pos dy ) { … } /************************************************************************** * * @Function: * Compute_Funcs * * @Description: * Computes the projection and movement function pointers according * to the current graphics state. */ static void Compute_Funcs( TT_ExecContext exc ) { … } /************************************************************************** * * @Function: * Normalize * * @Description: * Norms a vector. * * @Input: * Vx :: * The horizontal input vector coordinate. * Vy :: * The vertical input vector coordinate. * * @Output: * R :: * The normed unit vector. * * @Return: * Returns FAILURE if a vector parameter is zero. * * @Note: * In case Vx and Vy are both zero, `Normalize' returns SUCCESS, and * R is undefined. */ static FT_Bool Normalize( FT_F26Dot6 Vx, FT_F26Dot6 Vy, FT_UnitVector* R ) { … } /************************************************************************** * * Here we start with the implementation of the various opcodes. * */ #define ARRAY_BOUND_ERROR … /************************************************************************** * * MPPEM[]: Measure Pixel Per EM * Opcode range: 0x4B * Stack: --> Euint16 */ static void Ins_MPPEM( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * MPS[]: Measure Point Size * Opcode range: 0x4C * Stack: --> Euint16 */ static void Ins_MPS( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * DUP[]: DUPlicate the stack's top element * Opcode range: 0x20 * Stack: StkElt --> StkElt StkElt */ static void Ins_DUP( FT_Long* args ) { … } /************************************************************************** * * POP[]: POP the stack's top element * Opcode range: 0x21 * Stack: StkElt --> */ static void Ins_POP( void ) { … } /************************************************************************** * * CLEAR[]: CLEAR the entire stack * Opcode range: 0x22 * Stack: StkElt... --> */ static void Ins_CLEAR( TT_ExecContext exc ) { … } /************************************************************************** * * SWAP[]: SWAP the stack's top two elements * Opcode range: 0x23 * Stack: 2 * StkElt --> 2 * StkElt */ static void Ins_SWAP( FT_Long* args ) { … } /************************************************************************** * * DEPTH[]: return the stack DEPTH * Opcode range: 0x24 * Stack: --> uint32 */ static void Ins_DEPTH( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * LT[]: Less Than * Opcode range: 0x50 * Stack: int32? int32? --> bool */ static void Ins_LT( FT_Long* args ) { … } /************************************************************************** * * LTEQ[]: Less Than or EQual * Opcode range: 0x51 * Stack: int32? int32? --> bool */ static void Ins_LTEQ( FT_Long* args ) { … } /************************************************************************** * * GT[]: Greater Than * Opcode range: 0x52 * Stack: int32? int32? --> bool */ static void Ins_GT( FT_Long* args ) { … } /************************************************************************** * * GTEQ[]: Greater Than or EQual * Opcode range: 0x53 * Stack: int32? int32? --> bool */ static void Ins_GTEQ( FT_Long* args ) { … } /************************************************************************** * * EQ[]: EQual * Opcode range: 0x54 * Stack: StkElt StkElt --> bool */ static void Ins_EQ( FT_Long* args ) { … } /************************************************************************** * * NEQ[]: Not EQual * Opcode range: 0x55 * Stack: StkElt StkElt --> bool */ static void Ins_NEQ( FT_Long* args ) { … } /************************************************************************** * * ODD[]: Is ODD * Opcode range: 0x56 * Stack: f26.6 --> bool */ static void Ins_ODD( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * EVEN[]: Is EVEN * Opcode range: 0x57 * Stack: f26.6 --> bool */ static void Ins_EVEN( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * AND[]: logical AND * Opcode range: 0x5A * Stack: uint32 uint32 --> uint32 */ static void Ins_AND( FT_Long* args ) { … } /************************************************************************** * * OR[]: logical OR * Opcode range: 0x5B * Stack: uint32 uint32 --> uint32 */ static void Ins_OR( FT_Long* args ) { … } /************************************************************************** * * NOT[]: logical NOT * Opcode range: 0x5C * Stack: StkElt --> uint32 */ static void Ins_NOT( FT_Long* args ) { … } /************************************************************************** * * ADD[]: ADD * Opcode range: 0x60 * Stack: f26.6 f26.6 --> f26.6 */ static void Ins_ADD( FT_Long* args ) { … } /************************************************************************** * * SUB[]: SUBtract * Opcode range: 0x61 * Stack: f26.6 f26.6 --> f26.6 */ static void Ins_SUB( FT_Long* args ) { … } /************************************************************************** * * DIV[]: DIVide * Opcode range: 0x62 * Stack: f26.6 f26.6 --> f26.6 */ static void Ins_DIV( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * MUL[]: MULtiply * Opcode range: 0x63 * Stack: f26.6 f26.6 --> f26.6 */ static void Ins_MUL( FT_Long* args ) { … } /************************************************************************** * * ABS[]: ABSolute value * Opcode range: 0x64 * Stack: f26.6 --> f26.6 */ static void Ins_ABS( FT_Long* args ) { … } /************************************************************************** * * NEG[]: NEGate * Opcode range: 0x65 * Stack: f26.6 --> f26.6 */ static void Ins_NEG( FT_Long* args ) { … } /************************************************************************** * * FLOOR[]: FLOOR * Opcode range: 0x66 * Stack: f26.6 --> f26.6 */ static void Ins_FLOOR( FT_Long* args ) { … } /************************************************************************** * * CEILING[]: CEILING * Opcode range: 0x67 * Stack: f26.6 --> f26.6 */ static void Ins_CEILING( FT_Long* args ) { … } /************************************************************************** * * RS[]: Read Store * Opcode range: 0x43 * Stack: uint32 --> uint32 */ static void Ins_RS( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * WS[]: Write Store * Opcode range: 0x42 * Stack: uint32 uint32 --> */ static void Ins_WS( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * WCVTP[]: Write CVT in Pixel units * Opcode range: 0x44 * Stack: f26.6 uint32 --> */ static void Ins_WCVTP( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * WCVTF[]: Write CVT in Funits * Opcode range: 0x70 * Stack: uint32 uint32 --> */ static void Ins_WCVTF( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * RCVT[]: Read CVT * Opcode range: 0x45 * Stack: uint32 --> f26.6 */ static void Ins_RCVT( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * AA[]: Adjust Angle * Opcode range: 0x7F * Stack: uint32 --> */ static void Ins_AA( void ) { … } /************************************************************************** * * DEBUG[]: DEBUG. Unsupported. * Opcode range: 0x4F * Stack: uint32 --> * * Note: The original instruction pops a value from the stack. */ static void Ins_DEBUG( TT_ExecContext exc ) { … } /************************************************************************** * * ROUND[ab]: ROUND value * Opcode range: 0x68-0x6B * Stack: f26.6 --> f26.6 */ static void Ins_ROUND( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * NROUND[ab]: No ROUNDing of value * Opcode range: 0x6C-0x6F * Stack: f26.6 --> f26.6 */ static void Ins_NROUND( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * MAX[]: MAXimum * Opcode range: 0x8B * Stack: int32? int32? --> int32 */ static void Ins_MAX( FT_Long* args ) { … } /************************************************************************** * * MIN[]: MINimum * Opcode range: 0x8C * Stack: int32? int32? --> int32 */ static void Ins_MIN( FT_Long* args ) { … } /************************************************************************** * * MINDEX[]: Move INDEXed element * Opcode range: 0x26 * Stack: int32? --> StkElt */ static void Ins_MINDEX( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * CINDEX[]: Copy INDEXed element * Opcode range: 0x25 * Stack: int32 --> StkElt */ static void Ins_CINDEX( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * ROLL[]: ROLL top three elements * Opcode range: 0x8A * Stack: 3 * StkElt --> 3 * StkElt */ static void Ins_ROLL( FT_Long* args ) { … } /************************************************************************** * * MANAGING THE FLOW OF CONTROL * */ /************************************************************************** * * SLOOP[]: Set LOOP variable * Opcode range: 0x17 * Stack: int32? --> */ static void Ins_SLOOP( TT_ExecContext exc, FT_Long* args ) { … } static FT_Bool SkipCode( TT_ExecContext exc ) { … } /************************************************************************** * * IF[]: IF test * Opcode range: 0x58 * Stack: StkElt --> */ static void Ins_IF( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * ELSE[]: ELSE * Opcode range: 0x1B * Stack: --> */ static void Ins_ELSE( TT_ExecContext exc ) { … } /************************************************************************** * * EIF[]: End IF * Opcode range: 0x59 * Stack: --> */ static void Ins_EIF( void ) { … } /************************************************************************** * * JMPR[]: JuMP Relative * Opcode range: 0x1C * Stack: int32 --> */ static void Ins_JMPR( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * JROT[]: Jump Relative On True * Opcode range: 0x78 * Stack: StkElt int32 --> */ static void Ins_JROT( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * JROF[]: Jump Relative On False * Opcode range: 0x79 * Stack: StkElt int32 --> */ static void Ins_JROF( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * DEFINING AND USING FUNCTIONS AND INSTRUCTIONS * */ /************************************************************************** * * FDEF[]: Function DEFinition * Opcode range: 0x2C * Stack: uint32 --> */ static void Ins_FDEF( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * ENDF[]: END Function definition * Opcode range: 0x2D * Stack: --> */ static void Ins_ENDF( TT_ExecContext exc ) { … } /************************************************************************** * * CALL[]: CALL function * Opcode range: 0x2B * Stack: uint32? --> */ static void Ins_CALL( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * LOOPCALL[]: LOOP and CALL function * Opcode range: 0x2A * Stack: uint32? Eint16? --> */ static void Ins_LOOPCALL( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * IDEF[]: Instruction DEFinition * Opcode range: 0x89 * Stack: Eint8 --> */ static void Ins_IDEF( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * PUSHING DATA ONTO THE INTERPRETER STACK * */ /************************************************************************** * * NPUSHB[]: PUSH N Bytes * Opcode range: 0x40 * Stack: --> uint32... */ static void Ins_NPUSHB( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * NPUSHW[]: PUSH N Words * Opcode range: 0x41 * Stack: --> int32... */ static void Ins_NPUSHW( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * PUSHB[abc]: PUSH Bytes * Opcode range: 0xB0-0xB7 * Stack: --> uint32... */ static void Ins_PUSHB( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * PUSHW[abc]: PUSH Words * Opcode range: 0xB8-0xBF * Stack: --> int32... */ static void Ins_PUSHW( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * MANAGING THE GRAPHICS STATE * */ static FT_Bool Ins_SxVTL( TT_ExecContext exc, FT_UShort aIdx1, FT_UShort aIdx2, FT_UnitVector* Vec ) { … } /************************************************************************** * * SVTCA[a]: Set (F and P) Vectors to Coordinate Axis * Opcode range: 0x00-0x01 * Stack: --> * * SPvTCA[a]: Set PVector to Coordinate Axis * Opcode range: 0x02-0x03 * Stack: --> * * SFvTCA[a]: Set FVector to Coordinate Axis * Opcode range: 0x04-0x05 * Stack: --> */ static void Ins_SxyTCA( TT_ExecContext exc ) { … } /************************************************************************** * * SPvTL[a]: Set PVector To Line * Opcode range: 0x06-0x07 * Stack: uint32 uint32 --> */ static void Ins_SPVTL( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * SFvTL[a]: Set FVector To Line * Opcode range: 0x08-0x09 * Stack: uint32 uint32 --> */ static void Ins_SFVTL( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * SFvTPv[]: Set FVector To PVector * Opcode range: 0x0E * Stack: --> */ static void Ins_SFVTPV( TT_ExecContext exc ) { … } /************************************************************************** * * SPvFS[]: Set PVector From Stack * Opcode range: 0x0A * Stack: f2.14 f2.14 --> */ static void Ins_SPVFS( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * SFvFS[]: Set FVector From Stack * Opcode range: 0x0B * Stack: f2.14 f2.14 --> */ static void Ins_SFVFS( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * GPv[]: Get Projection Vector * Opcode range: 0x0C * Stack: ef2.14 --> ef2.14 */ static void Ins_GPV( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * GFv[]: Get Freedom Vector * Opcode range: 0x0D * Stack: ef2.14 --> ef2.14 */ static void Ins_GFV( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * SRP0[]: Set Reference Point 0 * Opcode range: 0x10 * Stack: uint32 --> */ static void Ins_SRP0( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * SRP1[]: Set Reference Point 1 * Opcode range: 0x11 * Stack: uint32 --> */ static void Ins_SRP1( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * SRP2[]: Set Reference Point 2 * Opcode range: 0x12 * Stack: uint32 --> */ static void Ins_SRP2( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * SMD[]: Set Minimum Distance * Opcode range: 0x1A * Stack: f26.6 --> */ static void Ins_SMD( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * SCVTCI[]: Set Control Value Table Cut In * Opcode range: 0x1D * Stack: f26.6 --> */ static void Ins_SCVTCI( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * SSWCI[]: Set Single Width Cut In * Opcode range: 0x1E * Stack: f26.6 --> */ static void Ins_SSWCI( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * SSW[]: Set Single Width * Opcode range: 0x1F * Stack: int32? --> */ static void Ins_SSW( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * FLIPON[]: Set auto-FLIP to ON * Opcode range: 0x4D * Stack: --> */ static void Ins_FLIPON( TT_ExecContext exc ) { … } /************************************************************************** * * FLIPOFF[]: Set auto-FLIP to OFF * Opcode range: 0x4E * Stack: --> */ static void Ins_FLIPOFF( TT_ExecContext exc ) { … } /************************************************************************** * * SANGW[]: Set ANGle Weight * Opcode range: 0x7E * Stack: uint32 --> */ static void Ins_SANGW( void ) { … } /************************************************************************** * * SDB[]: Set Delta Base * Opcode range: 0x5E * Stack: uint32 --> */ static void Ins_SDB( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * SDS[]: Set Delta Shift * Opcode range: 0x5F * Stack: uint32 --> */ static void Ins_SDS( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * RTHG[]: Round To Half Grid * Opcode range: 0x19 * Stack: --> */ static void Ins_RTHG( TT_ExecContext exc ) { … } /************************************************************************** * * RTG[]: Round To Grid * Opcode range: 0x18 * Stack: --> */ static void Ins_RTG( TT_ExecContext exc ) { … } /************************************************************************** * RTDG[]: Round To Double Grid * Opcode range: 0x3D * Stack: --> */ static void Ins_RTDG( TT_ExecContext exc ) { … } /************************************************************************** * RUTG[]: Round Up To Grid * Opcode range: 0x7C * Stack: --> */ static void Ins_RUTG( TT_ExecContext exc ) { … } /************************************************************************** * * RDTG[]: Round Down To Grid * Opcode range: 0x7D * Stack: --> */ static void Ins_RDTG( TT_ExecContext exc ) { … } /************************************************************************** * * ROFF[]: Round OFF * Opcode range: 0x7A * Stack: --> */ static void Ins_ROFF( TT_ExecContext exc ) { … } /************************************************************************** * * SROUND[]: Super ROUND * Opcode range: 0x76 * Stack: Eint8 --> */ static void Ins_SROUND( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * S45ROUND[]: Super ROUND 45 degrees * Opcode range: 0x77 * Stack: uint32 --> */ static void Ins_S45ROUND( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * GC[a]: Get Coordinate projected onto * Opcode range: 0x46-0x47 * Stack: uint32 --> f26.6 * * XXX: UNDOCUMENTED: Measures from the original glyph must be taken * along the dual projection vector! */ static void Ins_GC( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * SCFS[]: Set Coordinate From Stack * Opcode range: 0x48 * Stack: f26.6 uint32 --> * * Formula: * * OA := OA + ( value - OA.p )/( f.p ) * f */ static void Ins_SCFS( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * MD[a]: Measure Distance * Opcode range: 0x49-0x4A * Stack: uint32 uint32 --> f26.6 * * XXX: UNDOCUMENTED: Measure taken in the original glyph must be along * the dual projection vector. * * XXX: UNDOCUMENTED: Flag attributes are inverted! * 0 => measure distance in original outline * 1 => measure distance in grid-fitted outline * * XXX: UNDOCUMENTED: `zp0 - zp1', and not `zp2 - zp1! */ static void Ins_MD( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * SDPvTL[a]: Set Dual PVector to Line * Opcode range: 0x86-0x87 * Stack: uint32 uint32 --> */ static void Ins_SDPVTL( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * SZP0[]: Set Zone Pointer 0 * Opcode range: 0x13 * Stack: uint32 --> */ static void Ins_SZP0( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * SZP1[]: Set Zone Pointer 1 * Opcode range: 0x14 * Stack: uint32 --> */ static void Ins_SZP1( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * SZP2[]: Set Zone Pointer 2 * Opcode range: 0x15 * Stack: uint32 --> */ static void Ins_SZP2( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * SZPS[]: Set Zone PointerS * Opcode range: 0x16 * Stack: uint32 --> */ static void Ins_SZPS( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * INSTCTRL[]: INSTruction ConTRoL * Opcode range: 0x8E * Stack: int32 int32 --> */ static void Ins_INSTCTRL( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * SCANCTRL[]: SCAN ConTRoL * Opcode range: 0x85 * Stack: uint32? --> */ static void Ins_SCANCTRL( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * SCANTYPE[]: SCAN TYPE * Opcode range: 0x8D * Stack: uint16 --> */ static void Ins_SCANTYPE( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * MANAGING OUTLINES * */ /************************************************************************** * * FLIPPT[]: FLIP PoinT * Opcode range: 0x80 * Stack: uint32... --> */ static void Ins_FLIPPT( TT_ExecContext exc ) { … } /************************************************************************** * * FLIPRGON[]: FLIP RanGe ON * Opcode range: 0x81 * Stack: uint32 uint32 --> */ static void Ins_FLIPRGON( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * FLIPRGOFF: FLIP RanGe OFF * Opcode range: 0x82 * Stack: uint32 uint32 --> */ static void Ins_FLIPRGOFF( TT_ExecContext exc, FT_Long* args ) { … } static FT_Bool Compute_Point_Displacement( TT_ExecContext exc, FT_F26Dot6* x, FT_F26Dot6* y, TT_GlyphZone zone, FT_UShort* refp ) { … } /* See `ttinterp.h' for details on backward compatibility mode. */ static void Move_Zp2_Point( TT_ExecContext exc, FT_UShort point, FT_F26Dot6 dx, FT_F26Dot6 dy, FT_Bool touch ) { … } /************************************************************************** * * SHP[a]: SHift Point by the last point * Opcode range: 0x32-0x33 * Stack: uint32... --> */ static void Ins_SHP( TT_ExecContext exc ) { … } /************************************************************************** * * SHC[a]: SHift Contour * Opcode range: 0x34-35 * Stack: uint32 --> * * UNDOCUMENTED: According to Greg Hitchcock, there is one (virtual) * contour in the twilight zone, namely contour number * zero which includes all points of it. */ static void Ins_SHC( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * SHZ[a]: SHift Zone * Opcode range: 0x36-37 * Stack: uint32 --> */ static void Ins_SHZ( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * SHPIX[]: SHift points by a PIXel amount * Opcode range: 0x38 * Stack: f26.6 uint32... --> */ static void Ins_SHPIX( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * MSIRP[a]: Move Stack Indirect Relative Position * Opcode range: 0x3A-0x3B * Stack: f26.6 uint32 --> */ static void Ins_MSIRP( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * MDAP[a]: Move Direct Absolute Point * Opcode range: 0x2E-0x2F * Stack: uint32 --> */ static void Ins_MDAP( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * MIAP[a]: Move Indirect Absolute Point * Opcode range: 0x3E-0x3F * Stack: uint32 uint32 --> */ static void Ins_MIAP( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * MDRP[abcde]: Move Direct Relative Point * Opcode range: 0xC0-0xDF * Stack: uint32 --> */ static void Ins_MDRP( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * MIRP[abcde]: Move Indirect Relative Point * Opcode range: 0xE0-0xFF * Stack: int32? uint32 --> */ static void Ins_MIRP( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * ALIGNRP[]: ALIGN Relative Point * Opcode range: 0x3C * Stack: uint32 uint32... --> */ static void Ins_ALIGNRP( TT_ExecContext exc ) { … } /************************************************************************** * * ISECT[]: moves point to InterSECTion * Opcode range: 0x0F * Stack: 5 * uint32 --> */ static void Ins_ISECT( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * ALIGNPTS[]: ALIGN PoinTS * Opcode range: 0x27 * Stack: uint32 uint32 --> */ static void Ins_ALIGNPTS( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * IP[]: Interpolate Point * Opcode range: 0x39 * Stack: uint32... --> */ /* SOMETIMES, DUMBER CODE IS BETTER CODE */ static void Ins_IP( TT_ExecContext exc ) { … } /************************************************************************** * * UTP[a]: UnTouch Point * Opcode range: 0x29 * Stack: uint32 --> */ static void Ins_UTP( TT_ExecContext exc, FT_Long* args ) { … } /* Local variables for Ins_IUP: */ IUP_Worker; static void iup_worker_shift_( IUP_Worker worker, FT_UInt p1, FT_UInt p2, FT_UInt p ) { … } static void iup_worker_interpolate_( IUP_Worker worker, FT_UInt p1, FT_UInt p2, FT_UInt ref1, FT_UInt ref2 ) { … } /************************************************************************** * * IUP[a]: Interpolate Untouched Points * Opcode range: 0x30-0x31 * Stack: --> */ static void Ins_IUP( TT_ExecContext exc ) { … } /************************************************************************** * * DELTAPn[]: DELTA exceptions P1, P2, P3 * Opcode range: 0x5D,0x71,0x72 * Stack: uint32 (2 * uint32)... --> */ static void Ins_DELTAP( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * DELTACn[]: DELTA exceptions C1, C2, C3 * Opcode range: 0x73,0x74,0x75 * Stack: uint32 (2 * uint32)... --> */ static void Ins_DELTAC( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * MISC. INSTRUCTIONS * */ /************************************************************************** * * GETINFO[]: GET INFOrmation * Opcode range: 0x88 * Stack: uint32 --> uint32 */ static void Ins_GETINFO( TT_ExecContext exc, FT_Long* args ) { … } #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT /************************************************************************** * * GETVARIATION[]: get normalized variation (blend) coordinates * Opcode range: 0x91 * Stack: --> f2.14... * * XXX: UNDOCUMENTED! There is no official documentation from Apple for * this bytecode instruction. Active only if a font has GX * variation axes. */ static void Ins_GETVARIATION( TT_ExecContext exc, FT_Long* args ) { … } /************************************************************************** * * GETDATA[]: no idea what this is good for * Opcode range: 0x92 * Stack: --> 17 * * XXX: UNDOCUMENTED! There is no documentation from Apple for this * very weird bytecode instruction. */ static void Ins_GETDATA( FT_Long* args ) { … } #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ static void Ins_UNKNOWN( TT_ExecContext exc ) { … } /************************************************************************** * * RUN * * This function executes a run of opcodes. It will exit in the * following cases: * * - Errors (in which case it returns FALSE). * * - Reaching the end of the main code range (returns TRUE). * Reaching the end of a code range within a function call is an * error. * * - After executing one single opcode, if the flag `Instruction_Trap' * is set to TRUE (returns TRUE). * * On exit with TRUE, test IP < CodeSize to know whether it comes from * an instruction trap or a normal termination. * * * Note: The documented DEBUG opcode pops a value from the stack. This * behaviour is unsupported; here a DEBUG opcode is always an * error. * * * THIS IS THE INTERPRETER'S MAIN LOOP. * */ /* documentation is in ttinterp.h */ FT_EXPORT_DEF( FT_Error ) TT_RunIns( void* exec ) { … } #else /* !TT_USE_BYTECODE_INTERPRETER */ /* ANSI C doesn't like empty source files */ typedef int tt_interp_dummy_; #endif /* !TT_USE_BYTECODE_INTERPRETER */ /* END */