📄 ttinterp.c
字号:
/******************************************************************* * * ttinterp.c 3.1 * * TrueType bytecode intepreter. * * Copyright 1996-1999 by * David Turner, Robert Wilhelm, and Werner Lemberg * * This file is part of the FreeType project, and may only be used * modified and distributed under the terms of the FreeType project * license, LICENSE.TXT. By continuing to use, modify, or distribute * this file you indicate that you have read the license and * understand and accept it fully. * * * Changes between 3.1 and 3.0: * * - A more relaxed version of the interpreter. It is now able to * ignore errors like out-of-bound array access and writes in order * to silently support broken glyphs (even if the results are not * always pretty). * * Note that one can use the flag TTLOAD_PEDANTIC to force * TrueType-compliant interpretation. * * - A big #if used to completely disable the interpreter, which * is due to the Apple patents issues which emerged recently. * ******************************************************************/#include "freetype.h"#include "tttypes.h"#include "ttdebug.h"#include "ttcalc.h"#include "ttmemory.h"#include "ttinterp.h"#ifdef TT_CONFIG_OPTION_NO_INTERPRETER LOCAL_FUNC TT_Error RunIns( PExecution_Context exc ) { /* do nothing - always successful */ (void)exc; return TT_Err_Ok; }#else#ifdef DEBUG_INTERPRETER#include <memory.h>#include "ttdebug.h"/* Define the `getch()' function. On Unix systems, it is an alias *//* for `getchar()', and the debugger front end must ensure that the *//* `stdin' file descriptor is not in line-by-line input mode. */#ifdef OS2#include <conio.h>#else#define getch getchar#endif#endif /* DEBUG_INTEPRETER *//* required by the tracing mode */#undef TT_COMPONENT#define TT_COMPONENT trace_interp/* In order to detect infinite loops in the code, we set-up *//* a counter within the run loop. a singly stroke of interpretation *//* is now limited to a maximum number of opcodes defined below.. *//* */#define MAX_RUNNABLE_OPCODES 1000000/* There are two kinds of implementations there: *//* *//* a. static implementation: *//* *//* The current execution context is a static variable, *//* which fields are accessed directly by the interpreter *//* during execution. The context is named 'cur'. *//* *//* This version is non-reentrant, of course. *//* *//* *//* b. indirect implementation: *//* *//* The current execution context is passed to _each_ *//* function as its first argument, and each field is *//* thus accessed indirectly. *//* *//* This version is, however, fully re-entrant. *//* *//* *//* The idea is that an indirect implementation may be *//* slower to execute on the low-end processors that are *//* used in some systems (like 386s or even 486s). *//* *//* When the interpreter started, we had no idea of the *//* time that glyph hinting (i.e. executing instructions) *//* could take in the whole process of rendering a glyph, *//* and a 10 to 30% performance penalty on low-end systems *//* didn't seem much of a good idea. This question led us *//* to provide two distinct builds of the C version from *//* a single source, with the use of macros (again). *//* *//* Now that the engine is working (and working really *//* well!), it seems that the greatest time-consuming *//* factors are: file i/o, glyph loading, rasterizing and *//* _then_ glyph hinting! *//* *//* Tests performed with two versions of the 'fttimer' *//* program seem to indicate that hinting takes less than 5% *//* of the rendering process, which is dominated by glyph *//* loading and scan-line conversion by an high order of *//* magnitude. *//* *//* As a consequence, the indirect implementation is now the *//* default, as its performance costs can be considered *//* negligible in our context. Note, however, that we *//* kept the same source with macros because: *//* *//* - the code is kept very close in design to the *//* Pascal one used for development. *//* *//* - it's much more readable that way! *//* *//* - it's still open to later experimentation and tuning */#ifndef TT_CONFIG_OPTION_STATIC_INTERPRETER /* indirect implementation */#define CUR (*exc) /* see ttobjs.h */#else /* static implementation */#define CUR cur static TExecution_Context cur; /* static exec. context variable */ /* apparently, we have a _lot_ of direct indexing when accessing */ /* the static 'cur', which makes the code bigger (due to all the */ /* four bytes addresses). */#endif /* !TT_CONFIG_OPTION_STATIC_INTERPRETER */#define INS_ARG EXEC_OPS PStorage args /* see ttobjs.h */#define SKIP_Code() SkipCode( EXEC_ARG )#define GET_ShortIns() GetShortIns( EXEC_ARG )#define COMPUTE_Funcs() Compute_Funcs( EXEC_ARG )#define NORMalize( x, y, v ) Normalize( EXEC_ARGS x, y, v )#define SET_SuperRound( scale, flags ) \ SetSuperRound( EXEC_ARGS scale, flags )#define INS_Goto_CodeRange( range, ip ) \ Ins_Goto_CodeRange( EXEC_ARGS range, ip )#define CUR_Func_project( x, y ) CUR.func_project( EXEC_ARGS x, y )#define CUR_Func_move( z, p, d ) CUR.func_move( EXEC_ARGS z, p, d )#define CUR_Func_dualproj( x, y ) CUR.func_dualproj( EXEC_ARGS x, y )#define CUR_Func_freeProj( x, y ) CUR.func_freeProj( EXEC_ARGS x, y )#define CUR_Func_round( d, c ) CUR.func_round( EXEC_ARGS d, c )#define CUR_Func_read_cvt( index ) \ CUR.func_read_cvt( EXEC_ARGS index )#define CUR_Func_write_cvt( index, val ) \ CUR.func_write_cvt( EXEC_ARGS index, val )#define CUR_Func_move_cvt( index, val ) \ CUR.func_move_cvt( EXEC_ARGS index, val )#define CURRENT_Ratio() Current_Ratio( EXEC_ARG )#define CURRENT_Ppem() Current_Ppem( EXEC_ARG )#define CALC_Length() Calc_Length( EXEC_ARG )#define INS_SxVTL( a, b, c, d ) Ins_SxVTL( EXEC_ARGS a, b, c, d )#define COMPUTE_Point_Displacement( a, b, c, d ) \ Compute_Point_Displacement( EXEC_ARGS a, b, c, d )#define MOVE_Zp2_Point( a, b, c, t ) Move_Zp2_Point( EXEC_ARGS a, b, c, t )#define CUR_Ppem() Cur_PPEM( EXEC_ARG ) /* Instruction dispatch function, as used by the interpreter */ typedef void (*TInstruction_Function)( INS_ARG );#define BOUNDS( x, n ) ( (x) >= (n) )/*********************************************************************//* *//* Before an opcode is executed, the interpreter verifies that *//* there are enough arguments on the stack, with the help of *//* the Pop_Push_Count table. *//* *//* For each opcode, the first column gives the number of arguments *//* that are popped from the stack; the second one gives the number *//* of those that are pushed in result. *//* *//* Note that for opcodes with a varying number of parameters, *//* either 0 or 1 arg is verified before execution, depending *//* on the nature of the instruction: *//* *//* - if the number of arguments is given by the bytecode *//* stream or the loop variable, 0 is chosen. *//* *//* - if the first argument is a count n that is followed *//* by arguments a1..an, then 1 is chosen. *//* *//*********************************************************************/#undef PACK#define PACK( x, y ) ((x << 4) | y) static const Byte Pop_Push_Count[256] = { /* opcodes are gathered in groups of 16 */ /* please keep the spaces as they are */ /* SVTCA y */ PACK( 0, 0 ), /* SVTCA x */ PACK( 0, 0 ), /* SPvTCA y */ PACK( 0, 0 ), /* SPvTCA x */ PACK( 0, 0 ), /* SFvTCA y */ PACK( 0, 0 ), /* SFvTCA x */ PACK( 0, 0 ), /* SPvTL // */ PACK( 2, 0 ), /* SPvTL + */ PACK( 2, 0 ), /* SFvTL // */ PACK( 2, 0 ), /* SFvTL + */ PACK( 2, 0 ), /* SPvFS */ PACK( 2, 0 ), /* SFvFS */ PACK( 2, 0 ), /* GPV */ PACK( 0, 2 ), /* GFV */ PACK( 0, 2 ), /* SFvTPv */ PACK( 0, 0 ), /* ISECT */ PACK( 5, 0 ), /* SRP0 */ PACK( 1, 0 ), /* SRP1 */ PACK( 1, 0 ), /* SRP2 */ PACK( 1, 0 ), /* SZP0 */ PACK( 1, 0 ), /* SZP1 */ PACK( 1, 0 ), /* SZP2 */ PACK( 1, 0 ), /* SZPS */ PACK( 1, 0 ), /* SLOOP */ PACK( 1, 0 ), /* RTG */ PACK( 0, 0 ), /* RTHG */ PACK( 0, 0 ), /* SMD */ PACK( 1, 0 ), /* ELSE */ PACK( 0, 0 ), /* JMPR */ PACK( 1, 0 ), /* SCvTCi */ PACK( 1, 0 ), /* SSwCi */ PACK( 1, 0 ), /* SSW */ PACK( 1, 0 ), /* DUP */ PACK( 1, 2 ), /* POP */ PACK( 1, 0 ), /* CLEAR */ PACK( 0, 0 ), /* SWAP */ PACK( 2, 2 ), /* DEPTH */ PACK( 0, 1 ), /* CINDEX */ PACK( 1, 1 ), /* MINDEX */ PACK( 1, 0 ), /* AlignPTS */ PACK( 2, 0 ), /* INS_$28 */ PACK( 0, 0 ), /* UTP */ PACK( 1, 0 ), /* LOOPCALL */ PACK( 2, 0 ), /* CALL */ PACK( 1, 0 ), /* FDEF */ PACK( 1, 0 ), /* ENDF */ PACK( 0, 0 ), /* MDAP[0] */ PACK( 1, 0 ), /* MDAP[1] */ PACK( 1, 0 ), /* IUP[0] */ PACK( 0, 0 ), /* IUP[1] */ PACK( 0, 0 ), /* SHP[0] */ PACK( 0, 0 ), /* SHP[1] */ PACK( 0, 0 ), /* SHC[0] */ PACK( 1, 0 ), /* SHC[1] */ PACK( 1, 0 ), /* SHZ[0] */ PACK( 1, 0 ), /* SHZ[1] */ PACK( 1, 0 ), /* SHPIX */ PACK( 1, 0 ), /* IP */ PACK( 0, 0 ), /* MSIRP[0] */ PACK( 2, 0 ), /* MSIRP[1] */ PACK( 2, 0 ), /* AlignRP */ PACK( 0, 0 ), /* RTDG */ PACK( 0, 0 ), /* MIAP[0] */ PACK( 2, 0 ), /* MIAP[1] */ PACK( 2, 0 ), /* NPushB */ PACK( 0, 0 ), /* NPushW */ PACK( 0, 0 ), /* WS */ PACK( 2, 0 ), /* RS */ PACK( 1, 1 ), /* WCvtP */ PACK( 2, 0 ), /* RCvt */ PACK( 1, 1 ), /* GC[0] */ PACK( 1, 1 ), /* GC[1] */ PACK( 1, 1 ), /* SCFS */ PACK( 2, 0 ), /* MD[0] */ PACK( 2, 1 ), /* MD[1] */ PACK( 2, 1 ), /* MPPEM */ PACK( 0, 1 ), /* MPS */ PACK( 0, 1 ), /* FlipON */ PACK( 0, 0 ), /* FlipOFF */ PACK( 0, 0 ), /* DEBUG */ PACK( 1, 0 ), /* LT */ PACK( 2, 1 ), /* LTEQ */ PACK( 2, 1 ), /* GT */ PACK( 2, 1 ), /* GTEQ */ PACK( 2, 1 ), /* EQ */ PACK( 2, 1 ), /* NEQ */ PACK( 2, 1 ), /* ODD */ PACK( 1, 1 ), /* EVEN */ PACK( 1, 1 ), /* IF */ PACK( 1, 0 ), /* EIF */ PACK( 0, 0 ), /* AND */ PACK( 2, 1 ), /* OR */ PACK( 2, 1 ), /* NOT */ PACK( 1, 1 ), /* DeltaP1 */ PACK( 1, 0 ), /* SDB */ PACK( 1, 0 ), /* SDS */ PACK( 1, 0 ), /* ADD */ PACK( 2, 1 ), /* SUB */ PACK( 2, 1 ), /* DIV */ PACK( 2, 1 ), /* MUL */ PACK( 2, 1 ), /* ABS */ PACK( 1, 1 ), /* NEG */ PACK( 1, 1 ), /* FLOOR */ PACK( 1, 1 ), /* CEILING */ PACK( 1, 1 ), /* ROUND[0] */ PACK( 1, 1 ), /* ROUND[1] */ PACK( 1, 1 ), /* ROUND[2] */ PACK( 1, 1 ), /* ROUND[3] */ PACK( 1, 1 ), /* NROUND[0] */ PACK( 1, 1 ), /* NROUND[1] */ PACK( 1, 1 ), /* NROUND[2] */ PACK( 1, 1 ), /* NROUND[3] */ PACK( 1, 1 ), /* WCvtF */ PACK( 2, 0 ), /* DeltaP2 */ PACK( 1, 0 ), /* DeltaP3 */ PACK( 1, 0 ), /* DeltaCn[0] */ PACK( 1, 0 ), /* DeltaCn[1] */ PACK( 1, 0 ), /* DeltaCn[2] */ PACK( 1, 0 ), /* SROUND */ PACK( 1, 0 ), /* S45Round */ PACK( 1, 0 ), /* JROT */ PACK( 2, 0 ), /* JROF */ PACK( 2, 0 ), /* ROFF */ PACK( 0, 0 ), /* INS_$7B */ PACK( 0, 0 ), /* RUTG */ PACK( 0, 0 ), /* RDTG */ PACK( 0, 0 ), /* SANGW */ PACK( 1, 0 ), /* AA */ PACK( 1, 0 ), /* FlipPT */ PACK( 0, 0 ), /* FlipRgON */ PACK( 2, 0 ), /* FlipRgOFF */ PACK( 2, 0 ), /* INS_$83 */ PACK( 0, 0 ), /* INS_$84 */ PACK( 0, 0 ), /* ScanCTRL */ PACK( 1, 0 ), /* SDVPTL[0] */ PACK( 2, 0 ), /* SDVPTL[1] */ PACK( 2, 0 ), /* GetINFO */ PACK( 1, 1 ), /* IDEF */ PACK( 1, 0 ), /* ROLL */ PACK( 3, 3 ), /* MAX */ PACK( 2, 1 ), /* MIN */ PACK( 2, 1 ), /* ScanTYPE */ PACK( 1, 0 ), /* InstCTRL */ PACK( 2, 0 ), /* INS_$8F */ PACK( 0, 0 ), /* INS_$90 */ PACK( 0, 0 ), /* INS_$91 */ PACK( 0, 0 ), /* INS_$92 */ PACK( 0, 0 ), /* INS_$93 */ PACK( 0, 0 ), /* INS_$94 */ PACK( 0, 0 ), /* INS_$95 */ PACK( 0, 0 ), /* INS_$96 */ PACK( 0, 0 ), /* INS_$97 */ PACK( 0, 0 ), /* INS_$98 */ PACK( 0, 0 ), /* INS_$99 */ PACK( 0, 0 ), /* INS_$9A */ PACK( 0, 0 ), /* INS_$9B */ PACK( 0, 0 ), /* INS_$9C */ PACK( 0, 0 ), /* INS_$9D */ PACK( 0, 0 ), /* INS_$9E */ PACK( 0, 0 ), /* INS_$9F */ PACK( 0, 0 ), /* INS_$A0 */ PACK( 0, 0 ), /* INS_$A1 */ PACK( 0, 0 ), /* INS_$A2 */ PACK( 0, 0 ), /* INS_$A3 */ PACK( 0, 0 ), /* INS_$A4 */ PACK( 0, 0 ), /* INS_$A5 */ PACK( 0, 0 ), /* INS_$A6 */ PACK( 0, 0 ), /* INS_$A7 */ PACK( 0, 0 ), /* INS_$A8 */ PACK( 0, 0 ), /* INS_$A9 */ PACK( 0, 0 ), /* INS_$AA */ PACK( 0, 0 ), /* INS_$AB */ PACK( 0, 0 ), /* INS_$AC */ PACK( 0, 0 ), /* INS_$AD */ PACK( 0, 0 ), /* INS_$AE */ PACK( 0, 0 ), /* INS_$AF */ PACK( 0, 0 ), /* PushB[0] */ PACK( 0, 1 ), /* PushB[1] */ PACK( 0, 2 ), /* PushB[2] */ PACK( 0, 3 ), /* PushB[3] */ PACK( 0, 4 ), /* PushB[4] */ PACK( 0, 5 ), /* PushB[5] */ PACK( 0, 6 ), /* PushB[6] */ PACK( 0, 7 ), /* PushB[7] */ PACK( 0, 8 ), /* PushW[0] */ PACK( 0, 1 ), /* PushW[1] */ PACK( 0, 2 ), /* PushW[2] */ PACK( 0, 3 ), /* PushW[3] */ PACK( 0, 4 ), /* PushW[4] */ PACK( 0, 5 ), /* PushW[5] */ PACK( 0, 6 ), /* PushW[6] */ PACK( 0, 7 ), /* PushW[7] */ PACK( 0, 8 ), /* MDRP[00] */ PACK( 1, 0 ), /* MDRP[01] */ PACK( 1, 0 ), /* MDRP[02] */ PACK( 1, 0 ), /* MDRP[03] */ PACK( 1, 0 ), /* MDRP[04] */ PACK( 1, 0 ), /* MDRP[05] */ PACK( 1, 0 ), /* MDRP[06] */ PACK( 1, 0 ), /* MDRP[07] */ PACK( 1, 0 ), /* MDRP[08] */ PACK( 1, 0 ), /* MDRP[09] */ PACK( 1, 0 ), /* MDRP[10] */ PACK( 1, 0 ), /* MDRP[11] */ PACK( 1, 0 ), /* MDRP[12] */ PACK( 1, 0 ), /* MDRP[13] */ PACK( 1, 0 ), /* MDRP[14] */ PACK( 1, 0 ), /* MDRP[15] */ PACK( 1, 0 ), /* MDRP[16] */ PACK( 1, 0 ), /* MDRP[17] */ PACK( 1, 0 ), /* MDRP[18] */ PACK( 1, 0 ), /* MDRP[19] */ PACK( 1, 0 ), /* MDRP[20] */ PACK( 1, 0 ), /* MDRP[21] */ PACK( 1, 0 ), /* MDRP[22] */ PACK( 1, 0 ),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -