Path: blob/master/thirdparty/freetype/src/truetype/ttinterp.c
10968 views
/****************************************************************************1*2* ttinterp.c3*4* TrueType bytecode interpreter (body).5*6* Copyright (C) 1996-2024 by7* David Turner, Robert Wilhelm, and Werner Lemberg.8*9* This file is part of the FreeType project, and may only be used,10* modified, and distributed under the terms of the FreeType project11* license, LICENSE.TXT. By continuing to use, modify, or distribute12* this file you indicate that you have read the license and13* understand and accept it fully.14*15*/161718/* Greg Hitchcock from Microsoft has helped a lot in resolving unclear */19/* issues; many thanks! */202122#include <freetype/internal/ftdebug.h>23#include <freetype/internal/ftcalc.h>24#include <freetype/fttrigon.h>25#include <freetype/ftsystem.h>26#include <freetype/ftdriver.h>27#include <freetype/ftmm.h>2829#include "ttinterp.h"30#include "tterrors.h"31#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT32#include "ttgxvar.h"33#endif343536#ifdef TT_USE_BYTECODE_INTERPRETER373839/**************************************************************************40*41* The macro FT_COMPONENT is used in trace mode. It is an implicit42* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log43* messages during execution.44*/45#undef FT_COMPONENT46#define FT_COMPONENT ttinterp474849#define NO_SUBPIXEL_HINTING \50( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \51TT_INTERPRETER_VERSION_35 )5253#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL54#define SUBPIXEL_HINTING_MINIMAL \55( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \56TT_INTERPRETER_VERSION_40 )57#endif5859#define PROJECT( v1, v2 ) \60exc->func_project( exc, \61SUB_LONG( (v1)->x, (v2)->x ), \62SUB_LONG( (v1)->y, (v2)->y ) )6364#define DUALPROJ( v1, v2 ) \65exc->func_dualproj( exc, \66SUB_LONG( (v1)->x, (v2)->x ), \67SUB_LONG( (v1)->y, (v2)->y ) )6869#define FAST_PROJECT( v ) \70exc->func_project( exc, (v)->x, (v)->y )7172#define FAST_DUALPROJ( v ) \73exc->func_dualproj( exc, (v)->x, (v)->y )747576/**************************************************************************77*78* Two simple bounds-checking macros.79*/80#define BOUNDS( x, n ) ( (FT_UInt)(x) >= (FT_UInt)(n) )81#define BOUNDSL( x, n ) ( (FT_ULong)(x) >= (FT_ULong)(n) )828384#undef SUCCESS85#define SUCCESS 08687#undef FAILURE88#define FAILURE 1899091/**************************************************************************92*93* CODERANGE FUNCTIONS94*95*/969798/**************************************************************************99*100* @Function:101* TT_Goto_CodeRange102*103* @Description:104* Switches to a new code range (updates the code related elements in105* `exec', and `IP').106*107* @Input:108* range ::109* The new execution code range.110*111* IP ::112* The new IP in the new code range.113*114* @InOut:115* exec ::116* The target execution context.117*/118FT_LOCAL_DEF( void )119TT_Goto_CodeRange( TT_ExecContext exec,120FT_Int range,121FT_Long IP )122{123TT_CodeRange* coderange;124125126FT_ASSERT( range >= 1 && range <= 3 );127128coderange = &exec->codeRangeTable[range - 1];129130FT_ASSERT( coderange->base );131132/* NOTE: Because the last instruction of a program may be a CALL */133/* which will return to the first byte *after* the code */134/* range, we test for IP <= Size instead of IP < Size. */135/* */136FT_ASSERT( IP <= coderange->size );137138exec->code = coderange->base;139exec->codeSize = coderange->size;140exec->IP = IP;141exec->curRange = range;142}143144145/**************************************************************************146*147* @Function:148* TT_Set_CodeRange149*150* @Description:151* Sets a code range.152*153* @Input:154* range ::155* The code range index.156*157* base ::158* The new code base.159*160* length ::161* The range size in bytes.162*163* @InOut:164* exec ::165* The target execution context.166*/167FT_LOCAL_DEF( void )168TT_Set_CodeRange( TT_ExecContext exec,169FT_Int range,170void* base,171FT_Long length )172{173FT_ASSERT( range >= 1 && range <= 3 );174175exec->codeRangeTable[range - 1].base = (FT_Byte*)base;176exec->codeRangeTable[range - 1].size = length;177}178179180/**************************************************************************181*182* @Function:183* TT_Clear_CodeRange184*185* @Description:186* Clears a code range.187*188* @Input:189* range ::190* The code range index.191*192* @InOut:193* exec ::194* The target execution context.195*/196FT_LOCAL_DEF( void )197TT_Clear_CodeRange( TT_ExecContext exec,198FT_Int range )199{200FT_ASSERT( range >= 1 && range <= 3 );201202exec->codeRangeTable[range - 1].base = NULL;203exec->codeRangeTable[range - 1].size = 0;204}205206207/**************************************************************************208*209* EXECUTION CONTEXT ROUTINES210*211*/212213214/**************************************************************************215*216* @Function:217* TT_Done_Context218*219* @Description:220* Destroys a given context.221*222* @Input:223* exec ::224* A handle to the target execution context.225*226* memory ::227* A handle to the parent memory object.228*229* @Note:230* Only the glyph loader and debugger should call this function.231*/232FT_LOCAL_DEF( void )233TT_Done_Context( TT_ExecContext exec )234{235FT_Memory memory = exec->memory;236237238/* points zone */239exec->maxPoints = 0;240exec->maxContours = 0;241242/* free stack */243FT_FREE( exec->stack );244exec->stackSize = 0;245246/* free glyf cvt working area */247FT_FREE( exec->glyfCvt );248exec->glyfCvtSize = 0;249250/* free glyf storage working area */251FT_FREE( exec->glyfStorage );252exec->glyfStoreSize = 0;253254/* free call stack */255FT_FREE( exec->callStack );256exec->callSize = 0;257exec->callTop = 0;258259/* free glyph code range */260FT_FREE( exec->glyphIns );261exec->glyphSize = 0;262263exec->size = NULL;264exec->face = NULL;265266FT_FREE( exec );267}268269270/**************************************************************************271*272* @Function:273* TT_Load_Context274*275* @Description:276* Prepare an execution context for glyph hinting.277*278* @Input:279* face ::280* A handle to the source face object.281*282* size ::283* A handle to the source size object.284*285* @InOut:286* exec ::287* A handle to the target execution context.288*289* @Return:290* FreeType error code. 0 means success.291*292* @Note:293* Only the glyph loader and debugger should call this function.294*295* Note that not all members of `TT_ExecContext` get initialized.296*/297FT_LOCAL_DEF( FT_Error )298TT_Load_Context( TT_ExecContext exec,299TT_Face face,300TT_Size size )301{302FT_Int i;303TT_MaxProfile* maxp;304FT_Error error;305FT_Memory memory = exec->memory;306307308exec->face = face;309maxp = &face->max_profile;310exec->size = size;311312if ( size )313{314exec->numFDefs = size->num_function_defs;315exec->maxFDefs = size->max_function_defs;316exec->numIDefs = size->num_instruction_defs;317exec->maxIDefs = size->max_instruction_defs;318exec->FDefs = size->function_defs;319exec->IDefs = size->instruction_defs;320exec->pointSize = size->point_size;321exec->tt_metrics = size->ttmetrics;322exec->metrics = *size->metrics;323324exec->maxFunc = size->max_func;325exec->maxIns = size->max_ins;326327for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )328exec->codeRangeTable[i] = size->codeRangeTable[i];329330/* set graphics state */331exec->GS = size->GS;332333exec->cvtSize = size->cvt_size;334exec->cvt = size->cvt;335336exec->storeSize = size->storage_size;337exec->storage = size->storage;338339exec->twilight = size->twilight;340341/* In case of multi-threading it can happen that the old size object */342/* no longer exists, thus we must clear all glyph zone references. */343FT_ZERO( &exec->zp0 );344exec->zp1 = exec->zp0;345exec->zp2 = exec->zp0;346}347348/* XXX: We reserve a little more elements on the stack to deal safely */349/* with broken fonts like arialbs, courbs, timesbs, etc. */350if ( FT_QRENEW_ARRAY( exec->stack,351exec->stackSize,352maxp->maxStackElements + 32 ) )353return error;354exec->stackSize = maxp->maxStackElements + 32;355356/* free previous glyph code range */357FT_FREE( exec->glyphIns );358exec->glyphSize = 0;359360exec->pts.n_points = 0;361exec->pts.n_contours = 0;362363exec->zp1 = exec->pts;364exec->zp2 = exec->pts;365exec->zp0 = exec->pts;366367exec->instruction_trap = FALSE;368369return FT_Err_Ok;370}371372373/**************************************************************************374*375* @Function:376* TT_Save_Context377*378* @Description:379* Saves the code ranges in a `size' object.380*381* @Input:382* exec ::383* A handle to the source execution context.384*385* @InOut:386* size ::387* A handle to the target size object.388*389* @Note:390* Only the glyph loader and debugger should call this function.391*/392FT_LOCAL_DEF( void )393TT_Save_Context( TT_ExecContext exec,394TT_Size size )395{396FT_Int i;397398399/* XXX: Will probably disappear soon with all the code range */400/* management, which is now rather obsolete. */401/* */402size->num_function_defs = exec->numFDefs;403size->num_instruction_defs = exec->numIDefs;404405size->max_func = exec->maxFunc;406size->max_ins = exec->maxIns;407408for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )409size->codeRangeTable[i] = exec->codeRangeTable[i];410}411412413/**************************************************************************414*415* @Function:416* TT_Run_Context417*418* @Description:419* Executes one or more instructions in the execution context.420*421* @Input:422* exec ::423* A handle to the target execution context.424*425* @Return:426* TrueType error code. 0 means success.427*/428FT_LOCAL_DEF( FT_Error )429TT_Run_Context( TT_ExecContext exec )430{431TT_Goto_CodeRange( exec, tt_coderange_glyph, 0 );432433exec->zp0 = exec->pts;434exec->zp1 = exec->pts;435exec->zp2 = exec->pts;436437exec->GS.gep0 = 1;438exec->GS.gep1 = 1;439exec->GS.gep2 = 1;440441exec->GS.projVector.x = 0x4000;442exec->GS.projVector.y = 0x0000;443444exec->GS.freeVector = exec->GS.projVector;445exec->GS.dualVector = exec->GS.projVector;446447exec->GS.round_state = 1;448exec->GS.loop = 1;449450/* some glyphs leave something on the stack. so we clean it */451/* before a new execution. */452exec->top = 0;453exec->callTop = 0;454455return exec->face->interpreter( exec );456}457458459/* The default value for `scan_control' is documented as FALSE in the */460/* TrueType specification. This is confusing since it implies a */461/* Boolean value. However, this is not the case, thus both the */462/* default values of our `scan_type' and `scan_control' fields (which */463/* the documentation's `scan_control' variable is split into) are */464/* zero. */465466const TT_GraphicsState tt_default_graphics_state =467{4680, 0, 0,469{ 0x4000, 0 },470{ 0x4000, 0 },471{ 0x4000, 0 },4724731, 64, 1,474TRUE, 68, 0, 0, 9, 3,4750, FALSE, 0, 1, 1, 1476};477478479/* documentation is in ttinterp.h */480481FT_EXPORT_DEF( TT_ExecContext )482TT_New_Context( TT_Driver driver )483{484FT_Memory memory;485FT_Error error;486487TT_ExecContext exec = NULL;488489490if ( !driver )491goto Fail;492493memory = driver->root.root.memory;494495/* allocate object and zero everything inside */496if ( FT_NEW( exec ) )497goto Fail;498499/* create callStack here, other allocations delayed */500exec->memory = memory;501exec->callSize = 32;502503if ( FT_QNEW_ARRAY( exec->callStack, exec->callSize ) )504FT_FREE( exec );505506Fail:507return exec;508}509510511/**************************************************************************512*513* Before an opcode is executed, the interpreter verifies that there are514* enough arguments on the stack, with the help of the `Pop_Push_Count'515* table.516*517* For each opcode, the first column gives the number of arguments that518* are popped from the stack; the second one gives the number of those519* that are pushed in result.520*521* Opcodes which have a varying number of parameters in the data stream522* (NPUSHB, NPUSHW) are handled specially; they have a negative value in523* the `opcode_length' table, and the value in `Pop_Push_Count' is set524* to zero.525*526*/527528529#undef PACK530#define PACK( x, y ) ( ( x << 4 ) | y )531532533static534const FT_Byte Pop_Push_Count[256] =535{536/* opcodes are gathered in groups of 16 */537/* please keep the spaces as they are */538539/* 0x00 */540/* SVTCA[0] */ PACK( 0, 0 ),541/* SVTCA[1] */ PACK( 0, 0 ),542/* SPVTCA[0] */ PACK( 0, 0 ),543/* SPVTCA[1] */ PACK( 0, 0 ),544/* SFVTCA[0] */ PACK( 0, 0 ),545/* SFVTCA[1] */ PACK( 0, 0 ),546/* SPVTL[0] */ PACK( 2, 0 ),547/* SPVTL[1] */ PACK( 2, 0 ),548/* SFVTL[0] */ PACK( 2, 0 ),549/* SFVTL[1] */ PACK( 2, 0 ),550/* SPVFS */ PACK( 2, 0 ),551/* SFVFS */ PACK( 2, 0 ),552/* GPV */ PACK( 0, 2 ),553/* GFV */ PACK( 0, 2 ),554/* SFVTPV */ PACK( 0, 0 ),555/* ISECT */ PACK( 5, 0 ),556557/* 0x10 */558/* SRP0 */ PACK( 1, 0 ),559/* SRP1 */ PACK( 1, 0 ),560/* SRP2 */ PACK( 1, 0 ),561/* SZP0 */ PACK( 1, 0 ),562/* SZP1 */ PACK( 1, 0 ),563/* SZP2 */ PACK( 1, 0 ),564/* SZPS */ PACK( 1, 0 ),565/* SLOOP */ PACK( 1, 0 ),566/* RTG */ PACK( 0, 0 ),567/* RTHG */ PACK( 0, 0 ),568/* SMD */ PACK( 1, 0 ),569/* ELSE */ PACK( 0, 0 ),570/* JMPR */ PACK( 1, 0 ),571/* SCVTCI */ PACK( 1, 0 ),572/* SSWCI */ PACK( 1, 0 ),573/* SSW */ PACK( 1, 0 ),574575/* 0x20 */576/* DUP */ PACK( 1, 2 ),577/* POP */ PACK( 1, 0 ),578/* CLEAR */ PACK( 0, 0 ),579/* SWAP */ PACK( 2, 2 ),580/* DEPTH */ PACK( 0, 1 ),581/* CINDEX */ PACK( 1, 1 ),582/* MINDEX */ PACK( 1, 0 ),583/* ALIGNPTS */ PACK( 2, 0 ),584/* INS_$28 */ PACK( 0, 0 ),585/* UTP */ PACK( 1, 0 ),586/* LOOPCALL */ PACK( 2, 0 ),587/* CALL */ PACK( 1, 0 ),588/* FDEF */ PACK( 1, 0 ),589/* ENDF */ PACK( 0, 0 ),590/* MDAP[0] */ PACK( 1, 0 ),591/* MDAP[1] */ PACK( 1, 0 ),592593/* 0x30 */594/* IUP[0] */ PACK( 0, 0 ),595/* IUP[1] */ PACK( 0, 0 ),596/* SHP[0] */ PACK( 0, 0 ), /* loops */597/* SHP[1] */ PACK( 0, 0 ), /* loops */598/* SHC[0] */ PACK( 1, 0 ),599/* SHC[1] */ PACK( 1, 0 ),600/* SHZ[0] */ PACK( 1, 0 ),601/* SHZ[1] */ PACK( 1, 0 ),602/* SHPIX */ PACK( 1, 0 ), /* loops */603/* IP */ PACK( 0, 0 ), /* loops */604/* MSIRP[0] */ PACK( 2, 0 ),605/* MSIRP[1] */ PACK( 2, 0 ),606/* ALIGNRP */ PACK( 0, 0 ), /* loops */607/* RTDG */ PACK( 0, 0 ),608/* MIAP[0] */ PACK( 2, 0 ),609/* MIAP[1] */ PACK( 2, 0 ),610611/* 0x40 */612/* NPUSHB */ PACK( 0, 0 ),613/* NPUSHW */ PACK( 0, 0 ),614/* WS */ PACK( 2, 0 ),615/* RS */ PACK( 1, 1 ),616/* WCVTP */ PACK( 2, 0 ),617/* RCVT */ PACK( 1, 1 ),618/* GC[0] */ PACK( 1, 1 ),619/* GC[1] */ PACK( 1, 1 ),620/* SCFS */ PACK( 2, 0 ),621/* MD[0] */ PACK( 2, 1 ),622/* MD[1] */ PACK( 2, 1 ),623/* MPPEM */ PACK( 0, 1 ),624/* MPS */ PACK( 0, 1 ),625/* FLIPON */ PACK( 0, 0 ),626/* FLIPOFF */ PACK( 0, 0 ),627/* DEBUG */ PACK( 1, 0 ),628629/* 0x50 */630/* LT */ PACK( 2, 1 ),631/* LTEQ */ PACK( 2, 1 ),632/* GT */ PACK( 2, 1 ),633/* GTEQ */ PACK( 2, 1 ),634/* EQ */ PACK( 2, 1 ),635/* NEQ */ PACK( 2, 1 ),636/* ODD */ PACK( 1, 1 ),637/* EVEN */ PACK( 1, 1 ),638/* IF */ PACK( 1, 0 ),639/* EIF */ PACK( 0, 0 ),640/* AND */ PACK( 2, 1 ),641/* OR */ PACK( 2, 1 ),642/* NOT */ PACK( 1, 1 ),643/* DELTAP1 */ PACK( 1, 0 ),644/* SDB */ PACK( 1, 0 ),645/* SDS */ PACK( 1, 0 ),646647/* 0x60 */648/* ADD */ PACK( 2, 1 ),649/* SUB */ PACK( 2, 1 ),650/* DIV */ PACK( 2, 1 ),651/* MUL */ PACK( 2, 1 ),652/* ABS */ PACK( 1, 1 ),653/* NEG */ PACK( 1, 1 ),654/* FLOOR */ PACK( 1, 1 ),655/* CEILING */ PACK( 1, 1 ),656/* ROUND[0] */ PACK( 1, 1 ),657/* ROUND[1] */ PACK( 1, 1 ),658/* ROUND[2] */ PACK( 1, 1 ),659/* ROUND[3] */ PACK( 1, 1 ),660/* NROUND[0] */ PACK( 1, 1 ),661/* NROUND[1] */ PACK( 1, 1 ),662/* NROUND[2] */ PACK( 1, 1 ),663/* NROUND[3] */ PACK( 1, 1 ),664665/* 0x70 */666/* WCVTF */ PACK( 2, 0 ),667/* DELTAP2 */ PACK( 1, 0 ),668/* DELTAP3 */ PACK( 1, 0 ),669/* DELTAC1 */ PACK( 1, 0 ),670/* DELTAC2 */ PACK( 1, 0 ),671/* DELTAC3 */ PACK( 1, 0 ),672/* SROUND */ PACK( 1, 0 ),673/* S45ROUND */ PACK( 1, 0 ),674/* JROT */ PACK( 2, 0 ),675/* JROF */ PACK( 2, 0 ),676/* ROFF */ PACK( 0, 0 ),677/* INS_$7B */ PACK( 0, 0 ),678/* RUTG */ PACK( 0, 0 ),679/* RDTG */ PACK( 0, 0 ),680/* SANGW */ PACK( 1, 0 ),681/* AA */ PACK( 1, 0 ),682683/* 0x80 */684/* FLIPPT */ PACK( 0, 0 ), /* loops */685/* FLIPRGON */ PACK( 2, 0 ),686/* FLIPRGOFF */ PACK( 2, 0 ),687/* INS_$83 */ PACK( 0, 0 ),688/* INS_$84 */ PACK( 0, 0 ),689/* SCANCTRL */ PACK( 1, 0 ),690/* SDPVTL[0] */ PACK( 2, 0 ),691/* SDPVTL[1] */ PACK( 2, 0 ),692/* GETINFO */ PACK( 1, 1 ),693/* IDEF */ PACK( 1, 0 ),694/* ROLL */ PACK( 3, 3 ),695/* MAX */ PACK( 2, 1 ),696/* MIN */ PACK( 2, 1 ),697/* SCANTYPE */ PACK( 1, 0 ),698/* INSTCTRL */ PACK( 2, 0 ),699/* INS_$8F */ PACK( 0, 0 ),700701/* 0x90 */702/* INS_$90 */ PACK( 0, 0 ),703/* GETVAR */ PACK( 0, 0 ), /* will be handled specially */704/* GETDATA */ PACK( 0, 1 ),705/* INS_$93 */ PACK( 0, 0 ),706/* INS_$94 */ PACK( 0, 0 ),707/* INS_$95 */ PACK( 0, 0 ),708/* INS_$96 */ PACK( 0, 0 ),709/* INS_$97 */ PACK( 0, 0 ),710/* INS_$98 */ PACK( 0, 0 ),711/* INS_$99 */ PACK( 0, 0 ),712/* INS_$9A */ PACK( 0, 0 ),713/* INS_$9B */ PACK( 0, 0 ),714/* INS_$9C */ PACK( 0, 0 ),715/* INS_$9D */ PACK( 0, 0 ),716/* INS_$9E */ PACK( 0, 0 ),717/* INS_$9F */ PACK( 0, 0 ),718719/* 0xA0 */720/* INS_$A0 */ PACK( 0, 0 ),721/* INS_$A1 */ PACK( 0, 0 ),722/* INS_$A2 */ PACK( 0, 0 ),723/* INS_$A3 */ PACK( 0, 0 ),724/* INS_$A4 */ PACK( 0, 0 ),725/* INS_$A5 */ PACK( 0, 0 ),726/* INS_$A6 */ PACK( 0, 0 ),727/* INS_$A7 */ PACK( 0, 0 ),728/* INS_$A8 */ PACK( 0, 0 ),729/* INS_$A9 */ PACK( 0, 0 ),730/* INS_$AA */ PACK( 0, 0 ),731/* INS_$AB */ PACK( 0, 0 ),732/* INS_$AC */ PACK( 0, 0 ),733/* INS_$AD */ PACK( 0, 0 ),734/* INS_$AE */ PACK( 0, 0 ),735/* INS_$AF */ PACK( 0, 0 ),736737/* 0xB0 */738/* PUSHB[0] */ PACK( 0, 1 ),739/* PUSHB[1] */ PACK( 0, 2 ),740/* PUSHB[2] */ PACK( 0, 3 ),741/* PUSHB[3] */ PACK( 0, 4 ),742/* PUSHB[4] */ PACK( 0, 5 ),743/* PUSHB[5] */ PACK( 0, 6 ),744/* PUSHB[6] */ PACK( 0, 7 ),745/* PUSHB[7] */ PACK( 0, 8 ),746/* PUSHW[0] */ PACK( 0, 1 ),747/* PUSHW[1] */ PACK( 0, 2 ),748/* PUSHW[2] */ PACK( 0, 3 ),749/* PUSHW[3] */ PACK( 0, 4 ),750/* PUSHW[4] */ PACK( 0, 5 ),751/* PUSHW[5] */ PACK( 0, 6 ),752/* PUSHW[6] */ PACK( 0, 7 ),753/* PUSHW[7] */ PACK( 0, 8 ),754755/* 0xC0 */756/* MDRP[00] */ PACK( 1, 0 ),757/* MDRP[01] */ PACK( 1, 0 ),758/* MDRP[02] */ PACK( 1, 0 ),759/* MDRP[03] */ PACK( 1, 0 ),760/* MDRP[04] */ PACK( 1, 0 ),761/* MDRP[05] */ PACK( 1, 0 ),762/* MDRP[06] */ PACK( 1, 0 ),763/* MDRP[07] */ PACK( 1, 0 ),764/* MDRP[08] */ PACK( 1, 0 ),765/* MDRP[09] */ PACK( 1, 0 ),766/* MDRP[10] */ PACK( 1, 0 ),767/* MDRP[11] */ PACK( 1, 0 ),768/* MDRP[12] */ PACK( 1, 0 ),769/* MDRP[13] */ PACK( 1, 0 ),770/* MDRP[14] */ PACK( 1, 0 ),771/* MDRP[15] */ PACK( 1, 0 ),772773/* 0xD0 */774/* MDRP[16] */ PACK( 1, 0 ),775/* MDRP[17] */ PACK( 1, 0 ),776/* MDRP[18] */ PACK( 1, 0 ),777/* MDRP[19] */ PACK( 1, 0 ),778/* MDRP[20] */ PACK( 1, 0 ),779/* MDRP[21] */ PACK( 1, 0 ),780/* MDRP[22] */ PACK( 1, 0 ),781/* MDRP[23] */ PACK( 1, 0 ),782/* MDRP[24] */ PACK( 1, 0 ),783/* MDRP[25] */ PACK( 1, 0 ),784/* MDRP[26] */ PACK( 1, 0 ),785/* MDRP[27] */ PACK( 1, 0 ),786/* MDRP[28] */ PACK( 1, 0 ),787/* MDRP[29] */ PACK( 1, 0 ),788/* MDRP[30] */ PACK( 1, 0 ),789/* MDRP[31] */ PACK( 1, 0 ),790791/* 0xE0 */792/* MIRP[00] */ PACK( 2, 0 ),793/* MIRP[01] */ PACK( 2, 0 ),794/* MIRP[02] */ PACK( 2, 0 ),795/* MIRP[03] */ PACK( 2, 0 ),796/* MIRP[04] */ PACK( 2, 0 ),797/* MIRP[05] */ PACK( 2, 0 ),798/* MIRP[06] */ PACK( 2, 0 ),799/* MIRP[07] */ PACK( 2, 0 ),800/* MIRP[08] */ PACK( 2, 0 ),801/* MIRP[09] */ PACK( 2, 0 ),802/* MIRP[10] */ PACK( 2, 0 ),803/* MIRP[11] */ PACK( 2, 0 ),804/* MIRP[12] */ PACK( 2, 0 ),805/* MIRP[13] */ PACK( 2, 0 ),806/* MIRP[14] */ PACK( 2, 0 ),807/* MIRP[15] */ PACK( 2, 0 ),808809/* 0xF0 */810/* MIRP[16] */ PACK( 2, 0 ),811/* MIRP[17] */ PACK( 2, 0 ),812/* MIRP[18] */ PACK( 2, 0 ),813/* MIRP[19] */ PACK( 2, 0 ),814/* MIRP[20] */ PACK( 2, 0 ),815/* MIRP[21] */ PACK( 2, 0 ),816/* MIRP[22] */ PACK( 2, 0 ),817/* MIRP[23] */ PACK( 2, 0 ),818/* MIRP[24] */ PACK( 2, 0 ),819/* MIRP[25] */ PACK( 2, 0 ),820/* MIRP[26] */ PACK( 2, 0 ),821/* MIRP[27] */ PACK( 2, 0 ),822/* MIRP[28] */ PACK( 2, 0 ),823/* MIRP[29] */ PACK( 2, 0 ),824/* MIRP[30] */ PACK( 2, 0 ),825/* MIRP[31] */ PACK( 2, 0 )826};827828829#ifdef FT_DEBUG_LEVEL_TRACE830831/* the first hex digit gives the length of the opcode name; the space */832/* after the digit is here just to increase readability of the source */833/* code */834835static836const char* const opcode_name[256] =837{838/* 0x00 */839"8 SVTCA[y]",840"8 SVTCA[x]",841"9 SPVTCA[y]",842"9 SPVTCA[x]",843"9 SFVTCA[y]",844"9 SFVTCA[x]",845"9 SPVTL[||]",846"8 SPVTL[+]",847"9 SFVTL[||]",848"8 SFVTL[+]",849"5 SPVFS",850"5 SFVFS",851"3 GPV",852"3 GFV",853"6 SFVTPV",854"5 ISECT",855856/* 0x10 */857"4 SRP0",858"4 SRP1",859"4 SRP2",860"4 SZP0",861"4 SZP1",862"4 SZP2",863"4 SZPS",864"5 SLOOP",865"3 RTG",866"4 RTHG",867"3 SMD",868"4 ELSE",869"4 JMPR",870"6 SCVTCI",871"5 SSWCI",872"3 SSW",873874/* 0x20 */875"3 DUP",876"3 POP",877"5 CLEAR",878"4 SWAP",879"5 DEPTH",880"6 CINDEX",881"6 MINDEX",882"8 ALIGNPTS",883"7 INS_$28",884"3 UTP",885"8 LOOPCALL",886"4 CALL",887"4 FDEF",888"4 ENDF",889"6 MDAP[]",890"9 MDAP[rnd]",891892/* 0x30 */893"6 IUP[y]",894"6 IUP[x]",895"8 SHP[rp2]",896"8 SHP[rp1]",897"8 SHC[rp2]",898"8 SHC[rp1]",899"8 SHZ[rp2]",900"8 SHZ[rp1]",901"5 SHPIX",902"2 IP",903"7 MSIRP[]",904"A MSIRP[rp0]",905"7 ALIGNRP",906"4 RTDG",907"6 MIAP[]",908"9 MIAP[rnd]",909910/* 0x40 */911"6 NPUSHB",912"6 NPUSHW",913"2 WS",914"2 RS",915"5 WCVTP",916"4 RCVT",917"8 GC[curr]",918"8 GC[orig]",919"4 SCFS",920"8 MD[curr]",921"8 MD[orig]",922"5 MPPEM",923"3 MPS",924"6 FLIPON",925"7 FLIPOFF",926"5 DEBUG",927928/* 0x50 */929"2 LT",930"4 LTEQ",931"2 GT",932"4 GTEQ",933"2 EQ",934"3 NEQ",935"3 ODD",936"4 EVEN",937"2 IF",938"3 EIF",939"3 AND",940"2 OR",941"3 NOT",942"7 DELTAP1",943"3 SDB",944"3 SDS",945946/* 0x60 */947"3 ADD",948"3 SUB",949"3 DIV",950"3 MUL",951"3 ABS",952"3 NEG",953"5 FLOOR",954"7 CEILING",955"8 ROUND[G]",956"8 ROUND[B]",957"8 ROUND[W]",958"7 ROUND[]",959"9 NROUND[G]",960"9 NROUND[B]",961"9 NROUND[W]",962"8 NROUND[]",963964/* 0x70 */965"5 WCVTF",966"7 DELTAP2",967"7 DELTAP3",968"7 DELTAC1",969"7 DELTAC2",970"7 DELTAC3",971"6 SROUND",972"8 S45ROUND",973"4 JROT",974"4 JROF",975"4 ROFF",976"7 INS_$7B",977"4 RUTG",978"4 RDTG",979"5 SANGW",980"2 AA",981982/* 0x80 */983"6 FLIPPT",984"8 FLIPRGON",985"9 FLIPRGOFF",986"7 INS_$83",987"7 INS_$84",988"8 SCANCTRL",989"A SDPVTL[||]",990"9 SDPVTL[+]",991"7 GETINFO",992"4 IDEF",993"4 ROLL",994"3 MAX",995"3 MIN",996"8 SCANTYPE",997"8 INSTCTRL",998"7 INS_$8F",9991000/* 0x90 */1001"7 INS_$90",1002#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT1003"C GETVARIATION",1004"7 GETDATA",1005#else1006"7 INS_$91",1007"7 INS_$92",1008#endif1009"7 INS_$93",1010"7 INS_$94",1011"7 INS_$95",1012"7 INS_$96",1013"7 INS_$97",1014"7 INS_$98",1015"7 INS_$99",1016"7 INS_$9A",1017"7 INS_$9B",1018"7 INS_$9C",1019"7 INS_$9D",1020"7 INS_$9E",1021"7 INS_$9F",10221023/* 0xA0 */1024"7 INS_$A0",1025"7 INS_$A1",1026"7 INS_$A2",1027"7 INS_$A3",1028"7 INS_$A4",1029"7 INS_$A5",1030"7 INS_$A6",1031"7 INS_$A7",1032"7 INS_$A8",1033"7 INS_$A9",1034"7 INS_$AA",1035"7 INS_$AB",1036"7 INS_$AC",1037"7 INS_$AD",1038"7 INS_$AE",1039"7 INS_$AF",10401041/* 0xB0 */1042"8 PUSHB[0]",1043"8 PUSHB[1]",1044"8 PUSHB[2]",1045"8 PUSHB[3]",1046"8 PUSHB[4]",1047"8 PUSHB[5]",1048"8 PUSHB[6]",1049"8 PUSHB[7]",1050"8 PUSHW[0]",1051"8 PUSHW[1]",1052"8 PUSHW[2]",1053"8 PUSHW[3]",1054"8 PUSHW[4]",1055"8 PUSHW[5]",1056"8 PUSHW[6]",1057"8 PUSHW[7]",10581059/* 0xC0 */1060"7 MDRP[G]",1061"7 MDRP[B]",1062"7 MDRP[W]",1063"6 MDRP[]",1064"8 MDRP[rG]",1065"8 MDRP[rB]",1066"8 MDRP[rW]",1067"7 MDRP[r]",1068"8 MDRP[mG]",1069"8 MDRP[mB]",1070"8 MDRP[mW]",1071"7 MDRP[m]",1072"9 MDRP[mrG]",1073"9 MDRP[mrB]",1074"9 MDRP[mrW]",1075"8 MDRP[mr]",10761077/* 0xD0 */1078"8 MDRP[pG]",1079"8 MDRP[pB]",1080"8 MDRP[pW]",1081"7 MDRP[p]",1082"9 MDRP[prG]",1083"9 MDRP[prB]",1084"9 MDRP[prW]",1085"8 MDRP[pr]",1086"9 MDRP[pmG]",1087"9 MDRP[pmB]",1088"9 MDRP[pmW]",1089"8 MDRP[pm]",1090"A MDRP[pmrG]",1091"A MDRP[pmrB]",1092"A MDRP[pmrW]",1093"9 MDRP[pmr]",10941095/* 0xE0 */1096"7 MIRP[G]",1097"7 MIRP[B]",1098"7 MIRP[W]",1099"6 MIRP[]",1100"8 MIRP[rG]",1101"8 MIRP[rB]",1102"8 MIRP[rW]",1103"7 MIRP[r]",1104"8 MIRP[mG]",1105"8 MIRP[mB]",1106"8 MIRP[mW]",1107"7 MIRP[m]",1108"9 MIRP[mrG]",1109"9 MIRP[mrB]",1110"9 MIRP[mrW]",1111"8 MIRP[mr]",11121113/* 0xF0 */1114"8 MIRP[pG]",1115"8 MIRP[pB]",1116"8 MIRP[pW]",1117"7 MIRP[p]",1118"9 MIRP[prG]",1119"9 MIRP[prB]",1120"9 MIRP[prW]",1121"8 MIRP[pr]",1122"9 MIRP[pmG]",1123"9 MIRP[pmB]",1124"9 MIRP[pmW]",1125"8 MIRP[pm]",1126"A MIRP[pmrG]",1127"A MIRP[pmrB]",1128"A MIRP[pmrW]",1129"9 MIRP[pmr]"1130};11311132#endif /* FT_DEBUG_LEVEL_TRACE */113311341135static1136const FT_Char opcode_length[256] =1137{11381, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,11391, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,11401, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,11411, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,11421143-1,-2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,11441, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,11451, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,11461, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,114711481, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,11491, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,11501, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,11512, 3, 4, 5, 6, 7, 8, 9, 3, 5, 7, 9, 11,13,15,17,115211531, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,11541, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,11551, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,11561, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 11157};11581159#undef PACK116011611162#ifndef FT_CONFIG_OPTION_NO_ASSEMBLER11631164#if defined( __arm__ ) && \1165( defined( __thumb2__ ) || !defined( __thumb__ ) )11661167#define TT_MulFix14 TT_MulFix14_arm11681169static FT_Int321170TT_MulFix14_arm( FT_Int32 a,1171FT_Int b )1172{1173FT_Int32 t, t2;117411751176#if defined( __CC_ARM ) || defined( __ARMCC__ )11771178__asm1179{1180smull t2, t, b, a /* (lo=t2,hi=t) = a*b */1181mov a, t, asr #31 /* a = (hi >> 31) */1182add a, a, #0x2000 /* a += 0x2000 */1183adds t2, t2, a /* t2 += a */1184adc t, t, #0 /* t += carry */1185mov a, t2, lsr #14 /* a = t2 >> 14 */1186orr a, a, t, lsl #18 /* a |= t << 18 */1187}11881189#elif defined( __GNUC__ )11901191__asm__ __volatile__ (1192"smull %1, %2, %4, %3\n\t" /* (lo=%1,hi=%2) = a*b */1193"mov %0, %2, asr #31\n\t" /* %0 = (hi >> 31) */1194#if defined( __clang__ ) && defined( __thumb2__ )1195"add.w %0, %0, #0x2000\n\t" /* %0 += 0x2000 */1196#else1197"add %0, %0, #0x2000\n\t" /* %0 += 0x2000 */1198#endif1199"adds %1, %1, %0\n\t" /* %1 += %0 */1200"adc %2, %2, #0\n\t" /* %2 += carry */1201"mov %0, %1, lsr #14\n\t" /* %0 = %1 >> 16 */1202"orr %0, %0, %2, lsl #18\n\t" /* %0 |= %2 << 16 */1203: "=r"(a), "=&r"(t2), "=&r"(t)1204: "r"(a), "r"(b)1205: "cc" );12061207#endif12081209return a;1210}12111212#endif /* __arm__ && ( __thumb2__ || !__thumb__ ) */12131214#endif /* !FT_CONFIG_OPTION_NO_ASSEMBLER */121512161217#if defined( __GNUC__ ) && \1218( defined( __i386__ ) || defined( __x86_64__ ) )12191220#define TT_MulFix14 TT_MulFix14_long_long12211222/* Temporarily disable the warning that C90 doesn't support `long long'. */1223#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 4061224#pragma GCC diagnostic push1225#endif1226#pragma GCC diagnostic ignored "-Wlong-long"12271228/* This is declared `noinline' because inlining the function results */1229/* in slower code. The `pure' attribute indicates that the result */1230/* only depends on the parameters. */1231static __attribute__(( noinline ))1232__attribute__(( pure )) FT_Int321233TT_MulFix14_long_long( FT_Int32 a,1234FT_Int b )1235{12361237long long ret = (long long)a * b;12381239/* The following line assumes that right shifting of signed values */1240/* will actually preserve the sign bit. The exact behaviour is */1241/* undefined, but this is true on x86 and x86_64. */1242long long tmp = ret >> 63;124312441245ret += 0x2000 + tmp;12461247return (FT_Int32)( ret >> 14 );1248}12491250#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 4061251#pragma GCC diagnostic pop1252#endif12531254#endif /* __GNUC__ && ( __i386__ || __x86_64__ ) */125512561257#ifndef TT_MulFix1412581259/* Compute (a*b)/2^14 with maximum accuracy and rounding. */1260/* This is optimized to be faster than calling FT_MulFix() */1261/* for platforms where sizeof(int) == 2. */1262static FT_Int321263TT_MulFix14( FT_Int32 a,1264FT_Int b )1265{1266FT_Int32 sign;1267FT_UInt32 ah, al, mid, lo, hi;126812691270sign = a ^ b;12711272if ( a < 0 )1273a = -a;1274if ( b < 0 )1275b = -b;12761277ah = (FT_UInt32)( ( a >> 16 ) & 0xFFFFU );1278al = (FT_UInt32)( a & 0xFFFFU );12791280lo = al * b;1281mid = ah * b;1282hi = mid >> 16;1283mid = ( mid << 16 ) + ( 1 << 13 ); /* rounding */1284lo += mid;1285if ( lo < mid )1286hi += 1;12871288mid = ( lo >> 14 ) | ( hi << 18 );12891290return sign >= 0 ? (FT_Int32)mid : -(FT_Int32)mid;1291}12921293#endif /* !TT_MulFix14 */129412951296#if defined( __GNUC__ ) && \1297( defined( __i386__ ) || \1298defined( __x86_64__ ) || \1299defined( __arm__ ) )13001301#define TT_DotFix14 TT_DotFix14_long_long13021303#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 4061304#pragma GCC diagnostic push1305#endif1306#pragma GCC diagnostic ignored "-Wlong-long"13071308static __attribute__(( pure )) FT_Int321309TT_DotFix14_long_long( FT_Int32 ax,1310FT_Int32 ay,1311FT_Int bx,1312FT_Int by )1313{1314/* Temporarily disable the warning that C90 doesn't support */1315/* `long long'. */13161317long long temp1 = (long long)ax * bx;1318long long temp2 = (long long)ay * by;131913201321temp1 += temp2;1322temp2 = temp1 >> 63;1323temp1 += 0x2000 + temp2;13241325return (FT_Int32)( temp1 >> 14 );13261327}13281329#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 4061330#pragma GCC diagnostic pop1331#endif13321333#endif /* __GNUC__ && (__arm__ || __i386__ || __x86_64__) */133413351336#ifndef TT_DotFix1413371338/* compute (ax*bx+ay*by)/2^14 with maximum accuracy and rounding */1339static FT_Int321340TT_DotFix14( FT_Int32 ax,1341FT_Int32 ay,1342FT_Int bx,1343FT_Int by )1344{1345FT_Int32 m, s, hi1, hi2, hi;1346FT_UInt32 l, lo1, lo2, lo;134713481349/* compute ax*bx as 64-bit value */1350l = (FT_UInt32)( ( ax & 0xFFFFU ) * bx );1351m = ( ax >> 16 ) * bx;13521353lo1 = l + ( (FT_UInt32)m << 16 );1354hi1 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo1 < l );13551356/* compute ay*by as 64-bit value */1357l = (FT_UInt32)( ( ay & 0xFFFFU ) * by );1358m = ( ay >> 16 ) * by;13591360lo2 = l + ( (FT_UInt32)m << 16 );1361hi2 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo2 < l );13621363/* add them */1364lo = lo1 + lo2;1365hi = hi1 + hi2 + ( lo < lo1 );13661367/* divide the result by 2^14 with rounding */1368s = hi >> 31;1369l = lo + (FT_UInt32)s;1370hi += s + ( l < lo );1371lo = l;13721373l = lo + 0x2000U;1374hi += ( l < lo );13751376return (FT_Int32)( ( (FT_UInt32)hi << 18 ) | ( l >> 14 ) );1377}13781379#endif /* TT_DotFix14 */138013811382/**************************************************************************1383*1384* @Function:1385* Current_Ratio1386*1387* @Description:1388* Returns the current aspect ratio scaling factor depending on the1389* projection vector's state and device resolutions.1390*1391* @Return:1392* The aspect ratio in 16.16 format, always <= 1.0 .1393*/1394static FT_Long1395Current_Ratio( TT_ExecContext exc )1396{1397if ( !exc->tt_metrics.ratio )1398{1399if ( exc->GS.projVector.y == 0 )1400exc->tt_metrics.ratio = exc->tt_metrics.x_ratio;14011402else if ( exc->GS.projVector.x == 0 )1403exc->tt_metrics.ratio = exc->tt_metrics.y_ratio;14041405else1406{1407FT_F26Dot6 x, y;140814091410x = TT_MulFix14( exc->tt_metrics.x_ratio,1411exc->GS.projVector.x );1412y = TT_MulFix14( exc->tt_metrics.y_ratio,1413exc->GS.projVector.y );1414exc->tt_metrics.ratio = FT_Hypot( x, y );1415}1416}1417return exc->tt_metrics.ratio;1418}141914201421FT_CALLBACK_DEF( FT_Long )1422Current_Ppem( TT_ExecContext exc )1423{1424return exc->tt_metrics.ppem;1425}142614271428FT_CALLBACK_DEF( FT_Long )1429Current_Ppem_Stretched( TT_ExecContext exc )1430{1431return FT_MulFix( exc->tt_metrics.ppem, Current_Ratio( exc ) );1432}143314341435/**************************************************************************1436*1437* Functions related to the control value table (CVT).1438*1439*/144014411442FT_CALLBACK_DEF( FT_F26Dot6 )1443Read_CVT( TT_ExecContext exc,1444FT_ULong idx )1445{1446return exc->cvt[idx];1447}144814491450FT_CALLBACK_DEF( FT_F26Dot6 )1451Read_CVT_Stretched( TT_ExecContext exc,1452FT_ULong idx )1453{1454return FT_MulFix( exc->cvt[idx], Current_Ratio( exc ) );1455}145614571458static void1459Modify_CVT_Check( TT_ExecContext exc )1460{1461if ( exc->iniRange == tt_coderange_glyph &&1462exc->cvt != exc->glyfCvt )1463{1464FT_Memory memory = exc->memory;1465FT_Error error;146614671468FT_MEM_QRENEW_ARRAY( exc->glyfCvt, exc->glyfCvtSize, exc->cvtSize );1469exc->error = error;1470if ( error )1471return;14721473exc->glyfCvtSize = exc->cvtSize;1474FT_ARRAY_COPY( exc->glyfCvt, exc->cvt, exc->glyfCvtSize );1475exc->cvt = exc->glyfCvt;1476}1477}147814791480FT_CALLBACK_DEF( void )1481Write_CVT( TT_ExecContext exc,1482FT_ULong idx,1483FT_F26Dot6 value )1484{1485Modify_CVT_Check( exc );1486if ( exc->error )1487return;14881489exc->cvt[idx] = value;1490}149114921493FT_CALLBACK_DEF( void )1494Write_CVT_Stretched( TT_ExecContext exc,1495FT_ULong idx,1496FT_F26Dot6 value )1497{1498Modify_CVT_Check( exc );1499if ( exc->error )1500return;15011502exc->cvt[idx] = FT_DivFix( value, Current_Ratio( exc ) );1503}150415051506FT_CALLBACK_DEF( void )1507Move_CVT( TT_ExecContext exc,1508FT_ULong idx,1509FT_F26Dot6 value )1510{1511Modify_CVT_Check( exc );1512if ( exc->error )1513return;15141515exc->cvt[idx] = ADD_LONG( exc->cvt[idx], value );1516}151715181519FT_CALLBACK_DEF( void )1520Move_CVT_Stretched( TT_ExecContext exc,1521FT_ULong idx,1522FT_F26Dot6 value )1523{1524Modify_CVT_Check( exc );1525if ( exc->error )1526return;15271528exc->cvt[idx] = ADD_LONG( exc->cvt[idx],1529FT_DivFix( value, Current_Ratio( exc ) ) );1530}153115321533/**************************************************************************1534*1535* @Function:1536* GetShortIns1537*1538* @Description:1539* Returns a short integer taken from the instruction stream at1540* address IP.1541*1542* @Return:1543* Short read at code[IP].1544*1545* @Note:1546* This one could become a macro.1547*/1548static FT_Short1549GetShortIns( TT_ExecContext exc )1550{1551/* Reading a byte stream so there is no endianness (DaveP) */1552exc->IP += 2;1553return (FT_Short)( ( exc->code[exc->IP - 2] << 8 ) +1554exc->code[exc->IP - 1] );1555}155615571558/**************************************************************************1559*1560* @Function:1561* Ins_Goto_CodeRange1562*1563* @Description:1564* Goes to a certain code range in the instruction stream.1565*1566* @Input:1567* aRange ::1568* The index of the code range.1569*1570* aIP ::1571* The new IP address in the code range.1572*1573* @Return:1574* SUCCESS or FAILURE.1575*/1576static FT_Bool1577Ins_Goto_CodeRange( TT_ExecContext exc,1578FT_Int aRange,1579FT_Long aIP )1580{1581TT_CodeRange* range;158215831584if ( aRange < 1 || aRange > 3 )1585{1586exc->error = FT_THROW( Bad_Argument );1587return FAILURE;1588}15891590range = &exc->codeRangeTable[aRange - 1];15911592if ( !range->base ) /* invalid coderange */1593{1594exc->error = FT_THROW( Invalid_CodeRange );1595return FAILURE;1596}15971598/* NOTE: Because the last instruction of a program may be a CALL */1599/* which will return to the first byte *after* the code */1600/* range, we test for aIP <= Size, instead of aIP < Size. */16011602if ( aIP > range->size )1603{1604exc->error = FT_THROW( Code_Overflow );1605return FAILURE;1606}16071608exc->code = range->base;1609exc->codeSize = range->size;1610exc->IP = aIP;1611exc->curRange = aRange;16121613return SUCCESS;1614}161516161617/*1618*1619* Apple's TrueType specification at1620*1621* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM02/Chap2.html#order1622*1623* gives the following order of operations in instructions that move1624* points.1625*1626* - check single width cut-in (MIRP, MDRP)1627*1628* - check control value cut-in (MIRP, MIAP)1629*1630* - apply engine compensation (MIRP, MDRP)1631*1632* - round distance (MIRP, MDRP) or value (MIAP, MDAP)1633*1634* - check minimum distance (MIRP,MDRP)1635*1636* - move point (MIRP, MDRP, MIAP, MSIRP, MDAP)1637*1638* For rounding instructions, engine compensation happens before rounding.1639*1640*/164116421643/**************************************************************************1644*1645* @Function:1646* Direct_Move1647*1648* @Description:1649* Moves a point by a given distance along the freedom vector. The1650* point will be `touched'.1651*1652* @Input:1653* point ::1654* The index of the point to move.1655*1656* distance ::1657* The distance to apply.1658*1659* @InOut:1660* zone ::1661* The affected glyph zone.1662*1663* @Note:1664* See `ttinterp.h' for details on backward compatibility mode.1665* `Touches' the point.1666*/1667static void1668Direct_Move( TT_ExecContext exc,1669TT_GlyphZone zone,1670FT_UShort point,1671FT_F26Dot6 distance )1672{1673FT_F26Dot6 v;167416751676v = exc->GS.freeVector.x;16771678if ( v != 0 )1679{1680#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL1681/* Exception to the post-IUP curfew: Allow the x component of */1682/* diagonal moves, but only post-IUP. DejaVu tries to adjust */1683/* diagonal stems like on `Z' and `z' post-IUP. */1684if ( SUBPIXEL_HINTING_MINIMAL && !exc->backward_compatibility )1685zone->cur[point].x = ADD_LONG( zone->cur[point].x,1686FT_MulDiv( distance,1687v,1688exc->F_dot_P ) );1689else1690#endif16911692if ( NO_SUBPIXEL_HINTING )1693zone->cur[point].x = ADD_LONG( zone->cur[point].x,1694FT_MulDiv( distance,1695v,1696exc->F_dot_P ) );16971698zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;1699}17001701v = exc->GS.freeVector.y;17021703if ( v != 0 )1704{1705#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL1706if ( !( SUBPIXEL_HINTING_MINIMAL &&1707exc->backward_compatibility &&1708exc->iupx_called &&1709exc->iupy_called ) )1710#endif1711zone->cur[point].y = ADD_LONG( zone->cur[point].y,1712FT_MulDiv( distance,1713v,1714exc->F_dot_P ) );17151716zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;1717}1718}171917201721/**************************************************************************1722*1723* @Function:1724* Direct_Move_Orig1725*1726* @Description:1727* Moves the *original* position of a point by a given distance along1728* the freedom vector. Obviously, the point will not be `touched'.1729*1730* @Input:1731* point ::1732* The index of the point to move.1733*1734* distance ::1735* The distance to apply.1736*1737* @InOut:1738* zone ::1739* The affected glyph zone.1740*/1741static void1742Direct_Move_Orig( TT_ExecContext exc,1743TT_GlyphZone zone,1744FT_UShort point,1745FT_F26Dot6 distance )1746{1747FT_F26Dot6 v;174817491750v = exc->GS.freeVector.x;17511752if ( v != 0 )1753zone->org[point].x = ADD_LONG( zone->org[point].x,1754FT_MulDiv( distance,1755v,1756exc->F_dot_P ) );17571758v = exc->GS.freeVector.y;17591760if ( v != 0 )1761zone->org[point].y = ADD_LONG( zone->org[point].y,1762FT_MulDiv( distance,1763v,1764exc->F_dot_P ) );1765}176617671768/**************************************************************************1769*1770* Special versions of Direct_Move()1771*1772* The following versions are used whenever both vectors are both1773* along one of the coordinate unit vectors, i.e. in 90% of the cases.1774* See `ttinterp.h' for details on backward compatibility mode.1775*1776*/177717781779static void1780Direct_Move_X( TT_ExecContext exc,1781TT_GlyphZone zone,1782FT_UShort point,1783FT_F26Dot6 distance )1784{1785#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL1786if ( SUBPIXEL_HINTING_MINIMAL && !exc->backward_compatibility )1787zone->cur[point].x = ADD_LONG( zone->cur[point].x, distance );1788else1789#endif17901791if ( NO_SUBPIXEL_HINTING )1792zone->cur[point].x = ADD_LONG( zone->cur[point].x, distance );17931794zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;1795}179617971798static void1799Direct_Move_Y( TT_ExecContext exc,1800TT_GlyphZone zone,1801FT_UShort point,1802FT_F26Dot6 distance )1803{1804FT_UNUSED( exc );18051806#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL1807if ( !( SUBPIXEL_HINTING_MINIMAL &&1808exc->backward_compatibility &&1809exc->iupx_called && exc->iupy_called ) )1810#endif1811zone->cur[point].y = ADD_LONG( zone->cur[point].y, distance );18121813zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;1814}181518161817/**************************************************************************1818*1819* Special versions of Direct_Move_Orig()1820*1821* The following versions are used whenever both vectors are both1822* along one of the coordinate unit vectors, i.e. in 90% of the cases.1823*1824*/182518261827static void1828Direct_Move_Orig_X( TT_ExecContext exc,1829TT_GlyphZone zone,1830FT_UShort point,1831FT_F26Dot6 distance )1832{1833FT_UNUSED( exc );18341835zone->org[point].x = ADD_LONG( zone->org[point].x, distance );1836}183718381839static void1840Direct_Move_Orig_Y( TT_ExecContext exc,1841TT_GlyphZone zone,1842FT_UShort point,1843FT_F26Dot6 distance )1844{1845FT_UNUSED( exc );18461847zone->org[point].y = ADD_LONG( zone->org[point].y, distance );1848}18491850/**************************************************************************1851*1852* @Function:1853* Round_None1854*1855* @Description:1856* Does not round, but adds engine compensation.1857*1858* @Input:1859* distance ::1860* The distance (not) to round.1861*1862* color ::1863* The engine compensation color.1864*1865* @Return:1866* The compensated distance.1867*/1868static FT_F26Dot61869Round_None( TT_ExecContext exc,1870FT_F26Dot6 distance,1871FT_Int color )1872{1873FT_F26Dot6 compensation = exc->tt_metrics.compensations[color];1874FT_F26Dot6 val;187518761877if ( distance >= 0 )1878{1879val = ADD_LONG( distance, compensation );1880if ( val < 0 )1881val = 0;1882}1883else1884{1885val = SUB_LONG( distance, compensation );1886if ( val > 0 )1887val = 0;1888}1889return val;1890}189118921893/**************************************************************************1894*1895* @Function:1896* Round_To_Grid1897*1898* @Description:1899* Rounds value to grid after adding engine compensation.1900*1901* @Input:1902* distance ::1903* The distance to round.1904*1905* color ::1906* The engine compensation color.1907*1908* @Return:1909* Rounded distance.1910*/1911static FT_F26Dot61912Round_To_Grid( TT_ExecContext exc,1913FT_F26Dot6 distance,1914FT_Int color )1915{1916FT_F26Dot6 compensation = exc->tt_metrics.compensations[color];1917FT_F26Dot6 val;191819191920if ( distance >= 0 )1921{1922val = FT_PIX_ROUND_LONG( ADD_LONG( distance, compensation ) );1923if ( val < 0 )1924val = 0;1925}1926else1927{1928val = NEG_LONG( FT_PIX_ROUND_LONG( SUB_LONG( compensation,1929distance ) ) );1930if ( val > 0 )1931val = 0;1932}19331934return val;1935}193619371938/**************************************************************************1939*1940* @Function:1941* Round_To_Half_Grid1942*1943* @Description:1944* Rounds value to half grid after adding engine compensation.1945*1946* @Input:1947* distance ::1948* The distance to round.1949*1950* color ::1951* The engine compensation color.1952*1953* @Return:1954* Rounded distance.1955*/1956static FT_F26Dot61957Round_To_Half_Grid( TT_ExecContext exc,1958FT_F26Dot6 distance,1959FT_Int color )1960{1961FT_F26Dot6 compensation = exc->tt_metrics.compensations[color];1962FT_F26Dot6 val;196319641965if ( distance >= 0 )1966{1967val = ADD_LONG( FT_PIX_FLOOR( ADD_LONG( distance, compensation ) ),196832 );1969if ( val < 0 )1970val = 32;1971}1972else1973{1974val = NEG_LONG( ADD_LONG( FT_PIX_FLOOR( SUB_LONG( compensation,1975distance ) ),197632 ) );1977if ( val > 0 )1978val = -32;1979}19801981return val;1982}198319841985/**************************************************************************1986*1987* @Function:1988* Round_Down_To_Grid1989*1990* @Description:1991* Rounds value down to grid after adding engine compensation.1992*1993* @Input:1994* distance ::1995* The distance to round.1996*1997* color ::1998* The engine compensation color.1999*2000* @Return:2001* Rounded distance.2002*/2003static FT_F26Dot62004Round_Down_To_Grid( TT_ExecContext exc,2005FT_F26Dot6 distance,2006FT_Int color )2007{2008FT_F26Dot6 compensation = exc->tt_metrics.compensations[color];2009FT_F26Dot6 val;201020112012if ( distance >= 0 )2013{2014val = FT_PIX_FLOOR( ADD_LONG( distance, compensation ) );2015if ( val < 0 )2016val = 0;2017}2018else2019{2020val = NEG_LONG( FT_PIX_FLOOR( SUB_LONG( compensation, distance ) ) );2021if ( val > 0 )2022val = 0;2023}20242025return val;2026}202720282029/**************************************************************************2030*2031* @Function:2032* Round_Up_To_Grid2033*2034* @Description:2035* Rounds value up to grid after adding engine compensation.2036*2037* @Input:2038* distance ::2039* The distance to round.2040*2041* color ::2042* The engine compensation color.2043*2044* @Return:2045* Rounded distance.2046*/2047static FT_F26Dot62048Round_Up_To_Grid( TT_ExecContext exc,2049FT_F26Dot6 distance,2050FT_Int color )2051{2052FT_F26Dot6 compensation = exc->tt_metrics.compensations[color];2053FT_F26Dot6 val;205420552056if ( distance >= 0 )2057{2058val = FT_PIX_CEIL_LONG( ADD_LONG( distance, compensation ) );2059if ( val < 0 )2060val = 0;2061}2062else2063{2064val = NEG_LONG( FT_PIX_CEIL_LONG( SUB_LONG( compensation,2065distance ) ) );2066if ( val > 0 )2067val = 0;2068}20692070return val;2071}207220732074/**************************************************************************2075*2076* @Function:2077* Round_To_Double_Grid2078*2079* @Description:2080* Rounds value to double grid after adding engine compensation.2081*2082* @Input:2083* distance ::2084* The distance to round.2085*2086* color ::2087* The engine compensation color.2088*2089* @Return:2090* Rounded distance.2091*/2092static FT_F26Dot62093Round_To_Double_Grid( TT_ExecContext exc,2094FT_F26Dot6 distance,2095FT_Int color )2096{2097FT_F26Dot6 compensation = exc->tt_metrics.compensations[color];2098FT_F26Dot6 val;209921002101if ( distance >= 0 )2102{2103val = FT_PAD_ROUND_LONG( ADD_LONG( distance, compensation ), 32 );2104if ( val < 0 )2105val = 0;2106}2107else2108{2109val = NEG_LONG( FT_PAD_ROUND_LONG( SUB_LONG( compensation, distance ),211032 ) );2111if ( val > 0 )2112val = 0;2113}21142115return val;2116}211721182119/**************************************************************************2120*2121* @Function:2122* Round_Super2123*2124* @Description:2125* Super-rounds value to grid after adding engine compensation.2126*2127* @Input:2128* distance ::2129* The distance to round.2130*2131* color ::2132* The engine compensation color.2133*2134* @Return:2135* Rounded distance.2136*2137* @Note:2138* The TrueType specification says very little about the relationship2139* between rounding and engine compensation. However, it seems from2140* the description of super round that we should add the compensation2141* before rounding.2142*/2143static FT_F26Dot62144Round_Super( TT_ExecContext exc,2145FT_F26Dot6 distance,2146FT_Int color )2147{2148FT_F26Dot6 compensation = exc->tt_metrics.compensations[color];2149FT_F26Dot6 val;215021512152if ( distance >= 0 )2153{2154val = ADD_LONG( distance,2155exc->threshold - exc->phase + compensation ) &2156-exc->period;2157val = ADD_LONG( val, exc->phase );2158if ( val < 0 )2159val = exc->phase;2160}2161else2162{2163val = NEG_LONG( SUB_LONG( exc->threshold - exc->phase + compensation,2164distance ) &2165-exc->period );2166val = SUB_LONG( val, exc->phase );2167if ( val > 0 )2168val = -exc->phase;2169}21702171return val;2172}217321742175/**************************************************************************2176*2177* @Function:2178* Round_Super_452179*2180* @Description:2181* Super-rounds value to grid after adding engine compensation.2182*2183* @Input:2184* distance ::2185* The distance to round.2186*2187* color ::2188* The engine compensation color.2189*2190* @Return:2191* Rounded distance.2192*2193* @Note:2194* There is a separate function for Round_Super_45() as we may need2195* greater precision.2196*/2197static FT_F26Dot62198Round_Super_45( TT_ExecContext exc,2199FT_F26Dot6 distance,2200FT_Int color )2201{2202FT_F26Dot6 compensation = exc->tt_metrics.compensations[color];2203FT_F26Dot6 val;220422052206if ( distance >= 0 )2207{2208val = ( ADD_LONG( distance,2209exc->threshold - exc->phase + compensation ) /2210exc->period ) * exc->period;2211val = ADD_LONG( val, exc->phase );2212if ( val < 0 )2213val = exc->phase;2214}2215else2216{2217val = NEG_LONG( ( SUB_LONG( exc->threshold - exc->phase + compensation,2218distance ) /2219exc->period ) * exc->period );2220val = SUB_LONG( val, exc->phase );2221if ( val > 0 )2222val = -exc->phase;2223}22242225return val;2226}222722282229/**************************************************************************2230*2231* @Function:2232* Compute_Round2233*2234* @Description:2235* Sets the rounding mode.2236*2237* @Input:2238* round_mode ::2239* The rounding mode to be used.2240*/2241static void2242Compute_Round( TT_ExecContext exc,2243FT_Byte round_mode )2244{2245switch ( round_mode )2246{2247case TT_Round_Off:2248exc->func_round = (TT_Round_Func)Round_None;2249break;22502251case TT_Round_To_Grid:2252exc->func_round = (TT_Round_Func)Round_To_Grid;2253break;22542255case TT_Round_Up_To_Grid:2256exc->func_round = (TT_Round_Func)Round_Up_To_Grid;2257break;22582259case TT_Round_Down_To_Grid:2260exc->func_round = (TT_Round_Func)Round_Down_To_Grid;2261break;22622263case TT_Round_To_Half_Grid:2264exc->func_round = (TT_Round_Func)Round_To_Half_Grid;2265break;22662267case TT_Round_To_Double_Grid:2268exc->func_round = (TT_Round_Func)Round_To_Double_Grid;2269break;22702271case TT_Round_Super:2272exc->func_round = (TT_Round_Func)Round_Super;2273break;22742275case TT_Round_Super_45:2276exc->func_round = (TT_Round_Func)Round_Super_45;2277break;2278}2279}228022812282/**************************************************************************2283*2284* @Function:2285* SetSuperRound2286*2287* @Description:2288* Sets Super Round parameters.2289*2290* @Input:2291* GridPeriod ::2292* The grid period.2293*2294* selector ::2295* The SROUND opcode.2296*/2297static void2298SetSuperRound( TT_ExecContext exc,2299FT_F2Dot14 GridPeriod,2300FT_Long selector )2301{2302switch ( (FT_Int)( selector & 0xC0 ) )2303{2304case 0:2305exc->period = GridPeriod / 2;2306break;23072308case 0x40:2309exc->period = GridPeriod;2310break;23112312case 0x80:2313exc->period = GridPeriod * 2;2314break;23152316/* This opcode is reserved, but... */2317case 0xC0:2318exc->period = GridPeriod;2319break;2320}23212322switch ( (FT_Int)( selector & 0x30 ) )2323{2324case 0:2325exc->phase = 0;2326break;23272328case 0x10:2329exc->phase = exc->period / 4;2330break;23312332case 0x20:2333exc->phase = exc->period / 2;2334break;23352336case 0x30:2337exc->phase = exc->period * 3 / 4;2338break;2339}23402341if ( ( selector & 0x0F ) == 0 )2342exc->threshold = exc->period - 1;2343else2344exc->threshold = ( (FT_Int)( selector & 0x0F ) - 4 ) * exc->period / 8;23452346/* convert to F26Dot6 format */2347exc->period >>= 8;2348exc->phase >>= 8;2349exc->threshold >>= 8;2350}235123522353/**************************************************************************2354*2355* @Function:2356* Project2357*2358* @Description:2359* Computes the projection of vector given by (v2-v1) along the2360* current projection vector.2361*2362* @Input:2363* v1 ::2364* First input vector.2365* v2 ::2366* Second input vector.2367*2368* @Return:2369* The distance in F26dot6 format.2370*/2371static FT_F26Dot62372Project( TT_ExecContext exc,2373FT_Pos dx,2374FT_Pos dy )2375{2376return TT_DotFix14( dx, dy,2377exc->GS.projVector.x,2378exc->GS.projVector.y );2379}238023812382/**************************************************************************2383*2384* @Function:2385* Dual_Project2386*2387* @Description:2388* Computes the projection of the vector given by (v2-v1) along the2389* current dual vector.2390*2391* @Input:2392* v1 ::2393* First input vector.2394* v2 ::2395* Second input vector.2396*2397* @Return:2398* The distance in F26dot6 format.2399*/2400static FT_F26Dot62401Dual_Project( TT_ExecContext exc,2402FT_Pos dx,2403FT_Pos dy )2404{2405return TT_DotFix14( dx, dy,2406exc->GS.dualVector.x,2407exc->GS.dualVector.y );2408}240924102411/**************************************************************************2412*2413* @Function:2414* Project_x2415*2416* @Description:2417* Computes the projection of the vector given by (v2-v1) along the2418* horizontal axis.2419*2420* @Input:2421* v1 ::2422* First input vector.2423* v2 ::2424* Second input vector.2425*2426* @Return:2427* The distance in F26dot6 format.2428*/2429static FT_F26Dot62430Project_x( TT_ExecContext exc,2431FT_Pos dx,2432FT_Pos dy )2433{2434FT_UNUSED( exc );2435FT_UNUSED( dy );24362437return dx;2438}243924402441/**************************************************************************2442*2443* @Function:2444* Project_y2445*2446* @Description:2447* Computes the projection of the vector given by (v2-v1) along the2448* vertical axis.2449*2450* @Input:2451* v1 ::2452* First input vector.2453* v2 ::2454* Second input vector.2455*2456* @Return:2457* The distance in F26dot6 format.2458*/2459static FT_F26Dot62460Project_y( TT_ExecContext exc,2461FT_Pos dx,2462FT_Pos dy )2463{2464FT_UNUSED( exc );2465FT_UNUSED( dx );24662467return dy;2468}246924702471/**************************************************************************2472*2473* @Function:2474* Compute_Funcs2475*2476* @Description:2477* Computes the projection and movement function pointers according2478* to the current graphics state.2479*/2480static void2481Compute_Funcs( TT_ExecContext exc )2482{2483if ( exc->GS.freeVector.x == 0x4000 )2484exc->F_dot_P = exc->GS.projVector.x;2485else if ( exc->GS.freeVector.y == 0x4000 )2486exc->F_dot_P = exc->GS.projVector.y;2487else2488exc->F_dot_P =2489( (FT_Long)exc->GS.projVector.x * exc->GS.freeVector.x +2490(FT_Long)exc->GS.projVector.y * exc->GS.freeVector.y ) >> 14;24912492if ( exc->GS.projVector.x == 0x4000 )2493exc->func_project = (TT_Project_Func)Project_x;2494else if ( exc->GS.projVector.y == 0x4000 )2495exc->func_project = (TT_Project_Func)Project_y;2496else2497exc->func_project = (TT_Project_Func)Project;24982499if ( exc->GS.dualVector.x == 0x4000 )2500exc->func_dualproj = (TT_Project_Func)Project_x;2501else if ( exc->GS.dualVector.y == 0x4000 )2502exc->func_dualproj = (TT_Project_Func)Project_y;2503else2504exc->func_dualproj = (TT_Project_Func)Dual_Project;25052506exc->func_move = (TT_Move_Func)Direct_Move;2507exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig;25082509if ( exc->F_dot_P == 0x4000L )2510{2511if ( exc->GS.freeVector.x == 0x4000 )2512{2513exc->func_move = (TT_Move_Func)Direct_Move_X;2514exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig_X;2515}2516else if ( exc->GS.freeVector.y == 0x4000 )2517{2518exc->func_move = (TT_Move_Func)Direct_Move_Y;2519exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig_Y;2520}2521}25222523/* at small sizes, F_dot_P can become too small, resulting */2524/* in overflows and `spikes' in a number of glyphs like `w'. */25252526if ( FT_ABS( exc->F_dot_P ) < 0x400L )2527exc->F_dot_P = 0x4000L;25282529/* Disable cached aspect ratio */2530exc->tt_metrics.ratio = 0;2531}253225332534/**************************************************************************2535*2536* @Function:2537* Normalize2538*2539* @Description:2540* Norms a vector.2541*2542* @Input:2543* Vx ::2544* The horizontal input vector coordinate.2545* Vy ::2546* The vertical input vector coordinate.2547*2548* @Output:2549* R ::2550* The normed unit vector.2551*2552* @Return:2553* Returns FAILURE if a vector parameter is zero.2554*2555* @Note:2556* In case Vx and Vy are both zero, `Normalize' returns SUCCESS, and2557* R is undefined.2558*/2559static FT_Bool2560Normalize( FT_F26Dot6 Vx,2561FT_F26Dot6 Vy,2562FT_UnitVector* R )2563{2564FT_Vector V;256525662567if ( Vx == 0 && Vy == 0 )2568{2569/* XXX: UNDOCUMENTED! It seems that it is possible to try */2570/* to normalize the vector (0,0). Return immediately. */2571return SUCCESS;2572}25732574V.x = Vx;2575V.y = Vy;25762577FT_Vector_NormLen( &V );25782579R->x = (FT_F2Dot14)( V.x / 4 );2580R->y = (FT_F2Dot14)( V.y / 4 );25812582return SUCCESS;2583}258425852586/**************************************************************************2587*2588* Here we start with the implementation of the various opcodes.2589*2590*/259125922593#define ARRAY_BOUND_ERROR \2594do \2595{ \2596exc->error = FT_THROW( Invalid_Reference ); \2597return; \2598} while (0)259926002601/**************************************************************************2602*2603* MPPEM[]: Measure Pixel Per EM2604* Opcode range: 0x4B2605* Stack: --> Euint162606*/2607static void2608Ins_MPPEM( TT_ExecContext exc,2609FT_Long* args )2610{2611args[0] = exc->func_cur_ppem( exc );2612}261326142615/**************************************************************************2616*2617* MPS[]: Measure Point Size2618* Opcode range: 0x4C2619* Stack: --> Euint162620*/2621static void2622Ins_MPS( TT_ExecContext exc,2623FT_Long* args )2624{2625if ( NO_SUBPIXEL_HINTING )2626{2627/* Microsoft's GDI bytecode interpreter always returns value 12; */2628/* we return the current PPEM value instead. */2629args[0] = exc->func_cur_ppem( exc );2630}2631else2632{2633/* A possible practical application of the MPS instruction is to */2634/* implement optical scaling and similar features, which should be */2635/* based on perceptual attributes, thus independent of the */2636/* resolution. */2637args[0] = exc->pointSize;2638}2639}264026412642/**************************************************************************2643*2644* DUP[]: DUPlicate the stack's top element2645* Opcode range: 0x202646* Stack: StkElt --> StkElt StkElt2647*/2648static void2649Ins_DUP( FT_Long* args )2650{2651args[1] = args[0];2652}265326542655/**************************************************************************2656*2657* POP[]: POP the stack's top element2658* Opcode range: 0x212659* Stack: StkElt -->2660*/2661static void2662Ins_POP( void )2663{2664/* nothing to do */2665}266626672668/**************************************************************************2669*2670* CLEAR[]: CLEAR the entire stack2671* Opcode range: 0x222672* Stack: StkElt... -->2673*/2674static void2675Ins_CLEAR( TT_ExecContext exc )2676{2677exc->new_top = 0;2678}267926802681/**************************************************************************2682*2683* SWAP[]: SWAP the stack's top two elements2684* Opcode range: 0x232685* Stack: 2 * StkElt --> 2 * StkElt2686*/2687static void2688Ins_SWAP( FT_Long* args )2689{2690FT_Long L;269126922693L = args[0];2694args[0] = args[1];2695args[1] = L;2696}269726982699/**************************************************************************2700*2701* DEPTH[]: return the stack DEPTH2702* Opcode range: 0x242703* Stack: --> uint322704*/2705static void2706Ins_DEPTH( TT_ExecContext exc,2707FT_Long* args )2708{2709args[0] = exc->top;2710}271127122713/**************************************************************************2714*2715* LT[]: Less Than2716* Opcode range: 0x502717* Stack: int32? int32? --> bool2718*/2719static void2720Ins_LT( FT_Long* args )2721{2722args[0] = ( args[0] < args[1] );2723}272427252726/**************************************************************************2727*2728* LTEQ[]: Less Than or EQual2729* Opcode range: 0x512730* Stack: int32? int32? --> bool2731*/2732static void2733Ins_LTEQ( FT_Long* args )2734{2735args[0] = ( args[0] <= args[1] );2736}273727382739/**************************************************************************2740*2741* GT[]: Greater Than2742* Opcode range: 0x522743* Stack: int32? int32? --> bool2744*/2745static void2746Ins_GT( FT_Long* args )2747{2748args[0] = ( args[0] > args[1] );2749}275027512752/**************************************************************************2753*2754* GTEQ[]: Greater Than or EQual2755* Opcode range: 0x532756* Stack: int32? int32? --> bool2757*/2758static void2759Ins_GTEQ( FT_Long* args )2760{2761args[0] = ( args[0] >= args[1] );2762}276327642765/**************************************************************************2766*2767* EQ[]: EQual2768* Opcode range: 0x542769* Stack: StkElt StkElt --> bool2770*/2771static void2772Ins_EQ( FT_Long* args )2773{2774args[0] = ( args[0] == args[1] );2775}277627772778/**************************************************************************2779*2780* NEQ[]: Not EQual2781* Opcode range: 0x552782* Stack: StkElt StkElt --> bool2783*/2784static void2785Ins_NEQ( FT_Long* args )2786{2787args[0] = ( args[0] != args[1] );2788}278927902791/**************************************************************************2792*2793* ODD[]: Is ODD2794* Opcode range: 0x562795* Stack: f26.6 --> bool2796*/2797static void2798Ins_ODD( TT_ExecContext exc,2799FT_Long* args )2800{2801args[0] = ( ( exc->func_round( exc, args[0], 3 ) & 127 ) == 64 );2802}280328042805/**************************************************************************2806*2807* EVEN[]: Is EVEN2808* Opcode range: 0x572809* Stack: f26.6 --> bool2810*/2811static void2812Ins_EVEN( TT_ExecContext exc,2813FT_Long* args )2814{2815args[0] = ( ( exc->func_round( exc, args[0], 3 ) & 127 ) == 0 );2816}281728182819/**************************************************************************2820*2821* AND[]: logical AND2822* Opcode range: 0x5A2823* Stack: uint32 uint32 --> uint322824*/2825static void2826Ins_AND( FT_Long* args )2827{2828args[0] = ( args[0] && args[1] );2829}283028312832/**************************************************************************2833*2834* OR[]: logical OR2835* Opcode range: 0x5B2836* Stack: uint32 uint32 --> uint322837*/2838static void2839Ins_OR( FT_Long* args )2840{2841args[0] = ( args[0] || args[1] );2842}284328442845/**************************************************************************2846*2847* NOT[]: logical NOT2848* Opcode range: 0x5C2849* Stack: StkElt --> uint322850*/2851static void2852Ins_NOT( FT_Long* args )2853{2854args[0] = !args[0];2855}285628572858/**************************************************************************2859*2860* ADD[]: ADD2861* Opcode range: 0x602862* Stack: f26.6 f26.6 --> f26.62863*/2864static void2865Ins_ADD( FT_Long* args )2866{2867args[0] = ADD_LONG( args[0], args[1] );2868}286928702871/**************************************************************************2872*2873* SUB[]: SUBtract2874* Opcode range: 0x612875* Stack: f26.6 f26.6 --> f26.62876*/2877static void2878Ins_SUB( FT_Long* args )2879{2880args[0] = SUB_LONG( args[0], args[1] );2881}288228832884/**************************************************************************2885*2886* DIV[]: DIVide2887* Opcode range: 0x622888* Stack: f26.6 f26.6 --> f26.62889*/2890static void2891Ins_DIV( TT_ExecContext exc,2892FT_Long* args )2893{2894if ( args[1] == 0 )2895exc->error = FT_THROW( Divide_By_Zero );2896else2897args[0] = FT_MulDiv_No_Round( args[0], 64L, args[1] );2898}289929002901/**************************************************************************2902*2903* MUL[]: MULtiply2904* Opcode range: 0x632905* Stack: f26.6 f26.6 --> f26.62906*/2907static void2908Ins_MUL( FT_Long* args )2909{2910args[0] = FT_MulDiv( args[0], args[1], 64L );2911}291229132914/**************************************************************************2915*2916* ABS[]: ABSolute value2917* Opcode range: 0x642918* Stack: f26.6 --> f26.62919*/2920static void2921Ins_ABS( FT_Long* args )2922{2923if ( args[0] < 0 )2924args[0] = NEG_LONG( args[0] );2925}292629272928/**************************************************************************2929*2930* NEG[]: NEGate2931* Opcode range: 0x652932* Stack: f26.6 --> f26.62933*/2934static void2935Ins_NEG( FT_Long* args )2936{2937args[0] = NEG_LONG( args[0] );2938}293929402941/**************************************************************************2942*2943* FLOOR[]: FLOOR2944* Opcode range: 0x662945* Stack: f26.6 --> f26.62946*/2947static void2948Ins_FLOOR( FT_Long* args )2949{2950args[0] = FT_PIX_FLOOR( args[0] );2951}295229532954/**************************************************************************2955*2956* CEILING[]: CEILING2957* Opcode range: 0x672958* Stack: f26.6 --> f26.62959*/2960static void2961Ins_CEILING( FT_Long* args )2962{2963args[0] = FT_PIX_CEIL_LONG( args[0] );2964}296529662967/**************************************************************************2968*2969* RS[]: Read Store2970* Opcode range: 0x432971* Stack: uint32 --> uint322972*/2973static void2974Ins_RS( TT_ExecContext exc,2975FT_Long* args )2976{2977FT_ULong I = (FT_ULong)args[0];297829792980if ( BOUNDSL( I, exc->storeSize ) )2981{2982if ( exc->pedantic_hinting )2983ARRAY_BOUND_ERROR;2984else2985args[0] = 0;2986}2987else2988args[0] = exc->storage[I];2989}299029912992/**************************************************************************2993*2994* WS[]: Write Store2995* Opcode range: 0x422996* Stack: uint32 uint32 -->2997*/2998static void2999Ins_WS( TT_ExecContext exc,3000FT_Long* args )3001{3002FT_ULong I = (FT_ULong)args[0];300330043005if ( BOUNDSL( I, exc->storeSize ) )3006{3007if ( exc->pedantic_hinting )3008ARRAY_BOUND_ERROR;3009}3010else3011{3012if ( exc->iniRange == tt_coderange_glyph &&3013exc->storage != exc->glyfStorage )3014{3015FT_Memory memory = exc->memory;3016FT_Error error;301730183019FT_MEM_QRENEW_ARRAY( exc->glyfStorage,3020exc->glyfStoreSize,3021exc->storeSize );3022exc->error = error;3023if ( error )3024return;30253026exc->glyfStoreSize = exc->storeSize;3027FT_ARRAY_COPY( exc->glyfStorage, exc->storage, exc->glyfStoreSize );3028exc->storage = exc->glyfStorage;3029}30303031exc->storage[I] = args[1];3032}3033}303430353036/**************************************************************************3037*3038* WCVTP[]: Write CVT in Pixel units3039* Opcode range: 0x443040* Stack: f26.6 uint32 -->3041*/3042static void3043Ins_WCVTP( TT_ExecContext exc,3044FT_Long* args )3045{3046FT_ULong I = (FT_ULong)args[0];304730483049if ( BOUNDSL( I, exc->cvtSize ) )3050{3051if ( exc->pedantic_hinting )3052ARRAY_BOUND_ERROR;3053}3054else3055exc->func_write_cvt( exc, I, args[1] );3056}305730583059/**************************************************************************3060*3061* WCVTF[]: Write CVT in Funits3062* Opcode range: 0x703063* Stack: uint32 uint32 -->3064*/3065static void3066Ins_WCVTF( TT_ExecContext exc,3067FT_Long* args )3068{3069FT_ULong I = (FT_ULong)args[0];307030713072if ( BOUNDSL( I, exc->cvtSize ) )3073{3074if ( exc->pedantic_hinting )3075ARRAY_BOUND_ERROR;3076}3077else3078exc->cvt[I] = FT_MulFix( args[1], exc->tt_metrics.scale );3079}308030813082/**************************************************************************3083*3084* RCVT[]: Read CVT3085* Opcode range: 0x453086* Stack: uint32 --> f26.63087*/3088static void3089Ins_RCVT( TT_ExecContext exc,3090FT_Long* args )3091{3092FT_ULong I = (FT_ULong)args[0];309330943095if ( BOUNDSL( I, exc->cvtSize ) )3096{3097if ( exc->pedantic_hinting )3098ARRAY_BOUND_ERROR;3099else3100args[0] = 0;3101}3102else3103args[0] = exc->func_read_cvt( exc, I );3104}310531063107/**************************************************************************3108*3109* AA[]: Adjust Angle3110* Opcode range: 0x7F3111* Stack: uint32 -->3112*/3113static void3114Ins_AA( void )3115{3116/* intentionally no longer supported */3117}311831193120/**************************************************************************3121*3122* DEBUG[]: DEBUG. Unsupported.3123* Opcode range: 0x4F3124* Stack: uint32 -->3125*3126* Note: The original instruction pops a value from the stack.3127*/3128static void3129Ins_DEBUG( TT_ExecContext exc )3130{3131exc->error = FT_THROW( Debug_OpCode );3132}313331343135/**************************************************************************3136*3137* ROUND[ab]: ROUND value3138* Opcode range: 0x68-0x6B3139* Stack: f26.6 --> f26.63140*/3141static void3142Ins_ROUND( TT_ExecContext exc,3143FT_Long* args )3144{3145args[0] = exc->func_round( exc, args[0], exc->opcode & 3 );3146}314731483149/**************************************************************************3150*3151* NROUND[ab]: No ROUNDing of value3152* Opcode range: 0x6C-0x6F3153* Stack: f26.6 --> f26.63154*/3155static void3156Ins_NROUND( TT_ExecContext exc,3157FT_Long* args )3158{3159args[0] = Round_None( exc, args[0], exc->opcode & 3 );3160}316131623163/**************************************************************************3164*3165* MAX[]: MAXimum3166* Opcode range: 0x8B3167* Stack: int32? int32? --> int323168*/3169static void3170Ins_MAX( FT_Long* args )3171{3172if ( args[1] > args[0] )3173args[0] = args[1];3174}317531763177/**************************************************************************3178*3179* MIN[]: MINimum3180* Opcode range: 0x8C3181* Stack: int32? int32? --> int323182*/3183static void3184Ins_MIN( FT_Long* args )3185{3186if ( args[1] < args[0] )3187args[0] = args[1];3188}318931903191/**************************************************************************3192*3193* MINDEX[]: Move INDEXed element3194* Opcode range: 0x263195* Stack: int32? --> StkElt3196*/3197static void3198Ins_MINDEX( TT_ExecContext exc,3199FT_Long* args )3200{3201FT_Long L, K;320232033204L = args[0];32053206if ( L <= 0 || L > exc->args )3207{3208if ( exc->pedantic_hinting )3209exc->error = FT_THROW( Invalid_Reference );3210}3211else3212{3213K = exc->stack[exc->args - L];32143215FT_ARRAY_MOVE( &exc->stack[exc->args - L ],3216&exc->stack[exc->args - L + 1],3217( L - 1 ) );32183219exc->stack[exc->args - 1] = K;3220}3221}322232233224/**************************************************************************3225*3226* CINDEX[]: Copy INDEXed element3227* Opcode range: 0x253228* Stack: int32 --> StkElt3229*/3230static void3231Ins_CINDEX( TT_ExecContext exc,3232FT_Long* args )3233{3234FT_Long L;323532363237L = args[0];32383239if ( L <= 0 || L > exc->args )3240{3241if ( exc->pedantic_hinting )3242exc->error = FT_THROW( Invalid_Reference );3243args[0] = 0;3244}3245else3246args[0] = exc->stack[exc->args - L];3247}324832493250/**************************************************************************3251*3252* ROLL[]: ROLL top three elements3253* Opcode range: 0x8A3254* Stack: 3 * StkElt --> 3 * StkElt3255*/3256static void3257Ins_ROLL( FT_Long* args )3258{3259FT_Long A, B, C;326032613262A = args[2];3263B = args[1];3264C = args[0];32653266args[2] = C;3267args[1] = A;3268args[0] = B;3269}327032713272/**************************************************************************3273*3274* MANAGING THE FLOW OF CONTROL3275*3276*/327732783279/**************************************************************************3280*3281* SLOOP[]: Set LOOP variable3282* Opcode range: 0x173283* Stack: int32? -->3284*/3285static void3286Ins_SLOOP( TT_ExecContext exc,3287FT_Long* args )3288{3289if ( args[0] < 0 )3290exc->error = FT_THROW( Bad_Argument );3291else3292{3293/* we heuristically limit the number of loops to 16 bits */3294exc->GS.loop = args[0] > 0xFFFFL ? 0xFFFFL : args[0];3295}3296}329732983299static FT_Bool3300SkipCode( TT_ExecContext exc )3301{3302exc->IP += exc->length;33033304if ( exc->IP < exc->codeSize )3305{3306exc->opcode = exc->code[exc->IP];33073308exc->length = opcode_length[exc->opcode];3309if ( exc->length < 0 )3310{3311if ( exc->IP + 1 >= exc->codeSize )3312goto Fail_Overflow;3313exc->length = 2 - exc->length * exc->code[exc->IP + 1];3314}33153316if ( exc->IP + exc->length <= exc->codeSize )3317return SUCCESS;3318}33193320Fail_Overflow:3321exc->error = FT_THROW( Code_Overflow );3322return FAILURE;3323}332433253326/**************************************************************************3327*3328* IF[]: IF test3329* Opcode range: 0x583330* Stack: StkElt -->3331*/3332static void3333Ins_IF( TT_ExecContext exc,3334FT_Long* args )3335{3336FT_Int nIfs;3337FT_Bool Out;333833393340if ( args[0] != 0 )3341return;33423343nIfs = 1;3344Out = 0;33453346do3347{3348if ( SkipCode( exc ) == FAILURE )3349return;33503351switch ( exc->opcode )3352{3353case 0x58: /* IF */3354nIfs++;3355break;33563357case 0x1B: /* ELSE */3358Out = FT_BOOL( nIfs == 1 );3359break;33603361case 0x59: /* EIF */3362nIfs--;3363Out = FT_BOOL( nIfs == 0 );3364break;3365}3366} while ( Out == 0 );3367}336833693370/**************************************************************************3371*3372* ELSE[]: ELSE3373* Opcode range: 0x1B3374* Stack: -->3375*/3376static void3377Ins_ELSE( TT_ExecContext exc )3378{3379FT_Int nIfs;338033813382nIfs = 1;33833384do3385{3386if ( SkipCode( exc ) == FAILURE )3387return;33883389switch ( exc->opcode )3390{3391case 0x58: /* IF */3392nIfs++;3393break;33943395case 0x59: /* EIF */3396nIfs--;3397break;3398}3399} while ( nIfs != 0 );3400}340134023403/**************************************************************************3404*3405* EIF[]: End IF3406* Opcode range: 0x593407* Stack: -->3408*/3409static void3410Ins_EIF( void )3411{3412/* nothing to do */3413}341434153416/**************************************************************************3417*3418* JMPR[]: JuMP Relative3419* Opcode range: 0x1C3420* Stack: int32 -->3421*/3422static void3423Ins_JMPR( TT_ExecContext exc,3424FT_Long* args )3425{3426if ( args[0] == 0 && exc->args == 0 )3427{3428exc->error = FT_THROW( Bad_Argument );3429return;3430}34313432exc->IP = ADD_LONG( exc->IP, args[0] );3433if ( exc->IP < 0 ||3434( exc->callTop > 0 &&3435exc->IP > exc->callStack[exc->callTop - 1].Def->end ) )3436{3437exc->error = FT_THROW( Bad_Argument );3438return;3439}34403441exc->step_ins = FALSE;34423443if ( args[0] < 0 )3444{3445if ( ++exc->neg_jump_counter > exc->neg_jump_counter_max )3446exc->error = FT_THROW( Execution_Too_Long );3447}3448}344934503451/**************************************************************************3452*3453* JROT[]: Jump Relative On True3454* Opcode range: 0x783455* Stack: StkElt int32 -->3456*/3457static void3458Ins_JROT( TT_ExecContext exc,3459FT_Long* args )3460{3461if ( args[1] != 0 )3462Ins_JMPR( exc, args );3463}346434653466/**************************************************************************3467*3468* JROF[]: Jump Relative On False3469* Opcode range: 0x793470* Stack: StkElt int32 -->3471*/3472static void3473Ins_JROF( TT_ExecContext exc,3474FT_Long* args )3475{3476if ( args[1] == 0 )3477Ins_JMPR( exc, args );3478}347934803481/**************************************************************************3482*3483* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS3484*3485*/348634873488/**************************************************************************3489*3490* FDEF[]: Function DEFinition3491* Opcode range: 0x2C3492* Stack: uint32 -->3493*/3494static void3495Ins_FDEF( TT_ExecContext exc,3496FT_Long* args )3497{3498FT_ULong n;3499TT_DefRecord* rec;3500TT_DefRecord* limit;350135023503/* FDEF is only allowed in `prep' or `fpgm' */3504if ( exc->iniRange == tt_coderange_glyph )3505{3506exc->error = FT_THROW( DEF_In_Glyf_Bytecode );3507return;3508}35093510/* some font programs are broken enough to redefine functions! */3511/* We will then parse the current table. */35123513rec = exc->FDefs;3514limit = FT_OFFSET( rec, exc->numFDefs );3515n = (FT_ULong)args[0];35163517for ( ; rec < limit; rec++ )3518{3519if ( rec->opc == n )3520break;3521}35223523if ( rec == limit )3524{3525/* check that there is enough room for new functions */3526if ( exc->numFDefs >= exc->maxFDefs )3527{3528exc->error = FT_THROW( Too_Many_Function_Defs );3529return;3530}3531exc->numFDefs++;3532}35333534/* Although FDEF takes unsigned 32-bit integer, */3535/* func # must be within unsigned 16-bit integer */3536if ( n > 0xFFFFU )3537{3538exc->error = FT_THROW( Too_Many_Function_Defs );3539return;3540}35413542rec->range = exc->curRange;3543rec->opc = (FT_UInt16)n;3544rec->start = exc->IP + 1;3545rec->active = TRUE;35463547if ( n > exc->maxFunc )3548exc->maxFunc = (FT_UInt16)n;35493550/* Now skip the whole function definition. */3551/* We don't allow nested IDEFS & FDEFs. */35523553while ( SkipCode( exc ) == SUCCESS )3554{3555switch ( exc->opcode )3556{3557case 0x89: /* IDEF */3558case 0x2C: /* FDEF */3559exc->error = FT_THROW( Nested_DEFS );3560return;35613562case 0x2D: /* ENDF */3563rec->end = exc->IP;3564return;3565}3566}3567}356835693570/**************************************************************************3571*3572* ENDF[]: END Function definition3573* Opcode range: 0x2D3574* Stack: -->3575*/3576static void3577Ins_ENDF( TT_ExecContext exc )3578{3579TT_CallRec* pRec;358035813582if ( exc->callTop <= 0 ) /* We encountered an ENDF without a call */3583{3584exc->error = FT_THROW( ENDF_In_Exec_Stream );3585return;3586}35873588exc->callTop--;35893590pRec = &exc->callStack[exc->callTop];35913592pRec->Cur_Count--;35933594exc->step_ins = FALSE;35953596if ( pRec->Cur_Count > 0 )3597{3598exc->callTop++;3599exc->IP = pRec->Def->start;3600}3601else3602/* Loop through the current function */3603Ins_Goto_CodeRange( exc, pRec->Caller_Range, pRec->Caller_IP );36043605/* Exit the current call frame. */36063607/* NOTE: If the last instruction of a program is a */3608/* CALL or LOOPCALL, the return address is */3609/* always out of the code range. This is a */3610/* valid address, and it is why we do not test */3611/* the result of Ins_Goto_CodeRange() here! */3612}361336143615/**************************************************************************3616*3617* CALL[]: CALL function3618* Opcode range: 0x2B3619* Stack: uint32? -->3620*/3621static void3622Ins_CALL( TT_ExecContext exc,3623FT_Long* args )3624{3625FT_ULong F;3626TT_CallRec* pCrec;3627TT_DefRecord* def;362836293630/* first of all, check the index */36313632F = (FT_ULong)args[0];3633if ( BOUNDSL( F, exc->maxFunc + 1 ) )3634goto Fail;36353636if ( !exc->FDefs )3637goto Fail;36383639/* Except for some old Apple fonts, all functions in a TrueType */3640/* font are defined in increasing order, starting from 0. This */3641/* means that we normally have */3642/* */3643/* exc->maxFunc+1 == exc->numFDefs */3644/* exc->FDefs[n].opc == n for n in 0..exc->maxFunc */3645/* */3646/* If this isn't true, we need to look up the function table. */36473648def = exc->FDefs + F;3649if ( exc->maxFunc + 1 != exc->numFDefs || def->opc != F )3650{3651/* look up the FDefs table */3652TT_DefRecord* limit;365336543655def = exc->FDefs;3656limit = def + exc->numFDefs;36573658while ( def < limit && def->opc != F )3659def++;36603661if ( def == limit )3662goto Fail;3663}36643665/* check that the function is active */3666if ( !def->active )3667goto Fail;36683669/* check the call stack */3670if ( exc->callTop >= exc->callSize )3671{3672exc->error = FT_THROW( Stack_Overflow );3673return;3674}36753676pCrec = exc->callStack + exc->callTop;36773678pCrec->Caller_Range = exc->curRange;3679pCrec->Caller_IP = exc->IP + 1;3680pCrec->Cur_Count = 1;3681pCrec->Def = def;36823683exc->callTop++;36843685Ins_Goto_CodeRange( exc, def->range, def->start );36863687exc->step_ins = FALSE;36883689return;36903691Fail:3692exc->error = FT_THROW( Invalid_Reference );3693}369436953696/**************************************************************************3697*3698* LOOPCALL[]: LOOP and CALL function3699* Opcode range: 0x2A3700* Stack: uint32? Eint16? -->3701*/3702static void3703Ins_LOOPCALL( TT_ExecContext exc,3704FT_Long* args )3705{3706FT_ULong F;3707TT_CallRec* pCrec;3708TT_DefRecord* def;370937103711/* first of all, check the index */3712F = (FT_ULong)args[1];3713if ( BOUNDSL( F, exc->maxFunc + 1 ) )3714goto Fail;37153716/* Except for some old Apple fonts, all functions in a TrueType */3717/* font are defined in increasing order, starting from 0. This */3718/* means that we normally have */3719/* */3720/* exc->maxFunc+1 == exc->numFDefs */3721/* exc->FDefs[n].opc == n for n in 0..exc->maxFunc */3722/* */3723/* If this isn't true, we need to look up the function table. */37243725def = FT_OFFSET( exc->FDefs, F );3726if ( exc->maxFunc + 1 != exc->numFDefs || def->opc != F )3727{3728/* look up the FDefs table */3729TT_DefRecord* limit;373037313732def = exc->FDefs;3733limit = FT_OFFSET( def, exc->numFDefs );37343735while ( def < limit && def->opc != F )3736def++;37373738if ( def == limit )3739goto Fail;3740}37413742/* check that the function is active */3743if ( !def->active )3744goto Fail;37453746/* check stack */3747if ( exc->callTop >= exc->callSize )3748{3749exc->error = FT_THROW( Stack_Overflow );3750return;3751}37523753if ( args[0] > 0 )3754{3755pCrec = exc->callStack + exc->callTop;37563757pCrec->Caller_Range = exc->curRange;3758pCrec->Caller_IP = exc->IP + 1;3759pCrec->Cur_Count = (FT_Int)args[0];3760pCrec->Def = def;37613762exc->callTop++;37633764Ins_Goto_CodeRange( exc, def->range, def->start );37653766exc->step_ins = FALSE;37673768exc->loopcall_counter += (FT_ULong)args[0];3769if ( exc->loopcall_counter > exc->loopcall_counter_max )3770exc->error = FT_THROW( Execution_Too_Long );3771}37723773return;37743775Fail:3776exc->error = FT_THROW( Invalid_Reference );3777}377837793780/**************************************************************************3781*3782* IDEF[]: Instruction DEFinition3783* Opcode range: 0x893784* Stack: Eint8 -->3785*/3786static void3787Ins_IDEF( TT_ExecContext exc,3788FT_Long* args )3789{3790TT_DefRecord* def;3791TT_DefRecord* limit;379237933794/* we enable IDEF only in `prep' or `fpgm' */3795if ( exc->iniRange == tt_coderange_glyph )3796{3797exc->error = FT_THROW( DEF_In_Glyf_Bytecode );3798return;3799}38003801/* First of all, look for the same function in our table */38023803def = exc->IDefs;3804limit = FT_OFFSET( def, exc->numIDefs );38053806for ( ; def < limit; def++ )3807if ( def->opc == (FT_ULong)args[0] )3808break;38093810if ( def == limit )3811{3812/* check that there is enough room for a new instruction */3813if ( exc->numIDefs >= exc->maxIDefs )3814{3815exc->error = FT_THROW( Too_Many_Instruction_Defs );3816return;3817}3818exc->numIDefs++;3819}38203821/* opcode must be unsigned 8-bit integer */3822if ( 0 > args[0] || args[0] > 0x00FF )3823{3824exc->error = FT_THROW( Too_Many_Instruction_Defs );3825return;3826}38273828def->opc = (FT_Byte)args[0];3829def->start = exc->IP + 1;3830def->range = exc->curRange;3831def->active = TRUE;38323833if ( (FT_ULong)args[0] > exc->maxIns )3834exc->maxIns = (FT_Byte)args[0];38353836/* Now skip the whole function definition. */3837/* We don't allow nested IDEFs & FDEFs. */38383839while ( SkipCode( exc ) == SUCCESS )3840{3841switch ( exc->opcode )3842{3843case 0x89: /* IDEF */3844case 0x2C: /* FDEF */3845exc->error = FT_THROW( Nested_DEFS );3846return;3847case 0x2D: /* ENDF */3848def->end = exc->IP;3849return;3850}3851}3852}385338543855/**************************************************************************3856*3857* PUSHING DATA ONTO THE INTERPRETER STACK3858*3859*/386038613862/**************************************************************************3863*3864* NPUSHB[]: PUSH N Bytes3865* Opcode range: 0x403866* Stack: --> uint32...3867*/3868static void3869Ins_NPUSHB( TT_ExecContext exc,3870FT_Long* args )3871{3872FT_UShort L, K;387338743875L = (FT_UShort)exc->code[exc->IP + 1];38763877if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) )3878{3879exc->error = FT_THROW( Stack_Overflow );3880return;3881}38823883for ( K = 1; K <= L; K++ )3884args[K - 1] = exc->code[exc->IP + K + 1];38853886exc->new_top += L;3887}388838893890/**************************************************************************3891*3892* NPUSHW[]: PUSH N Words3893* Opcode range: 0x413894* Stack: --> int32...3895*/3896static void3897Ins_NPUSHW( TT_ExecContext exc,3898FT_Long* args )3899{3900FT_UShort L, K;390139023903L = (FT_UShort)exc->code[exc->IP + 1];39043905if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) )3906{3907exc->error = FT_THROW( Stack_Overflow );3908return;3909}39103911exc->IP += 2;39123913for ( K = 0; K < L; K++ )3914args[K] = GetShortIns( exc );39153916exc->step_ins = FALSE;3917exc->new_top += L;3918}391939203921/**************************************************************************3922*3923* PUSHB[abc]: PUSH Bytes3924* Opcode range: 0xB0-0xB73925* Stack: --> uint32...3926*/3927static void3928Ins_PUSHB( TT_ExecContext exc,3929FT_Long* args )3930{3931FT_UShort L, K;393239333934L = (FT_UShort)( exc->opcode - 0xB0 + 1 );39353936if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) )3937{3938exc->error = FT_THROW( Stack_Overflow );3939return;3940}39413942for ( K = 1; K <= L; K++ )3943args[K - 1] = exc->code[exc->IP + K];3944}394539463947/**************************************************************************3948*3949* PUSHW[abc]: PUSH Words3950* Opcode range: 0xB8-0xBF3951* Stack: --> int32...3952*/3953static void3954Ins_PUSHW( TT_ExecContext exc,3955FT_Long* args )3956{3957FT_UShort L, K;395839593960L = (FT_UShort)( exc->opcode - 0xB8 + 1 );39613962if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) )3963{3964exc->error = FT_THROW( Stack_Overflow );3965return;3966}39673968exc->IP++;39693970for ( K = 0; K < L; K++ )3971args[K] = GetShortIns( exc );39723973exc->step_ins = FALSE;3974}397539763977/**************************************************************************3978*3979* MANAGING THE GRAPHICS STATE3980*3981*/398239833984static FT_Bool3985Ins_SxVTL( TT_ExecContext exc,3986FT_UShort aIdx1,3987FT_UShort aIdx2,3988FT_UnitVector* Vec )3989{3990FT_Long A, B, C;3991FT_Vector* p1;3992FT_Vector* p2;39933994FT_Byte opcode = exc->opcode;399539963997if ( BOUNDS( aIdx1, exc->zp2.n_points ) ||3998BOUNDS( aIdx2, exc->zp1.n_points ) )3999{4000if ( exc->pedantic_hinting )4001exc->error = FT_THROW( Invalid_Reference );4002return FAILURE;4003}40044005p1 = exc->zp1.cur + aIdx2;4006p2 = exc->zp2.cur + aIdx1;40074008A = SUB_LONG( p1->x, p2->x );4009B = SUB_LONG( p1->y, p2->y );40104011/* If p1 == p2, SPvTL and SFvTL behave the same as */4012/* SPvTCA[X] and SFvTCA[X], respectively. */4013/* */4014/* Confirmed by Greg Hitchcock. */40154016if ( A == 0 && B == 0 )4017{4018A = 0x4000;4019opcode = 0;4020}40214022if ( ( opcode & 1 ) != 0 )4023{4024C = B; /* counter-clockwise rotation */4025B = A;4026A = NEG_LONG( C );4027}40284029Normalize( A, B, Vec );40304031return SUCCESS;4032}403340344035/**************************************************************************4036*4037* SVTCA[a]: Set (F and P) Vectors to Coordinate Axis4038* Opcode range: 0x00-0x014039* Stack: -->4040*4041* SPvTCA[a]: Set PVector to Coordinate Axis4042* Opcode range: 0x02-0x034043* Stack: -->4044*4045* SFvTCA[a]: Set FVector to Coordinate Axis4046* Opcode range: 0x04-0x054047* Stack: -->4048*/4049static void4050Ins_SxyTCA( TT_ExecContext exc )4051{4052FT_Short AA, BB;40534054FT_Byte opcode = exc->opcode;405540564057AA = (FT_Short)( ( opcode & 1 ) << 14 );4058BB = (FT_Short)( AA ^ 0x4000 );40594060if ( opcode < 4 )4061{4062exc->GS.projVector.x = AA;4063exc->GS.projVector.y = BB;40644065exc->GS.dualVector.x = AA;4066exc->GS.dualVector.y = BB;4067}40684069if ( ( opcode & 2 ) == 0 )4070{4071exc->GS.freeVector.x = AA;4072exc->GS.freeVector.y = BB;4073}40744075Compute_Funcs( exc );4076}407740784079/**************************************************************************4080*4081* SPvTL[a]: Set PVector To Line4082* Opcode range: 0x06-0x074083* Stack: uint32 uint32 -->4084*/4085static void4086Ins_SPVTL( TT_ExecContext exc,4087FT_Long* args )4088{4089if ( Ins_SxVTL( exc,4090(FT_UShort)args[1],4091(FT_UShort)args[0],4092&exc->GS.projVector ) == SUCCESS )4093{4094exc->GS.dualVector = exc->GS.projVector;4095Compute_Funcs( exc );4096}4097}409840994100/**************************************************************************4101*4102* SFvTL[a]: Set FVector To Line4103* Opcode range: 0x08-0x094104* Stack: uint32 uint32 -->4105*/4106static void4107Ins_SFVTL( TT_ExecContext exc,4108FT_Long* args )4109{4110if ( Ins_SxVTL( exc,4111(FT_UShort)args[1],4112(FT_UShort)args[0],4113&exc->GS.freeVector ) == SUCCESS )4114{4115Compute_Funcs( exc );4116}4117}411841194120/**************************************************************************4121*4122* SFvTPv[]: Set FVector To PVector4123* Opcode range: 0x0E4124* Stack: -->4125*/4126static void4127Ins_SFVTPV( TT_ExecContext exc )4128{4129exc->GS.freeVector = exc->GS.projVector;4130Compute_Funcs( exc );4131}413241334134/**************************************************************************4135*4136* SPvFS[]: Set PVector From Stack4137* Opcode range: 0x0A4138* Stack: f2.14 f2.14 -->4139*/4140static void4141Ins_SPVFS( TT_ExecContext exc,4142FT_Long* args )4143{4144FT_Short S;4145FT_Long X, Y;414641474148/* Only use low 16bits, then sign extend */4149S = (FT_Short)args[1];4150Y = (FT_Long)S;4151S = (FT_Short)args[0];4152X = (FT_Long)S;41534154Normalize( X, Y, &exc->GS.projVector );41554156exc->GS.dualVector = exc->GS.projVector;4157Compute_Funcs( exc );4158}415941604161/**************************************************************************4162*4163* SFvFS[]: Set FVector From Stack4164* Opcode range: 0x0B4165* Stack: f2.14 f2.14 -->4166*/4167static void4168Ins_SFVFS( TT_ExecContext exc,4169FT_Long* args )4170{4171FT_Short S;4172FT_Long X, Y;417341744175/* Only use low 16bits, then sign extend */4176S = (FT_Short)args[1];4177Y = (FT_Long)S;4178S = (FT_Short)args[0];4179X = S;41804181Normalize( X, Y, &exc->GS.freeVector );4182Compute_Funcs( exc );4183}418441854186/**************************************************************************4187*4188* GPv[]: Get Projection Vector4189* Opcode range: 0x0C4190* Stack: ef2.14 --> ef2.144191*/4192static void4193Ins_GPV( TT_ExecContext exc,4194FT_Long* args )4195{4196args[0] = exc->GS.projVector.x;4197args[1] = exc->GS.projVector.y;4198}419942004201/**************************************************************************4202*4203* GFv[]: Get Freedom Vector4204* Opcode range: 0x0D4205* Stack: ef2.14 --> ef2.144206*/4207static void4208Ins_GFV( TT_ExecContext exc,4209FT_Long* args )4210{4211args[0] = exc->GS.freeVector.x;4212args[1] = exc->GS.freeVector.y;4213}421442154216/**************************************************************************4217*4218* SRP0[]: Set Reference Point 04219* Opcode range: 0x104220* Stack: uint32 -->4221*/4222static void4223Ins_SRP0( TT_ExecContext exc,4224FT_Long* args )4225{4226exc->GS.rp0 = (FT_UShort)args[0];4227}422842294230/**************************************************************************4231*4232* SRP1[]: Set Reference Point 14233* Opcode range: 0x114234* Stack: uint32 -->4235*/4236static void4237Ins_SRP1( TT_ExecContext exc,4238FT_Long* args )4239{4240exc->GS.rp1 = (FT_UShort)args[0];4241}424242434244/**************************************************************************4245*4246* SRP2[]: Set Reference Point 24247* Opcode range: 0x124248* Stack: uint32 -->4249*/4250static void4251Ins_SRP2( TT_ExecContext exc,4252FT_Long* args )4253{4254exc->GS.rp2 = (FT_UShort)args[0];4255}425642574258/**************************************************************************4259*4260* SMD[]: Set Minimum Distance4261* Opcode range: 0x1A4262* Stack: f26.6 -->4263*/4264static void4265Ins_SMD( TT_ExecContext exc,4266FT_Long* args )4267{4268exc->GS.minimum_distance = args[0];4269}427042714272/**************************************************************************4273*4274* SCVTCI[]: Set Control Value Table Cut In4275* Opcode range: 0x1D4276* Stack: f26.6 -->4277*/4278static void4279Ins_SCVTCI( TT_ExecContext exc,4280FT_Long* args )4281{4282exc->GS.control_value_cutin = (FT_F26Dot6)args[0];4283}428442854286/**************************************************************************4287*4288* SSWCI[]: Set Single Width Cut In4289* Opcode range: 0x1E4290* Stack: f26.6 -->4291*/4292static void4293Ins_SSWCI( TT_ExecContext exc,4294FT_Long* args )4295{4296exc->GS.single_width_cutin = (FT_F26Dot6)args[0];4297}429842994300/**************************************************************************4301*4302* SSW[]: Set Single Width4303* Opcode range: 0x1F4304* Stack: int32? -->4305*/4306static void4307Ins_SSW( TT_ExecContext exc,4308FT_Long* args )4309{4310exc->GS.single_width_value = FT_MulFix( args[0],4311exc->tt_metrics.scale );4312}431343144315/**************************************************************************4316*4317* FLIPON[]: Set auto-FLIP to ON4318* Opcode range: 0x4D4319* Stack: -->4320*/4321static void4322Ins_FLIPON( TT_ExecContext exc )4323{4324exc->GS.auto_flip = TRUE;4325}432643274328/**************************************************************************4329*4330* FLIPOFF[]: Set auto-FLIP to OFF4331* Opcode range: 0x4E4332* Stack: -->4333*/4334static void4335Ins_FLIPOFF( TT_ExecContext exc )4336{4337exc->GS.auto_flip = FALSE;4338}433943404341/**************************************************************************4342*4343* SANGW[]: Set ANGle Weight4344* Opcode range: 0x7E4345* Stack: uint32 -->4346*/4347static void4348Ins_SANGW( void )4349{4350/* instruction not supported anymore */4351}435243534354/**************************************************************************4355*4356* SDB[]: Set Delta Base4357* Opcode range: 0x5E4358* Stack: uint32 -->4359*/4360static void4361Ins_SDB( TT_ExecContext exc,4362FT_Long* args )4363{4364exc->GS.delta_base = (FT_UShort)args[0];4365}436643674368/**************************************************************************4369*4370* SDS[]: Set Delta Shift4371* Opcode range: 0x5F4372* Stack: uint32 -->4373*/4374static void4375Ins_SDS( TT_ExecContext exc,4376FT_Long* args )4377{4378if ( (FT_ULong)args[0] > 6UL )4379exc->error = FT_THROW( Bad_Argument );4380else4381exc->GS.delta_shift = (FT_UShort)args[0];4382}438343844385/**************************************************************************4386*4387* RTHG[]: Round To Half Grid4388* Opcode range: 0x194389* Stack: -->4390*/4391static void4392Ins_RTHG( TT_ExecContext exc )4393{4394exc->GS.round_state = TT_Round_To_Half_Grid;4395exc->func_round = (TT_Round_Func)Round_To_Half_Grid;4396}439743984399/**************************************************************************4400*4401* RTG[]: Round To Grid4402* Opcode range: 0x184403* Stack: -->4404*/4405static void4406Ins_RTG( TT_ExecContext exc )4407{4408exc->GS.round_state = TT_Round_To_Grid;4409exc->func_round = (TT_Round_Func)Round_To_Grid;4410}441144124413/**************************************************************************4414* RTDG[]: Round To Double Grid4415* Opcode range: 0x3D4416* Stack: -->4417*/4418static void4419Ins_RTDG( TT_ExecContext exc )4420{4421exc->GS.round_state = TT_Round_To_Double_Grid;4422exc->func_round = (TT_Round_Func)Round_To_Double_Grid;4423}442444254426/**************************************************************************4427* RUTG[]: Round Up To Grid4428* Opcode range: 0x7C4429* Stack: -->4430*/4431static void4432Ins_RUTG( TT_ExecContext exc )4433{4434exc->GS.round_state = TT_Round_Up_To_Grid;4435exc->func_round = (TT_Round_Func)Round_Up_To_Grid;4436}443744384439/**************************************************************************4440*4441* RDTG[]: Round Down To Grid4442* Opcode range: 0x7D4443* Stack: -->4444*/4445static void4446Ins_RDTG( TT_ExecContext exc )4447{4448exc->GS.round_state = TT_Round_Down_To_Grid;4449exc->func_round = (TT_Round_Func)Round_Down_To_Grid;4450}445144524453/**************************************************************************4454*4455* ROFF[]: Round OFF4456* Opcode range: 0x7A4457* Stack: -->4458*/4459static void4460Ins_ROFF( TT_ExecContext exc )4461{4462exc->GS.round_state = TT_Round_Off;4463exc->func_round = (TT_Round_Func)Round_None;4464}446544664467/**************************************************************************4468*4469* SROUND[]: Super ROUND4470* Opcode range: 0x764471* Stack: Eint8 -->4472*/4473static void4474Ins_SROUND( TT_ExecContext exc,4475FT_Long* args )4476{4477SetSuperRound( exc, 0x4000, args[0] );44784479exc->GS.round_state = TT_Round_Super;4480exc->func_round = (TT_Round_Func)Round_Super;4481}448244834484/**************************************************************************4485*4486* S45ROUND[]: Super ROUND 45 degrees4487* Opcode range: 0x774488* Stack: uint32 -->4489*/4490static void4491Ins_S45ROUND( TT_ExecContext exc,4492FT_Long* args )4493{4494SetSuperRound( exc, 0x2D41, args[0] );44954496exc->GS.round_state = TT_Round_Super_45;4497exc->func_round = (TT_Round_Func)Round_Super_45;4498}449945004501/**************************************************************************4502*4503* GC[a]: Get Coordinate projected onto4504* Opcode range: 0x46-0x474505* Stack: uint32 --> f26.64506*4507* XXX: UNDOCUMENTED: Measures from the original glyph must be taken4508* along the dual projection vector!4509*/4510static void4511Ins_GC( TT_ExecContext exc,4512FT_Long* args )4513{4514FT_ULong L;4515FT_F26Dot6 R;451645174518L = (FT_ULong)args[0];45194520if ( BOUNDSL( L, exc->zp2.n_points ) )4521{4522if ( exc->pedantic_hinting )4523exc->error = FT_THROW( Invalid_Reference );4524R = 0;4525}4526else4527{4528if ( exc->opcode & 1 )4529R = FAST_DUALPROJ( &exc->zp2.org[L] );4530else4531R = FAST_PROJECT( &exc->zp2.cur[L] );4532}45334534args[0] = R;4535}453645374538/**************************************************************************4539*4540* SCFS[]: Set Coordinate From Stack4541* Opcode range: 0x484542* Stack: f26.6 uint32 -->4543*4544* Formula:4545*4546* OA := OA + ( value - OA.p )/( f.p ) * f4547*/4548static void4549Ins_SCFS( TT_ExecContext exc,4550FT_Long* args )4551{4552FT_Long K;4553FT_UShort L;455445554556L = (FT_UShort)args[0];45574558if ( BOUNDS( L, exc->zp2.n_points ) )4559{4560if ( exc->pedantic_hinting )4561exc->error = FT_THROW( Invalid_Reference );4562return;4563}45644565K = FAST_PROJECT( &exc->zp2.cur[L] );45664567exc->func_move( exc, &exc->zp2, L, SUB_LONG( args[1], K ) );45684569/* UNDOCUMENTED! The MS rasterizer does that with */4570/* twilight points (confirmed by Greg Hitchcock) */4571if ( exc->GS.gep2 == 0 )4572exc->zp2.org[L] = exc->zp2.cur[L];4573}457445754576/**************************************************************************4577*4578* MD[a]: Measure Distance4579* Opcode range: 0x49-0x4A4580* Stack: uint32 uint32 --> f26.64581*4582* XXX: UNDOCUMENTED: Measure taken in the original glyph must be along4583* the dual projection vector.4584*4585* XXX: UNDOCUMENTED: Flag attributes are inverted!4586* 0 => measure distance in original outline4587* 1 => measure distance in grid-fitted outline4588*4589* XXX: UNDOCUMENTED: `zp0 - zp1', and not `zp2 - zp1!4590*/4591static void4592Ins_MD( TT_ExecContext exc,4593FT_Long* args )4594{4595FT_UShort K, L;4596FT_F26Dot6 D;459745984599K = (FT_UShort)args[1];4600L = (FT_UShort)args[0];46014602if ( BOUNDS( L, exc->zp0.n_points ) ||4603BOUNDS( K, exc->zp1.n_points ) )4604{4605if ( exc->pedantic_hinting )4606exc->error = FT_THROW( Invalid_Reference );4607D = 0;4608}4609else4610{4611if ( exc->opcode & 1 )4612D = PROJECT( exc->zp0.cur + L, exc->zp1.cur + K );4613else4614{4615/* XXX: UNDOCUMENTED: twilight zone special case */46164617if ( exc->GS.gep0 == 0 || exc->GS.gep1 == 0 )4618{4619FT_Vector* vec1 = exc->zp0.org + L;4620FT_Vector* vec2 = exc->zp1.org + K;462146224623D = DUALPROJ( vec1, vec2 );4624}4625else4626{4627FT_Vector* vec1 = exc->zp0.orus + L;4628FT_Vector* vec2 = exc->zp1.orus + K;462946304631if ( exc->metrics.x_scale == exc->metrics.y_scale )4632{4633/* this should be faster */4634D = DUALPROJ( vec1, vec2 );4635D = FT_MulFix( D, exc->metrics.x_scale );4636}4637else4638{4639FT_Vector vec;464046414642vec.x = FT_MulFix( vec1->x - vec2->x, exc->metrics.x_scale );4643vec.y = FT_MulFix( vec1->y - vec2->y, exc->metrics.y_scale );46444645D = FAST_DUALPROJ( &vec );4646}4647}4648}4649}46504651args[0] = D;4652}465346544655/**************************************************************************4656*4657* SDPvTL[a]: Set Dual PVector to Line4658* Opcode range: 0x86-0x874659* Stack: uint32 uint32 -->4660*/4661static void4662Ins_SDPVTL( TT_ExecContext exc,4663FT_Long* args )4664{4665FT_Long A, B, C;4666FT_UShort p1, p2; /* was FT_Int in pas type ERROR */46674668FT_Byte opcode = exc->opcode;466946704671p1 = (FT_UShort)args[1];4672p2 = (FT_UShort)args[0];46734674if ( BOUNDS( p2, exc->zp1.n_points ) ||4675BOUNDS( p1, exc->zp2.n_points ) )4676{4677if ( exc->pedantic_hinting )4678exc->error = FT_THROW( Invalid_Reference );4679return;4680}46814682{4683FT_Vector* v1 = exc->zp1.org + p2;4684FT_Vector* v2 = exc->zp2.org + p1;468546864687A = SUB_LONG( v1->x, v2->x );4688B = SUB_LONG( v1->y, v2->y );46894690/* If v1 == v2, SDPvTL behaves the same as */4691/* SVTCA[X], respectively. */4692/* */4693/* Confirmed by Greg Hitchcock. */46944695if ( A == 0 && B == 0 )4696{4697A = 0x4000;4698opcode = 0;4699}4700}47014702if ( ( opcode & 1 ) != 0 )4703{4704C = B; /* counter-clockwise rotation */4705B = A;4706A = NEG_LONG( C );4707}47084709Normalize( A, B, &exc->GS.dualVector );47104711{4712FT_Vector* v1 = exc->zp1.cur + p2;4713FT_Vector* v2 = exc->zp2.cur + p1;471447154716A = SUB_LONG( v1->x, v2->x );4717B = SUB_LONG( v1->y, v2->y );47184719if ( A == 0 && B == 0 )4720{4721A = 0x4000;4722opcode = 0;4723}4724}47254726if ( ( opcode & 1 ) != 0 )4727{4728C = B; /* counter-clockwise rotation */4729B = A;4730A = NEG_LONG( C );4731}47324733Normalize( A, B, &exc->GS.projVector );4734Compute_Funcs( exc );4735}473647374738/**************************************************************************4739*4740* SZP0[]: Set Zone Pointer 04741* Opcode range: 0x134742* Stack: uint32 -->4743*/4744static void4745Ins_SZP0( TT_ExecContext exc,4746FT_Long* args )4747{4748switch ( (FT_Int)args[0] )4749{4750case 0:4751exc->zp0 = exc->twilight;4752break;47534754case 1:4755exc->zp0 = exc->pts;4756break;47574758default:4759if ( exc->pedantic_hinting )4760exc->error = FT_THROW( Invalid_Reference );4761return;4762}47634764exc->GS.gep0 = (FT_UShort)args[0];4765}476647674768/**************************************************************************4769*4770* SZP1[]: Set Zone Pointer 14771* Opcode range: 0x144772* Stack: uint32 -->4773*/4774static void4775Ins_SZP1( TT_ExecContext exc,4776FT_Long* args )4777{4778switch ( (FT_Int)args[0] )4779{4780case 0:4781exc->zp1 = exc->twilight;4782break;47834784case 1:4785exc->zp1 = exc->pts;4786break;47874788default:4789if ( exc->pedantic_hinting )4790exc->error = FT_THROW( Invalid_Reference );4791return;4792}47934794exc->GS.gep1 = (FT_UShort)args[0];4795}479647974798/**************************************************************************4799*4800* SZP2[]: Set Zone Pointer 24801* Opcode range: 0x154802* Stack: uint32 -->4803*/4804static void4805Ins_SZP2( TT_ExecContext exc,4806FT_Long* args )4807{4808switch ( (FT_Int)args[0] )4809{4810case 0:4811exc->zp2 = exc->twilight;4812break;48134814case 1:4815exc->zp2 = exc->pts;4816break;48174818default:4819if ( exc->pedantic_hinting )4820exc->error = FT_THROW( Invalid_Reference );4821return;4822}48234824exc->GS.gep2 = (FT_UShort)args[0];4825}482648274828/**************************************************************************4829*4830* SZPS[]: Set Zone PointerS4831* Opcode range: 0x164832* Stack: uint32 -->4833*/4834static void4835Ins_SZPS( TT_ExecContext exc,4836FT_Long* args )4837{4838switch ( (FT_Int)args[0] )4839{4840case 0:4841exc->zp0 = exc->twilight;4842break;48434844case 1:4845exc->zp0 = exc->pts;4846break;48474848default:4849if ( exc->pedantic_hinting )4850exc->error = FT_THROW( Invalid_Reference );4851return;4852}48534854exc->zp1 = exc->zp0;4855exc->zp2 = exc->zp0;48564857exc->GS.gep0 = (FT_UShort)args[0];4858exc->GS.gep1 = (FT_UShort)args[0];4859exc->GS.gep2 = (FT_UShort)args[0];4860}486148624863/**************************************************************************4864*4865* INSTCTRL[]: INSTruction ConTRoL4866* Opcode range: 0x8E4867* Stack: int32 int32 -->4868*/4869static void4870Ins_INSTCTRL( TT_ExecContext exc,4871FT_Long* args )4872{4873FT_ULong K, L, Kf;487448754876K = (FT_ULong)args[1];4877L = (FT_ULong)args[0];48784879/* selector values cannot be `OR'ed; */4880/* they are indices starting with index 1, not flags */4881if ( K < 1 || K > 3 )4882{4883if ( exc->pedantic_hinting )4884exc->error = FT_THROW( Invalid_Reference );4885return;4886}48874888/* convert index to flag value */4889Kf = 1 << ( K - 1 );48904891if ( L != 0 )4892{4893/* arguments to selectors look like flag values */4894if ( L != Kf )4895{4896if ( exc->pedantic_hinting )4897exc->error = FT_THROW( Invalid_Reference );4898return;4899}4900}49014902/* INSTCTRL should only be used in the CVT program */4903if ( exc->iniRange == tt_coderange_cvt )4904{4905exc->GS.instruct_control &= ~(FT_Byte)Kf;4906exc->GS.instruct_control |= (FT_Byte)L;4907}49084909/* except to change the subpixel flags temporarily */4910else if ( exc->iniRange == tt_coderange_glyph && K == 3 )4911{4912#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL4913/* Native ClearType fonts sign a waiver that turns off all backward */4914/* compatibility hacks and lets them program points to the grid like */4915/* it's 1996. They might sign a waiver for just one glyph, though. */4916if ( SUBPIXEL_HINTING_MINIMAL )4917exc->backward_compatibility = !FT_BOOL( L == 4 );4918#endif4919}4920else if ( exc->pedantic_hinting )4921exc->error = FT_THROW( Invalid_Reference );4922}492349244925/**************************************************************************4926*4927* SCANCTRL[]: SCAN ConTRoL4928* Opcode range: 0x854929* Stack: uint32? -->4930*/4931static void4932Ins_SCANCTRL( TT_ExecContext exc,4933FT_Long* args )4934{4935FT_Int A;493649374938/* Get Threshold */4939A = (FT_Int)( args[0] & 0xFF );49404941if ( A == 0xFF )4942{4943exc->GS.scan_control = TRUE;4944return;4945}4946else if ( A == 0 )4947{4948exc->GS.scan_control = FALSE;4949return;4950}49514952if ( ( args[0] & 0x100 ) != 0 && exc->tt_metrics.ppem <= A )4953exc->GS.scan_control = TRUE;49544955if ( ( args[0] & 0x200 ) != 0 && exc->tt_metrics.rotated )4956exc->GS.scan_control = TRUE;49574958if ( ( args[0] & 0x400 ) != 0 && exc->tt_metrics.stretched )4959exc->GS.scan_control = TRUE;49604961if ( ( args[0] & 0x800 ) != 0 && exc->tt_metrics.ppem > A )4962exc->GS.scan_control = FALSE;49634964if ( ( args[0] & 0x1000 ) != 0 && exc->tt_metrics.rotated )4965exc->GS.scan_control = FALSE;49664967if ( ( args[0] & 0x2000 ) != 0 && exc->tt_metrics.stretched )4968exc->GS.scan_control = FALSE;4969}497049714972/**************************************************************************4973*4974* SCANTYPE[]: SCAN TYPE4975* Opcode range: 0x8D4976* Stack: uint16 -->4977*/4978static void4979Ins_SCANTYPE( TT_ExecContext exc,4980FT_Long* args )4981{4982if ( args[0] >= 0 )4983exc->GS.scan_type = (FT_Int)args[0] & 0xFFFF;4984}498549864987/**************************************************************************4988*4989* MANAGING OUTLINES4990*4991*/499249934994/**************************************************************************4995*4996* FLIPPT[]: FLIP PoinT4997* Opcode range: 0x804998* Stack: uint32... -->4999*/5000static void5001Ins_FLIPPT( TT_ExecContext exc )5002{5003FT_UShort point;500450055006#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL5007/* See `ttinterp.h' for details on backward compatibility mode. */5008if ( SUBPIXEL_HINTING_MINIMAL &&5009exc->backward_compatibility &&5010exc->iupx_called &&5011exc->iupy_called )5012goto Fail;5013#endif50145015if ( exc->top < exc->GS.loop )5016{5017if ( exc->pedantic_hinting )5018exc->error = FT_THROW( Too_Few_Arguments );5019goto Fail;5020}50215022while ( exc->GS.loop > 0 )5023{5024exc->args--;50255026point = (FT_UShort)exc->stack[exc->args];50275028if ( BOUNDS( point, exc->pts.n_points ) )5029{5030if ( exc->pedantic_hinting )5031{5032exc->error = FT_THROW( Invalid_Reference );5033return;5034}5035}5036else5037exc->pts.tags[point] ^= FT_CURVE_TAG_ON;50385039exc->GS.loop--;5040}50415042Fail:5043exc->GS.loop = 1;5044exc->new_top = exc->args;5045}504650475048/**************************************************************************5049*5050* FLIPRGON[]: FLIP RanGe ON5051* Opcode range: 0x815052* Stack: uint32 uint32 -->5053*/5054static void5055Ins_FLIPRGON( TT_ExecContext exc,5056FT_Long* args )5057{5058FT_UShort I, K, L;505950605061#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL5062/* See `ttinterp.h' for details on backward compatibility mode. */5063if ( SUBPIXEL_HINTING_MINIMAL &&5064exc->backward_compatibility &&5065exc->iupx_called &&5066exc->iupy_called )5067return;5068#endif50695070K = (FT_UShort)args[1];5071L = (FT_UShort)args[0];50725073if ( BOUNDS( K, exc->pts.n_points ) ||5074BOUNDS( L, exc->pts.n_points ) )5075{5076if ( exc->pedantic_hinting )5077exc->error = FT_THROW( Invalid_Reference );5078return;5079}50805081for ( I = L; I <= K; I++ )5082exc->pts.tags[I] |= FT_CURVE_TAG_ON;5083}508450855086/**************************************************************************5087*5088* FLIPRGOFF: FLIP RanGe OFF5089* Opcode range: 0x825090* Stack: uint32 uint32 -->5091*/5092static void5093Ins_FLIPRGOFF( TT_ExecContext exc,5094FT_Long* args )5095{5096FT_UShort I, K, L;509750985099#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL5100/* See `ttinterp.h' for details on backward compatibility mode. */5101if ( SUBPIXEL_HINTING_MINIMAL &&5102exc->backward_compatibility &&5103exc->iupx_called &&5104exc->iupy_called )5105return;5106#endif51075108K = (FT_UShort)args[1];5109L = (FT_UShort)args[0];51105111if ( BOUNDS( K, exc->pts.n_points ) ||5112BOUNDS( L, exc->pts.n_points ) )5113{5114if ( exc->pedantic_hinting )5115exc->error = FT_THROW( Invalid_Reference );5116return;5117}51185119for ( I = L; I <= K; I++ )5120exc->pts.tags[I] &= ~FT_CURVE_TAG_ON;5121}512251235124static FT_Bool5125Compute_Point_Displacement( TT_ExecContext exc,5126FT_F26Dot6* x,5127FT_F26Dot6* y,5128TT_GlyphZone zone,5129FT_UShort* refp )5130{5131TT_GlyphZoneRec zp;5132FT_UShort p;5133FT_F26Dot6 d;513451355136if ( exc->opcode & 1 )5137{5138zp = exc->zp0;5139p = exc->GS.rp1;5140}5141else5142{5143zp = exc->zp1;5144p = exc->GS.rp2;5145}51465147if ( BOUNDS( p, zp.n_points ) )5148{5149if ( exc->pedantic_hinting )5150exc->error = FT_THROW( Invalid_Reference );5151*refp = 0;5152return FAILURE;5153}51545155*zone = zp;5156*refp = p;51575158d = PROJECT( zp.cur + p, zp.org + p );51595160*x = FT_MulDiv( d, (FT_Long)exc->GS.freeVector.x, exc->F_dot_P );5161*y = FT_MulDiv( d, (FT_Long)exc->GS.freeVector.y, exc->F_dot_P );51625163return SUCCESS;5164}516551665167/* See `ttinterp.h' for details on backward compatibility mode. */5168static void5169Move_Zp2_Point( TT_ExecContext exc,5170FT_UShort point,5171FT_F26Dot6 dx,5172FT_F26Dot6 dy,5173FT_Bool touch )5174{5175if ( exc->GS.freeVector.x != 0 )5176{5177#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL5178if ( !( SUBPIXEL_HINTING_MINIMAL &&5179exc->backward_compatibility ) )5180#endif5181exc->zp2.cur[point].x = ADD_LONG( exc->zp2.cur[point].x, dx );51825183if ( touch )5184exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X;5185}51865187if ( exc->GS.freeVector.y != 0 )5188{5189#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL5190if ( !( SUBPIXEL_HINTING_MINIMAL &&5191exc->backward_compatibility &&5192exc->iupx_called &&5193exc->iupy_called ) )5194#endif5195exc->zp2.cur[point].y = ADD_LONG( exc->zp2.cur[point].y, dy );51965197if ( touch )5198exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y;5199}5200}520152025203/**************************************************************************5204*5205* SHP[a]: SHift Point by the last point5206* Opcode range: 0x32-0x335207* Stack: uint32... -->5208*/5209static void5210Ins_SHP( TT_ExecContext exc )5211{5212TT_GlyphZoneRec zp;5213FT_UShort refp;52145215FT_F26Dot6 dx, dy;5216FT_UShort point;521752185219if ( exc->top < exc->GS.loop )5220{5221if ( exc->pedantic_hinting )5222exc->error = FT_THROW( Invalid_Reference );5223goto Fail;5224}52255226if ( Compute_Point_Displacement( exc, &dx, &dy, &zp, &refp ) )5227return;52285229while ( exc->GS.loop > 0 )5230{5231exc->args--;5232point = (FT_UShort)exc->stack[exc->args];52335234if ( BOUNDS( point, exc->zp2.n_points ) )5235{5236if ( exc->pedantic_hinting )5237{5238exc->error = FT_THROW( Invalid_Reference );5239return;5240}5241}5242else5243Move_Zp2_Point( exc, point, dx, dy, TRUE );52445245exc->GS.loop--;5246}52475248Fail:5249exc->GS.loop = 1;5250exc->new_top = exc->args;5251}525252535254/**************************************************************************5255*5256* SHC[a]: SHift Contour5257* Opcode range: 0x34-355258* Stack: uint32 -->5259*5260* UNDOCUMENTED: According to Greg Hitchcock, there is one (virtual)5261* contour in the twilight zone, namely contour number5262* zero which includes all points of it.5263*/5264static void5265Ins_SHC( TT_ExecContext exc,5266FT_Long* args )5267{5268TT_GlyphZoneRec zp;5269FT_UShort refp;5270FT_F26Dot6 dx, dy;52715272FT_UShort contour, bounds;5273FT_UShort start, limit, i;527452755276contour = (FT_UShort)args[0];5277bounds = ( exc->GS.gep2 == 0 ) ? 1 : exc->zp2.n_contours;52785279if ( BOUNDS( contour, bounds ) )5280{5281if ( exc->pedantic_hinting )5282exc->error = FT_THROW( Invalid_Reference );5283return;5284}52855286if ( Compute_Point_Displacement( exc, &dx, &dy, &zp, &refp ) )5287return;52885289if ( contour == 0 )5290start = 0;5291else5292start = exc->zp2.contours[contour - 1] + 1 - exc->zp2.first_point;52935294/* we use the number of points if in the twilight zone */5295if ( exc->GS.gep2 == 0 )5296limit = exc->zp2.n_points;5297else5298limit = exc->zp2.contours[contour] + 1 - exc->zp2.first_point;52995300for ( i = start; i < limit; i++ )5301{5302if ( zp.cur != exc->zp2.cur || refp != i )5303Move_Zp2_Point( exc, i, dx, dy, TRUE );5304}5305}530653075308/**************************************************************************5309*5310* SHZ[a]: SHift Zone5311* Opcode range: 0x36-375312* Stack: uint32 -->5313*/5314static void5315Ins_SHZ( TT_ExecContext exc,5316FT_Long* args )5317{5318TT_GlyphZoneRec zp;5319FT_UShort refp;5320FT_F26Dot6 dx,5321dy;53225323FT_UShort limit, i;532453255326if ( BOUNDS( args[0], 2 ) )5327{5328if ( exc->pedantic_hinting )5329exc->error = FT_THROW( Invalid_Reference );5330return;5331}53325333if ( Compute_Point_Displacement( exc, &dx, &dy, &zp, &refp ) )5334return;53355336/* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points. */5337/* Twilight zone has no real contours, so use `n_points'. */5338/* Normal zone's `n_points' includes phantoms, so must */5339/* use end of last contour. */5340if ( exc->GS.gep2 == 0 )5341limit = exc->zp2.n_points;5342else if ( exc->GS.gep2 == 1 && exc->zp2.n_contours > 0 )5343limit = exc->zp2.contours[exc->zp2.n_contours - 1] + 1;5344else5345limit = 0;53465347/* XXX: UNDOCUMENTED! SHZ doesn't touch the points */5348for ( i = 0; i < limit; i++ )5349{5350if ( zp.cur != exc->zp2.cur || refp != i )5351Move_Zp2_Point( exc, i, dx, dy, FALSE );5352}5353}535453555356/**************************************************************************5357*5358* SHPIX[]: SHift points by a PIXel amount5359* Opcode range: 0x385360* Stack: f26.6 uint32... -->5361*/5362static void5363Ins_SHPIX( TT_ExecContext exc,5364FT_Long* args )5365{5366FT_F26Dot6 dx, dy;5367FT_UShort point;5368#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL5369FT_Bool in_twilight = FT_BOOL( exc->GS.gep0 == 0 ||5370exc->GS.gep1 == 0 ||5371exc->GS.gep2 == 0 );5372#endif5373537453755376if ( exc->top < exc->GS.loop + 1 )5377{5378if ( exc->pedantic_hinting )5379exc->error = FT_THROW( Invalid_Reference );5380goto Fail;5381}53825383dx = TT_MulFix14( args[0], exc->GS.freeVector.x );5384dy = TT_MulFix14( args[0], exc->GS.freeVector.y );53855386while ( exc->GS.loop > 0 )5387{5388exc->args--;53895390point = (FT_UShort)exc->stack[exc->args];53915392if ( BOUNDS( point, exc->zp2.n_points ) )5393{5394if ( exc->pedantic_hinting )5395{5396exc->error = FT_THROW( Invalid_Reference );5397return;5398}5399}5400else5401#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL5402if ( SUBPIXEL_HINTING_MINIMAL &&5403exc->backward_compatibility )5404{5405/* Special case: allow SHPIX to move points in the twilight zone. */5406/* Otherwise, treat SHPIX the same as DELTAP. Unbreaks various */5407/* fonts such as older versions of Rokkitt and DTL Argo T Light */5408/* that would glitch severely after calling ALIGNRP after a */5409/* blocked SHPIX. */5410if ( in_twilight ||5411( !( exc->iupx_called && exc->iupy_called ) &&5412( ( exc->is_composite && exc->GS.freeVector.y != 0 ) ||5413( exc->zp2.tags[point] & FT_CURVE_TAG_TOUCH_Y ) ) ) )5414Move_Zp2_Point( exc, point, 0, dy, TRUE );5415}5416else5417#endif5418Move_Zp2_Point( exc, point, dx, dy, TRUE );54195420exc->GS.loop--;5421}54225423Fail:5424exc->GS.loop = 1;5425exc->new_top = exc->args;5426}542754285429/**************************************************************************5430*5431* MSIRP[a]: Move Stack Indirect Relative Position5432* Opcode range: 0x3A-0x3B5433* Stack: f26.6 uint32 -->5434*/5435static void5436Ins_MSIRP( TT_ExecContext exc,5437FT_Long* args )5438{5439FT_UShort point = 0;5440FT_F26Dot6 distance;544154425443point = (FT_UShort)args[0];54445445if ( BOUNDS( point, exc->zp1.n_points ) ||5446BOUNDS( exc->GS.rp0, exc->zp0.n_points ) )5447{5448if ( exc->pedantic_hinting )5449exc->error = FT_THROW( Invalid_Reference );5450return;5451}54525453/* UNDOCUMENTED! The MS rasterizer does that with */5454/* twilight points (confirmed by Greg Hitchcock) */5455if ( exc->GS.gep1 == 0 )5456{5457exc->zp1.org[point] = exc->zp0.org[exc->GS.rp0];5458exc->func_move_orig( exc, &exc->zp1, point, args[1] );5459exc->zp1.cur[point] = exc->zp1.org[point];5460}54615462distance = PROJECT( exc->zp1.cur + point, exc->zp0.cur + exc->GS.rp0 );54635464exc->func_move( exc,5465&exc->zp1,5466point,5467SUB_LONG( args[1], distance ) );54685469exc->GS.rp1 = exc->GS.rp0;5470exc->GS.rp2 = point;54715472if ( ( exc->opcode & 1 ) != 0 )5473exc->GS.rp0 = point;5474}547554765477/**************************************************************************5478*5479* MDAP[a]: Move Direct Absolute Point5480* Opcode range: 0x2E-0x2F5481* Stack: uint32 -->5482*/5483static void5484Ins_MDAP( TT_ExecContext exc,5485FT_Long* args )5486{5487FT_UShort point;5488FT_F26Dot6 cur_dist;5489FT_F26Dot6 distance;549054915492point = (FT_UShort)args[0];54935494if ( BOUNDS( point, exc->zp0.n_points ) )5495{5496if ( exc->pedantic_hinting )5497exc->error = FT_THROW( Invalid_Reference );5498return;5499}55005501if ( ( exc->opcode & 1 ) != 0 )5502{5503cur_dist = FAST_PROJECT( &exc->zp0.cur[point] );5504distance = SUB_LONG( exc->func_round( exc, cur_dist, 3 ), cur_dist );5505}5506else5507distance = 0;55085509exc->func_move( exc, &exc->zp0, point, distance );55105511exc->GS.rp0 = point;5512exc->GS.rp1 = point;5513}551455155516/**************************************************************************5517*5518* MIAP[a]: Move Indirect Absolute Point5519* Opcode range: 0x3E-0x3F5520* Stack: uint32 uint32 -->5521*/5522static void5523Ins_MIAP( TT_ExecContext exc,5524FT_Long* args )5525{5526FT_ULong cvtEntry;5527FT_UShort point;5528FT_F26Dot6 distance;5529FT_F26Dot6 org_dist;553055315532cvtEntry = (FT_ULong)args[1];5533point = (FT_UShort)args[0];55345535if ( BOUNDS( point, exc->zp0.n_points ) ||5536BOUNDSL( cvtEntry, exc->cvtSize ) )5537{5538if ( exc->pedantic_hinting )5539exc->error = FT_THROW( Invalid_Reference );5540goto Fail;5541}55425543/* UNDOCUMENTED! */5544/* */5545/* The behaviour of an MIAP instruction is quite different when used */5546/* in the twilight zone. */5547/* */5548/* First, no control value cut-in test is performed as it would fail */5549/* anyway. Second, the original point, i.e. (org_x,org_y) of */5550/* zp0.point, is set to the absolute, unrounded distance found in the */5551/* CVT. */5552/* */5553/* This is used in the CVT programs of the Microsoft fonts Arial, */5554/* Times, etc., in order to re-adjust some key font heights. It */5555/* allows the use of the IP instruction in the twilight zone, which */5556/* otherwise would be invalid according to the specification. */5557/* */5558/* We implement it with a special sequence for the twilight zone. */5559/* This is a bad hack, but it seems to work. */5560/* */5561/* Confirmed by Greg Hitchcock. */55625563distance = exc->func_read_cvt( exc, cvtEntry );55645565if ( exc->GS.gep0 == 0 ) /* If in twilight zone */5566{5567exc->zp0.org[point].x = TT_MulFix14( distance,5568exc->GS.freeVector.x );5569exc->zp0.org[point].y = TT_MulFix14( distance,5570exc->GS.freeVector.y );5571exc->zp0.cur[point] = exc->zp0.org[point];5572}55735574org_dist = FAST_PROJECT( &exc->zp0.cur[point] );55755576if ( ( exc->opcode & 1 ) != 0 ) /* rounding and control cut-in flag */5577{5578FT_F26Dot6 control_value_cutin = exc->GS.control_value_cutin;5579FT_F26Dot6 delta;558055815582delta = SUB_LONG( distance, org_dist );5583if ( delta < 0 )5584delta = NEG_LONG( delta );55855586if ( delta > control_value_cutin )5587distance = org_dist;55885589distance = exc->func_round( exc, distance, 3 );5590}55915592exc->func_move( exc, &exc->zp0, point, SUB_LONG( distance, org_dist ) );55935594Fail:5595exc->GS.rp0 = point;5596exc->GS.rp1 = point;5597}559855995600/**************************************************************************5601*5602* MDRP[abcde]: Move Direct Relative Point5603* Opcode range: 0xC0-0xDF5604* Stack: uint32 -->5605*/5606static void5607Ins_MDRP( TT_ExecContext exc,5608FT_Long* args )5609{5610FT_UShort point = 0;5611FT_F26Dot6 org_dist, distance;561256135614point = (FT_UShort)args[0];56155616if ( BOUNDS( point, exc->zp1.n_points ) ||5617BOUNDS( exc->GS.rp0, exc->zp0.n_points ) )5618{5619if ( exc->pedantic_hinting )5620exc->error = FT_THROW( Invalid_Reference );5621goto Fail;5622}56235624/* XXX: Is there some undocumented feature while in the */5625/* twilight zone? */56265627/* XXX: UNDOCUMENTED: twilight zone special case */56285629if ( exc->GS.gep0 == 0 || exc->GS.gep1 == 0 )5630{5631FT_Vector* vec1 = &exc->zp1.org[point];5632FT_Vector* vec2 = &exc->zp0.org[exc->GS.rp0];563356345635org_dist = DUALPROJ( vec1, vec2 );5636}5637else5638{5639FT_Vector* vec1 = &exc->zp1.orus[point];5640FT_Vector* vec2 = &exc->zp0.orus[exc->GS.rp0];564156425643if ( exc->metrics.x_scale == exc->metrics.y_scale )5644{5645/* this should be faster */5646org_dist = DUALPROJ( vec1, vec2 );5647org_dist = FT_MulFix( org_dist, exc->metrics.x_scale );5648}5649else5650{5651FT_Vector vec;565256535654vec.x = FT_MulFix( SUB_LONG( vec1->x, vec2->x ),5655exc->metrics.x_scale );5656vec.y = FT_MulFix( SUB_LONG( vec1->y, vec2->y ),5657exc->metrics.y_scale );56585659org_dist = FAST_DUALPROJ( &vec );5660}5661}56625663/* single width cut-in test */56645665/* |org_dist - single_width_value| < single_width_cutin */5666if ( exc->GS.single_width_cutin > 0 &&5667org_dist < exc->GS.single_width_value +5668exc->GS.single_width_cutin &&5669org_dist > exc->GS.single_width_value -5670exc->GS.single_width_cutin )5671{5672if ( org_dist >= 0 )5673org_dist = exc->GS.single_width_value;5674else5675org_dist = -exc->GS.single_width_value;5676}56775678/* round flag */56795680if ( ( exc->opcode & 4 ) != 0 )5681{5682distance = exc->func_round( exc, org_dist, exc->opcode & 3 );5683}5684else5685distance = Round_None( exc, org_dist, exc->opcode & 3 );56865687/* minimum distance flag */56885689if ( ( exc->opcode & 8 ) != 0 )5690{5691FT_F26Dot6 minimum_distance = exc->GS.minimum_distance;569256935694if ( org_dist >= 0 )5695{5696if ( distance < minimum_distance )5697distance = minimum_distance;5698}5699else5700{5701if ( distance > NEG_LONG( minimum_distance ) )5702distance = NEG_LONG( minimum_distance );5703}5704}57055706/* now move the point */57075708org_dist = PROJECT( exc->zp1.cur + point, exc->zp0.cur + exc->GS.rp0 );57095710exc->func_move( exc, &exc->zp1, point, SUB_LONG( distance, org_dist ) );57115712Fail:5713exc->GS.rp1 = exc->GS.rp0;5714exc->GS.rp2 = point;57155716if ( ( exc->opcode & 16 ) != 0 )5717exc->GS.rp0 = point;5718}571957205721/**************************************************************************5722*5723* MIRP[abcde]: Move Indirect Relative Point5724* Opcode range: 0xE0-0xFF5725* Stack: int32? uint32 -->5726*/5727static void5728Ins_MIRP( TT_ExecContext exc,5729FT_Long* args )5730{5731FT_UShort point;5732FT_ULong cvtEntry;57335734FT_F26Dot6 cvt_dist,5735distance,5736cur_dist,5737org_dist;57385739FT_F26Dot6 delta;574057415742point = (FT_UShort)args[0];5743cvtEntry = (FT_ULong)( ADD_LONG( args[1], 1 ) );57445745/* XXX: UNDOCUMENTED! cvt[-1] = 0 always */57465747if ( BOUNDS( point, exc->zp1.n_points ) ||5748BOUNDSL( cvtEntry, exc->cvtSize + 1 ) ||5749BOUNDS( exc->GS.rp0, exc->zp0.n_points ) )5750{5751if ( exc->pedantic_hinting )5752exc->error = FT_THROW( Invalid_Reference );5753goto Fail;5754}57555756if ( !cvtEntry )5757cvt_dist = 0;5758else5759cvt_dist = exc->func_read_cvt( exc, cvtEntry - 1 );57605761/* single width test */57625763delta = SUB_LONG( cvt_dist, exc->GS.single_width_value );5764if ( delta < 0 )5765delta = NEG_LONG( delta );57665767if ( delta < exc->GS.single_width_cutin )5768{5769if ( cvt_dist >= 0 )5770cvt_dist = exc->GS.single_width_value;5771else5772cvt_dist = -exc->GS.single_width_value;5773}57745775/* UNDOCUMENTED! The MS rasterizer does that with */5776/* twilight points (confirmed by Greg Hitchcock) */5777if ( exc->GS.gep1 == 0 )5778{5779exc->zp1.org[point].x = ADD_LONG(5780exc->zp0.org[exc->GS.rp0].x,5781TT_MulFix14( cvt_dist,5782exc->GS.freeVector.x ) );5783exc->zp1.org[point].y = ADD_LONG(5784exc->zp0.org[exc->GS.rp0].y,5785TT_MulFix14( cvt_dist,5786exc->GS.freeVector.y ) );5787exc->zp1.cur[point] = exc->zp1.org[point];5788}57895790org_dist = DUALPROJ( &exc->zp1.org[point], &exc->zp0.org[exc->GS.rp0] );5791cur_dist = PROJECT ( &exc->zp1.cur[point], &exc->zp0.cur[exc->GS.rp0] );57925793/* auto-flip test */57945795if ( exc->GS.auto_flip )5796{5797if ( ( org_dist ^ cvt_dist ) < 0 )5798cvt_dist = NEG_LONG( cvt_dist );5799}58005801/* control value cut-in and round */58025803if ( ( exc->opcode & 4 ) != 0 )5804{5805/* XXX: UNDOCUMENTED! Only perform cut-in test when both points */5806/* refer to the same zone. */58075808if ( exc->GS.gep0 == exc->GS.gep1 )5809{5810FT_F26Dot6 control_value_cutin = exc->GS.control_value_cutin;581158125813/* XXX: According to Greg Hitchcock, the following wording is */5814/* the right one: */5815/* */5816/* When the absolute difference between the value in */5817/* the table [CVT] and the measurement directly from */5818/* the outline is _greater_ than the cut_in value, the */5819/* outline measurement is used. */5820/* */5821/* This is from `instgly.doc'. The description in */5822/* `ttinst2.doc', version 1.66, is thus incorrect since */5823/* it implies `>=' instead of `>'. */58245825delta = SUB_LONG( cvt_dist, org_dist );5826if ( delta < 0 )5827delta = NEG_LONG( delta );58285829if ( delta > control_value_cutin )5830cvt_dist = org_dist;5831}58325833distance = exc->func_round( exc, cvt_dist, exc->opcode & 3 );5834}5835else5836distance = Round_None( exc, cvt_dist, exc->opcode & 3 );58375838/* minimum distance test */58395840if ( ( exc->opcode & 8 ) != 0 )5841{5842FT_F26Dot6 minimum_distance = exc->GS.minimum_distance;584358445845if ( org_dist >= 0 )5846{5847if ( distance < minimum_distance )5848distance = minimum_distance;5849}5850else5851{5852if ( distance > NEG_LONG( minimum_distance ) )5853distance = NEG_LONG( minimum_distance );5854}5855}58565857exc->func_move( exc,5858&exc->zp1,5859point,5860SUB_LONG( distance, cur_dist ) );58615862Fail:5863exc->GS.rp1 = exc->GS.rp0;58645865if ( ( exc->opcode & 16 ) != 0 )5866exc->GS.rp0 = point;58675868exc->GS.rp2 = point;5869}587058715872/**************************************************************************5873*5874* ALIGNRP[]: ALIGN Relative Point5875* Opcode range: 0x3C5876* Stack: uint32 uint32... -->5877*/5878static void5879Ins_ALIGNRP( TT_ExecContext exc )5880{5881FT_UShort point;5882FT_F26Dot6 distance;588358845885if ( exc->top < exc->GS.loop ||5886BOUNDS( exc->GS.rp0, exc->zp0.n_points ) )5887{5888if ( exc->pedantic_hinting )5889exc->error = FT_THROW( Invalid_Reference );5890goto Fail;5891}58925893while ( exc->GS.loop > 0 )5894{5895exc->args--;58965897point = (FT_UShort)exc->stack[exc->args];58985899if ( BOUNDS( point, exc->zp1.n_points ) )5900{5901if ( exc->pedantic_hinting )5902{5903exc->error = FT_THROW( Invalid_Reference );5904return;5905}5906}5907else5908{5909distance = PROJECT( exc->zp1.cur + point,5910exc->zp0.cur + exc->GS.rp0 );59115912exc->func_move( exc, &exc->zp1, point, NEG_LONG( distance ) );5913}59145915exc->GS.loop--;5916}59175918Fail:5919exc->GS.loop = 1;5920exc->new_top = exc->args;5921}592259235924/**************************************************************************5925*5926* ISECT[]: moves point to InterSECTion5927* Opcode range: 0x0F5928* Stack: 5 * uint32 -->5929*/5930static void5931Ins_ISECT( TT_ExecContext exc,5932FT_Long* args )5933{5934FT_UShort point,5935a0, a1,5936b0, b1;59375938FT_F26Dot6 discriminant, dotproduct;59395940FT_F26Dot6 dx, dy,5941dax, day,5942dbx, dby;59435944FT_F26Dot6 val;59455946FT_Vector R;594759485949point = (FT_UShort)args[0];59505951a0 = (FT_UShort)args[1];5952a1 = (FT_UShort)args[2];5953b0 = (FT_UShort)args[3];5954b1 = (FT_UShort)args[4];59555956if ( BOUNDS( b0, exc->zp0.n_points ) ||5957BOUNDS( b1, exc->zp0.n_points ) ||5958BOUNDS( a0, exc->zp1.n_points ) ||5959BOUNDS( a1, exc->zp1.n_points ) ||5960BOUNDS( point, exc->zp2.n_points ) )5961{5962if ( exc->pedantic_hinting )5963exc->error = FT_THROW( Invalid_Reference );5964return;5965}59665967/* Cramer's rule */59685969dbx = SUB_LONG( exc->zp0.cur[b1].x, exc->zp0.cur[b0].x );5970dby = SUB_LONG( exc->zp0.cur[b1].y, exc->zp0.cur[b0].y );59715972dax = SUB_LONG( exc->zp1.cur[a1].x, exc->zp1.cur[a0].x );5973day = SUB_LONG( exc->zp1.cur[a1].y, exc->zp1.cur[a0].y );59745975dx = SUB_LONG( exc->zp0.cur[b0].x, exc->zp1.cur[a0].x );5976dy = SUB_LONG( exc->zp0.cur[b0].y, exc->zp1.cur[a0].y );59775978discriminant = ADD_LONG( FT_MulDiv( dax, NEG_LONG( dby ), 0x40 ),5979FT_MulDiv( day, dbx, 0x40 ) );5980dotproduct = ADD_LONG( FT_MulDiv( dax, dbx, 0x40 ),5981FT_MulDiv( day, dby, 0x40 ) );59825983/* The discriminant above is actually a cross product of vectors */5984/* da and db. Together with the dot product, they can be used as */5985/* surrogates for sine and cosine of the angle between the vectors. */5986/* Indeed, */5987/* dotproduct = |da||db|cos(angle) */5988/* discriminant = |da||db|sin(angle) . */5989/* We use these equations to reject grazing intersections by */5990/* thresholding abs(tan(angle)) at 1/19, corresponding to 3 degrees. */5991if ( MUL_LONG( 19, FT_ABS( discriminant ) ) > FT_ABS( dotproduct ) )5992{5993val = ADD_LONG( FT_MulDiv( dx, NEG_LONG( dby ), 0x40 ),5994FT_MulDiv( dy, dbx, 0x40 ) );59955996R.x = FT_MulDiv( val, dax, discriminant );5997R.y = FT_MulDiv( val, day, discriminant );59985999/* XXX: Block in backward_compatibility and/or post-IUP? */6000exc->zp2.cur[point].x = ADD_LONG( exc->zp1.cur[a0].x, R.x );6001exc->zp2.cur[point].y = ADD_LONG( exc->zp1.cur[a0].y, R.y );6002}6003else6004{6005/* else, take the middle of the middles of A and B */60066007/* XXX: Block in backward_compatibility and/or post-IUP? */6008exc->zp2.cur[point].x =6009ADD_LONG( ADD_LONG( exc->zp1.cur[a0].x, exc->zp1.cur[a1].x ),6010ADD_LONG( exc->zp0.cur[b0].x, exc->zp0.cur[b1].x ) ) / 4;6011exc->zp2.cur[point].y =6012ADD_LONG( ADD_LONG( exc->zp1.cur[a0].y, exc->zp1.cur[a1].y ),6013ADD_LONG( exc->zp0.cur[b0].y, exc->zp0.cur[b1].y ) ) / 4;6014}60156016exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_BOTH;6017}601860196020/**************************************************************************6021*6022* ALIGNPTS[]: ALIGN PoinTS6023* Opcode range: 0x276024* Stack: uint32 uint32 -->6025*/6026static void6027Ins_ALIGNPTS( TT_ExecContext exc,6028FT_Long* args )6029{6030FT_UShort p1, p2;6031FT_F26Dot6 distance;603260336034p1 = (FT_UShort)args[0];6035p2 = (FT_UShort)args[1];60366037if ( BOUNDS( p1, exc->zp1.n_points ) ||6038BOUNDS( p2, exc->zp0.n_points ) )6039{6040if ( exc->pedantic_hinting )6041exc->error = FT_THROW( Invalid_Reference );6042return;6043}60446045distance = PROJECT( exc->zp0.cur + p2, exc->zp1.cur + p1 ) / 2;60466047exc->func_move( exc, &exc->zp1, p1, distance );6048exc->func_move( exc, &exc->zp0, p2, NEG_LONG( distance ) );6049}605060516052/**************************************************************************6053*6054* IP[]: Interpolate Point6055* Opcode range: 0x396056* Stack: uint32... -->6057*/60586059/* SOMETIMES, DUMBER CODE IS BETTER CODE */60606061static void6062Ins_IP( TT_ExecContext exc )6063{6064FT_F26Dot6 old_range, cur_range;6065FT_Vector* orus_base;6066FT_Vector* cur_base;6067FT_Int twilight;606860696070if ( exc->top < exc->GS.loop )6071{6072if ( exc->pedantic_hinting )6073exc->error = FT_THROW( Invalid_Reference );6074goto Fail;6075}60766077/*6078* We need to deal in a special way with the twilight zone.6079* Otherwise, by definition, the value of exc->twilight.orus[n] is (0,0),6080* for every n.6081*/6082twilight = ( exc->GS.gep0 == 0 ||6083exc->GS.gep1 == 0 ||6084exc->GS.gep2 == 0 );60856086if ( BOUNDS( exc->GS.rp1, exc->zp0.n_points ) )6087{6088if ( exc->pedantic_hinting )6089exc->error = FT_THROW( Invalid_Reference );6090goto Fail;6091}60926093if ( twilight )6094orus_base = &exc->zp0.org[exc->GS.rp1];6095else6096orus_base = &exc->zp0.orus[exc->GS.rp1];60976098cur_base = &exc->zp0.cur[exc->GS.rp1];60996100/* XXX: There are some glyphs in some braindead but popular */6101/* fonts out there (e.g. [aeu]grave in monotype.ttf) */6102/* calling IP[] with bad values of rp[12]. */6103/* Do something sane when this odd thing happens. */6104if ( BOUNDS( exc->GS.rp1, exc->zp0.n_points ) ||6105BOUNDS( exc->GS.rp2, exc->zp1.n_points ) )6106{6107old_range = 0;6108cur_range = 0;6109}6110else6111{6112if ( twilight )6113old_range = DUALPROJ( &exc->zp1.org[exc->GS.rp2], orus_base );6114else if ( exc->metrics.x_scale == exc->metrics.y_scale )6115old_range = DUALPROJ( &exc->zp1.orus[exc->GS.rp2], orus_base );6116else6117{6118FT_Vector vec;611961206121vec.x = FT_MulFix( SUB_LONG( exc->zp1.orus[exc->GS.rp2].x,6122orus_base->x ),6123exc->metrics.x_scale );6124vec.y = FT_MulFix( SUB_LONG( exc->zp1.orus[exc->GS.rp2].y,6125orus_base->y ),6126exc->metrics.y_scale );61276128old_range = FAST_DUALPROJ( &vec );6129}61306131cur_range = PROJECT( &exc->zp1.cur[exc->GS.rp2], cur_base );6132}61336134for ( ; exc->GS.loop > 0; exc->GS.loop-- )6135{6136FT_UInt point = (FT_UInt)exc->stack[--exc->args];6137FT_F26Dot6 org_dist, cur_dist, new_dist;613861396140/* check point bounds */6141if ( BOUNDS( point, exc->zp2.n_points ) )6142{6143if ( exc->pedantic_hinting )6144{6145exc->error = FT_THROW( Invalid_Reference );6146return;6147}6148continue;6149}61506151if ( twilight )6152org_dist = DUALPROJ( &exc->zp2.org[point], orus_base );6153else if ( exc->metrics.x_scale == exc->metrics.y_scale )6154org_dist = DUALPROJ( &exc->zp2.orus[point], orus_base );6155else6156{6157FT_Vector vec;615861596160vec.x = FT_MulFix( SUB_LONG( exc->zp2.orus[point].x,6161orus_base->x ),6162exc->metrics.x_scale );6163vec.y = FT_MulFix( SUB_LONG( exc->zp2.orus[point].y,6164orus_base->y ),6165exc->metrics.y_scale );61666167org_dist = FAST_DUALPROJ( &vec );6168}61696170cur_dist = PROJECT( &exc->zp2.cur[point], cur_base );61716172if ( org_dist )6173{6174if ( old_range )6175new_dist = FT_MulDiv( org_dist, cur_range, old_range );6176else6177{6178/* This is the same as what MS does for the invalid case: */6179/* */6180/* delta = (Original_Pt - Original_RP1) - */6181/* (Current_Pt - Current_RP1) ; */6182/* */6183/* In FreeType speak: */6184/* */6185/* delta = org_dist - cur_dist . */6186/* */6187/* We move `point' by `new_dist - cur_dist' after leaving */6188/* this block, thus we have */6189/* */6190/* new_dist - cur_dist = delta , */6191/* new_dist - cur_dist = org_dist - cur_dist , */6192/* new_dist = org_dist . */61936194new_dist = org_dist;6195}6196}6197else6198new_dist = 0;61996200exc->func_move( exc,6201&exc->zp2,6202(FT_UShort)point,6203SUB_LONG( new_dist, cur_dist ) );6204}62056206Fail:6207exc->GS.loop = 1;6208exc->new_top = exc->args;6209}621062116212/**************************************************************************6213*6214* UTP[a]: UnTouch Point6215* Opcode range: 0x296216* Stack: uint32 -->6217*/6218static void6219Ins_UTP( TT_ExecContext exc,6220FT_Long* args )6221{6222FT_UShort point;6223FT_Byte mask;622462256226point = (FT_UShort)args[0];62276228if ( BOUNDS( point, exc->zp0.n_points ) )6229{6230if ( exc->pedantic_hinting )6231exc->error = FT_THROW( Invalid_Reference );6232return;6233}62346235mask = 0xFF;62366237if ( exc->GS.freeVector.x != 0 )6238mask &= ~FT_CURVE_TAG_TOUCH_X;62396240if ( exc->GS.freeVector.y != 0 )6241mask &= ~FT_CURVE_TAG_TOUCH_Y;62426243exc->zp0.tags[point] &= mask;6244}624562466247/* Local variables for Ins_IUP: */6248typedef struct IUP_WorkerRec_6249{6250FT_Vector* orgs; /* original and current coordinate */6251FT_Vector* curs; /* arrays */6252FT_Vector* orus;6253FT_UInt max_points;62546255} IUP_WorkerRec, *IUP_Worker;625662576258static void6259iup_worker_shift_( IUP_Worker worker,6260FT_UInt p1,6261FT_UInt p2,6262FT_UInt p )6263{6264FT_UInt i;6265FT_F26Dot6 dx;626662676268dx = SUB_LONG( worker->curs[p].x, worker->orgs[p].x );6269if ( dx != 0 )6270{6271for ( i = p1; i < p; i++ )6272worker->curs[i].x = ADD_LONG( worker->curs[i].x, dx );62736274for ( i = p + 1; i <= p2; i++ )6275worker->curs[i].x = ADD_LONG( worker->curs[i].x, dx );6276}6277}627862796280static void6281iup_worker_interpolate_( IUP_Worker worker,6282FT_UInt p1,6283FT_UInt p2,6284FT_UInt ref1,6285FT_UInt ref2 )6286{6287FT_UInt i;6288FT_F26Dot6 orus1, orus2, org1, org2, cur1, cur2, delta1, delta2;628962906291if ( p1 > p2 )6292return;62936294if ( BOUNDS( ref1, worker->max_points ) ||6295BOUNDS( ref2, worker->max_points ) )6296return;62976298orus1 = worker->orus[ref1].x;6299orus2 = worker->orus[ref2].x;63006301if ( orus1 > orus2 )6302{6303FT_F26Dot6 tmp_o;6304FT_UInt tmp_r;630563066307tmp_o = orus1;6308orus1 = orus2;6309orus2 = tmp_o;63106311tmp_r = ref1;6312ref1 = ref2;6313ref2 = tmp_r;6314}63156316org1 = worker->orgs[ref1].x;6317org2 = worker->orgs[ref2].x;6318cur1 = worker->curs[ref1].x;6319cur2 = worker->curs[ref2].x;6320delta1 = SUB_LONG( cur1, org1 );6321delta2 = SUB_LONG( cur2, org2 );63226323if ( cur1 == cur2 || orus1 == orus2 )6324{63256326/* trivial snap or shift of untouched points */6327for ( i = p1; i <= p2; i++ )6328{6329FT_F26Dot6 x = worker->orgs[i].x;633063316332if ( x <= org1 )6333x = ADD_LONG( x, delta1 );63346335else if ( x >= org2 )6336x = ADD_LONG( x, delta2 );63376338else6339x = cur1;63406341worker->curs[i].x = x;6342}6343}6344else6345{6346FT_Fixed scale = 0;6347FT_Bool scale_valid = 0;634863496350/* interpolation */6351for ( i = p1; i <= p2; i++ )6352{6353FT_F26Dot6 x = worker->orgs[i].x;635463556356if ( x <= org1 )6357x = ADD_LONG( x, delta1 );63586359else if ( x >= org2 )6360x = ADD_LONG( x, delta2 );63616362else6363{6364if ( !scale_valid )6365{6366scale_valid = 1;6367scale = FT_DivFix( SUB_LONG( cur2, cur1 ),6368SUB_LONG( orus2, orus1 ) );6369}63706371x = ADD_LONG( cur1,6372FT_MulFix( SUB_LONG( worker->orus[i].x, orus1 ),6373scale ) );6374}6375worker->curs[i].x = x;6376}6377}6378}637963806381/**************************************************************************6382*6383* IUP[a]: Interpolate Untouched Points6384* Opcode range: 0x30-0x316385* Stack: -->6386*/6387static void6388Ins_IUP( TT_ExecContext exc )6389{6390IUP_WorkerRec V;6391FT_Byte mask;63926393FT_UInt first_point; /* first point of contour */6394FT_UInt end_point; /* end point (last+1) of contour */63956396FT_UInt first_touched; /* first touched point in contour */6397FT_UInt cur_touched; /* current touched point in contour */63986399FT_UInt point; /* current point */6400FT_Short contour; /* current contour */640164026403#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL6404/* See `ttinterp.h' for details on backward compatibility mode. */6405/* Allow IUP until it has been called on both axes. Immediately */6406/* return on subsequent ones. */6407if ( SUBPIXEL_HINTING_MINIMAL &&6408exc->backward_compatibility )6409{6410if ( exc->iupx_called && exc->iupy_called )6411return;64126413if ( exc->opcode & 1 )6414exc->iupx_called = TRUE;6415else6416exc->iupy_called = TRUE;6417}6418#endif64196420/* ignore empty outlines */6421if ( exc->pts.n_contours == 0 )6422return;64236424if ( exc->opcode & 1 )6425{6426mask = FT_CURVE_TAG_TOUCH_X;6427V.orgs = exc->pts.org;6428V.curs = exc->pts.cur;6429V.orus = exc->pts.orus;6430}6431else6432{6433mask = FT_CURVE_TAG_TOUCH_Y;6434V.orgs = (FT_Vector*)( (FT_Pos*)exc->pts.org + 1 );6435V.curs = (FT_Vector*)( (FT_Pos*)exc->pts.cur + 1 );6436V.orus = (FT_Vector*)( (FT_Pos*)exc->pts.orus + 1 );6437}6438V.max_points = exc->pts.n_points;64396440contour = 0;6441point = 0;64426443do6444{6445end_point = exc->pts.contours[contour] - exc->pts.first_point;6446first_point = point;64476448if ( BOUNDS( end_point, exc->pts.n_points ) )6449end_point = exc->pts.n_points - 1;64506451while ( point <= end_point && ( exc->pts.tags[point] & mask ) == 0 )6452point++;64536454if ( point <= end_point )6455{6456first_touched = point;6457cur_touched = point;64586459point++;64606461while ( point <= end_point )6462{6463if ( ( exc->pts.tags[point] & mask ) != 0 )6464{6465iup_worker_interpolate_( &V,6466cur_touched + 1,6467point - 1,6468cur_touched,6469point );6470cur_touched = point;6471}64726473point++;6474}64756476if ( cur_touched == first_touched )6477iup_worker_shift_( &V, first_point, end_point, cur_touched );6478else6479{6480iup_worker_interpolate_( &V,6481(FT_UShort)( cur_touched + 1 ),6482end_point,6483cur_touched,6484first_touched );64856486if ( first_touched > 0 )6487iup_worker_interpolate_( &V,6488first_point,6489first_touched - 1,6490cur_touched,6491first_touched );6492}6493}6494contour++;6495} while ( contour < exc->pts.n_contours );6496}649764986499/**************************************************************************6500*6501* DELTAPn[]: DELTA exceptions P1, P2, P36502* Opcode range: 0x5D,0x71,0x726503* Stack: uint32 (2 * uint32)... -->6504*/6505static void6506Ins_DELTAP( TT_ExecContext exc,6507FT_Long* args )6508{6509FT_ULong nump, k;6510FT_UShort A;6511FT_ULong C, P;6512FT_Long B;651365146515P = (FT_ULong)exc->func_cur_ppem( exc );6516nump = (FT_ULong)args[0]; /* some points theoretically may occur more6517than once, thus UShort isn't enough */65186519for ( k = 1; k <= nump; k++ )6520{6521if ( exc->args < 2 )6522{6523if ( exc->pedantic_hinting )6524exc->error = FT_THROW( Too_Few_Arguments );6525exc->args = 0;6526goto Fail;6527}65286529exc->args -= 2;65306531A = (FT_UShort)exc->stack[exc->args + 1];6532B = exc->stack[exc->args];65336534/* XXX: Because some popular fonts contain some invalid DeltaP */6535/* instructions, we simply ignore them when the stacked */6536/* point reference is off limit, rather than returning an */6537/* error. As a delta instruction doesn't change a glyph */6538/* in great ways, this shouldn't be a problem. */65396540if ( !BOUNDS( A, exc->zp0.n_points ) )6541{6542C = ( (FT_ULong)B & 0xF0 ) >> 4;65436544switch ( exc->opcode )6545{6546case 0x5D:6547break;65486549case 0x71:6550C += 16;6551break;65526553case 0x72:6554C += 32;6555break;6556}65576558C += exc->GS.delta_base;65596560if ( P == C )6561{6562B = ( (FT_ULong)B & 0xF ) - 8;6563if ( B >= 0 )6564B++;6565B *= 1L << ( 6 - exc->GS.delta_shift );656665676568#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL6569/* See `ttinterp.h' for details on backward compatibility */6570/* mode. */6571if ( SUBPIXEL_HINTING_MINIMAL &&6572exc->backward_compatibility )6573{6574if ( !( exc->iupx_called && exc->iupy_called ) &&6575( ( exc->is_composite && exc->GS.freeVector.y != 0 ) ||6576( exc->zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) ) )6577exc->func_move( exc, &exc->zp0, A, B );6578}6579else6580#endif6581exc->func_move( exc, &exc->zp0, A, B );6582}6583}6584else6585if ( exc->pedantic_hinting )6586exc->error = FT_THROW( Invalid_Reference );6587}65886589Fail:6590exc->new_top = exc->args;6591}659265936594/**************************************************************************6595*6596* DELTACn[]: DELTA exceptions C1, C2, C36597* Opcode range: 0x73,0x74,0x756598* Stack: uint32 (2 * uint32)... -->6599*/6600static void6601Ins_DELTAC( TT_ExecContext exc,6602FT_Long* args )6603{6604FT_ULong nump, k;6605FT_ULong A, C, P;6606FT_Long B;660766086609P = (FT_ULong)exc->func_cur_ppem( exc );6610nump = (FT_ULong)args[0];66116612for ( k = 1; k <= nump; k++ )6613{6614if ( exc->args < 2 )6615{6616if ( exc->pedantic_hinting )6617exc->error = FT_THROW( Too_Few_Arguments );6618exc->args = 0;6619goto Fail;6620}66216622exc->args -= 2;66236624A = (FT_ULong)exc->stack[exc->args + 1];6625B = exc->stack[exc->args];66266627if ( BOUNDSL( A, exc->cvtSize ) )6628{6629if ( exc->pedantic_hinting )6630{6631exc->error = FT_THROW( Invalid_Reference );6632return;6633}6634}6635else6636{6637C = ( (FT_ULong)B & 0xF0 ) >> 4;66386639switch ( exc->opcode )6640{6641case 0x73:6642break;66436644case 0x74:6645C += 16;6646break;66476648case 0x75:6649C += 32;6650break;6651}66526653C += exc->GS.delta_base;66546655if ( P == C )6656{6657B = ( (FT_ULong)B & 0xF ) - 8;6658if ( B >= 0 )6659B++;6660B *= 1L << ( 6 - exc->GS.delta_shift );66616662exc->func_move_cvt( exc, A, B );6663}6664}6665}66666667Fail:6668exc->new_top = exc->args;6669}667066716672/**************************************************************************6673*6674* MISC. INSTRUCTIONS6675*6676*/667766786679/**************************************************************************6680*6681* GETINFO[]: GET INFOrmation6682* Opcode range: 0x886683* Stack: uint32 --> uint326684*/6685static void6686Ins_GETINFO( TT_ExecContext exc,6687FT_Long* args )6688{6689FT_Long K;6690TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( exc->face );669166926693K = 0;66946695if ( ( args[0] & 1 ) != 0 )6696K = driver->interpreter_version;66976698/*********************************6699* GLYPH ROTATED6700* Selector Bit: 16701* Return Bit(s): 86702*/6703if ( ( args[0] & 2 ) != 0 && exc->tt_metrics.rotated )6704K |= 1 << 8;67056706/*********************************6707* GLYPH STRETCHED6708* Selector Bit: 26709* Return Bit(s): 96710*/6711if ( ( args[0] & 4 ) != 0 && exc->tt_metrics.stretched )6712K |= 1 << 9;67136714#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT6715/*********************************6716* VARIATION GLYPH6717* Selector Bit: 36718* Return Bit(s): 106719*/6720if ( (args[0] & 8 ) != 0 && exc->face->blend )6721K |= 1 << 10;6722#endif67236724/*********************************6725* BI-LEVEL HINTING AND6726* GRAYSCALE RENDERING6727* Selector Bit: 56728* Return Bit(s): 126729*/6730if ( ( args[0] & 32 ) != 0 && exc->grayscale )6731K |= 1 << 12;67326733#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL6734/* Toggle the following flags only outside of monochrome mode. */6735/* Otherwise, instructions may behave weirdly and rendering results */6736/* may differ between v35 and v40 mode, e.g., in `Times New Roman */6737/* Bold Italic'. */6738if ( SUBPIXEL_HINTING_MINIMAL && exc->subpixel_hinting_lean )6739{6740/*********************************6741* HINTING FOR SUBPIXEL6742* Selector Bit: 66743* Return Bit(s): 136744*6745* v40 does subpixel hinting by default.6746*/6747if ( ( args[0] & 64 ) != 0 )6748K |= 1 << 13;67496750/*********************************6751* VERTICAL LCD SUBPIXELS?6752* Selector Bit: 86753* Return Bit(s): 156754*/6755if ( ( args[0] & 256 ) != 0 && exc->vertical_lcd_lean )6756K |= 1 << 15;67576758/*********************************6759* SUBPIXEL POSITIONED?6760* Selector Bit: 106761* Return Bit(s): 176762*6763* XXX: FreeType supports it, dependent on what client does?6764*/6765if ( ( args[0] & 1024 ) != 0 )6766K |= 1 << 17;67676768/*********************************6769* SYMMETRICAL SMOOTHING6770* Selector Bit: 116771* Return Bit(s): 186772*6773* The only smoothing method FreeType supports unless someone sets6774* FT_LOAD_TARGET_MONO.6775*/6776if ( ( args[0] & 2048 ) != 0 && exc->subpixel_hinting_lean )6777K |= 1 << 18;67786779/*********************************6780* CLEARTYPE HINTING AND6781* GRAYSCALE RENDERING6782* Selector Bit: 126783* Return Bit(s): 196784*6785* Grayscale rendering is what FreeType does anyway unless someone6786* sets FT_LOAD_TARGET_MONO or FT_LOAD_TARGET_LCD(_V)6787*/6788if ( ( args[0] & 4096 ) != 0 && exc->grayscale_cleartype )6789K |= 1 << 19;6790}6791#endif67926793args[0] = K;6794}679567966797#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT67986799/**************************************************************************6800*6801* GETVARIATION[]: get normalized variation (blend) coordinates6802* Opcode range: 0x916803* Stack: --> f2.14...6804*6805* XXX: UNDOCUMENTED! There is no official documentation from Apple for6806* this bytecode instruction. Active only if a font has GX6807* variation axes.6808*/6809static void6810Ins_GETVARIATION( TT_ExecContext exc,6811FT_Long* args )6812{6813FT_UInt num_axes = exc->face->blend->num_axis;6814FT_Fixed* coords = exc->face->blend->normalizedcoords;68156816FT_UInt i;681768186819if ( BOUNDS( num_axes, exc->stackSize + 1 - exc->top ) )6820{6821exc->error = FT_THROW( Stack_Overflow );6822return;6823}68246825if ( coords )6826{6827for ( i = 0; i < num_axes; i++ )6828args[i] = coords[i] >> 2; /* convert 16.16 to 2.14 format */6829}6830else6831{6832for ( i = 0; i < num_axes; i++ )6833args[i] = 0;6834}6835}683668376838/**************************************************************************6839*6840* GETDATA[]: no idea what this is good for6841* Opcode range: 0x926842* Stack: --> 176843*6844* XXX: UNDOCUMENTED! There is no documentation from Apple for this6845* very weird bytecode instruction.6846*/6847static void6848Ins_GETDATA( FT_Long* args )6849{6850args[0] = 17;6851}68526853#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */685468556856static void6857Ins_UNKNOWN( TT_ExecContext exc )6858{6859TT_DefRecord* def = exc->IDefs;6860TT_DefRecord* limit = FT_OFFSET( def, exc->numIDefs );686168626863for ( ; def < limit; def++ )6864{6865if ( (FT_Byte)def->opc == exc->opcode && def->active )6866{6867TT_CallRec* call;686868696870if ( exc->callTop >= exc->callSize )6871{6872exc->error = FT_THROW( Stack_Overflow );6873return;6874}68756876call = exc->callStack + exc->callTop++;68776878call->Caller_Range = exc->curRange;6879call->Caller_IP = exc->IP + 1;6880call->Cur_Count = 1;6881call->Def = def;68826883Ins_Goto_CodeRange( exc, def->range, def->start );68846885exc->step_ins = FALSE;6886return;6887}6888}68896890exc->error = FT_THROW( Invalid_Opcode );6891}689268936894/**************************************************************************6895*6896* RUN6897*6898* This function executes a run of opcodes. It will exit in the6899* following cases:6900*6901* - Errors (in which case it returns FALSE).6902*6903* - Reaching the end of the main code range (returns TRUE).6904* Reaching the end of a code range within a function call is an6905* error.6906*6907* - After executing one single opcode, if the flag `Instruction_Trap'6908* is set to TRUE (returns TRUE).6909*6910* On exit with TRUE, test IP < CodeSize to know whether it comes from6911* an instruction trap or a normal termination.6912*6913*6914* Note: The documented DEBUG opcode pops a value from the stack. This6915* behaviour is unsupported; here a DEBUG opcode is always an6916* error.6917*6918*6919* THIS IS THE INTERPRETER'S MAIN LOOP.6920*6921*/692269236924/* documentation is in ttinterp.h */69256926FT_EXPORT_DEF( FT_Error )6927TT_RunIns( void* exec )6928{6929TT_ExecContext exc = (TT_ExecContext)exec;69306931FT_ULong ins_counter = 0; /* executed instructions counter */6932FT_ULong num_twilight_points;6933FT_UShort i;693469356936/* We restrict the number of twilight points to a reasonable, */6937/* heuristic value to avoid slow execution of malformed bytecode. */6938num_twilight_points = FT_MAX( 30,69392 * ( exc->pts.n_points + exc->cvtSize ) );6940if ( exc->twilight.n_points > num_twilight_points )6941{6942if ( num_twilight_points > 0xFFFFU )6943num_twilight_points = 0xFFFFU;69446945FT_TRACE5(( "TT_RunIns: Resetting number of twilight points\n" ));6946FT_TRACE5(( " from %d to the more reasonable value %ld\n",6947exc->twilight.n_points,6948num_twilight_points ));6949exc->twilight.n_points = (FT_UShort)num_twilight_points;6950}69516952/* Set up loop detectors. We restrict the number of LOOPCALL loops */6953/* and the number of JMPR, JROT, and JROF calls with a negative */6954/* argument to values that depend on various parameters like the */6955/* size of the CVT table or the number of points in the current */6956/* glyph (if applicable). */6957/* */6958/* The idea is that in real-world bytecode you either iterate over */6959/* all CVT entries (in the `prep' table), or over all points (or */6960/* contours, in the `glyf' table) of a glyph, and such iterations */6961/* don't happen very often. */6962exc->loopcall_counter = 0;6963exc->neg_jump_counter = 0;69646965/* The maximum values are heuristic. */6966if ( exc->pts.n_points )6967exc->loopcall_counter_max = FT_MAX( 50,696810 * exc->pts.n_points ) +6969FT_MAX( 50,6970exc->cvtSize / 10 );6971else6972exc->loopcall_counter_max = 300 + 22 * exc->cvtSize;69736974/* as a protection against an unreasonable number of CVT entries */6975/* we assume at most 100 control values per glyph for the counter */6976if ( exc->loopcall_counter_max >6977100 * (FT_ULong)exc->face->root.num_glyphs )6978exc->loopcall_counter_max = 100 * (FT_ULong)exc->face->root.num_glyphs;69796980FT_TRACE5(( "TT_RunIns: Limiting total number of loops in LOOPCALL"6981" to %ld\n", exc->loopcall_counter_max ));69826983exc->neg_jump_counter_max = exc->loopcall_counter_max;6984FT_TRACE5(( "TT_RunIns: Limiting total number of backward jumps"6985" to %ld\n", exc->neg_jump_counter_max ));69866987/* set PPEM and CVT functions */6988exc->tt_metrics.ratio = 0;6989if ( exc->metrics.x_ppem != exc->metrics.y_ppem )6990{6991/* non-square pixels, use the stretched routines */6992exc->func_cur_ppem = Current_Ppem_Stretched;6993exc->func_read_cvt = Read_CVT_Stretched;6994exc->func_write_cvt = Write_CVT_Stretched;6995exc->func_move_cvt = Move_CVT_Stretched;6996}6997else6998{6999/* square pixels, use normal routines */7000exc->func_cur_ppem = Current_Ppem;7001exc->func_read_cvt = Read_CVT;7002exc->func_write_cvt = Write_CVT;7003exc->func_move_cvt = Move_CVT;7004}70057006exc->iniRange = exc->curRange;70077008Compute_Funcs( exc );7009Compute_Round( exc, (FT_Byte)exc->GS.round_state );70107011/* These flags cancel execution of some opcodes after IUP is called */7012#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL7013exc->iupx_called = FALSE;7014exc->iupy_called = FALSE;7015#endif70167017do7018{7019exc->opcode = exc->code[exc->IP];70207021#ifdef FT_DEBUG_LEVEL_TRACE7022if ( ft_trace_levels[trace_ttinterp] >= 6 )7023{7024FT_Long cnt = FT_MIN( 8, exc->top );7025FT_Long n;702670277028/* if tracing level is 7, show current code position */7029/* and the first few stack elements also */7030FT_TRACE6(( " " ));7031FT_TRACE7(( "%06ld ", exc->IP ));7032FT_TRACE6(( "%s", opcode_name[exc->opcode] + 2 ));7033FT_TRACE7(( "%*s", *opcode_name[exc->opcode] == 'A'7034? 27035: 12 - ( *opcode_name[exc->opcode] - '0' ),7036"#" ));7037for ( n = 1; n <= cnt; n++ )7038FT_TRACE7(( " %ld", exc->stack[exc->top - n] ));7039FT_TRACE6(( "\n" ));7040}7041#endif /* FT_DEBUG_LEVEL_TRACE */70427043if ( ( exc->length = opcode_length[exc->opcode] ) < 0 )7044{7045if ( exc->IP + 1 >= exc->codeSize )7046goto LErrorCodeOverflow_;70477048exc->length = 2 - exc->length * exc->code[exc->IP + 1];7049}70507051if ( exc->IP + exc->length > exc->codeSize )7052goto LErrorCodeOverflow_;70537054/* First, let's check for empty stack and overflow */7055exc->args = exc->top - ( Pop_Push_Count[exc->opcode] >> 4 );70567057/* `args' is the top of the stack once arguments have been popped. */7058/* One can also interpret it as the index of the last argument. */7059if ( exc->args < 0 )7060{7061if ( exc->pedantic_hinting )7062{7063exc->error = FT_THROW( Too_Few_Arguments );7064goto LErrorLabel_;7065}70667067/* push zeroes onto the stack */7068for ( i = 0; i < Pop_Push_Count[exc->opcode] >> 4; i++ )7069exc->stack[i] = 0;7070exc->args = 0;7071}70727073#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT7074if ( exc->opcode == 0x91 )7075{7076/* this is very special: GETVARIATION returns */7077/* a variable number of arguments */70787079/* it is the job of the application to `activate' GX handling, */7080/* that is, calling any of the GX API functions on the current */7081/* font to select a variation instance */7082if ( exc->face->blend )7083exc->new_top = exc->args + exc->face->blend->num_axis;7084}7085else7086#endif7087exc->new_top = exc->args + ( Pop_Push_Count[exc->opcode] & 15 );70887089/* `new_top' is the new top of the stack, after the instruction's */7090/* execution. `top' will be set to `new_top' after the `switch' */7091/* statement. */7092if ( exc->new_top > exc->stackSize )7093{7094exc->error = FT_THROW( Stack_Overflow );7095goto LErrorLabel_;7096}70977098exc->step_ins = TRUE;7099exc->error = FT_Err_Ok;71007101{7102FT_Long* args = exc->stack + exc->args;7103FT_Byte opcode = exc->opcode;710471057106switch ( opcode )7107{7108case 0x00: /* SVTCA y */7109case 0x01: /* SVTCA x */7110case 0x02: /* SPvTCA y */7111case 0x03: /* SPvTCA x */7112case 0x04: /* SFvTCA y */7113case 0x05: /* SFvTCA x */7114Ins_SxyTCA( exc );7115break;71167117case 0x06: /* SPvTL // */7118case 0x07: /* SPvTL + */7119Ins_SPVTL( exc, args );7120break;71217122case 0x08: /* SFvTL // */7123case 0x09: /* SFvTL + */7124Ins_SFVTL( exc, args );7125break;71267127case 0x0A: /* SPvFS */7128Ins_SPVFS( exc, args );7129break;71307131case 0x0B: /* SFvFS */7132Ins_SFVFS( exc, args );7133break;71347135case 0x0C: /* GPv */7136Ins_GPV( exc, args );7137break;71387139case 0x0D: /* GFv */7140Ins_GFV( exc, args );7141break;71427143case 0x0E: /* SFvTPv */7144Ins_SFVTPV( exc );7145break;71467147case 0x0F: /* ISECT */7148Ins_ISECT( exc, args );7149break;71507151case 0x10: /* SRP0 */7152Ins_SRP0( exc, args );7153break;71547155case 0x11: /* SRP1 */7156Ins_SRP1( exc, args );7157break;71587159case 0x12: /* SRP2 */7160Ins_SRP2( exc, args );7161break;71627163case 0x13: /* SZP0 */7164Ins_SZP0( exc, args );7165break;71667167case 0x14: /* SZP1 */7168Ins_SZP1( exc, args );7169break;71707171case 0x15: /* SZP2 */7172Ins_SZP2( exc, args );7173break;71747175case 0x16: /* SZPS */7176Ins_SZPS( exc, args );7177break;71787179case 0x17: /* SLOOP */7180Ins_SLOOP( exc, args );7181break;71827183case 0x18: /* RTG */7184Ins_RTG( exc );7185break;71867187case 0x19: /* RTHG */7188Ins_RTHG( exc );7189break;71907191case 0x1A: /* SMD */7192Ins_SMD( exc, args );7193break;71947195case 0x1B: /* ELSE */7196Ins_ELSE( exc );7197break;71987199case 0x1C: /* JMPR */7200Ins_JMPR( exc, args );7201break;72027203case 0x1D: /* SCVTCI */7204Ins_SCVTCI( exc, args );7205break;72067207case 0x1E: /* SSWCI */7208Ins_SSWCI( exc, args );7209break;72107211case 0x1F: /* SSW */7212Ins_SSW( exc, args );7213break;72147215case 0x20: /* DUP */7216Ins_DUP( args );7217break;72187219case 0x21: /* POP */7220Ins_POP();7221break;72227223case 0x22: /* CLEAR */7224Ins_CLEAR( exc );7225break;72267227case 0x23: /* SWAP */7228Ins_SWAP( args );7229break;72307231case 0x24: /* DEPTH */7232Ins_DEPTH( exc, args );7233break;72347235case 0x25: /* CINDEX */7236Ins_CINDEX( exc, args );7237break;72387239case 0x26: /* MINDEX */7240Ins_MINDEX( exc, args );7241break;72427243case 0x27: /* ALIGNPTS */7244Ins_ALIGNPTS( exc, args );7245break;72467247case 0x28: /* RAW */7248Ins_UNKNOWN( exc );7249break;72507251case 0x29: /* UTP */7252Ins_UTP( exc, args );7253break;72547255case 0x2A: /* LOOPCALL */7256Ins_LOOPCALL( exc, args );7257break;72587259case 0x2B: /* CALL */7260Ins_CALL( exc, args );7261break;72627263case 0x2C: /* FDEF */7264Ins_FDEF( exc, args );7265break;72667267case 0x2D: /* ENDF */7268Ins_ENDF( exc );7269break;72707271case 0x2E: /* MDAP */7272case 0x2F: /* MDAP */7273Ins_MDAP( exc, args );7274break;72757276case 0x30: /* IUP */7277case 0x31: /* IUP */7278Ins_IUP( exc );7279break;72807281case 0x32: /* SHP */7282case 0x33: /* SHP */7283Ins_SHP( exc );7284break;72857286case 0x34: /* SHC */7287case 0x35: /* SHC */7288Ins_SHC( exc, args );7289break;72907291case 0x36: /* SHZ */7292case 0x37: /* SHZ */7293Ins_SHZ( exc, args );7294break;72957296case 0x38: /* SHPIX */7297Ins_SHPIX( exc, args );7298break;72997300case 0x39: /* IP */7301Ins_IP( exc );7302break;73037304case 0x3A: /* MSIRP */7305case 0x3B: /* MSIRP */7306Ins_MSIRP( exc, args );7307break;73087309case 0x3C: /* AlignRP */7310Ins_ALIGNRP( exc );7311break;73127313case 0x3D: /* RTDG */7314Ins_RTDG( exc );7315break;73167317case 0x3E: /* MIAP */7318case 0x3F: /* MIAP */7319Ins_MIAP( exc, args );7320break;73217322case 0x40: /* NPUSHB */7323Ins_NPUSHB( exc, args );7324break;73257326case 0x41: /* NPUSHW */7327Ins_NPUSHW( exc, args );7328break;73297330case 0x42: /* WS */7331Ins_WS( exc, args );7332break;73337334case 0x43: /* RS */7335Ins_RS( exc, args );7336break;73377338case 0x44: /* WCVTP */7339Ins_WCVTP( exc, args );7340break;73417342case 0x45: /* RCVT */7343Ins_RCVT( exc, args );7344break;73457346case 0x46: /* GC */7347case 0x47: /* GC */7348Ins_GC( exc, args );7349break;73507351case 0x48: /* SCFS */7352Ins_SCFS( exc, args );7353break;73547355case 0x49: /* MD */7356case 0x4A: /* MD */7357Ins_MD( exc, args );7358break;73597360case 0x4B: /* MPPEM */7361Ins_MPPEM( exc, args );7362break;73637364case 0x4C: /* MPS */7365Ins_MPS( exc, args );7366break;73677368case 0x4D: /* FLIPON */7369Ins_FLIPON( exc );7370break;73717372case 0x4E: /* FLIPOFF */7373Ins_FLIPOFF( exc );7374break;73757376case 0x4F: /* DEBUG */7377Ins_DEBUG( exc );7378break;73797380case 0x50: /* LT */7381Ins_LT( args );7382break;73837384case 0x51: /* LTEQ */7385Ins_LTEQ( args );7386break;73877388case 0x52: /* GT */7389Ins_GT( args );7390break;73917392case 0x53: /* GTEQ */7393Ins_GTEQ( args );7394break;73957396case 0x54: /* EQ */7397Ins_EQ( args );7398break;73997400case 0x55: /* NEQ */7401Ins_NEQ( args );7402break;74037404case 0x56: /* ODD */7405Ins_ODD( exc, args );7406break;74077408case 0x57: /* EVEN */7409Ins_EVEN( exc, args );7410break;74117412case 0x58: /* IF */7413Ins_IF( exc, args );7414break;74157416case 0x59: /* EIF */7417Ins_EIF();7418break;74197420case 0x5A: /* AND */7421Ins_AND( args );7422break;74237424case 0x5B: /* OR */7425Ins_OR( args );7426break;74277428case 0x5C: /* NOT */7429Ins_NOT( args );7430break;74317432case 0x5D: /* DELTAP1 */7433Ins_DELTAP( exc, args );7434break;74357436case 0x5E: /* SDB */7437Ins_SDB( exc, args );7438break;74397440case 0x5F: /* SDS */7441Ins_SDS( exc, args );7442break;74437444case 0x60: /* ADD */7445Ins_ADD( args );7446break;74477448case 0x61: /* SUB */7449Ins_SUB( args );7450break;74517452case 0x62: /* DIV */7453Ins_DIV( exc, args );7454break;74557456case 0x63: /* MUL */7457Ins_MUL( args );7458break;74597460case 0x64: /* ABS */7461Ins_ABS( args );7462break;74637464case 0x65: /* NEG */7465Ins_NEG( args );7466break;74677468case 0x66: /* FLOOR */7469Ins_FLOOR( args );7470break;74717472case 0x67: /* CEILING */7473Ins_CEILING( args );7474break;74757476case 0x68: /* ROUND */7477case 0x69: /* ROUND */7478case 0x6A: /* ROUND */7479case 0x6B: /* ROUND */7480Ins_ROUND( exc, args );7481break;74827483case 0x6C: /* NROUND */7484case 0x6D: /* NROUND */7485case 0x6E: /* NRRUND */7486case 0x6F: /* NROUND */7487Ins_NROUND( exc, args );7488break;74897490case 0x70: /* WCVTF */7491Ins_WCVTF( exc, args );7492break;74937494case 0x71: /* DELTAP2 */7495case 0x72: /* DELTAP3 */7496Ins_DELTAP( exc, args );7497break;74987499case 0x73: /* DELTAC0 */7500case 0x74: /* DELTAC1 */7501case 0x75: /* DELTAC2 */7502Ins_DELTAC( exc, args );7503break;75047505case 0x76: /* SROUND */7506Ins_SROUND( exc, args );7507break;75087509case 0x77: /* S45Round */7510Ins_S45ROUND( exc, args );7511break;75127513case 0x78: /* JROT */7514Ins_JROT( exc, args );7515break;75167517case 0x79: /* JROF */7518Ins_JROF( exc, args );7519break;75207521case 0x7A: /* ROFF */7522Ins_ROFF( exc );7523break;75247525case 0x7B: /* ???? */7526Ins_UNKNOWN( exc );7527break;75287529case 0x7C: /* RUTG */7530Ins_RUTG( exc );7531break;75327533case 0x7D: /* RDTG */7534Ins_RDTG( exc );7535break;75367537case 0x7E: /* SANGW */7538Ins_SANGW();7539break;75407541case 0x7F: /* AA */7542Ins_AA();7543break;75447545case 0x80: /* FLIPPT */7546Ins_FLIPPT( exc );7547break;75487549case 0x81: /* FLIPRGON */7550Ins_FLIPRGON( exc, args );7551break;75527553case 0x82: /* FLIPRGOFF */7554Ins_FLIPRGOFF( exc, args );7555break;75567557case 0x83: /* UNKNOWN */7558case 0x84: /* UNKNOWN */7559Ins_UNKNOWN( exc );7560break;75617562case 0x85: /* SCANCTRL */7563Ins_SCANCTRL( exc, args );7564break;75657566case 0x86: /* SDPvTL */7567case 0x87: /* SDPvTL */7568Ins_SDPVTL( exc, args );7569break;75707571case 0x88: /* GETINFO */7572Ins_GETINFO( exc, args );7573break;75747575case 0x89: /* IDEF */7576Ins_IDEF( exc, args );7577break;75787579case 0x8A: /* ROLL */7580Ins_ROLL( args );7581break;75827583case 0x8B: /* MAX */7584Ins_MAX( args );7585break;75867587case 0x8C: /* MIN */7588Ins_MIN( args );7589break;75907591case 0x8D: /* SCANTYPE */7592Ins_SCANTYPE( exc, args );7593break;75947595case 0x8E: /* INSTCTRL */7596Ins_INSTCTRL( exc, args );7597break;75987599case 0x8F: /* ADJUST */7600case 0x90: /* ADJUST */7601Ins_UNKNOWN( exc );7602break;76037604#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT7605case 0x91:7606/* it is the job of the application to `activate' GX handling, */7607/* that is, calling any of the GX API functions on the current */7608/* font to select a variation instance */7609if ( exc->face->blend )7610Ins_GETVARIATION( exc, args );7611else7612Ins_UNKNOWN( exc );7613break;76147615case 0x92:7616/* there is at least one MS font (LaoUI.ttf version 5.01) that */7617/* uses IDEFs for 0x91 and 0x92; for this reason we activate */7618/* GETDATA for GX fonts only, similar to GETVARIATION */7619if ( exc->face->blend )7620Ins_GETDATA( args );7621else7622Ins_UNKNOWN( exc );7623break;7624#endif76257626default:7627if ( opcode >= 0xE0 )7628Ins_MIRP( exc, args );7629else if ( opcode >= 0xC0 )7630Ins_MDRP( exc, args );7631else if ( opcode >= 0xB8 )7632Ins_PUSHW( exc, args );7633else if ( opcode >= 0xB0 )7634Ins_PUSHB( exc, args );7635else7636Ins_UNKNOWN( exc );7637}7638}76397640if ( exc->error )7641{7642switch ( exc->error )7643{7644/* looking for redefined instructions */7645case FT_ERR( Invalid_Opcode ):7646{7647TT_DefRecord* def = exc->IDefs;7648TT_DefRecord* limit = FT_OFFSET( def, exc->numIDefs );764976507651for ( ; def < limit; def++ )7652{7653if ( def->active && exc->opcode == (FT_Byte)def->opc )7654{7655TT_CallRec* callrec;765676577658if ( exc->callTop >= exc->callSize )7659{7660exc->error = FT_THROW( Invalid_Reference );7661goto LErrorLabel_;7662}76637664callrec = &exc->callStack[exc->callTop];76657666callrec->Caller_Range = exc->curRange;7667callrec->Caller_IP = exc->IP + 1;7668callrec->Cur_Count = 1;7669callrec->Def = def;76707671if ( Ins_Goto_CodeRange( exc,7672def->range,7673def->start ) == FAILURE )7674goto LErrorLabel_;76757676goto LSuiteLabel_;7677}7678}7679}76807681exc->error = FT_THROW( Invalid_Opcode );7682goto LErrorLabel_;76837684#if 07685break; /* Unreachable code warning suppression. */7686/* Leave to remind in case a later change the editor */7687/* to consider break; */7688#endif76897690default:7691goto LErrorLabel_;76927693#if 07694break;7695#endif7696}7697}76987699exc->top = exc->new_top;77007701if ( exc->step_ins )7702exc->IP += exc->length;77037704/* increment instruction counter and check if we didn't */7705/* run this program for too long (e.g. infinite loops). */7706if ( ++ins_counter > TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES )7707{7708exc->error = FT_THROW( Execution_Too_Long );7709goto LErrorLabel_;7710}77117712LSuiteLabel_:7713if ( exc->IP >= exc->codeSize )7714{7715if ( exc->callTop > 0 )7716{7717exc->error = FT_THROW( Code_Overflow );7718goto LErrorLabel_;7719}7720else7721goto LNo_Error_;7722}7723} while ( !exc->instruction_trap );77247725LNo_Error_:7726FT_TRACE4(( " %ld instruction%s executed\n",7727ins_counter,7728ins_counter == 1 ? "" : "s" ));77297730return FT_Err_Ok;77317732LErrorCodeOverflow_:7733exc->error = FT_THROW( Code_Overflow );77347735LErrorLabel_:7736if ( exc->error && !exc->instruction_trap )7737FT_TRACE1(( " The interpreter returned error 0x%x\n", exc->error ));77387739return exc->error;7740}77417742#else /* !TT_USE_BYTECODE_INTERPRETER */77437744/* ANSI C doesn't like empty source files */7745typedef int tt_interp_dummy_;77467747#endif /* !TT_USE_BYTECODE_INTERPRETER */774877497750/* END */775177527753