/***************************************************************************//* *//* ttinterp.c *//* *//* TrueType bytecode interpreter (body). *//* *//* Copyright 1996-2018 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<ft2build.h>#includeFT_INTERNAL_DEBUG_H#includeFT_INTERNAL_CALC_H#includeFT_TRIGONOMETRY_H#includeFT_SYSTEM_H#includeFT_DRIVER_H#includeFT_MULTIPLE_MASTERS_H#include"ttinterp.h"#include"tterrors.h"#include"ttsubpix.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 trace_ttinterp#define NO_SUBPIXEL_HINTING \ ( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \ TT_INTERPRETER_VERSION_35 )#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY#define SUBPIXEL_HINTING_INFINALITY \ ( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \ TT_INTERPRETER_VERSION_38 )#endif#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL#define SUBPIXEL_HINTING_MINIMAL \ ( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \ TT_INTERPRETER_VERSION_40 )#endif#define PROJECT( v1, v2 ) \ exc->func_project( exc, \ SUB_LONG( (v1)->x, (v2)->x ), \ SUB_LONG( (v1)->y, (v2)->y ) )#define DUALPROJ( v1, v2 ) \ exc->func_dualproj( exc, \ SUB_LONG( (v1)->x, (v2)->x ), \ SUB_LONG( (v1)->y, (v2)->y ) )#define FAST_PROJECT( v ) \ exc->func_project( exc, (v)->x, (v)->y )#define FAST_DUALPROJ( v ) \ exc->func_dualproj( exc, (v)->x, (v)->y )/*************************************************************************//* *//* Two simple bounds-checking macros. *//* */#define BOUNDS( x, n ) ( (FT_UInt)(x) >= (FT_UInt)(n) )#define BOUNDSL( x, n ) ( (FT_ULong)(x) >= (FT_ULong)(n) )#undef SUCCESS#define SUCCESS 0#undef FAILURE#define FAILURE 1/*************************************************************************//* *//* 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_ExecContextexec,FT_Intrange,FT_LongIP){TT_CodeRange*coderange;FT_ASSERT(range>=1&&range<=3);coderange=&exec->codeRangeTable[range-1];FT_ASSERT(coderange->base);/* NOTE: Because the last instruction of a program may be a CALL *//* which will return to the first byte *after* the code *//* range, we test for IP <= Size instead of IP < Size. *//* */FT_ASSERT(IP<=coderange->size);exec->code=coderange->base;exec->codeSize=coderange->size;exec->IP=IP;exec->curRange=range;}/*************************************************************************//* *//* <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_ExecContextexec,FT_Intrange,void*base,FT_Longlength){FT_ASSERT(range>=1&&range<=3);exec->codeRangeTable[range-1].base=(FT_Byte*)base;exec->codeRangeTable[range-1].size=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_ExecContextexec,FT_Intrange){FT_ASSERT(range>=1&&range<=3);exec->codeRangeTable[range-1].base=NULL;exec->codeRangeTable[range-1].size=0;}/*************************************************************************//* *//* 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_ExecContextexec){FT_Memorymemory=exec->memory;/* points zone */exec->maxPoints=0;exec->maxContours=0;/* free stack */FT_FREE(exec->stack);exec->stackSize=0;/* free call stack */FT_FREE(exec->callStack);exec->callSize=0;exec->callTop=0;/* free glyph code range */FT_FREE(exec->glyphIns);exec->glyphSize=0;exec->size=NULL;exec->face=NULL;FT_FREE(exec);}/*************************************************************************//* *//* <Function> *//* Init_Context *//* *//* <Description> *//* Initializes a context object. *//* *//* <Input> *//* memory :: A handle to the parent memory object. *//* *//* <InOut> *//* exec :: A handle to the target execution context. *//* *//* <Return> *//* FreeType error code. 0 means success. *//* */staticFT_ErrorInit_Context(TT_ExecContextexec,FT_Memorymemory){FT_Errorerror;FT_TRACE1(("Init_Context: new object at 0x%08p\n",exec));exec->memory=memory;exec->callSize=32;if(FT_NEW_ARRAY(exec->callStack,exec->callSize))gotoFail_Memory;/* all values in the context are set to 0 already, but this is *//* here as a remainder */exec->maxPoints=0;exec->maxContours=0;exec->stackSize=0;exec->glyphSize=0;exec->stack=NULL;exec->glyphIns=NULL;exec->face=NULL;exec->size=NULL;returnFT_Err_Ok;Fail_Memory:FT_ERROR(("Init_Context: not enough memory for %p\n",exec));TT_Done_Context(exec);returnerror;}/*************************************************************************//* *//* <Function> *//* Update_Max *//* *//* <Description> *//* Checks the size of a buffer and reallocates it if necessary. *//* *//* <Input> *//* memory :: A handle to the parent memory object. *//* *//* multiplier :: The size in bytes of each element in the buffer. *//* *//* new_max :: The new capacity (size) of the buffer. *//* *//* <InOut> *//* size :: The address of the buffer's current size expressed *//* in elements. *//* *//* buff :: The address of the buffer base pointer. *//* *//* <Return> *//* FreeType error code. 0 means success. *//* */FT_LOCAL_DEF(FT_Error)Update_Max(FT_Memorymemory,FT_ULong*size,FT_ULongmultiplier,void*_pbuff,FT_ULongnew_max){FT_Errorerror;void**pbuff=(void**)_pbuff;if(*size<new_max){if(FT_REALLOC(*pbuff,*size*multiplier,new_max*multiplier))returnerror;*size=new_max;}returnFT_Err_Ok;}/*************************************************************************//* *//* <Function> *//* TT_Load_Context *//* *//* <Description> *//* Prepare an execution context for glyph hinting. *//* *//* <Input> *//* face :: A handle to the source face object. *//* *//* size :: A handle to the source size object. *//* *//* <InOut> *//* exec :: A handle to the target execution context. *//* *//* <Return> *//* FreeType error code. 0 means success. *//* *//* <Note> *//* Only the glyph loader and debugger should call this function. *//* */FT_LOCAL_DEF(FT_Error)TT_Load_Context(TT_ExecContextexec,TT_Faceface,TT_Sizesize){FT_Inti;FT_ULongtmp;TT_MaxProfile*maxp;FT_Errorerror;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->pointSize=size->point_size;exec->tt_metrics=size->ttmetrics;exec->metrics=*size->metrics;exec->maxFunc=size->max_func;exec->maxIns=size->max_ins;for(i=0;i<TT_MAX_CODE_RANGES;i++)exec->codeRangeTable[i]=size->codeRangeTable[i];/* set graphics state */exec->GS=size->GS;exec->cvtSize=size->cvt_size;exec->cvt=size->cvt;exec->storeSize=size->storage_size;exec->storage=size->storage;exec->twilight=size->twilight;/* In case of multi-threading it can happen that the old size object *//* no longer exists, thus we must clear all glyph zone references. */FT_ZERO(&exec->zp0);exec->zp1=exec->zp0;exec->zp2=exec->zp0;}/* XXX: We reserve a little more elements on the stack to deal safely *//* with broken fonts like arialbs, courbs, timesbs, etc. */tmp=(FT_ULong)exec->stackSize;error=Update_Max(exec->memory,&tmp,sizeof(FT_F26Dot6),(void*)&exec->stack,maxp->maxStackElements+32);exec->stackSize=(FT_Long)tmp;if(error)returnerror;tmp=exec->glyphSize;error=Update_Max(exec->memory,&tmp,sizeof(FT_Byte),(void*)&exec->glyphIns,maxp->maxSizeOfInstructions);exec->glyphSize=(FT_UShort)tmp;if(error)returnerror;exec->pts.n_points=0;exec->pts.n_contours=0;exec->zp1=exec->pts;exec->zp2=exec->pts;exec->zp0=exec->pts;exec->instruction_trap=FALSE;returnFT_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. *//* *//* <Note> *//* Only the glyph loader and debugger should call this function. *//* */FT_LOCAL_DEF(void)TT_Save_Context(TT_ExecContextexec,TT_Sizesize){FT_Inti;/* XXX: 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];}/*************************************************************************//* *//* <Function> *//* TT_Run_Context *//* *//* <Description> *//* Executes one or more instructions in the execution context. *//* *//* <Input> *//* debug :: A Boolean flag. If set, the function sets some internal *//* variables and returns immediately, otherwise TT_RunIns() *//* is called. *//* *//* This is commented out currently. *//* *//* <Input> *//* exec :: A handle to the target execution context. *//* *//* <Return> *//* TrueType error code. 0 means success. *//* */FT_LOCAL_DEF(FT_Error)TT_Run_Context(TT_ExecContextexec){TT_Goto_CodeRange(exec,tt_coderange_glyph,0);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;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;returnexec->face->interpreter(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. */constTT_GraphicsStatett_default_graphics_state={0,0,0,{0x4000,0},{0x4000,0},{0x4000,0},1,64,1,TRUE,68,0,0,9,3,0,FALSE,0,1,1,1};/* documentation is in ttinterp.h */FT_EXPORT_DEF(TT_ExecContext)TT_New_Context(TT_Driverdriver){FT_Memorymemory;FT_Errorerror;TT_ExecContextexec=NULL;if(!driver)gotoFail;memory=driver->root.root.memory;/* allocate object */if(FT_NEW(exec))gotoFail;/* initialize it; in case of error this deallocates `exec' too */error=Init_Context(exec,memory);if(error)gotoFail;returnexec;Fail:returnNULL;}/*************************************************************************//* *//* Before an opcode is executed, the interpreter verifies that there are *//* enough arguments on the stack, with the help of the `Pop_Push_Count' *//* table. *//* *//* For each opcode, the first column gives the number of arguments that *//* are popped from the stack; the second one gives the number of those *//* that are pushed in result. *//* *//* Opcodes which have a varying number of parameters in the data stream *//* (NPUSHB, NPUSHW) are handled specially; they have a negative value in *//* the `opcode_length' table, and the value in `Pop_Push_Count' is set *//* to zero. *//* *//*************************************************************************/#undef PACK#define PACK( x, y ) ( ( x << 4 ) | y )staticconstFT_BytePop_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),/* loops *//* SHP[1] */PACK(0,0),/* loops *//* SHC[0] */PACK(1,0),/* SHC[1] */PACK(1,0),/* SHZ[0] */PACK(1,0),/* SHZ[1] */PACK(1,0),/* SHPIX */PACK(1,0),/* loops *//* IP */PACK(0,0),/* loops *//* MSIRP[0] */PACK(2,0),/* MSIRP[1] */PACK(2,0),/* AlignRP */PACK(0,0),/* loops *//* 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),/* loops *//* FlipRgON */PACK(2,0),/* FlipRgOFF */PACK(2,0),/* INS_$83 */PACK(0,0),/* INS_$84 */PACK(0,0),/* ScanCTRL */PACK(1,0),/* SDPvTL[0] */PACK(2,0),/* SDPvTL[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),/* GETVAR */PACK(0,0),/* will be handled specially *//* GETDATA */PACK(0,1),/* 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)};#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 */staticconstchar*constopcode_name[256]={"7 SVTCA y","7 SVTCA x","8 SPvTCA y","8 SPvTCA x","8 SFvTCA y","8 SFvTCA x","8 SPvTL ||","7 SPvTL +","8 SFvTL ||","7 SFvTL +","5 SPvFS","5 SFvFS","3 GPv","3 GFv","6 SFvTPv","5 ISECT","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","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","7 MDAP[0]","7 MDAP[1]","6 IUP[0]","6 IUP[1]","6 SHP[0]","6 SHP[1]","6 SHC[0]","6 SHC[1]","6 SHZ[0]","6 SHZ[1]","5 SHPIX","2 IP","8 MSIRP[0]","8 MSIRP[1]","7 AlignRP","4 RTDG","7 MIAP[0]","7 MIAP[1]","6 NPushB","6 NPushW","2 WS","2 RS","5 WCvtP","4 RCvt","5 GC[0]","5 GC[1]","4 SCFS","5 MD[0]","5 MD[1]","5 MPPEM","3 MPS","6 FlipON","7 FlipOFF","5 DEBUG","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","3 ADD","3 SUB","3 DIV","3 MUL","3 ABS","3 NEG","5 FLOOR","7 CEILING","8 ROUND[0]","8 ROUND[1]","8 ROUND[2]","8 ROUND[3]","9 NROUND[0]","9 NROUND[1]","9 NROUND[2]","9 NROUND[3]","5 WCvtF","7 DeltaP2","7 DeltaP3","A DeltaCn[0]","A DeltaCn[1]","A DeltaCn[2]","6 SROUND","8 S45Round","4 JROT","4 JROF","4 ROFF","7 INS_$7B","4 RUTG","4 RDTG","5 SANGW","2 AA","6 FlipPT","8 FlipRgON","9 FlipRgOFF","7 INS_$83","7 INS_$84","8 ScanCTRL","9 SDPvTL[0]","9 SDPvTL[1]","7 GetINFO","4 IDEF","4 ROLL","3 MAX","3 MIN","8 ScanTYPE","8 InstCTRL","7 INS_$8F","7 INS_$90",#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT"6 GETVAR","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","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","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]","8 MDRP[00]","8 MDRP[01]","8 MDRP[02]","8 MDRP[03]","8 MDRP[04]","8 MDRP[05]","8 MDRP[06]","8 MDRP[07]","8 MDRP[08]","8 MDRP[09]","8 MDRP[10]","8 MDRP[11]","8 MDRP[12]","8 MDRP[13]","8 MDRP[14]","8 MDRP[15]","8 MDRP[16]","8 MDRP[17]","8 MDRP[18]","8 MDRP[19]","8 MDRP[20]","8 MDRP[21]","8 MDRP[22]","8 MDRP[23]","8 MDRP[24]","8 MDRP[25]","8 MDRP[26]","8 MDRP[27]","8 MDRP[28]","8 MDRP[29]","8 MDRP[30]","8 MDRP[31]","8 MIRP[00]","8 MIRP[01]","8 MIRP[02]","8 MIRP[03]","8 MIRP[04]","8 MIRP[05]","8 MIRP[06]","8 MIRP[07]","8 MIRP[08]","8 MIRP[09]","8 MIRP[10]","8 MIRP[11]","8 MIRP[12]","8 MIRP[13]","8 MIRP[14]","8 MIRP[15]","8 MIRP[16]","8 MIRP[17]","8 MIRP[18]","8 MIRP[19]","8 MIRP[20]","8 MIRP[21]","8 MIRP[22]","8 MIRP[23]","8 MIRP[24]","8 MIRP[25]","8 MIRP[26]","8 MIRP[27]","8 MIRP[28]","8 MIRP[29]","8 MIRP[30]","8 MIRP[31]"};#endif /* FT_DEBUG_LEVEL_TRACE */staticconstFT_Charopcode_length[256]={1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,-1,-2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,3,4,5,6,7,8,9,3,5,7,9,11,13,15,17,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};#undef PACK#ifndef FT_CONFIG_OPTION_NO_ASSEMBLER#if defined( __arm__ ) && \ ( defined( __thumb2__ ) || !defined( __thumb__ ) )#define TT_MulFix14 TT_MulFix14_armstaticFT_Int32TT_MulFix14_arm(FT_Int32a,FT_Intb){FT_Int32t,t2;#if defined( __CC_ARM ) || defined( __ARMCC__ )__asm{smullt2,t,b,a/* (lo=t2,hi=t) = a*b */mova,t,asr#31/* a = (hi >> 31) */adda,a,#0x2000/* a += 0x2000 */addst2,t2,a/* t2 += a */adct,t,#0/* t += carry */mova,t2,lsr#14/* a = t2 >> 14 */orra,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");#endifreturna;}#endif /* __arm__ && ( __thumb2__ || !__thumb__ ) */#endif /* !FT_CONFIG_OPTION_NO_ASSEMBLER */#if defined( __GNUC__ ) && \ ( defined( __i386__ ) || defined( __x86_64__ ) )#define TT_MulFix14 TT_MulFix14_long_long/* 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_Int32TT_MulFix14_long_long(FT_Int32a,FT_Intb){longlongret=(longlong)a*b;/* The following line assumes that right shifting of signed values *//* will actually preserve the sign bit. The exact behaviour is *//* undefined, but this is true on x86 and x86_64. */longlongtmp=ret>>63;ret+=0x2000+tmp;return(FT_Int32)(ret>>14);}#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. */staticFT_Int32TT_MulFix14(FT_Int32a,FT_Intb){FT_Int32sign;FT_UInt32ah,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);returnsign>=0?(FT_Int32)mid:-(FT_Int32)mid;}#endif /* !TT_MulFix14 */#if defined( __GNUC__ ) && \ ( defined( __i386__ ) || \ defined( __x86_64__ ) || \ defined( __arm__ ) )#define TT_DotFix14 TT_DotFix14_long_long#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406#pragma GCC diagnostic push#endif#pragma GCC diagnostic ignored "-Wlong-long"static__attribute__((pure))FT_Int32TT_DotFix14_long_long(FT_Int32ax,FT_Int32ay,FT_Intbx,FT_Intby){/* Temporarily disable the warning that C90 doesn't support *//* `long long'. */longlongtemp1=(longlong)ax*bx;longlongtemp2=(longlong)ay*by;temp1+=temp2;temp2=temp1>>63;temp1+=0x2000+temp2;return(FT_Int32)(temp1>>14);}#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 */staticFT_Int32TT_DotFix14(FT_Int32ax,FT_Int32ay,FT_Intbx,FT_Intby){FT_Int32m,s,hi1,hi2,hi;FT_UInt32l,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 . *//* */staticFT_LongCurrent_Ratio(TT_ExecContextexc){if(!exc->tt_metrics.ratio){if(exc->GS.projVector.y==0)exc->tt_metrics.ratio=exc->tt_metrics.x_ratio;elseif(exc->GS.projVector.x==0)exc->tt_metrics.ratio=exc->tt_metrics.y_ratio;else{FT_F26Dot6x,y;x=TT_MulFix14(exc->tt_metrics.x_ratio,exc->GS.projVector.x);y=TT_MulFix14(exc->tt_metrics.y_ratio,exc->GS.projVector.y);exc->tt_metrics.ratio=FT_Hypot(x,y);}}returnexc->tt_metrics.ratio;}FT_CALLBACK_DEF(FT_Long)Current_Ppem(TT_ExecContextexc){returnexc->tt_metrics.ppem;}FT_CALLBACK_DEF(FT_Long)Current_Ppem_Stretched(TT_ExecContextexc){returnFT_MulFix(exc->tt_metrics.ppem,Current_Ratio(exc));}/*************************************************************************//* *//* Functions related to the control value table (CVT). *//* *//*************************************************************************/FT_CALLBACK_DEF(FT_F26Dot6)Read_CVT(TT_ExecContextexc,FT_ULongidx){returnexc->cvt[idx];}FT_CALLBACK_DEF(FT_F26Dot6)Read_CVT_Stretched(TT_ExecContextexc,FT_ULongidx){returnFT_MulFix(exc->cvt[idx],Current_Ratio(exc));}FT_CALLBACK_DEF(void)Write_CVT(TT_ExecContextexc,FT_ULongidx,FT_F26Dot6value){exc->cvt[idx]=value;}FT_CALLBACK_DEF(void)Write_CVT_Stretched(TT_ExecContextexc,FT_ULongidx,FT_F26Dot6value){exc->cvt[idx]=FT_DivFix(value,Current_Ratio(exc));}FT_CALLBACK_DEF(void)Move_CVT(TT_ExecContextexc,FT_ULongidx,FT_F26Dot6value){exc->cvt[idx]+=value;}FT_CALLBACK_DEF(void)Move_CVT_Stretched(TT_ExecContextexc,FT_ULongidx,FT_F26Dot6value){exc->cvt[idx]+=FT_DivFix(value,Current_Ratio(exc));}/*************************************************************************//* *//* <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. *//* */staticFT_ShortGetShortIns(TT_ExecContextexc){/* Reading a byte stream so there is no endianness (DaveP) */exc->IP+=2;return(FT_Short)((exc->code[exc->IP-2]<<8)+exc->code[exc->IP-1]);}/*************************************************************************//* *//* <Function> *//* Ins_Goto_CodeRange *//* *//* <Description> *//* Goes to a certain code range in the instruction stream. *//* *//* <Input> *//* aRange :: The index of the code range. *//* *//* aIP :: The new IP address in the code range. *//* *//* <Return> *//* SUCCESS or FAILURE. *//* */staticFT_BoolIns_Goto_CodeRange(TT_ExecContextexc,FT_IntaRange,FT_LongaIP){TT_CodeRange*range;if(aRange<1||aRange>3){exc->error=FT_THROW(Bad_Argument);returnFAILURE;}range=&exc->codeRangeTable[aRange-1];if(!range->base)/* invalid coderange */{exc->error=FT_THROW(Invalid_CodeRange);returnFAILURE;}/* 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){exc->error=FT_THROW(Code_Overflow);returnFAILURE;}exc->code=range->base;exc->codeSize=range->size;exc->IP=aIP;exc->curRange=aRange;returnSUCCESS;}/*************************************************************************//* *//* <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. *//* */staticvoidDirect_Move(TT_ExecContextexc,TT_GlyphZonezone,FT_UShortpoint,FT_F26Dot6distance){FT_F26Dot6v;v=exc->GS.freeVector.x;if(v!=0){#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITYif(SUBPIXEL_HINTING_INFINALITY&&(!exc->ignore_x_mode||(exc->sph_tweak_flags&SPH_TWEAK_ALLOW_X_DMOVE)))zone->cur[point].x=ADD_LONG(zone->cur[point].x,FT_MulDiv(distance,v,exc->F_dot_P));else#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL/* Exception to the post-IUP curfew: Allow the x component of *//* diagonal moves, but only post-IUP. DejaVu tries to adjust *//* diagonal stems like on `Z' and `z' post-IUP. */if(SUBPIXEL_HINTING_MINIMAL&&!exc->backward_compatibility)zone->cur[point].x=ADD_LONG(zone->cur[point].x,FT_MulDiv(distance,v,exc->F_dot_P));else#endifif(NO_SUBPIXEL_HINTING)zone->cur[point].x=ADD_LONG(zone->cur[point].x,FT_MulDiv(distance,v,exc->F_dot_P));zone->tags[point]|=FT_CURVE_TAG_TOUCH_X;}v=exc->GS.freeVector.y;if(v!=0){#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMALif(!(SUBPIXEL_HINTING_MINIMAL&&exc->backward_compatibility&&exc->iupx_called&&exc->iupy_called))#endifzone->cur[point].y=ADD_LONG(zone->cur[point].y,FT_MulDiv(distance,v,exc->F_dot_P));zone->tags[point]|=FT_CURVE_TAG_TOUCH_Y;}}/*************************************************************************//* *//* <Function> *//* Direct_Move_Orig *//* *//* <Description> *//* Moves the *original* position of a point by a given distance along *//* the freedom vector. Obviously, the point will not be `touched'. *//* *//* <Input> *//* point :: The index of the point to move. *//* *//* distance :: The distance to apply. *//* *//* <InOut> *//* zone :: The affected glyph zone. *//* */staticvoidDirect_Move_Orig(TT_ExecContextexc,TT_GlyphZonezone,FT_UShortpoint,FT_F26Dot6distance){FT_F26Dot6v;v=exc->GS.freeVector.x;if(v!=0)zone->org[point].x=ADD_LONG(zone->org[point].x,FT_MulDiv(distance,v,exc->F_dot_P));v=exc->GS.freeVector.y;if(v!=0)zone->org[point].y=ADD_LONG(zone->org[point].y,FT_MulDiv(distance,v,exc->F_dot_P));}/*************************************************************************//* *//* Special versions of Direct_Move() *//* *//* The following versions are used whenever both vectors are both *//* along one of the coordinate unit vectors, i.e. in 90% of the cases. *//* See `ttinterp.h' for details on backward compatibility mode. *//* *//*************************************************************************/staticvoidDirect_Move_X(TT_ExecContextexc,TT_GlyphZonezone,FT_UShortpoint,FT_F26Dot6distance){#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITYif(SUBPIXEL_HINTING_INFINALITY&&!exc->ignore_x_mode)zone->cur[point].x=ADD_LONG(zone->cur[point].x,distance);else#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMALif(SUBPIXEL_HINTING_MINIMAL&&!exc->backward_compatibility)zone->cur[point].x=ADD_LONG(zone->cur[point].x,distance);else#endifif(NO_SUBPIXEL_HINTING)zone->cur[point].x=ADD_LONG(zone->cur[point].x,distance);zone->tags[point]|=FT_CURVE_TAG_TOUCH_X;}staticvoidDirect_Move_Y(TT_ExecContextexc,TT_GlyphZonezone,FT_UShortpoint,FT_F26Dot6distance){FT_UNUSED(exc);#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMALif(!(SUBPIXEL_HINTING_MINIMAL&&exc->backward_compatibility&&exc->iupx_called&&exc->iupy_called))#endifzone->cur[point].y=ADD_LONG(zone->cur[point].y,distance);zone->tags[point]|=FT_CURVE_TAG_TOUCH_Y;}/*************************************************************************//* *//* Special versions of Direct_Move_Orig() *//* *//* The following versions are used whenever both vectors are both *//* along one of the coordinate unit vectors, i.e. in 90% of the cases. *//* *//*************************************************************************/staticvoidDirect_Move_Orig_X(TT_ExecContextexc,TT_GlyphZonezone,FT_UShortpoint,FT_F26Dot6distance){FT_UNUSED(exc);zone->org[point].x=ADD_LONG(zone->org[point].x,distance);}staticvoidDirect_Move_Orig_Y(TT_ExecContextexc,TT_GlyphZonezone,FT_UShortpoint,FT_F26Dot6distance){FT_UNUSED(exc);zone->org[point].y=ADD_LONG(zone->org[point].y,distance);}/*************************************************************************//* *//* <Function> *//* Round_None *//* *//* <Description> *//* Does not round, but adds engine compensation. *//* *//* <Input> *//* distance :: The distance (not) to round. *//* *//* compensation :: The engine compensation. *//* *//* <Return> *//* The compensated distance. *//* *//* <Note> *//* The TrueType specification says very few about the relationship *//* between rounding and engine compensation. However, it seems from *//* the description of super round that we should add the compensation *//* before rounding. *//* */staticFT_F26Dot6Round_None(TT_ExecContextexc,FT_F26Dot6distance,FT_F26Dot6compensation){FT_F26Dot6val;FT_UNUSED(exc);if(distance>=0){val=ADD_LONG(distance,compensation);if(val<0)val=0;}else{val=SUB_LONG(distance,compensation);if(val>0)val=0;}returnval;}/*************************************************************************//* *//* <Function> *//* Round_To_Grid *//* *//* <Description> *//* Rounds value to grid after adding engine compensation. *//* *//* <Input> *//* distance :: The distance to round. *//* *//* compensation :: The engine compensation. *//* *//* <Return> *//* Rounded distance. *//* */staticFT_F26Dot6Round_To_Grid(TT_ExecContextexc,FT_F26Dot6distance,FT_F26Dot6compensation){FT_F26Dot6val;FT_UNUSED(exc);if(distance>=0){val=FT_PIX_ROUND_LONG(ADD_LONG(distance,compensation));if(val<0)val=0;}else{val=NEG_LONG(FT_PIX_ROUND_LONG(SUB_LONG(compensation,distance)));if(val>0)val=0;}returnval;}/*************************************************************************//* *//* <Function> *//* Round_To_Half_Grid *//* *//* <Description> *//* Rounds value to half grid after adding engine compensation. *//* *//* <Input> *//* distance :: The distance to round. *//* *//* compensation :: The engine compensation. *//* *//* <Return> *//* Rounded distance. *//* */staticFT_F26Dot6Round_To_Half_Grid(TT_ExecContextexc,FT_F26Dot6distance,FT_F26Dot6compensation){FT_F26Dot6val;FT_UNUSED(exc);if(distance>=0){val=ADD_LONG(FT_PIX_FLOOR(ADD_LONG(distance,compensation)),32);if(val<0)val=32;}else{val=NEG_LONG(ADD_LONG(FT_PIX_FLOOR(SUB_LONG(compensation,distance)),32));if(val>0)val=-32;}returnval;}/*************************************************************************//* *//* <Function> *//* Round_Down_To_Grid *//* *//* <Description> *//* Rounds value down to grid after adding engine compensation. *//* *//* <Input> *//* distance :: The distance to round. *//* *//* compensation :: The engine compensation. *//* *//* <Return> *//* Rounded distance. *//* */staticFT_F26Dot6Round_Down_To_Grid(TT_ExecContextexc,FT_F26Dot6distance,FT_F26Dot6compensation){FT_F26Dot6val;FT_UNUSED(exc);if(distance>=0){val=FT_PIX_FLOOR(ADD_LONG(distance,compensation));if(val<0)val=0;}else{val=NEG_LONG(FT_PIX_FLOOR(SUB_LONG(compensation,distance)));if(val>0)val=0;}returnval;}/*************************************************************************//* *//* <Function> *//* Round_Up_To_Grid *//* *//* <Description> *//* Rounds value up to grid after adding engine compensation. *//* *//* <Input> *//* distance :: The distance to round. *//* *//* compensation :: The engine compensation. *//* *//* <Return> *//* Rounded distance. *//* */staticFT_F26Dot6Round_Up_To_Grid(TT_ExecContextexc,FT_F26Dot6distance,FT_F26Dot6compensation){FT_F26Dot6val;FT_UNUSED(exc);if(distance>=0){val=FT_PIX_CEIL_LONG(ADD_LONG(distance,compensation));if(val<0)val=0;}else{val=NEG_LONG(FT_PIX_CEIL_LONG(SUB_LONG(compensation,distance)));if(val>0)val=0;}returnval;}/*************************************************************************//* *//* <Function> *//* Round_To_Double_Grid *//* *//* <Description> *//* Rounds value to double grid after adding engine compensation. *//* *//* <Input> *//* distance :: The distance to round. *//* *//* compensation :: The engine compensation. *//* *//* <Return> *//* Rounded distance. *//* */staticFT_F26Dot6Round_To_Double_Grid(TT_ExecContextexc,FT_F26Dot6distance,FT_F26Dot6compensation){FT_F26Dot6val;FT_UNUSED(exc);if(distance>=0){val=FT_PAD_ROUND_LONG(ADD_LONG(distance,compensation),32);if(val<0)val=0;}else{val=NEG_LONG(FT_PAD_ROUND_LONG(SUB_LONG(compensation,distance),32));if(val>0)val=0;}returnval;}/*************************************************************************//* *//* <Function> *//* Round_Super *//* *//* <Description> *//* Super-rounds value to grid after adding engine compensation. *//* *//* <Input> *//* distance :: The distance to round. *//* *//* compensation :: The engine compensation. *//* *//* <Return> *//* Rounded distance. *//* *//* <Note> *//* The TrueType specification says very 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. *//* */staticFT_F26Dot6Round_Super(TT_ExecContextexc,FT_F26Dot6distance,FT_F26Dot6compensation){FT_F26Dot6val;if(distance>=0){val=ADD_LONG(distance,exc->threshold-exc->phase+compensation)&-exc->period;val=ADD_LONG(val,exc->phase);if(val<0)val=exc->phase;}else{val=NEG_LONG(SUB_LONG(exc->threshold-exc->phase+compensation,distance)&-exc->period);val=SUB_LONG(val,exc->phase);if(val>0)val=-exc->phase;}returnval;}/*************************************************************************//* *//* <Function> *//* Round_Super_45 *//* *//* <Description> *//* Super-rounds value to grid after adding engine compensation. *//* *//* <Input> *//* distance :: The distance to round. *//* *//* compensation :: The engine compensation. *//* *//* <Return> *//* Rounded distance. *//* *//* <Note> *//* There is a separate function for Round_Super_45() as we may need *//* greater precision. *//* */staticFT_F26Dot6Round_Super_45(TT_ExecContextexc,FT_F26Dot6distance,FT_F26Dot6compensation){FT_F26Dot6val;if(distance>=0){val=(ADD_LONG(distance,exc->threshold-exc->phase+compensation)/exc->period)*exc->period;val=ADD_LONG(val,exc->phase);if(val<0)val=exc->phase;}else{val=NEG_LONG((SUB_LONG(exc->threshold-exc->phase+compensation,distance)/exc->period)*exc->period);val=SUB_LONG(val,exc->phase);if(val>0)val=-exc->phase;}returnval;}/*************************************************************************//* *//* <Function> *//* Compute_Round *//* *//* <Description> *//* Sets the rounding mode. *//* *//* <Input> *//* round_mode :: The rounding mode to be used. *//* */staticvoidCompute_Round(TT_ExecContextexc,FT_Byteround_mode){switch(round_mode){caseTT_Round_Off:exc->func_round=(TT_Round_Func)Round_None;break;caseTT_Round_To_Grid:exc->func_round=(TT_Round_Func)Round_To_Grid;break;caseTT_Round_Up_To_Grid:exc->func_round=(TT_Round_Func)Round_Up_To_Grid;break;caseTT_Round_Down_To_Grid:exc->func_round=(TT_Round_Func)Round_Down_To_Grid;break;caseTT_Round_To_Half_Grid:exc->func_round=(TT_Round_Func)Round_To_Half_Grid;break;caseTT_Round_To_Double_Grid:exc->func_round=(TT_Round_Func)Round_To_Double_Grid;break;caseTT_Round_Super:exc->func_round=(TT_Round_Func)Round_Super;break;caseTT_Round_Super_45:exc->func_round=(TT_Round_Func)Round_Super_45;break;}}/*************************************************************************//* *//* <Function> *//* SetSuperRound *//* *//* <Description> *//* Sets Super Round parameters. *//* *//* <Input> *//* GridPeriod :: The grid period. *//* *//* selector :: The SROUND opcode. *//* */staticvoidSetSuperRound(TT_ExecContextexc,FT_F2Dot14GridPeriod,FT_Longselector){switch((FT_Int)(selector&0xC0)){case0:exc->period=GridPeriod/2;break;case0x40:exc->period=GridPeriod;break;case0x80:exc->period=GridPeriod*2;break;/* This opcode is reserved, but... */case0xC0:exc->period=GridPeriod;break;}switch((FT_Int)(selector&0x30)){case0:exc->phase=0;break;case0x10:exc->phase=exc->period/4;break;case0x20:exc->phase=exc->period/2;break;case0x30:exc->phase=exc->period*3/4;break;}if((selector&0x0F)==0)exc->threshold=exc->period-1;elseexc->threshold=((FT_Int)(selector&0x0F)-4)*exc->period/8;/* convert to F26Dot6 format */exc->period>>=8;exc->phase>>=8;exc->threshold>>=8;}/*************************************************************************//* *//* <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. *//* */staticFT_F26Dot6Project(TT_ExecContextexc,FT_Posdx,FT_Posdy){returnTT_DotFix14(dx,dy,exc->GS.projVector.x,exc->GS.projVector.y);}/*************************************************************************//* *//* <Function> *//* Dual_Project *//* *//* <Description> *//* Computes the projection of the vector given by (v2-v1) along the *//* current dual vector. *//* *//* <Input> *//* v1 :: First input vector. *//* v2 :: Second input vector. *//* *//* <Return> *//* The distance in F26dot6 format. *//* */staticFT_F26Dot6Dual_Project(TT_ExecContextexc,FT_Posdx,FT_Posdy){returnTT_DotFix14(dx,dy,exc->GS.dualVector.x,exc->GS.dualVector.y);}/*************************************************************************//* *//* <Function> *//* Project_x *//* *//* <Description> *//* Computes the projection of the vector given by (v2-v1) along the *//* horizontal axis. *//* *//* <Input> *//* v1 :: First input vector. *//* v2 :: Second input vector. *//* *//* <Return> *//* The distance in F26dot6 format. *//* */staticFT_F26Dot6Project_x(TT_ExecContextexc,FT_Posdx,FT_Posdy){FT_UNUSED(exc);FT_UNUSED(dy);returndx;}/*************************************************************************//* *//* <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. *//* */staticFT_F26Dot6Project_y(TT_ExecContextexc,FT_Posdx,FT_Posdy){FT_UNUSED(exc);FT_UNUSED(dx);returndy;}/*************************************************************************//* *//* <Function> *//* Compute_Funcs *//* *//* <Description> *//* Computes the projection and movement function pointers according *//* to the current graphics state. *//* */staticvoidCompute_Funcs(TT_ExecContextexc){if(exc->GS.freeVector.x==0x4000)exc->F_dot_P=exc->GS.projVector.x;elseif(exc->GS.freeVector.y==0x4000)exc->F_dot_P=exc->GS.projVector.y;elseexc->F_dot_P=((FT_Long)exc->GS.projVector.x*exc->GS.freeVector.x+(FT_Long)exc->GS.projVector.y*exc->GS.freeVector.y)>>14;if(exc->GS.projVector.x==0x4000)exc->func_project=(TT_Project_Func)Project_x;elseif(exc->GS.projVector.y==0x4000)exc->func_project=(TT_Project_Func)Project_y;elseexc->func_project=(TT_Project_Func)Project;if(exc->GS.dualVector.x==0x4000)exc->func_dualproj=(TT_Project_Func)Project_x;elseif(exc->GS.dualVector.y==0x4000)exc->func_dualproj=(TT_Project_Func)Project_y;elseexc->func_dualproj=(TT_Project_Func)Dual_Project;exc->func_move=(TT_Move_Func)Direct_Move;exc->func_move_orig=(TT_Move_Func)Direct_Move_Orig;if(exc->F_dot_P==0x4000L){if(exc->GS.freeVector.x==0x4000){exc->func_move=(TT_Move_Func)Direct_Move_X;exc->func_move_orig=(TT_Move_Func)Direct_Move_Orig_X;}elseif(exc->GS.freeVector.y==0x4000){exc->func_move=(TT_Move_Func)Direct_Move_Y;exc->func_move_orig=(TT_Move_Func)Direct_Move_Orig_Y;}}/* at small sizes, F_dot_P can become too small, resulting *//* in overflows and `spikes' in a number of glyphs like `w'. */if(FT_ABS(exc->F_dot_P)<0x400L)exc->F_dot_P=0x4000L;/* Disable cached aspect ratio */exc->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. *//* */staticFT_BoolNormalize(FT_F26Dot6Vx,FT_F26Dot6Vy,FT_UnitVector*R){FT_VectorV;if(Vx==0&&Vy==0){/* XXX: UNDOCUMENTED! It seems that it is possible to try *//* to normalize the vector (0,0). Return immediately. */returnSUCCESS;}V.x=Vx;V.y=Vy;FT_Vector_NormLen(&V);R->x=(FT_F2Dot14)(V.x/4);R->y=(FT_F2Dot14)(V.y/4);returnSUCCESS;}/*************************************************************************//* *//* Here we start with the implementation of the various opcodes. *//* *//*************************************************************************/#define ARRAY_BOUND_ERROR \ do \ { \ exc->error = FT_THROW( Invalid_Reference ); \ return; \ } while (0)/*************************************************************************//* *//* MPPEM[]: Measure Pixel Per EM *//* Opcode range: 0x4B *//* Stack: --> Euint16 *//* */staticvoidIns_MPPEM(TT_ExecContextexc,FT_Long*args){args[0]=exc->func_cur_ppem(exc);}/*************************************************************************//* *//* MPS[]: Measure Point Size *//* Opcode range: 0x4C *//* Stack: --> Euint16 *//* */staticvoidIns_MPS(TT_ExecContextexc,FT_Long*args){if(NO_SUBPIXEL_HINTING){/* Microsoft's GDI bytecode interpreter always returns value 12; *//* we return the current PPEM value instead. */args[0]=exc->func_cur_ppem(exc);}else{/* A possible practical application of the MPS instruction is to *//* implement optical scaling and similar features, which should be *//* based on perceptual attributes, thus independent of the *//* resolution. */args[0]=exc->pointSize;}}/*************************************************************************//* *//* DUP[]: DUPlicate the stack's top element *//* Opcode range: 0x20 *//* Stack: StkElt --> StkElt StkElt *//* */staticvoidIns_DUP(FT_Long*args){args[1]=args[0];}/*************************************************************************//* *//* POP[]: POP the stack's top element *//* Opcode range: 0x21 *//* Stack: StkElt --> *//* */staticvoidIns_POP(void){/* nothing to do */}/*************************************************************************//* *//* CLEAR[]: CLEAR the entire stack *//* Opcode range: 0x22 *//* Stack: StkElt... --> *//* */staticvoidIns_CLEAR(TT_ExecContextexc){exc->new_top=0;}/*************************************************************************//* *//* SWAP[]: SWAP the stack's top two elements *//* Opcode range: 0x23 *//* Stack: 2 * StkElt --> 2 * StkElt *//* */staticvoidIns_SWAP(FT_Long*args){FT_LongL;L=args[0];args[0]=args[1];args[1]=L;}/*************************************************************************//* *//* DEPTH[]: return the stack DEPTH *//* Opcode range: 0x24 *//* Stack: --> uint32 *//* */staticvoidIns_DEPTH(TT_ExecContextexc,FT_Long*args){args[0]=exc->top;}/*************************************************************************//* *//* LT[]: Less Than *//* Opcode range: 0x50 *//* Stack: int32? int32? --> bool *//* */staticvoidIns_LT(FT_Long*args){args[0]=(args[0]<args[1]);}/*************************************************************************//* *//* LTEQ[]: Less Than or EQual *//* Opcode range: 0x51 *//* Stack: int32? int32? --> bool *//* */staticvoidIns_LTEQ(FT_Long*args){args[0]=(args[0]<=args[1]);}/*************************************************************************//* *//* GT[]: Greater Than *//* Opcode range: 0x52 *//* Stack: int32? int32? --> bool *//* */staticvoidIns_GT(FT_Long*args){args[0]=(args[0]>args[1]);}/*************************************************************************//* *//* GTEQ[]: Greater Than or EQual *//* Opcode range: 0x53 *//* Stack: int32? int32? --> bool *//* */staticvoidIns_GTEQ(FT_Long*args){args[0]=(args[0]>=args[1]);}/*************************************************************************//* *//* EQ[]: EQual *//* Opcode range: 0x54 *//* Stack: StkElt StkElt --> bool *//* */staticvoidIns_EQ(FT_Long*args){args[0]=(args[0]==args[1]);}/*************************************************************************//* *//* NEQ[]: Not EQual *//* Opcode range: 0x55 *//* Stack: StkElt StkElt --> bool *//* */staticvoidIns_NEQ(FT_Long*args){args[0]=(args[0]!=args[1]);}/*************************************************************************//* *//* ODD[]: Is ODD *//* Opcode range: 0x56 *//* Stack: f26.6 --> bool *//* */staticvoidIns_ODD(TT_ExecContextexc,FT_Long*args){args[0]=((exc->func_round(exc,args[0],0)&127)==64);}/*************************************************************************//* *//* EVEN[]: Is EVEN *//* Opcode range: 0x57 *//* Stack: f26.6 --> bool *//* */staticvoidIns_EVEN(TT_ExecContextexc,FT_Long*args){args[0]=((exc->func_round(exc,args[0],0)&127)==0);}/*************************************************************************//* *//* AND[]: logical AND *//* Opcode range: 0x5A *//* Stack: uint32 uint32 --> uint32 *//* */staticvoidIns_AND(FT_Long*args){args[0]=(args[0]&&args[1]);}/*************************************************************************//* *//* OR[]: logical OR *//* Opcode range: 0x5B *//* Stack: uint32 uint32 --> uint32 *//* */staticvoidIns_OR(FT_Long*args){args[0]=(args[0]||args[1]);}/*************************************************************************//* *//* NOT[]: logical NOT *//* Opcode range: 0x5C *//* Stack: StkElt --> uint32 *//* */staticvoidIns_NOT(FT_Long*args){args[0]=!args[0];}/*************************************************************************//* *//* ADD[]: ADD *//* Opcode range: 0x60 *//* Stack: f26.6 f26.6 --> f26.6 *//* */staticvoidIns_ADD(FT_Long*args){args[0]=ADD_LONG(args[0],args[1]);}/*************************************************************************//* *//* SUB[]: SUBtract *//* Opcode range: 0x61 *//* Stack: f26.6 f26.6 --> f26.6 *//* */staticvoidIns_SUB(FT_Long*args){args[0]=SUB_LONG(args[0],args[1]);}/*************************************************************************//* *//* DIV[]: DIVide *//* Opcode range: 0x62 *//* Stack: f26.6 f26.6 --> f26.6 *//* */staticvoidIns_DIV(TT_ExecContextexc,FT_Long*args){if(args[1]==0)exc->error=FT_THROW(Divide_By_Zero);elseargs[0]=FT_MulDiv_No_Round(args[0],64L,args[1]);}/*************************************************************************//* *//* MUL[]: MULtiply *//* Opcode range: 0x63 *//* Stack: f26.6 f26.6 --> f26.6 *//* */staticvoidIns_MUL(FT_Long*args){args[0]=FT_MulDiv(args[0],args[1],64L);}/*************************************************************************//* *//* ABS[]: ABSolute value *//* Opcode range: 0x64 *//* Stack: f26.6 --> f26.6 *//* */staticvoidIns_ABS(FT_Long*args){if(args[0]<0)args[0]=NEG_LONG(args[0]);}/*************************************************************************//* *//* NEG[]: NEGate *//* Opcode range: 0x65 *//* Stack: f26.6 --> f26.6 *//* */staticvoidIns_NEG(FT_Long*args){args[0]=NEG_LONG(args[0]);}/*************************************************************************//* *//* FLOOR[]: FLOOR *//* Opcode range: 0x66 *//* Stack: f26.6 --> f26.6 *//* */staticvoidIns_FLOOR(FT_Long*args){args[0]=FT_PIX_FLOOR(args[0]);}/*************************************************************************//* *//* CEILING[]: CEILING *//* Opcode range: 0x67 *//* Stack: f26.6 --> f26.6 *//* */staticvoidIns_CEILING(FT_Long*args){args[0]=FT_PIX_CEIL_LONG(args[0]);}/*************************************************************************//* *//* RS[]: Read Store *//* Opcode range: 0x43 *//* Stack: uint32 --> uint32 *//* */staticvoidIns_RS(TT_ExecContextexc,FT_Long*args){FT_ULongI=(FT_ULong)args[0];if(BOUNDSL(I,exc->storeSize)){if(exc->pedantic_hinting)ARRAY_BOUND_ERROR;elseargs[0]=0;}else{#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY/* subpixel hinting - avoid Typeman Dstroke and *//* IStroke and Vacuform rounds */if(SUBPIXEL_HINTING_INFINALITY&&exc->ignore_x_mode&&((I==24&&(exc->face->sph_found_func_flags&(SPH_FDEF_SPACING_1|SPH_FDEF_SPACING_2)))||(I==22&&(exc->sph_in_func_flags&SPH_FDEF_TYPEMAN_STROKES))||(I==8&&(exc->face->sph_found_func_flags&SPH_FDEF_VACUFORM_ROUND_1)&&exc->iup_called)))args[0]=0;else#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */args[0]=exc->storage[I];}}/*************************************************************************//* *//* WS[]: Write Store *//* Opcode range: 0x42 *//* Stack: uint32 uint32 --> *//* */staticvoidIns_WS(TT_ExecContextexc,FT_Long*args){FT_ULongI=(FT_ULong)args[0];if(BOUNDSL(I,exc->storeSize)){if(exc->pedantic_hinting)ARRAY_BOUND_ERROR;}elseexc->storage[I]=args[1];}/*************************************************************************//* *//* WCVTP[]: Write CVT in Pixel units *//* Opcode range: 0x44 *//* Stack: f26.6 uint32 --> *//* */staticvoidIns_WCVTP(TT_ExecContextexc,FT_Long*args){FT_ULongI=(FT_ULong)args[0];if(BOUNDSL(I,exc->cvtSize)){if(exc->pedantic_hinting)ARRAY_BOUND_ERROR;}elseexc->func_write_cvt(exc,I,args[1]);}/*************************************************************************//* *//* WCVTF[]: Write CVT in Funits *//* Opcode range: 0x70 *//* Stack: uint32 uint32 --> *//* */staticvoidIns_WCVTF(TT_ExecContextexc,FT_Long*args){FT_ULongI=(FT_ULong)args[0];if(BOUNDSL(I,exc->cvtSize)){if(exc->pedantic_hinting)ARRAY_BOUND_ERROR;}elseexc->cvt[I]=FT_MulFix(args[1],exc->tt_metrics.scale);}/*************************************************************************//* *//* RCVT[]: Read CVT *//* Opcode range: 0x45 *//* Stack: uint32 --> f26.6 *//* */staticvoidIns_RCVT(TT_ExecContextexc,FT_Long*args){FT_ULongI=(FT_ULong)args[0];if(BOUNDSL(I,exc->cvtSize)){if(exc->pedantic_hinting)ARRAY_BOUND_ERROR;elseargs[0]=0;}elseargs[0]=exc->func_read_cvt(exc,I);}/*************************************************************************//* *//* AA[]: Adjust Angle *//* Opcode range: 0x7F *//* Stack: uint32 --> *//* */staticvoidIns_AA(void){/* intentionally no longer supported */}/*************************************************************************//* *//* DEBUG[]: DEBUG. Unsupported. *//* Opcode range: 0x4F *//* Stack: uint32 --> *//* *//* Note: The original instruction pops a value from the stack. *//* */staticvoidIns_DEBUG(TT_ExecContextexc){exc->error=FT_THROW(Debug_OpCode);}/*************************************************************************//* *//* ROUND[ab]: ROUND value *//* Opcode range: 0x68-0x6B *//* Stack: f26.6 --> f26.6 *//* */staticvoidIns_ROUND(TT_ExecContextexc,FT_Long*args){args[0]=exc->func_round(exc,args[0],exc->tt_metrics.compensations[exc->opcode-0x68]);}/*************************************************************************//* *//* NROUND[ab]: No ROUNDing of value *//* Opcode range: 0x6C-0x6F *//* Stack: f26.6 --> f26.6 *//* */staticvoidIns_NROUND(TT_ExecContextexc,FT_Long*args){args[0]=Round_None(exc,args[0],exc->tt_metrics.compensations[exc->opcode-0x6C]);}/*************************************************************************//* *//* MAX[]: MAXimum *//* Opcode range: 0x8B *//* Stack: int32? int32? --> int32 *//* */staticvoidIns_MAX(FT_Long*args){if(args[1]>args[0])args[0]=args[1];}/*************************************************************************//* *//* MIN[]: MINimum *//* Opcode range: 0x8C *//* Stack: int32? int32? --> int32 *//* */staticvoidIns_MIN(FT_Long*args){if(args[1]<args[0])args[0]=args[1];}/*************************************************************************//* *//* MINDEX[]: Move INDEXed element *//* Opcode range: 0x26 *//* Stack: int32? --> StkElt *//* */staticvoidIns_MINDEX(TT_ExecContextexc,FT_Long*args){FT_LongL,K;L=args[0];if(L<=0||L>exc->args){if(exc->pedantic_hinting)exc->error=FT_THROW(Invalid_Reference);}else{K=exc->stack[exc->args-L];FT_ARRAY_MOVE(&exc->stack[exc->args-L],&exc->stack[exc->args-L+1],(L-1));exc->stack[exc->args-1]=K;}}/*************************************************************************//* *//* CINDEX[]: Copy INDEXed element *//* Opcode range: 0x25 *//* Stack: int32 --> StkElt *//* */staticvoidIns_CINDEX(TT_ExecContextexc,FT_Long*args){FT_LongL;L=args[0];if(L<=0||L>exc->args){if(exc->pedantic_hinting)exc->error=FT_THROW(Invalid_Reference);args[0]=0;}elseargs[0]=exc->stack[exc->args-L];}/*************************************************************************//* *//* ROLL[]: ROLL top three elements *//* Opcode range: 0x8A *//* Stack: 3 * StkElt --> 3 * StkElt *//* */staticvoidIns_ROLL(FT_Long*args){FT_LongA,B,C;A=args[2];B=args[1];C=args[0];args[2]=C;args[1]=A;args[0]=B;}/*************************************************************************//* *//* MANAGING THE FLOW OF CONTROL *//* *//*************************************************************************//*************************************************************************//* *//* SLOOP[]: Set LOOP variable *//* Opcode range: 0x17 *//* Stack: int32? --> *//* */staticvoidIns_SLOOP(TT_ExecContextexc,FT_Long*args){if(args[0]<0)exc->error=FT_THROW(Bad_Argument);else{/* we heuristically limit the number of loops to 16 bits */exc->GS.loop=args[0]>0xFFFFL?0xFFFFL:args[0];}}staticFT_BoolSkipCode(TT_ExecContextexc){exc->IP+=exc->length;if(exc->IP<exc->codeSize){exc->opcode=exc->code[exc->IP];exc->length=opcode_length[exc->opcode];if(exc->length<0){if(exc->IP+1>=exc->codeSize)gotoFail_Overflow;exc->length=2-exc->length*exc->code[exc->IP+1];}if(exc->IP+exc->length<=exc->codeSize)returnSUCCESS;}Fail_Overflow:exc->error=FT_THROW(Code_Overflow);returnFAILURE;}/*************************************************************************//* *//* IF[]: IF test *//* Opcode range: 0x58 *//* Stack: StkElt --> *//* */staticvoidIns_IF(TT_ExecContextexc,FT_Long*args){FT_IntnIfs;FT_BoolOut;if(args[0]!=0)return;nIfs=1;Out=0;do{if(SkipCode(exc)==FAILURE)return;switch(exc->opcode){case0x58:/* IF */nIfs++;break;case0x1B:/* ELSE */Out=FT_BOOL(nIfs==1);break;case0x59:/* EIF */nIfs--;Out=FT_BOOL(nIfs==0);break;}}while(Out==0);}/*************************************************************************//* *//* ELSE[]: ELSE *//* Opcode range: 0x1B *//* Stack: --> *//* */staticvoidIns_ELSE(TT_ExecContextexc){FT_IntnIfs;nIfs=1;do{if(SkipCode(exc)==FAILURE)return;switch(exc->opcode){case0x58:/* IF */nIfs++;break;case0x59:/* EIF */nIfs--;break;}}while(nIfs!=0);}/*************************************************************************//* *//* EIF[]: End IF *//* Opcode range: 0x59 *//* Stack: --> *//* */staticvoidIns_EIF(void){/* nothing to do */}/*************************************************************************//* *//* JMPR[]: JuMP Relative *//* Opcode range: 0x1C *//* Stack: int32 --> *//* */staticvoidIns_JMPR(TT_ExecContextexc,FT_Long*args){if(args[0]==0&&exc->args==0){exc->error=FT_THROW(Bad_Argument);return;}exc->IP+=args[0];if(exc->IP<0||(exc->callTop>0&&exc->IP>exc->callStack[exc->callTop-1].Def->end)){exc->error=FT_THROW(Bad_Argument);return;}exc->step_ins=FALSE;if(args[0]<0){if(++exc->neg_jump_counter>exc->neg_jump_counter_max)exc->error=FT_THROW(Execution_Too_Long);}}/*************************************************************************//* *//* JROT[]: Jump Relative On True *//* Opcode range: 0x78 *//* Stack: StkElt int32 --> *//* */staticvoidIns_JROT(TT_ExecContextexc,FT_Long*args){if(args[1]!=0)Ins_JMPR(exc,args);}/*************************************************************************//* *//* JROF[]: Jump Relative On False *//* Opcode range: 0x79 *//* Stack: StkElt int32 --> *//* */staticvoidIns_JROF(TT_ExecContextexc,FT_Long*args){if(args[1]==0)Ins_JMPR(exc,args);}/*************************************************************************//* *//* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS *//* *//*************************************************************************//*************************************************************************//* *//* FDEF[]: Function DEFinition *//* Opcode range: 0x2C *//* Stack: uint32 --> *//* */staticvoidIns_FDEF(TT_ExecContextexc,FT_Long*args){FT_ULongn;TT_DefRecord*rec;TT_DefRecord*limit;#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY/* arguments to opcodes are skipped by `SKIP_Code' */FT_Byteopcode_pattern[9][12]={/* #0 inline delta function 1 */{0x4B,/* PPEM */0x53,/* GTEQ */0x23,/* SWAP */0x4B,/* PPEM */0x51,/* LTEQ */0x5A,/* AND */0x58,/* IF */0x38,/* SHPIX */0x1B,/* ELSE */0x21,/* POP */0x21,/* POP */0x59/* EIF */},/* #1 inline delta function 2 */{0x4B,/* PPEM */0x54,/* EQ */0x58,/* IF */0x38,/* SHPIX */0x1B,/* ELSE */0x21,/* POP */0x21,/* POP */0x59/* EIF */},/* #2 diagonal stroke function */{0x20,/* DUP */0x20,/* DUP */0xB0,/* PUSHB_1 *//* 1 */0x60,/* ADD */0x46,/* GC_cur */0xB0,/* PUSHB_1 *//* 64 */0x23,/* SWAP */0x42/* WS */},/* #3 VacuFormRound function */{0x45,/* RCVT */0x23,/* SWAP */0x46,/* GC_cur */0x60,/* ADD */0x20,/* DUP */0xB0/* PUSHB_1 *//* 38 */},/* #4 TTFautohint bytecode (old) */{0x20,/* DUP */0x64,/* ABS */0xB0,/* PUSHB_1 *//* 32 */0x60,/* ADD */0x66,/* FLOOR */0x23,/* SWAP */0xB0/* PUSHB_1 */},/* #5 spacing function 1 */{0x01,/* SVTCA_x */0xB0,/* PUSHB_1 *//* 24 */0x43,/* RS */0x58/* IF */},/* #6 spacing function 2 */{0x01,/* SVTCA_x */0x18,/* RTG */0xB0,/* PUSHB_1 *//* 24 */0x43,/* RS */0x58/* IF */},/* #7 TypeMan Talk DiagEndCtrl function */{0x01,/* SVTCA_x */0x20,/* DUP */0xB0,/* PUSHB_1 *//* 3 */0x25,/* CINDEX */},/* #8 TypeMan Talk Align */{0x06,/* SPVTL */0x7D,/* RDTG */},};FT_UShortopcode_patterns=9;FT_UShortopcode_pointer[9]={0,0,0,0,0,0,0,0,0};FT_UShortopcode_size[9]={12,8,8,6,7,4,5,4,2};FT_UShorti;#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY *//* FDEF is only allowed in `prep' or `fpgm' */if(exc->curRange==tt_coderange_glyph){exc->error=FT_THROW(DEF_In_Glyf_Bytecode);return;}/* some font programs are broken enough to redefine functions! *//* We will then parse the current table. */rec=exc->FDefs;limit=rec+exc->numFDefs;n=(FT_ULong)args[0];for(;rec<limit;rec++){if(rec->opc==n)break;}if(rec==limit){/* check that there is enough room for new functions */if(exc->numFDefs>=exc->maxFDefs){exc->error=FT_THROW(Too_Many_Function_Defs);return;}exc->numFDefs++;}/* Although FDEF takes unsigned 32-bit integer, *//* func # must be within unsigned 16-bit integer */if(n>0xFFFFU){exc->error=FT_THROW(Too_Many_Function_Defs);return;}rec->range=exc->curRange;rec->opc=(FT_UInt16)n;rec->start=exc->IP+1;rec->active=TRUE;rec->inline_delta=FALSE;rec->sph_fdef_flags=0x0000;if(n>exc->maxFunc)exc->maxFunc=(FT_UInt16)n;#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY/* We don't know for sure these are typeman functions, *//* however they are only active when RS 22 is called */if(n>=64&&n<=66)rec->sph_fdef_flags|=SPH_FDEF_TYPEMAN_STROKES;#endif/* Now skip the whole function definition. *//* We don't allow nested IDEFS & FDEFs. */while(SkipCode(exc)==SUCCESS){#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITYif(SUBPIXEL_HINTING_INFINALITY){for(i=0;i<opcode_patterns;i++){if(opcode_pointer[i]<opcode_size[i]&&exc->opcode==opcode_pattern[i][opcode_pointer[i]]){opcode_pointer[i]+=1;if(opcode_pointer[i]==opcode_size[i]){FT_TRACE6(("sph: Function %d, opcode ptrn: %d, %s %s\n",i,n,exc->face->root.family_name,exc->face->root.style_name));switch(i){case0:rec->sph_fdef_flags|=SPH_FDEF_INLINE_DELTA_1;exc->face->sph_found_func_flags|=SPH_FDEF_INLINE_DELTA_1;break;case1:rec->sph_fdef_flags|=SPH_FDEF_INLINE_DELTA_2;exc->face->sph_found_func_flags|=SPH_FDEF_INLINE_DELTA_2;break;case2:switch(n){/* needs to be implemented still */case58:rec->sph_fdef_flags|=SPH_FDEF_DIAGONAL_STROKE;exc->face->sph_found_func_flags|=SPH_FDEF_DIAGONAL_STROKE;}break;case3:switch(n){case0:rec->sph_fdef_flags|=SPH_FDEF_VACUFORM_ROUND_1;exc->face->sph_found_func_flags|=SPH_FDEF_VACUFORM_ROUND_1;}break;case4:/* probably not necessary to detect anymore */rec->sph_fdef_flags|=SPH_FDEF_TTFAUTOHINT_1;exc->face->sph_found_func_flags|=SPH_FDEF_TTFAUTOHINT_1;break;case5:switch(n){case0:case1:case2:case4:case7:case8:rec->sph_fdef_flags|=SPH_FDEF_SPACING_1;exc->face->sph_found_func_flags|=SPH_FDEF_SPACING_1;}break;case6:switch(n){case0:case1:case2:case4:case7:case8:rec->sph_fdef_flags|=SPH_FDEF_SPACING_2;exc->face->sph_found_func_flags|=SPH_FDEF_SPACING_2;}break;case7:rec->sph_fdef_flags|=SPH_FDEF_TYPEMAN_DIAGENDCTRL;exc->face->sph_found_func_flags|=SPH_FDEF_TYPEMAN_DIAGENDCTRL;break;case8:#if 0 rec->sph_fdef_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL; exc->face->sph_found_func_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL;#endifbreak;}opcode_pointer[i]=0;}}elseopcode_pointer[i]=0;}/* Set sph_compatibility_mode only when deltas are detected */exc->face->sph_compatibility_mode=((exc->face->sph_found_func_flags&SPH_FDEF_INLINE_DELTA_1)|(exc->face->sph_found_func_flags&SPH_FDEF_INLINE_DELTA_2));}#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */switch(exc->opcode){case0x89:/* IDEF */case0x2C:/* FDEF */exc->error=FT_THROW(Nested_DEFS);return;case0x2D:/* ENDF */rec->end=exc->IP;return;}}}/*************************************************************************//* *//* ENDF[]: END Function definition *//* Opcode range: 0x2D *//* Stack: --> *//* */staticvoidIns_ENDF(TT_ExecContextexc){TT_CallRec*pRec;#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITYexc->sph_in_func_flags=0x0000;#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */if(exc->callTop<=0)/* We encountered an ENDF without a call */{exc->error=FT_THROW(ENDF_In_Exec_Stream);return;}exc->callTop--;pRec=&exc->callStack[exc->callTop];pRec->Cur_Count--;exc->step_ins=FALSE;if(pRec->Cur_Count>0){exc->callTop++;exc->IP=pRec->Def->start;}else/* Loop through the current function */Ins_Goto_CodeRange(exc,pRec->Caller_Range,pRec->Caller_IP);/* Exit the current call frame. *//* NOTE: If the last instruction of a program is a *//* CALL or LOOPCALL, the return address is *//* always out of the code range. This is a *//* valid address, and it is why we do not test *//* the result of Ins_Goto_CodeRange() here! */}/*************************************************************************//* *//* CALL[]: CALL function *//* Opcode range: 0x2B *//* Stack: uint32? --> *//* */staticvoidIns_CALL(TT_ExecContextexc,FT_Long*args){FT_ULongF;TT_CallRec*pCrec;TT_DefRecord*def;/* first of all, check the index */F=(FT_ULong)args[0];if(BOUNDSL(F,exc->maxFunc+1))gotoFail;/* Except for some old Apple fonts, all functions in a TrueType *//* font are defined in increasing order, starting from 0. This *//* means that we normally have *//* *//* exc->maxFunc+1 == exc->numFDefs *//* exc->FDefs[n].opc == n for n in 0..exc->maxFunc *//* *//* If this isn't true, we need to look up the function table. */def=exc->FDefs+F;if(exc->maxFunc+1!=exc->numFDefs||def->opc!=F){/* look up the FDefs table */TT_DefRecord*limit;def=exc->FDefs;limit=def+exc->numFDefs;while(def<limit&&def->opc!=F)def++;if(def==limit)gotoFail;}/* check that the function is active */if(!def->active)gotoFail;#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITYif(SUBPIXEL_HINTING_INFINALITY&&exc->ignore_x_mode&&((exc->iup_called&&(exc->sph_tweak_flags&SPH_TWEAK_NO_CALL_AFTER_IUP))||(def->sph_fdef_flags&SPH_FDEF_VACUFORM_ROUND_1)))gotoFail;elseexc->sph_in_func_flags=def->sph_fdef_flags;#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY *//* check the call stack */if(exc->callTop>=exc->callSize){exc->error=FT_THROW(Stack_Overflow);return;}pCrec=exc->callStack+exc->callTop;pCrec->Caller_Range=exc->curRange;pCrec->Caller_IP=exc->IP+1;pCrec->Cur_Count=1;pCrec->Def=def;exc->callTop++;Ins_Goto_CodeRange(exc,def->range,def->start);exc->step_ins=FALSE;return;Fail:exc->error=FT_THROW(Invalid_Reference);}/*************************************************************************//* *//* LOOPCALL[]: LOOP and CALL function *//* Opcode range: 0x2A *//* Stack: uint32? Eint16? --> *//* */staticvoidIns_LOOPCALL(TT_ExecContextexc,FT_Long*args){FT_ULongF;TT_CallRec*pCrec;TT_DefRecord*def;/* first of all, check the index */F=(FT_ULong)args[1];if(BOUNDSL(F,exc->maxFunc+1))gotoFail;/* Except for some old Apple fonts, all functions in a TrueType *//* font are defined in increasing order, starting from 0. This *//* means that we normally have *//* *//* exc->maxFunc+1 == exc->numFDefs *//* exc->FDefs[n].opc == n for n in 0..exc->maxFunc *//* *//* If this isn't true, we need to look up the function table. */def=exc->FDefs+F;if(exc->maxFunc+1!=exc->numFDefs||def->opc!=F){/* look up the FDefs table */TT_DefRecord*limit;def=exc->FDefs;limit=def+exc->numFDefs;while(def<limit&&def->opc!=F)def++;if(def==limit)gotoFail;}/* check that the function is active */if(!def->active)gotoFail;#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITYif(SUBPIXEL_HINTING_INFINALITY&&exc->ignore_x_mode&&(def->sph_fdef_flags&SPH_FDEF_VACUFORM_ROUND_1))gotoFail;elseexc->sph_in_func_flags=def->sph_fdef_flags;#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY *//* check stack */if(exc->callTop>=exc->callSize){exc->error=FT_THROW(Stack_Overflow);return;}if(args[0]>0){pCrec=exc->callStack+exc->callTop;pCrec->Caller_Range=exc->curRange;pCrec->Caller_IP=exc->IP+1;pCrec->Cur_Count=(FT_Int)args[0];pCrec->Def=def;exc->callTop++;Ins_Goto_CodeRange(exc,def->range,def->start);exc->step_ins=FALSE;exc->loopcall_counter+=(FT_ULong)args[0];if(exc->loopcall_counter>exc->loopcall_counter_max)exc->error=FT_THROW(Execution_Too_Long);}return;Fail:exc->error=FT_THROW(Invalid_Reference);}/*************************************************************************//* *//* IDEF[]: Instruction DEFinition *//* Opcode range: 0x89 *//* Stack: Eint8 --> *//* */staticvoidIns_IDEF(TT_ExecContextexc,FT_Long*args){TT_DefRecord*def;TT_DefRecord*limit;/* we enable IDEF only in `prep' or `fpgm' */if(exc->curRange==tt_coderange_glyph){exc->error=FT_THROW(DEF_In_Glyf_Bytecode);return;}/* First of all, look for the same function in our table */def=exc->IDefs;limit=def+exc->numIDefs;for(;def<limit;def++)if(def->opc==(FT_ULong)args[0])break;if(def==limit){/* check that there is enough room for a new instruction */if(exc->numIDefs>=exc->maxIDefs){exc->error=FT_THROW(Too_Many_Instruction_Defs);return;}exc->numIDefs++;}/* opcode must be unsigned 8-bit integer */if(0>args[0]||args[0]>0x00FF){exc->error=FT_THROW(Too_Many_Instruction_Defs);return;}def->opc=(FT_Byte)args[0];def->start=exc->IP+1;def->range=exc->curRange;def->active=TRUE;if((FT_ULong)args[0]>exc->maxIns)exc->maxIns=(FT_Byte)args[0];/* Now skip the whole function definition. *//* We don't allow nested IDEFs & FDEFs. */while(SkipCode(exc)==SUCCESS){switch(exc->opcode){case0x89:/* IDEF */case0x2C:/* FDEF */exc->error=FT_THROW(Nested_DEFS);return;case0x2D:/* ENDF */def->end=exc->IP;return;}}}/*************************************************************************//* *//* PUSHING DATA ONTO THE INTERPRETER STACK *//* *//*************************************************************************//*************************************************************************//* *//* NPUSHB[]: PUSH N Bytes *//* Opcode range: 0x40 *//* Stack: --> uint32... *//* */staticvoidIns_NPUSHB(TT_ExecContextexc,FT_Long*args){FT_UShortL,K;L=(FT_UShort)exc->code[exc->IP+1];if(BOUNDS(L,exc->stackSize+1-exc->top)){exc->error=FT_THROW(Stack_Overflow);return;}for(K=1;K<=L;K++)args[K-1]=exc->code[exc->IP+K+1];exc->new_top+=L;}/*************************************************************************//* *//* NPUSHW[]: PUSH N Words *//* Opcode range: 0x41 *//* Stack: --> int32... *//* */staticvoidIns_NPUSHW(TT_ExecContextexc,FT_Long*args){FT_UShortL,K;L=(FT_UShort)exc->code[exc->IP+1];if(BOUNDS(L,exc->stackSize+1-exc->top)){exc->error=FT_THROW(Stack_Overflow);return;}exc->IP+=2;for(K=0;K<L;K++)args[K]=GetShortIns(exc);exc->step_ins=FALSE;exc->new_top+=L;}/*************************************************************************//* *//* PUSHB[abc]: PUSH Bytes *//* Opcode range: 0xB0-0xB7 *//* Stack: --> uint32... *//* */staticvoidIns_PUSHB(TT_ExecContextexc,FT_Long*args){FT_UShortL,K;L=(FT_UShort)(exc->opcode-0xB0+1);if(BOUNDS(L,exc->stackSize+1-exc->top)){exc->error=FT_THROW(Stack_Overflow);return;}for(K=1;K<=L;K++)args[K-1]=exc->code[exc->IP+K];}/*************************************************************************//* *//* PUSHW[abc]: PUSH Words *//* Opcode range: 0xB8-0xBF *//* Stack: --> int32... *//* */staticvoidIns_PUSHW(TT_ExecContextexc,FT_Long*args){FT_UShortL,K;L=(FT_UShort)(exc->opcode-0xB8+1);if(BOUNDS(L,exc->stackSize+1-exc->top)){exc->error=FT_THROW(Stack_Overflow);return;}exc->IP++;for(K=0;K<L;K++)args[K]=GetShortIns(exc);exc->step_ins=FALSE;}/*************************************************************************//* *//* MANAGING THE GRAPHICS STATE *//* *//*************************************************************************/staticFT_BoolIns_SxVTL(TT_ExecContextexc,FT_UShortaIdx1,FT_UShortaIdx2,FT_UnitVector*Vec){FT_LongA,B,C;FT_Vector*p1;FT_Vector*p2;FT_Byteopcode=exc->opcode;if(BOUNDS(aIdx1,exc->zp2.n_points)||BOUNDS(aIdx2,exc->zp1.n_points)){if(exc->pedantic_hinting)exc->error=FT_THROW(Invalid_Reference);returnFAILURE;}p1=exc->zp1.cur+aIdx2;p2=exc->zp2.cur+aIdx1;A=SUB_LONG(p1->x,p2->x);B=SUB_LONG(p1->y,p2->y);/* If p1 == p2, SPvTL and SFvTL behave the same as *//* SPvTCA[X] and SFvTCA[X], respectively. *//* *//* Confirmed by Greg Hitchcock. */if(A==0&&B==0){A=0x4000;opcode=0;}if((opcode&1)!=0){C=B;/* counter clockwise rotation */B=A;A=NEG_LONG(C);}Normalize(A,B,Vec);returnSUCCESS;}/*************************************************************************//* *//* 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: --> *//* */staticvoidIns_SxyTCA(TT_ExecContextexc){FT_ShortAA,BB;FT_Byteopcode=exc->opcode;AA=(FT_Short)((opcode&1)<<14);BB=(FT_Short)(AA^0x4000);if(opcode<4){exc->GS.projVector.x=AA;exc->GS.projVector.y=BB;exc->GS.dualVector.x=AA;exc->GS.dualVector.y=BB;}if((opcode&2)==0){exc->GS.freeVector.x=AA;exc->GS.freeVector.y=BB;}Compute_Funcs(exc);}/*************************************************************************//* *//* SPvTL[a]: Set PVector To Line *//* Opcode range: 0x06-0x07 *//* Stack: uint32 uint32 --> *//* */staticvoidIns_SPVTL(TT_ExecContextexc,FT_Long*args){if(Ins_SxVTL(exc,(FT_UShort)args[1],(FT_UShort)args[0],&exc->GS.projVector)==SUCCESS){exc->GS.dualVector=exc->GS.projVector;Compute_Funcs(exc);}}/*************************************************************************//* *//* SFvTL[a]: Set FVector To Line *//* Opcode range: 0x08-0x09 *//* Stack: uint32 uint32 --> *//* */staticvoidIns_SFVTL(TT_ExecContextexc,FT_Long*args){if(Ins_SxVTL(exc,(FT_UShort)args[1],(FT_UShort)args[0],&exc->GS.freeVector)==SUCCESS){Compute_Funcs(exc);}}/*************************************************************************//* *//* SFvTPv[]: Set FVector To PVector *//* Opcode range: 0x0E *//* Stack: --> *//* */staticvoidIns_SFVTPV(TT_ExecContextexc){exc->GS.freeVector=exc->GS.projVector;Compute_Funcs(exc);}/*************************************************************************//* *//* SPvFS[]: Set PVector From Stack *//* Opcode range: 0x0A *//* Stack: f2.14 f2.14 --> *//* */staticvoidIns_SPVFS(TT_ExecContextexc,FT_Long*args){FT_ShortS;FT_LongX,Y;/* Only use low 16bits, then sign extend */S=(FT_Short)args[1];Y=(FT_Long)S;S=(FT_Short)args[0];X=(FT_Long)S;Normalize(X,Y,&exc->GS.projVector);exc->GS.dualVector=exc->GS.projVector;Compute_Funcs(exc);}/*************************************************************************//* *//* SFvFS[]: Set FVector From Stack *//* Opcode range: 0x0B *//* Stack: f2.14 f2.14 --> *//* */staticvoidIns_SFVFS(TT_ExecContextexc,FT_Long*args){FT_ShortS;FT_LongX,Y;/* Only use low 16bits, then sign extend */S=(FT_Short)args[1];Y=(FT_Long)S;S=(FT_Short)args[0];X=S;Normalize(X,Y,&exc->GS.freeVector);Compute_Funcs(exc);}/*************************************************************************//* *//* GPv[]: Get Projection Vector *//* Opcode range: 0x0C *//* Stack: ef2.14 --> ef2.14 *//* */staticvoidIns_GPV(TT_ExecContextexc,FT_Long*args){args[0]=exc->GS.projVector.x;args[1]=exc->GS.projVector.y;}/*************************************************************************//* *//* GFv[]: Get Freedom Vector *//* Opcode range: 0x0D *//* Stack: ef2.14 --> ef2.14 *//* */staticvoidIns_GFV(TT_ExecContextexc,FT_Long*args){args[0]=exc->GS.freeVector.x;args[1]=exc->GS.freeVector.y;}/*************************************************************************//* *//* SRP0[]: Set Reference Point 0 *//* Opcode range: 0x10 *//* Stack: uint32 --> *//* */staticvoidIns_SRP0(TT_ExecContextexc,FT_Long*args){exc->GS.rp0=(FT_UShort)args[0];}/*************************************************************************//* *//* SRP1[]: Set Reference Point 1 *//* Opcode range: 0x11 *//* Stack: uint32 --> *//* */staticvoidIns_SRP1(TT_ExecContextexc,FT_Long*args){exc->GS.rp1=(FT_UShort)args[0];}/*************************************************************************//* *//* SRP2[]: Set Reference Point 2 *//* Opcode range: 0x12 *//* Stack: uint32 --> *//* */staticvoidIns_SRP2(TT_ExecContextexc,FT_Long*args){exc->GS.rp2=(FT_UShort)args[0];}/*************************************************************************//* *//* SMD[]: Set Minimum Distance *//* Opcode range: 0x1A *//* Stack: f26.6 --> *//* */staticvoidIns_SMD(TT_ExecContextexc,FT_Long*args){exc->GS.minimum_distance=args[0];}/*************************************************************************//* *//* SCVTCI[]: Set Control Value Table Cut In *//* Opcode range: 0x1D *//* Stack: f26.6 --> *//* */staticvoidIns_SCVTCI(TT_ExecContextexc,FT_Long*args){exc->GS.control_value_cutin=(FT_F26Dot6)args[0];}/*************************************************************************//* *//* SSWCI[]: Set Single Width Cut In *//* Opcode range: 0x1E *//* Stack: f26.6 --> *//* */staticvoidIns_SSWCI(TT_ExecContextexc,FT_Long*args){exc->GS.single_width_cutin=(FT_F26Dot6)args[0];}/*************************************************************************//* *//* SSW[]: Set Single Width *//* Opcode range: 0x1F *//* Stack: int32? --> *//* */staticvoidIns_SSW(TT_ExecContextexc,FT_Long*args){exc->GS.single_width_value=FT_MulFix(args[0],exc->tt_metrics.scale);}/*************************************************************************//* *//* FLIPON[]: Set auto-FLIP to ON *//* Opcode range: 0x4D *//* Stack: --> *//* */staticvoidIns_FLIPON(TT_ExecContextexc){exc->GS.auto_flip=TRUE;}/*************************************************************************//* *//* FLIPOFF[]: Set auto-FLIP to OFF *//* Opcode range: 0x4E *//* Stack: --> *//* */staticvoidIns_FLIPOFF(TT_ExecContextexc){exc->GS.auto_flip=FALSE;}/*************************************************************************//* *//* SANGW[]: Set ANGle Weight *//* Opcode range: 0x7E *//* Stack: uint32 --> *//* */staticvoidIns_SANGW(void){/* instruction not supported anymore */}/*************************************************************************//* *//* SDB[]: Set Delta Base *//* Opcode range: 0x5E *//* Stack: uint32 --> *//* */staticvoidIns_SDB(TT_ExecContextexc,FT_Long*args){exc->GS.delta_base=(FT_UShort)args[0];}/*************************************************************************//* *//* SDS[]: Set Delta Shift *//* Opcode range: 0x5F *//* Stack: uint32 --> *//* */staticvoidIns_SDS(TT_ExecContextexc,FT_Long*args){if((FT_ULong)args[0]>6UL)exc->error=FT_THROW(Bad_Argument);elseexc->GS.delta_shift=(FT_UShort)args[0];}/*************************************************************************//* *//* RTHG[]: Round To Half Grid *//* Opcode range: 0x19 *//* Stack: --> *//* */staticvoidIns_RTHG(TT_ExecContextexc){exc->GS.round_state=TT_Round_To_Half_Grid;exc->func_round=(TT_Round_Func)Round_To_Half_Grid;}/*************************************************************************//* *//* RTG[]: Round To Grid *//* Opcode range: 0x18 *//* Stack: --> *//* */staticvoidIns_RTG(TT_ExecContextexc){exc->GS.round_state=TT_Round_To_Grid;exc->func_round=(TT_Round_Func)Round_To_Grid;}/*************************************************************************//* RTDG[]: Round To Double Grid *//* Opcode range: 0x3D *//* Stack: --> *//* */staticvoidIns_RTDG(TT_ExecContextexc){exc->GS.round_state=TT_Round_To_Double_Grid;exc->func_round=(TT_Round_Func)Round_To_Double_Grid;}/*************************************************************************//* RUTG[]: Round Up To Grid *//* Opcode range: 0x7C *//* Stack: --> *//* */staticvoidIns_RUTG(TT_ExecContextexc){exc->GS.round_state=TT_Round_Up_To_Grid;exc->func_round=(TT_Round_Func)Round_Up_To_Grid;}/*************************************************************************//* *//* RDTG[]: Round Down To Grid *//* Opcode range: 0x7D *//* Stack: --> *//* */staticvoidIns_RDTG(TT_ExecContextexc){exc->GS.round_state=TT_Round_Down_To_Grid;exc->func_round=(TT_Round_Func)Round_Down_To_Grid;}/*************************************************************************//* *//* ROFF[]: Round OFF *//* Opcode range: 0x7A *//* Stack: --> *//* */staticvoidIns_ROFF(TT_ExecContextexc){exc->GS.round_state=TT_Round_Off;exc->func_round=(TT_Round_Func)Round_None;}/*************************************************************************//* *//* SROUND[]: Super ROUND *//* Opcode range: 0x76 *//* Stack: Eint8 --> *//* */staticvoidIns_SROUND(TT_ExecContextexc,FT_Long*args){SetSuperRound(exc,0x4000,args[0]);exc->GS.round_state=TT_Round_Super;exc->func_round=(TT_Round_Func)Round_Super;}/*************************************************************************//* *//* S45ROUND[]: Super ROUND 45 degrees *//* Opcode range: 0x77 *//* Stack: uint32 --> *//* */staticvoidIns_S45ROUND(TT_ExecContextexc,FT_Long*args){SetSuperRound(exc,0x2D41,args[0]);exc->GS.round_state=TT_Round_Super_45;exc->func_round=(TT_Round_Func)Round_Super_45;}/*************************************************************************//* *//* 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! *//* */staticvoidIns_GC(TT_ExecContextexc,FT_Long*args){FT_ULongL;FT_F26Dot6R;L=(FT_ULong)args[0];if(BOUNDSL(L,exc->zp2.n_points)){if(exc->pedantic_hinting)exc->error=FT_THROW(Invalid_Reference);R=0;}else{if(exc->opcode&1)R=FAST_DUALPROJ(&exc->zp2.org[L]);elseR=FAST_PROJECT(&exc->zp2.cur[L]);}args[0]=R;}/*************************************************************************//* *//* SCFS[]: Set Coordinate From Stack *//* Opcode range: 0x48 *//* Stack: f26.6 uint32 --> *//* *//* Formula: *//* *//* OA := OA + ( value - OA.p )/( f.p ) * f *//* */staticvoidIns_SCFS(TT_ExecContextexc,FT_Long*args){FT_LongK;FT_UShortL;L=(FT_UShort)args[0];if(BOUNDS(L,exc->zp2.n_points)){if(exc->pedantic_hinting)exc->error=FT_THROW(Invalid_Reference);return;}K=FAST_PROJECT(&exc->zp2.cur[L]);exc->func_move(exc,&exc->zp2,L,SUB_LONG(args[1],K));/* UNDOCUMENTED! The MS rasterizer does that with *//* twilight points (confirmed by Greg Hitchcock) */if(exc->GS.gep2==0)exc->zp2.org[L]=exc->zp2.cur[L];}/*************************************************************************//* *//* 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! *//* */staticvoidIns_MD(TT_ExecContextexc,FT_Long*args){FT_UShortK,L;FT_F26Dot6D;K=(FT_UShort)args[1];L=(FT_UShort)args[0];if(BOUNDS(L,exc->zp0.n_points)||BOUNDS(K,exc->zp1.n_points)){if(exc->pedantic_hinting)exc->error=FT_THROW(Invalid_Reference);D=0;}else{if(exc->opcode&1)D=PROJECT(exc->zp0.cur+L,exc->zp1.cur+K);else{/* XXX: UNDOCUMENTED: twilight zone special case */if(exc->GS.gep0==0||exc->GS.gep1==0){FT_Vector*vec1=exc->zp0.org+L;FT_Vector*vec2=exc->zp1.org+K;D=DUALPROJ(vec1,vec2);}else{FT_Vector*vec1=exc->zp0.orus+L;FT_Vector*vec2=exc->zp1.orus+K;if(exc->metrics.x_scale==exc->metrics.y_scale){/* this should be faster */D=DUALPROJ(vec1,vec2);D=FT_MulFix(D,exc->metrics.x_scale);}else{FT_Vectorvec;vec.x=FT_MulFix(vec1->x-vec2->x,exc->metrics.x_scale);vec.y=FT_MulFix(vec1->y-vec2->y,exc->metrics.y_scale);D=FAST_DUALPROJ(&vec);}}}}#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY/* Disable Type 2 Vacuform Rounds - e.g. Arial Narrow */if(SUBPIXEL_HINTING_INFINALITY&&exc->ignore_x_mode&&FT_ABS(D)==64)D+=1;#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */args[0]=D;}/*************************************************************************//* *//* SDPvTL[a]: Set Dual PVector to Line *//* Opcode range: 0x86-0x87 *//* Stack: uint32 uint32 --> *//* */staticvoidIns_SDPVTL(TT_ExecContextexc,FT_Long*args){FT_LongA,B,C;FT_UShortp1,p2;/* was FT_Int in pas type ERROR */FT_Byteopcode=exc->opcode;p1=(FT_UShort)args[1];p2=(FT_UShort)args[0];if(BOUNDS(p2,exc->zp1.n_points)||BOUNDS(p1,exc->zp2.n_points)){if(exc->pedantic_hinting)exc->error=FT_THROW(Invalid_Reference);return;}{FT_Vector*v1=exc->zp1.org+p2;FT_Vector*v2=exc->zp2.org+p1;A=SUB_LONG(v1->x,v2->x);B=SUB_LONG(v1->y,v2->y);/* If v1 == v2, SDPvTL behaves the same as *//* SVTCA[X], respectively. *//* *//* Confirmed by Greg Hitchcock. */if(A==0&&B==0){A=0x4000;opcode=0;}}if((opcode&1)!=0){C=B;/* counter clockwise rotation */B=A;A=NEG_LONG(C);}Normalize(A,B,&exc->GS.dualVector);{FT_Vector*v1=exc->zp1.cur+p2;FT_Vector*v2=exc->zp2.cur+p1;A=SUB_LONG(v1->x,v2->x);B=SUB_LONG(v1->y,v2->y);if(A==0&&B==0){A=0x4000;opcode=0;}}if((opcode&1)!=0){C=B;/* counter clockwise rotation */B=A;A=NEG_LONG(C);}Normalize(A,B,&exc->GS.projVector);Compute_Funcs(exc);}/*************************************************************************//* *//* SZP0[]: Set Zone Pointer 0 *//* Opcode range: 0x13 *//* Stack: uint32 --> *//* */staticvoidIns_SZP0(TT_ExecContextexc,FT_Long*args){switch((FT_Int)args[0]){case0:exc->zp0=exc->twilight;break;case1:exc->zp0=exc->pts;break;default:if(exc->pedantic_hinting)exc->error=FT_THROW(Invalid_Reference);return;}exc->GS.gep0=(FT_UShort)args[0];}/*************************************************************************//* *//* SZP1[]: Set Zone Pointer 1 *//* Opcode range: 0x14 *//* Stack: uint32 --> *//* */staticvoidIns_SZP1(TT_ExecContextexc,FT_Long*args){switch((FT_Int)args[0]){case0:exc->zp1=exc->twilight;break;case1:exc->zp1=exc->pts;break;default:if(exc->pedantic_hinting)exc->error=FT_THROW(Invalid_Reference);return;}exc->GS.gep1=(FT_UShort)args[0];}/*************************************************************************//* *//* SZP2[]: Set Zone Pointer 2 *//* Opcode range: 0x15 *//* Stack: uint32 --> *//* */staticvoidIns_SZP2(TT_ExecContextexc,FT_Long*args){switch((FT_Int)args[0]){case0:exc->zp2=exc->twilight;break;case1:exc->zp2=exc->pts;break;default:if(exc->pedantic_hinting)exc->error=FT_THROW(Invalid_Reference);return;}exc->GS.gep2=(FT_UShort)args[0];}/*************************************************************************//* *//* SZPS[]: Set Zone PointerS *//* Opcode range: 0x16 *//* Stack: uint32 --> *//* */staticvoidIns_SZPS(TT_ExecContextexc,FT_Long*args){switch((FT_Int)args[0]){case0:exc->zp0=exc->twilight;break;case1:exc->zp0=exc->pts;break;default:if(exc->pedantic_hinting)exc->error=FT_THROW(Invalid_Reference);return;}exc->zp1=exc->zp0;exc->zp2=exc->zp0;exc->GS.gep0=(FT_UShort)args[0];exc->GS.gep1=(FT_UShort)args[0];exc->GS.gep2=(FT_UShort)args[0];}/*************************************************************************//* *//* INSTCTRL[]: INSTruction ConTRoL *//* Opcode range: 0x8E *//* Stack: int32 int32 --> *//* */staticvoidIns_INSTCTRL(TT_ExecContextexc,FT_Long*args){FT_ULongK,L,Kf;K=(FT_ULong)args[1];L=(FT_ULong)args[0];/* selector values cannot be `OR'ed; *//* they are indices starting with index 1, not flags */if(K<1||K>3){if(exc->pedantic_hinting)exc->error=FT_THROW(Invalid_Reference);return;}/* convert index to flag value */Kf=1<<(K-1);if(L!=0){/* arguments to selectors look like flag values */if(L!=Kf){if(exc->pedantic_hinting)exc->error=FT_THROW(Invalid_Reference);return;}}exc->GS.instruct_control&=~(FT_Byte)Kf;exc->GS.instruct_control|=(FT_Byte)L;if(K==3){#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY/* INSTCTRL modifying flag 3 also has an effect *//* outside of the CVT program */if(SUBPIXEL_HINTING_INFINALITY)exc->ignore_x_mode=FT_BOOL(L==4);#endif#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL/* Native ClearType fonts sign a waiver that turns off all backward *//* compatibility hacks and lets them program points to the grid like *//* it's 1996. They might sign a waiver for just one glyph, though. */if(SUBPIXEL_HINTING_MINIMAL)exc->backward_compatibility=!FT_BOOL(L==4);#endif}}/*************************************************************************//* *//* SCANCTRL[]: SCAN ConTRoL *//* Opcode range: 0x85 *//* Stack: uint32? --> *//* */staticvoidIns_SCANCTRL(TT_ExecContextexc,FT_Long*args){FT_IntA;/* Get Threshold */A=(FT_Int)(args[0]&0xFF);if(A==0xFF){exc->GS.scan_control=TRUE;return;}elseif(A==0){exc->GS.scan_control=FALSE;return;}if((args[0]&0x100)!=0&&exc->tt_metrics.ppem<=A)exc->GS.scan_control=TRUE;if((args[0]&0x200)!=0&&exc->tt_metrics.rotated)exc->GS.scan_control=TRUE;if((args[0]&0x400)!=0&&exc->tt_metrics.stretched)exc->GS.scan_control=TRUE;if((args[0]&0x800)!=0&&exc->tt_metrics.ppem>A)exc->GS.scan_control=FALSE;if((args[0]&0x1000)!=0&&exc->tt_metrics.rotated)exc->GS.scan_control=FALSE;if((args[0]&0x2000)!=0&&exc->tt_metrics.stretched)exc->GS.scan_control=FALSE;}/*************************************************************************//* *//* SCANTYPE[]: SCAN TYPE *//* Opcode range: 0x8D *//* Stack: uint16 --> *//* */staticvoidIns_SCANTYPE(TT_ExecContextexc,FT_Long*args){if(args[0]>=0)exc->GS.scan_type=(FT_Int)args[0]&0xFFFF;}/*************************************************************************//* *//* MANAGING OUTLINES *//* *//*************************************************************************//*************************************************************************//* *//* FLIPPT[]: FLIP PoinT *//* Opcode range: 0x80 *//* Stack: uint32... --> *//* */staticvoidIns_FLIPPT(TT_ExecContextexc){FT_UShortpoint;#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL/* See `ttinterp.h' for details on backward compatibility mode. */if(SUBPIXEL_HINTING_MINIMAL&&exc->backward_compatibility&&exc->iupx_called&&exc->iupy_called)gotoFail;#endifif(exc->top<exc->GS.loop){if(exc->pedantic_hinting)exc->error=FT_THROW(Too_Few_Arguments);gotoFail;}while(exc->GS.loop>0){exc->args--;point=(FT_UShort)exc->stack[exc->args];if(BOUNDS(point,exc->pts.n_points)){if(exc->pedantic_hinting){exc->error=FT_THROW(Invalid_Reference);return;}}elseexc->pts.tags[point]^=FT_CURVE_TAG_ON;exc->GS.loop--;}Fail:exc->GS.loop=1;exc->new_top=exc->args;}/*************************************************************************//* *//* FLIPRGON[]: FLIP RanGe ON *//* Opcode range: 0x81 *//* Stack: uint32 uint32 --> *//* */staticvoidIns_FLIPRGON(TT_ExecContextexc,FT_Long*args){FT_UShortI,K,L;#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL/* See `ttinterp.h' for details on backward compatibility mode. */if(SUBPIXEL_HINTING_MINIMAL&&exc->backward_compatibility&&exc->iupx_called&&exc->iupy_called)return;#endifK=(FT_UShort)args[1];L=(FT_UShort)args[0];if(BOUNDS(K,exc->pts.n_points)||BOUNDS(L,exc->pts.n_points)){if(exc->pedantic_hinting)exc->error=FT_THROW(Invalid_Reference);return;}for(I=L;I<=K;I++)exc->pts.tags[I]|=FT_CURVE_TAG_ON;}/*************************************************************************//* *//* FLIPRGOFF: FLIP RanGe OFF *//* Opcode range: 0x82 *//* Stack: uint32 uint32 --> *//* */staticvoidIns_FLIPRGOFF(TT_ExecContextexc,FT_Long*args){FT_UShortI,K,L;#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL/* See `ttinterp.h' for details on backward compatibility mode. */if(SUBPIXEL_HINTING_MINIMAL&&exc->backward_compatibility&&exc->iupx_called&&exc->iupy_called)return;#endifK=(FT_UShort)args[1];L=(FT_UShort)args[0];if(BOUNDS(K,exc->pts.n_points)||BOUNDS(L,exc->pts.n_points)){if(exc->pedantic_hinting)exc->error=FT_THROW(Invalid_Reference);return;}for(I=L;I<=K;I++)exc->pts.tags[I]&=~FT_CURVE_TAG_ON;}staticFT_BoolCompute_Point_Displacement(TT_ExecContextexc,FT_F26Dot6*x,FT_F26Dot6*y,TT_GlyphZonezone,FT_UShort*refp){TT_GlyphZoneReczp;FT_UShortp;FT_F26Dot6d;if(exc->opcode&1){zp=exc->zp0;p=exc->GS.rp1;}else{zp=exc->zp1;p=exc->GS.rp2;}if(BOUNDS(p,zp.n_points)){if(exc->pedantic_hinting)exc->error=FT_THROW(Invalid_Reference);*refp=0;returnFAILURE;}*zone=zp;*refp=p;d=PROJECT(zp.cur+p,zp.org+p);*x=FT_MulDiv(d,(FT_Long)exc->GS.freeVector.x,exc->F_dot_P);*y=FT_MulDiv(d,(FT_Long)exc->GS.freeVector.y,exc->F_dot_P);returnSUCCESS;}/* See `ttinterp.h' for details on backward compatibility mode. */staticvoidMove_Zp2_Point(TT_ExecContextexc,FT_UShortpoint,FT_F26Dot6dx,FT_F26Dot6dy,FT_Booltouch){if(exc->GS.freeVector.x!=0){#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMALif(!(SUBPIXEL_HINTING_MINIMAL&&exc->backward_compatibility))#endifexc->zp2.cur[point].x=ADD_LONG(exc->zp2.cur[point].x,dx);if(touch)exc->zp2.tags[point]|=FT_CURVE_TAG_TOUCH_X;}if(exc->GS.freeVector.y!=0){#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMALif(!(SUBPIXEL_HINTING_MINIMAL&&exc->backward_compatibility&&exc->iupx_called&&exc->iupy_called))#endifexc->zp2.cur[point].y=ADD_LONG(exc->zp2.cur[point].y,dy);if(touch)exc->zp2.tags[point]|=FT_CURVE_TAG_TOUCH_Y;}}/*************************************************************************//* *//* SHP[a]: SHift Point by the last point *//* Opcode range: 0x32-0x33 *//* Stack: uint32... --> *//* */staticvoidIns_SHP(TT_ExecContextexc){TT_GlyphZoneReczp;FT_UShortrefp;FT_F26Dot6dx,dy;FT_UShortpoint;if(exc->top<exc->GS.loop){if(exc->pedantic_hinting)exc->error=FT_THROW(Invalid_Reference);gotoFail;}if(Compute_Point_Displacement(exc,&dx,&dy,&zp,&refp))return;while(exc->GS.loop>0){exc->args--;point=(FT_UShort)exc->stack[exc->args];if(BOUNDS(point,exc->zp2.n_points)){if(exc->pedantic_hinting){exc->error=FT_THROW(Invalid_Reference);return;}}else#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY/* doesn't follow Cleartype spec but produces better result */if(SUBPIXEL_HINTING_INFINALITY&&exc->ignore_x_mode)Move_Zp2_Point(exc,point,0,dy,TRUE);else#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */Move_Zp2_Point(exc,point,dx,dy,TRUE);exc->GS.loop--;}Fail:exc->GS.loop=1;exc->new_top=exc->args;}/*************************************************************************//* *//* 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. *//* */staticvoidIns_SHC(TT_ExecContextexc,FT_Long*args){TT_GlyphZoneReczp;FT_UShortrefp;FT_F26Dot6dx,dy;FT_Shortcontour,bounds;FT_UShortstart,limit,i;contour=(FT_Short)args[0];bounds=(exc->GS.gep2==0)?1:exc->zp2.n_contours;if(BOUNDS(contour,bounds)){if(exc->pedantic_hinting)exc->error=FT_THROW(Invalid_Reference);return;}if(Compute_Point_Displacement(exc,&dx,&dy,&zp,&refp))return;if(contour==0)start=0;elsestart=(FT_UShort)(exc->zp2.contours[contour-1]+1-exc->zp2.first_point);/* we use the number of points if in the twilight zone */if(exc->GS.gep2==0)limit=exc->zp2.n_points;elselimit=(FT_UShort)(exc->zp2.contours[contour]-exc->zp2.first_point+1);for(i=start;i<limit;i++){if(zp.cur!=exc->zp2.cur||refp!=i)Move_Zp2_Point(exc,i,dx,dy,TRUE);}}/*************************************************************************//* *//* SHZ[a]: SHift Zone *//* Opcode range: 0x36-37 *//* Stack: uint32 --> *//* */staticvoidIns_SHZ(TT_ExecContextexc,FT_Long*args){TT_GlyphZoneReczp;FT_UShortrefp;FT_F26Dot6dx,dy;FT_UShortlimit,i;if(BOUNDS(args[0],2)){if(exc->pedantic_hinting)exc->error=FT_THROW(Invalid_Reference);return;}if(Compute_Point_Displacement(exc,&dx,&dy,&zp,&refp))return;/* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points. *//* Twilight zone has no real contours, so use `n_points'. *//* Normal zone's `n_points' includes phantoms, so must *//* use end of last contour. */if(exc->GS.gep2==0)limit=(FT_UShort)exc->zp2.n_points;elseif(exc->GS.gep2==1&&exc->zp2.n_contours>0)limit=(FT_UShort)(exc->zp2.contours[exc->zp2.n_contours-1]+1);elselimit=0;/* XXX: UNDOCUMENTED! SHZ doesn't touch the points */for(i=0;i<limit;i++){if(zp.cur!=exc->zp2.cur||refp!=i)Move_Zp2_Point(exc,i,dx,dy,FALSE);}}/*************************************************************************//* *//* SHPIX[]: SHift points by a PIXel amount *//* Opcode range: 0x38 *//* Stack: f26.6 uint32... --> *//* */staticvoidIns_SHPIX(TT_ExecContextexc,FT_Long*args){FT_F26Dot6dx,dy;FT_UShortpoint;#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITYFT_IntB1,B2;#endif#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMALFT_Boolin_twilight=FT_BOOL(exc->GS.gep0==0||exc->GS.gep1==0||exc->GS.gep2==0);#endifif(exc->top<exc->GS.loop+1){if(exc->pedantic_hinting)exc->error=FT_THROW(Invalid_Reference);gotoFail;}dx=TT_MulFix14(args[0],exc->GS.freeVector.x);dy=TT_MulFix14(args[0],exc->GS.freeVector.y);while(exc->GS.loop>0){exc->args--;point=(FT_UShort)exc->stack[exc->args];if(BOUNDS(point,exc->zp2.n_points)){if(exc->pedantic_hinting){exc->error=FT_THROW(Invalid_Reference);return;}}else#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITYif(SUBPIXEL_HINTING_INFINALITY){/* If not using ignore_x_mode rendering, allow ZP2 move. *//* If inline deltas aren't allowed, skip ZP2 move. *//* If using ignore_x_mode rendering, allow ZP2 point move if: *//* - freedom vector is y and sph_compatibility_mode is off *//* - the glyph is composite and the move is in the Y direction *//* - the glyph is specifically set to allow SHPIX moves *//* - the move is on a previously Y-touched point */if(exc->ignore_x_mode){/* save point for later comparison */if(exc->GS.freeVector.y!=0)B1=exc->zp2.cur[point].y;elseB1=exc->zp2.cur[point].x;if(!exc->face->sph_compatibility_mode&&exc->GS.freeVector.y!=0){Move_Zp2_Point(exc,point,dx,dy,TRUE);/* save new point */if(exc->GS.freeVector.y!=0){B2=exc->zp2.cur[point].y;/* reverse any disallowed moves */if((exc->sph_tweak_flags&SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES)&&(B1&63)!=0&&(B2&63)!=0&&B1!=B2)Move_Zp2_Point(exc,point,NEG_LONG(dx),NEG_LONG(dy),TRUE);}}elseif(exc->face->sph_compatibility_mode){if(exc->sph_tweak_flags&SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES){dx=FT_PIX_ROUND(B1+dx)-B1;dy=FT_PIX_ROUND(B1+dy)-B1;}/* skip post-iup deltas */if(exc->iup_called&&((exc->sph_in_func_flags&SPH_FDEF_INLINE_DELTA_1)||(exc->sph_in_func_flags&SPH_FDEF_INLINE_DELTA_2)))gotoSkip;if(!(exc->sph_tweak_flags&SPH_TWEAK_ALWAYS_SKIP_DELTAP)&&((exc->is_composite&&exc->GS.freeVector.y!=0)||(exc->zp2.tags[point]&FT_CURVE_TAG_TOUCH_Y)||(exc->sph_tweak_flags&SPH_TWEAK_DO_SHPIX)))Move_Zp2_Point(exc,point,0,dy,TRUE);/* save new point */if(exc->GS.freeVector.y!=0){B2=exc->zp2.cur[point].y;/* reverse any disallowed moves */if((B1&63)==0&&(B2&63)!=0&&B1!=B2)Move_Zp2_Point(exc,point,0,NEG_LONG(dy),TRUE);}}elseif(exc->sph_in_func_flags&SPH_FDEF_TYPEMAN_DIAGENDCTRL)Move_Zp2_Point(exc,point,dx,dy,TRUE);}elseMove_Zp2_Point(exc,point,dx,dy,TRUE);}else#endif#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMALif(SUBPIXEL_HINTING_MINIMAL&&exc->backward_compatibility){/* Special case: allow SHPIX to move points in the twilight zone. *//* Otherwise, treat SHPIX the same as DELTAP. Unbreaks various *//* fonts such as older versions of Rokkitt and DTL Argo T Light *//* that would glitch severely after calling ALIGNRP after a *//* blocked SHPIX. */if(in_twilight||(!(exc->iupx_called&&exc->iupy_called)&&((exc->is_composite&&exc->GS.freeVector.y!=0)||(exc->zp2.tags[point]&FT_CURVE_TAG_TOUCH_Y))))Move_Zp2_Point(exc,point,0,dy,TRUE);}else#endifMove_Zp2_Point(exc,point,dx,dy,TRUE);#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITYSkip:#endifexc->GS.loop--;}Fail:exc->GS.loop=1;exc->new_top=exc->args;}/*************************************************************************//* *//* MSIRP[a]: Move Stack Indirect Relative Position *//* Opcode range: 0x3A-0x3B *//* Stack: f26.6 uint32 --> *//* */staticvoidIns_MSIRP(TT_ExecContextexc,FT_Long*args){FT_UShortpoint=0;FT_F26Dot6distance;#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITYFT_F26Dot6control_value_cutin=0;FT_F26Dot6delta;if(SUBPIXEL_HINTING_INFINALITY){control_value_cutin=exc->GS.control_value_cutin;if(exc->ignore_x_mode&&exc->GS.freeVector.x!=0&&!(exc->sph_tweak_flags&SPH_TWEAK_NORMAL_ROUND))control_value_cutin=0;}#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */point=(FT_UShort)args[0];if(BOUNDS(point,exc->zp1.n_points)||BOUNDS(exc->GS.rp0,exc->zp0.n_points)){if(exc->pedantic_hinting)exc->error=FT_THROW(Invalid_Reference);return;}/* UNDOCUMENTED! The MS rasterizer does that with *//* twilight points (confirmed by Greg Hitchcock) */if(exc->GS.gep1==0){exc->zp1.org[point]=exc->zp0.org[exc->GS.rp0];exc->func_move_orig(exc,&exc->zp1,point,args[1]);exc->zp1.cur[point]=exc->zp1.org[point];}distance=PROJECT(exc->zp1.cur+point,exc->zp0.cur+exc->GS.rp0);#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITYdelta=SUB_LONG(distance,args[1]);if(delta<0)delta=NEG_LONG(delta);/* subpixel hinting - make MSIRP respect CVT cut-in; */if(SUBPIXEL_HINTING_INFINALITY&&exc->ignore_x_mode&&exc->GS.freeVector.x!=0&&delta>=control_value_cutin)distance=args[1];#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */exc->func_move(exc,&exc->zp1,point,SUB_LONG(args[1],distance));exc->GS.rp1=exc->GS.rp0;exc->GS.rp2=point;if((exc->opcode&1)!=0)exc->GS.rp0=point;}/*************************************************************************//* *//* MDAP[a]: Move Direct Absolute Point *//* Opcode range: 0x2E-0x2F *//* Stack: uint32 --> *//* */staticvoidIns_MDAP(TT_ExecContextexc,FT_Long*args){FT_UShortpoint;FT_F26Dot6cur_dist;FT_F26Dot6distance;point=(FT_UShort)args[0];if(BOUNDS(point,exc->zp0.n_points)){if(exc->pedantic_hinting)exc->error=FT_THROW(Invalid_Reference);return;}if((exc->opcode&1)!=0){cur_dist=FAST_PROJECT(&exc->zp0.cur[point]);#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITYif(SUBPIXEL_HINTING_INFINALITY&&exc->ignore_x_mode&&exc->GS.freeVector.x!=0)distance=SUB_LONG(Round_None(exc,cur_dist,exc->tt_metrics.compensations[0]),cur_dist);else#endifdistance=SUB_LONG(exc->func_round(exc,cur_dist,exc->tt_metrics.compensations[0]),cur_dist);}elsedistance=0;exc->func_move(exc,&exc->zp0,point,distance);exc->GS.rp0=point;exc->GS.rp1=point;}/*************************************************************************//* *//* MIAP[a]: Move Indirect Absolute Point *//* Opcode range: 0x3E-0x3F *//* Stack: uint32 uint32 --> *//* */staticvoidIns_MIAP(TT_ExecContextexc,FT_Long*args){FT_ULongcvtEntry;FT_UShortpoint;FT_F26Dot6distance;FT_F26Dot6org_dist;FT_F26Dot6control_value_cutin;control_value_cutin=exc->GS.control_value_cutin;cvtEntry=(FT_ULong)args[1];point=(FT_UShort)args[0];#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITYif(SUBPIXEL_HINTING_INFINALITY&&exc->ignore_x_mode&&exc->GS.freeVector.x!=0&&exc->GS.freeVector.y==0&&!(exc->sph_tweak_flags&SPH_TWEAK_NORMAL_ROUND))control_value_cutin=0;#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */if(BOUNDS(point,exc->zp0.n_points)||BOUNDSL(cvtEntry,exc->cvtSize)){if(exc->pedantic_hinting)exc->error=FT_THROW(Invalid_Reference);gotoFail;}/* UNDOCUMENTED! *//* *//* The behaviour of an MIAP instruction is quite different when used *//* in the twilight zone. *//* *//* First, no control value cut-in test is performed as it would fail *//* anyway. Second, the original point, i.e. (org_x,org_y) of *//* zp0.point, is set to the absolute, unrounded distance found in the *//* CVT. *//* *//* This is used in the CVT programs of the Microsoft fonts Arial, *//* Times, etc., in order to re-adjust some key font heights. It *//* allows the use of the IP instruction in the twilight zone, which *//* otherwise would be invalid according to the specification. *//* *//* We implement it with a special sequence for the twilight zone. *//* This is a bad hack, but it seems to work. *//* *//* Confirmed by Greg Hitchcock. */distance=exc->func_read_cvt(exc,cvtEntry);if(exc->GS.gep0==0)/* If in twilight zone */{#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY/* Only adjust if not in sph_compatibility_mode or ignore_x_mode. *//* Determined via experimentation and may be incorrect... */if(!(SUBPIXEL_HINTING_INFINALITY&&(exc->ignore_x_mode&&exc->face->sph_compatibility_mode)))#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */exc->zp0.org[point].x=TT_MulFix14(distance,exc->GS.freeVector.x);exc->zp0.org[point].y=TT_MulFix14(distance,exc->GS.freeVector.y),exc->zp0.cur[point]=exc->zp0.org[point];}#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITYif(SUBPIXEL_HINTING_INFINALITY&&exc->ignore_x_mode&&(exc->sph_tweak_flags&SPH_TWEAK_MIAP_HACK)&&distance>0&&exc->GS.freeVector.y!=0)distance=0;#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */org_dist=FAST_PROJECT(&exc->zp0.cur[point]);if((exc->opcode&1)!=0)/* rounding and control cut-in flag */{FT_F26Dot6delta;delta=SUB_LONG(distance,org_dist);if(delta<0)delta=NEG_LONG(delta);if(delta>control_value_cutin)distance=org_dist;#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITYif(SUBPIXEL_HINTING_INFINALITY&&exc->ignore_x_mode&&exc->GS.freeVector.x!=0)distance=Round_None(exc,distance,exc->tt_metrics.compensations[0]);else#endifdistance=exc->func_round(exc,distance,exc->tt_metrics.compensations[0]);}exc->func_move(exc,&exc->zp0,point,SUB_LONG(distance,org_dist));Fail:exc->GS.rp0=point;exc->GS.rp1=point;}/*************************************************************************//* *//* MDRP[abcde]: Move Direct Relative Point *//* Opcode range: 0xC0-0xDF *//* Stack: uint32 --> *//* */staticvoidIns_MDRP(TT_ExecContextexc,FT_Long*args){FT_UShortpoint=0;FT_F26Dot6org_dist,distance,minimum_distance;minimum_distance=exc->GS.minimum_distance;#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITYif(SUBPIXEL_HINTING_INFINALITY&&exc->ignore_x_mode&&exc->GS.freeVector.x!=0&&!(exc->sph_tweak_flags&SPH_TWEAK_NORMAL_ROUND))minimum_distance=0;#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */point=(FT_UShort)args[0];if(BOUNDS(point,exc->zp1.n_points)||BOUNDS(exc->GS.rp0,exc->zp0.n_points)){if(exc->pedantic_hinting)exc->error=FT_THROW(Invalid_Reference);gotoFail;}/* XXX: Is there some undocumented feature while in the *//* twilight zone? *//* XXX: UNDOCUMENTED: twilight zone special case */if(exc->GS.gep0==0||exc->GS.gep1==0){FT_Vector*vec1=&exc->zp1.org[point];FT_Vector*vec2=&exc->zp0.org[exc->GS.rp0];org_dist=DUALPROJ(vec1,vec2);}else{FT_Vector*vec1=&exc->zp1.orus[point];FT_Vector*vec2=&exc->zp0.orus[exc->GS.rp0];if(exc->metrics.x_scale==exc->metrics.y_scale){/* this should be faster */org_dist=DUALPROJ(vec1,vec2);org_dist=FT_MulFix(org_dist,exc->metrics.x_scale);}else{FT_Vectorvec;vec.x=FT_MulFix(SUB_LONG(vec1->x,vec2->x),exc->metrics.x_scale);vec.y=FT_MulFix(SUB_LONG(vec1->y,vec2->y),exc->metrics.y_scale);org_dist=FAST_DUALPROJ(&vec);}}/* single width cut-in test *//* |org_dist - single_width_value| < single_width_cutin */if(exc->GS.single_width_cutin>0&&org_dist<exc->GS.single_width_value+exc->GS.single_width_cutin&&org_dist>exc->GS.single_width_value-exc->GS.single_width_cutin){if(org_dist>=0)org_dist=exc->GS.single_width_value;elseorg_dist=-exc->GS.single_width_value;}/* round flag */if((exc->opcode&4)!=0){#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITYif(SUBPIXEL_HINTING_INFINALITY&&exc->ignore_x_mode&&exc->GS.freeVector.x!=0)distance=Round_None(exc,org_dist,exc->tt_metrics.compensations[exc->opcode&3]);else#endifdistance=exc->func_round(exc,org_dist,exc->tt_metrics.compensations[exc->opcode&3]);}elsedistance=Round_None(exc,org_dist,exc->tt_metrics.compensations[exc->opcode&3]);/* minimum distance flag */if((exc->opcode&8)!=0){if(org_dist>=0){if(distance<minimum_distance)distance=minimum_distance;}else{if(distance>NEG_LONG(minimum_distance))distance=NEG_LONG(minimum_distance);}}/* now move the point */org_dist=PROJECT(exc->zp1.cur+point,exc->zp0.cur+exc->GS.rp0);exc->func_move(exc,&exc->zp1,point,SUB_LONG(distance,org_dist));Fail:exc->GS.rp1=exc->GS.rp0;exc->GS.rp2=point;if((exc->opcode&16)!=0)exc->GS.rp0=point;}/*************************************************************************//* *//* MIRP[abcde]: Move Indirect Relative Point *//* Opcode range: 0xE0-0xFF *//* Stack: int32? uint32 --> *//* */staticvoidIns_MIRP(TT_ExecContextexc,FT_Long*args){FT_UShortpoint;FT_ULongcvtEntry;FT_F26Dot6cvt_dist,distance,cur_dist,org_dist,control_value_cutin,minimum_distance;#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITYFT_IntB1=0;/* pacify compiler */FT_IntB2=0;FT_Boolreverse_move=FALSE;#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */minimum_distance=exc->GS.minimum_distance;control_value_cutin=exc->GS.control_value_cutin;point=(FT_UShort)args[0];cvtEntry=(FT_ULong)(ADD_LONG(args[1],1));#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITYif(SUBPIXEL_HINTING_INFINALITY&&exc->ignore_x_mode&&exc->GS.freeVector.x!=0&&!(exc->sph_tweak_flags&SPH_TWEAK_NORMAL_ROUND))control_value_cutin=minimum_distance=0;#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY *//* XXX: UNDOCUMENTED! cvt[-1] = 0 always */if(BOUNDS(point,exc->zp1.n_points)||BOUNDSL(cvtEntry,exc->cvtSize+1)||BOUNDS(exc->GS.rp0,exc->zp0.n_points)){if(exc->pedantic_hinting)exc->error=FT_THROW(Invalid_Reference);gotoFail;}if(!cvtEntry)cvt_dist=0;elsecvt_dist=exc->func_read_cvt(exc,cvtEntry-1);/* single width test */if(FT_ABS(cvt_dist-exc->GS.single_width_value)<exc->GS.single_width_cutin){if(cvt_dist>=0)cvt_dist=exc->GS.single_width_value;elsecvt_dist=-exc->GS.single_width_value;}/* UNDOCUMENTED! The MS rasterizer does that with *//* twilight points (confirmed by Greg Hitchcock) */if(exc->GS.gep1==0){exc->zp1.org[point].x=exc->zp0.org[exc->GS.rp0].x+TT_MulFix14(cvt_dist,exc->GS.freeVector.x);exc->zp1.org[point].y=exc->zp0.org[exc->GS.rp0].y+TT_MulFix14(cvt_dist,exc->GS.freeVector.y);exc->zp1.cur[point]=exc->zp1.org[point];}org_dist=DUALPROJ(&exc->zp1.org[point],&exc->zp0.org[exc->GS.rp0]);cur_dist=PROJECT(&exc->zp1.cur[point],&exc->zp0.cur[exc->GS.rp0]);/* auto-flip test */if(exc->GS.auto_flip){if((org_dist^cvt_dist)<0)cvt_dist=-cvt_dist;}#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITYif(SUBPIXEL_HINTING_INFINALITY&&exc->ignore_x_mode&&exc->GS.freeVector.y!=0&&(exc->sph_tweak_flags&SPH_TWEAK_TIMES_NEW_ROMAN_HACK)){if(cur_dist<-64)cvt_dist-=16;elseif(cur_dist>64&&cur_dist<84)cvt_dist+=32;}#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY *//* control value cut-in and round */if((exc->opcode&4)!=0){/* XXX: UNDOCUMENTED! Only perform cut-in test when both points *//* refer to the same zone. */if(exc->GS.gep0==exc->GS.gep1){FT_F26Dot6delta;/* XXX: According to Greg Hitchcock, the following wording is *//* the right one: *//* *//* When the absolute difference between the value in *//* the table [CVT] and the measurement directly from *//* the outline is _greater_ than the cut_in value, the *//* outline measurement is used. *//* *//* This is from `instgly.doc'. The description in *//* `ttinst2.doc', version 1.66, is thus incorrect since *//* it implies `>=' instead of `>'. */delta=SUB_LONG(cvt_dist,org_dist);if(delta<0)delta=NEG_LONG(delta);if(delta>control_value_cutin)cvt_dist=org_dist;}distance=exc->func_round(exc,cvt_dist,exc->tt_metrics.compensations[exc->opcode&3]);}else{#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY/* do cvt cut-in always in MIRP for sph */if(SUBPIXEL_HINTING_INFINALITY&&exc->ignore_x_mode&&exc->GS.gep0==exc->GS.gep1){FT_F26Dot6delta;delta=SUB_LONG(cvt_dist,org_dist);if(delta<0)delta=NEG_LONG(delta);if(delta>control_value_cutin)cvt_dist=org_dist;}#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */distance=Round_None(exc,cvt_dist,exc->tt_metrics.compensations[exc->opcode&3]);}/* minimum distance test */if((exc->opcode&8)!=0){if(org_dist>=0){if(distance<minimum_distance)distance=minimum_distance;}else{if(distance>NEG_LONG(minimum_distance))distance=NEG_LONG(minimum_distance);}}#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITYif(SUBPIXEL_HINTING_INFINALITY){B1=exc->zp1.cur[point].y;/* Round moves if necessary */if(exc->ignore_x_mode&&exc->GS.freeVector.y!=0&&(exc->sph_tweak_flags&SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES))distance=FT_PIX_ROUND(B1+distance-cur_dist)-B1+cur_dist;if(exc->ignore_x_mode&&exc->GS.freeVector.y!=0&&(exc->opcode&16)==0&&(exc->opcode&8)==0&&(exc->sph_tweak_flags&SPH_TWEAK_COURIER_NEW_2_HACK))distance+=64;}#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */exc->func_move(exc,&exc->zp1,point,SUB_LONG(distance,cur_dist));#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITYif(SUBPIXEL_HINTING_INFINALITY){B2=exc->zp1.cur[point].y;/* Reverse move if necessary */if(exc->ignore_x_mode){if(exc->face->sph_compatibility_mode&&exc->GS.freeVector.y!=0&&(B1&63)==0&&(B2&63)!=0)reverse_move=TRUE;if((exc->sph_tweak_flags&SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES)&&exc->GS.freeVector.y!=0&&(B2&63)!=0&&(B1&63)!=0)reverse_move=TRUE;}if(reverse_move)exc->func_move(exc,&exc->zp1,point,SUB_LONG(cur_dist,distance));}#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */Fail:exc->GS.rp1=exc->GS.rp0;if((exc->opcode&16)!=0)exc->GS.rp0=point;exc->GS.rp2=point;}/*************************************************************************//* *//* ALIGNRP[]: ALIGN Relative Point *//* Opcode range: 0x3C *//* Stack: uint32 uint32... --> *//* */staticvoidIns_ALIGNRP(TT_ExecContextexc){FT_UShortpoint;FT_F26Dot6distance;#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITYif(SUBPIXEL_HINTING_INFINALITY&&exc->ignore_x_mode&&exc->iup_called&&(exc->sph_tweak_flags&SPH_TWEAK_NO_ALIGNRP_AFTER_IUP)){exc->error=FT_THROW(Invalid_Reference);gotoFail;}#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */if(exc->top<exc->GS.loop||BOUNDS(exc->GS.rp0,exc->zp0.n_points)){if(exc->pedantic_hinting)exc->error=FT_THROW(Invalid_Reference);gotoFail;}while(exc->GS.loop>0){exc->args--;point=(FT_UShort)exc->stack[exc->args];if(BOUNDS(point,exc->zp1.n_points)){if(exc->pedantic_hinting){exc->error=FT_THROW(Invalid_Reference);return;}}else{distance=PROJECT(exc->zp1.cur+point,exc->zp0.cur+exc->GS.rp0);exc->func_move(exc,&exc->zp1,point,NEG_LONG(distance));}exc->GS.loop--;}Fail:exc->GS.loop=1;exc->new_top=exc->args;}/*************************************************************************//* *//* ISECT[]: moves point to InterSECTion *//* Opcode range: 0x0F *//* Stack: 5 * uint32 --> *//* */staticvoidIns_ISECT(TT_ExecContextexc,FT_Long*args){FT_UShortpoint,a0,a1,b0,b1;FT_F26Dot6discriminant,dotproduct;FT_F26Dot6dx,dy,dax,day,dbx,dby;FT_F26Dot6val;FT_VectorR;point=(FT_UShort)args[0];a0=(FT_UShort)args[1];a1=(FT_UShort)args[2];b0=(FT_UShort)args[3];b1=(FT_UShort)args[4];if(BOUNDS(b0,exc->zp0.n_points)||BOUNDS(b1,exc->zp0.n_points)||BOUNDS(a0,exc->zp1.n_points)||BOUNDS(a1,exc->zp1.n_points)||BOUNDS(point,exc->zp2.n_points)){if(exc->pedantic_hinting)exc->error=FT_THROW(Invalid_Reference);return;}/* Cramer's rule */dbx=SUB_LONG(exc->zp0.cur[b1].x,exc->zp0.cur[b0].x);dby=SUB_LONG(exc->zp0.cur[b1].y,exc->zp0.cur[b0].y);dax=SUB_LONG(exc->zp1.cur[a1].x,exc->zp1.cur[a0].x);day=SUB_LONG(exc->zp1.cur[a1].y,exc->zp1.cur[a0].y);dx=SUB_LONG(exc->zp0.cur[b0].x,exc->zp1.cur[a0].x);dy=SUB_LONG(exc->zp0.cur[b0].y,exc->zp1.cur[a0].y);discriminant=ADD_LONG(FT_MulDiv(dax,NEG_LONG(dby),0x40),FT_MulDiv(day,dbx,0x40));dotproduct=ADD_LONG(FT_MulDiv(dax,dbx,0x40),FT_MulDiv(day,dby,0x40));/* The discriminant above is actually a cross product of vectors *//* da and db. Together with the dot product, they can be used as *//* surrogates for sine and cosine of the angle between the vectors. *//* Indeed, *//* dotproduct = |da||db|cos(angle) *//* discriminant = |da||db|sin(angle) . *//* We use these equations to reject grazing intersections by *//* thresholding abs(tan(angle)) at 1/19, corresponding to 3 degrees. */if(MUL_LONG(19,FT_ABS(discriminant))>FT_ABS(dotproduct)){val=ADD_LONG(FT_MulDiv(dx,NEG_LONG(dby),0x40),FT_MulDiv(dy,dbx,0x40));R.x=FT_MulDiv(val,dax,discriminant);R.y=FT_MulDiv(val,day,discriminant);/* XXX: Block in backward_compatibility and/or post-IUP? */exc->zp2.cur[point].x=ADD_LONG(exc->zp1.cur[a0].x,R.x);exc->zp2.cur[point].y=ADD_LONG(exc->zp1.cur[a0].y,R.y);}else{/* else, take the middle of the middles of A and B *//* XXX: Block in backward_compatibility and/or post-IUP? */exc->zp2.cur[point].x=ADD_LONG(ADD_LONG(exc->zp1.cur[a0].x,exc->zp1.cur[a1].x),ADD_LONG(exc->zp0.cur[b0].x,exc->zp0.cur[b1].x))/4;exc->zp2.cur[point].y=ADD_LONG(ADD_LONG(exc->zp1.cur[a0].y,exc->zp1.cur[a1].y),ADD_LONG(exc->zp0.cur[b0].y,exc->zp0.cur[b1].y))/4;}exc->zp2.tags[point]|=FT_CURVE_TAG_TOUCH_BOTH;}/*************************************************************************//* *//* ALIGNPTS[]: ALIGN PoinTS *//* Opcode range: 0x27 *//* Stack: uint32 uint32 --> *//* */staticvoidIns_ALIGNPTS(TT_ExecContextexc,FT_Long*args){FT_UShortp1,p2;FT_F26Dot6distance;p1=(FT_UShort)args[0];p2=(FT_UShort)args[1];if(BOUNDS(p1,exc->zp1.n_points)||BOUNDS(p2,exc->zp0.n_points)){if(exc->pedantic_hinting)exc->error=FT_THROW(Invalid_Reference);return;}distance=PROJECT(exc->zp0.cur+p2,exc->zp1.cur+p1)/2;exc->func_move(exc,&exc->zp1,p1,distance);exc->func_move(exc,&exc->zp0,p2,NEG_LONG(distance));}/*************************************************************************//* *//* IP[]: Interpolate Point *//* Opcode range: 0x39 *//* Stack: uint32... --> *//* *//* SOMETIMES, DUMBER CODE IS BETTER CODE */staticvoidIns_IP(TT_ExecContextexc){FT_F26Dot6old_range,cur_range;FT_Vector*orus_base;FT_Vector*cur_base;FT_Inttwilight;if(exc->top<exc->GS.loop){if(exc->pedantic_hinting)exc->error=FT_THROW(Invalid_Reference);gotoFail;}/* * We need to deal in a special way with the twilight zone. * Otherwise, by definition, the value of exc->twilight.orus[n] is (0,0), * for every n. */twilight=(exc->GS.gep0==0||exc->GS.gep1==0||exc->GS.gep2==0);if(BOUNDS(exc->GS.rp1,exc->zp0.n_points)){if(exc->pedantic_hinting)exc->error=FT_THROW(Invalid_Reference);gotoFail;}if(twilight)orus_base=&exc->zp0.org[exc->GS.rp1];elseorus_base=&exc->zp0.orus[exc->GS.rp1];cur_base=&exc->zp0.cur[exc->GS.rp1];/* XXX: There are some glyphs in some braindead but popular *//* fonts out there (e.g. [aeu]grave in monotype.ttf) *//* calling IP[] with bad values of rp[12]. *//* Do something sane when this odd thing happens. */if(BOUNDS(exc->GS.rp1,exc->zp0.n_points)||BOUNDS(exc->GS.rp2,exc->zp1.n_points)){old_range=0;cur_range=0;}else{if(twilight)old_range=DUALPROJ(&exc->zp1.org[exc->GS.rp2],orus_base);elseif(exc->metrics.x_scale==exc->metrics.y_scale)old_range=DUALPROJ(&exc->zp1.orus[exc->GS.rp2],orus_base);else{FT_Vectorvec;vec.x=FT_MulFix(SUB_LONG(exc->zp1.orus[exc->GS.rp2].x,orus_base->x),exc->metrics.x_scale);vec.y=FT_MulFix(SUB_LONG(exc->zp1.orus[exc->GS.rp2].y,orus_base->y),exc->metrics.y_scale);old_range=FAST_DUALPROJ(&vec);}cur_range=PROJECT(&exc->zp1.cur[exc->GS.rp2],cur_base);}for(;exc->GS.loop>0;exc->GS.loop--){FT_UIntpoint=(FT_UInt)exc->stack[--exc->args];FT_F26Dot6org_dist,cur_dist,new_dist;/* check point bounds */if(BOUNDS(point,exc->zp2.n_points)){if(exc->pedantic_hinting){exc->error=FT_THROW(Invalid_Reference);return;}continue;}if(twilight)org_dist=DUALPROJ(&exc->zp2.org[point],orus_base);elseif(exc->metrics.x_scale==exc->metrics.y_scale)org_dist=DUALPROJ(&exc->zp2.orus[point],orus_base);else{FT_Vectorvec;vec.x=FT_MulFix(SUB_LONG(exc->zp2.orus[point].x,orus_base->x),exc->metrics.x_scale);vec.y=FT_MulFix(SUB_LONG(exc->zp2.orus[point].y,orus_base->y),exc->metrics.y_scale);org_dist=FAST_DUALPROJ(&vec);}cur_dist=PROJECT(&exc->zp2.cur[point],cur_base);if(org_dist){if(old_range)new_dist=FT_MulDiv(org_dist,cur_range,old_range);else{/* This is the same as what MS does for the invalid case: *//* *//* delta = (Original_Pt - Original_RP1) - *//* (Current_Pt - Current_RP1) ; *//* *//* In FreeType speak: *//* *//* delta = org_dist - cur_dist . *//* *//* We move `point' by `new_dist - cur_dist' after leaving *//* this block, thus we have *//* *//* new_dist - cur_dist = delta , *//* new_dist - cur_dist = org_dist - cur_dist , *//* new_dist = org_dist . */new_dist=org_dist;}}elsenew_dist=0;exc->func_move(exc,&exc->zp2,(FT_UShort)point,SUB_LONG(new_dist,cur_dist));}Fail:exc->GS.loop=1;exc->new_top=exc->args;}/*************************************************************************//* *//* UTP[a]: UnTouch Point *//* Opcode range: 0x29 *//* Stack: uint32 --> *//* */staticvoidIns_UTP(TT_ExecContextexc,FT_Long*args){FT_UShortpoint;FT_Bytemask;point=(FT_UShort)args[0];if(BOUNDS(point,exc->zp0.n_points)){if(exc->pedantic_hinting)exc->error=FT_THROW(Invalid_Reference);return;}mask=0xFF;if(exc->GS.freeVector.x!=0)mask&=~FT_CURVE_TAG_TOUCH_X;if(exc->GS.freeVector.y!=0)mask&=~FT_CURVE_TAG_TOUCH_Y;exc->zp0.tags[point]&=mask;}/* Local variables for Ins_IUP: */typedefstructIUP_WorkerRec_{FT_Vector*orgs;/* original and current coordinate */FT_Vector*curs;/* arrays */FT_Vector*orus;FT_UIntmax_points;}IUP_WorkerRec,*IUP_Worker;staticvoid_iup_worker_shift(IUP_Workerworker,FT_UIntp1,FT_UIntp2,FT_UIntp){FT_UInti;FT_F26Dot6dx;dx=SUB_LONG(worker->curs[p].x,worker->orgs[p].x);if(dx!=0){for(i=p1;i<p;i++)worker->curs[i].x=ADD_LONG(worker->curs[i].x,dx);for(i=p+1;i<=p2;i++)worker->curs[i].x=ADD_LONG(worker->curs[i].x,dx);}}staticvoid_iup_worker_interpolate(IUP_Workerworker,FT_UIntp1,FT_UIntp2,FT_UIntref1,FT_UIntref2){FT_UInti;FT_F26Dot6orus1,orus2,org1,org2,cur1,cur2,delta1,delta2;if(p1>p2)return;if(BOUNDS(ref1,worker->max_points)||BOUNDS(ref2,worker->max_points))return;orus1=worker->orus[ref1].x;orus2=worker->orus[ref2].x;if(orus1>orus2){FT_F26Dot6tmp_o;FT_UInttmp_r;tmp_o=orus1;orus1=orus2;orus2=tmp_o;tmp_r=ref1;ref1=ref2;ref2=tmp_r;}org1=worker->orgs[ref1].x;org2=worker->orgs[ref2].x;cur1=worker->curs[ref1].x;cur2=worker->curs[ref2].x;delta1=SUB_LONG(cur1,org1);delta2=SUB_LONG(cur2,org2);if(cur1==cur2||orus1==orus2){/* trivial snap or shift of untouched points */for(i=p1;i<=p2;i++){FT_F26Dot6x=worker->orgs[i].x;if(x<=org1)x=ADD_LONG(x,delta1);elseif(x>=org2)x=ADD_LONG(x,delta2);elsex=cur1;worker->curs[i].x=x;}}else{FT_Fixedscale=0;FT_Boolscale_valid=0;/* interpolation */for(i=p1;i<=p2;i++){FT_F26Dot6x=worker->orgs[i].x;if(x<=org1)x=ADD_LONG(x,delta1);elseif(x>=org2)x=ADD_LONG(x,delta2);else{if(!scale_valid){scale_valid=1;scale=FT_DivFix(SUB_LONG(cur2,cur1),SUB_LONG(orus2,orus1));}x=ADD_LONG(cur1,FT_MulFix(SUB_LONG(worker->orus[i].x,orus1),scale));}worker->curs[i].x=x;}}}/*************************************************************************//* *//* IUP[a]: Interpolate Untouched Points *//* Opcode range: 0x30-0x31 *//* Stack: --> *//* */staticvoidIns_IUP(TT_ExecContextexc){IUP_WorkerRecV;FT_Bytemask;FT_UIntfirst_point;/* first point of contour */FT_UIntend_point;/* end point (last+1) of contour */FT_UIntfirst_touched;/* first touched point in contour */FT_UIntcur_touched;/* current touched point in contour */FT_UIntpoint;/* current point */FT_Shortcontour;/* current contour */#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL/* See `ttinterp.h' for details on backward compatibility mode. *//* Allow IUP until it has been called on both axes. Immediately *//* return on subsequent ones. */if(SUBPIXEL_HINTING_MINIMAL&&exc->backward_compatibility){if(exc->iupx_called&&exc->iupy_called)return;if(exc->opcode&1)exc->iupx_called=TRUE;elseexc->iupy_called=TRUE;}#endif/* ignore empty outlines */if(exc->pts.n_contours==0)return;if(exc->opcode&1){mask=FT_CURVE_TAG_TOUCH_X;V.orgs=exc->pts.org;V.curs=exc->pts.cur;V.orus=exc->pts.orus;}else{mask=FT_CURVE_TAG_TOUCH_Y;V.orgs=(FT_Vector*)((FT_Pos*)exc->pts.org+1);V.curs=(FT_Vector*)((FT_Pos*)exc->pts.cur+1);V.orus=(FT_Vector*)((FT_Pos*)exc->pts.orus+1);}V.max_points=exc->pts.n_points;contour=0;point=0;#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITYif(SUBPIXEL_HINTING_INFINALITY&&exc->ignore_x_mode){exc->iup_called=TRUE;if(exc->sph_tweak_flags&SPH_TWEAK_SKIP_IUP)return;}#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */do{end_point=exc->pts.contours[contour]-exc->pts.first_point;first_point=point;if(BOUNDS(end_point,exc->pts.n_points))end_point=exc->pts.n_points-1;while(point<=end_point&&(exc->pts.tags[point]&mask)==0)point++;if(point<=end_point){first_touched=point;cur_touched=point;point++;while(point<=end_point){if((exc->pts.tags[point]&mask)!=0){_iup_worker_interpolate(&V,cur_touched+1,point-1,cur_touched,point);cur_touched=point;}point++;}if(cur_touched==first_touched)_iup_worker_shift(&V,first_point,end_point,cur_touched);else{_iup_worker_interpolate(&V,(FT_UShort)(cur_touched+1),end_point,cur_touched,first_touched);if(first_touched>0)_iup_worker_interpolate(&V,first_point,first_touched-1,cur_touched,first_touched);}}contour++;}while(contour<exc->pts.n_contours);}/*************************************************************************//* *//* DELTAPn[]: DELTA exceptions P1, P2, P3 *//* Opcode range: 0x5D,0x71,0x72 *//* Stack: uint32 (2 * uint32)... --> *//* */staticvoidIns_DELTAP(TT_ExecContextexc,FT_Long*args){FT_ULongnump,k;FT_UShortA;FT_ULongC,P;FT_LongB;#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITYFT_UShortB1,B2;if(SUBPIXEL_HINTING_INFINALITY&&exc->ignore_x_mode&&exc->iup_called&&(exc->sph_tweak_flags&SPH_TWEAK_NO_DELTAP_AFTER_IUP))gotoFail;#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */P=(FT_ULong)exc->func_cur_ppem(exc);nump=(FT_ULong)args[0];/* some points theoretically may occur more than once, thus UShort isn't enough */for(k=1;k<=nump;k++){if(exc->args<2){if(exc->pedantic_hinting)exc->error=FT_THROW(Too_Few_Arguments);exc->args=0;gotoFail;}exc->args-=2;A=(FT_UShort)exc->stack[exc->args+1];B=exc->stack[exc->args];/* XXX: Because some popular fonts contain some invalid DeltaP *//* instructions, we simply ignore them when the stacked *//* point reference is off limit, rather than returning an *//* error. As a delta instruction doesn't change a glyph *//* in great ways, this shouldn't be a problem. */if(!BOUNDS(A,exc->zp0.n_points)){C=((FT_ULong)B&0xF0)>>4;switch(exc->opcode){case0x5D:break;case0x71:C+=16;break;case0x72:C+=32;break;}C+=exc->GS.delta_base;if(P==C){B=((FT_ULong)B&0xF)-8;if(B>=0)B++;B*=1L<<(6-exc->GS.delta_shift);#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITYif(SUBPIXEL_HINTING_INFINALITY){/* * Allow delta move if * * - not using ignore_x_mode rendering, * - glyph is specifically set to allow it, or * - glyph is composite and freedom vector is not in subpixel * direction. */if(!exc->ignore_x_mode||(exc->sph_tweak_flags&SPH_TWEAK_ALWAYS_DO_DELTAP)||(exc->is_composite&&exc->GS.freeVector.y!=0))exc->func_move(exc,&exc->zp0,A,B);/* Otherwise, apply subpixel hinting and compatibility mode *//* rules, always skipping deltas in subpixel direction. */elseif(exc->ignore_x_mode&&exc->GS.freeVector.y!=0){/* save the y value of the point now; compare after move */B1=(FT_UShort)exc->zp0.cur[A].y;/* Standard subpixel hinting: Allow y move for y-touched *//* points. This messes up DejaVu ... */if(!exc->face->sph_compatibility_mode&&(exc->zp0.tags[A]&FT_CURVE_TAG_TOUCH_Y))exc->func_move(exc,&exc->zp0,A,B);/* compatibility mode */elseif(exc->face->sph_compatibility_mode&&!(exc->sph_tweak_flags&SPH_TWEAK_ALWAYS_SKIP_DELTAP)){if(exc->sph_tweak_flags&SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES)B=FT_PIX_ROUND(B1+B)-B1;/* Allow delta move if using sph_compatibility_mode, *//* IUP has not been called, and point is touched on Y. */if(!exc->iup_called&&(exc->zp0.tags[A]&FT_CURVE_TAG_TOUCH_Y))exc->func_move(exc,&exc->zp0,A,B);}B2=(FT_UShort)exc->zp0.cur[A].y;/* Reverse this move if it results in a disallowed move */if(exc->GS.freeVector.y!=0&&((exc->face->sph_compatibility_mode&&(B1&63)==0&&(B2&63)!=0)||((exc->sph_tweak_flags&SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES_DELTAP)&&(B1&63)!=0&&(B2&63)!=0)))exc->func_move(exc,&exc->zp0,A,NEG_LONG(B));}}else#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */{#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL/* See `ttinterp.h' for details on backward compatibility *//* mode. */if(SUBPIXEL_HINTING_MINIMAL&&exc->backward_compatibility){if(!(exc->iupx_called&&exc->iupy_called)&&((exc->is_composite&&exc->GS.freeVector.y!=0)||(exc->zp0.tags[A]&FT_CURVE_TAG_TOUCH_Y)))exc->func_move(exc,&exc->zp0,A,B);}else#endifexc->func_move(exc,&exc->zp0,A,B);}}}elseif(exc->pedantic_hinting)exc->error=FT_THROW(Invalid_Reference);}Fail:exc->new_top=exc->args;}/*************************************************************************//* *//* DELTACn[]: DELTA exceptions C1, C2, C3 *//* Opcode range: 0x73,0x74,0x75 *//* Stack: uint32 (2 * uint32)... --> *//* */staticvoidIns_DELTAC(TT_ExecContextexc,FT_Long*args){FT_ULongnump,k;FT_ULongA,C,P;FT_LongB;P=(FT_ULong)exc->func_cur_ppem(exc);nump=(FT_ULong)args[0];for(k=1;k<=nump;k++){if(exc->args<2){if(exc->pedantic_hinting)exc->error=FT_THROW(Too_Few_Arguments);exc->args=0;gotoFail;}exc->args-=2;A=(FT_ULong)exc->stack[exc->args+1];B=exc->stack[exc->args];if(BOUNDSL(A,exc->cvtSize)){if(exc->pedantic_hinting){exc->error=FT_THROW(Invalid_Reference);return;}}else{C=((FT_ULong)B&0xF0)>>4;switch(exc->opcode){case0x73:break;case0x74:C+=16;break;case0x75:C+=32;break;}C+=exc->GS.delta_base;if(P==C){B=((FT_ULong)B&0xF)-8;if(B>=0)B++;B*=1L<<(6-exc->GS.delta_shift);exc->func_move_cvt(exc,A,B);}}}Fail:exc->new_top=exc->args;}/*************************************************************************//* *//* MISC. INSTRUCTIONS *//* *//*************************************************************************//*************************************************************************//* *//* GETINFO[]: GET INFOrmation *//* Opcode range: 0x88 *//* Stack: uint32 --> uint32 *//* *//* XXX: UNDOCUMENTED: Selector bits higher than 9 are currently (May *//* 2015) not documented in the OpenType specification. *//* *//* Selector bit 11 is incorrectly described as bit 8, while the *//* real meaning of bit 8 (vertical LCD subpixels) stays *//* undocumented. The same mistake can be found in Greg Hitchcock's *//* whitepaper. *//* */staticvoidIns_GETINFO(TT_ExecContextexc,FT_Long*args){FT_LongK;TT_Driverdriver=(TT_Driver)FT_FACE_DRIVER(exc->face);K=0;#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY/********************************//* RASTERIZER VERSION *//* Selector Bit: 0 *//* Return Bit(s): 0-7 *//* */if(SUBPIXEL_HINTING_INFINALITY&&(args[0]&1)!=0&&exc->subpixel_hinting){if(exc->ignore_x_mode){/* if in ClearType backward compatibility mode, *//* we sometimes change the TrueType version dynamically */K=exc->rasterizer_version;FT_TRACE6(("Setting rasterizer version %d\n",exc->rasterizer_version));}elseK=TT_INTERPRETER_VERSION_38;}else#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */if((args[0]&1)!=0)K=driver->interpreter_version;/********************************//* GLYPH ROTATED *//* Selector Bit: 1 *//* Return Bit(s): 8 *//* */if((args[0]&2)!=0&&exc->tt_metrics.rotated)K|=1<<8;/********************************//* GLYPH STRETCHED *//* Selector Bit: 2 *//* Return Bit(s): 9 *//* */if((args[0]&4)!=0&&exc->tt_metrics.stretched)K|=1<<9;#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT/********************************//* VARIATION GLYPH *//* Selector Bit: 3 *//* Return Bit(s): 10 *//* *//* XXX: UNDOCUMENTED! */if((args[0]&8)!=0&&exc->face->blend)K|=1<<10;#endif/********************************//* BI-LEVEL HINTING AND *//* GRAYSCALE RENDERING *//* Selector Bit: 5 *//* Return Bit(s): 12 *//* */if((args[0]&32)!=0&&exc->grayscale)K|=1<<12;#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL/* Toggle the following flags only outside of monochrome mode. *//* Otherwise, instructions may behave weirdly and rendering results *//* may differ between v35 and v40 mode, e.g., in `Times New Roman *//* Bold Italic'. */if(SUBPIXEL_HINTING_MINIMAL&&exc->subpixel_hinting_lean){/********************************//* HINTING FOR SUBPIXEL *//* Selector Bit: 6 *//* Return Bit(s): 13 *//* *//* v40 does subpixel hinting by default. */if((args[0]&64)!=0)K|=1<<13;/********************************//* VERTICAL LCD SUBPIXELS? *//* Selector Bit: 8 *//* Return Bit(s): 15 *//* */if((args[0]&256)!=0&&exc->vertical_lcd_lean)K|=1<<15;/********************************//* SUBPIXEL POSITIONED? *//* Selector Bit: 10 *//* Return Bit(s): 17 *//* *//* XXX: FreeType supports it, dependent on what client does? */if((args[0]&1024)!=0)K|=1<<17;/********************************//* SYMMETRICAL SMOOTHING *//* Selector Bit: 11 *//* Return Bit(s): 18 *//* *//* The only smoothing method FreeType supports unless someone sets *//* FT_LOAD_TARGET_MONO. */if((args[0]&2048)!=0&&exc->subpixel_hinting_lean)K|=1<<18;/********************************//* CLEARTYPE HINTING AND *//* GRAYSCALE RENDERING *//* Selector Bit: 12 *//* Return Bit(s): 19 *//* *//* Grayscale rendering is what FreeType does anyway unless someone *//* sets FT_LOAD_TARGET_MONO or FT_LOAD_TARGET_LCD(_V) */if((args[0]&4096)!=0&&exc->grayscale_cleartype)K|=1<<19;}#endif#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITYif(SUBPIXEL_HINTING_INFINALITY&&exc->rasterizer_version>=TT_INTERPRETER_VERSION_35){if(exc->rasterizer_version>=37){/********************************//* HINTING FOR SUBPIXEL *//* Selector Bit: 6 *//* Return Bit(s): 13 *//* */if((args[0]&64)!=0&&exc->subpixel_hinting)K|=1<<13;/********************************//* COMPATIBLE WIDTHS ENABLED *//* Selector Bit: 7 *//* Return Bit(s): 14 *//* *//* Functionality still needs to be added */if((args[0]&128)!=0&&exc->compatible_widths)K|=1<<14;/********************************//* VERTICAL LCD SUBPIXELS? *//* Selector Bit: 8 *//* Return Bit(s): 15 *//* *//* Functionality still needs to be added */if((args[0]&256)!=0&&exc->vertical_lcd)K|=1<<15;/********************************//* HINTING FOR BGR? *//* Selector Bit: 9 *//* Return Bit(s): 16 *//* *//* Functionality still needs to be added */if((args[0]&512)!=0&&exc->bgr)K|=1<<16;if(exc->rasterizer_version>=38){/********************************//* SUBPIXEL POSITIONED? *//* Selector Bit: 10 *//* Return Bit(s): 17 *//* *//* Functionality still needs to be added */if((args[0]&1024)!=0&&exc->subpixel_positioned)K|=1<<17;/********************************//* SYMMETRICAL SMOOTHING *//* Selector Bit: 11 *//* Return Bit(s): 18 *//* *//* Functionality still needs to be added */if((args[0]&2048)!=0&&exc->symmetrical_smoothing)K|=1<<18;/********************************//* GRAY CLEARTYPE *//* Selector Bit: 12 *//* Return Bit(s): 19 *//* *//* Functionality still needs to be added */if((args[0]&4096)!=0&&exc->gray_cleartype)K|=1<<19;}}}#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */args[0]=K;}#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. *//* */staticvoidIns_GETVARIATION(TT_ExecContextexc,FT_Long*args){FT_UIntnum_axes=exc->face->blend->num_axis;FT_Fixed*coords=exc->face->blend->normalizedcoords;FT_UInti;if(BOUNDS(num_axes,exc->stackSize+1-exc->top)){exc->error=FT_THROW(Stack_Overflow);return;}if(coords){for(i=0;i<num_axes;i++)args[i]=coords[i]>>2;/* convert 16.16 to 2.14 format */}else{for(i=0;i<num_axes;i++)args[i]=0;}}/*************************************************************************//* *//* 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. *//* */staticvoidIns_GETDATA(FT_Long*args){args[0]=17;}#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */staticvoidIns_UNKNOWN(TT_ExecContextexc){TT_DefRecord*def=exc->IDefs;TT_DefRecord*limit=def+exc->numIDefs;for(;def<limit;def++){if((FT_Byte)def->opc==exc->opcode&&def->active){TT_CallRec*call;if(exc->callTop>=exc->callSize){exc->error=FT_THROW(Stack_Overflow);return;}call=exc->callStack+exc->callTop++;call->Caller_Range=exc->curRange;call->Caller_IP=exc->IP+1;call->Cur_Count=1;call->Def=def;Ins_Goto_CodeRange(exc,def->range,def->start);exc->step_ins=FALSE;return;}}exc->error=FT_THROW(Invalid_Opcode);}/*************************************************************************//* *//* 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(TT_ExecContextexc){FT_ULongins_counter=0;/* executed instructions counter */FT_ULongnum_twilight_points;FT_UShorti;#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITYFT_Byteopcode_pattern[1][2]={/* #8 TypeMan Talk Align */{0x06,/* SPVTL */0x7D,/* RDTG */},};FT_UShortopcode_patterns=1;FT_UShortopcode_pointer[1]={0};FT_UShortopcode_size[1]={1};#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITYexc->iup_called=FALSE;#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL/* * Toggle backward compatibility according to what font wants, except * when * * 1) we have a `tricky' font that heavily relies on the interpreter to * render glyphs correctly, for example DFKai-SB, or * 2) FT_RENDER_MODE_MONO (i.e, monochome rendering) is requested. * * In those cases, backward compatibility needs to be turned off to get * correct rendering. The rendering is then completely up to the * font's programming. * */if(SUBPIXEL_HINTING_MINIMAL&&exc->subpixel_hinting_lean&&!FT_IS_TRICKY(&exc->face->root))exc->backward_compatibility=!(exc->GS.instruct_control&4);elseexc->backward_compatibility=FALSE;exc->iupx_called=FALSE;exc->iupy_called=FALSE;#endif/* We restrict the number of twilight points to a reasonable, *//* heuristic value to avoid slow execution of malformed bytecode. */num_twilight_points=FT_MAX(30,2*(exc->pts.n_points+exc->cvtSize));if(exc->twilight.n_points>num_twilight_points){if(num_twilight_points>0xFFFFU)num_twilight_points=0xFFFFU;FT_TRACE5(("TT_RunIns: Resetting number of twilight points\n"" from %d to the more reasonable value %d\n",exc->twilight.n_points,num_twilight_points));exc->twilight.n_points=(FT_UShort)num_twilight_points;}/* Set up loop detectors. We restrict the number of LOOPCALL loops *//* and the number of JMPR, JROT, and JROF calls with a negative *//* argument to values that depend on various parameters like the *//* size of the CVT table or the number of points in the current *//* glyph (if applicable). *//* *//* The idea is that in real-world bytecode you either iterate over *//* all CVT entries (in the `prep' table), or over all points (or *//* contours, in the `glyf' table) of a glyph, and such iterations *//* don't happen very often. */exc->loopcall_counter=0;exc->neg_jump_counter=0;/* The maximum values are heuristic. */if(exc->pts.n_points)exc->loopcall_counter_max=FT_MAX(50,10*exc->pts.n_points)+FT_MAX(50,exc->cvtSize/10);elseexc->loopcall_counter_max=300+8*exc->cvtSize;/* as a protection against an unreasonable number of CVT entries *//* we assume at most 100 control values per glyph for the counter */if(exc->loopcall_counter_max>100*(FT_ULong)exc->face->root.num_glyphs)exc->loopcall_counter_max=100*(FT_ULong)exc->face->root.num_glyphs;FT_TRACE5(("TT_RunIns: Limiting total number of loops in LOOPCALL"" to %d\n",exc->loopcall_counter_max));exc->neg_jump_counter_max=exc->loopcall_counter_max;FT_TRACE5(("TT_RunIns: Limiting total number of backward jumps"" to %d\n",exc->neg_jump_counter_max));/* set PPEM and CVT functions */exc->tt_metrics.ratio=0;if(exc->metrics.x_ppem!=exc->metrics.y_ppem){/* non-square pixels, use the stretched routines */exc->func_cur_ppem=Current_Ppem_Stretched;exc->func_read_cvt=Read_CVT_Stretched;exc->func_write_cvt=Write_CVT_Stretched;exc->func_move_cvt=Move_CVT_Stretched;}else{/* square pixels, use normal routines */exc->func_cur_ppem=Current_Ppem;exc->func_read_cvt=Read_CVT;exc->func_write_cvt=Write_CVT;exc->func_move_cvt=Move_CVT;}Compute_Funcs(exc);Compute_Round(exc,(FT_Byte)exc->GS.round_state);do{exc->opcode=exc->code[exc->IP];#ifdef FT_DEBUG_LEVEL_TRACE{FT_Longcnt=FT_MIN(8,exc->top);FT_Longn;/* if tracing level is 7, show current code position *//* and the first few stack elements also */FT_TRACE6((" "));FT_TRACE7(("%06d ",exc->IP));FT_TRACE6((opcode_name[exc->opcode]+2));FT_TRACE7(("%*s",*opcode_name[exc->opcode]=='A'?2:12-(*opcode_name[exc->opcode]-'0'),"#"));for(n=1;n<=cnt;n++)FT_TRACE7((" %d",exc->stack[exc->top-n]));FT_TRACE6(("\n"));}#endif /* FT_DEBUG_LEVEL_TRACE */if((exc->length=opcode_length[exc->opcode])<0){if(exc->IP+1>=exc->codeSize)gotoLErrorCodeOverflow_;exc->length=2-exc->length*exc->code[exc->IP+1];}if(exc->IP+exc->length>exc->codeSize)gotoLErrorCodeOverflow_;/* First, let's check for empty stack and overflow */exc->args=exc->top-(Pop_Push_Count[exc->opcode]>>4);/* `args' is the top of the stack once arguments have been popped. *//* One can also interpret it as the index of the last argument. */if(exc->args<0){if(exc->pedantic_hinting){exc->error=FT_THROW(Too_Few_Arguments);gotoLErrorLabel_;}/* push zeroes onto the stack */for(i=0;i<Pop_Push_Count[exc->opcode]>>4;i++)exc->stack[i]=0;exc->args=0;}#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORTif(exc->opcode==0x91){/* this is very special: GETVARIATION returns *//* a variable number of arguments *//* it is the job of the application to `activate' GX handling, *//* this is, calling any of the GX API functions on the current *//* font to select a variation instance */if(exc->face->blend)exc->new_top=exc->args+exc->face->blend->num_axis;}else#endifexc->new_top=exc->args+(Pop_Push_Count[exc->opcode]&15);/* `new_top' is the new top of the stack, after the instruction's *//* execution. `top' will be set to `new_top' after the `switch' *//* statement. */if(exc->new_top>exc->stackSize){exc->error=FT_THROW(Stack_Overflow);gotoLErrorLabel_;}exc->step_ins=TRUE;exc->error=FT_Err_Ok;#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITYif(SUBPIXEL_HINTING_INFINALITY){for(i=0;i<opcode_patterns;i++){if(opcode_pointer[i]<opcode_size[i]&&exc->opcode==opcode_pattern[i][opcode_pointer[i]]){opcode_pointer[i]+=1;if(opcode_pointer[i]==opcode_size[i]){FT_TRACE6(("sph: opcode ptrn: %d, %s %s\n",i,exc->face->root.family_name,exc->face->root.style_name));switch(i){case0:break;}opcode_pointer[i]=0;}}elseopcode_pointer[i]=0;}}#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */{FT_Long*args=exc->stack+exc->args;FT_Byteopcode=exc->opcode;switch(opcode){case0x00:/* SVTCA y */case0x01:/* SVTCA x */case0x02:/* SPvTCA y */case0x03:/* SPvTCA x */case0x04:/* SFvTCA y */case0x05:/* SFvTCA x */Ins_SxyTCA(exc);break;case0x06:/* SPvTL // */case0x07:/* SPvTL + */Ins_SPVTL(exc,args);break;case0x08:/* SFvTL // */case0x09:/* SFvTL + */Ins_SFVTL(exc,args);break;case0x0A:/* SPvFS */Ins_SPVFS(exc,args);break;case0x0B:/* SFvFS */Ins_SFVFS(exc,args);break;case0x0C:/* GPv */Ins_GPV(exc,args);break;case0x0D:/* GFv */Ins_GFV(exc,args);break;case0x0E:/* SFvTPv */Ins_SFVTPV(exc);break;case0x0F:/* ISECT */Ins_ISECT(exc,args);break;case0x10:/* SRP0 */Ins_SRP0(exc,args);break;case0x11:/* SRP1 */Ins_SRP1(exc,args);break;case0x12:/* SRP2 */Ins_SRP2(exc,args);break;case0x13:/* SZP0 */Ins_SZP0(exc,args);break;case0x14:/* SZP1 */Ins_SZP1(exc,args);break;case0x15:/* SZP2 */Ins_SZP2(exc,args);break;case0x16:/* SZPS */Ins_SZPS(exc,args);break;case0x17:/* SLOOP */Ins_SLOOP(exc,args);break;case0x18:/* RTG */Ins_RTG(exc);break;case0x19:/* RTHG */Ins_RTHG(exc);break;case0x1A:/* SMD */Ins_SMD(exc,args);break;case0x1B:/* ELSE */Ins_ELSE(exc);break;case0x1C:/* JMPR */Ins_JMPR(exc,args);break;case0x1D:/* SCVTCI */Ins_SCVTCI(exc,args);break;case0x1E:/* SSWCI */Ins_SSWCI(exc,args);break;case0x1F:/* SSW */Ins_SSW(exc,args);break;case0x20:/* DUP */Ins_DUP(args);break;case0x21:/* POP */Ins_POP();break;case0x22:/* CLEAR */Ins_CLEAR(exc);break;case0x23:/* SWAP */Ins_SWAP(args);break;case0x24:/* DEPTH */Ins_DEPTH(exc,args);break;case0x25:/* CINDEX */Ins_CINDEX(exc,args);break;case0x26:/* MINDEX */Ins_MINDEX(exc,args);break;case0x27:/* ALIGNPTS */Ins_ALIGNPTS(exc,args);break;case0x28:/* RAW */Ins_UNKNOWN(exc);break;case0x29:/* UTP */Ins_UTP(exc,args);break;case0x2A:/* LOOPCALL */Ins_LOOPCALL(exc,args);break;case0x2B:/* CALL */Ins_CALL(exc,args);break;case0x2C:/* FDEF */Ins_FDEF(exc,args);break;case0x2D:/* ENDF */Ins_ENDF(exc);break;case0x2E:/* MDAP */case0x2F:/* MDAP */Ins_MDAP(exc,args);break;case0x30:/* IUP */case0x31:/* IUP */Ins_IUP(exc);break;case0x32:/* SHP */case0x33:/* SHP */Ins_SHP(exc);break;case0x34:/* SHC */case0x35:/* SHC */Ins_SHC(exc,args);break;case0x36:/* SHZ */case0x37:/* SHZ */Ins_SHZ(exc,args);break;case0x38:/* SHPIX */Ins_SHPIX(exc,args);break;case0x39:/* IP */Ins_IP(exc);break;case0x3A:/* MSIRP */case0x3B:/* MSIRP */Ins_MSIRP(exc,args);break;case0x3C:/* AlignRP */Ins_ALIGNRP(exc);break;case0x3D:/* RTDG */Ins_RTDG(exc);break;case0x3E:/* MIAP */case0x3F:/* MIAP */Ins_MIAP(exc,args);break;case0x40:/* NPUSHB */Ins_NPUSHB(exc,args);break;case0x41:/* NPUSHW */Ins_NPUSHW(exc,args);break;case0x42:/* WS */Ins_WS(exc,args);break;case0x43:/* RS */Ins_RS(exc,args);break;case0x44:/* WCVTP */Ins_WCVTP(exc,args);break;case0x45:/* RCVT */Ins_RCVT(exc,args);break;case0x46:/* GC */case0x47:/* GC */Ins_GC(exc,args);break;case0x48:/* SCFS */Ins_SCFS(exc,args);break;case0x49:/* MD */case0x4A:/* MD */Ins_MD(exc,args);break;case0x4B:/* MPPEM */Ins_MPPEM(exc,args);break;case0x4C:/* MPS */Ins_MPS(exc,args);break;case0x4D:/* FLIPON */Ins_FLIPON(exc);break;case0x4E:/* FLIPOFF */Ins_FLIPOFF(exc);break;case0x4F:/* DEBUG */Ins_DEBUG(exc);break;case0x50:/* LT */Ins_LT(args);break;case0x51:/* LTEQ */Ins_LTEQ(args);break;case0x52:/* GT */Ins_GT(args);break;case0x53:/* GTEQ */Ins_GTEQ(args);break;case0x54:/* EQ */Ins_EQ(args);break;case0x55:/* NEQ */Ins_NEQ(args);break;case0x56:/* ODD */Ins_ODD(exc,args);break;case0x57:/* EVEN */Ins_EVEN(exc,args);break;case0x58:/* IF */Ins_IF(exc,args);break;case0x59:/* EIF */Ins_EIF();break;case0x5A:/* AND */Ins_AND(args);break;case0x5B:/* OR */Ins_OR(args);break;case0x5C:/* NOT */Ins_NOT(args);break;case0x5D:/* DELTAP1 */Ins_DELTAP(exc,args);break;case0x5E:/* SDB */Ins_SDB(exc,args);break;case0x5F:/* SDS */Ins_SDS(exc,args);break;case0x60:/* ADD */Ins_ADD(args);break;case0x61:/* SUB */Ins_SUB(args);break;case0x62:/* DIV */Ins_DIV(exc,args);break;case0x63:/* MUL */Ins_MUL(args);break;case0x64:/* ABS */Ins_ABS(args);break;case0x65:/* NEG */Ins_NEG(args);break;case0x66:/* FLOOR */Ins_FLOOR(args);break;case0x67:/* CEILING */Ins_CEILING(args);break;case0x68:/* ROUND */case0x69:/* ROUND */case0x6A:/* ROUND */case0x6B:/* ROUND */Ins_ROUND(exc,args);break;case0x6C:/* NROUND */case0x6D:/* NROUND */case0x6E:/* NRRUND */case0x6F:/* NROUND */Ins_NROUND(exc,args);break;case0x70:/* WCVTF */Ins_WCVTF(exc,args);break;case0x71:/* DELTAP2 */case0x72:/* DELTAP3 */Ins_DELTAP(exc,args);break;case0x73:/* DELTAC0 */case0x74:/* DELTAC1 */case0x75:/* DELTAC2 */Ins_DELTAC(exc,args);break;case0x76:/* SROUND */Ins_SROUND(exc,args);break;case0x77:/* S45Round */Ins_S45ROUND(exc,args);break;case0x78:/* JROT */Ins_JROT(exc,args);break;case0x79:/* JROF */Ins_JROF(exc,args);break;case0x7A:/* ROFF */Ins_ROFF(exc);break;case0x7B:/* ???? */Ins_UNKNOWN(exc);break;case0x7C:/* RUTG */Ins_RUTG(exc);break;case0x7D:/* RDTG */Ins_RDTG(exc);break;case0x7E:/* SANGW */Ins_SANGW();break;case0x7F:/* AA */Ins_AA();break;case0x80:/* FLIPPT */Ins_FLIPPT(exc);break;case0x81:/* FLIPRGON */Ins_FLIPRGON(exc,args);break;case0x82:/* FLIPRGOFF */Ins_FLIPRGOFF(exc,args);break;case0x83:/* UNKNOWN */case0x84:/* UNKNOWN */Ins_UNKNOWN(exc);break;case0x85:/* SCANCTRL */Ins_SCANCTRL(exc,args);break;case0x86:/* SDPvTL */case0x87:/* SDPvTL */Ins_SDPVTL(exc,args);break;case0x88:/* GETINFO */Ins_GETINFO(exc,args);break;case0x89:/* IDEF */Ins_IDEF(exc,args);break;case0x8A:/* ROLL */Ins_ROLL(args);break;case0x8B:/* MAX */Ins_MAX(args);break;case0x8C:/* MIN */Ins_MIN(args);break;case0x8D:/* SCANTYPE */Ins_SCANTYPE(exc,args);break;case0x8E:/* INSTCTRL */Ins_INSTCTRL(exc,args);break;case0x8F:/* ADJUST */case0x90:/* ADJUST */Ins_UNKNOWN(exc);break;#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORTcase0x91:/* it is the job of the application to `activate' GX handling, *//* this is, calling any of the GX API functions on the current *//* font to select a variation instance */if(exc->face->blend)Ins_GETVARIATION(exc,args);elseIns_UNKNOWN(exc);break;case0x92:/* there is at least one MS font (LaoUI.ttf version 5.01) that *//* uses IDEFs for 0x91 and 0x92; for this reason we activate *//* GETDATA for GX fonts only, similar to GETVARIATION */if(exc->face->blend)Ins_GETDATA(args);elseIns_UNKNOWN(exc);break;#endifdefault:if(opcode>=0xE0)Ins_MIRP(exc,args);elseif(opcode>=0xC0)Ins_MDRP(exc,args);elseif(opcode>=0xB8)Ins_PUSHW(exc,args);elseif(opcode>=0xB0)Ins_PUSHB(exc,args);elseIns_UNKNOWN(exc);}}if(exc->error){switch(exc->error){/* looking for redefined instructions */caseFT_ERR(Invalid_Opcode):{TT_DefRecord*def=exc->IDefs;TT_DefRecord*limit=def+exc->numIDefs;for(;def<limit;def++){if(def->active&&exc->opcode==(FT_Byte)def->opc){TT_CallRec*callrec;if(exc->callTop>=exc->callSize){exc->error=FT_THROW(Invalid_Reference);gotoLErrorLabel_;}callrec=&exc->callStack[exc->callTop];callrec->Caller_Range=exc->curRange;callrec->Caller_IP=exc->IP+1;callrec->Cur_Count=1;callrec->Def=def;if(Ins_Goto_CodeRange(exc,def->range,def->start)==FAILURE)gotoLErrorLabel_;gotoLSuiteLabel_;}}}exc->error=FT_THROW(Invalid_Opcode);gotoLErrorLabel_;#if 0 break; /* Unreachable code warning suppression. */ /* Leave to remind in case a later change the editor */ /* to consider break; */#endifdefault:gotoLErrorLabel_;#if 0 break;#endif}}exc->top=exc->new_top;if(exc->step_ins)exc->IP+=exc->length;/* increment instruction counter and check if we didn't *//* run this program for too long (e.g. infinite loops). */if(++ins_counter>TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES)returnFT_THROW(Execution_Too_Long);LSuiteLabel_:if(exc->IP>=exc->codeSize){if(exc->callTop>0){exc->error=FT_THROW(Code_Overflow);gotoLErrorLabel_;}elsegotoLNo_Error_;}}while(!exc->instruction_trap);LNo_Error_:FT_TRACE4((" %d instruction%s executed\n",ins_counter,ins_counter==1?"":"s"));returnFT_Err_Ok;LErrorCodeOverflow_:exc->error=FT_THROW(Code_Overflow);LErrorLabel_:if(exc->error&&!exc->instruction_trap)FT_TRACE1((" The interpreter returned error 0x%x\n",exc->error));returnexc->error;}#else /* !TT_USE_BYTECODE_INTERPRETER *//* ANSI C doesn't like empty source files */typedefint_tt_interp_dummy;#endif /* !TT_USE_BYTECODE_INTERPRETER *//* END */